--- /dev/null
+From a54a0939f5009c54e9af579b3fdc74170c199bdd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Oct 2023 09:25:30 +0000
+Subject: cifs: handle cases where a channel is closed
+
+From: Shyam Prasad N <sprasad@microsoft.com>
+
+[ Upstream commit 0c51cc6f2cb0108e7d49805f6e089cd85caab279 ]
+
+So far, SMB multichannel could only scale up, but not
+scale down the number of channels. In this series of
+patch, we now allow the client to deal with the case
+of multichannel disabled on the server when the share
+is mounted. With that change, we now need the ability
+to scale down the channels.
+
+This change allows the client to deal with cases of
+missing channels more gracefully.
+
+Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Stable-dep-of: 78e727e58e54 ("cifs: update iface_last_update on each query-and-update")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/cifs_debug.c | 5 +++++
+ fs/smb/client/cifsglob.h | 1 +
+ fs/smb/client/cifsproto.h | 2 +-
+ fs/smb/client/connect.c | 6 +++++-
+ fs/smb/client/sess.c | 28 ++++++++++++++++++++++++----
+ fs/smb/client/smb2transport.c | 8 +++++++-
+ 6 files changed, 43 insertions(+), 7 deletions(-)
+
+diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c
+index a2584ad8808a..3230ed7eadde 100644
+--- a/fs/smb/client/cifs_debug.c
++++ b/fs/smb/client/cifs_debug.c
+@@ -138,6 +138,11 @@ cifs_dump_channel(struct seq_file *m, int i, struct cifs_chan *chan)
+ {
+ struct TCP_Server_Info *server = chan->server;
+
++ if (!server) {
++ seq_printf(m, "\n\n\t\tChannel: %d DISABLED", i+1);
++ return;
++ }
++
+ seq_printf(m, "\n\n\t\tChannel: %d ConnectionId: 0x%llx"
+ "\n\t\tNumber of credits: %d,%d,%d Dialect 0x%x"
+ "\n\t\tTCP status: %d Instance: %d"
+diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
+index ec1e5e20a36b..e3ef8eee68d1 100644
+--- a/fs/smb/client/cifsglob.h
++++ b/fs/smb/client/cifsglob.h
+@@ -1060,6 +1060,7 @@ struct cifs_ses {
+ spinlock_t chan_lock;
+ /* ========= begin: protected by chan_lock ======== */
+ #define CIFS_MAX_CHANNELS 16
++#define CIFS_INVAL_CHAN_INDEX (-1)
+ #define CIFS_ALL_CHANNELS_SET(ses) \
+ ((1UL << (ses)->chan_count) - 1)
+ #define CIFS_ALL_CHANS_GOOD(ses) \
+diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
+index c858feaf4f92..0eb62ccd476f 100644
+--- a/fs/smb/client/cifsproto.h
++++ b/fs/smb/client/cifsproto.h
+@@ -622,7 +622,7 @@ bool is_server_using_iface(struct TCP_Server_Info *server,
+ bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface);
+ void cifs_ses_mark_for_reconnect(struct cifs_ses *ses);
+
+-unsigned int
++int
+ cifs_ses_get_chan_index(struct cifs_ses *ses,
+ struct TCP_Server_Info *server);
+ void
+diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
+index b82f60d6f47e..a482afa3fa42 100644
+--- a/fs/smb/client/connect.c
++++ b/fs/smb/client/connect.c
+@@ -169,8 +169,12 @@ cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server,
+ list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
+ spin_lock(&ses->chan_lock);
+ for (i = 0; i < ses->chan_count; i++) {
++ if (!ses->chans[i].server)
++ continue;
++
+ spin_lock(&ses->chans[i].server->srv_lock);
+- ses->chans[i].server->tcpStatus = CifsNeedReconnect;
++ if (ses->chans[i].server->tcpStatus != CifsExiting)
++ ses->chans[i].server->tcpStatus = CifsNeedReconnect;
+ spin_unlock(&ses->chans[i].server->srv_lock);
+ }
+ spin_unlock(&ses->chan_lock);
+diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c
+index 80050e36f045..650a3ec9e6e5 100644
+--- a/fs/smb/client/sess.c
++++ b/fs/smb/client/sess.c
+@@ -69,7 +69,7 @@ bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface)
+
+ /* channel helper functions. assumed that chan_lock is held by caller. */
+
+-unsigned int
++int
+ cifs_ses_get_chan_index(struct cifs_ses *ses,
+ struct TCP_Server_Info *server)
+ {
+@@ -85,14 +85,17 @@ cifs_ses_get_chan_index(struct cifs_ses *ses,
+ cifs_dbg(VFS, "unable to get chan index for server: 0x%llx",
+ server->conn_id);
+ WARN_ON(1);
+- return 0;
++ return CIFS_INVAL_CHAN_INDEX;
+ }
+
+ void
+ cifs_chan_set_in_reconnect(struct cifs_ses *ses,
+ struct TCP_Server_Info *server)
+ {
+- unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
++ int chan_index = cifs_ses_get_chan_index(ses, server);
++
++ if (chan_index == CIFS_INVAL_CHAN_INDEX)
++ return;
+
+ ses->chans[chan_index].in_reconnect = true;
+ }
+@@ -102,6 +105,8 @@ cifs_chan_clear_in_reconnect(struct cifs_ses *ses,
+ struct TCP_Server_Info *server)
+ {
+ unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
++ if (chan_index == CIFS_INVAL_CHAN_INDEX)
++ return;
+
+ ses->chans[chan_index].in_reconnect = false;
+ }
+@@ -111,6 +116,8 @@ cifs_chan_in_reconnect(struct cifs_ses *ses,
+ struct TCP_Server_Info *server)
+ {
+ unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
++ if (chan_index == CIFS_INVAL_CHAN_INDEX)
++ return true; /* err on the safer side */
+
+ return CIFS_CHAN_IN_RECONNECT(ses, chan_index);
+ }
+@@ -120,6 +127,8 @@ cifs_chan_set_need_reconnect(struct cifs_ses *ses,
+ struct TCP_Server_Info *server)
+ {
+ unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
++ if (chan_index == CIFS_INVAL_CHAN_INDEX)
++ return;
+
+ set_bit(chan_index, &ses->chans_need_reconnect);
+ cifs_dbg(FYI, "Set reconnect bitmask for chan %u; now 0x%lx\n",
+@@ -131,6 +140,8 @@ cifs_chan_clear_need_reconnect(struct cifs_ses *ses,
+ struct TCP_Server_Info *server)
+ {
+ unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
++ if (chan_index == CIFS_INVAL_CHAN_INDEX)
++ return;
+
+ clear_bit(chan_index, &ses->chans_need_reconnect);
+ cifs_dbg(FYI, "Cleared reconnect bitmask for chan %u; now 0x%lx\n",
+@@ -142,6 +153,8 @@ cifs_chan_needs_reconnect(struct cifs_ses *ses,
+ struct TCP_Server_Info *server)
+ {
+ unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
++ if (chan_index == CIFS_INVAL_CHAN_INDEX)
++ return true; /* err on the safer side */
+
+ return CIFS_CHAN_NEEDS_RECONNECT(ses, chan_index);
+ }
+@@ -151,6 +164,8 @@ cifs_chan_is_iface_active(struct cifs_ses *ses,
+ struct TCP_Server_Info *server)
+ {
+ unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
++ if (chan_index == CIFS_INVAL_CHAN_INDEX)
++ return true; /* err on the safer side */
+
+ return ses->chans[chan_index].iface &&
+ ses->chans[chan_index].iface->is_active;
+@@ -293,7 +308,7 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
+
+ spin_lock(&ses->chan_lock);
+ chan_index = cifs_ses_get_chan_index(ses, server);
+- if (!chan_index) {
++ if (chan_index == CIFS_INVAL_CHAN_INDEX) {
+ spin_unlock(&ses->chan_lock);
+ return 0;
+ }
+@@ -403,6 +418,11 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
+
+ spin_lock(&ses->chan_lock);
+ chan_index = cifs_ses_get_chan_index(ses, server);
++ if (chan_index == CIFS_INVAL_CHAN_INDEX) {
++ spin_unlock(&ses->chan_lock);
++ return 0;
++ }
++
+ ses->chans[chan_index].iface = iface;
+
+ /* No iface is found. if secondary chan, drop connection */
+diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c
+index a136fc4cc2b5..5a3ca62d2f07 100644
+--- a/fs/smb/client/smb2transport.c
++++ b/fs/smb/client/smb2transport.c
+@@ -413,7 +413,13 @@ generate_smb3signingkey(struct cifs_ses *ses,
+ ses->ses_status == SES_GOOD);
+
+ chan_index = cifs_ses_get_chan_index(ses, server);
+- /* TODO: introduce ref counting for channels when the can be freed */
++ if (chan_index == CIFS_INVAL_CHAN_INDEX) {
++ spin_unlock(&ses->chan_lock);
++ spin_unlock(&ses->ses_lock);
++
++ return -EINVAL;
++ }
++
+ spin_unlock(&ses->chan_lock);
+ spin_unlock(&ses->ses_lock);
+
+--
+2.43.0
+
--- /dev/null
+From e3a58a9a8a880e691f0c35025084cc98bab84cde Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 2 Jan 2024 13:14:46 +0000
+Subject: cifs: handle servers that still advertise multichannel after
+ disabling
+
+From: Shyam Prasad N <sprasad@microsoft.com>
+
+[ Upstream commit f591062bdbf4742b7f1622173017f19e927057b0 ]
+
+Some servers like Azure SMB servers always advertise multichannel
+capability in server capabilities list. Such servers return error
+STATUS_NOT_IMPLEMENTED for ioctl calls to query server interfaces,
+and expect clients to consider that as a sign that they do not support
+multichannel.
+
+We already handled this at mount time. Soon after the tree connect,
+we query server interfaces. And when server returned STATUS_NOT_IMPLEMENTED,
+we kept interface list as empty. When cifs_try_adding_channels gets
+called, it would not find any interfaces, so will not add channels.
+
+For the case where an active multichannel mount exists, and multichannel
+is disabled by such a server, this change will now allow the client
+to disable secondary channels on the mount. It will check the return
+status of query server interfaces call soon after a tree reconnect.
+If the return status is EOPNOTSUPP, then instead of the check to add
+more channels, we'll disable the secondary channels instead.
+
+For better code reuse, this change also moves the common code for
+disabling multichannel to a helper function.
+
+Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Stable-dep-of: 78e727e58e54 ("cifs: update iface_last_update on each query-and-update")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/smb2ops.c | 8 +--
+ fs/smb/client/smb2pdu.c | 107 +++++++++++++++++++++++++---------------
+ 2 files changed, 69 insertions(+), 46 deletions(-)
+
+diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
+index 0604696f59c1..8caf2cefc8a7 100644
+--- a/fs/smb/client/smb2ops.c
++++ b/fs/smb/client/smb2ops.c
+@@ -614,7 +614,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
+ "multichannel not available\n"
+ "Empty network interface list returned by server %s\n",
+ ses->server->hostname);
+- rc = -EINVAL;
++ rc = -EOPNOTSUPP;
+ goto out;
+ }
+
+@@ -734,12 +734,6 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
+ if ((bytes_left > 8) || p->Next)
+ cifs_dbg(VFS, "%s: incomplete interface info\n", __func__);
+
+-
+- if (!ses->iface_count) {
+- rc = -EINVAL;
+- goto out;
+- }
+-
+ out:
+ /*
+ * Go through the list again and put the inactive entries
+diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
+index a3995c6dc1ad..d846c238b7dd 100644
+--- a/fs/smb/client/smb2pdu.c
++++ b/fs/smb/client/smb2pdu.c
+@@ -156,6 +156,57 @@ smb2_hdr_assemble(struct smb2_hdr *shdr, __le16 smb2_cmd,
+ return;
+ }
+
++/* helper function for code reuse */
++static int
++cifs_chan_skip_or_disable(struct cifs_ses *ses,
++ struct TCP_Server_Info *server,
++ bool from_reconnect)
++{
++ struct TCP_Server_Info *pserver;
++ unsigned int chan_index;
++
++ if (SERVER_IS_CHAN(server)) {
++ cifs_dbg(VFS,
++ "server %s does not support multichannel anymore. Skip secondary channel\n",
++ ses->server->hostname);
++
++ spin_lock(&ses->chan_lock);
++ chan_index = cifs_ses_get_chan_index(ses, server);
++ if (chan_index == CIFS_INVAL_CHAN_INDEX) {
++ spin_unlock(&ses->chan_lock);
++ goto skip_terminate;
++ }
++
++ ses->chans[chan_index].server = NULL;
++ spin_unlock(&ses->chan_lock);
++
++ /*
++ * the above reference of server by channel
++ * needs to be dropped without holding chan_lock
++ * as cifs_put_tcp_session takes a higher lock
++ * i.e. cifs_tcp_ses_lock
++ */
++ cifs_put_tcp_session(server, from_reconnect);
++
++ server->terminate = true;
++ cifs_signal_cifsd_for_reconnect(server, false);
++
++ /* mark primary server as needing reconnect */
++ pserver = server->primary_server;
++ cifs_signal_cifsd_for_reconnect(pserver, false);
++skip_terminate:
++ mutex_unlock(&ses->session_mutex);
++ return -EHOSTDOWN;
++ }
++
++ cifs_server_dbg(VFS,
++ "server does not support multichannel anymore. Disable all other channels\n");
++ cifs_disable_secondary_channels(ses);
++
++
++ return 0;
++}
++
+ static int
+ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
+ struct TCP_Server_Info *server, bool from_reconnect)
+@@ -164,8 +215,6 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
+ struct nls_table *nls_codepage = NULL;
+ struct cifs_ses *ses;
+ int xid;
+- struct TCP_Server_Info *pserver;
+- unsigned int chan_index;
+
+ /*
+ * SMB2s NegProt, SessSetup, Logoff do not have tcon yet so
+@@ -310,44 +359,11 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
+ */
+ if (ses->chan_count > 1 &&
+ !(server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) {
+- if (SERVER_IS_CHAN(server)) {
+- cifs_dbg(VFS, "server %s does not support " \
+- "multichannel anymore. skipping secondary channel\n",
+- ses->server->hostname);
+-
+- spin_lock(&ses->chan_lock);
+- chan_index = cifs_ses_get_chan_index(ses, server);
+- if (chan_index == CIFS_INVAL_CHAN_INDEX) {
+- spin_unlock(&ses->chan_lock);
+- goto skip_terminate;
+- }
+-
+- ses->chans[chan_index].server = NULL;
+- spin_unlock(&ses->chan_lock);
+-
+- /*
+- * the above reference of server by channel
+- * needs to be dropped without holding chan_lock
+- * as cifs_put_tcp_session takes a higher lock
+- * i.e. cifs_tcp_ses_lock
+- */
+- cifs_put_tcp_session(server, from_reconnect);
+-
+- server->terminate = true;
+- cifs_signal_cifsd_for_reconnect(server, false);
+-
+- /* mark primary server as needing reconnect */
+- pserver = server->primary_server;
+- cifs_signal_cifsd_for_reconnect(pserver, false);
+-
+-skip_terminate:
++ rc = cifs_chan_skip_or_disable(ses, server,
++ from_reconnect);
++ if (rc) {
+ mutex_unlock(&ses->session_mutex);
+- rc = -EHOSTDOWN;
+ goto out;
+- } else {
+- cifs_server_dbg(VFS, "does not support " \
+- "multichannel anymore. disabling all other channels\n");
+- cifs_disable_secondary_channels(ses);
+ }
+ }
+
+@@ -395,11 +411,23 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
+ rc = SMB3_request_interfaces(xid, tcon, false);
+ free_xid(xid);
+
+- if (rc)
++ if (rc == -EOPNOTSUPP) {
++ /*
++ * some servers like Azure SMB server do not advertise
++ * that multichannel has been disabled with server
++ * capabilities, rather return STATUS_NOT_IMPLEMENTED.
++ * treat this as server not supporting multichannel
++ */
++
++ rc = cifs_chan_skip_or_disable(ses, server,
++ from_reconnect);
++ goto skip_add_channels;
++ } else if (rc)
+ cifs_dbg(FYI, "%s: failed to query server interfaces: %d\n",
+ __func__, rc);
+
+ if (ses->chan_max > ses->chan_count &&
++ ses->iface_count &&
+ !SERVER_IS_CHAN(server)) {
+ if (ses->chan_count == 1)
+ cifs_server_dbg(VFS, "supports multichannel now\n");
+@@ -409,6 +437,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
+ } else {
+ mutex_unlock(&ses->session_mutex);
+ }
++skip_add_channels:
+
+ if (smb2_command != SMB2_INTERNAL_CMD)
+ if (mod_delayed_work(cifsiod_wq, &server->reconnect, 0))
+--
+2.43.0
+
--- /dev/null
+From 72a8eaff0ccf35dedb6641183ad07acd1fda9d5b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Oct 2023 11:33:21 +0000
+Subject: cifs: handle when server starts supporting multichannel
+
+From: Shyam Prasad N <sprasad@microsoft.com>
+
+[ Upstream commit 705fc522fe9d58848c253ee0948567060f36e2a7 ]
+
+When the user mounts with multichannel option, but the
+server does not support it, there can be a time in future
+where it can be supported.
+
+With this change, such a case is handled.
+
+Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
+Stable-dep-of: 78e727e58e54 ("cifs: update iface_last_update on each query-and-update")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/cifsproto.h | 1 +
+ fs/smb/client/connect.c | 3 +++
+ fs/smb/client/smb2pdu.c | 32 ++++++++++++++++++++++++++++++--
+ 3 files changed, 34 insertions(+), 2 deletions(-)
+
+diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
+index 0eb62ccd476f..4a28cff87038 100644
+--- a/fs/smb/client/cifsproto.h
++++ b/fs/smb/client/cifsproto.h
+@@ -132,6 +132,7 @@ extern int SendReceiveBlockingLock(const unsigned int xid,
+ struct smb_hdr *in_buf,
+ struct smb_hdr *out_buf,
+ int *bytes_returned);
++
+ void
+ cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server,
+ bool all_channels);
+diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
+index 2f5be7dcd1f9..c0b1f30eecd7 100644
+--- a/fs/smb/client/connect.c
++++ b/fs/smb/client/connect.c
+@@ -128,6 +128,9 @@ static void smb2_query_server_interfaces(struct work_struct *work)
+ */
+ rc = SMB3_request_interfaces(0, tcon, false);
+ if (rc) {
++ if (rc == -EOPNOTSUPP)
++ return;
++
+ cifs_dbg(FYI, "%s: failed to query server interfaces: %d\n",
+ __func__, rc);
+ }
+diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
+index 0274ef67457b..288f22050c20 100644
+--- a/fs/smb/client/smb2pdu.c
++++ b/fs/smb/client/smb2pdu.c
+@@ -163,6 +163,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
+ int rc = 0;
+ struct nls_table *nls_codepage = NULL;
+ struct cifs_ses *ses;
++ int xid;
+
+ /*
+ * SMB2s NegProt, SessSetup, Logoff do not have tcon yet so
+@@ -307,17 +308,44 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
+ tcon->need_reopen_files = true;
+
+ rc = cifs_tree_connect(0, tcon, nls_codepage);
+- mutex_unlock(&ses->session_mutex);
+
+ cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
+ if (rc) {
+ /* If sess reconnected but tcon didn't, something strange ... */
++ mutex_unlock(&ses->session_mutex);
+ cifs_dbg(VFS, "reconnect tcon failed rc = %d\n", rc);
+ goto out;
+ }
+
++ if (!rc &&
++ (server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) {
++ mutex_unlock(&ses->session_mutex);
++
++ /*
++ * query server network interfaces, in case they change
++ */
++ xid = get_xid();
++ rc = SMB3_request_interfaces(xid, tcon, false);
++ free_xid(xid);
++
++ if (rc)
++ cifs_dbg(FYI, "%s: failed to query server interfaces: %d\n",
++ __func__, rc);
++
++ if (ses->chan_max > ses->chan_count &&
++ !SERVER_IS_CHAN(server)) {
++ if (ses->chan_count == 1)
++ cifs_server_dbg(VFS, "supports multichannel now\n");
++
++ cifs_try_adding_channels(ses);
++ }
++ } else {
++ mutex_unlock(&ses->session_mutex);
++ }
++
+ if (smb2_command != SMB2_INTERNAL_CMD)
+- mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
++ if (mod_delayed_work(cifsiod_wq, &server->reconnect, 0))
++ cifs_put_tcp_session(server, false);
+
+ atomic_inc(&tconInfoReconnectCount);
+ out:
+--
+2.43.0
+
--- /dev/null
+From 5b453a7be6de530810c2403054ba14bc1dfadfac Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Oct 2023 11:40:09 +0000
+Subject: cifs: handle when server stops supporting multichannel
+
+From: Shyam Prasad N <sprasad@microsoft.com>
+
+[ Upstream commit ee1d21794e55ab76505745d24101331552182002 ]
+
+When a server stops supporting multichannel, we will
+keep attempting reconnects to the secondary channels today.
+Avoid this by freeing extra channels when negotiate
+returns no multichannel support.
+
+Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Stable-dep-of: 78e727e58e54 ("cifs: update iface_last_update on each query-and-update")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/cifsglob.h | 1 +
+ fs/smb/client/cifsproto.h | 2 ++
+ fs/smb/client/connect.c | 10 ++++++
+ fs/smb/client/sess.c | 64 ++++++++++++++++++++++++++++-----
+ fs/smb/client/smb2pdu.c | 76 ++++++++++++++++++++++++++++++++++++++-
+ fs/smb/client/transport.c | 2 +-
+ 6 files changed, 145 insertions(+), 10 deletions(-)
+
+diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
+index e3ef8eee68d1..5e32c79f03a7 100644
+--- a/fs/smb/client/cifsglob.h
++++ b/fs/smb/client/cifsglob.h
+@@ -659,6 +659,7 @@ struct TCP_Server_Info {
+ bool noautotune; /* do not autotune send buf sizes */
+ bool nosharesock;
+ bool tcp_nodelay;
++ bool terminate;
+ unsigned int credits; /* send no more requests at once */
+ unsigned int max_credits; /* can override large 32000 default at mnt */
+ unsigned int in_flight; /* number of requests on the wire to server */
+diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
+index 4a28cff87038..c00f84420559 100644
+--- a/fs/smb/client/cifsproto.h
++++ b/fs/smb/client/cifsproto.h
+@@ -647,6 +647,8 @@ cifs_chan_needs_reconnect(struct cifs_ses *ses,
+ bool
+ cifs_chan_is_iface_active(struct cifs_ses *ses,
+ struct TCP_Server_Info *server);
++void
++cifs_disable_secondary_channels(struct cifs_ses *ses);
+ int
+ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server);
+ int
+diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
+index c0b1f30eecd7..f43f51f2d1c1 100644
+--- a/fs/smb/client/connect.c
++++ b/fs/smb/client/connect.c
+@@ -215,6 +215,14 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
+
+ spin_lock(&cifs_tcp_ses_lock);
+ list_for_each_entry_safe(ses, nses, &pserver->smb_ses_list, smb_ses_list) {
++ /*
++ * if channel has been marked for termination, nothing to do
++ * for the channel. in fact, we cannot find the channel for the
++ * server. So safe to exit here
++ */
++ if (server->terminate)
++ break;
++
+ /* check if iface is still active */
+ spin_lock(&ses->chan_lock);
+ if (!cifs_chan_is_iface_active(ses, server)) {
+@@ -252,6 +260,8 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
+ spin_lock(&tcon->tc_lock);
+ tcon->status = TID_NEED_RECON;
+ spin_unlock(&tcon->tc_lock);
++
++ cancel_delayed_work(&tcon->query_interfaces);
+ }
+ if (ses->tcon_ipc) {
+ ses->tcon_ipc->need_reconnect = true;
+diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c
+index 650a3ec9e6e5..2ce1b7571371 100644
+--- a/fs/smb/client/sess.c
++++ b/fs/smb/client/sess.c
+@@ -290,6 +290,60 @@ int cifs_try_adding_channels(struct cifs_ses *ses)
+ return new_chan_count - old_chan_count;
+ }
+
++/*
++ * called when multichannel is disabled by the server.
++ * this always gets called from smb2_reconnect
++ * and cannot get called in parallel threads.
++ */
++void
++cifs_disable_secondary_channels(struct cifs_ses *ses)
++{
++ int i, chan_count;
++ struct TCP_Server_Info *server;
++ struct cifs_server_iface *iface;
++
++ spin_lock(&ses->chan_lock);
++ chan_count = ses->chan_count;
++ if (chan_count == 1)
++ goto done;
++
++ ses->chan_count = 1;
++
++ /* for all secondary channels reset the need reconnect bit */
++ ses->chans_need_reconnect &= 1;
++
++ for (i = 1; i < chan_count; i++) {
++ iface = ses->chans[i].iface;
++ server = ses->chans[i].server;
++
++ if (iface) {
++ spin_lock(&ses->iface_lock);
++ kref_put(&iface->refcount, release_iface);
++ ses->chans[i].iface = NULL;
++ iface->num_channels--;
++ if (iface->weight_fulfilled)
++ iface->weight_fulfilled--;
++ spin_unlock(&ses->iface_lock);
++ }
++
++ spin_unlock(&ses->chan_lock);
++ if (server && !server->terminate) {
++ server->terminate = true;
++ cifs_signal_cifsd_for_reconnect(server, false);
++ }
++ spin_lock(&ses->chan_lock);
++
++ if (server) {
++ ses->chans[i].server = NULL;
++ cifs_put_tcp_session(server, false);
++ }
++
++ }
++
++done:
++ spin_unlock(&ses->chan_lock);
++}
++
+ /*
+ * update the iface for the channel if necessary.
+ * will return 0 when iface is updated, 1 if removed, 2 otherwise
+@@ -589,14 +643,10 @@ cifs_ses_add_channel(struct cifs_ses *ses,
+
+ out:
+ if (rc && chan->server) {
+- /*
+- * we should avoid race with these delayed works before we
+- * remove this channel
+- */
+- cancel_delayed_work_sync(&chan->server->echo);
+- cancel_delayed_work_sync(&chan->server->reconnect);
++ cifs_put_tcp_session(chan->server, 0);
+
+ spin_lock(&ses->chan_lock);
++
+ /* we rely on all bits beyond chan_count to be clear */
+ cifs_chan_clear_need_reconnect(ses, chan->server);
+ ses->chan_count--;
+@@ -606,8 +656,6 @@ cifs_ses_add_channel(struct cifs_ses *ses,
+ */
+ WARN_ON(ses->chan_count < 1);
+ spin_unlock(&ses->chan_lock);
+-
+- cifs_put_tcp_session(chan->server, 0);
+ }
+
+ kfree(ctx->UNC);
+diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
+index 288f22050c20..f1977987ae74 100644
+--- a/fs/smb/client/smb2pdu.c
++++ b/fs/smb/client/smb2pdu.c
+@@ -164,6 +164,8 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
+ struct nls_table *nls_codepage = NULL;
+ struct cifs_ses *ses;
+ int xid;
++ struct TCP_Server_Info *pserver;
++ unsigned int chan_index;
+
+ /*
+ * SMB2s NegProt, SessSetup, Logoff do not have tcon yet so
+@@ -224,6 +226,12 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
+ return -EAGAIN;
+ }
+ }
++
++ /* if server is marked for termination, cifsd will cleanup */
++ if (server->terminate) {
++ spin_unlock(&server->srv_lock);
++ return -EHOSTDOWN;
++ }
+ spin_unlock(&server->srv_lock);
+
+ again:
+@@ -242,12 +250,24 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
+ tcon->need_reconnect);
+
+ mutex_lock(&ses->session_mutex);
++ /*
++ * if this is called by delayed work, and the channel has been disabled
++ * in parallel, the delayed work can continue to execute in parallel
++ * there's a chance that this channel may not exist anymore
++ */
++ spin_lock(&server->srv_lock);
++ if (server->tcpStatus == CifsExiting) {
++ spin_unlock(&server->srv_lock);
++ mutex_unlock(&ses->session_mutex);
++ rc = -EHOSTDOWN;
++ goto out;
++ }
++
+ /*
+ * Recheck after acquire mutex. If another thread is negotiating
+ * and the server never sends an answer the socket will be closed
+ * and tcpStatus set to reconnect.
+ */
+- spin_lock(&server->srv_lock);
+ if (server->tcpStatus == CifsNeedReconnect) {
+ spin_unlock(&server->srv_lock);
+ mutex_unlock(&ses->session_mutex);
+@@ -284,6 +304,53 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
+
+ rc = cifs_negotiate_protocol(0, ses, server);
+ if (!rc) {
++ /*
++ * if server stopped supporting multichannel
++ * and the first channel reconnected, disable all the others.
++ */
++ if (ses->chan_count > 1 &&
++ !(server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) {
++ if (SERVER_IS_CHAN(server)) {
++ cifs_dbg(VFS, "server %s does not support " \
++ "multichannel anymore. skipping secondary channel\n",
++ ses->server->hostname);
++
++ spin_lock(&ses->chan_lock);
++ chan_index = cifs_ses_get_chan_index(ses, server);
++ if (chan_index == CIFS_INVAL_CHAN_INDEX) {
++ spin_unlock(&ses->chan_lock);
++ goto skip_terminate;
++ }
++
++ ses->chans[chan_index].server = NULL;
++ spin_unlock(&ses->chan_lock);
++
++ /*
++ * the above reference of server by channel
++ * needs to be dropped without holding chan_lock
++ * as cifs_put_tcp_session takes a higher lock
++ * i.e. cifs_tcp_ses_lock
++ */
++ cifs_put_tcp_session(server, 1);
++
++ server->terminate = true;
++ cifs_signal_cifsd_for_reconnect(server, false);
++
++ /* mark primary server as needing reconnect */
++ pserver = server->primary_server;
++ cifs_signal_cifsd_for_reconnect(pserver, false);
++
++skip_terminate:
++ mutex_unlock(&ses->session_mutex);
++ rc = -EHOSTDOWN;
++ goto out;
++ } else {
++ cifs_server_dbg(VFS, "does not support " \
++ "multichannel anymore. disabling all other channels\n");
++ cifs_disable_secondary_channels(ses);
++ }
++ }
++
+ rc = cifs_setup_session(0, ses, server, nls_codepage);
+ if ((rc == -EACCES) && !tcon->retry) {
+ mutex_unlock(&ses->session_mutex);
+@@ -3863,6 +3930,13 @@ void smb2_reconnect_server(struct work_struct *work)
+ /* Prevent simultaneous reconnects that can corrupt tcon->rlist list */
+ mutex_lock(&pserver->reconnect_mutex);
+
++ /* if the server is marked for termination, drop the ref count here */
++ if (server->terminate) {
++ cifs_put_tcp_session(server, true);
++ mutex_unlock(&pserver->reconnect_mutex);
++ return;
++ }
++
+ INIT_LIST_HEAD(&tmp_list);
+ INIT_LIST_HEAD(&tmp_ses_list);
+ cifs_dbg(FYI, "Reconnecting tcons and channels\n");
+diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c
+index d553b7a54621..4f717ad7c21b 100644
+--- a/fs/smb/client/transport.c
++++ b/fs/smb/client/transport.c
+@@ -1023,7 +1023,7 @@ struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses)
+ spin_lock(&ses->chan_lock);
+ for (i = 0; i < ses->chan_count; i++) {
+ server = ses->chans[i].server;
+- if (!server)
++ if (!server || server->terminate)
+ continue;
+
+ /*
+--
+2.43.0
+
--- /dev/null
+From 980324fe16226cda05649fa31e5ad79e60818e1f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Oct 2023 11:43:09 +0000
+Subject: cifs: reconnect work should have reference on server struct
+
+From: Shyam Prasad N <sprasad@microsoft.com>
+
+[ Upstream commit 19a4b9d6c372cab6a3b2c9a061a236136fe95274 ]
+
+The delayed work for reconnect takes server struct
+as a parameter. But it does so without holding a ref
+to it. Normally, this may not show a problem as
+the reconnect work is only cancelled on umount.
+
+However, since we now plan to support scaling down of
+channels, and the scale down can happen from reconnect
+work itself, we need to fix it.
+
+This change takes a reference on the server struct
+before it is passed to the delayed work. And drops
+the reference in the delayed work itself. Or if
+the delayed work is successfully cancelled, by the
+process that cancels it.
+
+Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Stable-dep-of: 78e727e58e54 ("cifs: update iface_last_update on each query-and-update")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/connect.c | 27 +++++++++++++++++++++------
+ fs/smb/client/smb2pdu.c | 23 +++++++++++++----------
+ 2 files changed, 34 insertions(+), 16 deletions(-)
+
+diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
+index a482afa3fa42..2f5be7dcd1f9 100644
+--- a/fs/smb/client/connect.c
++++ b/fs/smb/client/connect.c
+@@ -388,7 +388,13 @@ static int __cifs_reconnect(struct TCP_Server_Info *server,
+ spin_unlock(&server->srv_lock);
+ cifs_swn_reset_server_dstaddr(server);
+ cifs_server_unlock(server);
+- mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
++
++ /* increase ref count which reconnect work will drop */
++ spin_lock(&cifs_tcp_ses_lock);
++ server->srv_count++;
++ spin_unlock(&cifs_tcp_ses_lock);
++ if (mod_delayed_work(cifsiod_wq, &server->reconnect, 0))
++ cifs_put_tcp_session(server, false);
+ }
+ } while (server->tcpStatus == CifsNeedReconnect);
+
+@@ -518,7 +524,13 @@ static int reconnect_dfs_server(struct TCP_Server_Info *server)
+ spin_unlock(&server->srv_lock);
+ cifs_swn_reset_server_dstaddr(server);
+ cifs_server_unlock(server);
+- mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
++
++ /* increase ref count which reconnect work will drop */
++ spin_lock(&cifs_tcp_ses_lock);
++ server->srv_count++;
++ spin_unlock(&cifs_tcp_ses_lock);
++ if (mod_delayed_work(cifsiod_wq, &server->reconnect, 0))
++ cifs_put_tcp_session(server, false);
+ } while (server->tcpStatus == CifsNeedReconnect);
+
+ mutex_lock(&server->refpath_lock);
+@@ -1605,16 +1617,19 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
+
+ cancel_delayed_work_sync(&server->echo);
+
+- if (from_reconnect)
++ if (from_reconnect) {
+ /*
+ * Avoid deadlock here: reconnect work calls
+ * cifs_put_tcp_session() at its end. Need to be sure
+ * that reconnect work does nothing with server pointer after
+ * that step.
+ */
+- cancel_delayed_work(&server->reconnect);
+- else
+- cancel_delayed_work_sync(&server->reconnect);
++ if (cancel_delayed_work(&server->reconnect))
++ cifs_put_tcp_session(server, from_reconnect);
++ } else {
++ if (cancel_delayed_work_sync(&server->reconnect))
++ cifs_put_tcp_session(server, from_reconnect);
++ }
+
+ spin_lock(&server->srv_lock);
+ server->tcpStatus = CifsExiting;
+diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
+index 888eb59ad86f..0274ef67457b 100644
+--- a/fs/smb/client/smb2pdu.c
++++ b/fs/smb/client/smb2pdu.c
+@@ -3879,12 +3879,6 @@ void smb2_reconnect_server(struct work_struct *work)
+ }
+ spin_unlock(&ses->chan_lock);
+ }
+- /*
+- * Get the reference to server struct to be sure that the last call of
+- * cifs_put_tcon() in the loop below won't release the server pointer.
+- */
+- if (tcon_exist || ses_exist)
+- server->srv_count++;
+
+ spin_unlock(&cifs_tcp_ses_lock);
+
+@@ -3932,13 +3926,17 @@ void smb2_reconnect_server(struct work_struct *work)
+
+ done:
+ cifs_dbg(FYI, "Reconnecting tcons and channels finished\n");
+- if (resched)
++ if (resched) {
+ queue_delayed_work(cifsiod_wq, &server->reconnect, 2 * HZ);
++ mutex_unlock(&pserver->reconnect_mutex);
++
++ /* no need to put tcp session as we're retrying */
++ return;
++ }
+ mutex_unlock(&pserver->reconnect_mutex);
+
+ /* now we can safely release srv struct */
+- if (tcon_exist || ses_exist)
+- cifs_put_tcp_session(server, 1);
++ cifs_put_tcp_session(server, true);
+ }
+
+ int
+@@ -3958,7 +3956,12 @@ SMB2_echo(struct TCP_Server_Info *server)
+ server->ops->need_neg(server)) {
+ spin_unlock(&server->srv_lock);
+ /* No need to send echo on newly established connections */
+- mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
++ spin_lock(&cifs_tcp_ses_lock);
++ server->srv_count++;
++ spin_unlock(&cifs_tcp_ses_lock);
++ if (mod_delayed_work(cifsiod_wq, &server->reconnect, 0))
++ cifs_put_tcp_session(server, false);
++
+ return rc;
+ }
+ spin_unlock(&server->srv_lock);
+--
+2.43.0
+
--- /dev/null
+From e0401d1f68695cd540b09e01970245c8ab6a8e8b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 6 Dec 2023 16:37:38 +0000
+Subject: cifs: reconnect worker should take reference on server struct
+ unconditionally
+
+From: Shyam Prasad N <sprasad@microsoft.com>
+
+[ Upstream commit 04909192ada3285070f8ced0af7f07735478b364 ]
+
+Reconnect worker currently assumes that the server struct
+is alive and only takes reference on the server if it needs
+to call smb2_reconnect.
+
+With the new ability to disable channels based on whether the
+server has multichannel disabled, this becomes a problem when
+we need to disable established channels. While disabling the
+channels and deallocating the server, there could be reconnect
+work that could not be cancelled (because it started).
+
+This change forces the reconnect worker to unconditionally
+take a reference on the server when it runs.
+
+Also, this change now allows smb2_reconnect to know if it was
+called by the reconnect worker. Based on this, the cifs_put_tcp_session
+can decide whether it can cancel the reconnect work synchronously or not.
+
+Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Stable-dep-of: 78e727e58e54 ("cifs: update iface_last_update on each query-and-update")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/connect.c | 8 ++++----
+ fs/smb/client/smb2pdu.c | 29 +++++++++++++++--------------
+ 2 files changed, 19 insertions(+), 18 deletions(-)
+
+diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
+index 2a30245287d5..432248e955ed 100644
+--- a/fs/smb/client/connect.c
++++ b/fs/smb/client/connect.c
+@@ -1612,10 +1612,6 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
+ list_del_init(&server->tcp_ses_list);
+ spin_unlock(&cifs_tcp_ses_lock);
+
+- /* For secondary channels, we pick up ref-count on the primary server */
+- if (SERVER_IS_CHAN(server))
+- cifs_put_tcp_session(server->primary_server, from_reconnect);
+-
+ cancel_delayed_work_sync(&server->echo);
+
+ if (from_reconnect)
+@@ -1629,6 +1625,10 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
+ else
+ cancel_delayed_work_sync(&server->reconnect);
+
++ /* For secondary channels, we pick up ref-count on the primary server */
++ if (SERVER_IS_CHAN(server))
++ cifs_put_tcp_session(server->primary_server, from_reconnect);
++
+ spin_lock(&server->srv_lock);
+ server->tcpStatus = CifsExiting;
+ spin_unlock(&server->srv_lock);
+diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
+index da752f41a4e6..a3995c6dc1ad 100644
+--- a/fs/smb/client/smb2pdu.c
++++ b/fs/smb/client/smb2pdu.c
+@@ -158,7 +158,7 @@ smb2_hdr_assemble(struct smb2_hdr *shdr, __le16 smb2_cmd,
+
+ static int
+ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
+- struct TCP_Server_Info *server)
++ struct TCP_Server_Info *server, bool from_reconnect)
+ {
+ int rc = 0;
+ struct nls_table *nls_codepage = NULL;
+@@ -331,7 +331,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
+ * as cifs_put_tcp_session takes a higher lock
+ * i.e. cifs_tcp_ses_lock
+ */
+- cifs_put_tcp_session(server, 1);
++ cifs_put_tcp_session(server, from_reconnect);
+
+ server->terminate = true;
+ cifs_signal_cifsd_for_reconnect(server, false);
+@@ -504,7 +504,7 @@ static int smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon,
+ {
+ int rc;
+
+- rc = smb2_reconnect(smb2_command, tcon, server);
++ rc = smb2_reconnect(smb2_command, tcon, server, false);
+ if (rc)
+ return rc;
+
+@@ -3924,6 +3924,15 @@ void smb2_reconnect_server(struct work_struct *work)
+ int rc;
+ bool resched = false;
+
++ /* first check if ref count has reached 0, if not inc ref count */
++ spin_lock(&cifs_tcp_ses_lock);
++ if (!server->srv_count) {
++ spin_unlock(&cifs_tcp_ses_lock);
++ return;
++ }
++ server->srv_count++;
++ spin_unlock(&cifs_tcp_ses_lock);
++
+ /* If server is a channel, select the primary channel */
+ pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
+
+@@ -3981,17 +3990,10 @@ void smb2_reconnect_server(struct work_struct *work)
+ }
+ spin_unlock(&ses->chan_lock);
+ }
+- /*
+- * Get the reference to server struct to be sure that the last call of
+- * cifs_put_tcon() in the loop below won't release the server pointer.
+- */
+- if (tcon_exist || ses_exist)
+- server->srv_count++;
+-
+ spin_unlock(&cifs_tcp_ses_lock);
+
+ list_for_each_entry_safe(tcon, tcon2, &tmp_list, rlist) {
+- rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon, server);
++ rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon, server, true);
+ if (!rc)
+ cifs_reopen_persistent_handles(tcon);
+ else
+@@ -4024,7 +4026,7 @@ void smb2_reconnect_server(struct work_struct *work)
+ /* now reconnect sessions for necessary channels */
+ list_for_each_entry_safe(ses, ses2, &tmp_ses_list, rlist) {
+ tcon->ses = ses;
+- rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon, server);
++ rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon, server, true);
+ if (rc)
+ resched = true;
+ list_del_init(&ses->rlist);
+@@ -4039,8 +4041,7 @@ void smb2_reconnect_server(struct work_struct *work)
+ mutex_unlock(&pserver->reconnect_mutex);
+
+ /* now we can safely release srv struct */
+- if (tcon_exist || ses_exist)
+- cifs_put_tcp_session(server, 1);
++ cifs_put_tcp_session(server, true);
+ }
+
+ int
+--
+2.43.0
+
--- /dev/null
+From 25c77fdd03109541f14ba45bbc7b11692da19709 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 3 Jan 2024 12:51:49 +0000
+Subject: cifs: update iface_last_update on each query-and-update
+
+From: Shyam Prasad N <sprasad@microsoft.com>
+
+[ Upstream commit 78e727e58e54efca4c23863fbd9e16e9d2d83f81 ]
+
+iface_last_update was an unused field when it was introduced.
+Later, when we had periodic update of server interface list,
+this field was used regularly to decide when to update next.
+
+However, with the new logic of updating the interfaces, it
+becomes crucial that this field be updated whenever
+parse_server_interfaces runs successfully.
+
+This change updates this field when either the server does
+not support query of interfaces; so that we do not query
+the interfaces repeatedly. It also updates the field when
+the function reaches the end.
+
+Fixes: aa45dadd34e4 ("cifs: change iface_list from array to sorted linked list")
+Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/smb2ops.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
+index 8caf2cefc8a7..e33ed0fbc318 100644
+--- a/fs/smb/client/smb2ops.c
++++ b/fs/smb/client/smb2ops.c
+@@ -615,6 +615,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
+ "Empty network interface list returned by server %s\n",
+ ses->server->hostname);
+ rc = -EOPNOTSUPP;
++ ses->iface_last_update = jiffies;
+ goto out;
+ }
+
+@@ -712,7 +713,6 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
+
+ ses->iface_count++;
+ spin_unlock(&ses->iface_lock);
+- ses->iface_last_update = jiffies;
+ next_iface:
+ nb_iface++;
+ next = le32_to_cpu(p->Next);
+@@ -734,6 +734,8 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
+ if ((bytes_left > 8) || p->Next)
+ cifs_dbg(VFS, "%s: incomplete interface info\n", __func__);
+
++ ses->iface_last_update = jiffies;
++
+ out:
+ /*
+ * Go through the list again and put the inactive entries
+--
+2.43.0
+
--- /dev/null
+From 723056ffcc9eaf4dd2e102cfe0897781b1060f55 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 Dec 2023 17:04:52 +0100
+Subject: dmaengine: fix NULL pointer in channel unregistration function
+
+From: Amelie Delaunay <amelie.delaunay@foss.st.com>
+
+[ Upstream commit f5c24d94512f1b288262beda4d3dcb9629222fc7 ]
+
+__dma_async_device_channel_register() can fail. In case of failure,
+chan->local is freed (with free_percpu()), and chan->local is nullified.
+When dma_async_device_unregister() is called (because of managed API or
+intentionally by DMA controller driver), channels are unconditionally
+unregistered, leading to this NULL pointer:
+[ 1.318693] Unable to handle kernel NULL pointer dereference at virtual address 00000000000000d0
+[...]
+[ 1.484499] Call trace:
+[ 1.486930] device_del+0x40/0x394
+[ 1.490314] device_unregister+0x20/0x7c
+[ 1.494220] __dma_async_device_channel_unregister+0x68/0xc0
+
+Look at dma_async_device_register() function error path, channel device
+unregistration is done only if chan->local is not NULL.
+
+Then add the same condition at the beginning of
+__dma_async_device_channel_unregister() function, to avoid NULL pointer
+issue whatever the API used to reach this function.
+
+Fixes: d2fb0a043838 ("dmaengine: break out channel registration")
+Signed-off-by: Amelie Delaunay <amelie.delaunay@foss.st.com>
+Reviewed-by: Dave Jiang <dave.jiang@intel.com>
+Link: https://lore.kernel.org/r/20231213160452.2598073-1-amelie.delaunay@foss.st.com
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/dma/dmaengine.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
+index b7388ae62d7f..491b22240221 100644
+--- a/drivers/dma/dmaengine.c
++++ b/drivers/dma/dmaengine.c
+@@ -1103,6 +1103,9 @@ EXPORT_SYMBOL_GPL(dma_async_device_channel_register);
+ static void __dma_async_device_channel_unregister(struct dma_device *device,
+ struct dma_chan *chan)
+ {
++ if (chan->local == NULL)
++ return;
++
+ WARN_ONCE(!device->device_release && chan->client_count,
+ "%s called while %d clients hold a reference\n",
+ __func__, chan->client_count);
+--
+2.43.0
+
--- /dev/null
+From 70e27894308fae25daf1e05d775cdd2d16cc7b7f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 14 Nov 2023 10:48:21 -0500
+Subject: dmaengine: fsl-edma: fix eDMAv4 channel allocation issue
+
+From: Frank Li <Frank.Li@nxp.com>
+
+[ Upstream commit dc51b4442dd94ab12c146c1897bbdb40e16d5636 ]
+
+The eDMAv4 channel mux has a limitation where certain requests must use
+even channels, while others must use odd numbers.
+
+Add two flags (ARGS_EVEN_CH and ARGS_ODD_CH) to reflect this limitation.
+The device tree source (dts) files need to be updated accordingly.
+
+This issue was identified by the following commit:
+commit a725990557e7 ("arm64: dts: imx93: Fix the dmas entries order")
+
+Reverting channel orders triggered this problem.
+
+Fixes: 72f5801a4e2b ("dmaengine: fsl-edma: integrate v3 support")
+Signed-off-by: Frank Li <Frank.Li@nxp.com>
+Link: https://lore.kernel.org/r/20231114154824.3617255-2-Frank.Li@nxp.com
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/dma/fsl-edma-main.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c
+index 00cb70aca34a..30df55da4dbb 100644
+--- a/drivers/dma/fsl-edma-main.c
++++ b/drivers/dma/fsl-edma-main.c
+@@ -26,6 +26,8 @@
+ #define ARGS_RX BIT(0)
+ #define ARGS_REMOTE BIT(1)
+ #define ARGS_MULTI_FIFO BIT(2)
++#define ARGS_EVEN_CH BIT(3)
++#define ARGS_ODD_CH BIT(4)
+
+ static void fsl_edma_synchronize(struct dma_chan *chan)
+ {
+@@ -159,6 +161,12 @@ static struct dma_chan *fsl_edma3_xlate(struct of_phandle_args *dma_spec,
+ fsl_chan->is_remote = dma_spec->args[2] & ARGS_REMOTE;
+ fsl_chan->is_multi_fifo = dma_spec->args[2] & ARGS_MULTI_FIFO;
+
++ if ((dma_spec->args[2] & ARGS_EVEN_CH) && (i & 0x1))
++ continue;
++
++ if ((dma_spec->args[2] & ARGS_ODD_CH) && !(i & 0x1))
++ continue;
++
+ if (!b_chmux && i == dma_spec->args[0]) {
+ chan = dma_get_slave_channel(chan);
+ chan->device->privatecnt++;
+--
+2.43.0
+
--- /dev/null
+From e62a16ef2b0f028e5d22351c020db283f51df1cb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 12 Dec 2023 10:21:58 +0800
+Subject: dmaengine: idxd: Move dma_free_coherent() out of spinlocked context
+
+From: Rex Zhang <rex.zhang@intel.com>
+
+[ Upstream commit e271c0ba3f919c48e90c64b703538fbb7865cb63 ]
+
+Task may be rescheduled within dma_free_coherent(). So dma_free_coherent()
+can't be called between spin_lock() and spin_unlock() to avoid Call Trace:
+ Call Trace:
+ <TASK>
+ dump_stack_lvl+0x37/0x50
+ __might_resched+0x16a/0x1c0
+ vunmap+0x2c/0x70
+ __iommu_dma_free+0x96/0x100
+ idxd_device_evl_free+0xd5/0x100 [idxd]
+ device_release_driver_internal+0x197/0x200
+ unbind_store+0xa1/0xb0
+ kernfs_fop_write_iter+0x120/0x1c0
+ vfs_write+0x2d3/0x400
+ ksys_write+0x63/0xe0
+ do_syscall_64+0x44/0xa0
+ entry_SYSCALL_64_after_hwframe+0x6e/0xd8
+Move it out of the context.
+
+Fixes: 244da66cda35 ("dmaengine: idxd: setup event log configuration")
+Signed-off-by: Rex Zhang <rex.zhang@intel.com>
+Reviewed-by: Dave Jiang <dave.jiang@intel.com>
+Reviewed-by: Fenghua Yu <fenghua.yu@intel.com>
+Link: https://lore.kernel.org/r/20231212022158.358619-2-rex.zhang@intel.com
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/dma/idxd/device.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c
+index 8f754f922217..fa0f880beae6 100644
+--- a/drivers/dma/idxd/device.c
++++ b/drivers/dma/idxd/device.c
+@@ -802,6 +802,9 @@ static int idxd_device_evl_setup(struct idxd_device *idxd)
+
+ static void idxd_device_evl_free(struct idxd_device *idxd)
+ {
++ void *evl_log;
++ unsigned int evl_log_size;
++ dma_addr_t evl_dma;
+ union gencfg_reg gencfg;
+ union genctrl_reg genctrl;
+ struct device *dev = &idxd->pdev->dev;
+@@ -822,11 +825,15 @@ static void idxd_device_evl_free(struct idxd_device *idxd)
+ iowrite64(0, idxd->reg_base + IDXD_EVLCFG_OFFSET);
+ iowrite64(0, idxd->reg_base + IDXD_EVLCFG_OFFSET + 8);
+
+- dma_free_coherent(dev, evl->log_size, evl->log, evl->dma);
+ bitmap_free(evl->bmap);
++ evl_log = evl->log;
++ evl_log_size = evl->log_size;
++ evl_dma = evl->dma;
+ evl->log = NULL;
+ evl->size = IDXD_EVL_SIZE_MIN;
+ spin_unlock(&evl->lock);
++
++ dma_free_coherent(dev, evl_log_size, evl_log, evl_dma);
+ }
+
+ static void idxd_group_config_write(struct idxd_group *group)
+--
+2.43.0
+
--- /dev/null
+From fc3445d032b02beb25fe4460daae50404dc8c441 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 10 Jan 2024 18:47:58 +0100
+Subject: docs: kernel_feat.py: fix potential command injection
+
+From: Vegard Nossum <vegard.nossum@oracle.com>
+
+[ Upstream commit c48a7c44a1d02516309015b6134c9bb982e17008 ]
+
+The kernel-feat directive passes its argument straight to the shell.
+This is unfortunate and unnecessary.
+
+Let's always use paths relative to $srctree/Documentation/ and use
+subprocess.check_call() instead of subprocess.Popen(shell=True).
+
+This also makes the code shorter.
+
+This is analogous to commit 3231dd586277 ("docs: kernel_abi.py: fix
+command injection") where we did exactly the same thing for
+kernel_abi.py, somehow I completely missed this one.
+
+Link: https://fosstodon.org/@jani/111676532203641247
+Reported-by: Jani Nikula <jani.nikula@intel.com>
+Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Jonathan Corbet <corbet@lwn.net>
+Link: https://lore.kernel.org/r/20240110174758.3680506-1-vegard.nossum@oracle.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ Documentation/admin-guide/features.rst | 2 +-
+ Documentation/arch/arc/features.rst | 2 +-
+ Documentation/arch/arm/features.rst | 2 +-
+ Documentation/arch/arm64/features.rst | 2 +-
+ Documentation/arch/loongarch/features.rst | 2 +-
+ Documentation/arch/m68k/features.rst | 2 +-
+ Documentation/arch/mips/features.rst | 2 +-
+ Documentation/arch/nios2/features.rst | 2 +-
+ Documentation/arch/openrisc/features.rst | 2 +-
+ Documentation/arch/parisc/features.rst | 2 +-
+ Documentation/arch/s390/features.rst | 2 +-
+ Documentation/arch/sh/features.rst | 2 +-
+ Documentation/arch/sparc/features.rst | 2 +-
+ Documentation/arch/x86/features.rst | 2 +-
+ Documentation/arch/xtensa/features.rst | 2 +-
+ Documentation/powerpc/features.rst | 2 +-
+ Documentation/riscv/features.rst | 2 +-
+ Documentation/sphinx/kernel_feat.py | 55 ++++---------------
+ .../zh_CN/arch/loongarch/features.rst | 2 +-
+ .../translations/zh_CN/arch/mips/features.rst | 2 +-
+ 20 files changed, 30 insertions(+), 63 deletions(-)
+
+diff --git a/Documentation/admin-guide/features.rst b/Documentation/admin-guide/features.rst
+index 8c167082a84f..7651eca38227 100644
+--- a/Documentation/admin-guide/features.rst
++++ b/Documentation/admin-guide/features.rst
+@@ -1,3 +1,3 @@
+ .. SPDX-License-Identifier: GPL-2.0
+
+-.. kernel-feat:: $srctree/Documentation/features
++.. kernel-feat:: features
+diff --git a/Documentation/arch/arc/features.rst b/Documentation/arch/arc/features.rst
+index b793583d688a..49ff446ff744 100644
+--- a/Documentation/arch/arc/features.rst
++++ b/Documentation/arch/arc/features.rst
+@@ -1,3 +1,3 @@
+ .. SPDX-License-Identifier: GPL-2.0
+
+-.. kernel-feat:: $srctree/Documentation/features arc
++.. kernel-feat:: features arc
+diff --git a/Documentation/arch/arm/features.rst b/Documentation/arch/arm/features.rst
+index 7414ec03dd15..0e76aaf68eca 100644
+--- a/Documentation/arch/arm/features.rst
++++ b/Documentation/arch/arm/features.rst
+@@ -1,3 +1,3 @@
+ .. SPDX-License-Identifier: GPL-2.0
+
+-.. kernel-feat:: $srctree/Documentation/features arm
++.. kernel-feat:: features arm
+diff --git a/Documentation/arch/arm64/features.rst b/Documentation/arch/arm64/features.rst
+index dfa4cb3cd3ef..03321f4309d0 100644
+--- a/Documentation/arch/arm64/features.rst
++++ b/Documentation/arch/arm64/features.rst
+@@ -1,3 +1,3 @@
+ .. SPDX-License-Identifier: GPL-2.0
+
+-.. kernel-feat:: $srctree/Documentation/features arm64
++.. kernel-feat:: features arm64
+diff --git a/Documentation/arch/loongarch/features.rst b/Documentation/arch/loongarch/features.rst
+index ebacade3ea45..009f44c7951f 100644
+--- a/Documentation/arch/loongarch/features.rst
++++ b/Documentation/arch/loongarch/features.rst
+@@ -1,3 +1,3 @@
+ .. SPDX-License-Identifier: GPL-2.0
+
+-.. kernel-feat:: $srctree/Documentation/features loongarch
++.. kernel-feat:: features loongarch
+diff --git a/Documentation/arch/m68k/features.rst b/Documentation/arch/m68k/features.rst
+index 5107a2119472..de7f0ccf7fc8 100644
+--- a/Documentation/arch/m68k/features.rst
++++ b/Documentation/arch/m68k/features.rst
+@@ -1,3 +1,3 @@
+ .. SPDX-License-Identifier: GPL-2.0
+
+-.. kernel-feat:: $srctree/Documentation/features m68k
++.. kernel-feat:: features m68k
+diff --git a/Documentation/arch/mips/features.rst b/Documentation/arch/mips/features.rst
+index 1973d729b29a..6e0ffe3e7354 100644
+--- a/Documentation/arch/mips/features.rst
++++ b/Documentation/arch/mips/features.rst
+@@ -1,3 +1,3 @@
+ .. SPDX-License-Identifier: GPL-2.0
+
+-.. kernel-feat:: $srctree/Documentation/features mips
++.. kernel-feat:: features mips
+diff --git a/Documentation/arch/nios2/features.rst b/Documentation/arch/nios2/features.rst
+index 8449e63f69b2..89913810ccb5 100644
+--- a/Documentation/arch/nios2/features.rst
++++ b/Documentation/arch/nios2/features.rst
+@@ -1,3 +1,3 @@
+ .. SPDX-License-Identifier: GPL-2.0
+
+-.. kernel-feat:: $srctree/Documentation/features nios2
++.. kernel-feat:: features nios2
+diff --git a/Documentation/arch/openrisc/features.rst b/Documentation/arch/openrisc/features.rst
+index 3f7c40d219f2..bae2e25adfd6 100644
+--- a/Documentation/arch/openrisc/features.rst
++++ b/Documentation/arch/openrisc/features.rst
+@@ -1,3 +1,3 @@
+ .. SPDX-License-Identifier: GPL-2.0
+
+-.. kernel-feat:: $srctree/Documentation/features openrisc
++.. kernel-feat:: features openrisc
+diff --git a/Documentation/arch/parisc/features.rst b/Documentation/arch/parisc/features.rst
+index 501d7c450037..b3aa4d243b93 100644
+--- a/Documentation/arch/parisc/features.rst
++++ b/Documentation/arch/parisc/features.rst
+@@ -1,3 +1,3 @@
+ .. SPDX-License-Identifier: GPL-2.0
+
+-.. kernel-feat:: $srctree/Documentation/features parisc
++.. kernel-feat:: features parisc
+diff --git a/Documentation/arch/s390/features.rst b/Documentation/arch/s390/features.rst
+index 57c296a9d8f3..2883dc950681 100644
+--- a/Documentation/arch/s390/features.rst
++++ b/Documentation/arch/s390/features.rst
+@@ -1,3 +1,3 @@
+ .. SPDX-License-Identifier: GPL-2.0
+
+-.. kernel-feat:: $srctree/Documentation/features s390
++.. kernel-feat:: features s390
+diff --git a/Documentation/arch/sh/features.rst b/Documentation/arch/sh/features.rst
+index f722af3b6c99..fae48fe81e9b 100644
+--- a/Documentation/arch/sh/features.rst
++++ b/Documentation/arch/sh/features.rst
+@@ -1,3 +1,3 @@
+ .. SPDX-License-Identifier: GPL-2.0
+
+-.. kernel-feat:: $srctree/Documentation/features sh
++.. kernel-feat:: features sh
+diff --git a/Documentation/arch/sparc/features.rst b/Documentation/arch/sparc/features.rst
+index c0c92468b0fe..96835b6d598a 100644
+--- a/Documentation/arch/sparc/features.rst
++++ b/Documentation/arch/sparc/features.rst
+@@ -1,3 +1,3 @@
+ .. SPDX-License-Identifier: GPL-2.0
+
+-.. kernel-feat:: $srctree/Documentation/features sparc
++.. kernel-feat:: features sparc
+diff --git a/Documentation/arch/x86/features.rst b/Documentation/arch/x86/features.rst
+index b663f15053ce..a33616346a38 100644
+--- a/Documentation/arch/x86/features.rst
++++ b/Documentation/arch/x86/features.rst
+@@ -1,3 +1,3 @@
+ .. SPDX-License-Identifier: GPL-2.0
+
+-.. kernel-feat:: $srctree/Documentation/features x86
++.. kernel-feat:: features x86
+diff --git a/Documentation/arch/xtensa/features.rst b/Documentation/arch/xtensa/features.rst
+index 6b92c7bfa19d..28dcce1759be 100644
+--- a/Documentation/arch/xtensa/features.rst
++++ b/Documentation/arch/xtensa/features.rst
+@@ -1,3 +1,3 @@
+ .. SPDX-License-Identifier: GPL-2.0
+
+-.. kernel-feat:: $srctree/Documentation/features xtensa
++.. kernel-feat:: features xtensa
+diff --git a/Documentation/powerpc/features.rst b/Documentation/powerpc/features.rst
+index aeae73df86b0..ee4b95e04202 100644
+--- a/Documentation/powerpc/features.rst
++++ b/Documentation/powerpc/features.rst
+@@ -1,3 +1,3 @@
+ .. SPDX-License-Identifier: GPL-2.0
+
+-.. kernel-feat:: $srctree/Documentation/features powerpc
++.. kernel-feat:: features powerpc
+diff --git a/Documentation/riscv/features.rst b/Documentation/riscv/features.rst
+index c70ef6ac2368..36e90144adab 100644
+--- a/Documentation/riscv/features.rst
++++ b/Documentation/riscv/features.rst
+@@ -1,3 +1,3 @@
+ .. SPDX-License-Identifier: GPL-2.0
+
+-.. kernel-feat:: $srctree/Documentation/features riscv
++.. kernel-feat:: features riscv
+diff --git a/Documentation/sphinx/kernel_feat.py b/Documentation/sphinx/kernel_feat.py
+index 27b701ed3681..bdfaa3e4b202 100644
+--- a/Documentation/sphinx/kernel_feat.py
++++ b/Documentation/sphinx/kernel_feat.py
+@@ -37,8 +37,6 @@ import re
+ import subprocess
+ import sys
+
+-from os import path
+-
+ from docutils import nodes, statemachine
+ from docutils.statemachine import ViewList
+ from docutils.parsers.rst import directives, Directive
+@@ -76,33 +74,26 @@ class KernelFeat(Directive):
+ self.state.document.settings.env.app.warn(message, prefix="")
+
+ def run(self):
+-
+ doc = self.state.document
+ if not doc.settings.file_insertion_enabled:
+ raise self.warning("docutils: file insertion disabled")
+
+ env = doc.settings.env
+- cwd = path.dirname(doc.current_source)
+- cmd = "get_feat.pl rest --enable-fname --dir "
+- cmd += self.arguments[0]
+-
+- if len(self.arguments) > 1:
+- cmd += " --arch " + self.arguments[1]
+
+- srctree = path.abspath(os.environ["srctree"])
++ srctree = os.path.abspath(os.environ["srctree"])
+
+- fname = cmd
++ args = [
++ os.path.join(srctree, 'scripts/get_feat.pl'),
++ 'rest',
++ '--enable-fname',
++ '--dir',
++ os.path.join(srctree, 'Documentation', self.arguments[0]),
++ ]
+
+- # extend PATH with $(srctree)/scripts
+- path_env = os.pathsep.join([
+- srctree + os.sep + "scripts",
+- os.environ["PATH"]
+- ])
+- shell_env = os.environ.copy()
+- shell_env["PATH"] = path_env
+- shell_env["srctree"] = srctree
++ if len(self.arguments) > 1:
++ args.extend(['--arch', self.arguments[1]])
+
+- lines = self.runCmd(cmd, shell=True, cwd=cwd, env=shell_env)
++ lines = subprocess.check_output(args, cwd=os.path.dirname(doc.current_source)).decode('utf-8')
+
+ line_regex = re.compile("^\.\. FILE (\S+)$")
+
+@@ -121,30 +112,6 @@ class KernelFeat(Directive):
+ nodeList = self.nestedParse(out_lines, fname)
+ return nodeList
+
+- def runCmd(self, cmd, **kwargs):
+- u"""Run command ``cmd`` and return its stdout as unicode."""
+-
+- try:
+- proc = subprocess.Popen(
+- cmd
+- , stdout = subprocess.PIPE
+- , stderr = subprocess.PIPE
+- , **kwargs
+- )
+- out, err = proc.communicate()
+-
+- out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8')
+-
+- if proc.returncode != 0:
+- raise self.severe(
+- u"command '%s' failed with return code %d"
+- % (cmd, proc.returncode)
+- )
+- except OSError as exc:
+- raise self.severe(u"problems with '%s' directive: %s."
+- % (self.name, ErrorString(exc)))
+- return out
+-
+ def nestedParse(self, lines, fname):
+ content = ViewList()
+ node = nodes.section()
+diff --git a/Documentation/translations/zh_CN/arch/loongarch/features.rst b/Documentation/translations/zh_CN/arch/loongarch/features.rst
+index 82bfac180bdc..cec38dda8298 100644
+--- a/Documentation/translations/zh_CN/arch/loongarch/features.rst
++++ b/Documentation/translations/zh_CN/arch/loongarch/features.rst
+@@ -5,4 +5,4 @@
+ :Original: Documentation/arch/loongarch/features.rst
+ :Translator: Huacai Chen <chenhuacai@loongson.cn>
+
+-.. kernel-feat:: $srctree/Documentation/features loongarch
++.. kernel-feat:: features loongarch
+diff --git a/Documentation/translations/zh_CN/arch/mips/features.rst b/Documentation/translations/zh_CN/arch/mips/features.rst
+index da1b956e4a40..0d6df97db069 100644
+--- a/Documentation/translations/zh_CN/arch/mips/features.rst
++++ b/Documentation/translations/zh_CN/arch/mips/features.rst
+@@ -10,4 +10,4 @@
+
+ .. _cn_features:
+
+-.. kernel-feat:: $srctree/Documentation/features mips
++.. kernel-feat:: features mips
+--
+2.43.0
+
--- /dev/null
+From 0b21551690eba2dfcb2b9ad0a8f52097515ab394 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 2 Sep 2023 13:25:12 +0800
+Subject: docs: sparse: add sparse.rst to toctree
+
+From: Min-Hua Chen <minhuadotchen@gmail.com>
+
+[ Upstream commit c9ad95adc096f25004d4192258863806a68a9bc8 ]
+
+Add sparst.rst to toctree, so it can be part of the docs build.
+
+Cc: Randy Dunlap <rdunlap@infradead.org>
+Cc: Jonathan Corbet <corbet@lwn.net>
+Suggested-by: Jonathan Corbet <corbet@lwn.net>
+Signed-off-by: Min-Hua Chen <minhuadotchen@gmail.com>
+Signed-off-by: Jonathan Corbet <corbet@lwn.net>
+Link: https://lore.kernel.org/r/20230902052512.12184-4-minhuadotchen@gmail.com
+Stable-dep-of: c48a7c44a1d0 ("docs: kernel_feat.py: fix potential command injection")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../translations/zh_TW/dev-tools/index.rst | 40 +++++++++++++++++++
+ Documentation/translations/zh_TW/index.rst | 2 +-
+ 2 files changed, 41 insertions(+), 1 deletion(-)
+ create mode 100644 Documentation/translations/zh_TW/dev-tools/index.rst
+
+diff --git a/Documentation/translations/zh_TW/dev-tools/index.rst b/Documentation/translations/zh_TW/dev-tools/index.rst
+new file mode 100644
+index 000000000000..8f101db5a07f
+--- /dev/null
++++ b/Documentation/translations/zh_TW/dev-tools/index.rst
+@@ -0,0 +1,40 @@
++.. include:: ../disclaimer-zh_TW.rst
++
++:Original: Documentation/dev-tools/index.rst
++:Translator: Min-Hua Chen <minhuadotchen@gmail.com>
++
++============
++內核開發工具
++============
++
++本文檔是有關內核開發工具文檔的合集。
++目前這些文檔已經整理在一起,不需要再花費額外的精力。
++歡迎任何補丁。
++
++有關測試專用工具的簡要概述,參見
++Documentation/dev-tools/testing-overview.rst
++
++.. class:: toc-title
++
++ 目錄
++
++.. toctree::
++ :maxdepth: 2
++
++ sparse
++
++Todolist:
++
++ - coccinelle
++ - kcov
++ - ubsan
++ - kmemleak
++ - kcsan
++ - kfence
++ - kgdb
++ - kselftest
++ - kunit/index
++ - testing-overview
++ - gcov
++ - kasan
++ - gdb-kernel-debugging
+diff --git a/Documentation/translations/zh_TW/index.rst b/Documentation/translations/zh_TW/index.rst
+index d1cf0b4d8e46..ffcaf3272fe7 100644
+--- a/Documentation/translations/zh_TW/index.rst
++++ b/Documentation/translations/zh_TW/index.rst
+@@ -55,11 +55,11 @@ TODOList:
+ :maxdepth: 1
+
+ process/license-rules
++ dev-tools/index
+
+ TODOList:
+
+ * doc-guide/index
+-* dev-tools/index
+ * dev-tools/testing-overview
+ * kernel-hacking/index
+ * rust/index
+--
+2.43.0
+
--- /dev/null
+From 015fb88e61c923ace77301975fbbb1ccb1600574 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 2 Sep 2023 13:25:10 +0800
+Subject: docs: sparse: move TW sparse.txt to TW dev-tools
+
+From: Min-Hua Chen <minhuadotchen@gmail.com>
+
+[ Upstream commit 253f68f413a87a4e2bd93e61b00410e5e1b7b774 ]
+
+Follow Randy's advice [1] to move
+Documentation/translations/zh_TW/sparse.txt
+to
+Documentation/translations/zh_TW/dev-tools/sparse.txt
+
+[1] https://lore.kernel.org/lkml/bfab7c5b-e4d3-d8d9-afab-f43c0cdf26cf@infradead.org/
+
+Cc: Randy Dunlap <rdunlap@infradead.org>
+Suggested-by: Randy Dunlap <rdunlap@infradead.org>
+Reviewed-by: Randy Dunlap <rdunlap@infradead.org>
+Signed-off-by: Min-Hua Chen <minhuadotchen@gmail.com>
+Signed-off-by: Jonathan Corbet <corbet@lwn.net>
+Link: https://lore.kernel.org/r/20230902052512.12184-2-minhuadotchen@gmail.com
+Stable-dep-of: c48a7c44a1d0 ("docs: kernel_feat.py: fix potential command injection")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ Documentation/translations/zh_TW/{ => dev-tools}/sparse.txt | 0
+ 1 file changed, 0 insertions(+), 0 deletions(-)
+ rename Documentation/translations/zh_TW/{ => dev-tools}/sparse.txt (100%)
+
+diff --git a/Documentation/translations/zh_TW/sparse.txt b/Documentation/translations/zh_TW/dev-tools/sparse.txt
+similarity index 100%
+rename from Documentation/translations/zh_TW/sparse.txt
+rename to Documentation/translations/zh_TW/dev-tools/sparse.txt
+--
+2.43.0
+
--- /dev/null
+From 31d9518eba1dcf440452f27f9b15fd44ccc47e54 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 19 Dec 2023 17:26:01 -0300
+Subject: iio: adc: ad7091r: Allow users to configure device events
+
+From: Marcelo Schmitt <marcelo.schmitt@analog.com>
+
+[ Upstream commit 020e71c7ffc25dfe29ed9be6c2d39af7bd7f661f ]
+
+AD7091R-5 devices are supported by the ad7091r-5 driver together with
+the ad7091r-base driver. Those drivers declared iio events for notifying
+user space when ADC readings fall bellow the thresholds of low limit
+registers or above the values set in high limit registers.
+However, to configure iio events and their thresholds, a set of callback
+functions must be implemented and those were not present until now.
+The consequence of trying to configure ad7091r-5 events without the
+proper callback functions was a null pointer dereference in the kernel
+because the pointers to the callback functions were not set.
+
+Implement event configuration callbacks allowing users to read/write
+event thresholds and enable/disable event generation.
+
+Since the event spec structs are generic to AD7091R devices, also move
+those from the ad7091r-5 driver the base driver so they can be reused
+when support for ad7091r-2/-4/-8 be added.
+
+Fixes: ca69300173b6 ("iio: adc: Add support for AD7091R5 ADC")
+Suggested-by: David Lechner <dlechner@baylibre.com>
+Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
+Link: https://lore.kernel.org/r/59552d3548dabd56adc3107b7b4869afee2b0c3c.1703013352.git.marcelo.schmitt1@gmail.com
+Cc: <Stable@vger.kernel.org>
+Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iio/adc/ad7091r-base.c | 156 +++++++++++++++++++++++++++++++++
+ drivers/iio/adc/ad7091r-base.h | 6 ++
+ drivers/iio/adc/ad7091r5.c | 28 +-----
+ 3 files changed, 166 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/iio/adc/ad7091r-base.c b/drivers/iio/adc/ad7091r-base.c
+index 8aaa854f816f..3d36bcd26b0c 100644
+--- a/drivers/iio/adc/ad7091r-base.c
++++ b/drivers/iio/adc/ad7091r-base.c
+@@ -6,6 +6,7 @@
+ */
+
+ #include <linux/bitops.h>
++#include <linux/bitfield.h>
+ #include <linux/iio/events.h>
+ #include <linux/iio/iio.h>
+ #include <linux/interrupt.h>
+@@ -50,6 +51,27 @@ struct ad7091r_state {
+ struct mutex lock; /*lock to prevent concurent reads */
+ };
+
++const struct iio_event_spec ad7091r_events[] = {
++ {
++ .type = IIO_EV_TYPE_THRESH,
++ .dir = IIO_EV_DIR_RISING,
++ .mask_separate = BIT(IIO_EV_INFO_VALUE) |
++ BIT(IIO_EV_INFO_ENABLE),
++ },
++ {
++ .type = IIO_EV_TYPE_THRESH,
++ .dir = IIO_EV_DIR_FALLING,
++ .mask_separate = BIT(IIO_EV_INFO_VALUE) |
++ BIT(IIO_EV_INFO_ENABLE),
++ },
++ {
++ .type = IIO_EV_TYPE_THRESH,
++ .dir = IIO_EV_DIR_EITHER,
++ .mask_separate = BIT(IIO_EV_INFO_HYSTERESIS),
++ },
++};
++EXPORT_SYMBOL_NS_GPL(ad7091r_events, IIO_AD7091R);
++
+ static int ad7091r_set_mode(struct ad7091r_state *st, enum ad7091r_mode mode)
+ {
+ int ret, conf;
+@@ -169,8 +191,142 @@ static int ad7091r_read_raw(struct iio_dev *iio_dev,
+ return ret;
+ }
+
++static int ad7091r_read_event_config(struct iio_dev *indio_dev,
++ const struct iio_chan_spec *chan,
++ enum iio_event_type type,
++ enum iio_event_direction dir)
++{
++ struct ad7091r_state *st = iio_priv(indio_dev);
++ int val, ret;
++
++ switch (dir) {
++ case IIO_EV_DIR_RISING:
++ ret = regmap_read(st->map,
++ AD7091R_REG_CH_HIGH_LIMIT(chan->channel),
++ &val);
++ if (ret)
++ return ret;
++ return val != AD7091R_HIGH_LIMIT;
++ case IIO_EV_DIR_FALLING:
++ ret = regmap_read(st->map,
++ AD7091R_REG_CH_LOW_LIMIT(chan->channel),
++ &val);
++ if (ret)
++ return ret;
++ return val != AD7091R_LOW_LIMIT;
++ default:
++ return -EINVAL;
++ }
++}
++
++static int ad7091r_write_event_config(struct iio_dev *indio_dev,
++ const struct iio_chan_spec *chan,
++ enum iio_event_type type,
++ enum iio_event_direction dir, int state)
++{
++ struct ad7091r_state *st = iio_priv(indio_dev);
++
++ if (state) {
++ return regmap_set_bits(st->map, AD7091R_REG_CONF,
++ AD7091R_REG_CONF_ALERT_EN);
++ } else {
++ /*
++ * Set thresholds either to 0 or to 2^12 - 1 as appropriate to
++ * prevent alerts and thus disable event generation.
++ */
++ switch (dir) {
++ case IIO_EV_DIR_RISING:
++ return regmap_write(st->map,
++ AD7091R_REG_CH_HIGH_LIMIT(chan->channel),
++ AD7091R_HIGH_LIMIT);
++ case IIO_EV_DIR_FALLING:
++ return regmap_write(st->map,
++ AD7091R_REG_CH_LOW_LIMIT(chan->channel),
++ AD7091R_LOW_LIMIT);
++ default:
++ return -EINVAL;
++ }
++ }
++}
++
++static int ad7091r_read_event_value(struct iio_dev *indio_dev,
++ const struct iio_chan_spec *chan,
++ enum iio_event_type type,
++ enum iio_event_direction dir,
++ enum iio_event_info info, int *val, int *val2)
++{
++ struct ad7091r_state *st = iio_priv(indio_dev);
++ int ret;
++
++ switch (info) {
++ case IIO_EV_INFO_VALUE:
++ switch (dir) {
++ case IIO_EV_DIR_RISING:
++ ret = regmap_read(st->map,
++ AD7091R_REG_CH_HIGH_LIMIT(chan->channel),
++ val);
++ if (ret)
++ return ret;
++ return IIO_VAL_INT;
++ case IIO_EV_DIR_FALLING:
++ ret = regmap_read(st->map,
++ AD7091R_REG_CH_LOW_LIMIT(chan->channel),
++ val);
++ if (ret)
++ return ret;
++ return IIO_VAL_INT;
++ default:
++ return -EINVAL;
++ }
++ case IIO_EV_INFO_HYSTERESIS:
++ ret = regmap_read(st->map,
++ AD7091R_REG_CH_HYSTERESIS(chan->channel),
++ val);
++ if (ret)
++ return ret;
++ return IIO_VAL_INT;
++ default:
++ return -EINVAL;
++ }
++}
++
++static int ad7091r_write_event_value(struct iio_dev *indio_dev,
++ const struct iio_chan_spec *chan,
++ enum iio_event_type type,
++ enum iio_event_direction dir,
++ enum iio_event_info info, int val, int val2)
++{
++ struct ad7091r_state *st = iio_priv(indio_dev);
++
++ switch (info) {
++ case IIO_EV_INFO_VALUE:
++ switch (dir) {
++ case IIO_EV_DIR_RISING:
++ return regmap_write(st->map,
++ AD7091R_REG_CH_HIGH_LIMIT(chan->channel),
++ val);
++ case IIO_EV_DIR_FALLING:
++ return regmap_write(st->map,
++ AD7091R_REG_CH_LOW_LIMIT(chan->channel),
++ val);
++ default:
++ return -EINVAL;
++ }
++ case IIO_EV_INFO_HYSTERESIS:
++ return regmap_write(st->map,
++ AD7091R_REG_CH_HYSTERESIS(chan->channel),
++ val);
++ default:
++ return -EINVAL;
++ }
++}
++
+ static const struct iio_info ad7091r_info = {
+ .read_raw = ad7091r_read_raw,
++ .read_event_config = &ad7091r_read_event_config,
++ .write_event_config = &ad7091r_write_event_config,
++ .read_event_value = &ad7091r_read_event_value,
++ .write_event_value = &ad7091r_write_event_value,
+ };
+
+ static irqreturn_t ad7091r_event_handler(int irq, void *private)
+diff --git a/drivers/iio/adc/ad7091r-base.h b/drivers/iio/adc/ad7091r-base.h
+index 509748aef9b1..7a78976a2f80 100644
+--- a/drivers/iio/adc/ad7091r-base.h
++++ b/drivers/iio/adc/ad7091r-base.h
+@@ -8,6 +8,10 @@
+ #ifndef __DRIVERS_IIO_ADC_AD7091R_BASE_H__
+ #define __DRIVERS_IIO_ADC_AD7091R_BASE_H__
+
++/* AD7091R_REG_CH_LIMIT */
++#define AD7091R_HIGH_LIMIT 0xFFF
++#define AD7091R_LOW_LIMIT 0x0
++
+ struct device;
+ struct ad7091r_state;
+
+@@ -17,6 +21,8 @@ struct ad7091r_chip_info {
+ unsigned int vref_mV;
+ };
+
++extern const struct iio_event_spec ad7091r_events[3];
++
+ extern const struct regmap_config ad7091r_regmap_config;
+
+ int ad7091r_probe(struct device *dev, const char *name,
+diff --git a/drivers/iio/adc/ad7091r5.c b/drivers/iio/adc/ad7091r5.c
+index 2f048527b7b7..dae98c95ebb8 100644
+--- a/drivers/iio/adc/ad7091r5.c
++++ b/drivers/iio/adc/ad7091r5.c
+@@ -12,26 +12,6 @@
+
+ #include "ad7091r-base.h"
+
+-static const struct iio_event_spec ad7091r5_events[] = {
+- {
+- .type = IIO_EV_TYPE_THRESH,
+- .dir = IIO_EV_DIR_RISING,
+- .mask_separate = BIT(IIO_EV_INFO_VALUE) |
+- BIT(IIO_EV_INFO_ENABLE),
+- },
+- {
+- .type = IIO_EV_TYPE_THRESH,
+- .dir = IIO_EV_DIR_FALLING,
+- .mask_separate = BIT(IIO_EV_INFO_VALUE) |
+- BIT(IIO_EV_INFO_ENABLE),
+- },
+- {
+- .type = IIO_EV_TYPE_THRESH,
+- .dir = IIO_EV_DIR_EITHER,
+- .mask_separate = BIT(IIO_EV_INFO_HYSTERESIS),
+- },
+-};
+-
+ #define AD7091R_CHANNEL(idx, bits, ev, num_ev) { \
+ .type = IIO_VOLTAGE, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+@@ -44,10 +24,10 @@ static const struct iio_event_spec ad7091r5_events[] = {
+ .scan_type.realbits = bits, \
+ }
+ static const struct iio_chan_spec ad7091r5_channels_irq[] = {
+- AD7091R_CHANNEL(0, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)),
+- AD7091R_CHANNEL(1, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)),
+- AD7091R_CHANNEL(2, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)),
+- AD7091R_CHANNEL(3, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)),
++ AD7091R_CHANNEL(0, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
++ AD7091R_CHANNEL(1, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
++ AD7091R_CHANNEL(2, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
++ AD7091R_CHANNEL(3, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
+ };
+
+ static const struct iio_chan_spec ad7091r5_channels_noirq[] = {
+--
+2.43.0
+
--- /dev/null
+From 2d6478fb8be7e9bcb11f74ee89e8a787c1017b2f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 19 Dec 2023 17:26:27 -0300
+Subject: iio: adc: ad7091r: Enable internal vref if external vref is not
+ supplied
+
+From: Marcelo Schmitt <marcelo.schmitt@analog.com>
+
+[ Upstream commit e71c5c89bcb165a02df35325aa13d1ee40112401 ]
+
+The ADC needs a voltage reference to work correctly.
+Users can provide an external voltage reference or use the chip internal
+reference to operate the ADC.
+The availability of an in chip reference for the ADC saves the user from
+having to supply an external voltage reference, which makes the external
+reference an optional property as described in the device tree
+documentation.
+Though, to use the internal reference, it must be enabled by writing to
+the configuration register.
+Enable AD7091R internal voltage reference if no external vref is supplied.
+
+Fixes: 260442cc5be4 ("iio: adc: ad7091r5: Add scale and external VREF support")
+Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
+Link: https://lore.kernel.org/r/b865033fa6a4fc4bf2b4a98ec51a6144e0f64f77.1703013352.git.marcelo.schmitt1@gmail.com
+Cc: <Stable@vger.kernel.org>
+Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iio/adc/ad7091r-base.c | 7 +++++++
+ drivers/iio/adc/ad7091r-base.h | 2 ++
+ 2 files changed, 9 insertions(+)
+
+diff --git a/drivers/iio/adc/ad7091r-base.c b/drivers/iio/adc/ad7091r-base.c
+index 3d36bcd26b0c..76002b91c86a 100644
+--- a/drivers/iio/adc/ad7091r-base.c
++++ b/drivers/iio/adc/ad7091r-base.c
+@@ -405,7 +405,14 @@ int ad7091r_probe(struct device *dev, const char *name,
+ if (IS_ERR(st->vref)) {
+ if (PTR_ERR(st->vref) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
++
+ st->vref = NULL;
++ /* Enable internal vref */
++ ret = regmap_set_bits(st->map, AD7091R_REG_CONF,
++ AD7091R_REG_CONF_INT_VREF);
++ if (ret)
++ return dev_err_probe(st->dev, ret,
++ "Error on enable internal reference\n");
+ } else {
+ ret = regulator_enable(st->vref);
+ if (ret)
+diff --git a/drivers/iio/adc/ad7091r-base.h b/drivers/iio/adc/ad7091r-base.h
+index 7a78976a2f80..b9e1c8bf3440 100644
+--- a/drivers/iio/adc/ad7091r-base.h
++++ b/drivers/iio/adc/ad7091r-base.h
+@@ -8,6 +8,8 @@
+ #ifndef __DRIVERS_IIO_ADC_AD7091R_BASE_H__
+ #define __DRIVERS_IIO_ADC_AD7091R_BASE_H__
+
++#define AD7091R_REG_CONF_INT_VREF BIT(0)
++
+ /* AD7091R_REG_CH_LIMIT */
+ #define AD7091R_HIGH_LIMIT 0xFFF
+ #define AD7091R_LOW_LIMIT 0x0
+--
+2.43.0
+
--- /dev/null
+From b10c2fb17af63766edf41f5062096ba00c4ee4e5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 16 Dec 2023 14:46:37 -0300
+Subject: iio: adc: ad7091r: Set alert bit in config register
+
+From: Marcelo Schmitt <marcelo.schmitt@analog.com>
+
+[ Upstream commit 149694f5e79b0c7a36ceb76e7c0d590db8f151c1 ]
+
+The ad7091r-base driver sets up an interrupt handler for firing events
+when inputs are either above or below a certain threshold.
+However, for the interrupt signal to come from the device it must be
+configured to enable the ALERT/BUSY/GPO pin to be used as ALERT, which
+was not being done until now.
+Enable interrupt signals on the ALERT/BUSY/GPO pin by setting the proper
+bit in the configuration register.
+
+Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
+Link: https://lore.kernel.org/r/e8da2ee98d6df88318b14baf3dc9630e20218418.1702746240.git.marcelo.schmitt1@gmail.com
+Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+Stable-dep-of: 020e71c7ffc2 ("iio: adc: ad7091r: Allow users to configure device events")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iio/adc/ad7091r-base.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/drivers/iio/adc/ad7091r-base.c b/drivers/iio/adc/ad7091r-base.c
+index 0e5d3d2e9c98..8aaa854f816f 100644
+--- a/drivers/iio/adc/ad7091r-base.c
++++ b/drivers/iio/adc/ad7091r-base.c
+@@ -28,6 +28,7 @@
+ #define AD7091R_REG_RESULT_CONV_RESULT(x) ((x) & 0xfff)
+
+ /* AD7091R_REG_CONF */
++#define AD7091R_REG_CONF_ALERT_EN BIT(4)
+ #define AD7091R_REG_CONF_AUTO BIT(8)
+ #define AD7091R_REG_CONF_CMD BIT(10)
+
+@@ -232,6 +233,11 @@ int ad7091r_probe(struct device *dev, const char *name,
+ iio_dev->channels = chip_info->channels;
+
+ if (irq) {
++ ret = regmap_update_bits(st->map, AD7091R_REG_CONF,
++ AD7091R_REG_CONF_ALERT_EN, BIT(4));
++ if (ret)
++ return ret;
++
+ ret = devm_request_threaded_irq(dev, irq, NULL,
+ ad7091r_event_handler,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT, name, iio_dev);
+--
+2.43.0
+
--- /dev/null
+From e4910f6cbaeeb5ede337cab4669d21300960d1bf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 16 Jan 2024 13:19:17 +0100
+Subject: net: stmmac: Prevent DSA tags from breaking COE
+
+From: Romain Gantois <romain.gantois@bootlin.com>
+
+[ Upstream commit c2945c435c999c63e47f337bc7c13c98c21d0bcc ]
+
+Some DSA tagging protocols change the EtherType field in the MAC header
+e.g. DSA_TAG_PROTO_(DSA/EDSA/BRCM/MTK/RTL4C_A/SJA1105). On TX these tagged
+frames are ignored by the checksum offload engine and IP header checker of
+some stmmac cores.
+
+On RX, the stmmac driver wrongly assumes that checksums have been computed
+for these tagged packets, and sets CHECKSUM_UNNECESSARY.
+
+Add an additional check in the stmmac TX and RX hotpaths so that COE is
+deactivated for packets with ethertypes that will not trigger the COE and
+IP header checks.
+
+Fixes: 6b2c6e4a938f ("net: stmmac: propagate feature flags to vlan")
+Cc: <stable@vger.kernel.org>
+Reported-by: Richard Tresidder <rtresidd@electromag.com.au>
+Link: https://lore.kernel.org/netdev/e5c6c75f-2dfa-4e50-a1fb-6bf4cdb617c2@electromag.com.au/
+Reported-by: Romain Gantois <romain.gantois@bootlin.com>
+Link: https://lore.kernel.org/netdev/c57283ed-6b9b-b0e6-ee12-5655c1c54495@bootlin.com/
+Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Romain Gantois <romain.gantois@bootlin.com>
+Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/ethernet/stmicro/stmmac/stmmac_main.c | 32 +++++++++++++++++--
+ 1 file changed, 29 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+index 59e07efe08c9..684ec7058c82 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -4356,6 +4356,28 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
+ return NETDEV_TX_OK;
+ }
+
++/**
++ * stmmac_has_ip_ethertype() - Check if packet has IP ethertype
++ * @skb: socket buffer to check
++ *
++ * Check if a packet has an ethertype that will trigger the IP header checks
++ * and IP/TCP checksum engine of the stmmac core.
++ *
++ * Return: true if the ethertype can trigger the checksum engine, false
++ * otherwise
++ */
++static bool stmmac_has_ip_ethertype(struct sk_buff *skb)
++{
++ int depth = 0;
++ __be16 proto;
++
++ proto = __vlan_get_protocol(skb, eth_header_parse_protocol(skb),
++ &depth);
++
++ return (depth <= ETH_HLEN) &&
++ (proto == htons(ETH_P_IP) || proto == htons(ETH_P_IPV6));
++}
++
+ /**
+ * stmmac_xmit - Tx entry point of the driver
+ * @skb : the socket buffer
+@@ -4420,9 +4442,13 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
+ /* DWMAC IPs can be synthesized to support tx coe only for a few tx
+ * queues. In that case, checksum offloading for those queues that don't
+ * support tx coe needs to fallback to software checksum calculation.
++ *
++ * Packets that won't trigger the COE e.g. most DSA-tagged packets will
++ * also have to be checksummed in software.
+ */
+ if (csum_insertion &&
+- priv->plat->tx_queues_cfg[queue].coe_unsupported) {
++ (priv->plat->tx_queues_cfg[queue].coe_unsupported ||
++ !stmmac_has_ip_ethertype(skb))) {
+ if (unlikely(skb_checksum_help(skb)))
+ goto dma_map_err;
+ csum_insertion = !csum_insertion;
+@@ -4982,7 +5008,7 @@ static void stmmac_dispatch_skb_zc(struct stmmac_priv *priv, u32 queue,
+ stmmac_rx_vlan(priv->dev, skb);
+ skb->protocol = eth_type_trans(skb, priv->dev);
+
+- if (unlikely(!coe))
++ if (unlikely(!coe) || !stmmac_has_ip_ethertype(skb))
+ skb_checksum_none_assert(skb);
+ else
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+@@ -5498,7 +5524,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
+ stmmac_rx_vlan(priv->dev, skb);
+ skb->protocol = eth_type_trans(skb, priv->dev);
+
+- if (unlikely(!coe))
++ if (unlikely(!coe) || !stmmac_has_ip_ethertype(skb))
+ skb_checksum_none_assert(skb);
+ else
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+--
+2.43.0
+
--- /dev/null
+From 071be3267bf1cf00cff09a9e6758055b060f2a7b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 16 Sep 2023 14:33:12 +0800
+Subject: net: stmmac: Tx coe sw fallback
+
+From: Rohan G Thomas <rohan.g.thomas@intel.com>
+
+[ Upstream commit 8452a05b2c633b708dbe3e742f71b24bf21fe42d ]
+
+Add sw fallback of tx checksum calculation for those tx queues that
+don't support tx checksum offloading. DW xGMAC IP can be synthesized
+such that it can support tx checksum offloading only for a few
+initial tx queues. Also as Serge pointed out, for the DW QoS IP, tx
+coe can be individually configured for each tx queue.
+
+So when tx coe is enabled, for any tx queue that doesn't support
+tx coe with 'coe-unsupported' flag set will have a sw fallback
+happen in the driver for tx checksum calculation when any packets to
+be transmitted on these tx queues.
+
+Signed-off-by: Rohan G Thomas <rohan.g.thomas@intel.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: c2945c435c99 ("net: stmmac: Prevent DSA tags from breaking COE")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 10 ++++++++++
+ drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 3 +++
+ include/linux/stmmac.h | 1 +
+ 3 files changed, 14 insertions(+)
+
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+index 1bfcf673b3ce..59e07efe08c9 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -4417,6 +4417,16 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
+ WARN_ON(tx_q->tx_skbuff[first_entry]);
+
+ csum_insertion = (skb->ip_summed == CHECKSUM_PARTIAL);
++ /* DWMAC IPs can be synthesized to support tx coe only for a few tx
++ * queues. In that case, checksum offloading for those queues that don't
++ * support tx coe needs to fallback to software checksum calculation.
++ */
++ if (csum_insertion &&
++ priv->plat->tx_queues_cfg[queue].coe_unsupported) {
++ if (unlikely(skb_checksum_help(skb)))
++ goto dma_map_err;
++ csum_insertion = !csum_insertion;
++ }
+
+ if (likely(priv->extend_desc))
+ desc = (struct dma_desc *)(tx_q->dma_etx + entry);
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+index 2f0678f15fb7..30d5e635190e 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+@@ -276,6 +276,9 @@ static int stmmac_mtl_setup(struct platform_device *pdev,
+ plat->tx_queues_cfg[queue].use_prio = true;
+ }
+
++ plat->tx_queues_cfg[queue].coe_unsupported =
++ of_property_read_bool(q_node, "snps,coe-unsupported");
++
+ queue++;
+ }
+ if (queue != plat->tx_queues_to_use) {
+diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
+index e3f7ee169c08..5acb77968902 100644
+--- a/include/linux/stmmac.h
++++ b/include/linux/stmmac.h
+@@ -139,6 +139,7 @@ struct stmmac_rxq_cfg {
+
+ struct stmmac_txq_cfg {
+ u32 weight;
++ bool coe_unsupported;
+ u8 mode_to_use;
+ /* Credit Base Shaper parameters */
+ u32 send_slope;
+--
+2.43.0
+
--- /dev/null
+From 8ac376c7b23cd48dc254ca7f1710bfb1727c4d53 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 6 Dec 2023 16:37:37 +0000
+Subject: Revert "cifs: reconnect work should have reference on server struct"
+
+From: Shyam Prasad N <sprasad@microsoft.com>
+
+[ Upstream commit 823342524868168bf681f135d01b4ae10f5863ec ]
+
+This reverts commit 19a4b9d6c372cab6a3b2c9a061a236136fe95274.
+
+This earlier commit was making an assumption that each mod_delayed_work
+called for the reconnect work would result in smb2_reconnect_server
+being called twice. This assumption turns out to be untrue. So reverting
+this change for now.
+
+I will submit a follow-up patch to fix the actual problem in a different
+way.
+
+Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Stable-dep-of: 78e727e58e54 ("cifs: update iface_last_update on each query-and-update")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/connect.c | 27 ++++++---------------------
+ fs/smb/client/smb2pdu.c | 23 ++++++++++-------------
+ 2 files changed, 16 insertions(+), 34 deletions(-)
+
+diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
+index f43f51f2d1c1..2a30245287d5 100644
+--- a/fs/smb/client/connect.c
++++ b/fs/smb/client/connect.c
+@@ -401,13 +401,7 @@ static int __cifs_reconnect(struct TCP_Server_Info *server,
+ spin_unlock(&server->srv_lock);
+ cifs_swn_reset_server_dstaddr(server);
+ cifs_server_unlock(server);
+-
+- /* increase ref count which reconnect work will drop */
+- spin_lock(&cifs_tcp_ses_lock);
+- server->srv_count++;
+- spin_unlock(&cifs_tcp_ses_lock);
+- if (mod_delayed_work(cifsiod_wq, &server->reconnect, 0))
+- cifs_put_tcp_session(server, false);
++ mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
+ }
+ } while (server->tcpStatus == CifsNeedReconnect);
+
+@@ -537,13 +531,7 @@ static int reconnect_dfs_server(struct TCP_Server_Info *server)
+ spin_unlock(&server->srv_lock);
+ cifs_swn_reset_server_dstaddr(server);
+ cifs_server_unlock(server);
+-
+- /* increase ref count which reconnect work will drop */
+- spin_lock(&cifs_tcp_ses_lock);
+- server->srv_count++;
+- spin_unlock(&cifs_tcp_ses_lock);
+- if (mod_delayed_work(cifsiod_wq, &server->reconnect, 0))
+- cifs_put_tcp_session(server, false);
++ mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
+ } while (server->tcpStatus == CifsNeedReconnect);
+
+ mutex_lock(&server->refpath_lock);
+@@ -1630,19 +1618,16 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
+
+ cancel_delayed_work_sync(&server->echo);
+
+- if (from_reconnect) {
++ if (from_reconnect)
+ /*
+ * Avoid deadlock here: reconnect work calls
+ * cifs_put_tcp_session() at its end. Need to be sure
+ * that reconnect work does nothing with server pointer after
+ * that step.
+ */
+- if (cancel_delayed_work(&server->reconnect))
+- cifs_put_tcp_session(server, from_reconnect);
+- } else {
+- if (cancel_delayed_work_sync(&server->reconnect))
+- cifs_put_tcp_session(server, from_reconnect);
+- }
++ cancel_delayed_work(&server->reconnect);
++ else
++ cancel_delayed_work_sync(&server->reconnect);
+
+ spin_lock(&server->srv_lock);
+ server->tcpStatus = CifsExiting;
+diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
+index f1977987ae74..da752f41a4e6 100644
+--- a/fs/smb/client/smb2pdu.c
++++ b/fs/smb/client/smb2pdu.c
+@@ -3981,6 +3981,12 @@ void smb2_reconnect_server(struct work_struct *work)
+ }
+ spin_unlock(&ses->chan_lock);
+ }
++ /*
++ * Get the reference to server struct to be sure that the last call of
++ * cifs_put_tcon() in the loop below won't release the server pointer.
++ */
++ if (tcon_exist || ses_exist)
++ server->srv_count++;
+
+ spin_unlock(&cifs_tcp_ses_lock);
+
+@@ -4028,17 +4034,13 @@ void smb2_reconnect_server(struct work_struct *work)
+
+ done:
+ cifs_dbg(FYI, "Reconnecting tcons and channels finished\n");
+- if (resched) {
++ if (resched)
+ queue_delayed_work(cifsiod_wq, &server->reconnect, 2 * HZ);
+- mutex_unlock(&pserver->reconnect_mutex);
+-
+- /* no need to put tcp session as we're retrying */
+- return;
+- }
+ mutex_unlock(&pserver->reconnect_mutex);
+
+ /* now we can safely release srv struct */
+- cifs_put_tcp_session(server, true);
++ if (tcon_exist || ses_exist)
++ cifs_put_tcp_session(server, 1);
+ }
+
+ int
+@@ -4058,12 +4060,7 @@ SMB2_echo(struct TCP_Server_Info *server)
+ server->ops->need_neg(server)) {
+ spin_unlock(&server->srv_lock);
+ /* No need to send echo on newly established connections */
+- spin_lock(&cifs_tcp_ses_lock);
+- server->srv_count++;
+- spin_unlock(&cifs_tcp_ses_lock);
+- if (mod_delayed_work(cifsiod_wq, &server->reconnect, 0))
+- cifs_put_tcp_session(server, false);
+-
++ mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
+ return rc;
+ }
+ spin_unlock(&server->srv_lock);
+--
+2.43.0
+
--- /dev/null
+From ff07fb1a8fdd65fa498878c0f0163bab7f24c572 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 29 Oct 2023 08:20:40 +0100
+Subject: riscv: Fix an off-by-one in get_early_cmdline()
+
+From: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+
+[ Upstream commit adb1f95d388a43c4c564ef3e436f18900dde978e ]
+
+The ending NULL is not taken into account by strncat(), so switch to
+strlcat() to correctly compute the size of the available memory when
+appending CONFIG_CMDLINE to 'early_cmdline'.
+
+Fixes: 26e7aacb83df ("riscv: Allow to downgrade paging mode from the command line")
+Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+Reviewed-by: Alexandre Ghiti <alexghiti@rivosinc.com>
+Link: https://lore.kernel.org/r/9f66d2b58c8052d4055e90b8477ee55d9a0914f9.1698564026.git.christophe.jaillet@wanadoo.fr
+Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/riscv/kernel/pi/cmdline_early.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/arch/riscv/kernel/pi/cmdline_early.c b/arch/riscv/kernel/pi/cmdline_early.c
+index 68e786c84c94..f6d4dedffb84 100644
+--- a/arch/riscv/kernel/pi/cmdline_early.c
++++ b/arch/riscv/kernel/pi/cmdline_early.c
+@@ -38,8 +38,7 @@ static char *get_early_cmdline(uintptr_t dtb_pa)
+ if (IS_ENABLED(CONFIG_CMDLINE_EXTEND) ||
+ IS_ENABLED(CONFIG_CMDLINE_FORCE) ||
+ fdt_cmdline_size == 0 /* CONFIG_CMDLINE_FALLBACK */) {
+- strncat(early_cmdline, CONFIG_CMDLINE,
+- COMMAND_LINE_SIZE - fdt_cmdline_size);
++ strlcat(early_cmdline, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
+ }
+
+ return early_cmdline;
+--
+2.43.0
+
--- /dev/null
+From e31ef064e85fc95060c2fc7ffb201d5213ccf52b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 11 Jan 2024 13:05:32 +0100
+Subject: scsi: core: Kick the requeue list after inserting when flushing
+
+From: Niklas Cassel <cassel@kernel.org>
+
+[ Upstream commit 6df0e077d76bd144c533b61d6182676aae6b0a85 ]
+
+When libata calls ata_link_abort() to abort all ata queued commands, it
+calls blk_abort_request() on the SCSI command representing each QC.
+
+This causes scsi_timeout() to be called, which calls scsi_eh_scmd_add() for
+each SCSI command.
+
+scsi_eh_scmd_add() sets the SCSI host to state recovery, and then adds the
+command to shost->eh_cmd_q.
+
+This will wake up the SCSI EH, and eventually the libata EH strategy
+handler will be called, which calls scsi_eh_flush_done_q() to either flush
+retry or flush finish each failed command.
+
+The commands that are flush retried by scsi_eh_flush_done_q() are done so
+using scsi_queue_insert().
+
+Before commit 8b566edbdbfb ("scsi: core: Only kick the requeue list if
+necessary"), __scsi_queue_insert() called blk_mq_requeue_request() with the
+second argument set to true, indicating that it should always kick/run the
+requeue list after inserting.
+
+After commit 8b566edbdbfb ("scsi: core: Only kick the requeue list if
+necessary"), __scsi_queue_insert() does not kick/run the requeue list after
+inserting, if the current SCSI host state is recovery (which is the case in
+the libata example above).
+
+This optimization is probably fine in most cases, as I can only assume that
+most often someone will eventually kick/run the queues.
+
+However, that is not the case for scsi_eh_flush_done_q(), where we can see
+that the request gets inserted to the requeue list, but the queue is never
+started after the request has been inserted, leading to the block layer
+waiting for the completion of command that never gets to run.
+
+Since scsi_eh_flush_done_q() is called by SCSI EH context, the SCSI host
+state is most likely always in recovery when this function is called.
+
+Thus, let scsi_eh_flush_done_q() explicitly kick the requeue list after
+inserting a flush retry command, so that scsi_eh_flush_done_q() keeps the
+same behavior as before commit 8b566edbdbfb ("scsi: core: Only kick the
+requeue list if necessary").
+
+Simple reproducer for the libata example above:
+$ hdparm -Y /dev/sda
+$ echo 1 > /sys/class/scsi_device/0\:0\:0\:0/device/delete
+
+Fixes: 8b566edbdbfb ("scsi: core: Only kick the requeue list if necessary")
+Reported-by: Kevin Locke <kevin@kevinlocke.name>
+Closes: https://lore.kernel.org/linux-scsi/ZZw3Th70wUUvCiCY@kevinlocke.name/
+Signed-off-by: Niklas Cassel <cassel@kernel.org>
+Link: https://lore.kernel.org/r/20240111120533.3612509-1-cassel@kernel.org
+Reviewed-by: Bart Van Assche <bvanassche@acm.org>
+Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/scsi_error.c | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
+index 1223d34c04da..d983f4a0e9f1 100644
+--- a/drivers/scsi/scsi_error.c
++++ b/drivers/scsi/scsi_error.c
+@@ -2196,15 +2196,18 @@ void scsi_eh_flush_done_q(struct list_head *done_q)
+ struct scsi_cmnd *scmd, *next;
+
+ list_for_each_entry_safe(scmd, next, done_q, eh_entry) {
++ struct scsi_device *sdev = scmd->device;
++
+ list_del_init(&scmd->eh_entry);
+- if (scsi_device_online(scmd->device) &&
+- !scsi_noretry_cmd(scmd) && scsi_cmd_retry_allowed(scmd) &&
+- scsi_eh_should_retry_cmd(scmd)) {
++ if (scsi_device_online(sdev) && !scsi_noretry_cmd(scmd) &&
++ scsi_cmd_retry_allowed(scmd) &&
++ scsi_eh_should_retry_cmd(scmd)) {
+ SCSI_LOG_ERROR_RECOVERY(3,
+ scmd_printk(KERN_INFO, scmd,
+ "%s: flush retry cmd\n",
+ current->comm));
+ scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY);
++ blk_mq_kick_requeue_list(sdev->request_queue);
+ } else {
+ /*
+ * If just we got sense for the device (called
+--
+2.43.0
+
--- /dev/null
+From 5ab54fef88b1be59326a4f6cfb46794a0764fcc9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 18 Dec 2023 14:52:15 -0800
+Subject: scsi: ufs: core: Remove the ufshcd_hba_exit() call from
+ ufshcd_async_scan()
+
+From: Bart Van Assche <bvanassche@acm.org>
+
+[ Upstream commit ee36710912b2075c417100a8acc642c9c6496501 ]
+
+Calling ufshcd_hba_exit() from a function that is called asynchronously
+from ufshcd_init() is wrong because this triggers multiple race
+conditions. Instead of calling ufshcd_hba_exit(), log an error message.
+
+Reported-by: Daniel Mentz <danielmentz@google.com>
+Fixes: 1d337ec2f35e ("ufs: improve init sequence")
+Signed-off-by: Bart Van Assche <bvanassche@acm.org>
+Link: https://lore.kernel.org/r/20231218225229.2542156-3-bvanassche@acm.org
+Reviewed-by: Can Guo <quic_cang@quicinc.com>
+Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/ufs/core/ufshcd.c | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
+index 0971ae37f2a7..44e0437bd19d 100644
+--- a/drivers/ufs/core/ufshcd.c
++++ b/drivers/ufs/core/ufshcd.c
+@@ -8810,12 +8810,9 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie)
+
+ out:
+ pm_runtime_put_sync(hba->dev);
+- /*
+- * If we failed to initialize the device or the device is not
+- * present, turn off the power/clocks etc.
+- */
++
+ if (ret)
+- ufshcd_hba_exit(hba);
++ dev_err(hba->dev, "%s failed: %d\n", __func__, ret);
+ }
+
+ static enum scsi_timeout_action ufshcd_eh_timed_out(struct scsi_cmnd *scmd)
+--
+2.43.0
+
--- /dev/null
+From af43430da925196c65717ffb872eef90043da6f6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 3 Jan 2024 07:18:13 +0100
+Subject: serial: core: set missing supported flag for RX during TX GPIO
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Lino Sanfilippo <l.sanfilippo@kunbus.com>
+
+[ Upstream commit 1a33e33ca0e80d485458410f149265cdc0178cfa ]
+
+If the RS485 feature RX-during-TX is supported by means of a GPIO set the
+according supported flag. Otherwise setting this feature from userspace may
+not be possible, since in uart_sanitize_serial_rs485() the passed RS485
+configuration is matched against the supported features and unsupported
+settings are thereby removed and thus take no effect.
+
+Cc: <stable@vger.kernel.org>
+Fixes: 163f080eb717 ("serial: core: Add option to output RS485 RX_DURING_TX state via GPIO")
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Lino Sanfilippo <l.sanfilippo@kunbus.com>
+Link: https://lore.kernel.org/r/20240103061818.564-3-l.sanfilippo@kunbus.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/serial_core.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
+index 021e096bc4ed..bde5b6015305 100644
+--- a/drivers/tty/serial/serial_core.c
++++ b/drivers/tty/serial/serial_core.c
+@@ -3630,6 +3630,8 @@ int uart_get_rs485_mode(struct uart_port *port)
+ if (IS_ERR(desc))
+ return dev_err_probe(dev, PTR_ERR(desc), "Cannot get rs485-rx-during-tx-gpios\n");
+ port->rs485_rx_during_tx_gpio = desc;
++ if (port->rs485_rx_during_tx_gpio)
++ port->rs485_supported.flags |= SER_RS485_RX_DURING_TX;
+
+ return 0;
+ }
+--
+2.43.0
+
--- /dev/null
+From b4b7905e246ce50f256f0b7a7717702b93070adf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Oct 2023 17:23:46 +0300
+Subject: serial: core: Simplify uart_get_rs485_mode()
+
+From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+
+[ Upstream commit 7cda0b9eb6eb9e761f452e2ef4e81eca20b19938 ]
+
+Simplify uart_get_rs485_mode() by using temporary variable for
+the GPIO descriptor. With that, use proper type for the flags
+of the GPIO descriptor.
+
+Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Link: https://lore.kernel.org/r/20231003142346.3072929-1-andriy.shevchenko@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 1a33e33ca0e8 ("serial: core: set missing supported flag for RX during TX GPIO")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/serial_core.c | 30 ++++++++++++------------------
+ 1 file changed, 12 insertions(+), 18 deletions(-)
+
+diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
+index 18b49b1439a5..021e096bc4ed 100644
+--- a/drivers/tty/serial/serial_core.c
++++ b/drivers/tty/serial/serial_core.c
+@@ -3572,9 +3572,10 @@ int uart_get_rs485_mode(struct uart_port *port)
+ {
+ struct serial_rs485 *rs485conf = &port->rs485;
+ struct device *dev = port->dev;
++ enum gpiod_flags dflags;
++ struct gpio_desc *desc;
+ u32 rs485_delay[2];
+ int ret;
+- int rx_during_tx_gpio_flag;
+
+ if (!(port->rs485_supported.flags & SER_RS485_ENABLED))
+ return 0;
+@@ -3616,26 +3617,19 @@ int uart_get_rs485_mode(struct uart_port *port)
+ * bus participants enable it, no communication is possible at all.
+ * Works fine for short cables and users may enable for longer cables.
+ */
+- port->rs485_term_gpio = devm_gpiod_get_optional(dev, "rs485-term",
+- GPIOD_OUT_LOW);
+- if (IS_ERR(port->rs485_term_gpio)) {
+- ret = PTR_ERR(port->rs485_term_gpio);
+- port->rs485_term_gpio = NULL;
+- return dev_err_probe(dev, ret, "Cannot get rs485-term-gpios\n");
+- }
++ desc = devm_gpiod_get_optional(dev, "rs485-term", GPIOD_OUT_LOW);
++ if (IS_ERR(desc))
++ return dev_err_probe(dev, PTR_ERR(desc), "Cannot get rs485-term-gpios\n");
++ port->rs485_term_gpio = desc;
+ if (port->rs485_term_gpio)
+ port->rs485_supported.flags |= SER_RS485_TERMINATE_BUS;
+
+- rx_during_tx_gpio_flag = (rs485conf->flags & SER_RS485_RX_DURING_TX) ?
+- GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
+- port->rs485_rx_during_tx_gpio = devm_gpiod_get_optional(dev,
+- "rs485-rx-during-tx",
+- rx_during_tx_gpio_flag);
+- if (IS_ERR(port->rs485_rx_during_tx_gpio)) {
+- ret = PTR_ERR(port->rs485_rx_during_tx_gpio);
+- port->rs485_rx_during_tx_gpio = NULL;
+- return dev_err_probe(dev, ret, "Cannot get rs485-rx-during-tx-gpios\n");
+- }
++ dflags = (rs485conf->flags & SER_RS485_RX_DURING_TX) ?
++ GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
++ desc = devm_gpiod_get_optional(dev, "rs485-rx-during-tx", dflags);
++ if (IS_ERR(desc))
++ return dev_err_probe(dev, PTR_ERR(desc), "Cannot get rs485-rx-during-tx-gpios\n");
++ port->rs485_rx_during_tx_gpio = desc;
+
+ return 0;
+ }
+--
+2.43.0
+
--- /dev/null
+docs-sparse-move-tw-sparse.txt-to-tw-dev-tools.patch
+docs-sparse-add-sparse.rst-to-toctree.patch
+docs-kernel_feat.py-fix-potential-command-injection.patch
+serial-core-simplify-uart_get_rs485_mode.patch
+serial-core-set-missing-supported-flag-for-rx-during.patch
+soundwire-bus-introduce-controller_id.patch
+soundwire-fix-initializing-sysfs-for-same-devices-on.patch
+net-stmmac-tx-coe-sw-fallback.patch
+net-stmmac-prevent-dsa-tags-from-breaking-coe.patch
+iio-adc-ad7091r-set-alert-bit-in-config-register.patch
+iio-adc-ad7091r-allow-users-to-configure-device-even.patch
+iio-adc-ad7091r-enable-internal-vref-if-external-vre.patch
+dmaengine-fsl-edma-fix-edmav4-channel-allocation-iss.patch
+dmaengine-fix-null-pointer-in-channel-unregistration.patch
+dmaengine-idxd-move-dma_free_coherent-out-of-spinloc.patch
+scsi-ufs-core-remove-the-ufshcd_hba_exit-call-from-u.patch
+riscv-fix-an-off-by-one-in-get_early_cmdline.patch
+scsi-core-kick-the-requeue-list-after-inserting-when.patch
+sh-ecovec24-rename-missed-backlight-field-from-fbdev.patch
+smb-client-fix-parsing-of-smb3.1.1-posix-create-cont.patch
+cifs-handle-cases-where-a-channel-is-closed.patch
+cifs-reconnect-work-should-have-reference-on-server-.patch
+cifs-handle-when-server-starts-supporting-multichann.patch
+cifs-handle-when-server-stops-supporting-multichanne.patch
+revert-cifs-reconnect-work-should-have-reference-on-.patch
+cifs-reconnect-worker-should-take-reference-on-serve.patch
+cifs-handle-servers-that-still-advertise-multichanne.patch
+cifs-update-iface_last_update-on-each-query-and-upda.patch
--- /dev/null
+From 28688eee7cbf9785fd95a9cebdf786c613fb31e1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 25 Sep 2023 13:10:22 +0200
+Subject: sh: ecovec24: Rename missed backlight field from fbdev to dev
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Geert Uytterhoeven <geert+renesas@glider.be>
+
+[ Upstream commit d87123aa9a7920e88633ffc5c5a0a22ab08bdc06 ]
+
+One instance of gpio_backlight_platform_data.fbdev was renamed, but the
+second instance was forgotten, causing a build failure:
+
+ arch/sh/boards/mach-ecovec24/setup.c: In function ‘arch_setup’:
+ arch/sh/boards/mach-ecovec24/setup.c:1223:37: error: ‘struct gpio_backlight_platform_data’ has no member named ‘fbdev’; did you mean ‘dev’?
+ 1223 | gpio_backlight_data.fbdev = NULL;
+ | ^~~~~
+ | dev
+
+Fix this by updating the second instance.
+
+Fixes: ed369def91c1579a ("backlight/gpio_backlight: Rename field 'fbdev' to 'dev'")
+Reported-by: kernel test robot <lkp@intel.com>
+Closes: https://lore.kernel.org/oe-kbuild-all/202309231601.Uu6qcRnU-lkp@intel.com/
+Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
+Reviewed-by: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
+Link: https://lore.kernel.org/r/20230925111022.3626362-1-geert+renesas@glider.be
+Signed-off-by: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/sh/boards/mach-ecovec24/setup.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
+index 3be293335de5..7a788d44cc73 100644
+--- a/arch/sh/boards/mach-ecovec24/setup.c
++++ b/arch/sh/boards/mach-ecovec24/setup.c
+@@ -1220,7 +1220,7 @@ static int __init arch_setup(void)
+ lcdc_info.ch[0].num_modes = ARRAY_SIZE(ecovec_dvi_modes);
+
+ /* No backlight */
+- gpio_backlight_data.fbdev = NULL;
++ gpio_backlight_data.dev = NULL;
+
+ gpio_set_value(GPIO_PTA2, 1);
+ gpio_set_value(GPIO_PTU1, 1);
+--
+2.43.0
+
--- /dev/null
+From 42827830391802507a8b2e627b47d403317e2ce9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 19 Jan 2024 01:08:26 -0300
+Subject: smb: client: fix parsing of SMB3.1.1 POSIX create context
+
+From: Paulo Alcantara <pc@manguebit.com>
+
+[ Upstream commit 76025cc2285d9ede3d717fe4305d66f8be2d9346 ]
+
+The data offset for the SMB3.1.1 POSIX create context will always be
+8-byte aligned so having the check 'noff + nlen >= doff' in
+smb2_parse_contexts() is wrong as it will lead to -EINVAL because noff
++ nlen == doff.
+
+Fix the sanity check to correctly handle aligned create context data.
+
+Fixes: af1689a9b770 ("smb: client: fix potential OOBs in smb2_parse_contexts()")
+Signed-off-by: Paulo Alcantara <pc@manguebit.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/smb2pdu.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
+index 5276992e3647..888eb59ad86f 100644
+--- a/fs/smb/client/smb2pdu.c
++++ b/fs/smb/client/smb2pdu.c
+@@ -2185,7 +2185,7 @@ int smb2_parse_contexts(struct TCP_Server_Info *server,
+
+ noff = le16_to_cpu(cc->NameOffset);
+ nlen = le16_to_cpu(cc->NameLength);
+- if (noff + nlen >= doff)
++ if (noff + nlen > doff)
+ return -EINVAL;
+
+ name = (char *)cc + noff;
+--
+2.43.0
+
--- /dev/null
+From edbdfa05d3a3e9c980696b2165afda2a3eb1c05b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 17 Oct 2023 11:09:32 -0500
+Subject: soundwire: bus: introduce controller_id
+
+From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
+
+[ Upstream commit 6543ac13c623f906200dfd3f1c407d8d333b6995 ]
+
+The existing SoundWire support misses a clear Controller/Manager
+hiearchical definition to deal with all variants across SOC vendors.
+
+a) Intel platforms have one controller with 4 or more Managers.
+b) AMD platforms have two controllers with one Manager each, but due
+to BIOS issues use two different link_id values within the scope of a
+single controller.
+c) QCOM platforms have one or more controller with one Manager each.
+
+This patch adds a 'controller_id' which can be set by higher
+levels. If assigned to -1, the controller_id will be set to the
+system-unique IDA-assigned bus->id.
+
+The main change is that the bus->id is no longer used for any device
+name, which makes the definition completely predictable and not
+dependent on any enumeration order. The bus->id is only used to insert
+the Managers in the stream rt context.
+
+Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
+Reviewed-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
+Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
+Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Tested-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/stable/20231017160933.12624-2-pierre-louis.bossart%40linux.intel.com
+Tested-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20231017160933.12624-2-pierre-louis.bossart@linux.intel.com
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Stable-dep-of: 8a8a9ac8a497 ("soundwire: fix initializing sysfs for same devices on different buses")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soundwire/amd_manager.c | 8 ++++++++
+ drivers/soundwire/bus.c | 4 ++++
+ drivers/soundwire/debugfs.c | 2 +-
+ drivers/soundwire/intel_auxdevice.c | 3 +++
+ drivers/soundwire/master.c | 2 +-
+ drivers/soundwire/qcom.c | 3 +++
+ include/linux/soundwire/sdw.h | 4 +++-
+ 7 files changed, 23 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c
+index 3a99f6dcdfaf..a3b1f4e6f0f9 100644
+--- a/drivers/soundwire/amd_manager.c
++++ b/drivers/soundwire/amd_manager.c
+@@ -927,6 +927,14 @@ static int amd_sdw_manager_probe(struct platform_device *pdev)
+ amd_manager->bus.clk_stop_timeout = 200;
+ amd_manager->bus.link_id = amd_manager->instance;
+
++ /*
++ * Due to BIOS compatibility, the two links are exposed within
++ * the scope of a single controller. If this changes, the
++ * controller_id will have to be updated with drv_data
++ * information.
++ */
++ amd_manager->bus.controller_id = 0;
++
+ switch (amd_manager->instance) {
+ case ACP_SDW0:
+ amd_manager->num_dout_ports = AMD_SDW0_MAX_TX_PORTS;
+diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
+index 0e7bc3c40f9d..e7553c38be59 100644
+--- a/drivers/soundwire/bus.c
++++ b/drivers/soundwire/bus.c
+@@ -22,6 +22,10 @@ static int sdw_get_id(struct sdw_bus *bus)
+ return rc;
+
+ bus->id = rc;
++
++ if (bus->controller_id == -1)
++ bus->controller_id = rc;
++
+ return 0;
+ }
+
+diff --git a/drivers/soundwire/debugfs.c b/drivers/soundwire/debugfs.c
+index d1553cb77187..67abd7e52f09 100644
+--- a/drivers/soundwire/debugfs.c
++++ b/drivers/soundwire/debugfs.c
+@@ -20,7 +20,7 @@ void sdw_bus_debugfs_init(struct sdw_bus *bus)
+ return;
+
+ /* create the debugfs master-N */
+- snprintf(name, sizeof(name), "master-%d-%d", bus->id, bus->link_id);
++ snprintf(name, sizeof(name), "master-%d-%d", bus->controller_id, bus->link_id);
+ bus->debugfs = debugfs_create_dir(name, sdw_debugfs_root);
+ }
+
+diff --git a/drivers/soundwire/intel_auxdevice.c b/drivers/soundwire/intel_auxdevice.c
+index 7f15e3549e53..93698532deac 100644
+--- a/drivers/soundwire/intel_auxdevice.c
++++ b/drivers/soundwire/intel_auxdevice.c
+@@ -234,6 +234,9 @@ static int intel_link_probe(struct auxiliary_device *auxdev,
+ cdns->instance = sdw->instance;
+ cdns->msg_count = 0;
+
++ /* single controller for all SoundWire links */
++ bus->controller_id = 0;
++
+ bus->link_id = auxdev->id;
+ bus->clk_stop_timeout = 1;
+
+diff --git a/drivers/soundwire/master.c b/drivers/soundwire/master.c
+index 9b05c9e25ebe..51abedbbaa66 100644
+--- a/drivers/soundwire/master.c
++++ b/drivers/soundwire/master.c
+@@ -145,7 +145,7 @@ int sdw_master_device_add(struct sdw_bus *bus, struct device *parent,
+ md->dev.fwnode = fwnode;
+ md->dev.dma_mask = parent->dma_mask;
+
+- dev_set_name(&md->dev, "sdw-master-%d", bus->id);
++ dev_set_name(&md->dev, "sdw-master-%d-%d", bus->controller_id, bus->link_id);
+
+ ret = device_register(&md->dev);
+ if (ret) {
+diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
+index 55be9f4b8d59..e3ae4e4e07ac 100644
+--- a/drivers/soundwire/qcom.c
++++ b/drivers/soundwire/qcom.c
+@@ -1612,6 +1612,9 @@ static int qcom_swrm_probe(struct platform_device *pdev)
+ }
+ }
+
++ /* FIXME: is there a DT-defined value to use ? */
++ ctrl->bus.controller_id = -1;
++
+ ret = sdw_bus_master_add(&ctrl->bus, dev, dev->fwnode);
+ if (ret) {
+ dev_err(dev, "Failed to register Soundwire controller (%d)\n",
+diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
+index 4f3d14bb1538..c383579a008b 100644
+--- a/include/linux/soundwire/sdw.h
++++ b/include/linux/soundwire/sdw.h
+@@ -886,7 +886,8 @@ struct sdw_master_ops {
+ * struct sdw_bus - SoundWire bus
+ * @dev: Shortcut to &bus->md->dev to avoid changing the entire code.
+ * @md: Master device
+- * @link_id: Link id number, can be 0 to N, unique for each Master
++ * @controller_id: system-unique controller ID. If set to -1, the bus @id will be used.
++ * @link_id: Link id number, can be 0 to N, unique for each Controller
+ * @id: bus system-wide unique id
+ * @slaves: list of Slaves on this bus
+ * @assigned: Bitmap for Slave device numbers.
+@@ -918,6 +919,7 @@ struct sdw_master_ops {
+ struct sdw_bus {
+ struct device *dev;
+ struct sdw_master_device *md;
++ int controller_id;
+ unsigned int link_id;
+ int id;
+ struct list_head slaves;
+--
+2.43.0
+
--- /dev/null
+From 8f5395f655b54b48def212f6d1bc5424d8a734ad Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 17 Oct 2023 11:09:33 -0500
+Subject: soundwire: fix initializing sysfs for same devices on different buses
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit 8a8a9ac8a4972ee69d3dd3d1ae43963ae39cee18 ]
+
+If same devices with same device IDs are present on different soundwire
+buses, the probe fails due to conflicting device names and sysfs
+entries:
+
+ sysfs: cannot create duplicate filename '/bus/soundwire/devices/sdw:0:0217:0204:00:0'
+
+The link ID is 0 for both devices, so they should be differentiated by
+the controller ID. Add the controller ID so, the device names and sysfs entries look
+like:
+
+ sdw:1:0:0217:0204:00:0 -> ../../../devices/platform/soc@0/6ab0000.soundwire-controller/sdw-master-1-0/sdw:1:0:0217:0204:00:0
+ sdw:3:0:0217:0204:00:0 -> ../../../devices/platform/soc@0/6b10000.soundwire-controller/sdw-master-3-0/sdw:3:0:0217:0204:00:0
+
+[PLB changes: use bus->controller_id instead of bus->id]
+
+Fixes: 7c3cd189b86d ("soundwire: Add Master registration")
+Cc: stable@vger.kernel.org
+Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
+Reviewed-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
+Co-developed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
+Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Tested-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Acked-by: Mark Brown <broonie@kernel.org>
+Tested-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20231017160933.12624-3-pierre-louis.bossart@linux.intel.com
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soundwire/slave.c | 12 ++++++------
+ sound/soc/intel/boards/sof_sdw.c | 4 ++--
+ 2 files changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c
+index c1c1a2ac293a..060c2982e26b 100644
+--- a/drivers/soundwire/slave.c
++++ b/drivers/soundwire/slave.c
+@@ -39,14 +39,14 @@ int sdw_slave_add(struct sdw_bus *bus,
+ slave->dev.fwnode = fwnode;
+
+ if (id->unique_id == SDW_IGNORED_UNIQUE_ID) {
+- /* name shall be sdw:link:mfg:part:class */
+- dev_set_name(&slave->dev, "sdw:%01x:%04x:%04x:%02x",
+- bus->link_id, id->mfg_id, id->part_id,
++ /* name shall be sdw:ctrl:link:mfg:part:class */
++ dev_set_name(&slave->dev, "sdw:%01x:%01x:%04x:%04x:%02x",
++ bus->controller_id, bus->link_id, id->mfg_id, id->part_id,
+ id->class_id);
+ } else {
+- /* name shall be sdw:link:mfg:part:class:unique */
+- dev_set_name(&slave->dev, "sdw:%01x:%04x:%04x:%02x:%01x",
+- bus->link_id, id->mfg_id, id->part_id,
++ /* name shall be sdw:ctrl:link:mfg:part:class:unique */
++ dev_set_name(&slave->dev, "sdw:%01x:%01x:%04x:%04x:%02x:%01x",
++ bus->controller_id, bus->link_id, id->mfg_id, id->part_id,
+ id->class_id, id->unique_id);
+ }
+
+diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
+index 24e966a2ac2b..9ed572141fe5 100644
+--- a/sound/soc/intel/boards/sof_sdw.c
++++ b/sound/soc/intel/boards/sof_sdw.c
+@@ -1197,11 +1197,11 @@ static int fill_sdw_codec_dlc(struct device *dev,
+ else if (is_unique_device(adr_link, sdw_version, mfg_id, part_id,
+ class_id, adr_index))
+ codec->name = devm_kasprintf(dev, GFP_KERNEL,
+- "sdw:%01x:%04x:%04x:%02x", link_id,
++ "sdw:0:%01x:%04x:%04x:%02x", link_id,
+ mfg_id, part_id, class_id);
+ else
+ codec->name = devm_kasprintf(dev, GFP_KERNEL,
+- "sdw:%01x:%04x:%04x:%02x:%01x", link_id,
++ "sdw:0:%01x:%04x:%04x:%02x:%01x", link_id,
+ mfg_id, part_id, class_id, unique_id);
+
+ if (!codec->name)
+--
+2.43.0
+