From: Greg Kroah-Hartman Date: Fri, 15 May 2026 10:33:24 +0000 (+0200) Subject: 6.6-stable patches X-Git-Tag: v5.10.256~4 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e7aed67c417447b7fd34951705042c5193107c94;p=thirdparty%2Fkernel%2Fstable-queue.git 6.6-stable patches added patches: alsa-core-serialize-deferred-fasync-state-checks.patch alsa-hda-cs35l56-propagate-asp-tx-source-control-errors.patch alsa-misc-use-guard-for-spin-locks.patch alsa-seq-fix-ump-group-16-filtering.patch alsa-seq-notify-client-and-port-info-changes.patch bluetooth-hci_conn-fix-potential-uaf-in-create_big_sync.patch crypto-caam-guard-hmac-key-hex-dumps-in-hash_digest_key.patch crypto-nx-avoid-wflex-array-member-not-at-end-warning.patch crypto-nx-fix-bounce-buffer-leaks-in-nx842_crypto_-alloc-free-_ctx.patch crypto-nx-migrate-to-scomp-api.patch erofs-fix-unsigned-underflow-in-z_erofs_lz4_handle_overlap.patch fbcon-avoid-oob-font-access-if-console-rotation-fails.patch mm-hugetlb_cma-round-up-per_node-before-logging-it.patch net-ipv4-stop-checking-crypto_ahash_alignmask.patch net-ipv6-stop-checking-crypto_ahash_alignmask.patch net-stmmac-avoid-shadowing-global-buf_sz.patch net-stmmac-prevent-null-deref-when-rx-memory-exhausted.patch net-stmmac-rename-stmmac_get_entry-stmmac_next_entry.patch printk-add-print_hex_dump_devel.patch rxrpc-fix-conn-level-packet-handling-to-unshare-response-packets.patch spi-microchip-core-qspi-fix-controller-deregistration.patch spi-microchip-core-qspi-use-helper-function-devm_clk_get_enabled.patch spi-spi-ti-qspi-convert-to-platform-remove-callback-returning-void.patch spi-spi-ti-qspi-switch-to-use-modern-name.patch spi-sun4i-fix-controller-deregistration.patch spi-sun4i-switch-to-use-modern-name.patch spi-sun6i-fix-controller-deregistration.patch spi-sun6i-switch-to-use-modern-name.patch spi-syncuacer-fix-controller-deregistration.patch spi-synquacer-switch-to-use-modern-name.patch spi-tegra114-fix-controller-deregistration.patch spi-tegra20-sflash-fix-controller-deregistration.patch spi-ti-qspi-fix-controller-deregistration.patch spi-uniphier-fix-controller-deregistration.patch spi-uniphier-simplify-clock-handling-with-devm_clk_get_enabled.patch spi-uniphier-switch-to-use-modern-name.patch spi-zynq-qspi-fix-controller-deregistration.patch spi-zynq-qspi-simplify-clock-handling-with-devm_clk_get_enabled.patch spi-zynq-qspi-switch-to-use-modern-name.patch tracepoint-balance-regfunc-on-func_add-failure-in-tracepoint_add_func.patch xfrm-ah-account-for-esn-high-bits-in-async-callbacks.patch xfrm-defensively-unhash-xfrm_state-lists-in-__xfrm_state_delete.patch --- diff --git a/queue-6.6/alsa-core-serialize-deferred-fasync-state-checks.patch b/queue-6.6/alsa-core-serialize-deferred-fasync-state-checks.patch new file mode 100644 index 0000000000..0ccac42ce2 --- /dev/null +++ b/queue-6.6/alsa-core-serialize-deferred-fasync-state-checks.patch @@ -0,0 +1,64 @@ +From stable+bounces-246879-greg=kroah.com@vger.kernel.org Wed May 13 17:15:06 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 10:10:25 -0400 +Subject: ALSA: core: Serialize deferred fasync state checks +To: stable@vger.kernel.org +Cc: "Cássio Gabriel" , "Takashi Iwai" , "Sasha Levin" +Message-ID: <20260513141025.3748103-3-sashal@kernel.org> + +From: Cássio Gabriel + +[ Upstream commit 5337213381df578058e2e41da93cbd0e4639935f ] + +snd_fasync_helper() updates fasync->on under snd_fasync_lock, and +snd_fasync_work_fn() now also evaluates fasync->on under the same +lock. snd_kill_fasync() still tests the flag before taking the lock, +leaving an unsynchronized read against FASYNC enable/disable updates. + +Move the enabled-state check into the locked section. + +Also clear fasync->on under snd_fasync_lock in snd_fasync_free() +before unlinking the pending entry. Together with the locked sender-side +check, this publishes teardown before flushing the deferred work and +prevents a racing sender from requeueing the entry after free has +started. + +Fixes: ef34a0ae7a26 ("ALSA: core: Add async signal helpers") +Fixes: 8146cd333d23 ("ALSA: core: Fix potential data race at fasync handling") +Cc: stable@vger.kernel.org +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260506-alsa-core-fasync-on-lock-v1-1-ea48c77d6ca4@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + sound/core/misc.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/sound/core/misc.c ++++ b/sound/core/misc.c +@@ -219,9 +219,11 @@ EXPORT_SYMBOL_GPL(snd_fasync_helper); + + void snd_kill_fasync(struct snd_fasync *fasync, int signal, int poll) + { +- if (!fasync || !fasync->on) ++ if (!fasync) + return; + guard(spinlock_irqsave)(&snd_fasync_lock); ++ if (!fasync->on) ++ return; + fasync->signal = signal; + fasync->poll = poll; + list_move(&fasync->list, &snd_fasync_list); +@@ -234,8 +236,10 @@ void snd_fasync_free(struct snd_fasync * + if (!fasync) + return; + +- scoped_guard(spinlock_irq, &snd_fasync_lock) ++ scoped_guard(spinlock_irq, &snd_fasync_lock) { ++ fasync->on = 0; + list_del_init(&fasync->list); ++ } + + flush_work(&snd_fasync_work); + kfree(fasync); diff --git a/queue-6.6/alsa-hda-cs35l56-propagate-asp-tx-source-control-errors.patch b/queue-6.6/alsa-hda-cs35l56-propagate-asp-tx-source-control-errors.patch new file mode 100644 index 0000000000..197f6df872 --- /dev/null +++ b/queue-6.6/alsa-hda-cs35l56-propagate-asp-tx-source-control-errors.patch @@ -0,0 +1,76 @@ +From stable+bounces-246871-greg=kroah.com@vger.kernel.org Wed May 13 16:09:46 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 09:53:59 -0400 +Subject: ALSA: hda: cs35l56: Propagate ASP TX source control errors +To: stable@vger.kernel.org +Cc: "Cássio Gabriel" , "Richard Fitzgerald" , "Takashi Iwai" , "Sasha Levin" +Message-ID: <20260513135359.3741836-1-sashal@kernel.org> + +From: Cássio Gabriel + +[ Upstream commit 0faacc0841d66f3cf51989c10a83f3a82d52ff2c ] + +cs35l56_hda_mixer_get() ignores regmap_read() and +cs35l56_hda_mixer_put() ignores regmap_update_bits_check(). + +This makes the ASP TX source controls report success when a regmap +access fails. The write path returns no change instead of an error, +and the read path continues after a failed read instead of aborting +the control callback. + +Propagate the regmap errors, matching the posture and volume controls +in this driver. + +Fixes: 73cfbfa9caea ("ALSA: hda/cs35l56: Add driver for Cirrus Logic CS35L56 amplifier") +Cc: stable@vger.kernel.org +Signed-off-by: Cássio Gabriel +Reviewed-by: Richard Fitzgerald +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260423-alsa-cs35l56-asp-tx-source-errors-v1-1-17ea7c62ec31@gmail.com +[ adjusted path to sound/pci/hda/ and dropped cs35l56_hda_wait_dsp_ready() context ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + sound/pci/hda/cs35l56_hda.c | 19 ++++++++++++++----- + 1 file changed, 14 insertions(+), 5 deletions(-) + +--- a/sound/pci/hda/cs35l56_hda.c ++++ b/sound/pci/hda/cs35l56_hda.c +@@ -176,9 +176,13 @@ static int cs35l56_hda_mixer_get(struct + { + struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol); + unsigned int reg_val; +- int i; ++ int i, ret; ++ ++ ret = regmap_read(cs35l56->base.regmap, kcontrol->private_value, ++ ®_val); ++ if (ret) ++ return ret; + +- regmap_read(cs35l56->base.regmap, kcontrol->private_value, ®_val); + reg_val &= CS35L56_ASP_TXn_SRC_MASK; + + for (i = 0; i < CS35L56_NUM_INPUT_SRC; ++i) { +@@ -197,13 +201,18 @@ static int cs35l56_hda_mixer_put(struct + struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol); + unsigned int item = ucontrol->value.enumerated.item[0]; + bool changed; ++ int ret; + + if (item >= CS35L56_NUM_INPUT_SRC) + return -EINVAL; + +- regmap_update_bits_check(cs35l56->base.regmap, kcontrol->private_value, +- CS35L56_INPUT_MASK, cs35l56_tx_input_values[item], +- &changed); ++ ret = regmap_update_bits_check(cs35l56->base.regmap, ++ kcontrol->private_value, ++ CS35L56_INPUT_MASK, ++ cs35l56_tx_input_values[item], ++ &changed); ++ if (ret) ++ return ret; + + return changed; + } diff --git a/queue-6.6/alsa-misc-use-guard-for-spin-locks.patch b/queue-6.6/alsa-misc-use-guard-for-spin-locks.patch new file mode 100644 index 0000000000..81f47ca12f --- /dev/null +++ b/queue-6.6/alsa-misc-use-guard-for-spin-locks.patch @@ -0,0 +1,73 @@ +From stable+bounces-246877-greg=kroah.com@vger.kernel.org Wed May 13 16:24:43 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 10:10:23 -0400 +Subject: ALSA: misc: Use guard() for spin locks +To: stable@vger.kernel.org +Cc: Takashi Iwai , Sasha Levin +Message-ID: <20260513141025.3748103-1-sashal@kernel.org> + +From: Takashi Iwai + +[ Upstream commit b8e1684163ae52db90f428965bd9aaff7205c02e ] + +Clean up the code using guard() for spin locks. + +Merely code refactoring, and no behavior change. + +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20250829151335.7342-20-tiwai@suse.de +Stable-dep-of: 5337213381df ("ALSA: core: Serialize deferred fasync state checks") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + sound/core/misc.c | 25 ++++++++++--------------- + 1 file changed, 10 insertions(+), 15 deletions(-) + +--- a/sound/core/misc.c ++++ b/sound/core/misc.c +@@ -202,35 +202,30 @@ int snd_fasync_helper(int fd, struct fil + INIT_LIST_HEAD(&fasync->list); + } + +- spin_lock_irq(&snd_fasync_lock); +- if (*fasyncp) { +- kfree(fasync); +- fasync = *fasyncp; +- } else { +- if (!fasync) { +- spin_unlock_irq(&snd_fasync_lock); +- return 0; ++ scoped_guard(spinlock_irq, &snd_fasync_lock) { ++ if (*fasyncp) { ++ kfree(fasync); ++ fasync = *fasyncp; ++ } else { ++ if (!fasync) ++ return 0; ++ *fasyncp = fasync; + } +- *fasyncp = fasync; ++ fasync->on = on; + } +- fasync->on = on; +- spin_unlock_irq(&snd_fasync_lock); + return fasync_helper(fd, file, on, &fasync->fasync); + } + EXPORT_SYMBOL_GPL(snd_fasync_helper); + + void snd_kill_fasync(struct snd_fasync *fasync, int signal, int poll) + { +- unsigned long flags; +- + if (!fasync || !fasync->on) + return; +- spin_lock_irqsave(&snd_fasync_lock, flags); ++ guard(spinlock_irqsave)(&snd_fasync_lock); + fasync->signal = signal; + fasync->poll = poll; + list_move(&fasync->list, &snd_fasync_list); + schedule_work(&snd_fasync_work); +- spin_unlock_irqrestore(&snd_fasync_lock, flags); + } + EXPORT_SYMBOL_GPL(snd_kill_fasync); + diff --git a/queue-6.6/alsa-seq-fix-ump-group-16-filtering.patch b/queue-6.6/alsa-seq-fix-ump-group-16-filtering.patch new file mode 100644 index 0000000000..c5f1cb85cb --- /dev/null +++ b/queue-6.6/alsa-seq-fix-ump-group-16-filtering.patch @@ -0,0 +1,79 @@ +From stable+bounces-246886-greg=kroah.com@vger.kernel.org Wed May 13 16:39:59 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 10:34:30 -0400 +Subject: ALSA: seq: Fix UMP group 16 filtering +To: stable@vger.kernel.org +Cc: "Cássio Gabriel" , "Takashi Iwai" , "Sasha Levin" +Message-ID: <20260513143430.3755036-2-sashal@kernel.org> + +From: Cássio Gabriel + +[ Upstream commit 92429ca999db99febced82f23362a71b2ba4c1d8 ] + +The sequencer UAPI defines group_filter as an unsigned int bitmap. +Bit 0 filters groupless messages and bits 1-16 filter UMP groups 1-16. + +The internal snd_seq_client storage is only unsigned short, so bit 16 +is truncated when userspace sets the filter. The same truncation affects +the automatic UMP client filter used to avoid delivery to inactive +groups, so events for group 16 cannot be filtered. + +Store the internal bitmap as unsigned int and keep both userspace-provided +and automatically generated values limited to the defined UAPI bits. + +Fixes: d2b706077792 ("ALSA: seq: Add UMP group filter") +Cc: stable@vger.kernel.org +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260506-alsa-seq-ump-group16-filter-v1-1-b75160bf6993@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + sound/core/seq/seq_clientmgr.c | 2 +- + sound/core/seq/seq_clientmgr.h | 5 ++++- + sound/core/seq/seq_ump_client.c | 2 +- + 3 files changed, 6 insertions(+), 3 deletions(-) + +--- a/sound/core/seq/seq_clientmgr.c ++++ b/sound/core/seq/seq_clientmgr.c +@@ -1333,7 +1333,7 @@ static int snd_seq_ioctl_set_client_info + if (client->user_pversion >= SNDRV_PROTOCOL_VERSION(1, 0, 3)) + client->midi_version = client_info->midi_version; + memcpy(client->event_filter, client_info->event_filter, 32); +- client->group_filter = client_info->group_filter; ++ client->group_filter = client_info->group_filter & SND_SEQ_GROUP_FILTER_MASK; + + /* notify the change */ + snd_seq_system_client_ev_client_change(client->number); +--- a/sound/core/seq/seq_clientmgr.h ++++ b/sound/core/seq/seq_clientmgr.h +@@ -14,6 +14,9 @@ + + /* client manager */ + ++#define SND_SEQ_GROUP_FILTER_MASK GENMASK(SNDRV_UMP_MAX_GROUPS, 0) ++#define SND_SEQ_GROUP_FILTER_GROUPS GENMASK(SNDRV_UMP_MAX_GROUPS, 1) ++ + struct snd_seq_user_client { + struct file *file; /* file struct of client */ + /* ... */ +@@ -40,7 +43,7 @@ struct snd_seq_client { + int number; /* client number */ + unsigned int filter; /* filter flags */ + DECLARE_BITMAP(event_filter, 256); +- unsigned short group_filter; ++ unsigned int group_filter; + snd_use_lock_t use_lock; + int event_lost; + /* ports */ +--- a/sound/core/seq/seq_ump_client.c ++++ b/sound/core/seq/seq_ump_client.c +@@ -370,7 +370,7 @@ static void setup_client_group_filter(st + cptr = snd_seq_kernel_client_get(client->seq_client); + if (!cptr) + return; +- filter = ~(1U << 0); /* always allow groupless messages */ ++ filter = SND_SEQ_GROUP_FILTER_GROUPS; /* always allow groupless messages */ + for (p = 0; p < SNDRV_UMP_MAX_GROUPS; p++) { + if (client->ump->groups[p].active) + filter &= ~(1U << (p + 1)); diff --git a/queue-6.6/alsa-seq-notify-client-and-port-info-changes.patch b/queue-6.6/alsa-seq-notify-client-and-port-info-changes.patch new file mode 100644 index 0000000000..02fa2c263a --- /dev/null +++ b/queue-6.6/alsa-seq-notify-client-and-port-info-changes.patch @@ -0,0 +1,69 @@ +From stable+bounces-246885-greg=kroah.com@vger.kernel.org Wed May 13 16:41:06 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 10:34:29 -0400 +Subject: ALSA: seq: Notify client and port info changes +To: stable@vger.kernel.org +Cc: Takashi Iwai , Mark Lentczner , Sasha Levin +Message-ID: <20260513143430.3755036-1-sashal@kernel.org> + +From: Takashi Iwai + +[ Upstream commit b8e49e24cdba27a0810a0988e810e2c68f2033cb ] + +It was supposed to be notified when a sequencer client info and a port +info has changed (via SNDRV_SEQ_EVENT_CLIENT_CHANGE and +SNDRV_SEQ_EVENT_PORT_CHANGE event, respectively), and there are +already helper functions. But those aren't really sent from the +driver so far, except for the recent support of UMP, simply due to the +lack of implementations. + +This patch adds the missing notifications at updating the client and +the port info. The formerly added notification for UMP is dropped +because it's handled now in the port info side. + +Reported-by: Mark Lentczner +Link: https://lore.kernel.org/CAPnksqRok7xGa4bxq9WWimVV=28-7_j628OmrWLS=S0=hzaTHQ@mail.gmail.com +Link: https://patch.msgid.link/20241128074734.32165-1-tiwai@suse.de +Signed-off-by: Takashi Iwai +Stable-dep-of: 92429ca999db ("ALSA: seq: Fix UMP group 16 filtering") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + sound/core/seq/seq_clientmgr.c | 7 +++++++ + sound/core/seq/seq_ump_client.c | 2 -- + 2 files changed, 7 insertions(+), 2 deletions(-) + +--- a/sound/core/seq/seq_clientmgr.c ++++ b/sound/core/seq/seq_clientmgr.c +@@ -1334,6 +1334,10 @@ static int snd_seq_ioctl_set_client_info + client->midi_version = client_info->midi_version; + memcpy(client->event_filter, client_info->event_filter, 32); + client->group_filter = client_info->group_filter; ++ ++ /* notify the change */ ++ snd_seq_system_client_ev_client_change(client->number); ++ + return 0; + } + +@@ -1457,6 +1461,9 @@ static int snd_seq_ioctl_set_port_info(s + if (port) { + snd_seq_set_port_info(port, info); + snd_seq_port_unlock(port); ++ /* notify the change */ ++ snd_seq_system_client_ev_port_change(info->addr.client, ++ info->addr.port); + } + return 0; + } +--- a/sound/core/seq/seq_ump_client.c ++++ b/sound/core/seq/seq_ump_client.c +@@ -273,8 +273,6 @@ static void update_port_infos(struct seq + new); + if (err < 0) + continue; +- /* notify to system port */ +- snd_seq_system_client_ev_port_change(client->seq_client, i); + } + } + diff --git a/queue-6.6/bluetooth-hci_conn-fix-potential-uaf-in-create_big_sync.patch b/queue-6.6/bluetooth-hci_conn-fix-potential-uaf-in-create_big_sync.patch new file mode 100644 index 0000000000..4bb47ebbb1 --- /dev/null +++ b/queue-6.6/bluetooth-hci_conn-fix-potential-uaf-in-create_big_sync.patch @@ -0,0 +1,96 @@ +From stable+bounces-246967-greg=kroah.com@vger.kernel.org Wed May 13 19:49:43 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 13:31:46 -0400 +Subject: Bluetooth: hci_conn: fix potential UAF in create_big_sync +To: stable@vger.kernel.org +Cc: David Carlier , Luiz Augusto von Dentz , Sasha Levin +Message-ID: <20260513173146.3885958-1-sashal@kernel.org> + +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(-) + +--- a/net/bluetooth/hci_conn.c ++++ b/net/bluetooth/hci_conn.c +@@ -2014,6 +2014,9 @@ static int create_big_sync(struct hci_de + 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; + +@@ -2125,11 +2128,24 @@ static void create_big_complete(struct h + + 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, +@@ -2230,10 +2246,11 @@ struct hci_conn *hci_connect_bis(struct + 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); + } + diff --git a/queue-6.6/crypto-caam-guard-hmac-key-hex-dumps-in-hash_digest_key.patch b/queue-6.6/crypto-caam-guard-hmac-key-hex-dumps-in-hash_digest_key.patch new file mode 100644 index 0000000000..83e15071fc --- /dev/null +++ b/queue-6.6/crypto-caam-guard-hmac-key-hex-dumps-in-hash_digest_key.patch @@ -0,0 +1,68 @@ +From stable+bounces-245016-greg=kroah.com@vger.kernel.org Sun May 10 15:15:17 2026 +From: Sasha Levin +Date: Sun, 10 May 2026 09:15:08 -0400 +Subject: crypto: caam - guard HMAC key hex dumps in hash_digest_key +To: stable@vger.kernel.org +Cc: Thorsten Blum , Herbert Xu , Sasha Levin +Message-ID: <20260510131508.4113857-2-sashal@kernel.org> + +From: Thorsten Blum + +[ Upstream commit 177730a273b18e195263ed953853273e901b5064 ] + +Use print_hex_dump_devel() for dumping sensitive HMAC key bytes in +hash_digest_key() to avoid leaking secrets at runtime when +CONFIG_DYNAMIC_DEBUG is enabled. + +Fixes: 045e36780f11 ("crypto: caam - ahash hmac support") +Fixes: 3f16f6c9d632 ("crypto: caam/qi2 - add support for ahash algorithms") +Cc: stable@vger.kernel.org +Signed-off-by: Thorsten Blum +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/crypto/caam/caamalg_qi2.c | 4 ++-- + drivers/crypto/caam/caamhash.c | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/crypto/caam/caamalg_qi2.c ++++ b/drivers/crypto/caam/caamalg_qi2.c +@@ -3268,7 +3268,7 @@ static int hash_digest_key(struct caam_h + dpaa2_fl_set_addr(out_fle, key_dma); + dpaa2_fl_set_len(out_fle, digestsize); + +- print_hex_dump_debug("key_in@" __stringify(__LINE__)": ", ++ print_hex_dump_devel("key_in@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, *keylen, 1); + print_hex_dump_debug("shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), +@@ -3288,7 +3288,7 @@ static int hash_digest_key(struct caam_h + /* in progress */ + wait_for_completion(&result.completion); + ret = result.err; +- print_hex_dump_debug("digested key@" __stringify(__LINE__)": ", ++ print_hex_dump_devel("digested key@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, + digestsize, 1); + } +--- a/drivers/crypto/caam/caamhash.c ++++ b/drivers/crypto/caam/caamhash.c +@@ -393,7 +393,7 @@ static int hash_digest_key(struct caam_h + append_seq_store(desc, digestsize, LDST_CLASS_2_CCB | + LDST_SRCDST_BYTE_CONTEXT); + +- print_hex_dump_debug("key_in@"__stringify(__LINE__)": ", ++ print_hex_dump_devel("key_in@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, *keylen, 1); + print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), +@@ -408,7 +408,7 @@ static int hash_digest_key(struct caam_h + wait_for_completion(&result.completion); + ret = result.err; + +- print_hex_dump_debug("digested key@"__stringify(__LINE__)": ", ++ print_hex_dump_devel("digested key@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, + digestsize, 1); + } diff --git a/queue-6.6/crypto-nx-avoid-wflex-array-member-not-at-end-warning.patch b/queue-6.6/crypto-nx-avoid-wflex-array-member-not-at-end-warning.patch new file mode 100644 index 0000000000..c6195eeb40 --- /dev/null +++ b/queue-6.6/crypto-nx-avoid-wflex-array-member-not-at-end-warning.patch @@ -0,0 +1,120 @@ +From stable+bounces-244898-greg=kroah.com@vger.kernel.org Sat May 9 05:31:56 2026 +From: Sasha Levin +Date: Fri, 8 May 2026 23:31:48 -0400 +Subject: crypto: nx - Avoid -Wflex-array-member-not-at-end warning +To: stable@vger.kernel.org +Cc: "Gustavo A. R. Silva" , Herbert Xu , Sasha Levin +Message-ID: <20260509033150.3082044-1-sashal@kernel.org> + +From: "Gustavo A. R. Silva" + +[ Upstream commit 1e6b251ce1759392666856908113dd5d7cea044d ] + +-Wflex-array-member-not-at-end is coming in GCC-14, and we are getting +ready to enable it globally. So, we are deprecating flexible-array +members in the middle of another structure. + +There is currently an object (`header`) in `struct nx842_crypto_ctx` +that contains a flexible structure (`struct nx842_crypto_header`): + +struct nx842_crypto_ctx { + ... + struct nx842_crypto_header header; + struct nx842_crypto_header_group group[NX842_CRYPTO_GROUP_MAX]; + ... +}; + +So, in order to avoid ending up with a flexible-array member in the +middle of another struct, we use the `struct_group_tagged()` helper to +separate the flexible array from the rest of the members in the flexible +structure: + +struct nx842_crypto_header { + struct_group_tagged(nx842_crypto_header_hdr, hdr, + + ... the rest of the members + + ); + struct nx842_crypto_header_group group[]; +} __packed; + +With the change described above, we can now declare an object of the +type of the tagged struct, without embedding the flexible array in the +middle of another struct: + +struct nx842_crypto_ctx { + ... + struct nx842_crypto_header_hdr header; + struct nx842_crypto_header_group group[NX842_CRYPTO_GROUP_MAX]; + ... + } __packed; + +We also use `container_of()` whenever we need to retrieve a pointer to +the flexible structure, through which we can access the flexible +array if needed. + +So, with these changes, fix the following warning: + +In file included from drivers/crypto/nx/nx-842.c:55: +drivers/crypto/nx/nx-842.h:174:36: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end] + 174 | struct nx842_crypto_header header; + | ^~~~~~ + +Signed-off-by: Gustavo A. R. Silva +Signed-off-by: Herbert Xu +Stable-dep-of: adb3faf2db1a ("crypto: nx - fix bounce buffer leaks in nx842_crypto_{alloc,free}_ctx") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/crypto/nx/nx-842.c | 6 ++++-- + drivers/crypto/nx/nx-842.h | 10 ++++++---- + 2 files changed, 10 insertions(+), 6 deletions(-) + +--- a/drivers/crypto/nx/nx-842.c ++++ b/drivers/crypto/nx/nx-842.c +@@ -251,7 +251,9 @@ int nx842_crypto_compress(struct crypto_ + u8 *dst, unsigned int *dlen) + { + struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); +- struct nx842_crypto_header *hdr = &ctx->header; ++ struct nx842_crypto_header *hdr = ++ container_of(&ctx->header, ++ struct nx842_crypto_header, hdr); + struct nx842_crypto_param p; + struct nx842_constraints c = *ctx->driver->constraints; + unsigned int groups, hdrsize, h; +@@ -490,7 +492,7 @@ int nx842_crypto_decompress(struct crypt + } + + memcpy(&ctx->header, src, hdr_len); +- hdr = &ctx->header; ++ hdr = container_of(&ctx->header, struct nx842_crypto_header, hdr); + + for (n = 0; n < hdr->groups; n++) { + /* ignore applies to last group */ +--- a/drivers/crypto/nx/nx-842.h ++++ b/drivers/crypto/nx/nx-842.h +@@ -157,9 +157,11 @@ struct nx842_crypto_header_group { + } __packed; + + struct nx842_crypto_header { +- __be16 magic; /* NX842_CRYPTO_MAGIC */ +- __be16 ignore; /* decompressed end bytes to ignore */ +- u8 groups; /* total groups in this header */ ++ struct_group_tagged(nx842_crypto_header_hdr, hdr, ++ __be16 magic; /* NX842_CRYPTO_MAGIC */ ++ __be16 ignore; /* decompressed end bytes to ignore */ ++ u8 groups; /* total groups in this header */ ++ ); + struct nx842_crypto_header_group group[]; + } __packed; + +@@ -171,7 +173,7 @@ struct nx842_crypto_ctx { + u8 *wmem; + u8 *sbounce, *dbounce; + +- struct nx842_crypto_header header; ++ struct nx842_crypto_header_hdr header; + struct nx842_crypto_header_group group[NX842_CRYPTO_GROUP_MAX]; + + struct nx842_driver *driver; diff --git a/queue-6.6/crypto-nx-fix-bounce-buffer-leaks-in-nx842_crypto_-alloc-free-_ctx.patch b/queue-6.6/crypto-nx-fix-bounce-buffer-leaks-in-nx842_crypto_-alloc-free-_ctx.patch new file mode 100644 index 0000000000..7161948aee --- /dev/null +++ b/queue-6.6/crypto-nx-fix-bounce-buffer-leaks-in-nx842_crypto_-alloc-free-_ctx.patch @@ -0,0 +1,51 @@ +From stable+bounces-244900-greg=kroah.com@vger.kernel.org Sat May 9 05:31:58 2026 +From: Sasha Levin +Date: Fri, 8 May 2026 23:31:50 -0400 +Subject: crypto: nx - fix bounce buffer leaks in nx842_crypto_{alloc,free}_ctx +To: stable@vger.kernel.org +Cc: Thorsten Blum , Herbert Xu , Sasha Levin +Message-ID: <20260509033150.3082044-3-sashal@kernel.org> + +From: Thorsten Blum + +[ Upstream commit adb3faf2db1a66d0f015b44ac909a32dfc7f2f9c ] + +The bounce buffers are allocated with __get_free_pages() using +BOUNCE_BUFFER_ORDER (order 2 = 4 pages), but both the allocation error +path and nx842_crypto_free_ctx() release the buffers with free_page(). +Use free_pages() with the matching order instead. + +Fixes: ed70b479c2c0 ("crypto: nx - add hardware 842 crypto comp alg") +Cc: stable@vger.kernel.org +Signed-off-by: Thorsten Blum +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/crypto/nx/nx-842.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/crypto/nx/nx-842.c ++++ b/drivers/crypto/nx/nx-842.c +@@ -116,8 +116,8 @@ void *nx842_crypto_alloc_ctx(struct nx84 + ctx->dbounce = (u8 *)__get_free_pages(GFP_KERNEL, BOUNCE_BUFFER_ORDER); + if (!ctx->wmem || !ctx->sbounce || !ctx->dbounce) { + kfree(ctx->wmem); +- free_page((unsigned long)ctx->sbounce); +- free_page((unsigned long)ctx->dbounce); ++ free_pages((unsigned long)ctx->sbounce, BOUNCE_BUFFER_ORDER); ++ free_pages((unsigned long)ctx->dbounce, BOUNCE_BUFFER_ORDER); + kfree(ctx); + return ERR_PTR(-ENOMEM); + } +@@ -131,8 +131,8 @@ void nx842_crypto_free_ctx(void *p) + struct nx842_crypto_ctx *ctx = p; + + kfree(ctx->wmem); +- free_page((unsigned long)ctx->sbounce); +- free_page((unsigned long)ctx->dbounce); ++ free_pages((unsigned long)ctx->sbounce, BOUNCE_BUFFER_ORDER); ++ free_pages((unsigned long)ctx->dbounce, BOUNCE_BUFFER_ORDER); + } + EXPORT_SYMBOL_GPL(nx842_crypto_free_ctx); + diff --git a/queue-6.6/crypto-nx-migrate-to-scomp-api.patch b/queue-6.6/crypto-nx-migrate-to-scomp-api.patch new file mode 100644 index 0000000000..6dadaa834b --- /dev/null +++ b/queue-6.6/crypto-nx-migrate-to-scomp-api.patch @@ -0,0 +1,287 @@ +From stable+bounces-244899-greg=kroah.com@vger.kernel.org Sat May 9 05:31:59 2026 +From: Sasha Levin +Date: Fri, 8 May 2026 23:31:49 -0400 +Subject: crypto: nx - Migrate to scomp API +To: stable@vger.kernel.org +Cc: Ard Biesheuvel , Herbert Xu , Sasha Levin +Message-ID: <20260509033150.3082044-2-sashal@kernel.org> + +From: Ard Biesheuvel + +[ Upstream commit 980b5705f4e73f567e405cd18337cc32fd51cf79 ] + +The only remaining user of 842 compression has been migrated to the +acomp compression API, and so the NX hardware driver has to follow suit, +given that no users of the obsolete 'comp' API remain, and it is going +to be removed. + +So migrate the NX driver code to scomp. These will be wrapped and +exposed as acomp implementation via the crypto subsystem's +acomp-to-scomp adaptation layer. + +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Stable-dep-of: adb3faf2db1a ("crypto: nx - fix bounce buffer leaks in nx842_crypto_{alloc,free}_ctx") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/crypto/nx/nx-842.c | 33 +++++++++++++++++++-------------- + drivers/crypto/nx/nx-842.h | 15 ++++++++------- + drivers/crypto/nx/nx-common-powernv.c | 31 +++++++++++++++---------------- + drivers/crypto/nx/nx-common-pseries.c | 33 ++++++++++++++++----------------- + 4 files changed, 58 insertions(+), 54 deletions(-) + +--- a/drivers/crypto/nx/nx-842.c ++++ b/drivers/crypto/nx/nx-842.c +@@ -101,9 +101,13 @@ static int update_param(struct nx842_cry + return 0; + } + +-int nx842_crypto_init(struct crypto_tfm *tfm, struct nx842_driver *driver) ++void *nx842_crypto_alloc_ctx(struct nx842_driver *driver) + { +- struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); ++ struct nx842_crypto_ctx *ctx; ++ ++ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); ++ if (!ctx) ++ return ERR_PTR(-ENOMEM); + + spin_lock_init(&ctx->lock); + ctx->driver = driver; +@@ -114,22 +118,23 @@ int nx842_crypto_init(struct crypto_tfm + kfree(ctx->wmem); + free_page((unsigned long)ctx->sbounce); + free_page((unsigned long)ctx->dbounce); +- return -ENOMEM; ++ kfree(ctx); ++ return ERR_PTR(-ENOMEM); + } + +- return 0; ++ return ctx; + } +-EXPORT_SYMBOL_GPL(nx842_crypto_init); ++EXPORT_SYMBOL_GPL(nx842_crypto_alloc_ctx); + +-void nx842_crypto_exit(struct crypto_tfm *tfm) ++void nx842_crypto_free_ctx(void *p) + { +- struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); ++ struct nx842_crypto_ctx *ctx = p; + + kfree(ctx->wmem); + free_page((unsigned long)ctx->sbounce); + free_page((unsigned long)ctx->dbounce); + } +-EXPORT_SYMBOL_GPL(nx842_crypto_exit); ++EXPORT_SYMBOL_GPL(nx842_crypto_free_ctx); + + static void check_constraints(struct nx842_constraints *c) + { +@@ -246,11 +251,11 @@ nospc: + return update_param(p, slen, dskip + dlen); + } + +-int nx842_crypto_compress(struct crypto_tfm *tfm, ++int nx842_crypto_compress(struct crypto_scomp *tfm, + const u8 *src, unsigned int slen, +- u8 *dst, unsigned int *dlen) ++ u8 *dst, unsigned int *dlen, void *pctx) + { +- struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); ++ struct nx842_crypto_ctx *ctx = pctx; + struct nx842_crypto_header *hdr = + container_of(&ctx->header, + struct nx842_crypto_header, hdr); +@@ -431,11 +436,11 @@ usesw: + return update_param(p, slen + padding, dlen); + } + +-int nx842_crypto_decompress(struct crypto_tfm *tfm, ++int nx842_crypto_decompress(struct crypto_scomp *tfm, + const u8 *src, unsigned int slen, +- u8 *dst, unsigned int *dlen) ++ u8 *dst, unsigned int *dlen, void *pctx) + { +- struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); ++ struct nx842_crypto_ctx *ctx = pctx; + struct nx842_crypto_header *hdr; + struct nx842_crypto_param p; + struct nx842_constraints c = *ctx->driver->constraints; +--- a/drivers/crypto/nx/nx-842.h ++++ b/drivers/crypto/nx/nx-842.h +@@ -3,7 +3,6 @@ + #ifndef __NX_842_H__ + #define __NX_842_H__ + +-#include + #include + #include + #include +@@ -101,6 +100,8 @@ + #define LEN_ON_SIZE(pa, size) ((size) - ((pa) & ((size) - 1))) + #define LEN_ON_PAGE(pa) LEN_ON_SIZE(pa, PAGE_SIZE) + ++struct crypto_scomp; ++ + static inline unsigned long nx842_get_pa(void *addr) + { + if (!is_vmalloc_addr(addr)) +@@ -179,13 +180,13 @@ struct nx842_crypto_ctx { + struct nx842_driver *driver; + }; + +-int nx842_crypto_init(struct crypto_tfm *tfm, struct nx842_driver *driver); +-void nx842_crypto_exit(struct crypto_tfm *tfm); +-int nx842_crypto_compress(struct crypto_tfm *tfm, ++void *nx842_crypto_alloc_ctx(struct nx842_driver *driver); ++void nx842_crypto_free_ctx(void *ctx); ++int nx842_crypto_compress(struct crypto_scomp *tfm, + const u8 *src, unsigned int slen, +- u8 *dst, unsigned int *dlen); +-int nx842_crypto_decompress(struct crypto_tfm *tfm, ++ u8 *dst, unsigned int *dlen, void *ctx); ++int nx842_crypto_decompress(struct crypto_scomp *tfm, + const u8 *src, unsigned int slen, +- u8 *dst, unsigned int *dlen); ++ u8 *dst, unsigned int *dlen, void *ctx); + + #endif /* __NX_842_H__ */ +--- a/drivers/crypto/nx/nx-common-powernv.c ++++ b/drivers/crypto/nx/nx-common-powernv.c +@@ -9,6 +9,7 @@ + + #include "nx-842.h" + ++#include + #include + + #include +@@ -1031,23 +1032,21 @@ static struct nx842_driver nx842_powernv + .decompress = nx842_powernv_decompress, + }; + +-static int nx842_powernv_crypto_init(struct crypto_tfm *tfm) ++static void *nx842_powernv_crypto_alloc_ctx(void) + { +- return nx842_crypto_init(tfm, &nx842_powernv_driver); ++ return nx842_crypto_alloc_ctx(&nx842_powernv_driver); + } + +-static struct crypto_alg nx842_powernv_alg = { +- .cra_name = "842", +- .cra_driver_name = "842-nx", +- .cra_priority = 300, +- .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, +- .cra_ctxsize = sizeof(struct nx842_crypto_ctx), +- .cra_module = THIS_MODULE, +- .cra_init = nx842_powernv_crypto_init, +- .cra_exit = nx842_crypto_exit, +- .cra_u = { .compress = { +- .coa_compress = nx842_crypto_compress, +- .coa_decompress = nx842_crypto_decompress } } ++static struct scomp_alg nx842_powernv_alg = { ++ .base.cra_name = "842", ++ .base.cra_driver_name = "842-nx", ++ .base.cra_priority = 300, ++ .base.cra_module = THIS_MODULE, ++ ++ .alloc_ctx = nx842_powernv_crypto_alloc_ctx, ++ .free_ctx = nx842_crypto_free_ctx, ++ .compress = nx842_crypto_compress, ++ .decompress = nx842_crypto_decompress, + }; + + static __init int nx_compress_powernv_init(void) +@@ -1107,7 +1106,7 @@ static __init int nx_compress_powernv_in + nx842_powernv_exec = nx842_exec_vas; + } + +- ret = crypto_register_alg(&nx842_powernv_alg); ++ ret = crypto_register_scomp(&nx842_powernv_alg); + if (ret) { + nx_delete_coprocs(); + return ret; +@@ -1128,7 +1127,7 @@ static void __exit nx_compress_powernv_e + if (!nx842_ct) + vas_unregister_api_powernv(); + +- crypto_unregister_alg(&nx842_powernv_alg); ++ crypto_unregister_scomp(&nx842_powernv_alg); + + nx_delete_coprocs(); + } +--- a/drivers/crypto/nx/nx-common-pseries.c ++++ b/drivers/crypto/nx/nx-common-pseries.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + #include "nx-842.h" + #include "nx_csbcpb.h" /* struct nx_csbcpb */ +@@ -1008,23 +1009,21 @@ static struct nx842_driver nx842_pseries + .decompress = nx842_pseries_decompress, + }; + +-static int nx842_pseries_crypto_init(struct crypto_tfm *tfm) ++static void *nx842_pseries_crypto_alloc_ctx(void) + { +- return nx842_crypto_init(tfm, &nx842_pseries_driver); ++ return nx842_crypto_alloc_ctx(&nx842_pseries_driver); + } + +-static struct crypto_alg nx842_pseries_alg = { +- .cra_name = "842", +- .cra_driver_name = "842-nx", +- .cra_priority = 300, +- .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, +- .cra_ctxsize = sizeof(struct nx842_crypto_ctx), +- .cra_module = THIS_MODULE, +- .cra_init = nx842_pseries_crypto_init, +- .cra_exit = nx842_crypto_exit, +- .cra_u = { .compress = { +- .coa_compress = nx842_crypto_compress, +- .coa_decompress = nx842_crypto_decompress } } ++static struct scomp_alg nx842_pseries_alg = { ++ .base.cra_name = "842", ++ .base.cra_driver_name = "842-nx", ++ .base.cra_priority = 300, ++ .base.cra_module = THIS_MODULE, ++ ++ .alloc_ctx = nx842_pseries_crypto_alloc_ctx, ++ .free_ctx = nx842_crypto_free_ctx, ++ .compress = nx842_crypto_compress, ++ .decompress = nx842_crypto_decompress, + }; + + static int nx842_probe(struct vio_dev *viodev, +@@ -1072,7 +1071,7 @@ static int nx842_probe(struct vio_dev *v + if (ret) + goto error; + +- ret = crypto_register_alg(&nx842_pseries_alg); ++ ret = crypto_register_scomp(&nx842_pseries_alg); + if (ret) { + dev_err(&viodev->dev, "could not register comp alg: %d\n", ret); + goto error; +@@ -1120,7 +1119,7 @@ static void nx842_remove(struct vio_dev + if (caps_feat) + sysfs_remove_group(&viodev->dev.kobj, &nxcop_caps_attr_group); + +- crypto_unregister_alg(&nx842_pseries_alg); ++ crypto_unregister_scomp(&nx842_pseries_alg); + + spin_lock_irqsave(&devdata_mutex, flags); + old_devdata = rcu_dereference_check(devdata, +@@ -1252,7 +1251,7 @@ static void __exit nx842_pseries_exit(vo + + vas_unregister_api_pseries(); + +- crypto_unregister_alg(&nx842_pseries_alg); ++ crypto_unregister_scomp(&nx842_pseries_alg); + + spin_lock_irqsave(&devdata_mutex, flags); + old_devdata = rcu_dereference_check(devdata, diff --git a/queue-6.6/erofs-fix-unsigned-underflow-in-z_erofs_lz4_handle_overlap.patch b/queue-6.6/erofs-fix-unsigned-underflow-in-z_erofs_lz4_handle_overlap.patch new file mode 100644 index 0000000000..4788b53a6f --- /dev/null +++ b/queue-6.6/erofs-fix-unsigned-underflow-in-z_erofs_lz4_handle_overlap.patch @@ -0,0 +1,58 @@ +From stable+bounces-244910-greg=kroah.com@vger.kernel.org Sat May 9 05:54:40 2026 +From: Sasha Levin +Date: Fri, 8 May 2026 23:54:21 -0400 +Subject: erofs: fix unsigned underflow in z_erofs_lz4_handle_overlap() +To: stable@vger.kernel.org +Cc: Junrui Luo , Yuhao Jiang , Gao Xiang , Sasha Levin +Message-ID: <20260509035421.3122562-1-sashal@kernel.org> + +From: Junrui Luo + +[ Upstream commit 21e161de2dc660b1bb70ef5b156ab8e6e1cca3ab ] + +Some crafted images can have illegal (!partial_decoding && +m_llen < m_plen) extents, and the LZ4 inplace decompression path +can be wrongly hit, but it cannot handle (outpages < inpages) +properly: "outpages - inpages" wraps to a large value and +the subsequent rq->out[] access reads past the decompressed_pages +array. + +However, such crafted cases can correctly result in a corruption +report in the normal LZ4 non-inplace path. + +Let's add an additional check to fix this for backporting. + +Reproducible image (base64-encoded gzipped blob): + +H4sIAJGR12kCA+3SPUoDQRgG4MkmkkZk8QRbRFIIi9hbpEjrHQI5ghfwCN5BLCzTGtLbBI+g +dilSJo1CnIm7GEXFxhT6PDDwfrs73/ywIQD/1ePD4r7Ou6ETsrq4mu7XcWfj++Pb58nJU/9i +PNtbjhan04/9GtX4qVYc814WDqt6FaX5s+ZwXXeq52lndT6IuVvlblytLMvh4Gzwaf90nsvz +2DF/21+20T/ldgp5s1jXRaN4t/8izsy/OUB6e/Qa79r+JwAAAAAAAL52vQVuGQAAAP6+my1w +ywAAAAAAAADwu14ATsEYtgBQAAA= + +$ mount -t erofs -o cache_strategy=disabled foo.erofs /mnt +$ dd if=/mnt/data of=/dev/null bs=4096 count=1 + +Fixes: 598162d05080 ("erofs: support decompress big pcluster for lz4 backend") +Reported-by: Yuhao Jiang +Cc: stable@vger.kernel.org +Signed-off-by: Junrui Luo +Reviewed-by: Gao Xiang +Signed-off-by: Gao Xiang +[ inverted condition to early-out `goto docopy` form and used `ctx->inpages`/`ctx->outpages` instead of `rq->` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/erofs/decompressor.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/erofs/decompressor.c ++++ b/fs/erofs/decompressor.c +@@ -133,6 +133,7 @@ static void *z_erofs_lz4_handle_overlap( + if (rq->inplace_io) { + omargin = PAGE_ALIGN(ctx->oend) - ctx->oend; + if (rq->partial_decoding || !may_inplace || ++ ctx->outpages < ctx->inpages || + omargin < LZ4_DECOMPRESS_INPLACE_MARGIN(rq->inputsize)) + goto docopy; + diff --git a/queue-6.6/fbcon-avoid-oob-font-access-if-console-rotation-fails.patch b/queue-6.6/fbcon-avoid-oob-font-access-if-console-rotation-fails.patch new file mode 100644 index 0000000000..cca15144e1 --- /dev/null +++ b/queue-6.6/fbcon-avoid-oob-font-access-if-console-rotation-fails.patch @@ -0,0 +1,56 @@ +From stable+bounces-247304-greg=kroah.com@vger.kernel.org Fri May 15 03:30:44 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 21:26:17 -0400 +Subject: fbcon: Avoid OOB font access if console rotation fails +To: stable@vger.kernel.org +Cc: Thomas Zimmermann , Helge Deller , Sasha Levin +Message-ID: <20260515012617.2652194-1-sashal@kernel.org> + +From: Thomas Zimmermann + +[ Upstream commit e4ef723d8975a2694cc90733a6b888a5e2841842 ] + +Clear the font buffer if the reallocation during console rotation fails +in fbcon_rotate_font(). The putcs implementations for the rotated buffer +will return early in this case. See [1] for an example. + +Currently, fbcon_rotate_font() keeps the old buffer, which is too small +for the rotated font. Printing to the rotated console with a high-enough +character code will overflow the font buffer. + +v2: +- fix typos in commit message + +Signed-off-by: Thomas Zimmermann +Fixes: 6cc50e1c5b57 ("[PATCH] fbcon: Console Rotation - Add support to rotate font bitmap") +Cc: stable@vger.kernel.org # v2.6.15+ +Link: https://elixir.bootlin.com/linux/v6.19/source/drivers/video/fbdev/core/fbcon_ccw.c#L144 # [1] +Signed-off-by: Helge Deller +[ renamed `par` to `ops` to match the 6.12 local pointer name ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/video/fbdev/core/fbcon_rotate.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/video/fbdev/core/fbcon_rotate.c ++++ b/drivers/video/fbdev/core/fbcon_rotate.c +@@ -46,6 +46,10 @@ static int fbcon_rotate_font(struct fb_i + info->fbops->fb_sync(info); + + if (ops->fd_size < d_cellsize * len) { ++ kfree(ops->fontbuffer); ++ ops->fontbuffer = NULL; ++ ops->fd_size = 0; ++ + dst = kmalloc_array(len, d_cellsize, GFP_KERNEL); + + if (dst == NULL) { +@@ -54,7 +58,6 @@ static int fbcon_rotate_font(struct fb_i + } + + ops->fd_size = d_cellsize * len; +- kfree(ops->fontbuffer); + ops->fontbuffer = dst; + } + diff --git a/queue-6.6/mm-hugetlb_cma-round-up-per_node-before-logging-it.patch b/queue-6.6/mm-hugetlb_cma-round-up-per_node-before-logging-it.patch new file mode 100644 index 0000000000..42d4dd4b07 --- /dev/null +++ b/queue-6.6/mm-hugetlb_cma-round-up-per_node-before-logging-it.patch @@ -0,0 +1,79 @@ +From stable+bounces-247201-greg=kroah.com@vger.kernel.org Thu May 14 15:07:38 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 09:06:35 -0400 +Subject: mm/hugetlb_cma: round up per_node before logging it +To: stable@vger.kernel.org +Cc: Sang-Heon Jeon , Muchun Song , David Hildenbrand , Oscar Salvador , Andrew Morton , Sasha Levin +Message-ID: <20260514130635.228150-1-sashal@kernel.org> + +From: Sang-Heon Jeon + +[ Upstream commit 8f5ce56b76303c55b78a87af996e2e0f8535f979 ] + +When the user requests a total hugetlb CMA size without per-node +specification, hugetlb_cma_reserve() computes per_node from +hugetlb_cma_size and the number of nodes that have memory + + per_node = DIV_ROUND_UP(hugetlb_cma_size, + nodes_weight(hugetlb_bootmem_nodes)); + +The reservation loop later computes + + size = round_up(min(per_node, hugetlb_cma_size - reserved), + PAGE_SIZE << order); + +So the actually reserved per_node size is multiple of (PAGE_SIZE << +order), but the logged per_node is not rounded up, so it may be smaller +than the actual reserved size. + +For example, as the existing comment describes, if a 3 GB area is +requested on a machine with 4 NUMA nodes that have memory, 1 GB is +allocated on the first three nodes, but the printed log is + + hugetlb_cma: reserve 3072 MiB, up to 768 MiB per node + +Round per_node up to (PAGE_SIZE << order) before logging so that the +printed log always matches the actual reserved size. No functional change +to the actual reservation size, as the following case analysis shows + +1. remaining (hugetlb_cma_size - reserved) >= rounded per_node + - AS-IS: min() picks unrounded per_node; + round_up() returns rounded per_node + - TO-BE: min() picks rounded per_node; + round_up() returns rounded per_node (no-op) +2. remaining < unrounded per_node + - AS-IS: min() picks remaining; + round_up() returns round_up(remaining) + - TO-BE: min() picks remaining; + round_up() returns round_up(remaining) +3. unrounded per_node <= remaining < rounded per_node + - AS-IS: min() picks unrounded per_node; + round_up() returns rounded per_node + - TO-BE: min() picks remaining; + round_up() returns round_up(remaining) equals rounded per_node + +Link: https://lore.kernel.org/20260422143353.852257-1-ekffu200098@gmail.com +Fixes: cf11e85fc08c ("mm: hugetlb: optionally allocate gigantic hugepages using cma") # 5.7 +Signed-off-by: Sang-Heon Jeon +Reviewed-by: Muchun Song +Cc: David Hildenbrand +Cc: Oscar Salvador +Cc: +Signed-off-by: Andrew Morton +[ applied the single-line addition to mm/hugetlb.c since mm/hugetlb_cma.c didn't exist yet in 6.12 ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + mm/hugetlb.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -7493,6 +7493,7 @@ void __init hugetlb_cma_reserve(int orde + * let's allocate 1 GB on first three nodes and ignore the last one. + */ + per_node = DIV_ROUND_UP(hugetlb_cma_size, nr_online_nodes); ++ per_node = round_up(per_node, PAGE_SIZE << order); + pr_info("hugetlb_cma: reserve %lu MiB, up to %lu MiB per node\n", + hugetlb_cma_size / SZ_1M, per_node / SZ_1M); + } diff --git a/queue-6.6/net-ipv4-stop-checking-crypto_ahash_alignmask.patch b/queue-6.6/net-ipv4-stop-checking-crypto_ahash_alignmask.patch new file mode 100644 index 0000000000..e4124ce21e --- /dev/null +++ b/queue-6.6/net-ipv4-stop-checking-crypto_ahash_alignmask.patch @@ -0,0 +1,87 @@ +From stable+bounces-246943-greg=kroah.com@vger.kernel.org Wed May 13 18:49:24 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 12:46:33 -0400 +Subject: net: ipv4: stop checking crypto_ahash_alignmask +To: stable@vger.kernel.org +Cc: Eric Biggers , Herbert Xu , Sasha Levin +Message-ID: <20260513164635.3816490-1-sashal@kernel.org> + +From: Eric Biggers + +[ Upstream commit e77f5dd701381cef35b9ea8b6dea6e62c8a7f9f3 ] + +Now that the alignmask for ahash and shash algorithms is always 0, +crypto_ahash_alignmask() always returns 0 and will be removed. In +preparation for this, stop checking crypto_ahash_alignmask() in ah4.c. + +Signed-off-by: Eric Biggers +Signed-off-by: Herbert Xu +Stable-dep-of: ec54093e6a8f ("xfrm: ah: account for ESN high bits in async callbacks") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/ah4.c | 17 +++++++---------- + 1 file changed, 7 insertions(+), 10 deletions(-) + +--- a/net/ipv4/ah4.c ++++ b/net/ipv4/ah4.c +@@ -27,9 +27,7 @@ static void *ah_alloc_tmp(struct crypto_ + { + unsigned int len; + +- len = size + crypto_ahash_digestsize(ahash) + +- (crypto_ahash_alignmask(ahash) & +- ~(crypto_tfm_ctx_alignment() - 1)); ++ len = size + crypto_ahash_digestsize(ahash); + + len = ALIGN(len, crypto_tfm_ctx_alignment()); + +@@ -46,10 +44,9 @@ static inline u8 *ah_tmp_auth(void *tmp, + return tmp + offset; + } + +-static inline u8 *ah_tmp_icv(struct crypto_ahash *ahash, void *tmp, +- unsigned int offset) ++static inline u8 *ah_tmp_icv(void *tmp, unsigned int offset) + { +- return PTR_ALIGN((u8 *)tmp + offset, crypto_ahash_alignmask(ahash) + 1); ++ return tmp + offset; + } + + static inline struct ahash_request *ah_tmp_req(struct crypto_ahash *ahash, +@@ -129,7 +126,7 @@ static void ah_output_done(void *data, i + int ihl = ip_hdrlen(skb); + + iph = AH_SKB_CB(skb)->tmp; +- icv = ah_tmp_icv(ahp->ahash, iph, ihl); ++ icv = ah_tmp_icv(iph, ihl); + memcpy(ah->auth_data, icv, ahp->icv_trunc_len); + + top_iph->tos = iph->tos; +@@ -182,7 +179,7 @@ static int ah_output(struct xfrm_state * + if (!iph) + goto out; + seqhi = (__be32 *)((char *)iph + ihl); +- icv = ah_tmp_icv(ahash, seqhi, seqhi_len); ++ icv = ah_tmp_icv(seqhi, seqhi_len); + req = ah_tmp_req(ahash, icv); + sg = ah_req_sg(ahash, req); + seqhisg = sg + nfrags; +@@ -279,7 +276,7 @@ static void ah_input_done(void *data, in + + work_iph = AH_SKB_CB(skb)->tmp; + auth_data = ah_tmp_auth(work_iph, ihl); +- icv = ah_tmp_icv(ahp->ahash, auth_data, ahp->icv_trunc_len); ++ icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len); + + err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0; + if (err) +@@ -374,7 +371,7 @@ static int ah_input(struct xfrm_state *x + + seqhi = (__be32 *)((char *)work_iph + ihl); + auth_data = ah_tmp_auth(seqhi, seqhi_len); +- icv = ah_tmp_icv(ahash, auth_data, ahp->icv_trunc_len); ++ icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len); + req = ah_tmp_req(ahash, icv); + sg = ah_req_sg(ahash, req); + seqhisg = sg + nfrags; diff --git a/queue-6.6/net-ipv6-stop-checking-crypto_ahash_alignmask.patch b/queue-6.6/net-ipv6-stop-checking-crypto_ahash_alignmask.patch new file mode 100644 index 0000000000..7eb331809e --- /dev/null +++ b/queue-6.6/net-ipv6-stop-checking-crypto_ahash_alignmask.patch @@ -0,0 +1,87 @@ +From stable+bounces-246944-greg=kroah.com@vger.kernel.org Wed May 13 18:49:27 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 12:46:34 -0400 +Subject: net: ipv6: stop checking crypto_ahash_alignmask +To: stable@vger.kernel.org +Cc: Eric Biggers , Herbert Xu , Sasha Levin +Message-ID: <20260513164635.3816490-2-sashal@kernel.org> + +From: Eric Biggers + +[ Upstream commit 0a6bfaa0e695facb072f2fedfb55df37c4483b50 ] + +Now that the alignmask for ahash and shash algorithms is always 0, +crypto_ahash_alignmask() always returns 0 and will be removed. In +preparation for this, stop checking crypto_ahash_alignmask() in ah6.c. + +Signed-off-by: Eric Biggers +Signed-off-by: Herbert Xu +Stable-dep-of: ec54093e6a8f ("xfrm: ah: account for ESN high bits in async callbacks") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/ah6.c | 17 +++++++---------- + 1 file changed, 7 insertions(+), 10 deletions(-) + +--- a/net/ipv6/ah6.c ++++ b/net/ipv6/ah6.c +@@ -79,9 +79,7 @@ static void *ah_alloc_tmp(struct crypto_ + { + unsigned int len; + +- len = size + crypto_ahash_digestsize(ahash) + +- (crypto_ahash_alignmask(ahash) & +- ~(crypto_tfm_ctx_alignment() - 1)); ++ len = size + crypto_ahash_digestsize(ahash); + + len = ALIGN(len, crypto_tfm_ctx_alignment()); + +@@ -103,10 +101,9 @@ static inline u8 *ah_tmp_auth(u8 *tmp, u + return tmp + offset; + } + +-static inline u8 *ah_tmp_icv(struct crypto_ahash *ahash, void *tmp, +- unsigned int offset) ++static inline u8 *ah_tmp_icv(void *tmp, unsigned int offset) + { +- return PTR_ALIGN((u8 *)tmp + offset, crypto_ahash_alignmask(ahash) + 1); ++ return tmp + offset; + } + + static inline struct ahash_request *ah_tmp_req(struct crypto_ahash *ahash, +@@ -327,7 +324,7 @@ static void ah6_output_done(void *data, + + iph_base = AH_SKB_CB(skb)->tmp; + iph_ext = ah_tmp_ext(iph_base); +- icv = ah_tmp_icv(ahp->ahash, iph_ext, extlen); ++ icv = ah_tmp_icv(iph_ext, extlen); + + memcpy(ah->auth_data, icv, ahp->icv_trunc_len); + memcpy(top_iph, iph_base, IPV6HDR_BASELEN); +@@ -384,7 +381,7 @@ static int ah6_output(struct xfrm_state + + iph_ext = ah_tmp_ext(iph_base); + seqhi = (__be32 *)((char *)iph_ext + extlen); +- icv = ah_tmp_icv(ahash, seqhi, seqhi_len); ++ icv = ah_tmp_icv(seqhi, seqhi_len); + req = ah_tmp_req(ahash, icv); + sg = ah_req_sg(ahash, req); + seqhisg = sg + nfrags; +@@ -480,7 +477,7 @@ static void ah6_input_done(void *data, i + + work_iph = AH_SKB_CB(skb)->tmp; + auth_data = ah_tmp_auth(work_iph, hdr_len); +- icv = ah_tmp_icv(ahp->ahash, auth_data, ahp->icv_trunc_len); ++ icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len); + + err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0; + if (err) +@@ -588,7 +585,7 @@ static int ah6_input(struct xfrm_state * + + auth_data = ah_tmp_auth((u8 *)work_iph, hdr_len); + seqhi = (__be32 *)(auth_data + ahp->icv_trunc_len); +- icv = ah_tmp_icv(ahash, seqhi, seqhi_len); ++ icv = ah_tmp_icv(seqhi, seqhi_len); + req = ah_tmp_req(ahash, icv); + sg = ah_req_sg(ahash, req); + seqhisg = sg + nfrags; diff --git a/queue-6.6/net-stmmac-avoid-shadowing-global-buf_sz.patch b/queue-6.6/net-stmmac-avoid-shadowing-global-buf_sz.patch new file mode 100644 index 0000000000..e503b0aa19 --- /dev/null +++ b/queue-6.6/net-stmmac-avoid-shadowing-global-buf_sz.patch @@ -0,0 +1,51 @@ +From stable+bounces-245032-greg=kroah.com@vger.kernel.org Sun May 10 17:10:25 2026 +From: Sasha Levin +Date: Sun, 10 May 2026 11:10:17 -0400 +Subject: net: stmmac: avoid shadowing global buf_sz +To: stable@vger.kernel.org +Cc: "Russell King (Oracle)" , Furong Xu <0x1207@gmail.com>, Jakub Kicinski , Sasha Levin +Message-ID: <20260510151019.38468-1-sashal@kernel.org> + +From: "Russell King (Oracle)" + +[ Upstream commit 876cfb20e8892143c0c967b3657074f9131f9b5f ] + +stmmac_rx() declares a local variable named "buf_sz" but there is also +a global variable for a module parameter which is called the same. To +avoid confusion, rename the local variable. + +Signed-off-by: Russell King (Oracle) +Reviewed-by: Furong Xu <0x1207@gmail.com> +Link: https://patch.msgid.link/E1tpswi-005U6C-Py@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +Stable-dep-of: 0bb05e6adfa9 ("net: stmmac: Prevent NULL deref when RX memory exhausted") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -5279,10 +5279,10 @@ static int stmmac_rx(struct stmmac_priv + struct sk_buff *skb = NULL; + struct stmmac_xdp_buff ctx; + int xdp_status = 0; +- int buf_sz; ++ int bufsz; + + dma_dir = page_pool_get_dma_dir(rx_q->page_pool); +- buf_sz = DIV_ROUND_UP(priv->dma_conf.dma_buf_sz, PAGE_SIZE) * PAGE_SIZE; ++ bufsz = DIV_ROUND_UP(priv->dma_conf.dma_buf_sz, PAGE_SIZE) * PAGE_SIZE; + limit = min(priv->dma_conf.dma_rx_size - 1, (unsigned int)limit); + + if (netif_msg_rx_status(priv)) { +@@ -5397,7 +5397,7 @@ read_again: + dma_sync_single_for_cpu(priv->device, buf->addr, + buf1_len, dma_dir); + +- xdp_init_buff(&ctx.xdp, buf_sz, &rx_q->xdp_rxq); ++ xdp_init_buff(&ctx.xdp, bufsz, &rx_q->xdp_rxq); + xdp_prepare_buff(&ctx.xdp, page_address(buf->page), + buf->page_offset, buf1_len, true); + diff --git a/queue-6.6/net-stmmac-prevent-null-deref-when-rx-memory-exhausted.patch b/queue-6.6/net-stmmac-prevent-null-deref-when-rx-memory-exhausted.patch new file mode 100644 index 0000000000..903cb10153 --- /dev/null +++ b/queue-6.6/net-stmmac-prevent-null-deref-when-rx-memory-exhausted.patch @@ -0,0 +1,120 @@ +From stable+bounces-245034-greg=kroah.com@vger.kernel.org Sun May 10 17:10:28 2026 +From: Sasha Levin +Date: Sun, 10 May 2026 11:10:19 -0400 +Subject: net: stmmac: Prevent NULL deref when RX memory exhausted +To: stable@vger.kernel.org +Cc: Sam Edwards , Russell King , Sam Edwards , Paolo Abeni , Sasha Levin +Message-ID: <20260510151019.38468-3-sashal@kernel.org> + +From: Sam Edwards + +[ Upstream commit 0bb05e6adfa99a2ea1fee1125cc0953409f83ed8 ] + +The CPU receives frames from the MAC through conventional DMA: the CPU +allocates buffers for the MAC, then the MAC fills them and returns +ownership to the CPU. For each hardware RX queue, the CPU and MAC +coordinate through a shared ring array of DMA descriptors: one +descriptor per DMA buffer. Each descriptor includes the buffer's +physical address and a status flag ("OWN") indicating which side owns +the buffer: OWN=0 for CPU, OWN=1 for MAC. The CPU is only allowed to set +the flag and the MAC is only allowed to clear it, and both must move +through the ring in sequence: thus the ring is used for both +"submissions" and "completions." + +In the stmmac driver, stmmac_rx() bookmarks its position in the ring +with the `cur_rx` index. The main receive loop in that function checks +for rx_descs[cur_rx].own=0, gives the corresponding buffer to the +network stack (NULLing the pointer), and increments `cur_rx` modulo the +ring size. After the loop exits, stmmac_rx_refill(), which bookmarks its +position with `dirty_rx`, allocates fresh buffers and rearms the +descriptors (setting OWN=1). If it fails any allocation, it simply stops +early (leaving OWN=0) and will retry where it left off when next called. + +This means descriptors have a three-stage lifecycle (terms my own): +- `empty` (OWN=1, buffer valid) +- `full` (OWN=0, buffer valid and populated) +- `dirty` (OWN=0, buffer NULL) + +But because stmmac_rx() only checks OWN, it confuses `full`/`dirty`. In +the past (see 'Fixes:'), there was a bug where the loop could cycle +`cur_rx` all the way back to the first descriptor it dirtied, resulting +in a NULL dereference when mistaken for `full`. The aforementioned +commit resolved that *specific* failure by capping the loop's iteration +limit at `dma_rx_size - 1`, but this is only a partial fix: if the +previous stmmac_rx_refill() didn't complete, then there are leftover +`dirty` descriptors that the loop might encounter without needing to +cycle fully around. The current code therefore panics (see 'Closes:') +when stmmac_rx_refill() is memory-starved long enough for `cur_rx` to +catch up to `dirty_rx`. + +Fix this by explicitly checking, before advancing `cur_rx`, if the next +entry is dirty; exit the loop if so. This prevents processing of the +final, used descriptor until stmmac_rx_refill() succeeds, but +fully prevents the `cur_rx == dirty_rx` ambiguity as the previous bugfix +intended: so remove the clamp as well. Since stmmac_rx_zc() is a +copy-paste-and-tweak of stmmac_rx() and the code structure is identical, +any fix to stmmac_rx() will also need a corresponding fix for +stmmac_rx_zc(). Therefore, apply the same check there. + +In stmmac_rx() (not stmmac_rx_zc()), a related bug remains: after the +MAC sets OWN=0 on the final descriptor, it will be unable to send any +further DMA-complete IRQs until it's given more `empty` descriptors. +Currently, the driver simply *hopes* that the next stmmac_rx_refill() +succeeds, risking an indefinite stall of the receive process if not. But +this is not a regression, so it can be addressed in a future change. + +Fixes: b6cb4541853c7 ("net: stmmac: avoid rx queue overrun") +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221010 +Cc: stable@vger.kernel.org +Suggested-by: Russell King +Signed-off-by: Sam Edwards +Link: https://patch.msgid.link/20260422044503.5349-1-CFSworks@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 19 ++++++++++++------- + 1 file changed, 12 insertions(+), 7 deletions(-) + +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -5143,9 +5143,12 @@ read_again: + break; + + /* Prefetch the next RX descriptor */ +- rx_q->cur_rx = STMMAC_NEXT_ENTRY(rx_q->cur_rx, +- priv->dma_conf.dma_rx_size); +- next_entry = rx_q->cur_rx; ++ next_entry = STMMAC_NEXT_ENTRY(rx_q->cur_rx, ++ priv->dma_conf.dma_rx_size); ++ if (unlikely(next_entry == rx_q->dirty_rx)) ++ break; ++ ++ rx_q->cur_rx = next_entry; + + if (priv->extend_desc) + np = (struct dma_desc *)(rx_q->dma_erx + next_entry); +@@ -5283,7 +5286,6 @@ static int stmmac_rx(struct stmmac_priv + + dma_dir = page_pool_get_dma_dir(rx_q->page_pool); + bufsz = DIV_ROUND_UP(priv->dma_conf.dma_buf_sz, PAGE_SIZE) * PAGE_SIZE; +- limit = min(priv->dma_conf.dma_rx_size - 1, (unsigned int)limit); + + if (netif_msg_rx_status(priv)) { + void *rx_head; +@@ -5339,9 +5341,12 @@ read_again: + if (unlikely(status & dma_own)) + break; + +- rx_q->cur_rx = STMMAC_NEXT_ENTRY(rx_q->cur_rx, +- priv->dma_conf.dma_rx_size); +- next_entry = rx_q->cur_rx; ++ next_entry = STMMAC_NEXT_ENTRY(rx_q->cur_rx, ++ priv->dma_conf.dma_rx_size); ++ if (unlikely(next_entry == rx_q->dirty_rx)) ++ break; ++ ++ rx_q->cur_rx = next_entry; + + if (priv->extend_desc) + np = (struct dma_desc *)(rx_q->dma_erx + next_entry); diff --git a/queue-6.6/net-stmmac-rename-stmmac_get_entry-stmmac_next_entry.patch b/queue-6.6/net-stmmac-rename-stmmac_get_entry-stmmac_next_entry.patch new file mode 100644 index 0000000000..70ff814438 --- /dev/null +++ b/queue-6.6/net-stmmac-rename-stmmac_get_entry-stmmac_next_entry.patch @@ -0,0 +1,181 @@ +From stable+bounces-245033-greg=kroah.com@vger.kernel.org Sun May 10 17:10:27 2026 +From: Sasha Levin +Date: Sun, 10 May 2026 11:10:18 -0400 +Subject: net: stmmac: rename STMMAC_GET_ENTRY() -> STMMAC_NEXT_ENTRY() +To: stable@vger.kernel.org +Cc: "Russell King (Oracle)" , Jakub Kicinski , Sasha Levin +Message-ID: <20260510151019.38468-2-sashal@kernel.org> + +From: "Russell King (Oracle)" + +[ Upstream commit 6b4286e0550814cdc4b897f881ec1fa8b0313227 ] + +STMMAC_GET_ENTRY() doesn't describe what this macro is doing - it is +incrementing the provided index for the circular array of descriptors. +Replace "GET" with "NEXT" as this better describes the action here. + +Signed-off-by: Russell King (Oracle) +Link: https://patch.msgid.link/E1w2vba-0000000DbWo-1oL5@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +Stable-dep-of: 0bb05e6adfa9 ("net: stmmac: Prevent NULL deref when RX memory exhausted") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/stmicro/stmmac/chain_mode.c | 2 - + drivers/net/ethernet/stmicro/stmmac/common.h | 2 - + drivers/net/ethernet/stmicro/stmmac/ring_mode.c | 2 - + drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 26 +++++++++++----------- + 4 files changed, 16 insertions(+), 16 deletions(-) + +--- a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c ++++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c +@@ -47,7 +47,7 @@ static int jumbo_frm(struct stmmac_tx_qu + + while (len != 0) { + tx_q->tx_skbuff[entry] = NULL; +- entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size); ++ entry = STMMAC_NEXT_ENTRY(entry, priv->dma_conf.dma_tx_size); + desc = tx_q->dma_tx + entry; + + if (len > bmax) { +--- a/drivers/net/ethernet/stmicro/stmmac/common.h ++++ b/drivers/net/ethernet/stmicro/stmmac/common.h +@@ -54,7 +54,7 @@ + #define DMA_MIN_RX_SIZE 64 + #define DMA_MAX_RX_SIZE 1024 + #define DMA_DEFAULT_RX_SIZE 512 +-#define STMMAC_GET_ENTRY(x, size) ((x + 1) & (size - 1)) ++#define STMMAC_NEXT_ENTRY(x, size) ((x + 1) & (size - 1)) + + #undef FRAME_FILTER_DEBUG + /* #define FRAME_FILTER_DEBUG */ +--- a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c ++++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c +@@ -51,7 +51,7 @@ static int jumbo_frm(struct stmmac_tx_qu + stmmac_prepare_tx_desc(priv, desc, 1, bmax, csum, + STMMAC_RING_MODE, 0, false, skb->len); + tx_q->tx_skbuff[entry] = NULL; +- entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size); ++ entry = STMMAC_NEXT_ENTRY(entry, priv->dma_conf.dma_tx_size); + + if (priv->extend_desc) + desc = (struct dma_desc *)(tx_q->dma_etx + entry); +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -2503,7 +2503,7 @@ static bool stmmac_xdp_xmit_zc(struct st + + stmmac_enable_dma_transmission(priv, priv->ioaddr); + +- tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size); ++ tx_q->cur_tx = STMMAC_NEXT_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size); + entry = tx_q->cur_tx; + } + u64_stats_update_begin(&txq_stats->napi_syncp); +@@ -2659,7 +2659,7 @@ static int stmmac_tx_clean(struct stmmac + + stmmac_release_tx_desc(priv, p, priv->mode); + +- entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size); ++ entry = STMMAC_NEXT_ENTRY(entry, priv->dma_conf.dma_tx_size); + } + tx_q->dirty_tx = entry; + +@@ -3973,7 +3973,7 @@ static bool stmmac_vlan_insert(struct st + return false; + + stmmac_set_tx_owner(priv, p); +- tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size); ++ tx_q->cur_tx = STMMAC_NEXT_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size); + return true; + } + +@@ -4001,7 +4001,7 @@ static void stmmac_tso_allocator(struct + while (tmp_len > 0) { + dma_addr_t curr_addr; + +- tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, ++ tx_q->cur_tx = STMMAC_NEXT_ENTRY(tx_q->cur_tx, + priv->dma_conf.dma_tx_size); + WARN_ON(tx_q->tx_skbuff[tx_q->cur_tx]); + +@@ -4133,7 +4133,7 @@ static netdev_tx_t stmmac_tso_xmit(struc + + stmmac_set_mss(priv, mss_desc, mss); + tx_q->mss = mss; +- tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, ++ tx_q->cur_tx = STMMAC_NEXT_ENTRY(tx_q->cur_tx, + priv->dma_conf.dma_tx_size); + WARN_ON(tx_q->tx_skbuff[tx_q->cur_tx]); + } +@@ -4258,7 +4258,7 @@ static netdev_tx_t stmmac_tso_xmit(struc + * ndo_start_xmit will fill this descriptor the next time it's + * called and stmmac_tx_clean may clean up to this descriptor. + */ +- tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size); ++ tx_q->cur_tx = STMMAC_NEXT_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size); + + if (unlikely(stmmac_tx_avail(priv, queue) <= (MAX_SKB_FRAGS + 1))) { + netif_dbg(priv, hw, priv->dev, "%s: stop transmitted packets\n", +@@ -4451,7 +4451,7 @@ static netdev_tx_t stmmac_xmit(struct sk + int len = skb_frag_size(frag); + bool last_segment = (i == (nfrags - 1)); + +- entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size); ++ entry = STMMAC_NEXT_ENTRY(entry, priv->dma_conf.dma_tx_size); + WARN_ON(tx_q->tx_skbuff[entry]); + + if (likely(priv->extend_desc)) +@@ -4521,7 +4521,7 @@ static netdev_tx_t stmmac_xmit(struct sk + * ndo_start_xmit will fill this descriptor the next time it's + * called and stmmac_tx_clean may clean up to this descriptor. + */ +- entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size); ++ entry = STMMAC_NEXT_ENTRY(entry, priv->dma_conf.dma_tx_size); + tx_q->cur_tx = entry; + + if (netif_msg_pktdata(priv)) { +@@ -4691,7 +4691,7 @@ static inline void stmmac_rx_refill(stru + dma_wmb(); + stmmac_set_rx_owner(priv, p, use_rx_wd); + +- entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_rx_size); ++ entry = STMMAC_NEXT_ENTRY(entry, priv->dma_conf.dma_rx_size); + } + rx_q->dirty_rx = entry; + rx_q->rx_tail_addr = rx_q->dma_rx_phy + +@@ -4818,7 +4818,7 @@ static int stmmac_xdp_xmit_xdpf(struct s + + stmmac_enable_dma_transmission(priv, priv->ioaddr); + +- entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size); ++ entry = STMMAC_NEXT_ENTRY(entry, priv->dma_conf.dma_tx_size); + tx_q->cur_tx = entry; + + return STMMAC_XDP_TX; +@@ -5048,7 +5048,7 @@ static bool stmmac_rx_refill_zc(struct s + dma_wmb(); + stmmac_set_rx_owner(priv, rx_desc, use_rx_wd); + +- entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_rx_size); ++ entry = STMMAC_NEXT_ENTRY(entry, priv->dma_conf.dma_rx_size); + } + + if (rx_desc) { +@@ -5143,7 +5143,7 @@ read_again: + break; + + /* Prefetch the next RX descriptor */ +- rx_q->cur_rx = STMMAC_GET_ENTRY(rx_q->cur_rx, ++ rx_q->cur_rx = STMMAC_NEXT_ENTRY(rx_q->cur_rx, + priv->dma_conf.dma_rx_size); + next_entry = rx_q->cur_rx; + +@@ -5339,7 +5339,7 @@ read_again: + if (unlikely(status & dma_own)) + break; + +- rx_q->cur_rx = STMMAC_GET_ENTRY(rx_q->cur_rx, ++ rx_q->cur_rx = STMMAC_NEXT_ENTRY(rx_q->cur_rx, + priv->dma_conf.dma_rx_size); + next_entry = rx_q->cur_rx; + diff --git a/queue-6.6/printk-add-print_hex_dump_devel.patch b/queue-6.6/printk-add-print_hex_dump_devel.patch new file mode 100644 index 0000000000..0761898478 --- /dev/null +++ b/queue-6.6/printk-add-print_hex_dump_devel.patch @@ -0,0 +1,49 @@ +From stable+bounces-245015-greg=kroah.com@vger.kernel.org Sun May 10 15:15:16 2026 +From: Sasha Levin +Date: Sun, 10 May 2026 09:15:07 -0400 +Subject: printk: add print_hex_dump_devel() +To: stable@vger.kernel.org +Cc: Thorsten Blum , Herbert Xu , John Ogness , Sasha Levin +Message-ID: <20260510131508.4113857-1-sashal@kernel.org> + +From: Thorsten Blum + +[ Upstream commit d134feeb5df33fbf77f482f52a366a44642dba09 ] + +Add print_hex_dump_devel() as the hex dump equivalent of pr_devel(), +which emits output only when DEBUG is enabled, but keeps call sites +compiled otherwise. + +Suggested-by: Herbert Xu +Signed-off-by: Thorsten Blum +Reviewed-by: John Ogness +Signed-off-by: Herbert Xu +Stable-dep-of: 177730a273b1 ("crypto: caam - guard HMAC key hex dumps in hash_digest_key") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/printk.h | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- a/include/linux/printk.h ++++ b/include/linux/printk.h +@@ -745,6 +745,19 @@ static inline void print_hex_dump_debug( + } + #endif + ++#if defined(DEBUG) ++#define print_hex_dump_devel(prefix_str, prefix_type, rowsize, \ ++ groupsize, buf, len, ascii) \ ++ print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, rowsize, \ ++ groupsize, buf, len, ascii) ++#else ++static inline void print_hex_dump_devel(const char *prefix_str, int prefix_type, ++ int rowsize, int groupsize, ++ const void *buf, size_t len, bool ascii) ++{ ++} ++#endif ++ + /** + * print_hex_dump_bytes - shorthand form of print_hex_dump() with default params + * @prefix_str: string to prefix each line with; diff --git a/queue-6.6/rxrpc-fix-conn-level-packet-handling-to-unshare-response-packets.patch b/queue-6.6/rxrpc-fix-conn-level-packet-handling-to-unshare-response-packets.patch new file mode 100644 index 0000000000..76fd8affa5 --- /dev/null +++ b/queue-6.6/rxrpc-fix-conn-level-packet-handling-to-unshare-response-packets.patch @@ -0,0 +1,81 @@ +From stable+bounces-242797-greg=kroah.com@vger.kernel.org Sun May 3 16:33:27 2026 +From: Sasha Levin +Date: Sun, 3 May 2026 10:33:17 -0400 +Subject: rxrpc: Fix conn-level packet handling to unshare RESPONSE packets +To: stable@vger.kernel.org +Cc: David Howells , Marc Dionne , Jeffrey Altman , Simon Horman , linux-afs@lists.infradead.org, stable@kernel.org, Jakub Kicinski , Sasha Levin +Message-ID: <20260503143317.1089945-1-sashal@kernel.org> + +From: David Howells + +[ Upstream commit 24481a7f573305706054c59e275371f8d0fe919f ] + +The security operations that verify the RESPONSE packets decrypt bits of it +in place - however, the sk_buff may be shared with a packet sniffer, which +would lead to the sniffer seeing an apparently corrupt packet (actually +decrypted). + +Fix this by handing a copy of the packet off to the specific security +handler if the packet was cloned. + +Fixes: 17926a79320a ("[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both") +Closes: https://sashiko.dev/#/patchset/20260408121252.2249051-1-dhowells%40redhat.com +Signed-off-by: David Howells +cc: Marc Dionne +cc: Jeffrey Altman +cc: Simon Horman +cc: linux-afs@lists.infradead.org +cc: stable@kernel.org +Link: https://patch.msgid.link/20260422161438.2593376-5-dhowells@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/rxrpc/conn_event.c | 29 ++++++++++++++++++++++++++++- + 1 file changed, 28 insertions(+), 1 deletion(-) + +--- a/net/rxrpc/conn_event.c ++++ b/net/rxrpc/conn_event.c +@@ -226,6 +226,33 @@ static void rxrpc_call_is_secure(struct + rxrpc_notify_socket(call); + } + ++static int rxrpc_verify_response(struct rxrpc_connection *conn, ++ struct sk_buff *skb) ++{ ++ int ret; ++ ++ if (skb_cloned(skb)) { ++ /* Copy the packet if shared so that we can do in-place ++ * decryption. ++ */ ++ struct sk_buff *nskb = skb_copy(skb, GFP_NOFS); ++ ++ if (nskb) { ++ rxrpc_new_skb(nskb, rxrpc_skb_new_unshared); ++ ret = conn->security->verify_response(conn, nskb); ++ rxrpc_free_skb(nskb, rxrpc_skb_put_response_copy); ++ } else { ++ /* OOM - Drop the packet. */ ++ rxrpc_see_skb(skb, rxrpc_skb_see_unshare_nomem); ++ ret = -ENOMEM; ++ } ++ } else { ++ ret = conn->security->verify_response(conn, skb); ++ } ++ ++ return ret; ++} ++ + /* + * connection-level Rx packet processor + */ +@@ -253,7 +280,7 @@ static int rxrpc_process_event(struct rx + } + spin_unlock(&conn->state_lock); + +- ret = conn->security->verify_response(conn, skb); ++ ret = rxrpc_verify_response(conn, skb); + if (ret < 0) + return ret; + diff --git a/queue-6.6/series b/queue-6.6/series index bd7d2d4a9c..35b02d7123 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -402,3 +402,45 @@ hfsplus-fix-uninit-value-by-validating-catalog-record-size.patch hfsplus-fix-held-lock-freed-on-hfsplus_fill_super.patch wifi-rtl8xxxu-fix-potential-use-of-uninitialized-value.patch ksmbd-reset-rcount-per-connection-in-ksmbd_conn_wait_idle_sess_id.patch +crypto-nx-avoid-wflex-array-member-not-at-end-warning.patch +crypto-nx-migrate-to-scomp-api.patch +crypto-nx-fix-bounce-buffer-leaks-in-nx842_crypto_-alloc-free-_ctx.patch +erofs-fix-unsigned-underflow-in-z_erofs_lz4_handle_overlap.patch +printk-add-print_hex_dump_devel.patch +crypto-caam-guard-hmac-key-hex-dumps-in-hash_digest_key.patch +net-stmmac-avoid-shadowing-global-buf_sz.patch +net-stmmac-rename-stmmac_get_entry-stmmac_next_entry.patch +net-stmmac-prevent-null-deref-when-rx-memory-exhausted.patch +tracepoint-balance-regfunc-on-func_add-failure-in-tracepoint_add_func.patch +alsa-hda-cs35l56-propagate-asp-tx-source-control-errors.patch +alsa-misc-use-guard-for-spin-locks.patch +alsa-core-serialize-deferred-fasync-state-checks.patch +alsa-seq-notify-client-and-port-info-changes.patch +alsa-seq-fix-ump-group-16-filtering.patch +net-ipv4-stop-checking-crypto_ahash_alignmask.patch +net-ipv6-stop-checking-crypto_ahash_alignmask.patch +xfrm-ah-account-for-esn-high-bits-in-async-callbacks.patch +xfrm-defensively-unhash-xfrm_state-lists-in-__xfrm_state_delete.patch +bluetooth-hci_conn-fix-potential-uaf-in-create_big_sync.patch +spi-synquacer-switch-to-use-modern-name.patch +spi-syncuacer-fix-controller-deregistration.patch +spi-sun4i-switch-to-use-modern-name.patch +spi-sun4i-fix-controller-deregistration.patch +spi-spi-ti-qspi-convert-to-platform-remove-callback-returning-void.patch +spi-spi-ti-qspi-switch-to-use-modern-name.patch +spi-ti-qspi-fix-controller-deregistration.patch +spi-zynq-qspi-switch-to-use-modern-name.patch +spi-zynq-qspi-simplify-clock-handling-with-devm_clk_get_enabled.patch +spi-zynq-qspi-fix-controller-deregistration.patch +spi-sun6i-switch-to-use-modern-name.patch +spi-sun6i-fix-controller-deregistration.patch +spi-tegra114-fix-controller-deregistration.patch +spi-tegra20-sflash-fix-controller-deregistration.patch +spi-uniphier-switch-to-use-modern-name.patch +spi-uniphier-simplify-clock-handling-with-devm_clk_get_enabled.patch +spi-uniphier-fix-controller-deregistration.patch +mm-hugetlb_cma-round-up-per_node-before-logging-it.patch +spi-microchip-core-qspi-use-helper-function-devm_clk_get_enabled.patch +spi-microchip-core-qspi-fix-controller-deregistration.patch +fbcon-avoid-oob-font-access-if-console-rotation-fails.patch +rxrpc-fix-conn-level-packet-handling-to-unshare-response-packets.patch diff --git a/queue-6.6/spi-microchip-core-qspi-fix-controller-deregistration.patch b/queue-6.6/spi-microchip-core-qspi-fix-controller-deregistration.patch new file mode 100644 index 0000000000..9c4c74c5f9 --- /dev/null +++ b/queue-6.6/spi-microchip-core-qspi-fix-controller-deregistration.patch @@ -0,0 +1,64 @@ +From stable+bounces-247275-greg=kroah.com@vger.kernel.org Thu May 14 20:33:45 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 14:33:36 -0400 +Subject: spi: microchip-core-qspi: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Naga Sureshkumar Relli , Conor Dooley , Mark Brown , Sasha Levin +Message-ID: <20260514183336.771790-2-sashal@kernel.org> + +From: Johan Hovold + +[ Upstream commit e6464140d439f2d42f072eb422a5b1fec470c5a6 ] + +Make sure to deregister the controller before disabling underlying +resources like interrupts during driver unbind. + +Fixes: 8596124c4c1b ("spi: microchip-core-qspi: Add support for microchip fpga qspi controllers") +Cc: stable@vger.kernel.org # 6.1 +Cc: Naga Sureshkumar Relli +Signed-off-by: Johan Hovold +Acked-by: Conor Dooley +Link: https://patch.msgid.link/20260409120419.388546-19-johan@kernel.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-microchip-core-qspi.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +--- a/drivers/spi/spi-microchip-core-qspi.c ++++ b/drivers/spi/spi-microchip-core-qspi.c +@@ -512,7 +512,7 @@ static int mchp_coreqspi_probe(struct pl + "unable to allocate master for QSPI controller\n"); + + qspi = spi_controller_get_devdata(ctlr); +- platform_set_drvdata(pdev, qspi); ++ platform_set_drvdata(pdev, ctlr); + + qspi->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(qspi->regs)) +@@ -545,7 +545,7 @@ static int mchp_coreqspi_probe(struct pl + SPI_TX_DUAL | SPI_TX_QUAD; + ctlr->dev.of_node = np; + +- ret = devm_spi_register_controller(&pdev->dev, ctlr); ++ ret = spi_register_controller(ctlr); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "spi_register_controller failed\n"); +@@ -555,9 +555,13 @@ static int mchp_coreqspi_probe(struct pl + + static void mchp_coreqspi_remove(struct platform_device *pdev) + { +- struct mchp_coreqspi *qspi = platform_get_drvdata(pdev); +- u32 control = readl_relaxed(qspi->regs + REG_CONTROL); ++ struct spi_controller *ctlr = platform_get_drvdata(pdev); ++ struct mchp_coreqspi *qspi = spi_controller_get_devdata(ctlr); ++ u32 control; + ++ spi_unregister_controller(ctlr); ++ ++ control = readl_relaxed(qspi->regs + REG_CONTROL); + mchp_coreqspi_disable_ints(qspi); + control &= ~CONTROL_ENABLE; + writel_relaxed(control, qspi->regs + REG_CONTROL); diff --git a/queue-6.6/spi-microchip-core-qspi-use-helper-function-devm_clk_get_enabled.patch b/queue-6.6/spi-microchip-core-qspi-use-helper-function-devm_clk_get_enabled.patch new file mode 100644 index 0000000000..beff8a218f --- /dev/null +++ b/queue-6.6/spi-microchip-core-qspi-use-helper-function-devm_clk_get_enabled.patch @@ -0,0 +1,96 @@ +From stable+bounces-247274-greg=kroah.com@vger.kernel.org Thu May 14 20:33:42 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 14:33:35 -0400 +Subject: spi: microchip-core-qspi: Use helper function devm_clk_get_enabled() +To: stable@vger.kernel.org +Cc: Li Zetao , Jonathan Cameron , Mark Brown , Sasha Levin +Message-ID: <20260514183336.771790-1-sashal@kernel.org> + +From: Li Zetao + +[ Upstream commit e922f3fff21445117e9196bd8e940ad8e15ca8c7 ] + +Since commit 7ef9651e9792 ("clk: Provide new devm_clk helpers for prepared +and enabled clocks"), devm_clk_get() and clk_prepare_enable() can now be +replaced by devm_clk_get_enabled() when driver enables (and possibly +prepares) the clocks for the whole lifetime of the device. Moreover, it is +no longer necessary to unprepare and disable the clocks explicitly. + +Reviewed-by: Jonathan Cameron +Signed-off-by: Li Zetao +Link: https://lore.kernel.org/r/20230823133938.1359106-18-lizetao1@huawei.com +Signed-off-by: Mark Brown +Stable-dep-of: e6464140d439 ("spi: microchip-core-qspi: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-microchip-core-qspi.c | 29 +++++++---------------------- + 1 file changed, 7 insertions(+), 22 deletions(-) + +--- a/drivers/spi/spi-microchip-core-qspi.c ++++ b/drivers/spi/spi-microchip-core-qspi.c +@@ -519,30 +519,23 @@ static int mchp_coreqspi_probe(struct pl + return dev_err_probe(&pdev->dev, PTR_ERR(qspi->regs), + "failed to map registers\n"); + +- qspi->clk = devm_clk_get(&pdev->dev, NULL); ++ qspi->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(qspi->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(qspi->clk), + "could not get clock\n"); + +- ret = clk_prepare_enable(qspi->clk); +- if (ret) +- return dev_err_probe(&pdev->dev, ret, +- "failed to enable clock\n"); +- + init_completion(&qspi->data_completion); + mutex_init(&qspi->op_lock); + + qspi->irq = platform_get_irq(pdev, 0); +- if (qspi->irq < 0) { +- ret = qspi->irq; +- goto out; +- } ++ if (qspi->irq < 0) ++ return qspi->irq; + + ret = devm_request_irq(&pdev->dev, qspi->irq, mchp_coreqspi_isr, + IRQF_SHARED, pdev->name, qspi); + if (ret) { + dev_err(&pdev->dev, "request_irq failed %d\n", ret); +- goto out; ++ return ret; + } + + ctlr->bits_per_word_mask = SPI_BPW_MASK(8); +@@ -553,18 +546,11 @@ static int mchp_coreqspi_probe(struct pl + ctlr->dev.of_node = np; + + ret = devm_spi_register_controller(&pdev->dev, ctlr); +- if (ret) { +- dev_err_probe(&pdev->dev, ret, +- "spi_register_controller failed\n"); +- goto out; +- } ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, ++ "spi_register_controller failed\n"); + + return 0; +- +-out: +- clk_disable_unprepare(qspi->clk); +- +- return ret; + } + + static void mchp_coreqspi_remove(struct platform_device *pdev) +@@ -575,7 +561,6 @@ static void mchp_coreqspi_remove(struct + mchp_coreqspi_disable_ints(qspi); + control &= ~CONTROL_ENABLE; + writel_relaxed(control, qspi->regs + REG_CONTROL); +- clk_disable_unprepare(qspi->clk); + } + + static const struct of_device_id mchp_coreqspi_of_match[] = { diff --git a/queue-6.6/spi-spi-ti-qspi-convert-to-platform-remove-callback-returning-void.patch b/queue-6.6/spi-spi-ti-qspi-convert-to-platform-remove-callback-returning-void.patch new file mode 100644 index 0000000000..fa7519114e --- /dev/null +++ b/queue-6.6/spi-spi-ti-qspi-convert-to-platform-remove-callback-returning-void.patch @@ -0,0 +1,76 @@ +From stable+bounces-246995-greg=kroah.com@vger.kernel.org Wed May 13 20:11:11 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 14:08:40 -0400 +Subject: spi: spi-ti-qspi: Convert to platform remove callback returning void +To: stable@vger.kernel.org +Cc: "Uwe Kleine-König" , "Mark Brown" , "Sasha Levin" +Message-ID: <20260513180842.3912849-1-sashal@kernel.org> + +From: Uwe Kleine-König + +[ Upstream commit 2f2802d1a59d79a3d00cb429841db502c2bbc3df ] + +The .remove() callback for a platform driver returns an int which makes +many driver authors wrongly assume it's possible to do error handling by +returning an error code. However the value returned is ignored (apart +from emitting a warning) and this typically results in resource leaks. + +To improve here there is a quest to make the remove callback return +void. In the first step of this quest all drivers are converted to +.remove_new(), which already returns void. Eventually after all drivers +are converted, .remove_new() will be renamed to .remove(). + +Add an error message to the error path that returned an error before to +replace the core's error message with more information. Apart from the +different wording of the error message, this patch doesn't introduce a +semantic difference. + +Signed-off-by: Uwe Kleine-König +Link: https://lore.kernel.org/r/20231105172649.3738556-2-u.kleine-koenig@pengutronix.de +Signed-off-by: Mark Brown +Stable-dep-of: 0c18a1bacbb1 ("spi: ti-qspi: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-ti-qspi.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +--- a/drivers/spi/spi-ti-qspi.c ++++ b/drivers/spi/spi-ti-qspi.c +@@ -907,21 +907,22 @@ free_master: + return ret; + } + +-static int ti_qspi_remove(struct platform_device *pdev) ++static void ti_qspi_remove(struct platform_device *pdev) + { + struct ti_qspi *qspi = platform_get_drvdata(pdev); + int rc; + + rc = spi_master_suspend(qspi->master); +- if (rc) +- return rc; ++ if (rc) { ++ dev_alert(&pdev->dev, "spi_master_suspend() failed (%pe)\n", ++ ERR_PTR(rc)); ++ return; ++ } + + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + ti_qspi_dma_cleanup(qspi); +- +- return 0; + } + + static const struct dev_pm_ops ti_qspi_pm_ops = { +@@ -930,7 +931,7 @@ static const struct dev_pm_ops ti_qspi_p + + static struct platform_driver ti_qspi_driver = { + .probe = ti_qspi_probe, +- .remove = ti_qspi_remove, ++ .remove_new = ti_qspi_remove, + .driver = { + .name = "ti-qspi", + .pm = &ti_qspi_pm_ops, diff --git a/queue-6.6/spi-spi-ti-qspi-switch-to-use-modern-name.patch b/queue-6.6/spi-spi-ti-qspi-switch-to-use-modern-name.patch new file mode 100644 index 0000000000..2e7e14995c --- /dev/null +++ b/queue-6.6/spi-spi-ti-qspi-switch-to-use-modern-name.patch @@ -0,0 +1,293 @@ +From stable+bounces-246996-greg=kroah.com@vger.kernel.org Wed May 13 20:15:40 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 14:08:41 -0400 +Subject: spi: spi-ti-qspi: switch to use modern name +To: stable@vger.kernel.org +Cc: Yang Yingliang , Mark Brown , Sasha Levin +Message-ID: <20260513180842.3912849-2-sashal@kernel.org> + +From: Yang Yingliang + +[ Upstream commit 9d93c8d97b4cdb5edddb4c5530881c90eecb7e44 ] + +Change legacy name master to modern name host or controller. + +No functional changed. + +Signed-off-by: Yang Yingliang +Link: https://msgid.link/r/20231128093031.3707034-16-yangyingliang@huawei.com +Signed-off-by: Mark Brown +Stable-dep-of: 0c18a1bacbb1 ("spi: ti-qspi: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-ti-qspi.c | 88 +++++++++++++++++++++++----------------------- + 1 file changed, 44 insertions(+), 44 deletions(-) + +--- a/drivers/spi/spi-ti-qspi.c ++++ b/drivers/spi/spi-ti-qspi.c +@@ -40,7 +40,7 @@ struct ti_qspi { + /* list synchronization */ + struct mutex list_lock; + +- struct spi_master *master; ++ struct spi_controller *host; + void __iomem *base; + void __iomem *mmap_base; + size_t mmap_size; +@@ -137,20 +137,20 @@ static inline void ti_qspi_write(struct + + static int ti_qspi_setup(struct spi_device *spi) + { +- struct ti_qspi *qspi = spi_master_get_devdata(spi->master); ++ struct ti_qspi *qspi = spi_controller_get_devdata(spi->controller); + int ret; + +- if (spi->master->busy) { +- dev_dbg(qspi->dev, "master busy doing other transfers\n"); ++ if (spi->controller->busy) { ++ dev_dbg(qspi->dev, "host busy doing other transfers\n"); + return -EBUSY; + } + +- if (!qspi->master->max_speed_hz) { ++ if (!qspi->host->max_speed_hz) { + dev_err(qspi->dev, "spi max frequency not defined\n"); + return -EINVAL; + } + +- spi->max_speed_hz = min(spi->max_speed_hz, qspi->master->max_speed_hz); ++ spi->max_speed_hz = min(spi->max_speed_hz, qspi->host->max_speed_hz); + + ret = pm_runtime_resume_and_get(qspi->dev); + if (ret < 0) { +@@ -526,7 +526,7 @@ static int ti_qspi_dma_xfer_sg(struct ti + + static void ti_qspi_enable_memory_map(struct spi_device *spi) + { +- struct ti_qspi *qspi = spi_master_get_devdata(spi->master); ++ struct ti_qspi *qspi = spi_controller_get_devdata(spi->controller); + + ti_qspi_write(qspi, MM_SWITCH, QSPI_SPI_SWITCH_REG); + if (qspi->ctrl_base) { +@@ -540,7 +540,7 @@ static void ti_qspi_enable_memory_map(st + + static void ti_qspi_disable_memory_map(struct spi_device *spi) + { +- struct ti_qspi *qspi = spi_master_get_devdata(spi->master); ++ struct ti_qspi *qspi = spi_controller_get_devdata(spi->controller); + + ti_qspi_write(qspi, 0, QSPI_SPI_SWITCH_REG); + if (qspi->ctrl_base) +@@ -554,7 +554,7 @@ static void ti_qspi_setup_mmap_read(stru + u8 data_nbits, u8 addr_width, + u8 dummy_bytes) + { +- struct ti_qspi *qspi = spi_master_get_devdata(spi->master); ++ struct ti_qspi *qspi = spi_controller_get_devdata(spi->controller); + u32 memval = opcode; + + switch (data_nbits) { +@@ -576,7 +576,7 @@ static void ti_qspi_setup_mmap_read(stru + + static int ti_qspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) + { +- struct ti_qspi *qspi = spi_controller_get_devdata(mem->spi->master); ++ struct ti_qspi *qspi = spi_controller_get_devdata(mem->spi->controller); + size_t max_len; + + if (op->data.dir == SPI_MEM_DATA_IN) { +@@ -606,7 +606,7 @@ static int ti_qspi_adjust_op_size(struct + static int ti_qspi_exec_mem_op(struct spi_mem *mem, + const struct spi_mem_op *op) + { +- struct ti_qspi *qspi = spi_master_get_devdata(mem->spi->master); ++ struct ti_qspi *qspi = spi_controller_get_devdata(mem->spi->controller); + u32 from = 0; + int ret = 0; + +@@ -633,10 +633,10 @@ static int ti_qspi_exec_mem_op(struct sp + struct sg_table sgt; + + if (virt_addr_valid(op->data.buf.in) && +- !spi_controller_dma_map_mem_op_data(mem->spi->master, op, ++ !spi_controller_dma_map_mem_op_data(mem->spi->controller, op, + &sgt)) { + ret = ti_qspi_dma_xfer_sg(qspi, sgt, from); +- spi_controller_dma_unmap_mem_op_data(mem->spi->master, ++ spi_controller_dma_unmap_mem_op_data(mem->spi->controller, + op, &sgt); + } else { + ret = ti_qspi_dma_bounce_buffer(qspi, from, +@@ -658,10 +658,10 @@ static const struct spi_controller_mem_o + .adjust_op_size = ti_qspi_adjust_op_size, + }; + +-static int ti_qspi_start_transfer_one(struct spi_master *master, ++static int ti_qspi_start_transfer_one(struct spi_controller *host, + struct spi_message *m) + { +- struct ti_qspi *qspi = spi_master_get_devdata(master); ++ struct ti_qspi *qspi = spi_controller_get_devdata(host); + struct spi_device *spi = m->spi; + struct spi_transfer *t; + int status = 0, ret; +@@ -720,7 +720,7 @@ static int ti_qspi_start_transfer_one(st + + ti_qspi_write(qspi, qspi->cmd | QSPI_INVAL, QSPI_SPI_CMD_REG); + m->status = status; +- spi_finalize_current_message(master); ++ spi_finalize_current_message(host); + + return status; + } +@@ -756,33 +756,33 @@ MODULE_DEVICE_TABLE(of, ti_qspi_match); + static int ti_qspi_probe(struct platform_device *pdev) + { + struct ti_qspi *qspi; +- struct spi_master *master; ++ struct spi_controller *host; + struct resource *r, *res_mmap; + struct device_node *np = pdev->dev.of_node; + u32 max_freq; + int ret = 0, num_cs, irq; + dma_cap_mask_t mask; + +- master = spi_alloc_master(&pdev->dev, sizeof(*qspi)); +- if (!master) ++ host = spi_alloc_host(&pdev->dev, sizeof(*qspi)); ++ if (!host) + return -ENOMEM; + +- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD; ++ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD; + +- master->flags = SPI_CONTROLLER_HALF_DUPLEX; +- master->setup = ti_qspi_setup; +- master->auto_runtime_pm = true; +- master->transfer_one_message = ti_qspi_start_transfer_one; +- master->dev.of_node = pdev->dev.of_node; +- master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | +- SPI_BPW_MASK(8); +- master->mem_ops = &ti_qspi_mem_ops; ++ host->flags = SPI_CONTROLLER_HALF_DUPLEX; ++ host->setup = ti_qspi_setup; ++ host->auto_runtime_pm = true; ++ host->transfer_one_message = ti_qspi_start_transfer_one; ++ host->dev.of_node = pdev->dev.of_node; ++ host->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | ++ SPI_BPW_MASK(8); ++ host->mem_ops = &ti_qspi_mem_ops; + + if (!of_property_read_u32(np, "num-cs", &num_cs)) +- master->num_chipselect = num_cs; ++ host->num_chipselect = num_cs; + +- qspi = spi_master_get_devdata(master); +- qspi->master = master; ++ qspi = spi_controller_get_devdata(host); ++ qspi->host = host; + qspi->dev = &pdev->dev; + platform_set_drvdata(pdev, qspi); + +@@ -792,7 +792,7 @@ static int ti_qspi_probe(struct platform + if (r == NULL) { + dev_err(&pdev->dev, "missing platform data\n"); + ret = -ENODEV; +- goto free_master; ++ goto free_host; + } + } + +@@ -812,7 +812,7 @@ static int ti_qspi_probe(struct platform + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = irq; +- goto free_master; ++ goto free_host; + } + + mutex_init(&qspi->list_lock); +@@ -820,7 +820,7 @@ static int ti_qspi_probe(struct platform + qspi->base = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(qspi->base)) { + ret = PTR_ERR(qspi->base); +- goto free_master; ++ goto free_host; + } + + +@@ -830,7 +830,7 @@ static int ti_qspi_probe(struct platform + "syscon-chipselects"); + if (IS_ERR(qspi->ctrl_base)) { + ret = PTR_ERR(qspi->ctrl_base); +- goto free_master; ++ goto free_host; + } + ret = of_property_read_u32_index(np, + "syscon-chipselects", +@@ -838,7 +838,7 @@ static int ti_qspi_probe(struct platform + if (ret) { + dev_err(&pdev->dev, + "couldn't get ctrl_mod reg index\n"); +- goto free_master; ++ goto free_host; + } + } + +@@ -853,7 +853,7 @@ static int ti_qspi_probe(struct platform + pm_runtime_enable(&pdev->dev); + + if (!of_property_read_u32(np, "spi-max-frequency", &max_freq)) +- master->max_speed_hz = max_freq; ++ host->max_speed_hz = max_freq; + + dma_cap_zero(mask); + dma_cap_set(DMA_MEMCPY, mask); +@@ -876,7 +876,7 @@ static int ti_qspi_probe(struct platform + dma_release_channel(qspi->rx_chan); + goto no_dma; + } +- master->dma_rx = qspi->rx_chan; ++ host->dma_rx = qspi->rx_chan; + init_completion(&qspi->transfer_complete); + if (res_mmap) + qspi->mmap_phys_base = (dma_addr_t)res_mmap->start; +@@ -889,21 +889,21 @@ no_dma: + "mmap failed with error %ld using PIO mode\n", + PTR_ERR(qspi->mmap_base)); + qspi->mmap_base = NULL; +- master->mem_ops = NULL; ++ host->mem_ops = NULL; + } + } + qspi->mmap_enabled = false; + qspi->current_cs = -1; + +- ret = devm_spi_register_master(&pdev->dev, master); ++ ret = devm_spi_register_controller(&pdev->dev, host); + if (!ret) + return 0; + + ti_qspi_dma_cleanup(qspi); + + pm_runtime_disable(&pdev->dev); +-free_master: +- spi_master_put(master); ++free_host: ++ spi_controller_put(host); + return ret; + } + +@@ -912,9 +912,9 @@ static void ti_qspi_remove(struct platfo + struct ti_qspi *qspi = platform_get_drvdata(pdev); + int rc; + +- rc = spi_master_suspend(qspi->master); ++ rc = spi_controller_suspend(qspi->host); + if (rc) { +- dev_alert(&pdev->dev, "spi_master_suspend() failed (%pe)\n", ++ dev_alert(&pdev->dev, "spi_controller_suspend() failed (%pe)\n", + ERR_PTR(rc)); + return; + } diff --git a/queue-6.6/spi-sun4i-fix-controller-deregistration.patch b/queue-6.6/spi-sun4i-fix-controller-deregistration.patch new file mode 100644 index 0000000000..e8f3249dbc --- /dev/null +++ b/queue-6.6/spi-sun4i-fix-controller-deregistration.patch @@ -0,0 +1,54 @@ +From stable+bounces-246971-greg=kroah.com@vger.kernel.org Wed May 13 19:32:40 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 13:32:02 -0400 +Subject: spi: sun4i: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Maxime Ripard , Mark Brown , Sasha Levin +Message-ID: <20260513173202.3886782-2-sashal@kernel.org> + +From: Johan Hovold + +[ Upstream commit 42108a2f03e0fdeabe9d02d085bdb058baa1189f ] + +Make sure to deregister the controller before disabling underlying +resources like clocks during driver unbind. + +Fixes: b5f6517948cc ("spi: sunxi: Add Allwinner A10 SPI controller driver") +Cc: stable@vger.kernel.org # 3.15 +Cc: Maxime Ripard +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410081757.503099-19-johan@kernel.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-sun4i.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +--- a/drivers/spi/spi-sun4i.c ++++ b/drivers/spi/spi-sun4i.c +@@ -503,7 +503,7 @@ static int sun4i_spi_probe(struct platfo + pm_runtime_enable(&pdev->dev); + pm_runtime_idle(&pdev->dev); + +- ret = devm_spi_register_controller(&pdev->dev, host); ++ ret = spi_register_controller(host); + if (ret) { + dev_err(&pdev->dev, "cannot register SPI host\n"); + goto err_pm_disable; +@@ -521,7 +521,15 @@ err_free_host: + + static void sun4i_spi_remove(struct platform_device *pdev) + { ++ struct spi_controller *host = platform_get_drvdata(pdev); ++ ++ spi_controller_get(host); ++ ++ spi_unregister_controller(host); ++ + pm_runtime_force_suspend(&pdev->dev); ++ ++ spi_controller_put(host); + } + + static const struct of_device_id sun4i_spi_match[] = { diff --git a/queue-6.6/spi-sun4i-switch-to-use-modern-name.patch b/queue-6.6/spi-sun4i-switch-to-use-modern-name.patch new file mode 100644 index 0000000000..5429bd4945 --- /dev/null +++ b/queue-6.6/spi-sun4i-switch-to-use-modern-name.patch @@ -0,0 +1,207 @@ +From stable+bounces-246970-greg=kroah.com@vger.kernel.org Wed May 13 19:32:37 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 13:32:01 -0400 +Subject: spi: sun4i: switch to use modern name +To: stable@vger.kernel.org +Cc: Yang Yingliang , Mark Brown , Sasha Levin +Message-ID: <20260513173202.3886782-1-sashal@kernel.org> + +From: Yang Yingliang + +[ Upstream commit 6d232cc8a7e59af0c083319827541966a68817a0 ] + +Change legacy name master to modern name host or controller. + +No functional changed. + +Signed-off-by: Yang Yingliang +Link: https://msgid.link/r/20231128093031.3707034-7-yangyingliang@huawei.com +Signed-off-by: Mark Brown +Stable-dep-of: 42108a2f03e0 ("spi: sun4i: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-sun4i.c | 72 ++++++++++++++++++++++++------------------------ + 1 file changed, 36 insertions(+), 36 deletions(-) + +--- a/drivers/spi/spi-sun4i.c ++++ b/drivers/spi/spi-sun4i.c +@@ -75,7 +75,7 @@ + #define SUN4I_FIFO_STA_TF_CNT_BITS 16 + + struct sun4i_spi { +- struct spi_master *master; ++ struct spi_controller *host; + void __iomem *base_addr; + struct clk *hclk; + struct clk *mclk; +@@ -161,7 +161,7 @@ static inline void sun4i_spi_fill_fifo(s + + static void sun4i_spi_set_cs(struct spi_device *spi, bool enable) + { +- struct sun4i_spi *sspi = spi_master_get_devdata(spi->master); ++ struct sun4i_spi *sspi = spi_controller_get_devdata(spi->controller); + u32 reg; + + reg = sun4i_spi_read(sspi, SUN4I_CTL_REG); +@@ -201,11 +201,11 @@ static size_t sun4i_spi_max_transfer_siz + return SUN4I_MAX_XFER_SIZE - 1; + } + +-static int sun4i_spi_transfer_one(struct spi_master *master, ++static int sun4i_spi_transfer_one(struct spi_controller *host, + struct spi_device *spi, + struct spi_transfer *tfr) + { +- struct sun4i_spi *sspi = spi_master_get_devdata(master); ++ struct sun4i_spi *sspi = spi_controller_get_devdata(host); + unsigned int mclk_rate, div, timeout; + unsigned int start, end, tx_time; + unsigned int tx_len = 0; +@@ -334,7 +334,7 @@ static int sun4i_spi_transfer_one(struct + msecs_to_jiffies(tx_time)); + end = jiffies; + if (!timeout) { +- dev_warn(&master->dev, ++ dev_warn(&host->dev, + "%s: timeout transferring %u bytes@%iHz for %i(%i)ms", + dev_name(&spi->dev), tfr->len, tfr->speed_hz, + jiffies_to_msecs(end - start), tx_time); +@@ -389,8 +389,8 @@ static irqreturn_t sun4i_spi_handler(int + + static int sun4i_spi_runtime_resume(struct device *dev) + { +- struct spi_master *master = dev_get_drvdata(dev); +- struct sun4i_spi *sspi = spi_master_get_devdata(master); ++ struct spi_controller *host = dev_get_drvdata(dev); ++ struct sun4i_spi *sspi = spi_controller_get_devdata(host); + int ret; + + ret = clk_prepare_enable(sspi->hclk); +@@ -418,8 +418,8 @@ out: + + static int sun4i_spi_runtime_suspend(struct device *dev) + { +- struct spi_master *master = dev_get_drvdata(dev); +- struct sun4i_spi *sspi = spi_master_get_devdata(master); ++ struct spi_controller *host = dev_get_drvdata(dev); ++ struct sun4i_spi *sspi = spi_controller_get_devdata(host); + + clk_disable_unprepare(sspi->mclk); + clk_disable_unprepare(sspi->hclk); +@@ -429,62 +429,62 @@ static int sun4i_spi_runtime_suspend(str + + static int sun4i_spi_probe(struct platform_device *pdev) + { +- struct spi_master *master; ++ struct spi_controller *host; + struct sun4i_spi *sspi; + int ret = 0, irq; + +- master = spi_alloc_master(&pdev->dev, sizeof(struct sun4i_spi)); +- if (!master) { +- dev_err(&pdev->dev, "Unable to allocate SPI Master\n"); ++ host = spi_alloc_host(&pdev->dev, sizeof(struct sun4i_spi)); ++ if (!host) { ++ dev_err(&pdev->dev, "Unable to allocate SPI Host\n"); + return -ENOMEM; + } + +- platform_set_drvdata(pdev, master); +- sspi = spi_master_get_devdata(master); ++ platform_set_drvdata(pdev, host); ++ sspi = spi_controller_get_devdata(host); + + sspi->base_addr = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(sspi->base_addr)) { + ret = PTR_ERR(sspi->base_addr); +- goto err_free_master; ++ goto err_free_host; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = -ENXIO; +- goto err_free_master; ++ goto err_free_host; + } + + ret = devm_request_irq(&pdev->dev, irq, sun4i_spi_handler, + 0, "sun4i-spi", sspi); + if (ret) { + dev_err(&pdev->dev, "Cannot request IRQ\n"); +- goto err_free_master; ++ goto err_free_host; + } + +- sspi->master = master; +- master->max_speed_hz = 100 * 1000 * 1000; +- master->min_speed_hz = 3 * 1000; +- master->set_cs = sun4i_spi_set_cs; +- master->transfer_one = sun4i_spi_transfer_one; +- master->num_chipselect = 4; +- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; +- master->bits_per_word_mask = SPI_BPW_MASK(8); +- master->dev.of_node = pdev->dev.of_node; +- master->auto_runtime_pm = true; +- master->max_transfer_size = sun4i_spi_max_transfer_size; ++ sspi->host = host; ++ host->max_speed_hz = 100 * 1000 * 1000; ++ host->min_speed_hz = 3 * 1000; ++ host->set_cs = sun4i_spi_set_cs; ++ host->transfer_one = sun4i_spi_transfer_one; ++ host->num_chipselect = 4; ++ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; ++ host->bits_per_word_mask = SPI_BPW_MASK(8); ++ host->dev.of_node = pdev->dev.of_node; ++ host->auto_runtime_pm = true; ++ host->max_transfer_size = sun4i_spi_max_transfer_size; + + sspi->hclk = devm_clk_get(&pdev->dev, "ahb"); + if (IS_ERR(sspi->hclk)) { + dev_err(&pdev->dev, "Unable to acquire AHB clock\n"); + ret = PTR_ERR(sspi->hclk); +- goto err_free_master; ++ goto err_free_host; + } + + sspi->mclk = devm_clk_get(&pdev->dev, "mod"); + if (IS_ERR(sspi->mclk)) { + dev_err(&pdev->dev, "Unable to acquire module clock\n"); + ret = PTR_ERR(sspi->mclk); +- goto err_free_master; ++ goto err_free_host; + } + + init_completion(&sspi->done); +@@ -496,16 +496,16 @@ static int sun4i_spi_probe(struct platfo + ret = sun4i_spi_runtime_resume(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "Couldn't resume the device\n"); +- goto err_free_master; ++ goto err_free_host; + } + + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_idle(&pdev->dev); + +- ret = devm_spi_register_master(&pdev->dev, master); ++ ret = devm_spi_register_controller(&pdev->dev, host); + if (ret) { +- dev_err(&pdev->dev, "cannot register SPI master\n"); ++ dev_err(&pdev->dev, "cannot register SPI host\n"); + goto err_pm_disable; + } + +@@ -514,8 +514,8 @@ static int sun4i_spi_probe(struct platfo + err_pm_disable: + pm_runtime_disable(&pdev->dev); + sun4i_spi_runtime_suspend(&pdev->dev); +-err_free_master: +- spi_master_put(master); ++err_free_host: ++ spi_controller_put(host); + return ret; + } + diff --git a/queue-6.6/spi-sun6i-fix-controller-deregistration.patch b/queue-6.6/spi-sun6i-fix-controller-deregistration.patch new file mode 100644 index 0000000000..c559c43af0 --- /dev/null +++ b/queue-6.6/spi-sun6i-fix-controller-deregistration.patch @@ -0,0 +1,57 @@ +From stable+bounces-247048-greg=kroah.com@vger.kernel.org Thu May 14 01:06:27 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 19:05:13 -0400 +Subject: spi: sun6i: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Maxime Ripard , Mark Brown , Sasha Levin +Message-ID: <20260513230513.4027915-2-sashal@kernel.org> + +From: Johan Hovold + +[ Upstream commit d874a1c33aee0d88fb4ba2f8aeadaa9f1965209a ] + +Make sure to deregister the controller before disabling underlying +resources like clocks during driver unbind. + +Fixes: 3558fe900e8a ("spi: sunxi: Add Allwinner A31 SPI controller driver") +Cc: stable@vger.kernel.org # 3.15 +Cc: Maxime Ripard +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410081757.503099-20-johan@kernel.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-sun6i.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/drivers/spi/spi-sun6i.c ++++ b/drivers/spi/spi-sun6i.c +@@ -742,7 +742,7 @@ static int sun6i_spi_probe(struct platfo + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + +- ret = devm_spi_register_controller(&pdev->dev, host); ++ ret = spi_register_controller(host); + if (ret) { + dev_err(&pdev->dev, "cannot register SPI host\n"); + goto err_pm_disable; +@@ -768,12 +768,18 @@ static void sun6i_spi_remove(struct plat + { + struct spi_controller *host = platform_get_drvdata(pdev); + ++ spi_controller_get(host); ++ ++ spi_unregister_controller(host); ++ + pm_runtime_force_suspend(&pdev->dev); + + 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 sun6i_spi_cfg sun6i_a31_spi_cfg = { diff --git a/queue-6.6/spi-sun6i-switch-to-use-modern-name.patch b/queue-6.6/spi-sun6i-switch-to-use-modern-name.patch new file mode 100644 index 0000000000..2e1de742e8 --- /dev/null +++ b/queue-6.6/spi-sun6i-switch-to-use-modern-name.patch @@ -0,0 +1,392 @@ +From stable+bounces-247047-greg=kroah.com@vger.kernel.org Thu May 14 01:06:20 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 19:05:12 -0400 +Subject: spi: sun6i: switch to use modern name +To: stable@vger.kernel.org +Cc: Yang Yingliang , Mark Brown , Sasha Levin +Message-ID: <20260513230513.4027915-1-sashal@kernel.org> + +From: Yang Yingliang + +[ Upstream commit 9f55bb79893a9dc75982372bee1307bdce48976b ] + +Change legacy name master to modern name host or controller. + +No functional changed. + +Signed-off-by: Yang Yingliang +Link: https://msgid.link/r/20231128093031.3707034-8-yangyingliang@huawei.com +Signed-off-by: Mark Brown +Stable-dep-of: d874a1c33aee ("spi: sun6i: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-sun6i.c | 148 ++++++++++++++++++++++++------------------------ + 1 file changed, 74 insertions(+), 74 deletions(-) + +--- a/drivers/spi/spi-sun6i.c ++++ b/drivers/spi/spi-sun6i.c +@@ -97,7 +97,7 @@ struct sun6i_spi_cfg { + }; + + struct sun6i_spi { +- struct spi_master *master; ++ struct spi_controller *host; + void __iomem *base_addr; + dma_addr_t dma_addr_rx; + dma_addr_t dma_addr_tx; +@@ -181,7 +181,7 @@ static inline void sun6i_spi_fill_fifo(s + + static void sun6i_spi_set_cs(struct spi_device *spi, bool enable) + { +- struct sun6i_spi *sspi = spi_master_get_devdata(spi->master); ++ struct sun6i_spi *sspi = spi_controller_get_devdata(spi->controller); + u32 reg; + + reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG); +@@ -212,7 +212,7 @@ static int sun6i_spi_prepare_dma(struct + struct spi_transfer *tfr) + { + struct dma_async_tx_descriptor *rxdesc, *txdesc; +- struct spi_master *master = sspi->master; ++ struct spi_controller *host = sspi->host; + + rxdesc = NULL; + if (tfr->rx_buf) { +@@ -223,9 +223,9 @@ static int sun6i_spi_prepare_dma(struct + .src_maxburst = 8, + }; + +- dmaengine_slave_config(master->dma_rx, &rxconf); ++ dmaengine_slave_config(host->dma_rx, &rxconf); + +- rxdesc = dmaengine_prep_slave_sg(master->dma_rx, ++ rxdesc = dmaengine_prep_slave_sg(host->dma_rx, + tfr->rx_sg.sgl, + tfr->rx_sg.nents, + DMA_DEV_TO_MEM, +@@ -245,38 +245,38 @@ static int sun6i_spi_prepare_dma(struct + .dst_maxburst = 8, + }; + +- dmaengine_slave_config(master->dma_tx, &txconf); ++ dmaengine_slave_config(host->dma_tx, &txconf); + +- txdesc = dmaengine_prep_slave_sg(master->dma_tx, ++ txdesc = dmaengine_prep_slave_sg(host->dma_tx, + tfr->tx_sg.sgl, + tfr->tx_sg.nents, + DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT); + if (!txdesc) { + if (rxdesc) +- dmaengine_terminate_sync(master->dma_rx); ++ dmaengine_terminate_sync(host->dma_rx); + return -EINVAL; + } + } + + if (tfr->rx_buf) { + dmaengine_submit(rxdesc); +- dma_async_issue_pending(master->dma_rx); ++ dma_async_issue_pending(host->dma_rx); + } + + if (tfr->tx_buf) { + dmaengine_submit(txdesc); +- dma_async_issue_pending(master->dma_tx); ++ dma_async_issue_pending(host->dma_tx); + } + + return 0; + } + +-static int sun6i_spi_transfer_one(struct spi_master *master, ++static int sun6i_spi_transfer_one(struct spi_controller *host, + struct spi_device *spi, + struct spi_transfer *tfr) + { +- struct sun6i_spi *sspi = spi_master_get_devdata(master); ++ struct sun6i_spi *sspi = spi_controller_get_devdata(host); + unsigned int div, div_cdr1, div_cdr2, timeout; + unsigned int start, end, tx_time; + unsigned int trig_level; +@@ -293,7 +293,7 @@ static int sun6i_spi_transfer_one(struct + sspi->tx_buf = tfr->tx_buf; + sspi->rx_buf = tfr->rx_buf; + sspi->len = tfr->len; +- use_dma = master->can_dma ? master->can_dma(master, spi, tfr) : false; ++ use_dma = host->can_dma ? host->can_dma(host, spi, tfr) : false; + + /* Clear pending interrupts */ + sun6i_spi_write(sspi, SUN6I_INT_STA_REG, ~0); +@@ -463,7 +463,7 @@ static int sun6i_spi_transfer_one(struct + } else { + ret = sun6i_spi_prepare_dma(sspi, tfr); + if (ret) { +- dev_warn(&master->dev, ++ dev_warn(&host->dev, + "%s: prepare DMA failed, ret=%d", + dev_name(&spi->dev), ret); + return ret; +@@ -486,7 +486,7 @@ static int sun6i_spi_transfer_one(struct + reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG); + sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH); + +- tx_time = spi_controller_xfer_timeout(master, tfr); ++ tx_time = spi_controller_xfer_timeout(host, tfr); + start = jiffies; + timeout = wait_for_completion_timeout(&sspi->done, + msecs_to_jiffies(tx_time)); +@@ -502,13 +502,13 @@ static int sun6i_spi_transfer_one(struct + timeout = wait_for_completion_timeout(&sspi->dma_rx_done, + timeout); + if (!timeout) +- dev_warn(&master->dev, "RX DMA timeout\n"); ++ dev_warn(&host->dev, "RX DMA timeout\n"); + } + } + + end = jiffies; + if (!timeout) { +- dev_warn(&master->dev, ++ dev_warn(&host->dev, + "%s: timeout transferring %u bytes@%iHz for %i(%i)ms", + dev_name(&spi->dev), tfr->len, tfr->speed_hz, + jiffies_to_msecs(end - start), tx_time); +@@ -518,8 +518,8 @@ static int sun6i_spi_transfer_one(struct + sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0); + + if (ret && use_dma) { +- dmaengine_terminate_sync(master->dma_rx); +- dmaengine_terminate_sync(master->dma_tx); ++ dmaengine_terminate_sync(host->dma_rx); ++ dmaengine_terminate_sync(host->dma_tx); + } + + return ret; +@@ -564,8 +564,8 @@ static irqreturn_t sun6i_spi_handler(int + + static int sun6i_spi_runtime_resume(struct device *dev) + { +- struct spi_master *master = dev_get_drvdata(dev); +- struct sun6i_spi *sspi = spi_master_get_devdata(master); ++ struct spi_controller *host = dev_get_drvdata(dev); ++ struct sun6i_spi *sspi = spi_controller_get_devdata(host); + int ret; + + ret = clk_prepare_enable(sspi->hclk); +@@ -601,8 +601,8 @@ out: + + static int sun6i_spi_runtime_suspend(struct device *dev) + { +- struct spi_master *master = dev_get_drvdata(dev); +- struct sun6i_spi *sspi = spi_master_get_devdata(master); ++ struct spi_controller *host = dev_get_drvdata(dev); ++ struct sun6i_spi *sspi = spi_controller_get_devdata(host); + + reset_control_assert(sspi->rstc); + clk_disable_unprepare(sspi->mclk); +@@ -611,11 +611,11 @@ static int sun6i_spi_runtime_suspend(str + return 0; + } + +-static bool sun6i_spi_can_dma(struct spi_master *master, ++static bool sun6i_spi_can_dma(struct spi_controller *host, + struct spi_device *spi, + struct spi_transfer *xfer) + { +- struct sun6i_spi *sspi = spi_master_get_devdata(master); ++ struct sun6i_spi *sspi = spi_controller_get_devdata(host); + + /* + * If the number of spi words to transfer is less or equal than +@@ -627,67 +627,67 @@ static bool sun6i_spi_can_dma(struct spi + + static int sun6i_spi_probe(struct platform_device *pdev) + { +- struct spi_master *master; ++ struct spi_controller *host; + struct sun6i_spi *sspi; + struct resource *mem; + int ret = 0, irq; + +- master = spi_alloc_master(&pdev->dev, sizeof(struct sun6i_spi)); +- if (!master) { +- dev_err(&pdev->dev, "Unable to allocate SPI Master\n"); ++ host = spi_alloc_host(&pdev->dev, sizeof(struct sun6i_spi)); ++ if (!host) { ++ dev_err(&pdev->dev, "Unable to allocate SPI Host\n"); + return -ENOMEM; + } + +- platform_set_drvdata(pdev, master); +- sspi = spi_master_get_devdata(master); ++ platform_set_drvdata(pdev, host); ++ sspi = spi_controller_get_devdata(host); + + sspi->base_addr = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); + if (IS_ERR(sspi->base_addr)) { + ret = PTR_ERR(sspi->base_addr); +- goto err_free_master; ++ goto err_free_host; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = -ENXIO; +- goto err_free_master; ++ goto err_free_host; + } + + ret = devm_request_irq(&pdev->dev, irq, sun6i_spi_handler, + 0, "sun6i-spi", sspi); + if (ret) { + dev_err(&pdev->dev, "Cannot request IRQ\n"); +- goto err_free_master; ++ goto err_free_host; + } + +- sspi->master = master; ++ sspi->host = host; + sspi->cfg = of_device_get_match_data(&pdev->dev); + +- master->max_speed_hz = 100 * 1000 * 1000; +- master->min_speed_hz = 3 * 1000; +- master->use_gpio_descriptors = true; +- master->set_cs = sun6i_spi_set_cs; +- master->transfer_one = sun6i_spi_transfer_one; +- master->num_chipselect = 4; +- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST | +- sspi->cfg->mode_bits; +- master->bits_per_word_mask = SPI_BPW_MASK(8); +- master->dev.of_node = pdev->dev.of_node; +- master->auto_runtime_pm = true; +- master->max_transfer_size = sun6i_spi_max_transfer_size; ++ host->max_speed_hz = 100 * 1000 * 1000; ++ host->min_speed_hz = 3 * 1000; ++ host->use_gpio_descriptors = true; ++ host->set_cs = sun6i_spi_set_cs; ++ host->transfer_one = sun6i_spi_transfer_one; ++ host->num_chipselect = 4; ++ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST | ++ sspi->cfg->mode_bits; ++ host->bits_per_word_mask = SPI_BPW_MASK(8); ++ host->dev.of_node = pdev->dev.of_node; ++ host->auto_runtime_pm = true; ++ host->max_transfer_size = sun6i_spi_max_transfer_size; + + sspi->hclk = devm_clk_get(&pdev->dev, "ahb"); + if (IS_ERR(sspi->hclk)) { + dev_err(&pdev->dev, "Unable to acquire AHB clock\n"); + ret = PTR_ERR(sspi->hclk); +- goto err_free_master; ++ goto err_free_host; + } + + sspi->mclk = devm_clk_get(&pdev->dev, "mod"); + if (IS_ERR(sspi->mclk)) { + dev_err(&pdev->dev, "Unable to acquire module clock\n"); + ret = PTR_ERR(sspi->mclk); +- goto err_free_master; ++ goto err_free_host; + } + + init_completion(&sspi->done); +@@ -697,34 +697,34 @@ static int sun6i_spi_probe(struct platfo + if (IS_ERR(sspi->rstc)) { + dev_err(&pdev->dev, "Couldn't get reset controller\n"); + ret = PTR_ERR(sspi->rstc); +- goto err_free_master; ++ goto err_free_host; + } + +- master->dma_tx = dma_request_chan(&pdev->dev, "tx"); +- if (IS_ERR(master->dma_tx)) { ++ host->dma_tx = dma_request_chan(&pdev->dev, "tx"); ++ if (IS_ERR(host->dma_tx)) { + /* Check tx to see if we need defer probing driver */ +- if (PTR_ERR(master->dma_tx) == -EPROBE_DEFER) { ++ if (PTR_ERR(host->dma_tx) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; +- goto err_free_master; ++ goto err_free_host; + } + dev_warn(&pdev->dev, "Failed to request TX DMA channel\n"); +- master->dma_tx = NULL; ++ host->dma_tx = NULL; + } + +- master->dma_rx = dma_request_chan(&pdev->dev, "rx"); +- if (IS_ERR(master->dma_rx)) { +- if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER) { ++ host->dma_rx = dma_request_chan(&pdev->dev, "rx"); ++ if (IS_ERR(host->dma_rx)) { ++ if (PTR_ERR(host->dma_rx) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err_free_dma_tx; + } + dev_warn(&pdev->dev, "Failed to request RX DMA channel\n"); +- master->dma_rx = NULL; ++ host->dma_rx = NULL; + } + +- if (master->dma_tx && master->dma_rx) { ++ if (host->dma_tx && host->dma_rx) { + sspi->dma_addr_tx = mem->start + SUN6I_TXDATA_REG; + sspi->dma_addr_rx = mem->start + SUN6I_RXDATA_REG; +- master->can_dma = sun6i_spi_can_dma; ++ host->can_dma = sun6i_spi_can_dma; + } + + /* +@@ -742,9 +742,9 @@ static int sun6i_spi_probe(struct platfo + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + +- ret = devm_spi_register_master(&pdev->dev, master); ++ ret = devm_spi_register_controller(&pdev->dev, host); + if (ret) { +- dev_err(&pdev->dev, "cannot register SPI master\n"); ++ dev_err(&pdev->dev, "cannot register SPI host\n"); + goto err_pm_disable; + } + +@@ -754,26 +754,26 @@ err_pm_disable: + pm_runtime_disable(&pdev->dev); + sun6i_spi_runtime_suspend(&pdev->dev); + err_free_dma_rx: +- if (master->dma_rx) +- dma_release_channel(master->dma_rx); ++ if (host->dma_rx) ++ dma_release_channel(host->dma_rx); + err_free_dma_tx: +- if (master->dma_tx) +- dma_release_channel(master->dma_tx); +-err_free_master: +- spi_master_put(master); ++ if (host->dma_tx) ++ dma_release_channel(host->dma_tx); ++err_free_host: ++ spi_controller_put(host); + return ret; + } + + static void sun6i_spi_remove(struct platform_device *pdev) + { +- struct spi_master *master = platform_get_drvdata(pdev); ++ struct spi_controller *host = platform_get_drvdata(pdev); + + pm_runtime_force_suspend(&pdev->dev); + +- if (master->dma_tx) +- dma_release_channel(master->dma_tx); +- if (master->dma_rx) +- dma_release_channel(master->dma_rx); ++ if (host->dma_tx) ++ dma_release_channel(host->dma_tx); ++ if (host->dma_rx) ++ dma_release_channel(host->dma_rx); + } + + static const struct sun6i_spi_cfg sun6i_a31_spi_cfg = { diff --git a/queue-6.6/spi-syncuacer-fix-controller-deregistration.patch b/queue-6.6/spi-syncuacer-fix-controller-deregistration.patch new file mode 100644 index 0000000000..cc203996ab --- /dev/null +++ b/queue-6.6/spi-syncuacer-fix-controller-deregistration.patch @@ -0,0 +1,54 @@ +From stable+bounces-246969-greg=kroah.com@vger.kernel.org Wed May 13 19:42:05 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 13:31:54 -0400 +Subject: spi: syncuacer: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Masahisa Kojima , Mark Brown , Sasha Levin +Message-ID: <20260513173154.3886494-2-sashal@kernel.org> + +From: Johan Hovold + +[ Upstream commit 75d849c3452e9611de031db45b3149ba9a99035f ] + +Make sure to deregister the controller before disabling underlying +resources like clocks during driver unbind. + +Fixes: b0823ee35cf9 ("spi: Add spi driver for Socionext SynQuacer platform") +Cc: stable@vger.kernel.org # 5.3 +Cc: Masahisa Kojima +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410081757.503099-21-johan@kernel.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-synquacer.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/drivers/spi/spi-synquacer.c ++++ b/drivers/spi/spi-synquacer.c +@@ -719,7 +719,7 @@ static int synquacer_spi_probe(struct pl + pm_runtime_set_active(sspi->dev); + pm_runtime_enable(sspi->dev); + +- ret = devm_spi_register_controller(sspi->dev, host); ++ ret = spi_register_controller(host); + if (ret) + goto disable_pm; + +@@ -740,9 +740,15 @@ static void synquacer_spi_remove(struct + struct spi_controller *host = platform_get_drvdata(pdev); + struct synquacer_spi *sspi = spi_controller_get_devdata(host); + ++ spi_controller_get(host); ++ ++ spi_unregister_controller(host); ++ + pm_runtime_disable(sspi->dev); + + clk_disable_unprepare(sspi->clk); ++ ++ spi_controller_put(host); + } + + static int __maybe_unused synquacer_spi_suspend(struct device *dev) diff --git a/queue-6.6/spi-synquacer-switch-to-use-modern-name.patch b/queue-6.6/spi-synquacer-switch-to-use-modern-name.patch new file mode 100644 index 0000000000..efa3713a08 --- /dev/null +++ b/queue-6.6/spi-synquacer-switch-to-use-modern-name.patch @@ -0,0 +1,260 @@ +From stable+bounces-246968-greg=kroah.com@vger.kernel.org Wed May 13 19:32:28 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 13:31:53 -0400 +Subject: spi: synquacer: switch to use modern name +To: stable@vger.kernel.org +Cc: Yang Yingliang , Mark Brown , Sasha Levin +Message-ID: <20260513173154.3886494-1-sashal@kernel.org> + +From: Yang Yingliang + +[ Upstream commit 3524d1b727a66712f02f92807219a3650e5cf910 ] + +Change legacy name master to modern name host or controller. + +No functional changed. + +Signed-off-by: Yang Yingliang +Link: https://msgid.link/r/20231128093031.3707034-10-yangyingliang@huawei.com +Signed-off-by: Mark Brown +Stable-dep-of: 75d849c3452e ("spi: syncuacer: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-synquacer.c | 84 ++++++++++++++++++++++---------------------- + 1 file changed, 42 insertions(+), 42 deletions(-) + +--- a/drivers/spi/spi-synquacer.c ++++ b/drivers/spi/spi-synquacer.c +@@ -225,11 +225,11 @@ static int write_fifo(struct synquacer_s + return 0; + } + +-static int synquacer_spi_config(struct spi_master *master, ++static int synquacer_spi_config(struct spi_controller *host, + struct spi_device *spi, + struct spi_transfer *xfer) + { +- struct synquacer_spi *sspi = spi_master_get_devdata(master); ++ struct synquacer_spi *sspi = spi_controller_get_devdata(host); + unsigned int speed, mode, bpw, cs, bus_width, transfer_mode; + u32 rate, val, div; + +@@ -263,7 +263,7 @@ static int synquacer_spi_config(struct s + } + + sspi->transfer_mode = transfer_mode; +- rate = master->max_speed_hz; ++ rate = host->max_speed_hz; + + div = DIV_ROUND_UP(rate, speed); + if (div > 254) { +@@ -350,11 +350,11 @@ static int synquacer_spi_config(struct s + return 0; + } + +-static int synquacer_spi_transfer_one(struct spi_master *master, ++static int synquacer_spi_transfer_one(struct spi_controller *host, + struct spi_device *spi, + struct spi_transfer *xfer) + { +- struct synquacer_spi *sspi = spi_master_get_devdata(master); ++ struct synquacer_spi *sspi = spi_controller_get_devdata(host); + int ret; + int status = 0; + u32 words; +@@ -378,7 +378,7 @@ static int synquacer_spi_transfer_one(st + if (bpw == 8 && !(xfer->len % 4) && !(spi->mode & SPI_LSB_FIRST)) + xfer->bits_per_word = 32; + +- ret = synquacer_spi_config(master, spi, xfer); ++ ret = synquacer_spi_config(host, spi, xfer); + + /* restore */ + xfer->bits_per_word = bpw; +@@ -482,7 +482,7 @@ static int synquacer_spi_transfer_one(st + + static void synquacer_spi_set_cs(struct spi_device *spi, bool enable) + { +- struct synquacer_spi *sspi = spi_master_get_devdata(spi->master); ++ struct synquacer_spi *sspi = spi_controller_get_devdata(spi->controller); + u32 val; + + val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); +@@ -517,11 +517,11 @@ static int synquacer_spi_wait_status_upd + return -EBUSY; + } + +-static int synquacer_spi_enable(struct spi_master *master) ++static int synquacer_spi_enable(struct spi_controller *host) + { + u32 val; + int status; +- struct synquacer_spi *sspi = spi_master_get_devdata(master); ++ struct synquacer_spi *sspi = spi_controller_get_devdata(host); + + /* Disable module */ + writel(0, sspi->regs + SYNQUACER_HSSPI_REG_MCTRL); +@@ -601,18 +601,18 @@ static irqreturn_t sq_spi_tx_handler(int + static int synquacer_spi_probe(struct platform_device *pdev) + { + struct device_node *np = pdev->dev.of_node; +- struct spi_master *master; ++ struct spi_controller *host; + struct synquacer_spi *sspi; + int ret; + int rx_irq, tx_irq; + +- master = spi_alloc_master(&pdev->dev, sizeof(*sspi)); +- if (!master) ++ host = spi_alloc_host(&pdev->dev, sizeof(*sspi)); ++ if (!host) + return -ENOMEM; + +- platform_set_drvdata(pdev, master); ++ platform_set_drvdata(pdev, host); + +- sspi = spi_master_get_devdata(master); ++ sspi = spi_controller_get_devdata(host); + sspi->dev = &pdev->dev; + + init_completion(&sspi->transfer_done); +@@ -625,7 +625,7 @@ static int synquacer_spi_probe(struct pl + + sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IHCLK; /* Default */ + device_property_read_u32(&pdev->dev, "socionext,ihclk-rate", +- &master->max_speed_hz); /* for ACPI */ ++ &host->max_speed_hz); /* for ACPI */ + + if (dev_of_node(&pdev->dev)) { + if (device_property_match_string(&pdev->dev, +@@ -655,21 +655,21 @@ static int synquacer_spi_probe(struct pl + goto put_spi; + } + +- master->max_speed_hz = clk_get_rate(sspi->clk); ++ host->max_speed_hz = clk_get_rate(sspi->clk); + } + +- if (!master->max_speed_hz) { ++ if (!host->max_speed_hz) { + dev_err(&pdev->dev, "missing clock source\n"); + ret = -EINVAL; + goto disable_clk; + } +- master->min_speed_hz = master->max_speed_hz / 254; ++ host->min_speed_hz = host->max_speed_hz / 254; + + sspi->aces = device_property_read_bool(&pdev->dev, + "socionext,set-aces"); + sspi->rtm = device_property_read_bool(&pdev->dev, "socionext,use-rtm"); + +- master->num_chipselect = SYNQUACER_HSSPI_NUM_CHIP_SELECT; ++ host->num_chipselect = SYNQUACER_HSSPI_NUM_CHIP_SELECT; + + rx_irq = platform_get_irq(pdev, 0); + if (rx_irq <= 0) { +@@ -699,27 +699,27 @@ static int synquacer_spi_probe(struct pl + goto disable_clk; + } + +- master->dev.of_node = np; +- master->dev.fwnode = pdev->dev.fwnode; +- master->auto_runtime_pm = true; +- master->bus_num = pdev->id; +- +- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL | +- SPI_TX_QUAD | SPI_RX_QUAD; +- master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(24) | +- SPI_BPW_MASK(16) | SPI_BPW_MASK(8); ++ host->dev.of_node = np; ++ host->dev.fwnode = pdev->dev.fwnode; ++ host->auto_runtime_pm = true; ++ host->bus_num = pdev->id; ++ ++ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL | ++ SPI_TX_QUAD | SPI_RX_QUAD; ++ host->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(24) | ++ SPI_BPW_MASK(16) | SPI_BPW_MASK(8); + +- master->set_cs = synquacer_spi_set_cs; +- master->transfer_one = synquacer_spi_transfer_one; ++ host->set_cs = synquacer_spi_set_cs; ++ host->transfer_one = synquacer_spi_transfer_one; + +- ret = synquacer_spi_enable(master); ++ ret = synquacer_spi_enable(host); + if (ret) + goto disable_clk; + + pm_runtime_set_active(sspi->dev); + pm_runtime_enable(sspi->dev); + +- ret = devm_spi_register_master(sspi->dev, master); ++ ret = devm_spi_register_controller(sspi->dev, host); + if (ret) + goto disable_pm; + +@@ -730,15 +730,15 @@ disable_pm: + disable_clk: + clk_disable_unprepare(sspi->clk); + put_spi: +- spi_master_put(master); ++ spi_controller_put(host); + + return ret; + } + + static void synquacer_spi_remove(struct platform_device *pdev) + { +- struct spi_master *master = platform_get_drvdata(pdev); +- struct synquacer_spi *sspi = spi_master_get_devdata(master); ++ struct spi_controller *host = platform_get_drvdata(pdev); ++ struct synquacer_spi *sspi = spi_controller_get_devdata(host); + + pm_runtime_disable(sspi->dev); + +@@ -747,11 +747,11 @@ static void synquacer_spi_remove(struct + + static int __maybe_unused synquacer_spi_suspend(struct device *dev) + { +- struct spi_master *master = dev_get_drvdata(dev); +- struct synquacer_spi *sspi = spi_master_get_devdata(master); ++ struct spi_controller *host = dev_get_drvdata(dev); ++ struct synquacer_spi *sspi = spi_controller_get_devdata(host); + int ret; + +- ret = spi_master_suspend(master); ++ ret = spi_controller_suspend(host); + if (ret) + return ret; + +@@ -763,8 +763,8 @@ static int __maybe_unused synquacer_spi_ + + static int __maybe_unused synquacer_spi_resume(struct device *dev) + { +- struct spi_master *master = dev_get_drvdata(dev); +- struct synquacer_spi *sspi = spi_master_get_devdata(master); ++ struct spi_controller *host = dev_get_drvdata(dev); ++ struct synquacer_spi *sspi = spi_controller_get_devdata(host); + int ret; + + if (!pm_runtime_suspended(dev)) { +@@ -778,7 +778,7 @@ static int __maybe_unused synquacer_spi_ + return ret; + } + +- ret = synquacer_spi_enable(master); ++ ret = synquacer_spi_enable(host); + if (ret) { + clk_disable_unprepare(sspi->clk); + dev_err(dev, "failed to enable spi (%d)\n", ret); +@@ -786,7 +786,7 @@ static int __maybe_unused synquacer_spi_ + } + } + +- ret = spi_master_resume(master); ++ ret = spi_controller_resume(host); + if (ret < 0) + clk_disable_unprepare(sspi->clk); + diff --git a/queue-6.6/spi-tegra114-fix-controller-deregistration.patch b/queue-6.6/spi-tegra114-fix-controller-deregistration.patch new file mode 100644 index 0000000000..00a547f207 --- /dev/null +++ b/queue-6.6/spi-tegra114-fix-controller-deregistration.patch @@ -0,0 +1,59 @@ +From stable+bounces-247112-greg=kroah.com@vger.kernel.org Thu May 14 06:59:29 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 00:59:22 -0400 +Subject: spi: tegra114: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Jingoo Han , Mark Brown , Sasha Levin +Message-ID: <20260514045922.25250-1-sashal@kernel.org> + +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 +[ renamed spi_controller/host API calls to spi_master/master equivalents ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-tegra114.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/drivers/spi/spi-tegra114.c ++++ b/drivers/spi/spi-tegra114.c +@@ -1416,7 +1416,7 @@ static int tegra_spi_probe(struct platfo + } + + master->dev.of_node = pdev->dev.of_node; +- ret = devm_spi_register_master(&pdev->dev, master); ++ ret = spi_register_master(master); + if (ret < 0) { + dev_err(&pdev->dev, "can not register to master err %d\n", ret); + goto exit_free_irq; +@@ -1442,6 +1442,10 @@ static void tegra_spi_remove(struct plat + struct spi_master *master = platform_get_drvdata(pdev); + struct tegra_spi_data *tspi = spi_master_get_devdata(master); + ++ spi_master_get(master); ++ ++ spi_unregister_master(master); ++ + free_irq(tspi->irq, tspi); + + if (tspi->tx_dma_chan) +@@ -1453,6 +1457,8 @@ static void tegra_spi_remove(struct plat + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + tegra_spi_runtime_suspend(&pdev->dev); ++ ++ spi_master_put(master); + } + + #ifdef CONFIG_PM_SLEEP diff --git a/queue-6.6/spi-tegra20-sflash-fix-controller-deregistration.patch b/queue-6.6/spi-tegra20-sflash-fix-controller-deregistration.patch new file mode 100644 index 0000000000..55ff036eca --- /dev/null +++ b/queue-6.6/spi-tegra20-sflash-fix-controller-deregistration.patch @@ -0,0 +1,57 @@ +From stable+bounces-247113-greg=kroah.com@vger.kernel.org Thu May 14 06:59:42 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 00:59:34 -0400 +Subject: spi: tegra20-sflash: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Jingoo Han , Mark Brown , Sasha Levin +Message-ID: <20260514045934.26261-1-sashal@kernel.org> + +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 +[ translated spi_controller/host API to legacy spi_master/master naming and dropped devm-managed registration ] +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(-) + +--- a/drivers/spi/spi-tegra20-sflash.c ++++ b/drivers/spi/spi-tegra20-sflash.c +@@ -506,7 +506,7 @@ static int tegra_sflash_probe(struct pla + pm_runtime_put(&pdev->dev); + + master->dev.of_node = pdev->dev.of_node; +- ret = devm_spi_register_master(&pdev->dev, master); ++ ret = spi_register_master(master); + if (ret < 0) { + dev_err(&pdev->dev, "can not register to master err %d\n", ret); + goto exit_pm_disable; +@@ -529,11 +529,17 @@ static void tegra_sflash_remove(struct p + struct spi_master *master = platform_get_drvdata(pdev); + struct tegra_sflash_data *tsd = spi_master_get_devdata(master); + ++ spi_master_get(master); ++ ++ spi_unregister_master(master); ++ + free_irq(tsd->irq, tsd); + + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + tegra_sflash_runtime_suspend(&pdev->dev); ++ ++ spi_master_put(master); + } + + #ifdef CONFIG_PM_SLEEP diff --git a/queue-6.6/spi-ti-qspi-fix-controller-deregistration.patch b/queue-6.6/spi-ti-qspi-fix-controller-deregistration.patch new file mode 100644 index 0000000000..18f53f5526 --- /dev/null +++ b/queue-6.6/spi-ti-qspi-fix-controller-deregistration.patch @@ -0,0 +1,69 @@ +From stable+bounces-246997-greg=kroah.com@vger.kernel.org Wed May 13 20:10:45 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 14:08:42 -0400 +Subject: spi: ti-qspi: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Sebastian Andrzej Siewior , Mark Brown , Sasha Levin +Message-ID: <20260513180842.3912849-3-sashal@kernel.org> + +From: Johan Hovold + +[ Upstream commit 0c18a1bacbb1d8b8aa34d3d004a2cb8226c8b1ea ] + +Make sure to deregister the controller before disabling underlying +resources like clocks during driver unbind. + +Note that the controller is suspended before disabling and releasing +resources since commit 3ac066e2227c ("spi: spi-ti-qspi: Suspend the +queue before removing the device") which avoids issues like unclocked +accesses but prevents SPI device drivers from doing I/O during +deregistration. + +Fixes: 3b3a80019ff1 ("spi: ti-qspi: one only one interrupt handler") +Cc: stable@vger.kernel.org # 3.13 +Cc: Sebastian Andrzej Siewior +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410081757.503099-24-johan@kernel.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-ti-qspi.c | 14 ++++++-------- + 1 file changed, 6 insertions(+), 8 deletions(-) + +--- a/drivers/spi/spi-ti-qspi.c ++++ b/drivers/spi/spi-ti-qspi.c +@@ -895,7 +895,7 @@ no_dma: + qspi->mmap_enabled = false; + qspi->current_cs = -1; + +- ret = devm_spi_register_controller(&pdev->dev, host); ++ ret = spi_register_controller(host); + if (!ret) + return 0; + +@@ -910,19 +910,17 @@ free_host: + static void ti_qspi_remove(struct platform_device *pdev) + { + struct ti_qspi *qspi = platform_get_drvdata(pdev); +- int rc; + +- rc = spi_controller_suspend(qspi->host); +- if (rc) { +- dev_alert(&pdev->dev, "spi_controller_suspend() failed (%pe)\n", +- ERR_PTR(rc)); +- return; +- } ++ spi_controller_get(qspi->host); ++ ++ spi_unregister_controller(qspi->host); + + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + ti_qspi_dma_cleanup(qspi); ++ ++ spi_controller_put(qspi->host); + } + + static const struct dev_pm_ops ti_qspi_pm_ops = { diff --git a/queue-6.6/spi-uniphier-fix-controller-deregistration.patch b/queue-6.6/spi-uniphier-fix-controller-deregistration.patch new file mode 100644 index 0000000000..8013e96a3e --- /dev/null +++ b/queue-6.6/spi-uniphier-fix-controller-deregistration.patch @@ -0,0 +1,59 @@ +From stable+bounces-247177-greg=kroah.com@vger.kernel.org Thu May 14 13:46:41 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 07:46:35 -0400 +Subject: spi: uniphier: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Keiji Hayashibara , Mark Brown , Sasha Levin +Message-ID: <20260514114635.181243-3-sashal@kernel.org> + +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(-) + +--- a/drivers/spi/spi-uniphier.c ++++ b/drivers/spi/spi-uniphier.c +@@ -747,7 +747,7 @@ static int uniphier_spi_probe(struct pla + + 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 p + { + 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[] = { diff --git a/queue-6.6/spi-uniphier-simplify-clock-handling-with-devm_clk_get_enabled.patch b/queue-6.6/spi-uniphier-simplify-clock-handling-with-devm_clk_get_enabled.patch new file mode 100644 index 0000000000..d7fc766a73 --- /dev/null +++ b/queue-6.6/spi-uniphier-simplify-clock-handling-with-devm_clk_get_enabled.patch @@ -0,0 +1,99 @@ +From stable+bounces-247176-greg=kroah.com@vger.kernel.org Thu May 14 13:46:42 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 07:46:34 -0400 +Subject: spi: uniphier: Simplify clock handling with devm_clk_get_enabled() +To: stable@vger.kernel.org +Cc: Pei Xiao , Kunihiko Hayashi , Mark Brown , Sasha Levin +Message-ID: <20260514114635.181243-2-sashal@kernel.org> + +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(-) + +--- a/drivers/spi/spi-uniphier.c ++++ b/drivers/spi/spi-uniphier.c +@@ -666,28 +666,24 @@ static int uniphier_spi_probe(struct pla + } + 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 pla + 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 @@ out_release_dma: + 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 @@ out_host_put: + 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[] = { diff --git a/queue-6.6/spi-uniphier-switch-to-use-modern-name.patch b/queue-6.6/spi-uniphier-switch-to-use-modern-name.patch new file mode 100644 index 0000000000..00c81273f6 --- /dev/null +++ b/queue-6.6/spi-uniphier-switch-to-use-modern-name.patch @@ -0,0 +1,513 @@ +From stable+bounces-247175-greg=kroah.com@vger.kernel.org Thu May 14 13:46:42 2026 +From: Sasha Levin +Date: Thu, 14 May 2026 07:46:33 -0400 +Subject: spi: uniphier: switch to use modern name +To: stable@vger.kernel.org +Cc: Yang Yingliang , Mark Brown , Sasha Levin +Message-ID: <20260514114635.181243-1-sashal@kernel.org> + +From: Yang Yingliang + +[ Upstream commit 4c2ee0991013ca8a32bb093a017d460204790112 ] + +Change legacy name master to modern name host or controller. + +No functional changed. + +Signed-off-by: Yang Yingliang +Link: https://msgid.link/r/20231128093031.3707034-19-yangyingliang@huawei.com +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 | 198 ++++++++++++++++++++++----------------------- + 1 file changed, 99 insertions(+), 99 deletions(-) + +--- a/drivers/spi/spi-uniphier.c ++++ b/drivers/spi/spi-uniphier.c +@@ -26,7 +26,7 @@ struct uniphier_spi_priv { + void __iomem *base; + dma_addr_t base_dma_addr; + struct clk *clk; +- struct spi_master *master; ++ struct spi_controller *host; + struct completion xfer_done; + + int error; +@@ -127,7 +127,7 @@ static inline void uniphier_spi_irq_disa + + static void uniphier_spi_set_mode(struct spi_device *spi) + { +- struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master); ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(spi->controller); + u32 val1, val2; + + /* +@@ -180,7 +180,7 @@ static void uniphier_spi_set_mode(struct + + static void uniphier_spi_set_transfer_size(struct spi_device *spi, int size) + { +- struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master); ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(spi->controller); + u32 val; + + val = readl(priv->base + SSI_TXWDS); +@@ -198,7 +198,7 @@ static void uniphier_spi_set_transfer_si + static void uniphier_spi_set_baudrate(struct spi_device *spi, + unsigned int speed) + { +- struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master); ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(spi->controller); + u32 val, ckdiv; + + /* +@@ -217,7 +217,7 @@ static void uniphier_spi_set_baudrate(st + static void uniphier_spi_setup_transfer(struct spi_device *spi, + struct spi_transfer *t) + { +- struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master); ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(spi->controller); + u32 val; + + priv->error = 0; +@@ -333,7 +333,7 @@ static void uniphier_spi_fill_tx_fifo(st + + static void uniphier_spi_set_cs(struct spi_device *spi, bool enable) + { +- struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master); ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(spi->controller); + u32 val; + + val = readl(priv->base + SSI_FPS); +@@ -346,16 +346,16 @@ static void uniphier_spi_set_cs(struct s + writel(val, priv->base + SSI_FPS); + } + +-static bool uniphier_spi_can_dma(struct spi_master *master, ++static bool uniphier_spi_can_dma(struct spi_controller *host, + struct spi_device *spi, + struct spi_transfer *t) + { +- struct uniphier_spi_priv *priv = spi_master_get_devdata(master); ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host); + unsigned int bpw = bytes_per_word(priv->bits_per_word); + +- if ((!master->dma_tx && !master->dma_rx) +- || (!master->dma_tx && t->tx_buf) +- || (!master->dma_rx && t->rx_buf)) ++ if ((!host->dma_tx && !host->dma_rx) ++ || (!host->dma_tx && t->tx_buf) ++ || (!host->dma_rx && t->rx_buf)) + return false; + + return DIV_ROUND_UP(t->len, bpw) > SSI_FIFO_DEPTH; +@@ -363,33 +363,33 @@ static bool uniphier_spi_can_dma(struct + + static void uniphier_spi_dma_rxcb(void *data) + { +- struct spi_master *master = data; +- struct uniphier_spi_priv *priv = spi_master_get_devdata(master); ++ struct spi_controller *host = data; ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host); + int state = atomic_fetch_andnot(SSI_DMA_RX_BUSY, &priv->dma_busy); + + uniphier_spi_irq_disable(priv, SSI_IE_RXRE); + + if (!(state & SSI_DMA_TX_BUSY)) +- spi_finalize_current_transfer(master); ++ spi_finalize_current_transfer(host); + } + + static void uniphier_spi_dma_txcb(void *data) + { +- struct spi_master *master = data; +- struct uniphier_spi_priv *priv = spi_master_get_devdata(master); ++ struct spi_controller *host = data; ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host); + int state = atomic_fetch_andnot(SSI_DMA_TX_BUSY, &priv->dma_busy); + + uniphier_spi_irq_disable(priv, SSI_IE_TXRE); + + if (!(state & SSI_DMA_RX_BUSY)) +- spi_finalize_current_transfer(master); ++ spi_finalize_current_transfer(host); + } + +-static int uniphier_spi_transfer_one_dma(struct spi_master *master, ++static int uniphier_spi_transfer_one_dma(struct spi_controller *host, + struct spi_device *spi, + struct spi_transfer *t) + { +- struct uniphier_spi_priv *priv = spi_master_get_devdata(master); ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host); + struct dma_async_tx_descriptor *rxdesc = NULL, *txdesc = NULL; + int buswidth; + +@@ -412,23 +412,23 @@ static int uniphier_spi_transfer_one_dma + .src_maxburst = SSI_FIFO_BURST_NUM, + }; + +- dmaengine_slave_config(master->dma_rx, &rxconf); ++ dmaengine_slave_config(host->dma_rx, &rxconf); + + rxdesc = dmaengine_prep_slave_sg( +- master->dma_rx, ++ host->dma_rx, + t->rx_sg.sgl, t->rx_sg.nents, + DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!rxdesc) + goto out_err_prep; + + rxdesc->callback = uniphier_spi_dma_rxcb; +- rxdesc->callback_param = master; ++ rxdesc->callback_param = host; + + uniphier_spi_irq_enable(priv, SSI_IE_RXRE); + atomic_or(SSI_DMA_RX_BUSY, &priv->dma_busy); + + dmaengine_submit(rxdesc); +- dma_async_issue_pending(master->dma_rx); ++ dma_async_issue_pending(host->dma_rx); + } + + if (priv->tx_buf) { +@@ -439,23 +439,23 @@ static int uniphier_spi_transfer_one_dma + .dst_maxburst = SSI_FIFO_BURST_NUM, + }; + +- dmaengine_slave_config(master->dma_tx, &txconf); ++ dmaengine_slave_config(host->dma_tx, &txconf); + + txdesc = dmaengine_prep_slave_sg( +- master->dma_tx, ++ host->dma_tx, + t->tx_sg.sgl, t->tx_sg.nents, + DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!txdesc) + goto out_err_prep; + + txdesc->callback = uniphier_spi_dma_txcb; +- txdesc->callback_param = master; ++ txdesc->callback_param = host; + + uniphier_spi_irq_enable(priv, SSI_IE_TXRE); + atomic_or(SSI_DMA_TX_BUSY, &priv->dma_busy); + + dmaengine_submit(txdesc); +- dma_async_issue_pending(master->dma_tx); ++ dma_async_issue_pending(host->dma_tx); + } + + /* signal that we need to wait for completion */ +@@ -463,17 +463,17 @@ static int uniphier_spi_transfer_one_dma + + out_err_prep: + if (rxdesc) +- dmaengine_terminate_sync(master->dma_rx); ++ dmaengine_terminate_sync(host->dma_rx); + + return -EINVAL; + } + +-static int uniphier_spi_transfer_one_irq(struct spi_master *master, ++static int uniphier_spi_transfer_one_irq(struct spi_controller *host, + struct spi_device *spi, + struct spi_transfer *t) + { +- struct uniphier_spi_priv *priv = spi_master_get_devdata(master); +- struct device *dev = master->dev.parent; ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host); ++ struct device *dev = host->dev.parent; + unsigned long time_left; + + reinit_completion(&priv->xfer_done); +@@ -495,11 +495,11 @@ static int uniphier_spi_transfer_one_irq + return priv->error; + } + +-static int uniphier_spi_transfer_one_poll(struct spi_master *master, ++static int uniphier_spi_transfer_one_poll(struct spi_controller *host, + struct spi_device *spi, + struct spi_transfer *t) + { +- struct uniphier_spi_priv *priv = spi_master_get_devdata(master); ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host); + int loop = SSI_POLL_TIMEOUT_US * 10; + + while (priv->tx_bytes) { +@@ -520,14 +520,14 @@ static int uniphier_spi_transfer_one_pol + return 0; + + irq_transfer: +- return uniphier_spi_transfer_one_irq(master, spi, t); ++ return uniphier_spi_transfer_one_irq(host, spi, t); + } + +-static int uniphier_spi_transfer_one(struct spi_master *master, ++static int uniphier_spi_transfer_one(struct spi_controller *host, + struct spi_device *spi, + struct spi_transfer *t) + { +- struct uniphier_spi_priv *priv = spi_master_get_devdata(master); ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host); + unsigned long threshold; + bool use_dma; + +@@ -537,9 +537,9 @@ static int uniphier_spi_transfer_one(str + + uniphier_spi_setup_transfer(spi, t); + +- use_dma = master->can_dma ? master->can_dma(master, spi, t) : false; ++ use_dma = host->can_dma ? host->can_dma(host, spi, t) : false; + if (use_dma) +- return uniphier_spi_transfer_one_dma(master, spi, t); ++ return uniphier_spi_transfer_one_dma(host, spi, t); + + /* + * If the transfer operation will take longer than +@@ -548,33 +548,33 @@ static int uniphier_spi_transfer_one(str + threshold = DIV_ROUND_UP(SSI_POLL_TIMEOUT_US * priv->speed_hz, + USEC_PER_SEC * BITS_PER_BYTE); + if (t->len > threshold) +- return uniphier_spi_transfer_one_irq(master, spi, t); ++ return uniphier_spi_transfer_one_irq(host, spi, t); + else +- return uniphier_spi_transfer_one_poll(master, spi, t); ++ return uniphier_spi_transfer_one_poll(host, spi, t); + } + +-static int uniphier_spi_prepare_transfer_hardware(struct spi_master *master) ++static int uniphier_spi_prepare_transfer_hardware(struct spi_controller *host) + { +- struct uniphier_spi_priv *priv = spi_master_get_devdata(master); ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host); + + writel(SSI_CTL_EN, priv->base + SSI_CTL); + + return 0; + } + +-static int uniphier_spi_unprepare_transfer_hardware(struct spi_master *master) ++static int uniphier_spi_unprepare_transfer_hardware(struct spi_controller *host) + { +- struct uniphier_spi_priv *priv = spi_master_get_devdata(master); ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host); + + writel(0, priv->base + SSI_CTL); + + return 0; + } + +-static void uniphier_spi_handle_err(struct spi_master *master, ++static void uniphier_spi_handle_err(struct spi_controller *host, + struct spi_message *msg) + { +- struct uniphier_spi_priv *priv = spi_master_get_devdata(master); ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host); + u32 val; + + /* stop running spi transfer */ +@@ -587,12 +587,12 @@ static void uniphier_spi_handle_err(stru + uniphier_spi_irq_disable(priv, SSI_IE_ALL_MASK); + + if (atomic_read(&priv->dma_busy) & SSI_DMA_TX_BUSY) { +- dmaengine_terminate_async(master->dma_tx); ++ dmaengine_terminate_async(host->dma_tx); + atomic_andnot(SSI_DMA_TX_BUSY, &priv->dma_busy); + } + + if (atomic_read(&priv->dma_busy) & SSI_DMA_RX_BUSY) { +- dmaengine_terminate_async(master->dma_rx); ++ dmaengine_terminate_async(host->dma_rx); + atomic_andnot(SSI_DMA_RX_BUSY, &priv->dma_busy); + } + } +@@ -641,7 +641,7 @@ done: + static int uniphier_spi_probe(struct platform_device *pdev) + { + struct uniphier_spi_priv *priv; +- struct spi_master *master; ++ struct spi_controller *host; + struct resource *res; + struct dma_slave_caps caps; + u32 dma_tx_burst = 0, dma_rx_burst = 0; +@@ -649,20 +649,20 @@ static int uniphier_spi_probe(struct pla + int irq; + int ret; + +- master = spi_alloc_master(&pdev->dev, sizeof(*priv)); +- if (!master) ++ host = spi_alloc_host(&pdev->dev, sizeof(*priv)); ++ if (!host) + return -ENOMEM; + +- platform_set_drvdata(pdev, master); ++ platform_set_drvdata(pdev, host); + +- priv = spi_master_get_devdata(master); +- priv->master = master; ++ priv = spi_controller_get_devdata(host); ++ priv->host = host; + priv->is_save_param = false; + + priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(priv->base)) { + ret = PTR_ERR(priv->base); +- goto out_master_put; ++ goto out_host_put; + } + priv->base_dma_addr = res->start; + +@@ -670,12 +670,12 @@ static int uniphier_spi_probe(struct pla + if (IS_ERR(priv->clk)) { + dev_err(&pdev->dev, "failed to get clock\n"); + ret = PTR_ERR(priv->clk); +- goto out_master_put; ++ goto out_host_put; + } + + ret = clk_prepare_enable(priv->clk); + if (ret) +- goto out_master_put; ++ goto out_host_put; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { +@@ -694,35 +694,35 @@ static int uniphier_spi_probe(struct pla + + clk_rate = clk_get_rate(priv->clk); + +- master->max_speed_hz = DIV_ROUND_UP(clk_rate, SSI_MIN_CLK_DIVIDER); +- master->min_speed_hz = DIV_ROUND_UP(clk_rate, SSI_MAX_CLK_DIVIDER); +- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; +- master->dev.of_node = pdev->dev.of_node; +- master->bus_num = pdev->id; +- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); +- +- master->set_cs = uniphier_spi_set_cs; +- master->transfer_one = uniphier_spi_transfer_one; +- master->prepare_transfer_hardware ++ host->max_speed_hz = DIV_ROUND_UP(clk_rate, SSI_MIN_CLK_DIVIDER); ++ host->min_speed_hz = DIV_ROUND_UP(clk_rate, SSI_MAX_CLK_DIVIDER); ++ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; ++ host->dev.of_node = pdev->dev.of_node; ++ host->bus_num = pdev->id; ++ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); ++ ++ host->set_cs = uniphier_spi_set_cs; ++ host->transfer_one = uniphier_spi_transfer_one; ++ host->prepare_transfer_hardware + = uniphier_spi_prepare_transfer_hardware; +- master->unprepare_transfer_hardware ++ host->unprepare_transfer_hardware + = uniphier_spi_unprepare_transfer_hardware; +- master->handle_err = uniphier_spi_handle_err; +- master->can_dma = uniphier_spi_can_dma; ++ host->handle_err = uniphier_spi_handle_err; ++ host->can_dma = uniphier_spi_can_dma; + +- master->num_chipselect = 1; +- master->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX; ++ host->num_chipselect = 1; ++ host->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX; + +- master->dma_tx = dma_request_chan(&pdev->dev, "tx"); +- if (IS_ERR_OR_NULL(master->dma_tx)) { +- if (PTR_ERR(master->dma_tx) == -EPROBE_DEFER) { ++ host->dma_tx = dma_request_chan(&pdev->dev, "tx"); ++ if (IS_ERR_OR_NULL(host->dma_tx)) { ++ if (PTR_ERR(host->dma_tx) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto out_disable_clk; + } +- master->dma_tx = NULL; ++ host->dma_tx = NULL; + dma_tx_burst = INT_MAX; + } else { +- ret = dma_get_slave_caps(master->dma_tx, &caps); ++ ret = dma_get_slave_caps(host->dma_tx, &caps); + if (ret) { + dev_err(&pdev->dev, "failed to get TX DMA capacities: %d\n", + ret); +@@ -731,16 +731,16 @@ static int uniphier_spi_probe(struct pla + dma_tx_burst = caps.max_burst; + } + +- master->dma_rx = dma_request_chan(&pdev->dev, "rx"); +- if (IS_ERR_OR_NULL(master->dma_rx)) { +- if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER) { ++ host->dma_rx = dma_request_chan(&pdev->dev, "rx"); ++ if (IS_ERR_OR_NULL(host->dma_rx)) { ++ if (PTR_ERR(host->dma_rx) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto out_release_dma; + } +- master->dma_rx = NULL; ++ host->dma_rx = NULL; + dma_rx_burst = INT_MAX; + } else { +- ret = dma_get_slave_caps(master->dma_rx, &caps); ++ ret = dma_get_slave_caps(host->dma_rx, &caps); + if (ret) { + dev_err(&pdev->dev, "failed to get RX DMA capacities: %d\n", + ret); +@@ -749,41 +749,41 @@ static int uniphier_spi_probe(struct pla + dma_rx_burst = caps.max_burst; + } + +- master->max_dma_len = min(dma_tx_burst, dma_rx_burst); ++ host->max_dma_len = min(dma_tx_burst, dma_rx_burst); + +- ret = devm_spi_register_master(&pdev->dev, master); ++ ret = devm_spi_register_controller(&pdev->dev, host); + if (ret) + goto out_release_dma; + + return 0; + + out_release_dma: +- if (!IS_ERR_OR_NULL(master->dma_rx)) { +- dma_release_channel(master->dma_rx); +- master->dma_rx = NULL; +- } +- if (!IS_ERR_OR_NULL(master->dma_tx)) { +- dma_release_channel(master->dma_tx); +- master->dma_tx = NULL; ++ if (!IS_ERR_OR_NULL(host->dma_rx)) { ++ dma_release_channel(host->dma_rx); ++ host->dma_rx = NULL; ++ } ++ if (!IS_ERR_OR_NULL(host->dma_tx)) { ++ dma_release_channel(host->dma_tx); ++ host->dma_tx = NULL; + } + + out_disable_clk: + clk_disable_unprepare(priv->clk); + +-out_master_put: +- spi_master_put(master); ++out_host_put: ++ spi_controller_put(host); + return ret; + } + + static void uniphier_spi_remove(struct platform_device *pdev) + { +- struct spi_master *master = platform_get_drvdata(pdev); +- struct uniphier_spi_priv *priv = spi_master_get_devdata(master); ++ struct spi_controller *host = platform_get_drvdata(pdev); ++ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host); + +- if (master->dma_tx) +- dma_release_channel(master->dma_tx); +- if (master->dma_rx) +- dma_release_channel(master->dma_rx); ++ 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); + } diff --git a/queue-6.6/spi-zynq-qspi-fix-controller-deregistration.patch b/queue-6.6/spi-zynq-qspi-fix-controller-deregistration.patch new file mode 100644 index 0000000000..dde9db4ca5 --- /dev/null +++ b/queue-6.6/spi-zynq-qspi-fix-controller-deregistration.patch @@ -0,0 +1,73 @@ +From stable+bounces-247015-greg=kroah.com@vger.kernel.org Wed May 13 20:40:59 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 14:33:48 -0400 +Subject: spi: zynq-qspi: fix controller deregistration +To: stable@vger.kernel.org +Cc: Johan Hovold , Naga Sureshkumar Relli , Mark Brown , Sasha Levin +Message-ID: <20260513183348.3927281-3-sashal@kernel.org> + +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(-) + +--- a/drivers/spi/spi-zynq-qspi.c ++++ b/drivers/spi/spi-zynq-qspi.c +@@ -641,7 +641,7 @@ static int zynq_qspi_probe(struct platfo + + 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); +@@ -699,9 +699,9 @@ static int zynq_qspi_probe(struct platfo + /* 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; + } + +@@ -725,9 +725,16 @@ remove_ctlr: + */ + 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[] = { diff --git a/queue-6.6/spi-zynq-qspi-simplify-clock-handling-with-devm_clk_get_enabled.patch b/queue-6.6/spi-zynq-qspi-simplify-clock-handling-with-devm_clk_get_enabled.patch new file mode 100644 index 0000000000..d3dc1eda8e --- /dev/null +++ b/queue-6.6/spi-zynq-qspi-simplify-clock-handling-with-devm_clk_get_enabled.patch @@ -0,0 +1,142 @@ +From stable+bounces-247014-greg=kroah.com@vger.kernel.org Wed May 13 20:41:03 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 14:33:47 -0400 +Subject: spi: zynq-qspi: Simplify clock handling with devm_clk_get_enabled() +To: stable@vger.kernel.org +Cc: Pei Xiao , Michal Simek , Mark Brown , Sasha Levin +Message-ID: <20260513183348.3927281-2-sashal@kernel.org> + +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(-) + +--- a/drivers/spi/spi-zynq-qspi.c ++++ b/drivers/spi/spi-zynq-qspi.c +@@ -379,21 +379,10 @@ static int zynq_qspi_setup_op(struct 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); + +@@ -659,7 +648,7 @@ static int zynq_qspi_probe(struct platfo + 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); +@@ -668,36 +657,24 @@ static int zynq_qspi_probe(struct platfo + + 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", +@@ -707,7 +684,7 @@ static int zynq_qspi_probe(struct platfo + } 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; + } +@@ -725,15 +702,11 @@ static int zynq_qspi_probe(struct platfo + 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); + +@@ -755,9 +728,6 @@ static void zynq_qspi_remove(struct plat + 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[] = { diff --git a/queue-6.6/spi-zynq-qspi-switch-to-use-modern-name.patch b/queue-6.6/spi-zynq-qspi-switch-to-use-modern-name.patch new file mode 100644 index 0000000000..e55d0fbcf1 --- /dev/null +++ b/queue-6.6/spi-zynq-qspi-switch-to-use-modern-name.patch @@ -0,0 +1,145 @@ +From stable+bounces-247013-greg=kroah.com@vger.kernel.org Wed May 13 20:39:57 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 14:33:46 -0400 +Subject: spi: zynq-qspi: switch to use modern name +To: stable@vger.kernel.org +Cc: Yang Yingliang , Mark Brown , Sasha Levin +Message-ID: <20260513183348.3927281-1-sashal@kernel.org> + +From: Yang Yingliang + +[ Upstream commit 178ebb0c505b0a35edb4fb2a0e23a1f29e1db14d ] + +Change legacy name master/slave to modern name host/target or controller. + +No functional changed. + +Signed-off-by: Yang Yingliang +Link: https://msgid.link/r/20231128093031.3707034-24-yangyingliang@huawei.com +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 | 28 ++++++++++++++-------------- + 1 file changed, 14 insertions(+), 14 deletions(-) + +--- a/drivers/spi/spi-zynq-qspi.c ++++ b/drivers/spi/spi-zynq-qspi.c +@@ -54,10 +54,10 @@ + #define ZYNQ_QSPI_CONFIG_MSTREN_MASK BIT(0) /* Master Mode */ + + /* +- * QSPI Configuration Register - Baud rate and slave select ++ * QSPI Configuration Register - Baud rate and target select + * + * These are the values used in the calculation of baud rate divisor and +- * setting the slave select. ++ * setting the target select. + */ + #define ZYNQ_QSPI_CONFIG_BAUD_DIV_MAX GENMASK(2, 0) /* Baud rate maximum */ + #define ZYNQ_QSPI_CONFIG_BAUD_DIV_SHIFT 3 /* Baud rate divisor shift */ +@@ -164,14 +164,14 @@ static inline void zynq_qspi_write(struc + * + * The default settings of the QSPI controller's configurable parameters on + * reset are +- * - Master mode ++ * - Host mode + * - Baud rate divisor is set to 2 + * - Tx threshold set to 1l Rx threshold set to 32 + * - Flash memory interface mode enabled + * - Size of the word to be transferred as 8 bit + * This function performs the following actions + * - Disable and clear all the interrupts +- * - Enable manual slave select ++ * - Enable manual target select + * - Enable manual start + * - Deselect all the chip select lines + * - Set the size of the word to be transferred as 32 bit +@@ -289,7 +289,7 @@ static void zynq_qspi_txfifo_op(struct z + */ + static void zynq_qspi_chipselect(struct spi_device *spi, bool assert) + { +- struct spi_controller *ctlr = spi->master; ++ struct spi_controller *ctlr = spi->controller; + struct zynq_qspi *xqspi = spi_controller_get_devdata(ctlr); + u32 config_reg; + +@@ -377,7 +377,7 @@ static int zynq_qspi_config_op(struct zy + */ + static int zynq_qspi_setup_op(struct spi_device *spi) + { +- struct spi_controller *ctlr = spi->master; ++ struct spi_controller *ctlr = spi->controller; + struct zynq_qspi *qspi = spi_controller_get_devdata(ctlr); + int ret; + +@@ -534,7 +534,7 @@ static irqreturn_t zynq_qspi_irq(int irq + static int zynq_qspi_exec_mem_op(struct spi_mem *mem, + const struct spi_mem_op *op) + { +- struct zynq_qspi *xqspi = spi_controller_get_devdata(mem->spi->master); ++ struct zynq_qspi *xqspi = spi_controller_get_devdata(mem->spi->controller); + int err = 0, i; + u8 *tmpbuf; + +@@ -646,7 +646,7 @@ static int zynq_qspi_probe(struct platfo + struct zynq_qspi *xqspi; + u32 num_cs; + +- ctlr = spi_alloc_master(&pdev->dev, sizeof(*xqspi)); ++ ctlr = spi_alloc_host(&pdev->dev, sizeof(*xqspi)); + if (!ctlr) + return -ENOMEM; + +@@ -656,14 +656,14 @@ static int zynq_qspi_probe(struct platfo + xqspi->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(xqspi->regs)) { + ret = PTR_ERR(xqspi->regs); +- goto remove_master; ++ goto remove_ctlr; + } + + xqspi->pclk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(xqspi->pclk)) { + dev_err(&pdev->dev, "pclk clock not found.\n"); + ret = PTR_ERR(xqspi->pclk); +- goto remove_master; ++ goto remove_ctlr; + } + + init_completion(&xqspi->data_completion); +@@ -672,13 +672,13 @@ static int zynq_qspi_probe(struct platfo + if (IS_ERR(xqspi->refclk)) { + dev_err(&pdev->dev, "ref_clk clock not found.\n"); + ret = PTR_ERR(xqspi->refclk); +- goto remove_master; ++ goto remove_ctlr; + } + + ret = clk_prepare_enable(xqspi->pclk); + if (ret) { + dev_err(&pdev->dev, "Unable to enable APB clock.\n"); +- goto remove_master; ++ goto remove_ctlr; + } + + ret = clk_prepare_enable(xqspi->refclk); +@@ -724,7 +724,7 @@ static int zynq_qspi_probe(struct platfo + + ret = devm_spi_register_controller(&pdev->dev, ctlr); + if (ret) { +- dev_err(&pdev->dev, "spi_register_master failed\n"); ++ dev_err(&pdev->dev, "devm_spi_register_controller failed\n"); + goto clk_dis_all; + } + +@@ -734,7 +734,7 @@ clk_dis_all: + clk_disable_unprepare(xqspi->refclk); + clk_dis_pclk: + clk_disable_unprepare(xqspi->pclk); +-remove_master: ++remove_ctlr: + spi_controller_put(ctlr); + + return ret; diff --git a/queue-6.6/tracepoint-balance-regfunc-on-func_add-failure-in-tracepoint_add_func.patch b/queue-6.6/tracepoint-balance-regfunc-on-func_add-failure-in-tracepoint_add_func.patch new file mode 100644 index 0000000000..f6da3dd058 --- /dev/null +++ b/queue-6.6/tracepoint-balance-regfunc-on-func_add-failure-in-tracepoint_add_func.patch @@ -0,0 +1,56 @@ +From stable+bounces-245065-greg=kroah.com@vger.kernel.org Sun May 10 22:00:00 2026 +From: Sasha Levin +Date: Sun, 10 May 2026 15:59:53 -0400 +Subject: tracepoint: balance regfunc() on func_add() failure in tracepoint_add_func() +To: stable@vger.kernel.org +Cc: David Carlier , Masami Hiramatsu , Mathieu Desnoyers , "Steven Rostedt (Google)" , Sasha Levin +Message-ID: <20260510195953.593373-1-sashal@kernel.org> + +From: David Carlier + +[ Upstream commit fad217e16fded7f3c09f8637b0f6a224d58b5f2e ] + +When a tracepoint goes through the 0 -> 1 transition, tracepoint_add_func() +invokes the subsystem's ext->regfunc() before attempting to install the +new probe via func_add(). If func_add() then fails (for example, when +allocate_probes() cannot allocate a new probe array under memory pressure +and returns -ENOMEM), the function returns the error without calling the +matching ext->unregfunc(), leaving the side effects of regfunc() behind +with no installed probe to justify them. + +For syscall tracepoints this is particularly unpleasant: syscall_regfunc() +bumps sys_tracepoint_refcount and sets SYSCALL_TRACEPOINT on every task. +After a leaked failure, the refcount is stuck at a non-zero value with no +consumer, and every task continues paying the syscall trace entry/exit +overhead until reboot. Other subsystems providing regfunc()/unregfunc() +pairs exhibit similarly scoped persistent state. + +Mirror the existing 1 -> 0 cleanup and call ext->unregfunc() in the +func_add() error path, gated on the same condition used there so the +unwind is symmetric with the registration. + +Fixes: 8cf868affdc4 ("tracing: Have the reg function allow to fail") +Cc: stable@vger.kernel.org +Cc: Masami Hiramatsu +Cc: Mathieu Desnoyers +Link: https://patch.msgid.link/20260413190601.21993-1-devnexen@gmail.com +Signed-off-by: David Carlier +Signed-off-by: Steven Rostedt (Google) +[ changed `tp->ext->unregfunc` to `tp->unregfunc` to match older struct layout ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + kernel/tracepoint.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/kernel/tracepoint.c ++++ b/kernel/tracepoint.c +@@ -337,6 +337,8 @@ static int tracepoint_add_func(struct tr + lockdep_is_held(&tracepoints_mutex)); + old = func_add(&tp_funcs, func, prio); + if (IS_ERR(old)) { ++ if (tp->unregfunc && !static_key_enabled(&tp->key)) ++ tp->unregfunc(); + WARN_ON_ONCE(warn && PTR_ERR(old) != -ENOMEM); + return PTR_ERR(old); + } diff --git a/queue-6.6/xfrm-ah-account-for-esn-high-bits-in-async-callbacks.patch b/queue-6.6/xfrm-ah-account-for-esn-high-bits-in-async-callbacks.patch new file mode 100644 index 0000000000..b35ca80c7a --- /dev/null +++ b/queue-6.6/xfrm-ah-account-for-esn-high-bits-in-async-callbacks.patch @@ -0,0 +1,132 @@ +From stable+bounces-246945-greg=kroah.com@vger.kernel.org Wed May 13 19:18:18 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 12:46:35 -0400 +Subject: xfrm: ah: account for ESN high bits in async callbacks +To: stable@vger.kernel.org +Cc: Michael Bommarito , Steffen Klassert , Sasha Levin +Message-ID: <20260513164635.3816490-3-sashal@kernel.org> + +From: Michael Bommarito + +[ Upstream commit ec54093e6a8f87e800bb6aa15eb7fc1e33faa524 ] + +AH allocates its temporary auth/ICV layout differently when ESN is enabled: +the async ahash setup appends a 4-byte seqhi slot before the ICV or +auth_data area, but the async completion callbacks still reconstruct the +temporary layout as if seqhi were absent. + +With an async AH implementation selected, that makes AH copy or compare +the wrong bytes on both the IPv4 and IPv6 paths. In UML repro on IPv4 AH +with ESN and forced async hmac(sha1), ping fails with 100% packet loss, +and the callback logs show the pre-fix drift: + + ah4 output_done: esn=1 err=0 icv_off=20 expected_off=24 + ah4 input_done: esn=1 auth_off=20 expected_auth_off=24 icv_off=32 expected_icv_off=36 + +Reconstruct the callback-side layout the same way the setup path built it +by skipping the ESN seqhi slot before locating the saved auth_data or ICV. +Per RFC 4302, the ESN high-order 32 bits participate in the AH ICV +computation, so the async callbacks must account for the seqhi slot. + +Post-fix, the same IPv4 AH+ESN+forced-async-hmac(sha1) UML repro shows +the corrected offset (ah4 output_done: esn=1 err=0 icv_off=24 +expected_off=24) and ping succeeds; net/ipv4/ah4.o and net/ipv6/ah6.o +build clean at W=1. IPv6 AH+ESN was not exercised at runtime, and the +change has not been tested against a real async hardware AH engine. + +Fixes: d4d573d0334d ("{IPv4,xfrm} Add ESN support for AH egress part") +Fixes: d8b2a8600b0e ("{IPv4,xfrm} Add ESN support for AH ingress part") +Fixes: 26dd70c3fad3 ("{IPv6,xfrm} Add ESN support for AH egress part") +Fixes: 8d6da6f32557 ("{IPv6,xfrm} Add ESN support for AH ingress part") +Cc: stable@vger.kernel.org +Assisted-by: Codex:gpt-5-4 +Assisted-by: Claude:claude-opus-4-7 +Signed-off-by: Michael Bommarito +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/ah4.c | 14 ++++++++++++-- + net/ipv6/ah6.c | 14 ++++++++++++-- + 2 files changed, 24 insertions(+), 4 deletions(-) + +--- a/net/ipv4/ah4.c ++++ b/net/ipv4/ah4.c +@@ -124,9 +124,14 @@ static void ah_output_done(void *data, i + struct iphdr *top_iph = ip_hdr(skb); + struct ip_auth_hdr *ah = ip_auth_hdr(skb); + int ihl = ip_hdrlen(skb); ++ int seqhi_len = 0; ++ __be32 *seqhi; + ++ if (x->props.flags & XFRM_STATE_ESN) ++ seqhi_len = sizeof(*seqhi); + iph = AH_SKB_CB(skb)->tmp; +- icv = ah_tmp_icv(iph, ihl); ++ seqhi = (__be32 *)((char *)iph + ihl); ++ icv = ah_tmp_icv(seqhi, seqhi_len); + memcpy(ah->auth_data, icv, ahp->icv_trunc_len); + + top_iph->tos = iph->tos; +@@ -270,12 +275,17 @@ static void ah_input_done(void *data, in + struct ip_auth_hdr *ah = ip_auth_hdr(skb); + int ihl = ip_hdrlen(skb); + int ah_hlen = (ah->hdrlen + 2) << 2; ++ int seqhi_len = 0; ++ __be32 *seqhi; + + if (err) + goto out; + ++ if (x->props.flags & XFRM_STATE_ESN) ++ seqhi_len = sizeof(*seqhi); + work_iph = AH_SKB_CB(skb)->tmp; +- auth_data = ah_tmp_auth(work_iph, ihl); ++ seqhi = (__be32 *)((char *)work_iph + ihl); ++ auth_data = ah_tmp_auth(seqhi, seqhi_len); + icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len); + + err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0; +--- a/net/ipv6/ah6.c ++++ b/net/ipv6/ah6.c +@@ -317,14 +317,19 @@ static void ah6_output_done(void *data, + struct ipv6hdr *top_iph = ipv6_hdr(skb); + struct ip_auth_hdr *ah = ip_auth_hdr(skb); + struct tmp_ext *iph_ext; ++ int seqhi_len = 0; ++ __be32 *seqhi; + + extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr); + if (extlen) + extlen += sizeof(*iph_ext); + ++ if (x->props.flags & XFRM_STATE_ESN) ++ seqhi_len = sizeof(*seqhi); + iph_base = AH_SKB_CB(skb)->tmp; + iph_ext = ah_tmp_ext(iph_base); +- icv = ah_tmp_icv(iph_ext, extlen); ++ seqhi = (__be32 *)((char *)iph_ext + extlen); ++ icv = ah_tmp_icv(seqhi, seqhi_len); + + memcpy(ah->auth_data, icv, ahp->icv_trunc_len); + memcpy(top_iph, iph_base, IPV6HDR_BASELEN); +@@ -471,13 +476,18 @@ static void ah6_input_done(void *data, i + struct ip_auth_hdr *ah = ip_auth_hdr(skb); + int hdr_len = skb_network_header_len(skb); + int ah_hlen = ipv6_authlen(ah); ++ int seqhi_len = 0; ++ __be32 *seqhi; + + if (err) + goto out; + ++ if (x->props.flags & XFRM_STATE_ESN) ++ seqhi_len = sizeof(*seqhi); + work_iph = AH_SKB_CB(skb)->tmp; + auth_data = ah_tmp_auth(work_iph, hdr_len); +- icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len); ++ seqhi = (__be32 *)(auth_data + ahp->icv_trunc_len); ++ icv = ah_tmp_icv(seqhi, seqhi_len); + + err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0; + if (err) diff --git a/queue-6.6/xfrm-defensively-unhash-xfrm_state-lists-in-__xfrm_state_delete.patch b/queue-6.6/xfrm-defensively-unhash-xfrm_state-lists-in-__xfrm_state_delete.patch new file mode 100644 index 0000000000..da80a2c6e8 --- /dev/null +++ b/queue-6.6/xfrm-defensively-unhash-xfrm_state-lists-in-__xfrm_state_delete.patch @@ -0,0 +1,119 @@ +From stable+bounces-246964-greg=kroah.com@vger.kernel.org Wed May 13 19:16:52 2026 +From: Sasha Levin +Date: Wed, 13 May 2026 13:16:28 -0400 +Subject: xfrm: defensively unhash xfrm_state lists in __xfrm_state_delete +To: stable@vger.kernel.org +Cc: Michal Kosiorek , Steffen Klassert , Sasha Levin +Message-ID: <20260513171628.3878131-1-sashal@kernel.org> + +From: Michal Kosiorek + +[ Upstream commit 14acf9652e5690de3c7486c6db5fb8dafd0a32a3 ] + +KASAN reproduces a slab-use-after-free in __xfrm_state_delete()'s +hlist_del_rcu calls under syzkaller load on linux-6.12.y stable +(reproduced on 6.12.47, also reachable via the same code path on +torvalds/master and on the ipsec tree). Nine unique signatures cluster +in the xfrm_state lifecycle, the load-bearing one being: + + BUG: KASAN: slab-use-after-free in __hlist_del include/linux/list.h:990 [inline] + BUG: KASAN: slab-use-after-free in hlist_del_rcu include/linux/rculist.h:516 [inline] + BUG: KASAN: slab-use-after-free in __xfrm_state_delete net/xfrm/xfrm_state.c + Write of size 8 at addr ffff8881198bcb70 by task kworker/u8:9/435 + + Workqueue: netns cleanup_net + Call Trace: + __hlist_del / hlist_del_rcu + __xfrm_state_delete + xfrm_state_delete + xfrm_state_flush + xfrm_state_fini + ops_exit_list + cleanup_net + +The other observed signatures hit the same slab object from +__xfrm_state_lookup, xfrm_alloc_spi, __xfrm_state_insert and an OOB +write variant of __xfrm_state_delete, all on the byseq/byspi +hash chains. + +__xfrm_state_delete() guards its byseq and byspi unhashes with +value-based predicates: + + if (x->km.seq) + hlist_del_rcu(&x->byseq); + if (x->id.spi) + hlist_del_rcu(&x->byspi); + +while everywhere else in the file (e.g. state_cache, state_cache_input) +the safer hlist_unhashed() check is used. xfrm_alloc_spi() sets +x->id.spi = newspi inside xfrm_state_lock and then immediately inserts +into byspi, but a path that observes x->id.spi != 0 outside of +xfrm_state_lock can still skip-or-hit the byspi unhash inconsistently +with whether x is actually on the list. The same holds for x->km.seq +versus byseq, and the bydst/bysrc unhashes have no predicate at all, +so a second __xfrm_state_delete() on the same object writes through +LIST_POISON pprev. + +The defensive change here: + + - Use hlist_del_init_rcu() instead of hlist_del_rcu() on bydst, + bysrc, byseq and byspi so a second deletion is a no-op rather + than a write through LIST_POISON pprev. The byseq/byspi nodes + are already initialised in xfrm_state_alloc(). + - Test hlist_unhashed() rather than the value predicate for + byseq/byspi, so the unhash decision tracks list state rather than + mutable scalar fields. + +Empirical verification: applied this patch on top of v6.12.47, rebuilt, +and re-ran the same syzkaller harness for 1h16m on a previously-crashy +configuration that produced ~100 hits each of slab-use-after-free +Read in xfrm_alloc_spi / Read in __xfrm_state_lookup / Write in +__xfrm_state_delete. After the patch, 7.1M execs across 32 VMs at +~1550 exec/sec produced zero xfrm_state UAF/OOB hits. /proc/slabinfo +confirms the xfrm_state slab is actively allocated and freed during +the run (~143 KiB resident), so the fuzzer is still exercising those +code paths -- they just no longer crash. + +Reproduction: + + - Linux 6.12.47 x86_64 + KASAN_GENERIC + KASAN_INLINE + KCOV + - syzkaller @ 746545b8b1e4c3a128db8652b340d3df90ce61db + - 32 QEMU/KVM VMs x 2 vCPU on AWS c5.metal bare metal + - 9 unique signatures collected in ~9h, all within xfrm_state + lifecycle + +Fixes: fe9f1d8779cb ("xfrm: add state hashtable keyed by seq") +Fixes: 7b4dc3600e48 ("[XFRM]: Do not add a state whose SPI is zero to the SPI hash.") +Reported-by: Michal Kosiorek +Tested-by: Michal Kosiorek +Cc: stable@vger.kernel.org +Signed-off-by: Michal Kosiorek +Signed-off-by: Steffen Klassert +[ dropped state_cache/state_cache_input unhash hunks and xfrm_nat_keepalive_state_updated() call ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/xfrm/xfrm_state.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/net/xfrm/xfrm_state.c ++++ b/net/xfrm/xfrm_state.c +@@ -752,12 +752,12 @@ int __xfrm_state_delete(struct xfrm_stat + x->km.state = XFRM_STATE_DEAD; + spin_lock(&net->xfrm.xfrm_state_lock); + list_del(&x->km.all); +- hlist_del_rcu(&x->bydst); +- hlist_del_rcu(&x->bysrc); +- if (x->km.seq) +- hlist_del_rcu(&x->byseq); +- if (x->id.spi) +- hlist_del_rcu(&x->byspi); ++ hlist_del_init_rcu(&x->bydst); ++ hlist_del_init_rcu(&x->bysrc); ++ if (!hlist_unhashed(&x->byseq)) ++ hlist_del_init_rcu(&x->byseq); ++ if (!hlist_unhashed(&x->byspi)) ++ hlist_del_init_rcu(&x->byspi); + net->xfrm.state_num--; + spin_unlock(&net->xfrm.xfrm_state_lock); +