From: Sasha Levin Date: Sun, 16 Jun 2024 02:01:17 +0000 (-0400) Subject: Fixes for 5.10 X-Git-Tag: v4.19.316~10 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=92448420c65cbf58fab7285f870b125b561b65c5;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 5.10 Signed-off-by: Sasha Levin --- diff --git a/queue-5.10/af_unix-annotate-data-race-of-net-unx.sysctl_max_dgr.patch b/queue-5.10/af_unix-annotate-data-race-of-net-unx.sysctl_max_dgr.patch new file mode 100644 index 00000000000..9d554982bf7 --- /dev/null +++ b/queue-5.10/af_unix-annotate-data-race-of-net-unx.sysctl_max_dgr.patch @@ -0,0 +1,38 @@ +From 463ee629bf586c9b9c3323eb41bd82cc10f5f380 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Jun 2024 09:52:37 -0700 +Subject: af_unix: Annotate data-race of net->unx.sysctl_max_dgram_qlen. + +From: Kuniyuki Iwashima + +[ Upstream commit bd9f2d05731f6a112d0c7391a0d537bfc588dbe6 ] + +net->unx.sysctl_max_dgram_qlen is exposed as a sysctl knob and can be +changed concurrently. + +Let's use READ_ONCE() in unix_create1(). + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Kuniyuki Iwashima +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index 2456170c9ddc4..f1a9b3759d462 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -815,7 +815,7 @@ static struct sock *unix_create1(struct net *net, struct socket *sock, int kern) + + sk->sk_allocation = GFP_KERNEL_ACCOUNT; + sk->sk_write_space = unix_write_space; +- sk->sk_max_ack_backlog = net->unx.sysctl_max_dgram_qlen; ++ sk->sk_max_ack_backlog = READ_ONCE(net->unx.sysctl_max_dgram_qlen); + sk->sk_destruct = unix_sock_destructor; + u = unix_sk(sk); + u->inflight = 0; +-- +2.43.0 + diff --git a/queue-5.10/af_unix-annotate-data-race-of-sk-sk_shutdown-in-sk_d.patch b/queue-5.10/af_unix-annotate-data-race-of-sk-sk_shutdown-in-sk_d.patch new file mode 100644 index 00000000000..130b81542c1 --- /dev/null +++ b/queue-5.10/af_unix-annotate-data-race-of-sk-sk_shutdown-in-sk_d.patch @@ -0,0 +1,37 @@ +From 0ecdffcde5c3fa77e40d6ec4c583fc6d6f3bd55b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Jun 2024 09:52:41 -0700 +Subject: af_unix: Annotate data-race of sk->sk_shutdown in sk_diag_fill(). + +From: Kuniyuki Iwashima + +[ Upstream commit efaf24e30ec39ebbea9112227485805a48b0ceb1 ] + +While dumping sockets via UNIX_DIAG, we do not hold unix_state_lock(). + +Let's use READ_ONCE() to read sk->sk_shutdown. + +Fixes: e4e541a84863 ("sock-diag: Report shutdown for inet and unix sockets (v2)") +Signed-off-by: Kuniyuki Iwashima +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/unix/diag.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/unix/diag.c b/net/unix/diag.c +index 5bc5cb83cc6e4..7066a36234106 100644 +--- a/net/unix/diag.c ++++ b/net/unix/diag.c +@@ -164,7 +164,7 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_r + sock_diag_put_meminfo(sk, skb, UNIX_DIAG_MEMINFO)) + goto out_nlmsg_trim; + +- if (nla_put_u8(skb, UNIX_DIAG_SHUTDOWN, sk->sk_shutdown)) ++ if (nla_put_u8(skb, UNIX_DIAG_SHUTDOWN, READ_ONCE(sk->sk_shutdown))) + goto out_nlmsg_trim; + + if ((req->udiag_show & UDIAG_SHOW_UID) && +-- +2.43.0 + diff --git a/queue-5.10/af_unix-annotate-data-race-of-sk-sk_state-in-unix_in.patch b/queue-5.10/af_unix-annotate-data-race-of-sk-sk_state-in-unix_in.patch new file mode 100644 index 00000000000..5d96175707d --- /dev/null +++ b/queue-5.10/af_unix-annotate-data-race-of-sk-sk_state-in-unix_in.patch @@ -0,0 +1,50 @@ +From 94444b2646709bbf8bdc8143df8e44963b522187 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Jun 2024 09:52:29 -0700 +Subject: af_unix: Annotate data-race of sk->sk_state in unix_inq_len(). + +From: Kuniyuki Iwashima + +[ Upstream commit 3a0f38eb285c8c2eead4b3230c7ac2983707599d ] + +ioctl(SIOCINQ) calls unix_inq_len() that checks sk->sk_state first +and returns -EINVAL if it's TCP_LISTEN. + +Then, for SOCK_STREAM sockets, unix_inq_len() returns the number of +bytes in recvq. + +However, unix_inq_len() does not hold unix_state_lock(), and the +concurrent listen() might change the state after checking sk->sk_state. + +If the race occurs, 0 is returned for the listener, instead of -EINVAL, +because the length of skb with embryo is 0. + +We could hold unix_state_lock() in unix_inq_len(), but it's overkill +given the result is true for pre-listen() TCP_CLOSE state. + +So, let's use READ_ONCE() for sk->sk_state in unix_inq_len(). + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Kuniyuki Iwashima +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index 3ab726a668e8a..c2aaf4b832c65 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -2614,7 +2614,7 @@ long unix_inq_len(struct sock *sk) + struct sk_buff *skb; + long amount = 0; + +- if (sk->sk_state == TCP_LISTEN) ++ if (READ_ONCE(sk->sk_state) == TCP_LISTEN) + return -EINVAL; + + spin_lock(&sk->sk_receive_queue.lock); +-- +2.43.0 + diff --git a/queue-5.10/af_unix-annotate-data-races-around-sk-sk_state-in-se.patch b/queue-5.10/af_unix-annotate-data-races-around-sk-sk_state-in-se.patch new file mode 100644 index 00000000000..73f5d749db5 --- /dev/null +++ b/queue-5.10/af_unix-annotate-data-races-around-sk-sk_state-in-se.patch @@ -0,0 +1,72 @@ +From 80ef8ebce90c7fcc8a159986c507f391157c6e54 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Jun 2024 09:52:33 -0700 +Subject: af_unix: Annotate data-races around sk->sk_state in sendmsg() and + recvmsg(). + +From: Kuniyuki Iwashima + +[ Upstream commit 8a34d4e8d9742a24f74998f45a6a98edd923319b ] + +The following functions read sk->sk_state locklessly and proceed only if +the state is TCP_ESTABLISHED. + + * unix_stream_sendmsg + * unix_stream_read_generic + * unix_seqpacket_sendmsg + * unix_seqpacket_recvmsg + +Let's use READ_ONCE() there. + +Fixes: a05d2ad1c1f3 ("af_unix: Only allow recv on connected seqpacket sockets.") +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Kuniyuki Iwashima +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index 33dd6ed8de25d..2456170c9ddc4 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -1909,7 +1909,7 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, + goto out_err; + + if (msg->msg_namelen) { +- err = sk->sk_state == TCP_ESTABLISHED ? -EISCONN : -EOPNOTSUPP; ++ err = READ_ONCE(sk->sk_state) == TCP_ESTABLISHED ? -EISCONN : -EOPNOTSUPP; + goto out_err; + } else { + err = -ENOTCONN; +@@ -2112,7 +2112,7 @@ static int unix_seqpacket_sendmsg(struct socket *sock, struct msghdr *msg, + if (err) + return err; + +- if (sk->sk_state != TCP_ESTABLISHED) ++ if (READ_ONCE(sk->sk_state) != TCP_ESTABLISHED) + return -ENOTCONN; + + if (msg->msg_namelen) +@@ -2126,7 +2126,7 @@ static int unix_seqpacket_recvmsg(struct socket *sock, struct msghdr *msg, + { + struct sock *sk = sock->sk; + +- if (sk->sk_state != TCP_ESTABLISHED) ++ if (READ_ONCE(sk->sk_state) != TCP_ESTABLISHED) + return -ENOTCONN; + + return unix_dgram_recvmsg(sock, msg, size, flags); +@@ -2326,7 +2326,7 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state, + size_t size = state->size; + unsigned int last_len; + +- if (unlikely(sk->sk_state != TCP_ESTABLISHED)) { ++ if (unlikely(READ_ONCE(sk->sk_state) != TCP_ESTABLISHED)) { + err = -EINVAL; + goto out; + } +-- +2.43.0 + diff --git a/queue-5.10/af_unix-annotate-data-races-around-sk-sk_state-in-un.patch b/queue-5.10/af_unix-annotate-data-races-around-sk-sk_state-in-un.patch new file mode 100644 index 00000000000..00aedae77c4 --- /dev/null +++ b/queue-5.10/af_unix-annotate-data-races-around-sk-sk_state-in-un.patch @@ -0,0 +1,128 @@ +From c5a1f598f7e07e2e157dbde9f2ea436e7158d664 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Jun 2024 09:52:30 -0700 +Subject: af_unix: Annotate data-races around sk->sk_state in + unix_write_space() and poll(). + +From: Kuniyuki Iwashima + +[ Upstream commit eb0718fb3e97ad0d6f4529b810103451c90adf94 ] + +unix_poll() and unix_dgram_poll() read sk->sk_state locklessly and +calls unix_writable() which also reads sk->sk_state without holding +unix_state_lock(). + +Let's use READ_ONCE() in unix_poll() and unix_dgram_poll() and pass +it to unix_writable(). + +While at it, we remove TCP_SYN_SENT check in unix_dgram_poll() as +that state does not exist for AF_UNIX socket since the code was added. + +Fixes: 1586a5877db9 ("af_unix: do not report POLLOUT on listeners") +Fixes: 3c73419c09a5 ("af_unix: fix 'poll for write'/ connected DGRAM sockets") +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Kuniyuki Iwashima +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 25 ++++++++++++------------- + 1 file changed, 12 insertions(+), 13 deletions(-) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index c2aaf4b832c65..33dd6ed8de25d 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -447,9 +447,9 @@ static int unix_dgram_peer_wake_me(struct sock *sk, struct sock *other) + return 0; + } + +-static int unix_writable(const struct sock *sk) ++static int unix_writable(const struct sock *sk, unsigned char state) + { +- return sk->sk_state != TCP_LISTEN && ++ return state != TCP_LISTEN && + (refcount_read(&sk->sk_wmem_alloc) << 2) <= sk->sk_sndbuf; + } + +@@ -458,7 +458,7 @@ static void unix_write_space(struct sock *sk) + struct socket_wq *wq; + + rcu_read_lock(); +- if (unix_writable(sk)) { ++ if (unix_writable(sk, READ_ONCE(sk->sk_state))) { + wq = rcu_dereference(sk->sk_wq); + if (skwq_has_sleeper(wq)) + wake_up_interruptible_sync_poll(&wq->wait, +@@ -2713,12 +2713,14 @@ static int unix_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned lon + static __poll_t unix_poll(struct file *file, struct socket *sock, poll_table *wait) + { + struct sock *sk = sock->sk; ++ unsigned char state; + __poll_t mask; + u8 shutdown; + + sock_poll_wait(file, sock, wait); + mask = 0; + shutdown = READ_ONCE(sk->sk_shutdown); ++ state = READ_ONCE(sk->sk_state); + + /* exceptional events? */ + if (sk->sk_err) +@@ -2734,14 +2736,14 @@ static __poll_t unix_poll(struct file *file, struct socket *sock, poll_table *wa + + /* Connection-based need to check for termination and startup */ + if ((sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) && +- sk->sk_state == TCP_CLOSE) ++ state == TCP_CLOSE) + mask |= EPOLLHUP; + + /* + * we set writable also when the other side has shut down the + * connection. This prevents stuck sockets. + */ +- if (unix_writable(sk)) ++ if (unix_writable(sk, state)) + mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND; + + return mask; +@@ -2752,12 +2754,14 @@ static __poll_t unix_dgram_poll(struct file *file, struct socket *sock, + { + struct sock *sk = sock->sk, *other; + unsigned int writable; ++ unsigned char state; + __poll_t mask; + u8 shutdown; + + sock_poll_wait(file, sock, wait); + mask = 0; + shutdown = READ_ONCE(sk->sk_shutdown); ++ state = READ_ONCE(sk->sk_state); + + /* exceptional events? */ + if (sk->sk_err || !skb_queue_empty_lockless(&sk->sk_error_queue)) +@@ -2774,19 +2778,14 @@ static __poll_t unix_dgram_poll(struct file *file, struct socket *sock, + mask |= EPOLLIN | EPOLLRDNORM; + + /* Connection-based need to check for termination and startup */ +- if (sk->sk_type == SOCK_SEQPACKET) { +- if (sk->sk_state == TCP_CLOSE) +- mask |= EPOLLHUP; +- /* connection hasn't started yet? */ +- if (sk->sk_state == TCP_SYN_SENT) +- return mask; +- } ++ if (sk->sk_type == SOCK_SEQPACKET && state == TCP_CLOSE) ++ mask |= EPOLLHUP; + + /* No write status requested, avoid expensive OUT tests. */ + if (!(poll_requested_events(wait) & (EPOLLWRBAND|EPOLLWRNORM|EPOLLOUT))) + return mask; + +- writable = unix_writable(sk); ++ writable = unix_writable(sk, state); + if (writable) { + unix_state_lock(sk); + +-- +2.43.0 + diff --git a/queue-5.10/af_unix-annotate-data-races-around-sk-sk_state-in-un.patch-31294 b/queue-5.10/af_unix-annotate-data-races-around-sk-sk_state-in-un.patch-31294 new file mode 100644 index 00000000000..f1d99ba6d90 --- /dev/null +++ b/queue-5.10/af_unix-annotate-data-races-around-sk-sk_state-in-un.patch-31294 @@ -0,0 +1,71 @@ +From 128d9a92cfa187e88ae4ce98ee70b2569986f82c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Jun 2024 09:52:35 -0700 +Subject: af_unix: Annotate data-races around sk->sk_state in UNIX_DIAG. + +From: Kuniyuki Iwashima + +[ Upstream commit 0aa3be7b3e1f8f997312cc4705f8165e02806f8f ] + +While dumping AF_UNIX sockets via UNIX_DIAG, sk->sk_state is read +locklessly. + +Let's use READ_ONCE() there. + +Note that the result could be inconsistent if the socket is dumped +during the state change. This is common for other SOCK_DIAG and +similar interfaces. + +Fixes: c9da99e6475f ("unix_diag: Fixup RQLEN extension report") +Fixes: 2aac7a2cb0d9 ("unix_diag: Pending connections IDs NLA") +Fixes: 45a96b9be6ec ("unix_diag: Dumping all sockets core") +Signed-off-by: Kuniyuki Iwashima +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/unix/diag.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/net/unix/diag.c b/net/unix/diag.c +index 2975e7a061d0b..4666fabb04933 100644 +--- a/net/unix/diag.c ++++ b/net/unix/diag.c +@@ -64,7 +64,7 @@ static int sk_diag_dump_icons(struct sock *sk, struct sk_buff *nlskb) + u32 *buf; + int i; + +- if (sk->sk_state == TCP_LISTEN) { ++ if (READ_ONCE(sk->sk_state) == TCP_LISTEN) { + spin_lock(&sk->sk_receive_queue.lock); + + attr = nla_reserve(nlskb, UNIX_DIAG_ICONS, +@@ -102,7 +102,7 @@ static int sk_diag_show_rqlen(struct sock *sk, struct sk_buff *nlskb) + { + struct unix_diag_rqlen rql; + +- if (sk->sk_state == TCP_LISTEN) { ++ if (READ_ONCE(sk->sk_state) == TCP_LISTEN) { + rql.udiag_rqueue = sk->sk_receive_queue.qlen; + rql.udiag_wqueue = sk->sk_max_ack_backlog; + } else { +@@ -135,7 +135,7 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_r + rep = nlmsg_data(nlh); + rep->udiag_family = AF_UNIX; + rep->udiag_type = sk->sk_type; +- rep->udiag_state = sk->sk_state; ++ rep->udiag_state = READ_ONCE(sk->sk_state); + rep->pad = 0; + rep->udiag_ino = sk_ino; + sock_diag_save_cookie(sk, rep->udiag_cookie); +@@ -218,7 +218,7 @@ static int unix_diag_dump(struct sk_buff *skb, struct netlink_callback *cb) + continue; + if (num < s_num) + goto next; +- if (!(req->udiag_states & (1 << sk->sk_state))) ++ if (!(req->udiag_states & (1 << READ_ONCE(sk->sk_state)))) + goto next; + if (sk_diag_dump(sk, skb, req, sk_user_ns(skb->sk), + NETLINK_CB(cb->skb).portid, +-- +2.43.0 + diff --git a/queue-5.10/af_unix-use-skb_queue_len_lockless-in-sk_diag_show_r.patch b/queue-5.10/af_unix-use-skb_queue_len_lockless-in-sk_diag_show_r.patch new file mode 100644 index 00000000000..8474407950c --- /dev/null +++ b/queue-5.10/af_unix-use-skb_queue_len_lockless-in-sk_diag_show_r.patch @@ -0,0 +1,41 @@ +From f981f35e0e81dc46a7562da902635df118a28f12 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Jun 2024 09:52:40 -0700 +Subject: af_unix: Use skb_queue_len_lockless() in sk_diag_show_rqlen(). + +From: Kuniyuki Iwashima + +[ Upstream commit 5d915e584d8408211d4567c22685aae8820bfc55 ] + +We can dump the socket queue length via UNIX_DIAG by specifying +UDIAG_SHOW_RQLEN. + +If sk->sk_state is TCP_LISTEN, we return the recv queue length, +but here we do not hold recvq lock. + +Let's use skb_queue_len_lockless() in sk_diag_show_rqlen(). + +Fixes: c9da99e6475f ("unix_diag: Fixup RQLEN extension report") +Signed-off-by: Kuniyuki Iwashima +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/unix/diag.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/unix/diag.c b/net/unix/diag.c +index 4666fabb04933..5bc5cb83cc6e4 100644 +--- a/net/unix/diag.c ++++ b/net/unix/diag.c +@@ -103,7 +103,7 @@ static int sk_diag_show_rqlen(struct sock *sk, struct sk_buff *nlskb) + struct unix_diag_rqlen rql; + + if (READ_ONCE(sk->sk_state) == TCP_LISTEN) { +- rql.udiag_rqueue = sk->sk_receive_queue.qlen; ++ rql.udiag_rqueue = skb_queue_len_lockless(&sk->sk_receive_queue); + rql.udiag_wqueue = sk->sk_max_ack_backlog; + } else { + rql.udiag_rqueue = (u32) unix_inq_len(sk); +-- +2.43.0 + diff --git a/queue-5.10/af_unix-use-unix_recvq_full_lockless-in-unix_stream_.patch b/queue-5.10/af_unix-use-unix_recvq_full_lockless-in-unix_stream_.patch new file mode 100644 index 00000000000..5640bee10cf --- /dev/null +++ b/queue-5.10/af_unix-use-unix_recvq_full_lockless-in-unix_stream_.patch @@ -0,0 +1,72 @@ +From 977875692a62cd3271d1775f01eeebe93033d965 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Jun 2024 09:52:38 -0700 +Subject: af_unix: Use unix_recvq_full_lockless() in unix_stream_connect(). + +From: Kuniyuki Iwashima + +[ Upstream commit 45d872f0e65593176d880ec148f41ad7c02e40a7 ] + +Once sk->sk_state is changed to TCP_LISTEN, it never changes. + +unix_accept() takes advantage of this characteristics; it does not +hold the listener's unix_state_lock() and only acquires recvq lock +to pop one skb. + +It means unix_state_lock() does not prevent the queue length from +changing in unix_stream_connect(). + +Thus, we need to use unix_recvq_full_lockless() to avoid data-race. + +Now we remove unix_recvq_full() as no one uses it. + +Note that we can remove READ_ONCE() for sk->sk_max_ack_backlog in +unix_recvq_full_lockless() because of the following reasons: + + (1) For SOCK_DGRAM, it is a written-once field in unix_create1() + + (2) For SOCK_STREAM and SOCK_SEQPACKET, it is changed under the + listener's unix_state_lock() in unix_listen(), and we hold + the lock in unix_stream_connect() + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Kuniyuki Iwashima +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 10 ++-------- + 1 file changed, 2 insertions(+), 8 deletions(-) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index f1a9b3759d462..dff75de9de7de 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -189,15 +189,9 @@ static inline int unix_may_send(struct sock *sk, struct sock *osk) + return unix_peer(osk) == NULL || unix_our_peer(sk, osk); + } + +-static inline int unix_recvq_full(const struct sock *sk) +-{ +- return skb_queue_len(&sk->sk_receive_queue) > sk->sk_max_ack_backlog; +-} +- + static inline int unix_recvq_full_lockless(const struct sock *sk) + { +- return skb_queue_len_lockless(&sk->sk_receive_queue) > +- READ_ONCE(sk->sk_max_ack_backlog); ++ return skb_queue_len_lockless(&sk->sk_receive_queue) > sk->sk_max_ack_backlog; + } + + struct sock *unix_peer_get(struct sock *s) +@@ -1310,7 +1304,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, + if (other->sk_shutdown & RCV_SHUTDOWN) + goto out_unlock; + +- if (unix_recvq_full(other)) { ++ if (unix_recvq_full_lockless(other)) { + err = -EAGAIN; + if (!timeo) + goto out_unlock; +-- +2.43.0 + diff --git a/queue-5.10/btrfs-fix-leak-of-qgroup-extent-records-after-transa.patch b/queue-5.10/btrfs-fix-leak-of-qgroup-extent-records-after-transa.patch new file mode 100644 index 00000000000..0c307825cf6 --- /dev/null +++ b/queue-5.10/btrfs-fix-leak-of-qgroup-extent-records-after-transa.patch @@ -0,0 +1,66 @@ +From ea4d25997357002fa88cb30de2bc4610d8173548 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Jun 2024 12:49:08 +0100 +Subject: btrfs: fix leak of qgroup extent records after transaction abort + +From: Filipe Manana + +[ Upstream commit fb33eb2ef0d88e75564983ef057b44c5b7e4fded ] + +Qgroup extent records are created when delayed ref heads are created and +then released after accounting extents at btrfs_qgroup_account_extents(), +called during the transaction commit path. + +If a transaction is aborted we free the qgroup records by calling +btrfs_qgroup_destroy_extent_records() at btrfs_destroy_delayed_refs(), +unless we don't have delayed references. We are incorrectly assuming +that no delayed references means we don't have qgroup extents records. + +We can currently have no delayed references because we ran them all +during a transaction commit and the transaction was aborted after that +due to some error in the commit path. + +So fix this by ensuring we btrfs_qgroup_destroy_extent_records() at +btrfs_destroy_delayed_refs() even if we don't have any delayed references. + +Reported-by: syzbot+0fecc032fa134afd49df@syzkaller.appspotmail.com +Link: https://lore.kernel.org/linux-btrfs/0000000000004e7f980619f91835@google.com/ +Fixes: 81f7eb00ff5b ("btrfs: destroy qgroup extent records on transaction abort") +CC: stable@vger.kernel.org # 6.1+ +Reviewed-by: Josef Bacik +Reviewed-by: Qu Wenruo +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/disk-io.c | 10 +--------- + 1 file changed, 1 insertion(+), 9 deletions(-) + +diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c +index 019f0925fa73c..c484c145c5d05 100644 +--- a/fs/btrfs/disk-io.c ++++ b/fs/btrfs/disk-io.c +@@ -4442,19 +4442,11 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, + struct btrfs_fs_info *fs_info) + { + struct rb_node *node; +- struct btrfs_delayed_ref_root *delayed_refs; ++ struct btrfs_delayed_ref_root *delayed_refs = &trans->delayed_refs; + struct btrfs_delayed_ref_node *ref; + int ret = 0; + +- delayed_refs = &trans->delayed_refs; +- + spin_lock(&delayed_refs->lock); +- if (atomic_read(&delayed_refs->num_entries) == 0) { +- spin_unlock(&delayed_refs->lock); +- btrfs_debug(fs_info, "delayed_refs has NO entry"); +- return ret; +- } +- + while ((node = rb_first_cached(&delayed_refs->href_root)) != NULL) { + struct btrfs_delayed_ref_head *head; + struct rb_node *n; +-- +2.43.0 + diff --git a/queue-5.10/driver-core-platform-change-logic-implementing-platf.patch b/queue-5.10/driver-core-platform-change-logic-implementing-platf.patch new file mode 100644 index 00000000000..843911e24b4 --- /dev/null +++ b/queue-5.10/driver-core-platform-change-logic-implementing-platf.patch @@ -0,0 +1,83 @@ +From 70fc1c8589b4de6e2f301a4307f3774ef5bce168 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Nov 2020 13:46:10 +0100 +Subject: driver core: platform: change logic implementing + platform_driver_probe +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Uwe Kleine-König + +[ Upstream commit 16085668eacdc56c46652d0f3bfef81ecace57de ] + +Instead of overwriting the core driver's probe function handle probing +devices for drivers loaded by platform_driver_probe() in the platform +driver probe function. + +The intended goal is to not have to change the probe function to +simplify converting the platform bus to use bus functions. + +Signed-off-by: Uwe Kleine-König +Link: https://lore.kernel.org/r/20201119124611.2573057-2-u.kleine-koenig@pengutronix.de +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 55c421b36448 ("mmc: davinci: Don't strip remove function when driver is builtin") +Signed-off-by: Sasha Levin +--- + drivers/base/platform.c | 18 +++++++++++++++--- + 1 file changed, 15 insertions(+), 3 deletions(-) + +diff --git a/drivers/base/platform.c b/drivers/base/platform.c +index fa023cf80dc48..16426eb934632 100644 +--- a/drivers/base/platform.c ++++ b/drivers/base/platform.c +@@ -743,12 +743,25 @@ struct platform_device *platform_device_register_full( + } + EXPORT_SYMBOL_GPL(platform_device_register_full); + ++static int platform_probe_fail(struct platform_device *pdev); ++ + static int platform_drv_probe(struct device *_dev) + { + struct platform_driver *drv = to_platform_driver(_dev->driver); + struct platform_device *dev = to_platform_device(_dev); + int ret; + ++ /* ++ * A driver registered using platform_driver_probe() cannot be bound ++ * again later because the probe function usually lives in __init code ++ * and so is gone. For these drivers .probe is set to ++ * platform_probe_fail in __platform_driver_probe(). Don't even ++ * prepare clocks and PM domains for these to match the traditional ++ * behaviour. ++ */ ++ if (unlikely(drv->probe == platform_probe_fail)) ++ return -ENXIO; ++ + ret = of_clk_set_defaults(_dev->of_node, false); + if (ret < 0) + return ret; +@@ -822,7 +835,7 @@ void platform_driver_unregister(struct platform_driver *drv) + } + EXPORT_SYMBOL_GPL(platform_driver_unregister); + +-static int platform_drv_probe_fail(struct device *_dev) ++static int platform_probe_fail(struct platform_device *pdev) + { + return -ENXIO; + } +@@ -887,10 +900,9 @@ int __init_or_module __platform_driver_probe(struct platform_driver *drv, + * new devices fail. + */ + spin_lock(&drv->driver.bus->p->klist_drivers.k_lock); +- drv->probe = NULL; ++ drv->probe = platform_probe_fail; + if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list)) + retval = -ENODEV; +- drv->driver.probe = platform_drv_probe_fail; + spin_unlock(&drv->driver.bus->p->klist_drivers.k_lock); + + if (code != retval) +-- +2.43.0 + diff --git a/queue-5.10/driver-core-platform-emit-a-warning-if-a-remove-call.patch b/queue-5.10/driver-core-platform-emit-a-warning-if-a-remove-call.patch new file mode 100644 index 00000000000..6f128b6bfb7 --- /dev/null +++ b/queue-5.10/driver-core-platform-emit-a-warning-if-a-remove-call.patch @@ -0,0 +1,60 @@ +From 2f1ac60bc9668567f021c314312563951039f77b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Feb 2021 22:15:37 +0100 +Subject: driver core: platform: Emit a warning if a remove callback returned + non-zero +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Uwe Kleine-König + +[ Upstream commit e5e1c209788138f33ca6558bf9f572f6904f486d ] + +The driver core ignores the return value of a bus' remove callback. However +a driver returning an error code is a hint that there is a problem, +probably a driver author who expects that returning e.g. -EBUSY has any +effect. + +The right thing to do would be to make struct platform_driver::remove() +return void. With the immense number of platform drivers this is however a +big quest and I hope to prevent at least a few new drivers that return an +error code here. + +Signed-off-by: Uwe Kleine-König +Link: https://lore.kernel.org/r/20210207211537.19992-1-uwe@kleine-koenig.org +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 55c421b36448 ("mmc: davinci: Don't strip remove function when driver is builtin") +Signed-off-by: Sasha Levin +--- + drivers/base/platform.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/drivers/base/platform.c b/drivers/base/platform.c +index 90166535a5c05..d0b15cbab0ff0 100644 +--- a/drivers/base/platform.c ++++ b/drivers/base/platform.c +@@ -1305,13 +1305,16 @@ static int platform_remove(struct device *_dev) + { + struct platform_driver *drv = to_platform_driver(_dev->driver); + struct platform_device *dev = to_platform_device(_dev); +- int ret = 0; + +- if (drv->remove) +- ret = drv->remove(dev); ++ if (drv->remove) { ++ int ret = drv->remove(dev); ++ ++ if (ret) ++ dev_warn(_dev, "remove callback returned a non-zero value. This will be ignored.\n"); ++ } + dev_pm_domain_detach(_dev, true); + +- return ret; ++ return 0; + } + + static void platform_shutdown(struct device *_dev) +-- +2.43.0 + diff --git a/queue-5.10/driver-core-platform-reorder-functions.patch b/queue-5.10/driver-core-platform-reorder-functions.patch new file mode 100644 index 00000000000..9e2551c004c --- /dev/null +++ b/queue-5.10/driver-core-platform-reorder-functions.patch @@ -0,0 +1,361 @@ +From a434f44fb5e69a0050bd63e6eab777236da15b30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Nov 2020 13:46:09 +0100 +Subject: driver core: platform: reorder functions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Uwe Kleine-König + +[ Upstream commit e21d740a3fe5ad2db7b5f5c2331fe2b713b1edba ] + +This way all callbacks and structures used to initialize +platform_bus_type are defined just before platform_bus_type and in the +same order. Also move platform_drv_probe_fail just before it's only +user. + +Signed-off-by: Uwe Kleine-König +Link: https://lore.kernel.org/r/20201119124611.2573057-1-u.kleine-koenig@pengutronix.de +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 55c421b36448 ("mmc: davinci: Don't strip remove function when driver is builtin") +Signed-off-by: Sasha Levin +--- + drivers/base/platform.c | 293 ++++++++++++++++++++-------------------- + 1 file changed, 147 insertions(+), 146 deletions(-) + +diff --git a/drivers/base/platform.c b/drivers/base/platform.c +index 647066229fec3..fa023cf80dc48 100644 +--- a/drivers/base/platform.c ++++ b/drivers/base/platform.c +@@ -772,11 +772,6 @@ static int platform_drv_probe(struct device *_dev) + return ret; + } + +-static int platform_drv_probe_fail(struct device *_dev) +-{ +- return -ENXIO; +-} +- + static int platform_drv_remove(struct device *_dev) + { + struct platform_driver *drv = to_platform_driver(_dev->driver); +@@ -827,6 +822,11 @@ void platform_driver_unregister(struct platform_driver *drv) + } + EXPORT_SYMBOL_GPL(platform_driver_unregister); + ++static int platform_drv_probe_fail(struct device *_dev) ++{ ++ return -ENXIO; ++} ++ + /** + * __platform_driver_probe - register driver for non-hotpluggable device + * @drv: platform driver structure +@@ -1017,109 +1017,6 @@ void platform_unregister_drivers(struct platform_driver * const *drivers, + } + EXPORT_SYMBOL_GPL(platform_unregister_drivers); + +-/* modalias support enables more hands-off userspace setup: +- * (a) environment variable lets new-style hotplug events work once system is +- * fully running: "modprobe $MODALIAS" +- * (b) sysfs attribute lets new-style coldplug recover from hotplug events +- * mishandled before system is fully running: "modprobe $(cat modalias)" +- */ +-static ssize_t modalias_show(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- struct platform_device *pdev = to_platform_device(dev); +- int len; +- +- len = of_device_modalias(dev, buf, PAGE_SIZE); +- if (len != -ENODEV) +- return len; +- +- len = acpi_device_modalias(dev, buf, PAGE_SIZE - 1); +- if (len != -ENODEV) +- return len; +- +- return sysfs_emit(buf, "platform:%s\n", pdev->name); +-} +-static DEVICE_ATTR_RO(modalias); +- +-static ssize_t driver_override_store(struct device *dev, +- struct device_attribute *attr, +- const char *buf, size_t count) +-{ +- struct platform_device *pdev = to_platform_device(dev); +- int ret; +- +- ret = driver_set_override(dev, &pdev->driver_override, buf, count); +- if (ret) +- return ret; +- +- return count; +-} +- +-static ssize_t driver_override_show(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- struct platform_device *pdev = to_platform_device(dev); +- ssize_t len; +- +- device_lock(dev); +- len = sysfs_emit(buf, "%s\n", pdev->driver_override); +- device_unlock(dev); +- +- return len; +-} +-static DEVICE_ATTR_RW(driver_override); +- +-static ssize_t numa_node_show(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- return sysfs_emit(buf, "%d\n", dev_to_node(dev)); +-} +-static DEVICE_ATTR_RO(numa_node); +- +-static umode_t platform_dev_attrs_visible(struct kobject *kobj, struct attribute *a, +- int n) +-{ +- struct device *dev = container_of(kobj, typeof(*dev), kobj); +- +- if (a == &dev_attr_numa_node.attr && +- dev_to_node(dev) == NUMA_NO_NODE) +- return 0; +- +- return a->mode; +-} +- +-static struct attribute *platform_dev_attrs[] = { +- &dev_attr_modalias.attr, +- &dev_attr_numa_node.attr, +- &dev_attr_driver_override.attr, +- NULL, +-}; +- +-static struct attribute_group platform_dev_group = { +- .attrs = platform_dev_attrs, +- .is_visible = platform_dev_attrs_visible, +-}; +-__ATTRIBUTE_GROUPS(platform_dev); +- +-static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) +-{ +- struct platform_device *pdev = to_platform_device(dev); +- int rc; +- +- /* Some devices have extra OF data and an OF-style MODALIAS */ +- rc = of_device_uevent_modalias(dev, env); +- if (rc != -ENODEV) +- return rc; +- +- rc = acpi_device_uevent_modalias(dev, env); +- if (rc != -ENODEV) +- return rc; +- +- add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX, +- pdev->name); +- return 0; +-} +- + static const struct platform_device_id *platform_match_id( + const struct platform_device_id *id, + struct platform_device *pdev) +@@ -1134,44 +1031,6 @@ static const struct platform_device_id *platform_match_id( + return NULL; + } + +-/** +- * platform_match - bind platform device to platform driver. +- * @dev: device. +- * @drv: driver. +- * +- * Platform device IDs are assumed to be encoded like this: +- * "", where is a short description of the type of +- * device, like "pci" or "floppy", and is the enumerated +- * instance of the device, like '0' or '42'. Driver IDs are simply +- * "". So, extract the from the platform_device structure, +- * and compare it against the name of the driver. Return whether they match +- * or not. +- */ +-static int platform_match(struct device *dev, struct device_driver *drv) +-{ +- struct platform_device *pdev = to_platform_device(dev); +- struct platform_driver *pdrv = to_platform_driver(drv); +- +- /* When driver_override is set, only bind to the matching driver */ +- if (pdev->driver_override) +- return !strcmp(pdev->driver_override, drv->name); +- +- /* Attempt an OF style match first */ +- if (of_driver_match_device(dev, drv)) +- return 1; +- +- /* Then try ACPI style match */ +- if (acpi_driver_match_device(dev, drv)) +- return 1; +- +- /* Then try to match against the id table */ +- if (pdrv->id_table) +- return platform_match_id(pdrv->id_table, pdev) != NULL; +- +- /* fall-back to driver name match */ +- return (strcmp(pdev->name, drv->name) == 0); +-} +- + #ifdef CONFIG_PM_SLEEP + + static int platform_legacy_suspend(struct device *dev, pm_message_t mesg) +@@ -1316,6 +1175,148 @@ int platform_pm_restore(struct device *dev) + + #endif /* CONFIG_HIBERNATE_CALLBACKS */ + ++/* modalias support enables more hands-off userspace setup: ++ * (a) environment variable lets new-style hotplug events work once system is ++ * fully running: "modprobe $MODALIAS" ++ * (b) sysfs attribute lets new-style coldplug recover from hotplug events ++ * mishandled before system is fully running: "modprobe $(cat modalias)" ++ */ ++static ssize_t modalias_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ int len; ++ ++ len = of_device_modalias(dev, buf, PAGE_SIZE); ++ if (len != -ENODEV) ++ return len; ++ ++ len = acpi_device_modalias(dev, buf, PAGE_SIZE - 1); ++ if (len != -ENODEV) ++ return len; ++ ++ return sysfs_emit(buf, "platform:%s\n", pdev->name); ++} ++static DEVICE_ATTR_RO(modalias); ++ ++static ssize_t numa_node_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ return sysfs_emit(buf, "%d\n", dev_to_node(dev)); ++} ++static DEVICE_ATTR_RO(numa_node); ++ ++static ssize_t driver_override_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ ssize_t len; ++ ++ device_lock(dev); ++ len = sysfs_emit(buf, "%s\n", pdev->driver_override); ++ device_unlock(dev); ++ ++ return len; ++} ++ ++static ssize_t driver_override_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ int ret; ++ ++ ret = driver_set_override(dev, &pdev->driver_override, buf, count); ++ if (ret) ++ return ret; ++ ++ return count; ++} ++static DEVICE_ATTR_RW(driver_override); ++ ++static struct attribute *platform_dev_attrs[] = { ++ &dev_attr_modalias.attr, ++ &dev_attr_numa_node.attr, ++ &dev_attr_driver_override.attr, ++ NULL, ++}; ++ ++static umode_t platform_dev_attrs_visible(struct kobject *kobj, struct attribute *a, ++ int n) ++{ ++ struct device *dev = container_of(kobj, typeof(*dev), kobj); ++ ++ if (a == &dev_attr_numa_node.attr && ++ dev_to_node(dev) == NUMA_NO_NODE) ++ return 0; ++ ++ return a->mode; ++} ++ ++static struct attribute_group platform_dev_group = { ++ .attrs = platform_dev_attrs, ++ .is_visible = platform_dev_attrs_visible, ++}; ++__ATTRIBUTE_GROUPS(platform_dev); ++ ++ ++/** ++ * platform_match - bind platform device to platform driver. ++ * @dev: device. ++ * @drv: driver. ++ * ++ * Platform device IDs are assumed to be encoded like this: ++ * "", where is a short description of the type of ++ * device, like "pci" or "floppy", and is the enumerated ++ * instance of the device, like '0' or '42'. Driver IDs are simply ++ * "". So, extract the from the platform_device structure, ++ * and compare it against the name of the driver. Return whether they match ++ * or not. ++ */ ++static int platform_match(struct device *dev, struct device_driver *drv) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct platform_driver *pdrv = to_platform_driver(drv); ++ ++ /* When driver_override is set, only bind to the matching driver */ ++ if (pdev->driver_override) ++ return !strcmp(pdev->driver_override, drv->name); ++ ++ /* Attempt an OF style match first */ ++ if (of_driver_match_device(dev, drv)) ++ return 1; ++ ++ /* Then try ACPI style match */ ++ if (acpi_driver_match_device(dev, drv)) ++ return 1; ++ ++ /* Then try to match against the id table */ ++ if (pdrv->id_table) ++ return platform_match_id(pdrv->id_table, pdev) != NULL; ++ ++ /* fall-back to driver name match */ ++ return (strcmp(pdev->name, drv->name) == 0); ++} ++ ++static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ int rc; ++ ++ /* Some devices have extra OF data and an OF-style MODALIAS */ ++ rc = of_device_uevent_modalias(dev, env); ++ if (rc != -ENODEV) ++ return rc; ++ ++ rc = acpi_device_uevent_modalias(dev, env); ++ if (rc != -ENODEV) ++ return rc; ++ ++ add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX, ++ pdev->name); ++ return 0; ++} ++ + int platform_dma_configure(struct device *dev) + { + enum dev_dma_attr attr; +-- +2.43.0 + diff --git a/queue-5.10/driver-core-platform-use-bus_type-functions.patch b/queue-5.10/driver-core-platform-use-bus_type-functions.patch new file mode 100644 index 00000000000..2447398adce --- /dev/null +++ b/queue-5.10/driver-core-platform-use-bus_type-functions.patch @@ -0,0 +1,194 @@ +From 7ed89da8a1cec28a096b252d4d9fac6903474e7e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Nov 2020 13:46:11 +0100 +Subject: driver core: platform: use bus_type functions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Uwe Kleine-König + +[ Upstream commit 9c30921fe7994907e0b3e0637b2c8c0fc4b5171f ] + +This works towards the goal mentioned in 2006 in commit 594c8281f905 +("[PATCH] Add bus_type probe, remove, shutdown methods."). + +The functions are moved to where the other bus_type functions are +defined and renamed to match the already established naming scheme. + +Signed-off-by: Uwe Kleine-König +Link: https://lore.kernel.org/r/20201119124611.2573057-3-u.kleine-koenig@pengutronix.de +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 55c421b36448 ("mmc: davinci: Don't strip remove function when driver is builtin") +Signed-off-by: Sasha Levin +--- + drivers/base/platform.c | 132 ++++++++++++++++++++-------------------- + 1 file changed, 65 insertions(+), 67 deletions(-) + +diff --git a/drivers/base/platform.c b/drivers/base/platform.c +index 16426eb934632..90166535a5c05 100644 +--- a/drivers/base/platform.c ++++ b/drivers/base/platform.c +@@ -743,70 +743,6 @@ struct platform_device *platform_device_register_full( + } + EXPORT_SYMBOL_GPL(platform_device_register_full); + +-static int platform_probe_fail(struct platform_device *pdev); +- +-static int platform_drv_probe(struct device *_dev) +-{ +- struct platform_driver *drv = to_platform_driver(_dev->driver); +- struct platform_device *dev = to_platform_device(_dev); +- int ret; +- +- /* +- * A driver registered using platform_driver_probe() cannot be bound +- * again later because the probe function usually lives in __init code +- * and so is gone. For these drivers .probe is set to +- * platform_probe_fail in __platform_driver_probe(). Don't even +- * prepare clocks and PM domains for these to match the traditional +- * behaviour. +- */ +- if (unlikely(drv->probe == platform_probe_fail)) +- return -ENXIO; +- +- ret = of_clk_set_defaults(_dev->of_node, false); +- if (ret < 0) +- return ret; +- +- ret = dev_pm_domain_attach(_dev, true); +- if (ret) +- goto out; +- +- if (drv->probe) { +- ret = drv->probe(dev); +- if (ret) +- dev_pm_domain_detach(_dev, true); +- } +- +-out: +- if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) { +- dev_warn(_dev, "probe deferral not supported\n"); +- ret = -ENXIO; +- } +- +- return ret; +-} +- +-static int platform_drv_remove(struct device *_dev) +-{ +- struct platform_driver *drv = to_platform_driver(_dev->driver); +- struct platform_device *dev = to_platform_device(_dev); +- int ret = 0; +- +- if (drv->remove) +- ret = drv->remove(dev); +- dev_pm_domain_detach(_dev, true); +- +- return ret; +-} +- +-static void platform_drv_shutdown(struct device *_dev) +-{ +- struct platform_driver *drv = to_platform_driver(_dev->driver); +- struct platform_device *dev = to_platform_device(_dev); +- +- if (drv->shutdown) +- drv->shutdown(dev); +-} +- + /** + * __platform_driver_register - register a driver for platform-level devices + * @drv: platform driver structure +@@ -817,9 +753,6 @@ int __platform_driver_register(struct platform_driver *drv, + { + drv->driver.owner = owner; + drv->driver.bus = &platform_bus_type; +- drv->driver.probe = platform_drv_probe; +- drv->driver.remove = platform_drv_remove; +- drv->driver.shutdown = platform_drv_shutdown; + + return driver_register(&drv->driver); + } +@@ -1329,6 +1262,68 @@ static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) + return 0; + } + ++static int platform_probe(struct device *_dev) ++{ ++ struct platform_driver *drv = to_platform_driver(_dev->driver); ++ struct platform_device *dev = to_platform_device(_dev); ++ int ret; ++ ++ /* ++ * A driver registered using platform_driver_probe() cannot be bound ++ * again later because the probe function usually lives in __init code ++ * and so is gone. For these drivers .probe is set to ++ * platform_probe_fail in __platform_driver_probe(). Don't even prepare ++ * clocks and PM domains for these to match the traditional behaviour. ++ */ ++ if (unlikely(drv->probe == platform_probe_fail)) ++ return -ENXIO; ++ ++ ret = of_clk_set_defaults(_dev->of_node, false); ++ if (ret < 0) ++ return ret; ++ ++ ret = dev_pm_domain_attach(_dev, true); ++ if (ret) ++ goto out; ++ ++ if (drv->probe) { ++ ret = drv->probe(dev); ++ if (ret) ++ dev_pm_domain_detach(_dev, true); ++ } ++ ++out: ++ if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) { ++ dev_warn(_dev, "probe deferral not supported\n"); ++ ret = -ENXIO; ++ } ++ ++ return ret; ++} ++ ++static int platform_remove(struct device *_dev) ++{ ++ struct platform_driver *drv = to_platform_driver(_dev->driver); ++ struct platform_device *dev = to_platform_device(_dev); ++ int ret = 0; ++ ++ if (drv->remove) ++ ret = drv->remove(dev); ++ dev_pm_domain_detach(_dev, true); ++ ++ return ret; ++} ++ ++static void platform_shutdown(struct device *_dev) ++{ ++ struct platform_driver *drv = to_platform_driver(_dev->driver); ++ struct platform_device *dev = to_platform_device(_dev); ++ ++ if (drv->shutdown) ++ drv->shutdown(dev); ++} ++ ++ + int platform_dma_configure(struct device *dev) + { + enum dev_dma_attr attr; +@@ -1355,6 +1350,9 @@ struct bus_type platform_bus_type = { + .dev_groups = platform_dev_groups, + .match = platform_match, + .uevent = platform_uevent, ++ .probe = platform_probe, ++ .remove = platform_remove, ++ .shutdown = platform_shutdown, + .dma_configure = platform_dma_configure, + .pm = &platform_dev_pm_ops, + }; +-- +2.43.0 + diff --git a/queue-5.10/drm-amd-display-handle-y-carry-over-in-vcp-x.y-calcu.patch b/queue-5.10/drm-amd-display-handle-y-carry-over-in-vcp-x.y-calcu.patch new file mode 100644 index 00000000000..6336b6dcb20 --- /dev/null +++ b/queue-5.10/drm-amd-display-handle-y-carry-over-in-vcp-x.y-calcu.patch @@ -0,0 +1,44 @@ +From 490dc52c6132657102dd0eb224aebb36de1ac87b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Sep 2021 19:55:39 -0400 +Subject: drm/amd/display: Handle Y carry-over in VCP X.Y calculation + +From: George Shen + +[ Upstream commit 3626a6aebe62ce7067cdc460c0c644e9445386bb ] + +[Why/How] +Theoretically rare corner case where ceil(Y) results in rounding +up to an integer. If this happens, the 1 should be carried over to +the X value. + +Reviewed-by: Wenjing Liu +Acked-by: Anson Jacob +Signed-off-by: George Shen +Tested-by: Daniel Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c +index f70fcadf1ee55..a4a6b99bddbaf 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c +@@ -633,6 +633,12 @@ void enc1_stream_encoder_set_throttled_vcp_size( + x), + 26)); + ++ // If y rounds up to integer, carry it over to x. ++ if (y >> 26) { ++ x += 1; ++ y = 0; ++ } ++ + REG_SET_2(DP_MSE_RATE_CNTL, 0, + DP_MSE_RATE_X, x, + DP_MSE_RATE_Y, y); +-- +2.43.0 + diff --git a/queue-5.10/i2c-acpi-unbind-mux-adapters-before-delete.patch b/queue-5.10/i2c-acpi-unbind-mux-adapters-before-delete.patch new file mode 100644 index 00000000000..59a20bb2678 --- /dev/null +++ b/queue-5.10/i2c-acpi-unbind-mux-adapters-before-delete.patch @@ -0,0 +1,158 @@ +From 130ab3c5df5ac2b9abb9ac6915c9c7a0e0985d72 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 Mar 2024 11:16:32 +1300 +Subject: i2c: acpi: Unbind mux adapters before delete + +From: Hamish Martin + +[ Upstream commit 3f858bbf04dbac934ac279aaee05d49eb9910051 ] + +There is an issue with ACPI overlay table removal specifically related +to I2C multiplexers. + +Consider an ACPI SSDT Overlay that defines a PCA9548 I2C mux on an +existing I2C bus. When this table is loaded we see the creation of a +device for the overall PCA9548 chip and 8 further devices - one +i2c_adapter each for the mux channels. These are all bound to their +ACPI equivalents via an eventual invocation of acpi_bind_one(). + +When we unload the SSDT overlay we run into the problem. The ACPI +devices are deleted as normal via acpi_device_del_work_fn() and the +acpi_device_del_list. + +However, the following warning and stack trace is output as the +deletion does not go smoothly: +------------[ cut here ]------------ +kernfs: can not remove 'physical_node', no directory +WARNING: CPU: 1 PID: 11 at fs/kernfs/dir.c:1674 kernfs_remove_by_name_ns+0xb9/0xc0 +Modules linked in: +CPU: 1 PID: 11 Comm: kworker/u128:0 Not tainted 6.8.0-rc6+ #1 +Hardware name: congatec AG conga-B7E3/conga-B7E3, BIOS 5.13 05/16/2023 +Workqueue: kacpi_hotplug acpi_device_del_work_fn +RIP: 0010:kernfs_remove_by_name_ns+0xb9/0xc0 +Code: e4 00 48 89 ef e8 07 71 db ff 5b b8 fe ff ff ff 5d 41 5c 41 5d e9 a7 55 e4 00 0f 0b eb a6 48 c7 c7 f0 38 0d 9d e8 97 0a d5 ff <0f> 0b eb dc 0f 1f 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 +RSP: 0018:ffff9f864008fb28 EFLAGS: 00010286 +RAX: 0000000000000000 RBX: ffff8ef90a8d4940 RCX: 0000000000000000 +RDX: ffff8f000e267d10 RSI: ffff8f000e25c780 RDI: ffff8f000e25c780 +RBP: ffff8ef9186f9870 R08: 0000000000013ffb R09: 00000000ffffbfff +R10: 00000000ffffbfff R11: ffff8f000e0a0000 R12: ffff9f864008fb50 +R13: ffff8ef90c93dd60 R14: ffff8ef9010d0958 R15: ffff8ef9186f98c8 +FS: 0000000000000000(0000) GS:ffff8f000e240000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 00007f48f5253a08 CR3: 00000003cb82e000 CR4: 00000000003506f0 +Call Trace: + + ? kernfs_remove_by_name_ns+0xb9/0xc0 + ? __warn+0x7c/0x130 + ? kernfs_remove_by_name_ns+0xb9/0xc0 + ? report_bug+0x171/0x1a0 + ? handle_bug+0x3c/0x70 + ? exc_invalid_op+0x17/0x70 + ? asm_exc_invalid_op+0x1a/0x20 + ? kernfs_remove_by_name_ns+0xb9/0xc0 + ? kernfs_remove_by_name_ns+0xb9/0xc0 + acpi_unbind_one+0x108/0x180 + device_del+0x18b/0x490 + ? srso_return_thunk+0x5/0x5f + ? srso_return_thunk+0x5/0x5f + device_unregister+0xd/0x30 + i2c_del_adapter.part.0+0x1bf/0x250 + i2c_mux_del_adapters+0xa1/0xe0 + i2c_device_remove+0x1e/0x80 + device_release_driver_internal+0x19a/0x200 + bus_remove_device+0xbf/0x100 + device_del+0x157/0x490 + ? __pfx_device_match_fwnode+0x10/0x10 + ? srso_return_thunk+0x5/0x5f + device_unregister+0xd/0x30 + i2c_acpi_notify+0x10f/0x140 + notifier_call_chain+0x58/0xd0 + blocking_notifier_call_chain+0x3a/0x60 + acpi_device_del_work_fn+0x85/0x1d0 + process_one_work+0x134/0x2f0 + worker_thread+0x2f0/0x410 + ? __pfx_worker_thread+0x10/0x10 + kthread+0xe3/0x110 + ? __pfx_kthread+0x10/0x10 + ret_from_fork+0x2f/0x50 + ? __pfx_kthread+0x10/0x10 + ret_from_fork_asm+0x1b/0x30 + +---[ end trace 0000000000000000 ]--- +... +repeated 7 more times, 1 for each channel of the mux +... + +The issue is that the binding of the ACPI devices to their peer I2C +adapters is not correctly cleaned up. Digging deeper into the issue we +see that the deletion order is such that the ACPI devices matching the +mux channel i2c adapters are deleted first during the SSDT overlay +removal. For each of the channels we see a call to i2c_acpi_notify() +with ACPI_RECONFIG_DEVICE_REMOVE but, because these devices are not +actually i2c_clients, nothing is done for them. + +Later on, after each of the mux channels has been dealt with, we come +to delete the i2c_client representing the PCA9548 device. This is the +call stack we see above, whereby the kernel cleans up the i2c_client +including destruction of the mux and its channel adapters. At this +point we do attempt to unbind from the ACPI peers but those peers no +longer exist and so we hit the kernfs errors. + +The fix is to augment i2c_acpi_notify() to handle i2c_adapters. But, +given that the life cycle of the adapters is linked to the i2c_client, +instead of deleting the i2c_adapters during the i2c_acpi_notify(), we +just trigger unbinding of the ACPI device from the adapter device, and +allow the clean up of the adapter to continue in the way it always has. + +Signed-off-by: Hamish Martin +Reviewed-by: Mika Westerberg +Reviewed-by: Andi Shyti +Fixes: 525e6fabeae2 ("i2c / ACPI: add support for ACPI reconfigure notifications") +Cc: # v4.8+ +Signed-off-by: Wolfram Sang +Signed-off-by: Sasha Levin +--- + drivers/i2c/i2c-core-acpi.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c +index cdc10688d6bdf..ef2326ac15d23 100644 +--- a/drivers/i2c/i2c-core-acpi.c ++++ b/drivers/i2c/i2c-core-acpi.c +@@ -396,6 +396,11 @@ static struct i2c_client *i2c_acpi_find_client_by_adev(struct acpi_device *adev) + return i2c_find_device_by_fwnode(acpi_fwnode_handle(adev)); + } + ++static struct i2c_adapter *i2c_acpi_find_adapter_by_adev(struct acpi_device *adev) ++{ ++ return i2c_find_adapter_by_fwnode(acpi_fwnode_handle(adev)); ++} ++ + static int i2c_acpi_notify(struct notifier_block *nb, unsigned long value, + void *arg) + { +@@ -422,11 +427,17 @@ static int i2c_acpi_notify(struct notifier_block *nb, unsigned long value, + break; + + client = i2c_acpi_find_client_by_adev(adev); +- if (!client) +- break; ++ if (client) { ++ i2c_unregister_device(client); ++ put_device(&client->dev); ++ } ++ ++ adapter = i2c_acpi_find_adapter_by_adev(adev); ++ if (adapter) { ++ acpi_unbind_one(&adapter->dev); ++ put_device(&adapter->dev); ++ } + +- i2c_unregister_device(client); +- put_device(&client->dev); + break; + } + +-- +2.43.0 + diff --git a/queue-5.10/i2c-add-fwnode-apis.patch b/queue-5.10/i2c-add-fwnode-apis.patch new file mode 100644 index 00000000000..0347fc518df --- /dev/null +++ b/queue-5.10/i2c-add-fwnode-apis.patch @@ -0,0 +1,290 @@ +From 4ad6f37bdf7a6a52db69f154b835c23085db97d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Jan 2023 10:54:21 +0000 +Subject: i2c: add fwnode APIs + +From: Russell King (Oracle) + +[ Upstream commit 373c612d72461ddaea223592df31e62c934aae61 ] + +Add fwnode APIs for finding and getting I2C adapters, which will be +used by the SFP code. These are passed the fwnode corresponding to +the adapter, and return the I2C adapter. It is the responsibility of +the caller to find the appropriate fwnode. + +We keep the DT and ACPI interfaces, but where appropriate, recode them +to use the fwnode interfaces internally. + +Reviewed-by: Mika Westerberg +Signed-off-by: Russell King (Oracle) +Signed-off-by: Wolfram Sang +Stable-dep-of: 3f858bbf04db ("i2c: acpi: Unbind mux adapters before delete") +Signed-off-by: Sasha Levin +--- + drivers/i2c/i2c-core-acpi.c | 13 +---- + drivers/i2c/i2c-core-base.c | 98 +++++++++++++++++++++++++++++++++++++ + drivers/i2c/i2c-core-of.c | 66 ------------------------- + include/linux/i2c.h | 24 +++++++-- + 4 files changed, 120 insertions(+), 81 deletions(-) + +diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c +index 4b136d8710743..cdc10688d6bdf 100644 +--- a/drivers/i2c/i2c-core-acpi.c ++++ b/drivers/i2c/i2c-core-acpi.c +@@ -393,18 +393,7 @@ EXPORT_SYMBOL_GPL(i2c_acpi_find_adapter_by_handle); + + static struct i2c_client *i2c_acpi_find_client_by_adev(struct acpi_device *adev) + { +- struct device *dev; +- struct i2c_client *client; +- +- dev = bus_find_device_by_acpi_dev(&i2c_bus_type, adev); +- if (!dev) +- return NULL; +- +- client = i2c_verify_client(dev); +- if (!client) +- put_device(dev); +- +- return client; ++ return i2c_find_device_by_fwnode(acpi_fwnode_handle(adev)); + } + + static int i2c_acpi_notify(struct notifier_block *nb, unsigned long value, +diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c +index 8d4fa896d7909..e598cb7b31e18 100644 +--- a/drivers/i2c/i2c-core-base.c ++++ b/drivers/i2c/i2c-core-base.c +@@ -966,6 +966,35 @@ void i2c_unregister_device(struct i2c_client *client) + } + EXPORT_SYMBOL_GPL(i2c_unregister_device); + ++/** ++ * i2c_find_device_by_fwnode() - find an i2c_client for the fwnode ++ * @fwnode: &struct fwnode_handle corresponding to the &struct i2c_client ++ * ++ * Look up and return the &struct i2c_client corresponding to the @fwnode. ++ * If no client can be found, or @fwnode is NULL, this returns NULL. ++ * ++ * The user must call put_device(&client->dev) once done with the i2c client. ++ */ ++struct i2c_client *i2c_find_device_by_fwnode(struct fwnode_handle *fwnode) ++{ ++ struct i2c_client *client; ++ struct device *dev; ++ ++ if (!fwnode) ++ return NULL; ++ ++ dev = bus_find_device_by_fwnode(&i2c_bus_type, fwnode); ++ if (!dev) ++ return NULL; ++ ++ client = i2c_verify_client(dev); ++ if (!client) ++ put_device(dev); ++ ++ return client; ++} ++EXPORT_SYMBOL(i2c_find_device_by_fwnode); ++ + + static const struct i2c_device_id dummy_id[] = { + { "dummy", 0 }, +@@ -1731,6 +1760,75 @@ int devm_i2c_add_adapter(struct device *dev, struct i2c_adapter *adapter) + } + EXPORT_SYMBOL_GPL(devm_i2c_add_adapter); + ++static int i2c_dev_or_parent_fwnode_match(struct device *dev, const void *data) ++{ ++ if (dev_fwnode(dev) == data) ++ return 1; ++ ++ if (dev->parent && dev_fwnode(dev->parent) == data) ++ return 1; ++ ++ return 0; ++} ++ ++/** ++ * i2c_find_adapter_by_fwnode() - find an i2c_adapter for the fwnode ++ * @fwnode: &struct fwnode_handle corresponding to the &struct i2c_adapter ++ * ++ * Look up and return the &struct i2c_adapter corresponding to the @fwnode. ++ * If no adapter can be found, or @fwnode is NULL, this returns NULL. ++ * ++ * The user must call put_device(&adapter->dev) once done with the i2c adapter. ++ */ ++struct i2c_adapter *i2c_find_adapter_by_fwnode(struct fwnode_handle *fwnode) ++{ ++ struct i2c_adapter *adapter; ++ struct device *dev; ++ ++ if (!fwnode) ++ return NULL; ++ ++ dev = bus_find_device(&i2c_bus_type, NULL, fwnode, ++ i2c_dev_or_parent_fwnode_match); ++ if (!dev) ++ return NULL; ++ ++ adapter = i2c_verify_adapter(dev); ++ if (!adapter) ++ put_device(dev); ++ ++ return adapter; ++} ++EXPORT_SYMBOL(i2c_find_adapter_by_fwnode); ++ ++/** ++ * i2c_get_adapter_by_fwnode() - find an i2c_adapter for the fwnode ++ * @fwnode: &struct fwnode_handle corresponding to the &struct i2c_adapter ++ * ++ * Look up and return the &struct i2c_adapter corresponding to the @fwnode, ++ * and increment the adapter module's use count. If no adapter can be found, ++ * or @fwnode is NULL, this returns NULL. ++ * ++ * The user must call i2c_put_adapter(adapter) once done with the i2c adapter. ++ * Note that this is different from i2c_find_adapter_by_node(). ++ */ ++struct i2c_adapter *i2c_get_adapter_by_fwnode(struct fwnode_handle *fwnode) ++{ ++ struct i2c_adapter *adapter; ++ ++ adapter = i2c_find_adapter_by_fwnode(fwnode); ++ if (!adapter) ++ return NULL; ++ ++ if (!try_module_get(adapter->owner)) { ++ put_device(&adapter->dev); ++ adapter = NULL; ++ } ++ ++ return adapter; ++} ++EXPORT_SYMBOL(i2c_get_adapter_by_fwnode); ++ + static void i2c_parse_timing(struct device *dev, char *prop_name, u32 *cur_val_p, + u32 def_val, bool use_def) + { +diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c +index 3ed74aa4b44bb..bce6b796e04c2 100644 +--- a/drivers/i2c/i2c-core-of.c ++++ b/drivers/i2c/i2c-core-of.c +@@ -113,72 +113,6 @@ void of_i2c_register_devices(struct i2c_adapter *adap) + of_node_put(bus); + } + +-static int of_dev_or_parent_node_match(struct device *dev, const void *data) +-{ +- if (dev->of_node == data) +- return 1; +- +- if (dev->parent) +- return dev->parent->of_node == data; +- +- return 0; +-} +- +-/* must call put_device() when done with returned i2c_client device */ +-struct i2c_client *of_find_i2c_device_by_node(struct device_node *node) +-{ +- struct device *dev; +- struct i2c_client *client; +- +- dev = bus_find_device_by_of_node(&i2c_bus_type, node); +- if (!dev) +- return NULL; +- +- client = i2c_verify_client(dev); +- if (!client) +- put_device(dev); +- +- return client; +-} +-EXPORT_SYMBOL(of_find_i2c_device_by_node); +- +-/* must call put_device() when done with returned i2c_adapter device */ +-struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node) +-{ +- struct device *dev; +- struct i2c_adapter *adapter; +- +- dev = bus_find_device(&i2c_bus_type, NULL, node, +- of_dev_or_parent_node_match); +- if (!dev) +- return NULL; +- +- adapter = i2c_verify_adapter(dev); +- if (!adapter) +- put_device(dev); +- +- return adapter; +-} +-EXPORT_SYMBOL(of_find_i2c_adapter_by_node); +- +-/* must call i2c_put_adapter() when done with returned i2c_adapter device */ +-struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node *node) +-{ +- struct i2c_adapter *adapter; +- +- adapter = of_find_i2c_adapter_by_node(node); +- if (!adapter) +- return NULL; +- +- if (!try_module_get(adapter->owner)) { +- put_device(&adapter->dev); +- adapter = NULL; +- } +- +- return adapter; +-} +-EXPORT_SYMBOL(of_get_i2c_adapter_by_node); +- + static const struct of_device_id* + i2c_of_match_device_sysfs(const struct of_device_id *matches, + struct i2c_client *client) +diff --git a/include/linux/i2c.h b/include/linux/i2c.h +index 82c9b643876c9..da35562faaf33 100644 +--- a/include/linux/i2c.h ++++ b/include/linux/i2c.h +@@ -939,15 +939,33 @@ int i2c_handle_smbus_host_notify(struct i2c_adapter *adap, unsigned short addr); + + #endif /* I2C */ + ++/* must call put_device() when done with returned i2c_client device */ ++struct i2c_client *i2c_find_device_by_fwnode(struct fwnode_handle *fwnode); ++ ++/* must call put_device() when done with returned i2c_adapter device */ ++struct i2c_adapter *i2c_find_adapter_by_fwnode(struct fwnode_handle *fwnode); ++ ++/* must call i2c_put_adapter() when done with returned i2c_adapter device */ ++struct i2c_adapter *i2c_get_adapter_by_fwnode(struct fwnode_handle *fwnode); ++ + #if IS_ENABLED(CONFIG_OF) + /* must call put_device() when done with returned i2c_client device */ +-struct i2c_client *of_find_i2c_device_by_node(struct device_node *node); ++static inline struct i2c_client *of_find_i2c_device_by_node(struct device_node *node) ++{ ++ return i2c_find_device_by_fwnode(of_fwnode_handle(node)); ++} + + /* must call put_device() when done with returned i2c_adapter device */ +-struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node); ++static inline struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node) ++{ ++ return i2c_find_adapter_by_fwnode(of_fwnode_handle(node)); ++} + + /* must call i2c_put_adapter() when done with returned i2c_adapter device */ +-struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node *node); ++static inline struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node *node) ++{ ++ return i2c_get_adapter_by_fwnode(of_fwnode_handle(node)); ++} + + const struct of_device_id + *i2c_of_match_device(const struct of_device_id *matches, +-- +2.43.0 + diff --git a/queue-5.10/i2c-core-add-managed-function-for-adding-i2c-adapter.patch b/queue-5.10/i2c-core-add-managed-function-for-adding-i2c-adapter.patch new file mode 100644 index 00000000000..72cd0566206 --- /dev/null +++ b/queue-5.10/i2c-core-add-managed-function-for-adding-i2c-adapter.patch @@ -0,0 +1,78 @@ +From 667f87ed0c24ad7688e80c2cc772e3bdcfc94864 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Apr 2021 19:17:17 +0800 +Subject: i2c: core: add managed function for adding i2c adapters + +From: Yicong Yang + +[ Upstream commit 07740c92ae57ca21204f1e0c6f59272cdf3190cc ] + +Some I2C controller drivers will only unregister the I2C +adapter in their .remove() callback, which can be done +by simply using a managed variant to add the I2C adapter. + +So add the managed functions for adding the I2C adapter. + +Reviewed-by: Andy Shevchenko +Reviewed-by: Dmitry Osipenko +Signed-off-by: Yicong Yang +Signed-off-by: Wolfram Sang +Stable-dep-of: 3f858bbf04db ("i2c: acpi: Unbind mux adapters before delete") +Signed-off-by: Sasha Levin +--- + drivers/i2c/i2c-core-base.c | 26 ++++++++++++++++++++++++++ + include/linux/i2c.h | 1 + + 2 files changed, 27 insertions(+) + +diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c +index e8a89e18c640e..8d4fa896d7909 100644 +--- a/drivers/i2c/i2c-core-base.c ++++ b/drivers/i2c/i2c-core-base.c +@@ -1705,6 +1705,32 @@ void i2c_del_adapter(struct i2c_adapter *adap) + } + EXPORT_SYMBOL(i2c_del_adapter); + ++static void devm_i2c_del_adapter(void *adapter) ++{ ++ i2c_del_adapter(adapter); ++} ++ ++/** ++ * devm_i2c_add_adapter - device-managed variant of i2c_add_adapter() ++ * @dev: managing device for adding this I2C adapter ++ * @adapter: the adapter to add ++ * Context: can sleep ++ * ++ * Add adapter with dynamic bus number, same with i2c_add_adapter() ++ * but the adapter will be auto deleted on driver detach. ++ */ ++int devm_i2c_add_adapter(struct device *dev, struct i2c_adapter *adapter) ++{ ++ int ret; ++ ++ ret = i2c_add_adapter(adapter); ++ if (ret) ++ return ret; ++ ++ return devm_add_action_or_reset(dev, devm_i2c_del_adapter, adapter); ++} ++EXPORT_SYMBOL_GPL(devm_i2c_add_adapter); ++ + static void i2c_parse_timing(struct device *dev, char *prop_name, u32 *cur_val_p, + u32 def_val, bool use_def) + { +diff --git a/include/linux/i2c.h b/include/linux/i2c.h +index a670ae129f4b9..82c9b643876c9 100644 +--- a/include/linux/i2c.h ++++ b/include/linux/i2c.h +@@ -846,6 +846,7 @@ static inline void i2c_mark_adapter_resumed(struct i2c_adapter *adap) + */ + #if IS_ENABLED(CONFIG_I2C) + int i2c_add_adapter(struct i2c_adapter *adap); ++int devm_i2c_add_adapter(struct device *dev, struct i2c_adapter *adapter); + void i2c_del_adapter(struct i2c_adapter *adap); + int i2c_add_numbered_adapter(struct i2c_adapter *adap); + +-- +2.43.0 + diff --git a/queue-5.10/iio-accel-mxc4005-allow-module-autoloading-via-of-co.patch b/queue-5.10/iio-accel-mxc4005-allow-module-autoloading-via-of-co.patch new file mode 100644 index 00000000000..1cb4ce5eeaf --- /dev/null +++ b/queue-5.10/iio-accel-mxc4005-allow-module-autoloading-via-of-co.patch @@ -0,0 +1,51 @@ +From ee3a4a7c1313cc834bae493f306d009d604a52c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Oct 2023 18:39:28 +0200 +Subject: iio: accel: mxc4005: allow module autoloading via OF compatible + +From: Luca Ceresoli + +[ Upstream commit 4d7c16d08d248952c116f2eb9b7b5abc43a19688 ] + +Add OF device table with compatible strings to allow automatic module +loading. + +Signed-off-by: Luca Ceresoli +Reviewed-by: Krzysztof Kozlowski +Link: https://lore.kernel.org/r/20231004-mxc4005-device-tree-support-v1-2-e7c0faea72e4@bootlin.com +Signed-off-by: Jonathan Cameron +Stable-dep-of: 6b8cffdc4a31 ("iio: accel: mxc4005: Reset chip on probe() and resume()") +Signed-off-by: Sasha Levin +--- + drivers/iio/accel/mxc4005.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c +index e0d1491d52b01..558c0e67e10e1 100644 +--- a/drivers/iio/accel/mxc4005.c ++++ b/drivers/iio/accel/mxc4005.c +@@ -492,6 +492,13 @@ static const struct acpi_device_id mxc4005_acpi_match[] = { + }; + MODULE_DEVICE_TABLE(acpi, mxc4005_acpi_match); + ++static const struct of_device_id mxc4005_of_match[] = { ++ { .compatible = "memsic,mxc4005", }, ++ { .compatible = "memsic,mxc6655", }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, mxc4005_of_match); ++ + static const struct i2c_device_id mxc4005_id[] = { + {"mxc4005", 0}, + {"mxc6655", 0}, +@@ -503,6 +510,7 @@ static struct i2c_driver mxc4005_driver = { + .driver = { + .name = MXC4005_DRV_NAME, + .acpi_match_table = ACPI_PTR(mxc4005_acpi_match), ++ .of_match_table = mxc4005_of_match, + }, + .probe = mxc4005_probe, + .id_table = mxc4005_id, +-- +2.43.0 + diff --git a/queue-5.10/iio-accel-mxc4005-reset-chip-on-probe-and-resume.patch b/queue-5.10/iio-accel-mxc4005-reset-chip-on-probe-and-resume.patch new file mode 100644 index 00000000000..e22571dcce3 --- /dev/null +++ b/queue-5.10/iio-accel-mxc4005-reset-chip-on-probe-and-resume.patch @@ -0,0 +1,157 @@ +From 729a03d2d1d16422d82d0bb489b37f376a34a187 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Mar 2024 12:37:00 +0100 +Subject: iio: accel: mxc4005: Reset chip on probe() and resume() + +From: Hans de Goede + +[ Upstream commit 6b8cffdc4a31e4a72f75ecd1bc13fbf0dafee390 ] + +On some designs the chip is not properly reset when powered up at boot or +after a suspend/resume cycle. + +Use the sw-reset feature to ensure that the chip is in a clean state +after probe() / resume() and in the case of resume() restore the settings +(scale, trigger-enabled). + +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218578 +Signed-off-by: Hans de Goede +Link: https://lore.kernel.org/r/20240326113700.56725-3-hdegoede@redhat.com +Cc: +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/accel/mxc4005.c | 68 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 68 insertions(+) + +diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c +index 558c0e67e10e1..b6ed24042386d 100644 +--- a/drivers/iio/accel/mxc4005.c ++++ b/drivers/iio/accel/mxc4005.c +@@ -5,6 +5,7 @@ + * Copyright (c) 2014, Intel Corporation. + */ + ++#include + #include + #include + #include +@@ -36,6 +37,7 @@ + + #define MXC4005_REG_INT_CLR1 0x01 + #define MXC4005_REG_INT_CLR1_BIT_DRDYC 0x01 ++#define MXC4005_REG_INT_CLR1_SW_RST 0x10 + + #define MXC4005_REG_CONTROL 0x0D + #define MXC4005_REG_CONTROL_MASK_FSR GENMASK(6, 5) +@@ -43,6 +45,9 @@ + + #define MXC4005_REG_DEVICE_ID 0x0E + ++/* Datasheet does not specify a reset time, this is a conservative guess */ ++#define MXC4005_RESET_TIME_US 2000 ++ + enum mxc4005_axis { + AXIS_X, + AXIS_Y, +@@ -66,6 +71,8 @@ struct mxc4005_data { + s64 timestamp __aligned(8); + } scan; + bool trigger_enabled; ++ unsigned int control; ++ unsigned int int_mask1; + }; + + /* +@@ -353,6 +360,7 @@ static int mxc4005_set_trigger_state(struct iio_trigger *trig, + return ret; + } + ++ data->int_mask1 = val; + data->trigger_enabled = state; + mutex_unlock(&data->mutex); + +@@ -388,6 +396,13 @@ static int mxc4005_chip_init(struct mxc4005_data *data) + + dev_dbg(data->dev, "MXC4005 chip id %02x\n", reg); + ++ ret = regmap_write(data->regmap, MXC4005_REG_INT_CLR1, ++ MXC4005_REG_INT_CLR1_SW_RST); ++ if (ret < 0) ++ return dev_err_probe(data->dev, ret, "resetting chip\n"); ++ ++ fsleep(MXC4005_RESET_TIME_US); ++ + ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK0, 0); + if (ret < 0) + return dev_err_probe(data->dev, ret, "writing INT_MASK0\n"); +@@ -485,6 +500,58 @@ static int mxc4005_probe(struct i2c_client *client, + return devm_iio_device_register(&client->dev, indio_dev); + } + ++static int mxc4005_suspend(struct device *dev) ++{ ++ struct iio_dev *indio_dev = dev_get_drvdata(dev); ++ struct mxc4005_data *data = iio_priv(indio_dev); ++ int ret; ++ ++ /* Save control to restore it on resume */ ++ ret = regmap_read(data->regmap, MXC4005_REG_CONTROL, &data->control); ++ if (ret < 0) ++ dev_err(data->dev, "failed to read reg_control\n"); ++ ++ return ret; ++} ++ ++static int mxc4005_resume(struct device *dev) ++{ ++ struct iio_dev *indio_dev = dev_get_drvdata(dev); ++ struct mxc4005_data *data = iio_priv(indio_dev); ++ int ret; ++ ++ ret = regmap_write(data->regmap, MXC4005_REG_INT_CLR1, ++ MXC4005_REG_INT_CLR1_SW_RST); ++ if (ret) { ++ dev_err(data->dev, "failed to reset chip: %d\n", ret); ++ return ret; ++ } ++ ++ fsleep(MXC4005_RESET_TIME_US); ++ ++ ret = regmap_write(data->regmap, MXC4005_REG_CONTROL, data->control); ++ if (ret) { ++ dev_err(data->dev, "failed to restore control register\n"); ++ return ret; ++ } ++ ++ ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK0, 0); ++ if (ret) { ++ dev_err(data->dev, "failed to restore interrupt 0 mask\n"); ++ return ret; ++ } ++ ++ ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1, data->int_mask1); ++ if (ret) { ++ dev_err(data->dev, "failed to restore interrupt 1 mask\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static DEFINE_SIMPLE_DEV_PM_OPS(mxc4005_pm_ops, mxc4005_suspend, mxc4005_resume); ++ + static const struct acpi_device_id mxc4005_acpi_match[] = { + {"MXC4005", 0}, + {"MXC6655", 0}, +@@ -511,6 +578,7 @@ static struct i2c_driver mxc4005_driver = { + .name = MXC4005_DRV_NAME, + .acpi_match_table = ACPI_PTR(mxc4005_acpi_match), + .of_match_table = mxc4005_of_match, ++ .pm = pm_sleep_ptr(&mxc4005_pm_ops), + }, + .probe = mxc4005_probe, + .id_table = mxc4005_id, +-- +2.43.0 + diff --git a/queue-5.10/ipv6-fix-possible-race-in-__fib6_drop_pcpu_from.patch b/queue-5.10/ipv6-fix-possible-race-in-__fib6_drop_pcpu_from.patch new file mode 100644 index 00000000000..6dfe19ce6b7 --- /dev/null +++ b/queue-5.10/ipv6-fix-possible-race-in-__fib6_drop_pcpu_from.patch @@ -0,0 +1,130 @@ +From c8f875a80d17077012ae2e2652b05b3133c20b73 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Jun 2024 19:35:49 +0000 +Subject: ipv6: fix possible race in __fib6_drop_pcpu_from() + +From: Eric Dumazet + +[ Upstream commit b01e1c030770ff3b4fe37fc7cc6bca03f594133f ] + +syzbot found a race in __fib6_drop_pcpu_from() [1] + +If compiler reads more than once (*ppcpu_rt), +second read could read NULL, if another cpu clears +the value in rt6_get_pcpu_route(). + +Add a READ_ONCE() to prevent this race. + +Also add rcu_read_lock()/rcu_read_unlock() because +we rely on RCU protection while dereferencing pcpu_rt. + +[1] + +Oops: general protection fault, probably for non-canonical address 0xdffffc0000000012: 0000 [#1] PREEMPT SMP KASAN PTI +KASAN: null-ptr-deref in range [0x0000000000000090-0x0000000000000097] +CPU: 0 PID: 7543 Comm: kworker/u8:17 Not tainted 6.10.0-rc1-syzkaller-00013-g2bfcfd584ff5 #0 +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 04/02/2024 +Workqueue: netns cleanup_net + RIP: 0010:__fib6_drop_pcpu_from.part.0+0x10a/0x370 net/ipv6/ip6_fib.c:984 +Code: f8 48 c1 e8 03 80 3c 28 00 0f 85 16 02 00 00 4d 8b 3f 4d 85 ff 74 31 e8 74 a7 fa f7 49 8d bf 90 00 00 00 48 89 f8 48 c1 e8 03 <80> 3c 28 00 0f 85 1e 02 00 00 49 8b 87 90 00 00 00 48 8b 0c 24 48 +RSP: 0018:ffffc900040df070 EFLAGS: 00010206 +RAX: 0000000000000012 RBX: 0000000000000001 RCX: ffffffff89932e16 +RDX: ffff888049dd1e00 RSI: ffffffff89932d7c RDI: 0000000000000091 +RBP: dffffc0000000000 R08: 0000000000000005 R09: 0000000000000007 +R10: 0000000000000001 R11: 0000000000000006 R12: ffff88807fa080b8 +R13: fffffbfff1a9a07d R14: ffffed100ff41022 R15: 0000000000000001 +FS: 0000000000000000(0000) GS:ffff8880b9200000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 0000001b32c26000 CR3: 000000005d56e000 CR4: 00000000003526f0 +DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 +DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 +Call Trace: + + __fib6_drop_pcpu_from net/ipv6/ip6_fib.c:966 [inline] + fib6_drop_pcpu_from net/ipv6/ip6_fib.c:1027 [inline] + fib6_purge_rt+0x7f2/0x9f0 net/ipv6/ip6_fib.c:1038 + fib6_del_route net/ipv6/ip6_fib.c:1998 [inline] + fib6_del+0xa70/0x17b0 net/ipv6/ip6_fib.c:2043 + fib6_clean_node+0x426/0x5b0 net/ipv6/ip6_fib.c:2205 + fib6_walk_continue+0x44f/0x8d0 net/ipv6/ip6_fib.c:2127 + fib6_walk+0x182/0x370 net/ipv6/ip6_fib.c:2175 + fib6_clean_tree+0xd7/0x120 net/ipv6/ip6_fib.c:2255 + __fib6_clean_all+0x100/0x2d0 net/ipv6/ip6_fib.c:2271 + rt6_sync_down_dev net/ipv6/route.c:4906 [inline] + rt6_disable_ip+0x7ed/0xa00 net/ipv6/route.c:4911 + addrconf_ifdown.isra.0+0x117/0x1b40 net/ipv6/addrconf.c:3855 + addrconf_notify+0x223/0x19e0 net/ipv6/addrconf.c:3778 + notifier_call_chain+0xb9/0x410 kernel/notifier.c:93 + call_netdevice_notifiers_info+0xbe/0x140 net/core/dev.c:1992 + call_netdevice_notifiers_extack net/core/dev.c:2030 [inline] + call_netdevice_notifiers net/core/dev.c:2044 [inline] + dev_close_many+0x333/0x6a0 net/core/dev.c:1585 + unregister_netdevice_many_notify+0x46d/0x19f0 net/core/dev.c:11193 + unregister_netdevice_many net/core/dev.c:11276 [inline] + default_device_exit_batch+0x85b/0xae0 net/core/dev.c:11759 + ops_exit_list+0x128/0x180 net/core/net_namespace.c:178 + cleanup_net+0x5b7/0xbf0 net/core/net_namespace.c:640 + process_one_work+0x9fb/0x1b60 kernel/workqueue.c:3231 + process_scheduled_works kernel/workqueue.c:3312 [inline] + worker_thread+0x6c8/0xf70 kernel/workqueue.c:3393 + kthread+0x2c1/0x3a0 kernel/kthread.c:389 + ret_from_fork+0x45/0x80 arch/x86/kernel/process.c:147 + ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:244 + +Fixes: d52d3997f843 ("ipv6: Create percpu rt6_info") +Signed-off-by: Eric Dumazet +Cc: Martin KaFai Lau +Link: https://lore.kernel.org/r/20240604193549.981839-1-edumazet@google.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/ipv6/ip6_fib.c | 6 +++++- + net/ipv6/route.c | 1 + + 2 files changed, 6 insertions(+), 1 deletion(-) + +diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c +index b79e571e5a863..83f15e930b57a 100644 +--- a/net/ipv6/ip6_fib.c ++++ b/net/ipv6/ip6_fib.c +@@ -959,6 +959,7 @@ static void __fib6_drop_pcpu_from(struct fib6_nh *fib6_nh, + if (!fib6_nh->rt6i_pcpu) + return; + ++ rcu_read_lock(); + /* release the reference to this fib entry from + * all of its cached pcpu routes + */ +@@ -967,7 +968,9 @@ static void __fib6_drop_pcpu_from(struct fib6_nh *fib6_nh, + struct rt6_info *pcpu_rt; + + ppcpu_rt = per_cpu_ptr(fib6_nh->rt6i_pcpu, cpu); +- pcpu_rt = *ppcpu_rt; ++ ++ /* Paired with xchg() in rt6_get_pcpu_route() */ ++ pcpu_rt = READ_ONCE(*ppcpu_rt); + + /* only dropping the 'from' reference if the cached route + * is using 'match'. The cached pcpu_rt->from only changes +@@ -981,6 +984,7 @@ static void __fib6_drop_pcpu_from(struct fib6_nh *fib6_nh, + fib6_info_release(from); + } + } ++ rcu_read_unlock(); + } + + struct fib6_nh_pcpu_arg { +diff --git a/net/ipv6/route.c b/net/ipv6/route.c +index 88f96241ca971..62eaaf9532e1c 100644 +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -1396,6 +1396,7 @@ static struct rt6_info *rt6_get_pcpu_route(const struct fib6_result *res) + struct rt6_info *prev, **p; + + p = this_cpu_ptr(res->nh->rt6i_pcpu); ++ /* Paired with READ_ONCE() in __fib6_drop_pcpu_from() */ + prev = xchg(p, NULL); + if (prev) { + dst_dev_put(&prev->dst); +-- +2.43.0 + diff --git a/queue-5.10/ipv6-sr-block-bh-in-seg6_output_core-and-seg6_input_.patch b/queue-5.10/ipv6-sr-block-bh-in-seg6_output_core-and-seg6_input_.patch new file mode 100644 index 00000000000..935ed9b9334 --- /dev/null +++ b/queue-5.10/ipv6-sr-block-bh-in-seg6_output_core-and-seg6_input_.patch @@ -0,0 +1,95 @@ +From 54c991b2dc02f4985f90e86e6745db02f791bf74 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 May 2024 13:26:34 +0000 +Subject: ipv6: sr: block BH in seg6_output_core() and seg6_input_core() + +From: Eric Dumazet + +[ Upstream commit c0b98ac1cc104f48763cdb27b1e9ac25fd81fc90 ] + +As explained in commit 1378817486d6 ("tipc: block BH +before using dst_cache"), net/core/dst_cache.c +helpers need to be called with BH disabled. + +Disabling preemption in seg6_output_core() is not good enough, +because seg6_output_core() is called from process context, +lwtunnel_output() only uses rcu_read_lock(). + +We might be interrupted by a softirq, re-enter seg6_output_core() +and corrupt dst_cache data structures. + +Fix the race by using local_bh_disable() instead of +preempt_disable(). + +Apply a similar change in seg6_input_core(). + +Fixes: fa79581ea66c ("ipv6: sr: fix several BUGs when preemption is enabled") +Fixes: 6c8702c60b88 ("ipv6: sr: add support for SRH encapsulation and injection with lwtunnels") +Signed-off-by: Eric Dumazet +Cc: David Lebrun +Acked-by: Paolo Abeni +Link: https://lore.kernel.org/r/20240531132636.2637995-4-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/seg6_iptunnel.c | 14 ++++++-------- + 1 file changed, 6 insertions(+), 8 deletions(-) + +diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c +index 40ac23242c378..a73840da34ed9 100644 +--- a/net/ipv6/seg6_iptunnel.c ++++ b/net/ipv6/seg6_iptunnel.c +@@ -325,9 +325,8 @@ static int seg6_input(struct sk_buff *skb) + + slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate); + +- preempt_disable(); ++ local_bh_disable(); + dst = dst_cache_get(&slwt->cache); +- preempt_enable(); + + skb_dst_drop(skb); + +@@ -335,14 +334,13 @@ static int seg6_input(struct sk_buff *skb) + ip6_route_input(skb); + dst = skb_dst(skb); + if (!dst->error) { +- preempt_disable(); + dst_cache_set_ip6(&slwt->cache, dst, + &ipv6_hdr(skb)->saddr); +- preempt_enable(); + } + } else { + skb_dst_set(skb, dst); + } ++ local_bh_enable(); + + err = skb_cow_head(skb, LL_RESERVED_SPACE(dst->dev)); + if (unlikely(err)) +@@ -364,9 +362,9 @@ static int seg6_output(struct net *net, struct sock *sk, struct sk_buff *skb) + + slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate); + +- preempt_disable(); ++ local_bh_disable(); + dst = dst_cache_get(&slwt->cache); +- preempt_enable(); ++ local_bh_enable(); + + if (unlikely(!dst)) { + struct ipv6hdr *hdr = ipv6_hdr(skb); +@@ -386,9 +384,9 @@ static int seg6_output(struct net *net, struct sock *sk, struct sk_buff *skb) + goto drop; + } + +- preempt_disable(); ++ local_bh_disable(); + dst_cache_set_ip6(&slwt->cache, dst, &fl6.saddr); +- preempt_enable(); ++ local_bh_enable(); + } + + skb_dst_drop(skb); +-- +2.43.0 + diff --git a/queue-5.10/mmc-davinci-don-t-strip-remove-function-when-driver-.patch b/queue-5.10/mmc-davinci-don-t-strip-remove-function-when-driver-.patch new file mode 100644 index 00000000000..e3176ad8a0e --- /dev/null +++ b/queue-5.10/mmc-davinci-don-t-strip-remove-function-when-driver-.patch @@ -0,0 +1,59 @@ +From 68ca88e8d3f0c5a1d9054333d17d729b46faa870 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 24 Mar 2024 12:40:17 +0100 +Subject: mmc: davinci: Don't strip remove function when driver is builtin +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Uwe Kleine-König + +[ Upstream commit 55c421b364482b61c4c45313a535e61ed5ae4ea3 ] + +Using __exit for the remove function results in the remove callback being +discarded with CONFIG_MMC_DAVINCI=y. When such a device gets unbound (e.g. +using sysfs or hotplug), the driver is just removed without the cleanup +being performed. This results in resource leaks. Fix it by compiling in the +remove callback unconditionally. + +This also fixes a W=1 modpost warning: + +WARNING: modpost: drivers/mmc/host/davinci_mmc: section mismatch in +reference: davinci_mmcsd_driver+0x10 (section: .data) -> +davinci_mmcsd_remove (section: .exit.text) + +Fixes: b4cff4549b7a ("DaVinci: MMC: MMC/SD controller driver for DaVinci family") +Signed-off-by: Uwe Kleine-König +Cc: stable@vger.kernel.org +Link: https://lore.kernel.org/r/20240324114017.231936-2-u.kleine-koenig@pengutronix.de +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + drivers/mmc/host/davinci_mmc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c +index b597abd79cfce..97fc4d4c496b7 100644 +--- a/drivers/mmc/host/davinci_mmc.c ++++ b/drivers/mmc/host/davinci_mmc.c +@@ -1347,7 +1347,7 @@ static int davinci_mmcsd_probe(struct platform_device *pdev) + return ret; + } + +-static void __exit davinci_mmcsd_remove(struct platform_device *pdev) ++static void davinci_mmcsd_remove(struct platform_device *pdev) + { + struct mmc_davinci_host *host = platform_get_drvdata(pdev); + +@@ -1402,7 +1402,7 @@ static struct platform_driver davinci_mmcsd_driver = { + .of_match_table = davinci_mmc_dt_ids, + }, + .probe = davinci_mmcsd_probe, +- .remove_new = __exit_p(davinci_mmcsd_remove), ++ .remove_new = davinci_mmcsd_remove, + .id_table = davinci_mmc_devtype, + }; + +-- +2.43.0 + diff --git a/queue-5.10/mmc-davinci_mmc-convert-to-platform-remove-callback-.patch b/queue-5.10/mmc-davinci_mmc-convert-to-platform-remove-callback-.patch new file mode 100644 index 00000000000..0860b63e7bd --- /dev/null +++ b/queue-5.10/mmc-davinci_mmc-convert-to-platform-remove-callback-.patch @@ -0,0 +1,67 @@ +From b15fd216c538118e033889ae3b410236399e6f4a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Jul 2023 14:59:56 +0800 +Subject: mmc: davinci_mmc: Convert to platform remove callback returning void +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yangtao Li + +[ Upstream commit bc1711e8332da03648d8fe1950189237e66313af ] + +The .remove() callback for a platform driver returns an int which makes +many driver authors wrongly assume it's possible to do error handling by +returning an error code. However the value returned is (mostly) ignored +and this typically results in resource leaks. To improve here there is a +quest to make the remove callback return void. In the first step of this +quest all drivers are converted to .remove_new() which already returns +void. + +Trivially convert this driver from always returning zero in the remove +callback to the void returning variant. + +Cc: Uwe Kleine-König +Signed-off-by: Yangtao Li +Link: https://lore.kernel.org/r/20230727070051.17778-7-frank.li@vivo.com +Signed-off-by: Ulf Hansson +Stable-dep-of: 55c421b36448 ("mmc: davinci: Don't strip remove function when driver is builtin") +Signed-off-by: Sasha Levin +--- + drivers/mmc/host/davinci_mmc.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c +index 647928ab00a30..b597abd79cfce 100644 +--- a/drivers/mmc/host/davinci_mmc.c ++++ b/drivers/mmc/host/davinci_mmc.c +@@ -1347,7 +1347,7 @@ static int davinci_mmcsd_probe(struct platform_device *pdev) + return ret; + } + +-static int __exit davinci_mmcsd_remove(struct platform_device *pdev) ++static void __exit davinci_mmcsd_remove(struct platform_device *pdev) + { + struct mmc_davinci_host *host = platform_get_drvdata(pdev); + +@@ -1356,8 +1356,6 @@ static int __exit davinci_mmcsd_remove(struct platform_device *pdev) + davinci_release_dma_channels(host); + clk_disable_unprepare(host->clk); + mmc_free_host(host->mmc); +- +- return 0; + } + + #ifdef CONFIG_PM +@@ -1404,7 +1402,7 @@ static struct platform_driver davinci_mmcsd_driver = { + .of_match_table = davinci_mmc_dt_ids, + }, + .probe = davinci_mmcsd_probe, +- .remove = __exit_p(davinci_mmcsd_remove), ++ .remove_new = __exit_p(davinci_mmcsd_remove), + .id_table = davinci_mmc_devtype, + }; + +-- +2.43.0 + diff --git a/queue-5.10/mmc-jz4740-use-the-new-pm-macros.patch b/queue-5.10/mmc-jz4740-use-the-new-pm-macros.patch new file mode 100644 index 00000000000..313e5843408 --- /dev/null +++ b/queue-5.10/mmc-jz4740-use-the-new-pm-macros.patch @@ -0,0 +1,63 @@ +From 374615891aef31c57d972154f7c623573251ab37 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Dec 2021 00:21:01 +0000 +Subject: mmc: jz4740: Use the new PM macros + +From: Paul Cercueil + +[ Upstream commit e0d64ecc621715e9c7807e952b68475c62bbf630 ] + + - Use DEFINE_SIMPLE_DEV_PM_OPS() instead of the SIMPLE_DEV_PM_OPS() + macro. This makes it possible to remove the __maybe_unused flags + on the callback functions. + + - Since we only have callbacks for suspend/resume, we can conditionally + compile the dev_pm_ops structure for when CONFIG_PM_SLEEP is enabled; + so use the pm_sleep_ptr() macro instead of pm_ptr(). + +Signed-off-by: Paul Cercueil +Acked-by: Ulf Hansson +Signed-off-by: Rafael J. Wysocki +Stable-dep-of: 6b8cffdc4a31 ("iio: accel: mxc4005: Reset chip on probe() and resume()") +Signed-off-by: Sasha Levin +--- + drivers/mmc/host/jz4740_mmc.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c +index 62d00232f85ea..95ef64a103127 100644 +--- a/drivers/mmc/host/jz4740_mmc.c ++++ b/drivers/mmc/host/jz4740_mmc.c +@@ -1136,17 +1136,17 @@ static int jz4740_mmc_remove(struct platform_device *pdev) + return 0; + } + +-static int __maybe_unused jz4740_mmc_suspend(struct device *dev) ++static int jz4740_mmc_suspend(struct device *dev) + { + return pinctrl_pm_select_sleep_state(dev); + } + +-static int __maybe_unused jz4740_mmc_resume(struct device *dev) ++static int jz4740_mmc_resume(struct device *dev) + { + return pinctrl_select_default_state(dev); + } + +-static SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend, ++DEFINE_SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend, + jz4740_mmc_resume); + + static struct platform_driver jz4740_mmc_driver = { +@@ -1156,7 +1156,7 @@ static struct platform_driver jz4740_mmc_driver = { + .name = "jz4740-mmc", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .of_match_table = of_match_ptr(jz4740_mmc_of_match), +- .pm = pm_ptr(&jz4740_mmc_pm_ops), ++ .pm = pm_sleep_ptr(&jz4740_mmc_pm_ops), + }, + }; + +-- +2.43.0 + diff --git a/queue-5.10/mmc-mxc-use-the-new-pm-macros.patch b/queue-5.10/mmc-mxc-use-the-new-pm-macros.patch new file mode 100644 index 00000000000..d83e751a965 --- /dev/null +++ b/queue-5.10/mmc-mxc-use-the-new-pm-macros.patch @@ -0,0 +1,60 @@ +From 01e68c65285851b087e171ee5fdc183704e28c8c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Dec 2021 00:21:02 +0000 +Subject: mmc: mxc: Use the new PM macros + +From: Paul Cercueil + +[ Upstream commit 2cdbd92c2d1dff07ad56c39f5857ee644bbd2c8a ] + +Use DEFINE_SIMPLE_DEV_PM_OPS() instead of the SIMPLE_DEV_PM_OPS() +macro, along with using pm_sleep_ptr() as this driver doesn't handle +runtime PM. + +This makes it possible to remove the #ifdef CONFIG_PM guard around +the suspend/resume functions. + +Signed-off-by: Paul Cercueil +Acked-by: Ulf Hansson +Signed-off-by: Rafael J. Wysocki +Stable-dep-of: 6b8cffdc4a31 ("iio: accel: mxc4005: Reset chip on probe() and resume()") +Signed-off-by: Sasha Levin +--- + drivers/mmc/host/mxcmmc.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c +index 93a105b075645..a68c21506967f 100644 +--- a/drivers/mmc/host/mxcmmc.c ++++ b/drivers/mmc/host/mxcmmc.c +@@ -1209,7 +1209,6 @@ static int mxcmci_remove(struct platform_device *pdev) + return 0; + } + +-#ifdef CONFIG_PM_SLEEP + static int mxcmci_suspend(struct device *dev) + { + struct mmc_host *mmc = dev_get_drvdata(dev); +@@ -1236,9 +1235,8 @@ static int mxcmci_resume(struct device *dev) + + return ret; + } +-#endif + +-static SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume); ++DEFINE_SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume); + + static struct platform_driver mxcmci_driver = { + .probe = mxcmci_probe, +@@ -1247,7 +1245,7 @@ static struct platform_driver mxcmci_driver = { + .driver = { + .name = DRIVER_NAME, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, +- .pm = &mxcmci_pm_ops, ++ .pm = pm_sleep_ptr(&mxcmci_pm_ops), + .of_match_table = mxcmci_of_match, + } + }; +-- +2.43.0 + diff --git a/queue-5.10/net-ncsi-add-ncsi-intel-oem-command-to-keep-phy-up.patch b/queue-5.10/net-ncsi-add-ncsi-intel-oem-command-to-keep-phy-up.patch new file mode 100644 index 00000000000..936283e417b --- /dev/null +++ b/queue-5.10/net-ncsi-add-ncsi-intel-oem-command-to-keep-phy-up.patch @@ -0,0 +1,137 @@ +From b0a3b3c8bc325c609bfcf492eed91d0d4aa695ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jul 2021 15:27:53 +0300 +Subject: net/ncsi: add NCSI Intel OEM command to keep PHY up + +From: Ivan Mikhaylov + +[ Upstream commit abd2fddc94a619b96bf41c60429d4c32bd118e17 ] + +This allows to keep PHY link up and prevents any channel resets during +the host load. + +It is KEEP_PHY_LINK_UP option(Veto bit) in i210 datasheet which +block PHY reset and power state changes. + +Signed-off-by: Ivan Mikhaylov +Signed-off-by: David S. Miller +Stable-dep-of: e85e271dec02 ("net/ncsi: Fix the multi thread manner of NCSI driver") +Signed-off-by: Sasha Levin +--- + net/ncsi/Kconfig | 6 ++++++ + net/ncsi/internal.h | 5 +++++ + net/ncsi/ncsi-manage.c | 45 ++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 56 insertions(+) + +diff --git a/net/ncsi/Kconfig b/net/ncsi/Kconfig +index 93309081f5a40..ea1dd32b6b1f6 100644 +--- a/net/ncsi/Kconfig ++++ b/net/ncsi/Kconfig +@@ -17,3 +17,9 @@ config NCSI_OEM_CMD_GET_MAC + help + This allows to get MAC address from NCSI firmware and set them back to + controller. ++config NCSI_OEM_CMD_KEEP_PHY ++ bool "Keep PHY Link up" ++ depends on NET_NCSI ++ help ++ This allows to keep PHY link up and prevents any channel resets during ++ the host load. +diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h +index ec765f2a75691..1e3e587d04d39 100644 +--- a/net/ncsi/internal.h ++++ b/net/ncsi/internal.h +@@ -78,6 +78,9 @@ enum { + /* OEM Vendor Manufacture ID */ + #define NCSI_OEM_MFR_MLX_ID 0x8119 + #define NCSI_OEM_MFR_BCM_ID 0x113d ++#define NCSI_OEM_MFR_INTEL_ID 0x157 ++/* Intel specific OEM command */ ++#define NCSI_OEM_INTEL_CMD_KEEP_PHY 0x20 /* CMD ID for Keep PHY up */ + /* Broadcom specific OEM Command */ + #define NCSI_OEM_BCM_CMD_GMA 0x01 /* CMD ID for Get MAC */ + /* Mellanox specific OEM Command */ +@@ -86,6 +89,7 @@ enum { + #define NCSI_OEM_MLX_CMD_SMAF 0x01 /* CMD ID for Set MC Affinity */ + #define NCSI_OEM_MLX_CMD_SMAF_PARAM 0x07 /* Parameter for SMAF */ + /* OEM Command payload lengths*/ ++#define NCSI_OEM_INTEL_CMD_KEEP_PHY_LEN 7 + #define NCSI_OEM_BCM_CMD_GMA_LEN 12 + #define NCSI_OEM_MLX_CMD_GMA_LEN 8 + #define NCSI_OEM_MLX_CMD_SMAF_LEN 60 +@@ -274,6 +278,7 @@ enum { + ncsi_dev_state_probe_mlx_gma, + ncsi_dev_state_probe_mlx_smaf, + ncsi_dev_state_probe_cis, ++ ncsi_dev_state_probe_keep_phy, + ncsi_dev_state_probe_gvi, + ncsi_dev_state_probe_gc, + ncsi_dev_state_probe_gls, +diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c +index ffff8da707b8c..06ad7db553fb5 100644 +--- a/net/ncsi/ncsi-manage.c ++++ b/net/ncsi/ncsi-manage.c +@@ -689,6 +689,35 @@ static int set_one_vid(struct ncsi_dev_priv *ndp, struct ncsi_channel *nc, + return 0; + } + ++#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_KEEP_PHY) ++ ++static int ncsi_oem_keep_phy_intel(struct ncsi_cmd_arg *nca) ++{ ++ unsigned char data[NCSI_OEM_INTEL_CMD_KEEP_PHY_LEN]; ++ int ret = 0; ++ ++ nca->payload = NCSI_OEM_INTEL_CMD_KEEP_PHY_LEN; ++ ++ memset(data, 0, NCSI_OEM_INTEL_CMD_KEEP_PHY_LEN); ++ *(unsigned int *)data = ntohl((__force __be32)NCSI_OEM_MFR_INTEL_ID); ++ ++ data[4] = NCSI_OEM_INTEL_CMD_KEEP_PHY; ++ ++ /* PHY Link up attribute */ ++ data[6] = 0x1; ++ ++ nca->data = data; ++ ++ ret = ncsi_xmit_cmd(nca); ++ if (ret) ++ netdev_err(nca->ndp->ndev.dev, ++ "NCSI: Failed to transmit cmd 0x%x during configure\n", ++ nca->type); ++ return ret; ++} ++ ++#endif ++ + #if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC) + + /* NCSI OEM Command APIs */ +@@ -1391,8 +1420,24 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp) + goto error; + } + ++ nd->state = ncsi_dev_state_probe_gvi; ++ if (IS_ENABLED(CONFIG_NCSI_OEM_CMD_KEEP_PHY)) ++ nd->state = ncsi_dev_state_probe_keep_phy; ++ break; ++#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_KEEP_PHY) ++ case ncsi_dev_state_probe_keep_phy: ++ ndp->pending_req_num = 1; ++ ++ nca.type = NCSI_PKT_CMD_OEM; ++ nca.package = ndp->active_package->id; ++ nca.channel = 0; ++ ret = ncsi_oem_keep_phy_intel(&nca); ++ if (ret) ++ goto error; ++ + nd->state = ncsi_dev_state_probe_gvi; + break; ++#endif /* CONFIG_NCSI_OEM_CMD_KEEP_PHY */ + case ncsi_dev_state_probe_gvi: + case ncsi_dev_state_probe_gc: + case ncsi_dev_state_probe_gls: +-- +2.43.0 + diff --git a/queue-5.10/net-ncsi-fix-the-multi-thread-manner-of-ncsi-driver.patch b/queue-5.10/net-ncsi-fix-the-multi-thread-manner-of-ncsi-driver.patch new file mode 100644 index 00000000000..f5ae5be0176 --- /dev/null +++ b/queue-5.10/net-ncsi-fix-the-multi-thread-manner-of-ncsi-driver.patch @@ -0,0 +1,220 @@ +From a7fea049a76381cf0ad437fd1ccd549133021120 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 May 2024 14:58:55 +0800 +Subject: net/ncsi: Fix the multi thread manner of NCSI driver + +From: DelphineCCChiu + +[ Upstream commit e85e271dec0270982afed84f70dc37703fcc1d52 ] + +Currently NCSI driver will send several NCSI commands back to back without +waiting the response of previous NCSI command or timeout in some state +when NIC have multi channel. This operation against the single thread +manner defined by NCSI SPEC(section 6.3.2.3 in DSP0222_1.1.1) + +According to NCSI SPEC(section 6.2.13.1 in DSP0222_1.1.1), we should probe +one channel at a time by sending NCSI commands (Clear initial state, Get +version ID, Get capabilities...), than repeat this steps until the max +number of channels which we got from NCSI command (Get capabilities) has +been probed. + +Fixes: e6f44ed6d04d ("net/ncsi: Package and channel management") +Signed-off-by: DelphineCCChiu +Link: https://lore.kernel.org/r/20240529065856.825241-1-delphine_cc_chiu@wiwynn.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ncsi/internal.h | 2 ++ + net/ncsi/ncsi-manage.c | 73 +++++++++++++++++++++--------------------- + net/ncsi/ncsi-rsp.c | 4 ++- + 3 files changed, 41 insertions(+), 38 deletions(-) + +diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h +index 1e3e587d04d39..dea60e25e8607 100644 +--- a/net/ncsi/internal.h ++++ b/net/ncsi/internal.h +@@ -322,6 +322,7 @@ struct ncsi_dev_priv { + spinlock_t lock; /* Protect the NCSI device */ + unsigned int package_probe_id;/* Current ID during probe */ + unsigned int package_num; /* Number of packages */ ++ unsigned int channel_probe_id;/* Current cahnnel ID during probe */ + struct list_head packages; /* List of packages */ + struct ncsi_channel *hot_channel; /* Channel was ever active */ + struct ncsi_request requests[256]; /* Request table */ +@@ -340,6 +341,7 @@ struct ncsi_dev_priv { + bool multi_package; /* Enable multiple packages */ + bool mlx_multi_host; /* Enable multi host Mellanox */ + u32 package_whitelist; /* Packages to configure */ ++ unsigned char channel_count; /* Num of channels to probe */ + }; + + struct ncsi_cmd_arg { +diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c +index d2f8155af53e3..bb3248214746a 100644 +--- a/net/ncsi/ncsi-manage.c ++++ b/net/ncsi/ncsi-manage.c +@@ -510,17 +510,19 @@ static void ncsi_suspend_channel(struct ncsi_dev_priv *ndp) + + break; + case ncsi_dev_state_suspend_gls: +- ndp->pending_req_num = np->channel_num; ++ ndp->pending_req_num = 1; + + nca.type = NCSI_PKT_CMD_GLS; + nca.package = np->id; ++ nca.channel = ndp->channel_probe_id; ++ ret = ncsi_xmit_cmd(&nca); ++ if (ret) ++ goto error; ++ ndp->channel_probe_id++; + +- nd->state = ncsi_dev_state_suspend_dcnt; +- NCSI_FOR_EACH_CHANNEL(np, nc) { +- nca.channel = nc->id; +- ret = ncsi_xmit_cmd(&nca); +- if (ret) +- goto error; ++ if (ndp->channel_probe_id == ndp->channel_count) { ++ ndp->channel_probe_id = 0; ++ nd->state = ncsi_dev_state_suspend_dcnt; + } + + break; +@@ -1317,7 +1319,6 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp) + { + struct ncsi_dev *nd = &ndp->ndev; + struct ncsi_package *np; +- struct ncsi_channel *nc; + struct ncsi_cmd_arg nca; + unsigned char index; + int ret; +@@ -1395,23 +1396,6 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp) + + nd->state = ncsi_dev_state_probe_cis; + break; +- case ncsi_dev_state_probe_cis: +- ndp->pending_req_num = NCSI_RESERVED_CHANNEL; +- +- /* Clear initial state */ +- nca.type = NCSI_PKT_CMD_CIS; +- nca.package = ndp->active_package->id; +- for (index = 0; index < NCSI_RESERVED_CHANNEL; index++) { +- nca.channel = index; +- ret = ncsi_xmit_cmd(&nca); +- if (ret) +- goto error; +- } +- +- nd->state = ncsi_dev_state_probe_gvi; +- if (IS_ENABLED(CONFIG_NCSI_OEM_CMD_KEEP_PHY)) +- nd->state = ncsi_dev_state_probe_keep_phy; +- break; + case ncsi_dev_state_probe_keep_phy: + ndp->pending_req_num = 1; + +@@ -1424,14 +1408,17 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp) + + nd->state = ncsi_dev_state_probe_gvi; + break; ++ case ncsi_dev_state_probe_cis: + case ncsi_dev_state_probe_gvi: + case ncsi_dev_state_probe_gc: + case ncsi_dev_state_probe_gls: + np = ndp->active_package; +- ndp->pending_req_num = np->channel_num; ++ ndp->pending_req_num = 1; + +- /* Retrieve version, capability or link status */ +- if (nd->state == ncsi_dev_state_probe_gvi) ++ /* Clear initial state Retrieve version, capability or link status */ ++ if (nd->state == ncsi_dev_state_probe_cis) ++ nca.type = NCSI_PKT_CMD_CIS; ++ else if (nd->state == ncsi_dev_state_probe_gvi) + nca.type = NCSI_PKT_CMD_GVI; + else if (nd->state == ncsi_dev_state_probe_gc) + nca.type = NCSI_PKT_CMD_GC; +@@ -1439,19 +1426,29 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp) + nca.type = NCSI_PKT_CMD_GLS; + + nca.package = np->id; +- NCSI_FOR_EACH_CHANNEL(np, nc) { +- nca.channel = nc->id; +- ret = ncsi_xmit_cmd(&nca); +- if (ret) +- goto error; +- } ++ nca.channel = ndp->channel_probe_id; + +- if (nd->state == ncsi_dev_state_probe_gvi) ++ ret = ncsi_xmit_cmd(&nca); ++ if (ret) ++ goto error; ++ ++ if (nd->state == ncsi_dev_state_probe_cis) { ++ nd->state = ncsi_dev_state_probe_gvi; ++ if (IS_ENABLED(CONFIG_NCSI_OEM_CMD_KEEP_PHY) && ndp->channel_probe_id == 0) ++ nd->state = ncsi_dev_state_probe_keep_phy; ++ } else if (nd->state == ncsi_dev_state_probe_gvi) { + nd->state = ncsi_dev_state_probe_gc; +- else if (nd->state == ncsi_dev_state_probe_gc) ++ } else if (nd->state == ncsi_dev_state_probe_gc) { + nd->state = ncsi_dev_state_probe_gls; +- else ++ } else { ++ nd->state = ncsi_dev_state_probe_cis; ++ ndp->channel_probe_id++; ++ } ++ ++ if (ndp->channel_probe_id == ndp->channel_count) { ++ ndp->channel_probe_id = 0; + nd->state = ncsi_dev_state_probe_dp; ++ } + break; + case ncsi_dev_state_probe_dp: + ndp->pending_req_num = 1; +@@ -1752,6 +1749,7 @@ struct ncsi_dev *ncsi_register_dev(struct net_device *dev, + ndp->requests[i].ndp = ndp; + timer_setup(&ndp->requests[i].timer, ncsi_request_timeout, 0); + } ++ ndp->channel_count = NCSI_RESERVED_CHANNEL; + + spin_lock_irqsave(&ncsi_dev_lock, flags); + list_add_tail_rcu(&ndp->node, &ncsi_dev_list); +@@ -1784,6 +1782,7 @@ int ncsi_start_dev(struct ncsi_dev *nd) + + if (!(ndp->flags & NCSI_DEV_PROBED)) { + ndp->package_probe_id = 0; ++ ndp->channel_probe_id = 0; + nd->state = ncsi_dev_state_probe; + schedule_work(&ndp->work); + return 0; +diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c +index 6a46388116601..960e2cfc1fd2a 100644 +--- a/net/ncsi/ncsi-rsp.c ++++ b/net/ncsi/ncsi-rsp.c +@@ -795,12 +795,13 @@ static int ncsi_rsp_handler_gc(struct ncsi_request *nr) + struct ncsi_rsp_gc_pkt *rsp; + struct ncsi_dev_priv *ndp = nr->ndp; + struct ncsi_channel *nc; ++ struct ncsi_package *np; + size_t size; + + /* Find the channel */ + rsp = (struct ncsi_rsp_gc_pkt *)skb_network_header(nr->rsp); + ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, +- NULL, &nc); ++ &np, &nc); + if (!nc) + return -ENODEV; + +@@ -835,6 +836,7 @@ static int ncsi_rsp_handler_gc(struct ncsi_request *nr) + */ + nc->vlan_filter.bitmap = U64_MAX; + nc->vlan_filter.n_vids = rsp->vlan_cnt; ++ np->ndp->channel_count = rsp->channel_cnt; + + return 0; + } +-- +2.43.0 + diff --git a/queue-5.10/net-ncsi-simplify-kconfig-dts-control-flow.patch b/queue-5.10/net-ncsi-simplify-kconfig-dts-control-flow.patch new file mode 100644 index 00000000000..16206081814 --- /dev/null +++ b/queue-5.10/net-ncsi-simplify-kconfig-dts-control-flow.patch @@ -0,0 +1,152 @@ +From e195d65ad39fe7b0d0dd989ecaf3719948f9c53e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Nov 2023 10:07:33 -0600 +Subject: net/ncsi: Simplify Kconfig/dts control flow + +From: Peter Delevoryas + +[ Upstream commit c797ce168930ce3d62a9b7fc4d7040963ee6a01e ] + +Background: + +1. CONFIG_NCSI_OEM_CMD_KEEP_PHY + +If this is enabled, we send an extra OEM Intel command in the probe +sequence immediately after discovering a channel (e.g. after "Clear +Initial State"). + +2. CONFIG_NCSI_OEM_CMD_GET_MAC + +If this is enabled, we send one of 3 OEM "Get MAC Address" commands from +Broadcom, Mellanox (Nvidida), and Intel in the *configuration* sequence +for a channel. + +3. mellanox,multi-host (or mlx,multi-host) + +Introduced by this patch: + +https://lore.kernel.org/all/20200108234341.2590674-1-vijaykhemka@fb.com/ + +Which was actually originally from cosmo.chou@quantatw.com: + +https://github.com/facebook/openbmc-linux/commit/9f132a10ec48db84613519258cd8a317fb9c8f1b + +Cosmo claimed that the Nvidia ConnectX-4 and ConnectX-6 NIC's don't +respond to Get Version ID, et. al in the probe sequence unless you send +the Set MC Affinity command first. + +Problem Statement: + +We've been using a combination of #ifdef code blocks and IS_ENABLED() +conditions to conditionally send these OEM commands. + +It makes adding any new code around these commands hard to understand. + +Solution: + +In this patch, I just want to remove the conditionally compiled blocks +of code, and always use IS_ENABLED(...) to do dynamic control flow. + +I don't think the small amount of code this adds to non-users of the OEM +Kconfigs is a big deal. + +Signed-off-by: Peter Delevoryas +Signed-off-by: David S. Miller +Stable-dep-of: e85e271dec02 ("net/ncsi: Fix the multi thread manner of NCSI driver") +Signed-off-by: Sasha Levin +--- + net/ncsi/ncsi-manage.c | 20 +++----------------- + 1 file changed, 3 insertions(+), 17 deletions(-) + +diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c +index 06ad7db553fb5..d2f8155af53e3 100644 +--- a/net/ncsi/ncsi-manage.c ++++ b/net/ncsi/ncsi-manage.c +@@ -689,8 +689,6 @@ static int set_one_vid(struct ncsi_dev_priv *ndp, struct ncsi_channel *nc, + return 0; + } + +-#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_KEEP_PHY) +- + static int ncsi_oem_keep_phy_intel(struct ncsi_cmd_arg *nca) + { + unsigned char data[NCSI_OEM_INTEL_CMD_KEEP_PHY_LEN]; +@@ -716,10 +714,6 @@ static int ncsi_oem_keep_phy_intel(struct ncsi_cmd_arg *nca) + return ret; + } + +-#endif +- +-#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC) +- + /* NCSI OEM Command APIs */ + static int ncsi_oem_gma_handler_bcm(struct ncsi_cmd_arg *nca) + { +@@ -833,8 +827,6 @@ static int ncsi_gma_handler(struct ncsi_cmd_arg *nca, unsigned int mf_id) + return nch->handler(nca); + } + +-#endif /* CONFIG_NCSI_OEM_CMD_GET_MAC */ +- + /* Determine if a given channel from the channel_queue should be used for Tx */ + static bool ncsi_channel_is_tx(struct ncsi_dev_priv *ndp, + struct ncsi_channel *nc) +@@ -1016,20 +1008,18 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp) + goto error; + } + +- nd->state = ncsi_dev_state_config_oem_gma; ++ nd->state = IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC) ++ ? ncsi_dev_state_config_oem_gma ++ : ncsi_dev_state_config_clear_vids; + break; + case ncsi_dev_state_config_oem_gma: + nd->state = ncsi_dev_state_config_clear_vids; +- ret = -1; + +-#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC) + nca.type = NCSI_PKT_CMD_OEM; + nca.package = np->id; + nca.channel = nc->id; + ndp->pending_req_num = 1; + ret = ncsi_gma_handler(&nca, nc->version.mf_id); +-#endif /* CONFIG_NCSI_OEM_CMD_GET_MAC */ +- + if (ret < 0) + schedule_work(&ndp->work); + +@@ -1381,7 +1371,6 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp) + + schedule_work(&ndp->work); + break; +-#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC) + case ncsi_dev_state_probe_mlx_gma: + ndp->pending_req_num = 1; + +@@ -1406,7 +1395,6 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp) + + nd->state = ncsi_dev_state_probe_cis; + break; +-#endif /* CONFIG_NCSI_OEM_CMD_GET_MAC */ + case ncsi_dev_state_probe_cis: + ndp->pending_req_num = NCSI_RESERVED_CHANNEL; + +@@ -1424,7 +1412,6 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp) + if (IS_ENABLED(CONFIG_NCSI_OEM_CMD_KEEP_PHY)) + nd->state = ncsi_dev_state_probe_keep_phy; + break; +-#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_KEEP_PHY) + case ncsi_dev_state_probe_keep_phy: + ndp->pending_req_num = 1; + +@@ -1437,7 +1424,6 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp) + + nd->state = ncsi_dev_state_probe_gvi; + break; +-#endif /* CONFIG_NCSI_OEM_CMD_KEEP_PHY */ + case ncsi_dev_state_probe_gvi: + case ncsi_dev_state_probe_gc: + case ncsi_dev_state_probe_gls: +-- +2.43.0 + diff --git a/queue-5.10/net-sched-sch_multiq-fix-possible-oob-write-in-multi.patch b/queue-5.10/net-sched-sch_multiq-fix-possible-oob-write-in-multi.patch new file mode 100644 index 00000000000..af4d236b409 --- /dev/null +++ b/queue-5.10/net-sched-sch_multiq-fix-possible-oob-write-in-multi.patch @@ -0,0 +1,38 @@ +From dc581f99399c1bc308df11c1f4981df1ae227a95 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Jun 2024 15:13:03 +0800 +Subject: net: sched: sch_multiq: fix possible OOB write in multiq_tune() + +From: Hangyu Hua + +[ Upstream commit affc18fdc694190ca7575b9a86632a73b9fe043d ] + +q->bands will be assigned to qopt->bands to execute subsequent code logic +after kmalloc. So the old q->bands should not be used in kmalloc. +Otherwise, an out-of-bounds write will occur. + +Fixes: c2999f7fb05b ("net: sched: multiq: don't call qdisc_put() while holding tree lock") +Signed-off-by: Hangyu Hua +Acked-by: Cong Wang +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + net/sched/sch_multiq.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c +index 1c6dbcfa89b87..77fd7be3a9cd1 100644 +--- a/net/sched/sch_multiq.c ++++ b/net/sched/sch_multiq.c +@@ -185,7 +185,7 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt, + + qopt->bands = qdisc_dev(sch)->real_num_tx_queues; + +- removed = kmalloc(sizeof(*removed) * (q->max_bands - q->bands), ++ removed = kmalloc(sizeof(*removed) * (q->max_bands - qopt->bands), + GFP_KERNEL); + if (!removed) + return -ENOMEM; +-- +2.43.0 + diff --git a/queue-5.10/net-sched-taprio-always-validate-tca_taprio_attr_pri.patch b/queue-5.10/net-sched-taprio-always-validate-tca_taprio_attr_pri.patch new file mode 100644 index 00000000000..2e54874813c --- /dev/null +++ b/queue-5.10/net-sched-taprio-always-validate-tca_taprio_attr_pri.patch @@ -0,0 +1,63 @@ +From d0be3c2ddf77617dbd25713a80b93c9e8c1d9014 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Jun 2024 18:15:11 +0000 +Subject: net/sched: taprio: always validate TCA_TAPRIO_ATTR_PRIOMAP + +From: Eric Dumazet + +[ Upstream commit f921a58ae20852d188f70842431ce6519c4fdc36 ] + +If one TCA_TAPRIO_ATTR_PRIOMAP attribute has been provided, +taprio_parse_mqprio_opt() must validate it, or userspace +can inject arbitrary data to the kernel, the second time +taprio_change() is called. + +First call (with valid attributes) sets dev->num_tc +to a non zero value. + +Second call (with arbitrary mqprio attributes) +returns early from taprio_parse_mqprio_opt() +and bad things can happen. + +Fixes: a3d43c0d56f1 ("taprio: Add support adding an admin schedule") +Reported-by: Noam Rathaus +Signed-off-by: Eric Dumazet +Acked-by: Vinicius Costa Gomes +Reviewed-by: Vladimir Oltean +Link: https://lore.kernel.org/r/20240604181511.769870-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 15 ++++++--------- + 1 file changed, 6 insertions(+), 9 deletions(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index 2d842f31ec5a8..ec6b24edf5f93 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -925,16 +925,13 @@ static int taprio_parse_mqprio_opt(struct net_device *dev, + { + int i, j; + +- if (!qopt && !dev->num_tc) { +- NL_SET_ERR_MSG(extack, "'mqprio' configuration is necessary"); +- return -EINVAL; +- } +- +- /* If num_tc is already set, it means that the user already +- * configured the mqprio part +- */ +- if (dev->num_tc) ++ if (!qopt) { ++ if (!dev->num_tc) { ++ NL_SET_ERR_MSG(extack, "'mqprio' configuration is necessary"); ++ return -EINVAL; ++ } + return 0; ++ } + + /* Verify num_tc is not out of max range */ + if (qopt->num_tc > TC_MAX_QUEUE) { +-- +2.43.0 + diff --git a/queue-5.10/nilfs2-fix-nilfs_empty_dir-misjudgment-and-long-loop.patch b/queue-5.10/nilfs2-fix-nilfs_empty_dir-misjudgment-and-long-loop.patch new file mode 100644 index 00000000000..cba223b602d --- /dev/null +++ b/queue-5.10/nilfs2-fix-nilfs_empty_dir-misjudgment-and-long-loop.patch @@ -0,0 +1,51 @@ +From 70c2814b8a027e9dfd602098383a00328068f7c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Jun 2024 22:42:55 +0900 +Subject: nilfs2: fix nilfs_empty_dir() misjudgment and long loop on I/O errors + +From: Ryusuke Konishi + +[ Upstream commit 7373a51e7998b508af7136530f3a997b286ce81c ] + +The error handling in nilfs_empty_dir() when a directory folio/page read +fails is incorrect, as in the old ext2 implementation, and if the +folio/page cannot be read or nilfs_check_folio() fails, it will falsely +determine the directory as empty and corrupt the file system. + +In addition, since nilfs_empty_dir() does not immediately return on a +failed folio/page read, but continues to loop, this can cause a long loop +with I/O if i_size of the directory's inode is also corrupted, causing the +log writer thread to wait and hang, as reported by syzbot. + +Fix these issues by making nilfs_empty_dir() immediately return a false +value (0) if it fails to get a directory folio/page. + +Link: https://lkml.kernel.org/r/20240604134255.7165-1-konishi.ryusuke@gmail.com +Signed-off-by: Ryusuke Konishi +Reported-by: syzbot+c8166c541d3971bf6c87@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=c8166c541d3971bf6c87 +Fixes: 2ba466d74ed7 ("nilfs2: directory entry operations") +Tested-by: Ryusuke Konishi +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/nilfs2/dir.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/nilfs2/dir.c b/fs/nilfs2/dir.c +index 22f1f75a90c1a..552234ef22fe7 100644 +--- a/fs/nilfs2/dir.c ++++ b/fs/nilfs2/dir.c +@@ -627,7 +627,7 @@ int nilfs_empty_dir(struct inode *inode) + + kaddr = nilfs_get_page(inode, i, &page); + if (IS_ERR(kaddr)) +- continue; ++ return 0; + + de = (struct nilfs_dir_entry *)kaddr; + kaddr += nilfs_last_byte(inode, i) - NILFS_DIR_REC_LEN(1); +-- +2.43.0 + diff --git a/queue-5.10/nilfs2-remove-check-for-pageerror.patch b/queue-5.10/nilfs2-remove-check-for-pageerror.patch new file mode 100644 index 00000000000..9c4be63f798 --- /dev/null +++ b/queue-5.10/nilfs2-remove-check-for-pageerror.patch @@ -0,0 +1,35 @@ +From e482afb04174a60be8e0181608cda63249fbb4b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 May 2022 18:12:25 -0400 +Subject: nilfs2: Remove check for PageError + +From: Matthew Wilcox (Oracle) + +[ Upstream commit 79ea65563ad8aaab309d61eeb4d5019dd6cf5fa0 ] + +If read_mapping_page() encounters an error, it returns an errno, not a +page with PageError set, so this test is not needed. + +Signed-off-by: Matthew Wilcox (Oracle) +Stable-dep-of: 7373a51e7998 ("nilfs2: fix nilfs_empty_dir() misjudgment and long loop on I/O errors") +Signed-off-by: Sasha Levin +--- + fs/nilfs2/dir.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/nilfs2/dir.c b/fs/nilfs2/dir.c +index eb7de9e2a384e..24cfe9db66e02 100644 +--- a/fs/nilfs2/dir.c ++++ b/fs/nilfs2/dir.c +@@ -194,7 +194,7 @@ static struct page *nilfs_get_page(struct inode *dir, unsigned long n) + if (!IS_ERR(page)) { + kmap(page); + if (unlikely(!PageChecked(page))) { +- if (PageError(page) || !nilfs_check_page(page)) ++ if (!nilfs_check_page(page)) + goto fail; + } + } +-- +2.43.0 + diff --git a/queue-5.10/nilfs2-return-the-mapped-address-from-nilfs_get_page.patch b/queue-5.10/nilfs2-return-the-mapped-address-from-nilfs_get_page.patch new file mode 100644 index 00000000000..e6262c6cadf --- /dev/null +++ b/queue-5.10/nilfs2-return-the-mapped-address-from-nilfs_get_page.patch @@ -0,0 +1,146 @@ +From 581498ae936fcc7622fcf007db38c48905796177 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Nov 2023 23:30:25 +0900 +Subject: nilfs2: return the mapped address from nilfs_get_page() + +From: Matthew Wilcox (Oracle) + +[ Upstream commit 09a46acb3697e50548bb265afa1d79163659dd85 ] + +In prepartion for switching from kmap() to kmap_local(), return the kmap +address from nilfs_get_page() instead of having the caller look up +page_address(). + +[konishi.ryusuke: fixed a missing blank line after declaration] +Link: https://lkml.kernel.org/r/20231127143036.2425-7-konishi.ryusuke@gmail.com +Signed-off-by: Matthew Wilcox (Oracle) +Signed-off-by: Ryusuke Konishi +Signed-off-by: Andrew Morton +Stable-dep-of: 7373a51e7998 ("nilfs2: fix nilfs_empty_dir() misjudgment and long loop on I/O errors") +Signed-off-by: Sasha Levin +--- + fs/nilfs2/dir.c | 57 +++++++++++++++++++++++-------------------------- + 1 file changed, 27 insertions(+), 30 deletions(-) + +diff --git a/fs/nilfs2/dir.c b/fs/nilfs2/dir.c +index 24cfe9db66e02..22f1f75a90c1a 100644 +--- a/fs/nilfs2/dir.c ++++ b/fs/nilfs2/dir.c +@@ -186,19 +186,24 @@ static bool nilfs_check_page(struct page *page) + return false; + } + +-static struct page *nilfs_get_page(struct inode *dir, unsigned long n) ++static void *nilfs_get_page(struct inode *dir, unsigned long n, ++ struct page **pagep) + { + struct address_space *mapping = dir->i_mapping; + struct page *page = read_mapping_page(mapping, n, NULL); ++ void *kaddr; + +- if (!IS_ERR(page)) { +- kmap(page); +- if (unlikely(!PageChecked(page))) { +- if (!nilfs_check_page(page)) +- goto fail; +- } ++ if (IS_ERR(page)) ++ return page; ++ ++ kaddr = kmap(page); ++ if (unlikely(!PageChecked(page))) { ++ if (!nilfs_check_page(page)) ++ goto fail; + } +- return page; ++ ++ *pagep = page; ++ return kaddr; + + fail: + nilfs_put_page(page); +@@ -275,14 +280,14 @@ static int nilfs_readdir(struct file *file, struct dir_context *ctx) + for ( ; n < npages; n++, offset = 0) { + char *kaddr, *limit; + struct nilfs_dir_entry *de; +- struct page *page = nilfs_get_page(inode, n); ++ struct page *page; + +- if (IS_ERR(page)) { ++ kaddr = nilfs_get_page(inode, n, &page); ++ if (IS_ERR(kaddr)) { + nilfs_error(sb, "bad page in #%lu", inode->i_ino); + ctx->pos += PAGE_SIZE - offset; + return -EIO; + } +- kaddr = page_address(page); + de = (struct nilfs_dir_entry *)(kaddr + offset); + limit = kaddr + nilfs_last_byte(inode, n) - + NILFS_DIR_REC_LEN(1); +@@ -345,11 +350,9 @@ nilfs_find_entry(struct inode *dir, const struct qstr *qstr, + start = 0; + n = start; + do { +- char *kaddr; ++ char *kaddr = nilfs_get_page(dir, n, &page); + +- page = nilfs_get_page(dir, n); +- if (!IS_ERR(page)) { +- kaddr = page_address(page); ++ if (!IS_ERR(kaddr)) { + de = (struct nilfs_dir_entry *)kaddr; + kaddr += nilfs_last_byte(dir, n) - reclen; + while ((char *) de <= kaddr) { +@@ -387,15 +390,11 @@ nilfs_find_entry(struct inode *dir, const struct qstr *qstr, + + struct nilfs_dir_entry *nilfs_dotdot(struct inode *dir, struct page **p) + { +- struct page *page = nilfs_get_page(dir, 0); +- struct nilfs_dir_entry *de = NULL; ++ struct nilfs_dir_entry *de = nilfs_get_page(dir, 0, p); + +- if (!IS_ERR(page)) { +- de = nilfs_next_entry( +- (struct nilfs_dir_entry *)page_address(page)); +- *p = page; +- } +- return de; ++ if (IS_ERR(de)) ++ return NULL; ++ return nilfs_next_entry(de); + } + + ino_t nilfs_inode_by_name(struct inode *dir, const struct qstr *qstr) +@@ -459,12 +458,11 @@ int nilfs_add_link(struct dentry *dentry, struct inode *inode) + for (n = 0; n <= npages; n++) { + char *dir_end; + +- page = nilfs_get_page(dir, n); +- err = PTR_ERR(page); +- if (IS_ERR(page)) ++ kaddr = nilfs_get_page(dir, n, &page); ++ err = PTR_ERR(kaddr); ++ if (IS_ERR(kaddr)) + goto out; + lock_page(page); +- kaddr = page_address(page); + dir_end = kaddr + nilfs_last_byte(dir, n); + de = (struct nilfs_dir_entry *)kaddr; + kaddr += PAGE_SIZE - reclen; +@@ -627,11 +625,10 @@ int nilfs_empty_dir(struct inode *inode) + char *kaddr; + struct nilfs_dir_entry *de; + +- page = nilfs_get_page(inode, i); +- if (IS_ERR(page)) ++ kaddr = nilfs_get_page(inode, i, &page); ++ if (IS_ERR(kaddr)) + continue; + +- kaddr = page_address(page); + de = (struct nilfs_dir_entry *)kaddr; + kaddr += nilfs_last_byte(inode, i) - NILFS_DIR_REC_LEN(1); + +-- +2.43.0 + diff --git a/queue-5.10/platform-provide-a-remove-callback-that-returns-no-v.patch b/queue-5.10/platform-provide-a-remove-callback-that-returns-no-v.patch new file mode 100644 index 00000000000..0106f5d8f54 --- /dev/null +++ b/queue-5.10/platform-provide-a-remove-callback-that-returns-no-v.patch @@ -0,0 +1,86 @@ +From 6f4946eef20eaaf56aeb2414f4626249a8f4679a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Dec 2022 16:09:14 +0100 +Subject: platform: Provide a remove callback that returns no value +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Uwe Kleine-König + +[ Upstream commit 5c5a7680e67ba6fbbb5f4d79fa41485450c1985c ] + +struct platform_driver::remove returning an integer made driver authors +expect that returning an error code was proper error handling. However +the driver core ignores the error and continues to remove the device +because there is nothing the core could do anyhow and reentering the +remove callback again is only calling for trouble. + +So this is an source for errors typically yielding resource leaks in the +error path. + +As there are too many platform drivers to neatly convert them all to +return void in a single go, do it in several steps after this patch: + + a) Convert all drivers to implement .remove_new() returning void instead + of .remove() returning int; + b) Change struct platform_driver::remove() to return void and so make + it identical to .remove_new(); + c) Change all drivers back to .remove() now with the better prototype; + d) drop struct platform_driver::remove_new(). + +While this touches all drivers eventually twice, steps a) and c) can be +done one driver after another and so reduces coordination efforts +immensely and simplifies review. + +Signed-off-by: Uwe Kleine-König +Link: https://lore.kernel.org/r/20221209150914.3557650-1-u.kleine-koenig@pengutronix.de +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 55c421b36448 ("mmc: davinci: Don't strip remove function when driver is builtin") +Signed-off-by: Sasha Levin +--- + drivers/base/platform.c | 4 +++- + include/linux/platform_device.h | 11 +++++++++++ + 2 files changed, 14 insertions(+), 1 deletion(-) + +diff --git a/drivers/base/platform.c b/drivers/base/platform.c +index d0b15cbab0ff0..e07043d85c65c 100644 +--- a/drivers/base/platform.c ++++ b/drivers/base/platform.c +@@ -1306,7 +1306,9 @@ static int platform_remove(struct device *_dev) + struct platform_driver *drv = to_platform_driver(_dev->driver); + struct platform_device *dev = to_platform_device(_dev); + +- if (drv->remove) { ++ if (drv->remove_new) { ++ drv->remove_new(dev); ++ } else if (drv->remove) { + int ret = drv->remove(dev); + + if (ret) +diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h +index e7a83b0218077..870a918aa251c 100644 +--- a/include/linux/platform_device.h ++++ b/include/linux/platform_device.h +@@ -203,7 +203,18 @@ extern void platform_device_put(struct platform_device *pdev); + + struct platform_driver { + int (*probe)(struct platform_device *); ++ ++ /* ++ * Traditionally the remove callback returned an int which however is ++ * ignored by the driver core. This led to wrong expectations by driver ++ * authors who thought returning an error code was a valid error ++ * handling strategy. To convert to a callback returning void, new ++ * drivers should implement .remove_new() until the conversion it done ++ * that eventually makes .remove() return void. ++ */ + int (*remove)(struct platform_device *); ++ void (*remove_new)(struct platform_device *); ++ + void (*shutdown)(struct platform_device *); + int (*suspend)(struct platform_device *, pm_message_t state); + int (*resume)(struct platform_device *); +-- +2.43.0 + diff --git a/queue-5.10/pm-core-add-new-_pm_ops-macros-deprecate-old-ones.patch b/queue-5.10/pm-core-add-new-_pm_ops-macros-deprecate-old-ones.patch new file mode 100644 index 00000000000..1b770ec99c2 --- /dev/null +++ b/queue-5.10/pm-core-add-new-_pm_ops-macros-deprecate-old-ones.patch @@ -0,0 +1,197 @@ +From b934447a0fcbcd8bbd51c4dc6cbcc92c803bae21 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Dec 2021 00:21:00 +0000 +Subject: PM: core: Add new *_PM_OPS macros, deprecate old ones + +From: Paul Cercueil + +[ Upstream commit 1a3c7bb088266fa2db017be299f91f1c1894c857 ] + +This commit introduces the following macros: + +SYSTEM_SLEEP_PM_OPS() +LATE_SYSTEM_SLEEP_PM_OPS() +NOIRQ_SYSTEM_SLEEP_PM_OPS() +RUNTIME_PM_OPS() + +These new macros are very similar to their SET_*_PM_OPS() equivalent. +They however differ in the fact that the callbacks they set will always +be seen as referenced by the compiler. This means that the callback +functions don't need to be wrapped with a #ifdef CONFIG_PM guard, or +tagged with __maybe_unused, to prevent the compiler from complaining +about unused static symbols. The compiler will then simply evaluate at +compile time whether or not these symbols are dead code. + +The callbacks that are only useful with CONFIG_PM_SLEEP is enabled, are +now also wrapped with a new pm_sleep_ptr() macro, which is inspired from +pm_ptr(). This is needed for drivers that use different callbacks for +sleep and runtime PM, to handle the case where CONFIG_PM is set and +CONFIG_PM_SLEEP is not. + +This commit also deprecates the following macros: + +SIMPLE_DEV_PM_OPS() +UNIVERSAL_DEV_PM_OPS() + +And introduces the following macros: + +DEFINE_SIMPLE_DEV_PM_OPS() +DEFINE_UNIVERSAL_DEV_PM_OPS() + +These macros are similar to the functions they were created to replace, +with the following differences: + + - They use the new macros introduced above, and as such always + reference the provided callback functions. + + - They are not tagged with __maybe_unused. They are meant to be used + with pm_ptr() or pm_sleep_ptr() for DEFINE_UNIVERSAL_DEV_PM_OPS() + and DEFINE_SIMPLE_DEV_PM_OPS() respectively. + + - They declare the symbol static, since every driver seems to do that + anyway; and if a non-static use-case is needed an indirection pointer + could be used. + +The point of this change, is to progressively switch from a code model +where PM callbacks are all protected behind CONFIG_PM guards, to a code +model where the PM callbacks are always seen by the compiler, but +discarded if not used. + +Signed-off-by: Paul Cercueil +Reviewed-by: Jonathan Cameron +Signed-off-by: Rafael J. Wysocki +Stable-dep-of: 6b8cffdc4a31 ("iio: accel: mxc4005: Reset chip on probe() and resume()") +Signed-off-by: Sasha Levin +--- + include/linux/pm.h | 74 +++++++++++++++++++++++++++++++--------------- + 1 file changed, 50 insertions(+), 24 deletions(-) + +diff --git a/include/linux/pm.h b/include/linux/pm.h +index 5ac2c9ba5baf7..b4974dc837032 100644 +--- a/include/linux/pm.h ++++ b/include/linux/pm.h +@@ -301,47 +301,59 @@ struct dev_pm_ops { + int (*runtime_idle)(struct device *dev); + }; + ++#define SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ ++ .suspend = pm_sleep_ptr(suspend_fn), \ ++ .resume = pm_sleep_ptr(resume_fn), \ ++ .freeze = pm_sleep_ptr(suspend_fn), \ ++ .thaw = pm_sleep_ptr(resume_fn), \ ++ .poweroff = pm_sleep_ptr(suspend_fn), \ ++ .restore = pm_sleep_ptr(resume_fn), ++ ++#define LATE_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ ++ .suspend_late = pm_sleep_ptr(suspend_fn), \ ++ .resume_early = pm_sleep_ptr(resume_fn), \ ++ .freeze_late = pm_sleep_ptr(suspend_fn), \ ++ .thaw_early = pm_sleep_ptr(resume_fn), \ ++ .poweroff_late = pm_sleep_ptr(suspend_fn), \ ++ .restore_early = pm_sleep_ptr(resume_fn), ++ ++#define NOIRQ_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ ++ .suspend_noirq = pm_sleep_ptr(suspend_fn), \ ++ .resume_noirq = pm_sleep_ptr(resume_fn), \ ++ .freeze_noirq = pm_sleep_ptr(suspend_fn), \ ++ .thaw_noirq = pm_sleep_ptr(resume_fn), \ ++ .poweroff_noirq = pm_sleep_ptr(suspend_fn), \ ++ .restore_noirq = pm_sleep_ptr(resume_fn), ++ ++#define RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \ ++ .runtime_suspend = suspend_fn, \ ++ .runtime_resume = resume_fn, \ ++ .runtime_idle = idle_fn, ++ + #ifdef CONFIG_PM_SLEEP + #define SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ +- .suspend = suspend_fn, \ +- .resume = resume_fn, \ +- .freeze = suspend_fn, \ +- .thaw = resume_fn, \ +- .poweroff = suspend_fn, \ +- .restore = resume_fn, ++ SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) + #else + #define SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) + #endif + + #ifdef CONFIG_PM_SLEEP + #define SET_LATE_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ +- .suspend_late = suspend_fn, \ +- .resume_early = resume_fn, \ +- .freeze_late = suspend_fn, \ +- .thaw_early = resume_fn, \ +- .poweroff_late = suspend_fn, \ +- .restore_early = resume_fn, ++ LATE_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) + #else + #define SET_LATE_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) + #endif + + #ifdef CONFIG_PM_SLEEP + #define SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ +- .suspend_noirq = suspend_fn, \ +- .resume_noirq = resume_fn, \ +- .freeze_noirq = suspend_fn, \ +- .thaw_noirq = resume_fn, \ +- .poweroff_noirq = suspend_fn, \ +- .restore_noirq = resume_fn, ++ NOIRQ_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) + #else + #define SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) + #endif + + #ifdef CONFIG_PM + #define SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \ +- .runtime_suspend = suspend_fn, \ +- .runtime_resume = resume_fn, \ +- .runtime_idle = idle_fn, ++ RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) + #else + #define SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) + #endif +@@ -350,9 +362,9 @@ struct dev_pm_ops { + * Use this if you want to use the same suspend and resume callbacks for suspend + * to RAM and hibernation. + */ +-#define SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \ +-const struct dev_pm_ops __maybe_unused name = { \ +- SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ ++#define DEFINE_SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \ ++static const struct dev_pm_ops name = { \ ++ SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ + } + + /* +@@ -368,6 +380,19 @@ const struct dev_pm_ops __maybe_unused name = { \ + * .resume_early(), to the same routines as .runtime_suspend() and + * .runtime_resume(), respectively (and analogously for hibernation). + */ ++#define DEFINE_UNIVERSAL_DEV_PM_OPS(name, suspend_fn, resume_fn, idle_fn) \ ++static const struct dev_pm_ops name = { \ ++ SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ ++ RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \ ++} ++ ++/* Deprecated. Use DEFINE_SIMPLE_DEV_PM_OPS() instead. */ ++#define SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \ ++const struct dev_pm_ops __maybe_unused name = { \ ++ SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ ++} ++ ++/* Deprecated. Use DEFINE_UNIVERSAL_DEV_PM_OPS() instead. */ + #define UNIVERSAL_DEV_PM_OPS(name, suspend_fn, resume_fn, idle_fn) \ + const struct dev_pm_ops __maybe_unused name = { \ + SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ +@@ -375,6 +400,7 @@ const struct dev_pm_ops __maybe_unused name = { \ + } + + #define pm_ptr(_ptr) PTR_IF(IS_ENABLED(CONFIG_PM), (_ptr)) ++#define pm_sleep_ptr(_ptr) PTR_IF(IS_ENABLED(CONFIG_PM_SLEEP), (_ptr)) + + /* + * PM_EVENT_ messages +-- +2.43.0 + diff --git a/queue-5.10/pm-core-redefine-pm_ptr-macro.patch b/queue-5.10/pm-core-redefine-pm_ptr-macro.patch new file mode 100644 index 00000000000..e89c68bb26b --- /dev/null +++ b/queue-5.10/pm-core-redefine-pm_ptr-macro.patch @@ -0,0 +1,61 @@ +From e00842f7c10a45fd93086c7b3f32e5d7786cc590 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Dec 2021 00:20:59 +0000 +Subject: PM: core: Redefine pm_ptr() macro + +From: Paul Cercueil + +[ Upstream commit c06ef740d401d0f4ab188882bf6f8d9cf0f75eaf ] + +The pm_ptr() macro was previously conditionally defined, according to +the value of the CONFIG_PM option. This meant that the pointed structure +was either referenced (if CONFIG_PM was set), or never referenced (if +CONFIG_PM was not set), causing it to be detected as unused by the +compiler. + +This worked fine, but required the __maybe_unused compiler attribute to +be used to every symbol pointed to by a pointer wrapped with pm_ptr(). + +We can do better. With this change, the pm_ptr() is now defined the +same, independently of the value of CONFIG_PM. It now uses the (?:) +ternary operator to conditionally resolve to its argument. Since the +condition is known at compile time, the compiler will then choose to +discard the unused symbols, which won't need to be tagged with +__maybe_unused anymore. + +This pm_ptr() macro is usually used with pointers to dev_pm_ops +structures created with SIMPLE_DEV_PM_OPS() or similar macros. These do +use a __maybe_unused flag, which is now useless with this change, so it +later can be removed. However in the meantime it causes no harm, and all +the drivers still compile fine with the new pm_ptr() macro. + +Signed-off-by: Paul Cercueil +Reviewed-by: Jonathan Cameron +Reviewed-by: Arnd Bergmann +Signed-off-by: Rafael J. Wysocki +Stable-dep-of: 6b8cffdc4a31 ("iio: accel: mxc4005: Reset chip on probe() and resume()") +Signed-off-by: Sasha Levin +--- + include/linux/pm.h | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/include/linux/pm.h b/include/linux/pm.h +index 52d9724db9dc6..5ac2c9ba5baf7 100644 +--- a/include/linux/pm.h ++++ b/include/linux/pm.h +@@ -374,11 +374,7 @@ const struct dev_pm_ops __maybe_unused name = { \ + SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \ + } + +-#ifdef CONFIG_PM +-#define pm_ptr(_ptr) (_ptr) +-#else +-#define pm_ptr(_ptr) NULL +-#endif ++#define pm_ptr(_ptr) PTR_IF(IS_ENABLED(CONFIG_PM), (_ptr)) + + /* + * PM_EVENT_ messages +-- +2.43.0 + diff --git a/queue-5.10/pm-core-remove-static-qualifier-in-define_simple_dev.patch b/queue-5.10/pm-core-remove-static-qualifier-in-define_simple_dev.patch new file mode 100644 index 00000000000..218742ba62d --- /dev/null +++ b/queue-5.10/pm-core-remove-static-qualifier-in-define_simple_dev.patch @@ -0,0 +1,72 @@ +From 9ffb7506c82e744fb98f5c77572aac496f2fc122 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 7 Jan 2022 18:17:19 +0000 +Subject: PM: core: Remove static qualifier in DEFINE_SIMPLE_DEV_PM_OPS macro + +From: Paul Cercueil + +[ Upstream commit 52cc1d7f9786d2be44a3ab9b5b48416a7618e713 ] + +Keep this macro in line with the other ones. This makes it possible to +use them in the cases where the underlying dev_pm_ops structure is +exported. + +Restore the "static" qualifier in the two drivers where the +DEFINE_SIMPLE_DEV_PM_OPS macro was used. + +Signed-off-by: Paul Cercueil +Acked-by: Jonathan Cameron +Reviewed-by: Ulf Hansson +Signed-off-by: Rafael J. Wysocki +Stable-dep-of: 6b8cffdc4a31 ("iio: accel: mxc4005: Reset chip on probe() and resume()") +Signed-off-by: Sasha Levin +--- + drivers/mmc/host/jz4740_mmc.c | 4 ++-- + drivers/mmc/host/mxcmmc.c | 2 +- + include/linux/pm.h | 2 +- + 3 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c +index 95ef64a103127..da060e78e7ba9 100644 +--- a/drivers/mmc/host/jz4740_mmc.c ++++ b/drivers/mmc/host/jz4740_mmc.c +@@ -1146,8 +1146,8 @@ static int jz4740_mmc_resume(struct device *dev) + return pinctrl_select_default_state(dev); + } + +-DEFINE_SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend, +- jz4740_mmc_resume); ++static DEFINE_SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend, ++ jz4740_mmc_resume); + + static struct platform_driver jz4740_mmc_driver = { + .probe = jz4740_mmc_probe, +diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c +index a68c21506967f..7b5d89f646de4 100644 +--- a/drivers/mmc/host/mxcmmc.c ++++ b/drivers/mmc/host/mxcmmc.c +@@ -1236,7 +1236,7 @@ static int mxcmci_resume(struct device *dev) + return ret; + } + +-DEFINE_SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume); ++static DEFINE_SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume); + + static struct platform_driver mxcmci_driver = { + .probe = mxcmci_probe, +diff --git a/include/linux/pm.h b/include/linux/pm.h +index b4974dc837032..00e71f0b4c179 100644 +--- a/include/linux/pm.h ++++ b/include/linux/pm.h +@@ -363,7 +363,7 @@ struct dev_pm_ops { + * to RAM and hibernation. + */ + #define DEFINE_SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \ +-static const struct dev_pm_ops name = { \ ++const struct dev_pm_ops name = { \ + SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ + } + +-- +2.43.0 + diff --git a/queue-5.10/ptp-fix-error-message-on-failed-pin-verification.patch b/queue-5.10/ptp-fix-error-message-on-failed-pin-verification.patch new file mode 100644 index 00000000000..baca0af1dd0 --- /dev/null +++ b/queue-5.10/ptp-fix-error-message-on-failed-pin-verification.patch @@ -0,0 +1,42 @@ +From 0aad7e66476a3867bbc645b4a32d042822ace38a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Jun 2024 14:05:27 +0200 +Subject: ptp: Fix error message on failed pin verification + +From: Karol Kolacinski + +[ Upstream commit 323a359f9b077f382f4483023d096a4d316fd135 ] + +On failed verification of PTP clock pin, error message prints channel +number instead of pin index after "pin", which is incorrect. + +Fix error message by adding channel number to the message and printing +pin number instead of channel number. + +Fixes: 6092315dfdec ("ptp: introduce programmable pins.") +Signed-off-by: Karol Kolacinski +Acked-by: Richard Cochran +Link: https://lore.kernel.org/r/20240604120555.16643-1-karol.kolacinski@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/ptp/ptp_chardev.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c +index 9311f3d09c8fc..8eb902fe73a98 100644 +--- a/drivers/ptp/ptp_chardev.c ++++ b/drivers/ptp/ptp_chardev.c +@@ -84,7 +84,8 @@ int ptp_set_pinfunc(struct ptp_clock *ptp, unsigned int pin, + } + + if (info->verify(info, pin, func, chan)) { +- pr_err("driver cannot use function %u on pin %u\n", func, chan); ++ pr_err("driver cannot use function %u and channel %u on pin %u\n", ++ func, chan, pin); + return -EOPNOTSUPP; + } + +-- +2.43.0 + diff --git a/queue-5.10/s390-cpacf-get-rid-of-register-asm.patch b/queue-5.10/s390-cpacf-get-rid-of-register-asm.patch new file mode 100644 index 00000000000..85c96ad4d51 --- /dev/null +++ b/queue-5.10/s390-cpacf-get-rid-of-register-asm.patch @@ -0,0 +1,375 @@ +From 67dff0da116be96e472460e4bf7b63a26f39ec4a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 25 Jun 2021 16:42:55 +0200 +Subject: s390/cpacf: get rid of register asm + +From: Heiko Carstens + +[ Upstream commit b84d0c417a5ac1eb820c8114c0c7cf1fcbf6f017 ] + +Using register asm statements has been proven to be very error prone, +especially when using code instrumentation where gcc may add function +calls, which clobbers register contents in an unexpected way. + +Therefore get rid of register asm statements in cpacf code, and make +sure this bug class cannot happen. + +Reviewed-by: Patrick Steuer +Signed-off-by: Heiko Carstens +Stable-dep-of: 830999bd7e72 ("s390/cpacf: Split and rework cpacf query functions") +Signed-off-by: Sasha Levin +--- + arch/s390/include/asm/cpacf.h | 208 ++++++++++++++++++---------------- + 1 file changed, 111 insertions(+), 97 deletions(-) + +diff --git a/arch/s390/include/asm/cpacf.h b/arch/s390/include/asm/cpacf.h +index c0f3bfeddcbeb..646b12981f208 100644 +--- a/arch/s390/include/asm/cpacf.h ++++ b/arch/s390/include/asm/cpacf.h +@@ -173,17 +173,16 @@ typedef struct { unsigned char bytes[16]; } cpacf_mask_t; + */ + static __always_inline void __cpacf_query(unsigned int opcode, cpacf_mask_t *mask) + { +- register unsigned long r0 asm("0") = 0; /* query function */ +- register unsigned long r1 asm("1") = (unsigned long) mask; +- + asm volatile( +- " spm 0\n" /* pckmo doesn't change the cc */ ++ " lghi 0,0\n" /* query function */ ++ " lgr 1,%[mask]\n" ++ " spm 0\n" /* pckmo doesn't change the cc */ + /* Parameter regs are ignored, but must be nonzero and unique */ + "0: .insn rrf,%[opc] << 16,2,4,6,0\n" + " brc 1,0b\n" /* handle partial completion */ + : "=m" (*mask) +- : [fc] "d" (r0), [pba] "a" (r1), [opc] "i" (opcode) +- : "cc"); ++ : [mask] "d" ((unsigned long)mask), [opc] "i" (opcode) ++ : "cc", "0", "1"); + } + + static __always_inline int __cpacf_check_opcode(unsigned int opcode) +@@ -249,20 +248,22 @@ static __always_inline int cpacf_query_func(unsigned int opcode, unsigned int fu + static inline int cpacf_km(unsigned long func, void *param, + u8 *dest, const u8 *src, long src_len) + { +- register unsigned long r0 asm("0") = (unsigned long) func; +- register unsigned long r1 asm("1") = (unsigned long) param; +- register unsigned long r2 asm("2") = (unsigned long) src; +- register unsigned long r3 asm("3") = (unsigned long) src_len; +- register unsigned long r4 asm("4") = (unsigned long) dest; ++ union register_pair d, s; + ++ d.even = (unsigned long)dest; ++ s.even = (unsigned long)src; ++ s.odd = (unsigned long)src_len; + asm volatile( ++ " lgr 0,%[fc]\n" ++ " lgr 1,%[pba]\n" + "0: .insn rre,%[opc] << 16,%[dst],%[src]\n" + " brc 1,0b\n" /* handle partial completion */ +- : [src] "+a" (r2), [len] "+d" (r3), [dst] "+a" (r4) +- : [fc] "d" (r0), [pba] "a" (r1), [opc] "i" (CPACF_KM) +- : "cc", "memory"); ++ : [src] "+&d" (s.pair), [dst] "+&d" (d.pair) ++ : [fc] "d" (func), [pba] "d" ((unsigned long)param), ++ [opc] "i" (CPACF_KM) ++ : "cc", "memory", "0", "1"); + +- return src_len - r3; ++ return src_len - s.odd; + } + + /** +@@ -279,20 +280,22 @@ static inline int cpacf_km(unsigned long func, void *param, + static inline int cpacf_kmc(unsigned long func, void *param, + u8 *dest, const u8 *src, long src_len) + { +- register unsigned long r0 asm("0") = (unsigned long) func; +- register unsigned long r1 asm("1") = (unsigned long) param; +- register unsigned long r2 asm("2") = (unsigned long) src; +- register unsigned long r3 asm("3") = (unsigned long) src_len; +- register unsigned long r4 asm("4") = (unsigned long) dest; ++ union register_pair d, s; + ++ d.even = (unsigned long)dest; ++ s.even = (unsigned long)src; ++ s.odd = (unsigned long)src_len; + asm volatile( ++ " lgr 0,%[fc]\n" ++ " lgr 1,%[pba]\n" + "0: .insn rre,%[opc] << 16,%[dst],%[src]\n" + " brc 1,0b\n" /* handle partial completion */ +- : [src] "+a" (r2), [len] "+d" (r3), [dst] "+a" (r4) +- : [fc] "d" (r0), [pba] "a" (r1), [opc] "i" (CPACF_KMC) +- : "cc", "memory"); ++ : [src] "+&d" (s.pair), [dst] "+&d" (d.pair) ++ : [fc] "d" (func), [pba] "d" ((unsigned long)param), ++ [opc] "i" (CPACF_KMC) ++ : "cc", "memory", "0", "1"); + +- return src_len - r3; ++ return src_len - s.odd; + } + + /** +@@ -306,17 +309,19 @@ static inline int cpacf_kmc(unsigned long func, void *param, + static inline void cpacf_kimd(unsigned long func, void *param, + const u8 *src, long src_len) + { +- register unsigned long r0 asm("0") = (unsigned long) func; +- register unsigned long r1 asm("1") = (unsigned long) param; +- register unsigned long r2 asm("2") = (unsigned long) src; +- register unsigned long r3 asm("3") = (unsigned long) src_len; ++ union register_pair s; + ++ s.even = (unsigned long)src; ++ s.odd = (unsigned long)src_len; + asm volatile( ++ " lgr 0,%[fc]\n" ++ " lgr 1,%[pba]\n" + "0: .insn rre,%[opc] << 16,0,%[src]\n" + " brc 1,0b\n" /* handle partial completion */ +- : [src] "+a" (r2), [len] "+d" (r3) +- : [fc] "d" (r0), [pba] "a" (r1), [opc] "i" (CPACF_KIMD) +- : "cc", "memory"); ++ : [src] "+&d" (s.pair) ++ : [fc] "d" (func), [pba] "d" ((unsigned long)(param)), ++ [opc] "i" (CPACF_KIMD) ++ : "cc", "memory", "0", "1"); + } + + /** +@@ -329,17 +334,19 @@ static inline void cpacf_kimd(unsigned long func, void *param, + static inline void cpacf_klmd(unsigned long func, void *param, + const u8 *src, long src_len) + { +- register unsigned long r0 asm("0") = (unsigned long) func; +- register unsigned long r1 asm("1") = (unsigned long) param; +- register unsigned long r2 asm("2") = (unsigned long) src; +- register unsigned long r3 asm("3") = (unsigned long) src_len; ++ union register_pair s; + ++ s.even = (unsigned long)src; ++ s.odd = (unsigned long)src_len; + asm volatile( ++ " lgr 0,%[fc]\n" ++ " lgr 1,%[pba]\n" + "0: .insn rre,%[opc] << 16,0,%[src]\n" + " brc 1,0b\n" /* handle partial completion */ +- : [src] "+a" (r2), [len] "+d" (r3) +- : [fc] "d" (r0), [pba] "a" (r1), [opc] "i" (CPACF_KLMD) +- : "cc", "memory"); ++ : [src] "+&d" (s.pair) ++ : [fc] "d" (func), [pba] "d" ((unsigned long)param), ++ [opc] "i" (CPACF_KLMD) ++ : "cc", "memory", "0", "1"); + } + + /** +@@ -355,19 +362,21 @@ static inline void cpacf_klmd(unsigned long func, void *param, + static inline int cpacf_kmac(unsigned long func, void *param, + const u8 *src, long src_len) + { +- register unsigned long r0 asm("0") = (unsigned long) func; +- register unsigned long r1 asm("1") = (unsigned long) param; +- register unsigned long r2 asm("2") = (unsigned long) src; +- register unsigned long r3 asm("3") = (unsigned long) src_len; ++ union register_pair s; + ++ s.even = (unsigned long)src; ++ s.odd = (unsigned long)src_len; + asm volatile( ++ " lgr 0,%[fc]\n" ++ " lgr 1,%[pba]\n" + "0: .insn rre,%[opc] << 16,0,%[src]\n" + " brc 1,0b\n" /* handle partial completion */ +- : [src] "+a" (r2), [len] "+d" (r3) +- : [fc] "d" (r0), [pba] "a" (r1), [opc] "i" (CPACF_KMAC) +- : "cc", "memory"); ++ : [src] "+&d" (s.pair) ++ : [fc] "d" (func), [pba] "d" ((unsigned long)param), ++ [opc] "i" (CPACF_KMAC) ++ : "cc", "memory", "0", "1"); + +- return src_len - r3; ++ return src_len - s.odd; + } + + /** +@@ -385,22 +394,24 @@ static inline int cpacf_kmac(unsigned long func, void *param, + static inline int cpacf_kmctr(unsigned long func, void *param, u8 *dest, + const u8 *src, long src_len, u8 *counter) + { +- register unsigned long r0 asm("0") = (unsigned long) func; +- register unsigned long r1 asm("1") = (unsigned long) param; +- register unsigned long r2 asm("2") = (unsigned long) src; +- register unsigned long r3 asm("3") = (unsigned long) src_len; +- register unsigned long r4 asm("4") = (unsigned long) dest; +- register unsigned long r6 asm("6") = (unsigned long) counter; ++ union register_pair d, s, c; + ++ d.even = (unsigned long)dest; ++ s.even = (unsigned long)src; ++ s.odd = (unsigned long)src_len; ++ c.even = (unsigned long)counter; + asm volatile( ++ " lgr 0,%[fc]\n" ++ " lgr 1,%[pba]\n" + "0: .insn rrf,%[opc] << 16,%[dst],%[src],%[ctr],0\n" + " brc 1,0b\n" /* handle partial completion */ +- : [src] "+a" (r2), [len] "+d" (r3), +- [dst] "+a" (r4), [ctr] "+a" (r6) +- : [fc] "d" (r0), [pba] "a" (r1), [opc] "i" (CPACF_KMCTR) +- : "cc", "memory"); ++ : [src] "+&d" (s.pair), [dst] "+&d" (d.pair), ++ [ctr] "+&d" (c.pair) ++ : [fc] "d" (func), [pba] "d" ((unsigned long)param), ++ [opc] "i" (CPACF_KMCTR) ++ : "cc", "memory", "0", "1"); + +- return src_len - r3; ++ return src_len - s.odd; + } + + /** +@@ -417,20 +428,21 @@ static inline void cpacf_prno(unsigned long func, void *param, + u8 *dest, unsigned long dest_len, + const u8 *seed, unsigned long seed_len) + { +- register unsigned long r0 asm("0") = (unsigned long) func; +- register unsigned long r1 asm("1") = (unsigned long) param; +- register unsigned long r2 asm("2") = (unsigned long) dest; +- register unsigned long r3 asm("3") = (unsigned long) dest_len; +- register unsigned long r4 asm("4") = (unsigned long) seed; +- register unsigned long r5 asm("5") = (unsigned long) seed_len; ++ union register_pair d, s; + ++ d.even = (unsigned long)dest; ++ d.odd = (unsigned long)dest_len; ++ s.even = (unsigned long)seed; ++ s.odd = (unsigned long)seed_len; + asm volatile ( ++ " lgr 0,%[fc]\n" ++ " lgr 1,%[pba]\n" + "0: .insn rre,%[opc] << 16,%[dst],%[seed]\n" + " brc 1,0b\n" /* handle partial completion */ +- : [dst] "+a" (r2), [dlen] "+d" (r3) +- : [fc] "d" (r0), [pba] "a" (r1), +- [seed] "a" (r4), [slen] "d" (r5), [opc] "i" (CPACF_PRNO) +- : "cc", "memory"); ++ : [dst] "+&d" (d.pair) ++ : [fc] "d" (func), [pba] "d" ((unsigned long)param), ++ [seed] "d" (s.pair), [opc] "i" (CPACF_PRNO) ++ : "cc", "memory", "0", "1"); + } + + /** +@@ -443,19 +455,19 @@ static inline void cpacf_prno(unsigned long func, void *param, + static inline void cpacf_trng(u8 *ucbuf, unsigned long ucbuf_len, + u8 *cbuf, unsigned long cbuf_len) + { +- register unsigned long r0 asm("0") = (unsigned long) CPACF_PRNO_TRNG; +- register unsigned long r2 asm("2") = (unsigned long) ucbuf; +- register unsigned long r3 asm("3") = (unsigned long) ucbuf_len; +- register unsigned long r4 asm("4") = (unsigned long) cbuf; +- register unsigned long r5 asm("5") = (unsigned long) cbuf_len; ++ union register_pair u, c; + ++ u.even = (unsigned long)ucbuf; ++ u.odd = (unsigned long)ucbuf_len; ++ c.even = (unsigned long)cbuf; ++ c.odd = (unsigned long)cbuf_len; + asm volatile ( ++ " lghi 0,%[fc]\n" + "0: .insn rre,%[opc] << 16,%[ucbuf],%[cbuf]\n" + " brc 1,0b\n" /* handle partial completion */ +- : [ucbuf] "+a" (r2), [ucbuflen] "+d" (r3), +- [cbuf] "+a" (r4), [cbuflen] "+d" (r5) +- : [fc] "d" (r0), [opc] "i" (CPACF_PRNO) +- : "cc", "memory"); ++ : [ucbuf] "+&d" (u.pair), [cbuf] "+&d" (c.pair) ++ : [fc] "K" (CPACF_PRNO_TRNG), [opc] "i" (CPACF_PRNO) ++ : "cc", "memory", "0"); + } + + /** +@@ -466,15 +478,15 @@ static inline void cpacf_trng(u8 *ucbuf, unsigned long ucbuf_len, + */ + static inline void cpacf_pcc(unsigned long func, void *param) + { +- register unsigned long r0 asm("0") = (unsigned long) func; +- register unsigned long r1 asm("1") = (unsigned long) param; +- + asm volatile( ++ " lgr 0,%[fc]\n" ++ " lgr 1,%[pba]\n" + "0: .insn rre,%[opc] << 16,0,0\n" /* PCC opcode */ + " brc 1,0b\n" /* handle partial completion */ + : +- : [fc] "d" (r0), [pba] "a" (r1), [opc] "i" (CPACF_PCC) +- : "cc", "memory"); ++ : [fc] "d" (func), [pba] "d" ((unsigned long)param), ++ [opc] "i" (CPACF_PCC) ++ : "cc", "memory", "0", "1"); + } + + /** +@@ -487,14 +499,14 @@ static inline void cpacf_pcc(unsigned long func, void *param) + */ + static inline void cpacf_pckmo(long func, void *param) + { +- register unsigned long r0 asm("0") = (unsigned long) func; +- register unsigned long r1 asm("1") = (unsigned long) param; +- + asm volatile( ++ " lgr 0,%[fc]\n" ++ " lgr 1,%[pba]\n" + " .insn rre,%[opc] << 16,0,0\n" /* PCKMO opcode */ + : +- : [fc] "d" (r0), [pba] "a" (r1), [opc] "i" (CPACF_PCKMO) +- : "cc", "memory"); ++ : [fc] "d" (func), [pba] "d" ((unsigned long)param), ++ [opc] "i" (CPACF_PCKMO) ++ : "cc", "memory", "0", "1"); + } + + /** +@@ -512,21 +524,23 @@ static inline void cpacf_kma(unsigned long func, void *param, u8 *dest, + const u8 *src, unsigned long src_len, + const u8 *aad, unsigned long aad_len) + { +- register unsigned long r0 asm("0") = (unsigned long) func; +- register unsigned long r1 asm("1") = (unsigned long) param; +- register unsigned long r2 asm("2") = (unsigned long) src; +- register unsigned long r3 asm("3") = (unsigned long) src_len; +- register unsigned long r4 asm("4") = (unsigned long) aad; +- register unsigned long r5 asm("5") = (unsigned long) aad_len; +- register unsigned long r6 asm("6") = (unsigned long) dest; ++ union register_pair d, s, a; + ++ d.even = (unsigned long)dest; ++ s.even = (unsigned long)src; ++ s.odd = (unsigned long)src_len; ++ a.even = (unsigned long)aad; ++ a.odd = (unsigned long)aad_len; + asm volatile( ++ " lgr 0,%[fc]\n" ++ " lgr 1,%[pba]\n" + "0: .insn rrf,%[opc] << 16,%[dst],%[src],%[aad],0\n" + " brc 1,0b\n" /* handle partial completion */ +- : [dst] "+a" (r6), [src] "+a" (r2), [slen] "+d" (r3), +- [aad] "+a" (r4), [alen] "+d" (r5) +- : [fc] "d" (r0), [pba] "a" (r1), [opc] "i" (CPACF_KMA) +- : "cc", "memory"); ++ : [dst] "+&d" (d.pair), [src] "+&d" (s.pair), ++ [aad] "+&d" (a.pair) ++ : [fc] "d" (func), [pba] "d" ((unsigned long)param), ++ [opc] "i" (CPACF_KMA) ++ : "cc", "memory", "0", "1"); + } + + #endif /* _ASM_S390_CPACF_H */ +-- +2.43.0 + diff --git a/queue-5.10/s390-cpacf-split-and-rework-cpacf-query-functions.patch b/queue-5.10/s390-cpacf-split-and-rework-cpacf-query-functions.patch new file mode 100644 index 00000000000..e75c575bb08 --- /dev/null +++ b/queue-5.10/s390-cpacf-split-and-rework-cpacf-query-functions.patch @@ -0,0 +1,152 @@ +From 10586c7ae6ec3b01d18b5385fc96ffc248958045 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 May 2024 11:31:42 +0200 +Subject: s390/cpacf: Split and rework cpacf query functions + +From: Harald Freudenberger + +[ Upstream commit 830999bd7e72f4128b9dfa37090d9fa8120ce323 ] + +Rework the cpacf query functions to use the correct RRE +or RRF instruction formats and set register fields within +instructions correctly. + +Fixes: 1afd43e0fbba ("s390/crypto: allow to query all known cpacf functions") +Reported-by: Nina Schoetterl-Glausch +Suggested-by: Heiko Carstens +Suggested-by: Juergen Christ +Suggested-by: Holger Dengler +Signed-off-by: Harald Freudenberger +Reviewed-by: Holger Dengler +Reviewed-by: Juergen Christ +Cc: +Signed-off-by: Heiko Carstens +Signed-off-by: Sasha Levin +--- + arch/s390/include/asm/cpacf.h | 101 +++++++++++++++++++++++++++------- + 1 file changed, 81 insertions(+), 20 deletions(-) + +diff --git a/arch/s390/include/asm/cpacf.h b/arch/s390/include/asm/cpacf.h +index 646b12981f208..fa31f71cf5746 100644 +--- a/arch/s390/include/asm/cpacf.h ++++ b/arch/s390/include/asm/cpacf.h +@@ -161,28 +161,79 @@ + + typedef struct { unsigned char bytes[16]; } cpacf_mask_t; + +-/** +- * cpacf_query() - check if a specific CPACF function is available +- * @opcode: the opcode of the crypto instruction +- * @func: the function code to test for +- * +- * Executes the query function for the given crypto instruction @opcode +- * and checks if @func is available +- * +- * Returns 1 if @func is available for @opcode, 0 otherwise +- */ +-static __always_inline void __cpacf_query(unsigned int opcode, cpacf_mask_t *mask) ++static __always_inline void __cpacf_query_rre(u32 opc, u8 r1, u8 r2, ++ cpacf_mask_t *mask) + { + asm volatile( +- " lghi 0,0\n" /* query function */ +- " lgr 1,%[mask]\n" +- " spm 0\n" /* pckmo doesn't change the cc */ +- /* Parameter regs are ignored, but must be nonzero and unique */ +- "0: .insn rrf,%[opc] << 16,2,4,6,0\n" +- " brc 1,0b\n" /* handle partial completion */ +- : "=m" (*mask) +- : [mask] "d" ((unsigned long)mask), [opc] "i" (opcode) +- : "cc", "0", "1"); ++ " la %%r1,%[mask]\n" ++ " xgr %%r0,%%r0\n" ++ " .insn rre,%[opc] << 16,%[r1],%[r2]\n" ++ : [mask] "=R" (*mask) ++ : [opc] "i" (opc), ++ [r1] "i" (r1), [r2] "i" (r2) ++ : "cc", "r0", "r1"); ++} ++ ++static __always_inline void __cpacf_query_rrf(u32 opc, ++ u8 r1, u8 r2, u8 r3, u8 m4, ++ cpacf_mask_t *mask) ++{ ++ asm volatile( ++ " la %%r1,%[mask]\n" ++ " xgr %%r0,%%r0\n" ++ " .insn rrf,%[opc] << 16,%[r1],%[r2],%[r3],%[m4]\n" ++ : [mask] "=R" (*mask) ++ : [opc] "i" (opc), [r1] "i" (r1), [r2] "i" (r2), ++ [r3] "i" (r3), [m4] "i" (m4) ++ : "cc", "r0", "r1"); ++} ++ ++static __always_inline void __cpacf_query(unsigned int opcode, ++ cpacf_mask_t *mask) ++{ ++ switch (opcode) { ++ case CPACF_KDSA: ++ __cpacf_query_rre(CPACF_KDSA, 0, 2, mask); ++ break; ++ case CPACF_KIMD: ++ __cpacf_query_rre(CPACF_KIMD, 0, 2, mask); ++ break; ++ case CPACF_KLMD: ++ __cpacf_query_rre(CPACF_KLMD, 0, 2, mask); ++ break; ++ case CPACF_KM: ++ __cpacf_query_rre(CPACF_KM, 2, 4, mask); ++ break; ++ case CPACF_KMA: ++ __cpacf_query_rrf(CPACF_KMA, 2, 4, 6, 0, mask); ++ break; ++ case CPACF_KMAC: ++ __cpacf_query_rre(CPACF_KMAC, 0, 2, mask); ++ break; ++ case CPACF_KMC: ++ __cpacf_query_rre(CPACF_KMC, 2, 4, mask); ++ break; ++ case CPACF_KMCTR: ++ __cpacf_query_rrf(CPACF_KMCTR, 2, 4, 6, 0, mask); ++ break; ++ case CPACF_KMF: ++ __cpacf_query_rre(CPACF_KMF, 2, 4, mask); ++ break; ++ case CPACF_KMO: ++ __cpacf_query_rre(CPACF_KMO, 2, 4, mask); ++ break; ++ case CPACF_PCC: ++ __cpacf_query_rre(CPACF_PCC, 0, 0, mask); ++ break; ++ case CPACF_PCKMO: ++ __cpacf_query_rre(CPACF_PCKMO, 0, 0, mask); ++ break; ++ case CPACF_PRNO: ++ __cpacf_query_rre(CPACF_PRNO, 2, 4, mask); ++ break; ++ default: ++ BUG(); ++ } + } + + static __always_inline int __cpacf_check_opcode(unsigned int opcode) +@@ -210,6 +261,16 @@ static __always_inline int __cpacf_check_opcode(unsigned int opcode) + } + } + ++/** ++ * cpacf_query() - check if a specific CPACF function is available ++ * @opcode: the opcode of the crypto instruction ++ * @func: the function code to test for ++ * ++ * Executes the query function for the given crypto instruction @opcode ++ * and checks if @func is available ++ * ++ * Returns 1 if @func is available for @opcode, 0 otherwise ++ */ + static __always_inline int cpacf_query(unsigned int opcode, cpacf_mask_t *mask) + { + if (__cpacf_check_opcode(opcode)) { +-- +2.43.0 + diff --git a/queue-5.10/selftests-mm-compaction_test-fix-bogus-test-success-.patch b/queue-5.10/selftests-mm-compaction_test-fix-bogus-test-success-.patch new file mode 100644 index 00000000000..a6597b546ca --- /dev/null +++ b/queue-5.10/selftests-mm-compaction_test-fix-bogus-test-success-.patch @@ -0,0 +1,109 @@ +From 9d8d252585ec1b5418abb31badaf842030dc7eec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 May 2024 13:13:56 +0530 +Subject: selftests/mm: compaction_test: fix bogus test success on Aarch64 + +From: Dev Jain + +[ Upstream commit d4202e66a4b1fe6968f17f9f09bbc30d08f028a1 ] + +Patch series "Fixes for compaction_test", v2. + +The compaction_test memory selftest introduces fragmentation in memory +and then tries to allocate as many hugepages as possible. This series +addresses some problems. + +On Aarch64, if nr_hugepages == 0, then the test trivially succeeds since +compaction_index becomes 0, which is less than 3, due to no division by +zero exception being raised. We fix that by checking for division by +zero. + +Secondly, correctly set the number of hugepages to zero before trying +to set a large number of them. + +Now, consider a situation in which, at the start of the test, a non-zero +number of hugepages have been already set (while running the entire +selftests/mm suite, or manually by the admin). The test operates on 80% +of memory to avoid OOM-killer invocation, and because some memory is +already blocked by hugepages, it would increase the chance of OOM-killing. +Also, since mem_free used in check_compaction() is the value before we +set nr_hugepages to zero, the chance that the compaction_index will +be small is very high if the preset nr_hugepages was high, leading to a +bogus test success. + +This patch (of 3): + +Currently, if at runtime we are not able to allocate a huge page, the test +will trivially pass on Aarch64 due to no exception being raised on +division by zero while computing compaction_index. Fix that by checking +for nr_hugepages == 0. Anyways, in general, avoid a division by zero by +exiting the program beforehand. While at it, fix a typo, and handle the +case where the number of hugepages may overflow an integer. + +Link: https://lkml.kernel.org/r/20240521074358.675031-1-dev.jain@arm.com +Link: https://lkml.kernel.org/r/20240521074358.675031-2-dev.jain@arm.com +Fixes: bd67d5c15cc1 ("Test compaction of mlocked memory") +Signed-off-by: Dev Jain +Cc: Anshuman Khandual +Cc: Shuah Khan +Cc: Sri Jayaramappa +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/vm/compaction_test.c | 20 +++++++++++++------- + 1 file changed, 13 insertions(+), 7 deletions(-) + +diff --git a/tools/testing/selftests/vm/compaction_test.c b/tools/testing/selftests/vm/compaction_test.c +index 6aa6460b854ea..309b3750e57e1 100644 +--- a/tools/testing/selftests/vm/compaction_test.c ++++ b/tools/testing/selftests/vm/compaction_test.c +@@ -82,12 +82,13 @@ int prereq(void) + return -1; + } + +-int check_compaction(unsigned long mem_free, unsigned int hugepage_size) ++int check_compaction(unsigned long mem_free, unsigned long hugepage_size) + { ++ unsigned long nr_hugepages_ul; + int fd, ret = -1; + int compaction_index = 0; +- char initial_nr_hugepages[10] = {0}; +- char nr_hugepages[10] = {0}; ++ char initial_nr_hugepages[20] = {0}; ++ char nr_hugepages[20] = {0}; + + /* We want to test with 80% of available memory. Else, OOM killer comes + in to play */ +@@ -136,7 +137,12 @@ int check_compaction(unsigned long mem_free, unsigned int hugepage_size) + + /* We should have been able to request at least 1/3 rd of the memory in + huge pages */ +- compaction_index = mem_free/(atoi(nr_hugepages) * hugepage_size); ++ nr_hugepages_ul = strtoul(nr_hugepages, NULL, 10); ++ if (!nr_hugepages_ul) { ++ ksft_print_msg("ERROR: No memory is available as huge pages\n"); ++ goto close_fd; ++ } ++ compaction_index = mem_free/(nr_hugepages_ul * hugepage_size); + + lseek(fd, 0, SEEK_SET); + +@@ -147,11 +153,11 @@ int check_compaction(unsigned long mem_free, unsigned int hugepage_size) + goto close_fd; + } + +- ksft_print_msg("Number of huge pages allocated = %d\n", +- atoi(nr_hugepages)); ++ ksft_print_msg("Number of huge pages allocated = %lu\n", ++ nr_hugepages_ul); + + if (compaction_index > 3) { +- ksft_print_msg("ERROR: Less that 1/%d of memory is available\n" ++ ksft_print_msg("ERROR: Less than 1/%d of memory is available\n" + "as huge pages\n", compaction_index); + goto close_fd; + } +-- +2.43.0 + diff --git a/queue-5.10/selftests-mm-compaction_test-fix-incorrect-write-of-.patch b/queue-5.10/selftests-mm-compaction_test-fix-incorrect-write-of-.patch new file mode 100644 index 00000000000..6d0488c376c --- /dev/null +++ b/queue-5.10/selftests-mm-compaction_test-fix-incorrect-write-of-.patch @@ -0,0 +1,43 @@ +From 6f99f28bb952990648ac6317f192158cb93bbb6c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 May 2024 13:13:57 +0530 +Subject: selftests/mm: compaction_test: fix incorrect write of zero to + nr_hugepages + +From: Dev Jain + +[ Upstream commit 9ad665ef55eaad1ead1406a58a34f615a7c18b5e ] + +Currently, the test tries to set nr_hugepages to zero, but that is not +actually done because the file offset is not reset after read(). Fix that +using lseek(). + +Link: https://lkml.kernel.org/r/20240521074358.675031-3-dev.jain@arm.com +Fixes: bd67d5c15cc1 ("Test compaction of mlocked memory") +Signed-off-by: Dev Jain +Cc: +Cc: Anshuman Khandual +Cc: Shuah Khan +Cc: Sri Jayaramappa +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/vm/compaction_test.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tools/testing/selftests/vm/compaction_test.c b/tools/testing/selftests/vm/compaction_test.c +index 9b420140ba2ba..55dec92e1e58c 100644 +--- a/tools/testing/selftests/vm/compaction_test.c ++++ b/tools/testing/selftests/vm/compaction_test.c +@@ -103,6 +103,8 @@ int check_compaction(unsigned long mem_free, unsigned int hugepage_size) + goto close_fd; + } + ++ lseek(fd, 0, SEEK_SET); ++ + /* Start with the initial condition of 0 huge pages*/ + if (write(fd, "0", sizeof(char)) != sizeof(char)) { + perror("Failed to write 0 to /proc/sys/vm/nr_hugepages\n"); +-- +2.43.0 + diff --git a/queue-5.10/selftests-mm-conform-test-to-tap-format-output.patch b/queue-5.10/selftests-mm-conform-test-to-tap-format-output.patch new file mode 100644 index 00000000000..3448e2cc330 --- /dev/null +++ b/queue-5.10/selftests-mm-conform-test-to-tap-format-output.patch @@ -0,0 +1,229 @@ +From 64a8a975546c054c6ada33eeaaa9b15d456fb9cd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jan 2024 13:36:12 +0500 +Subject: selftests/mm: conform test to TAP format output + +From: Muhammad Usama Anjum + +[ Upstream commit 9a21701edc41465de56f97914741bfb7bfc2517d ] + +Conform the layout, informational and status messages to TAP. No +functional change is intended other than the layout of output messages. + +Link: https://lkml.kernel.org/r/20240101083614.1076768-1-usama.anjum@collabora.com +Signed-off-by: Muhammad Usama Anjum +Cc: Shuah Khan +Signed-off-by: Andrew Morton +Stable-dep-of: d4202e66a4b1 ("selftests/mm: compaction_test: fix bogus test success on Aarch64") +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/vm/compaction_test.c | 91 ++++++++++---------- + 1 file changed, 44 insertions(+), 47 deletions(-) + +diff --git a/tools/testing/selftests/vm/compaction_test.c b/tools/testing/selftests/vm/compaction_test.c +index 55dec92e1e58c..f81931c1f8386 100644 +--- a/tools/testing/selftests/vm/compaction_test.c ++++ b/tools/testing/selftests/vm/compaction_test.c +@@ -33,7 +33,7 @@ int read_memory_info(unsigned long *memfree, unsigned long *hugepagesize) + FILE *cmdfile = popen(cmd, "r"); + + if (!(fgets(buffer, sizeof(buffer), cmdfile))) { +- perror("Failed to read meminfo\n"); ++ ksft_print_msg("Failed to read meminfo: %s\n", strerror(errno)); + return -1; + } + +@@ -44,7 +44,7 @@ int read_memory_info(unsigned long *memfree, unsigned long *hugepagesize) + cmdfile = popen(cmd, "r"); + + if (!(fgets(buffer, sizeof(buffer), cmdfile))) { +- perror("Failed to read meminfo\n"); ++ ksft_print_msg("Failed to read meminfo: %s\n", strerror(errno)); + return -1; + } + +@@ -62,14 +62,14 @@ int prereq(void) + fd = open("/proc/sys/vm/compact_unevictable_allowed", + O_RDONLY | O_NONBLOCK); + if (fd < 0) { +- perror("Failed to open\n" +- "/proc/sys/vm/compact_unevictable_allowed\n"); ++ ksft_print_msg("Failed to open /proc/sys/vm/compact_unevictable_allowed: %s\n", ++ strerror(errno)); + return -1; + } + + if (read(fd, &allowed, sizeof(char)) != sizeof(char)) { +- perror("Failed to read from\n" +- "/proc/sys/vm/compact_unevictable_allowed\n"); ++ ksft_print_msg("Failed to read from /proc/sys/vm/compact_unevictable_allowed: %s\n", ++ strerror(errno)); + close(fd); + return -1; + } +@@ -78,12 +78,13 @@ int prereq(void) + if (allowed == '1') + return 0; + ++ ksft_print_msg("Compaction isn't allowed\n"); + return -1; + } + + int check_compaction(unsigned long mem_free, unsigned int hugepage_size) + { +- int fd; ++ int fd, ret = -1; + int compaction_index = 0; + char initial_nr_hugepages[10] = {0}; + char nr_hugepages[10] = {0}; +@@ -94,12 +95,14 @@ int check_compaction(unsigned long mem_free, unsigned int hugepage_size) + + fd = open("/proc/sys/vm/nr_hugepages", O_RDWR | O_NONBLOCK); + if (fd < 0) { +- perror("Failed to open /proc/sys/vm/nr_hugepages"); ++ ksft_test_result_fail("Failed to open /proc/sys/vm/nr_hugepages: %s\n", ++ strerror(errno)); + return -1; + } + + if (read(fd, initial_nr_hugepages, sizeof(initial_nr_hugepages)) <= 0) { +- perror("Failed to read from /proc/sys/vm/nr_hugepages"); ++ ksft_test_result_fail("Failed to read from /proc/sys/vm/nr_hugepages: %s\n", ++ strerror(errno)); + goto close_fd; + } + +@@ -107,7 +110,8 @@ int check_compaction(unsigned long mem_free, unsigned int hugepage_size) + + /* Start with the initial condition of 0 huge pages*/ + if (write(fd, "0", sizeof(char)) != sizeof(char)) { +- perror("Failed to write 0 to /proc/sys/vm/nr_hugepages\n"); ++ ksft_test_result_fail("Failed to write 0 to /proc/sys/vm/nr_hugepages: %s\n", ++ strerror(errno)); + goto close_fd; + } + +@@ -116,14 +120,16 @@ int check_compaction(unsigned long mem_free, unsigned int hugepage_size) + /* Request a large number of huge pages. The Kernel will allocate + as much as it can */ + if (write(fd, "100000", (6*sizeof(char))) != (6*sizeof(char))) { +- perror("Failed to write 100000 to /proc/sys/vm/nr_hugepages\n"); ++ ksft_test_result_fail("Failed to write 100000 to /proc/sys/vm/nr_hugepages: %s\n", ++ strerror(errno)); + goto close_fd; + } + + lseek(fd, 0, SEEK_SET); + + if (read(fd, nr_hugepages, sizeof(nr_hugepages)) <= 0) { +- perror("Failed to re-read from /proc/sys/vm/nr_hugepages\n"); ++ ksft_test_result_fail("Failed to re-read from /proc/sys/vm/nr_hugepages: %s\n", ++ strerror(errno)); + goto close_fd; + } + +@@ -131,67 +137,58 @@ int check_compaction(unsigned long mem_free, unsigned int hugepage_size) + huge pages */ + compaction_index = mem_free/(atoi(nr_hugepages) * hugepage_size); + +- if (compaction_index > 3) { +- printf("No of huge pages allocated = %d\n", +- (atoi(nr_hugepages))); +- fprintf(stderr, "ERROR: Less that 1/%d of memory is available\n" +- "as huge pages\n", compaction_index); +- goto close_fd; +- } +- +- printf("No of huge pages allocated = %d\n", +- (atoi(nr_hugepages))); +- + lseek(fd, 0, SEEK_SET); + + if (write(fd, initial_nr_hugepages, strlen(initial_nr_hugepages)) + != strlen(initial_nr_hugepages)) { +- perror("Failed to write value to /proc/sys/vm/nr_hugepages\n"); ++ ksft_test_result_fail("Failed to write value to /proc/sys/vm/nr_hugepages: %s\n", ++ strerror(errno)); + goto close_fd; + } + +- close(fd); +- return 0; ++ if (compaction_index > 3) { ++ ksft_print_msg("ERROR: Less that 1/%d of memory is available\n" ++ "as huge pages\n", compaction_index); ++ ksft_test_result_fail("No of huge pages allocated = %d\n", (atoi(nr_hugepages))); ++ goto close_fd; ++ } ++ ++ ksft_test_result_pass("Memory compaction succeeded. No of huge pages allocated = %d\n", ++ (atoi(nr_hugepages))); ++ ret = 0; + + close_fd: + close(fd); +- printf("Not OK. Compaction test failed."); +- return -1; ++ return ret; + } + + + int main(int argc, char **argv) + { + struct rlimit lim; +- struct map_list *list, *entry; ++ struct map_list *list = NULL, *entry; + size_t page_size, i; + void *map = NULL; + unsigned long mem_free = 0; + unsigned long hugepage_size = 0; + long mem_fragmentable_MB = 0; + +- if (prereq() != 0) { +- printf("Either the sysctl compact_unevictable_allowed is not\n" +- "set to 1 or couldn't read the proc file.\n" +- "Skipping the test\n"); +- return KSFT_SKIP; +- } ++ ksft_print_header(); ++ ++ if (prereq() != 0) ++ return ksft_exit_pass(); ++ ++ ksft_set_plan(1); + + lim.rlim_cur = RLIM_INFINITY; + lim.rlim_max = RLIM_INFINITY; +- if (setrlimit(RLIMIT_MEMLOCK, &lim)) { +- perror("Failed to set rlimit:\n"); +- return -1; +- } ++ if (setrlimit(RLIMIT_MEMLOCK, &lim)) ++ ksft_exit_fail_msg("Failed to set rlimit: %s\n", strerror(errno)); + + page_size = getpagesize(); + +- list = NULL; +- +- if (read_memory_info(&mem_free, &hugepage_size) != 0) { +- printf("ERROR: Cannot read meminfo\n"); +- return -1; +- } ++ if (read_memory_info(&mem_free, &hugepage_size) != 0) ++ ksft_exit_fail_msg("Failed to get meminfo\n"); + + mem_fragmentable_MB = mem_free * 0.8 / 1024; + +@@ -227,7 +224,7 @@ int main(int argc, char **argv) + } + + if (check_compaction(mem_free, hugepage_size) == 0) +- return 0; ++ return ksft_exit_pass(); + +- return -1; ++ return ksft_exit_fail(); + } +-- +2.43.0 + diff --git a/queue-5.10/selftests-mm-log-a-consistent-test-name-for-check_co.patch b/queue-5.10/selftests-mm-log-a-consistent-test-name-for-check_co.patch new file mode 100644 index 00000000000..159c5fd217d --- /dev/null +++ b/queue-5.10/selftests-mm-log-a-consistent-test-name-for-check_co.patch @@ -0,0 +1,124 @@ +From 6ba5b2b42f336d4ea9dfb04eac54464007ab588c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Feb 2024 14:30:04 +0000 +Subject: selftests/mm: log a consistent test name for check_compaction + +From: Mark Brown + +[ Upstream commit f3b7568c49420d2dcd251032c9ca1e069ec8a6c9 ] + +Every test result report in the compaction test prints a distinct log +messae, and some of the reports print a name that varies at runtime. This +causes problems for automation since a lot of automation software uses the +printed string as the name of the test, if the name varies from run to run +and from pass to fail then the automation software can't identify that a +test changed result or that the same tests are being run. + +Refactor the logging to use a consistent name when printing the result of +the test, printing the existing messages as diagnostic information instead +so they are still available for people trying to interpret the results. + +Link: https://lkml.kernel.org/r/20240209-kselftest-mm-cleanup-v1-2-a3c0386496b5@kernel.org +Signed-off-by: Mark Brown +Cc: Muhammad Usama Anjum +Cc: Ryan Roberts +Cc: Shuah Khan +Signed-off-by: Andrew Morton +Stable-dep-of: d4202e66a4b1 ("selftests/mm: compaction_test: fix bogus test success on Aarch64") +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/vm/compaction_test.c | 35 +++++++++++--------- + 1 file changed, 19 insertions(+), 16 deletions(-) + +diff --git a/tools/testing/selftests/vm/compaction_test.c b/tools/testing/selftests/vm/compaction_test.c +index f81931c1f8386..6aa6460b854ea 100644 +--- a/tools/testing/selftests/vm/compaction_test.c ++++ b/tools/testing/selftests/vm/compaction_test.c +@@ -95,14 +95,15 @@ int check_compaction(unsigned long mem_free, unsigned int hugepage_size) + + fd = open("/proc/sys/vm/nr_hugepages", O_RDWR | O_NONBLOCK); + if (fd < 0) { +- ksft_test_result_fail("Failed to open /proc/sys/vm/nr_hugepages: %s\n", +- strerror(errno)); +- return -1; ++ ksft_print_msg("Failed to open /proc/sys/vm/nr_hugepages: %s\n", ++ strerror(errno)); ++ ret = -1; ++ goto out; + } + + if (read(fd, initial_nr_hugepages, sizeof(initial_nr_hugepages)) <= 0) { +- ksft_test_result_fail("Failed to read from /proc/sys/vm/nr_hugepages: %s\n", +- strerror(errno)); ++ ksft_print_msg("Failed to read from /proc/sys/vm/nr_hugepages: %s\n", ++ strerror(errno)); + goto close_fd; + } + +@@ -110,8 +111,8 @@ int check_compaction(unsigned long mem_free, unsigned int hugepage_size) + + /* Start with the initial condition of 0 huge pages*/ + if (write(fd, "0", sizeof(char)) != sizeof(char)) { +- ksft_test_result_fail("Failed to write 0 to /proc/sys/vm/nr_hugepages: %s\n", +- strerror(errno)); ++ ksft_print_msg("Failed to write 0 to /proc/sys/vm/nr_hugepages: %s\n", ++ strerror(errno)); + goto close_fd; + } + +@@ -120,16 +121,16 @@ int check_compaction(unsigned long mem_free, unsigned int hugepage_size) + /* Request a large number of huge pages. The Kernel will allocate + as much as it can */ + if (write(fd, "100000", (6*sizeof(char))) != (6*sizeof(char))) { +- ksft_test_result_fail("Failed to write 100000 to /proc/sys/vm/nr_hugepages: %s\n", +- strerror(errno)); ++ ksft_print_msg("Failed to write 100000 to /proc/sys/vm/nr_hugepages: %s\n", ++ strerror(errno)); + goto close_fd; + } + + lseek(fd, 0, SEEK_SET); + + if (read(fd, nr_hugepages, sizeof(nr_hugepages)) <= 0) { +- ksft_test_result_fail("Failed to re-read from /proc/sys/vm/nr_hugepages: %s\n", +- strerror(errno)); ++ ksft_print_msg("Failed to re-read from /proc/sys/vm/nr_hugepages: %s\n", ++ strerror(errno)); + goto close_fd; + } + +@@ -141,24 +142,26 @@ int check_compaction(unsigned long mem_free, unsigned int hugepage_size) + + if (write(fd, initial_nr_hugepages, strlen(initial_nr_hugepages)) + != strlen(initial_nr_hugepages)) { +- ksft_test_result_fail("Failed to write value to /proc/sys/vm/nr_hugepages: %s\n", +- strerror(errno)); ++ ksft_print_msg("Failed to write value to /proc/sys/vm/nr_hugepages: %s\n", ++ strerror(errno)); + goto close_fd; + } + ++ ksft_print_msg("Number of huge pages allocated = %d\n", ++ atoi(nr_hugepages)); ++ + if (compaction_index > 3) { + ksft_print_msg("ERROR: Less that 1/%d of memory is available\n" + "as huge pages\n", compaction_index); +- ksft_test_result_fail("No of huge pages allocated = %d\n", (atoi(nr_hugepages))); + goto close_fd; + } + +- ksft_test_result_pass("Memory compaction succeeded. No of huge pages allocated = %d\n", +- (atoi(nr_hugepages))); + ret = 0; + + close_fd: + close(fd); ++ out: ++ ksft_test_result(ret == 0, "check_compaction\n"); + return ret; + } + +-- +2.43.0 + diff --git a/queue-5.10/serial-sc16is7xx-fix-bug-in-sc16is7xx_set_baud-when-.patch b/queue-5.10/serial-sc16is7xx-fix-bug-in-sc16is7xx_set_baud-when-.patch new file mode 100644 index 00000000000..016ffbf3c85 --- /dev/null +++ b/queue-5.10/serial-sc16is7xx-fix-bug-in-sc16is7xx_set_baud-when-.patch @@ -0,0 +1,96 @@ +From a0ca3d11410709cb0a2ba584d83dee6be31c72db Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Apr 2024 16:04:30 -0400 +Subject: serial: sc16is7xx: fix bug in sc16is7xx_set_baud() when using + prescaler + +From: Hugo Villeneuve + +[ Upstream commit 8492bd91aa055907c67ef04f2b56f6dadd1f44bf ] + +When using a high speed clock with a low baud rate, the 4x prescaler is +automatically selected if required. In that case, sc16is7xx_set_baud() +properly configures the chip registers, but returns an incorrect baud +rate by not taking into account the prescaler value. This incorrect baud +rate is then fed to uart_update_timeout(). + +For example, with an input clock of 80MHz, and a selected baud rate of 50, +sc16is7xx_set_baud() will return 200 instead of 50. + +Fix this by first changing the prescaler variable to hold the selected +prescaler value instead of the MCR bitfield. Then properly take into +account the selected prescaler value in the return value computation. + +Also add better documentation about the divisor value computation. + +Fixes: dfeae619d781 ("serial: sc16is7xx") +Cc: stable@vger.kernel.org +Signed-off-by: Hugo Villeneuve +Reviewed-by: Jiri Slaby +Link: https://lore.kernel.org/r/20240430200431.4102923-1-hugo@hugovil.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/sc16is7xx.c | 23 ++++++++++++++++++----- + 1 file changed, 18 insertions(+), 5 deletions(-) + +diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c +index 88b84d43c2d62..4ea52426acf9e 100644 +--- a/drivers/tty/serial/sc16is7xx.c ++++ b/drivers/tty/serial/sc16is7xx.c +@@ -490,16 +490,28 @@ static bool sc16is7xx_regmap_noinc(struct device *dev, unsigned int reg) + return reg == SC16IS7XX_RHR_REG; + } + ++/* ++ * Configure programmable baud rate generator (divisor) according to the ++ * desired baud rate. ++ * ++ * From the datasheet, the divisor is computed according to: ++ * ++ * XTAL1 input frequency ++ * ----------------------- ++ * prescaler ++ * divisor = --------------------------- ++ * baud-rate x sampling-rate ++ */ + static int sc16is7xx_set_baud(struct uart_port *port, int baud) + { + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + u8 lcr; +- u8 prescaler = 0; ++ unsigned int prescaler = 1; + unsigned long clk = port->uartclk, div = clk / 16 / baud; + + if (div >= BIT(16)) { +- prescaler = SC16IS7XX_MCR_CLKSEL_BIT; +- div /= 4; ++ prescaler = 4; ++ div /= prescaler; + } + + /* In an amazing feat of design, the Enhanced Features Register shares +@@ -534,9 +546,10 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud) + + mutex_unlock(&s->efr_lock); + ++ /* If bit MCR_CLKSEL is set, the divide by 4 prescaler is activated. */ + sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, + SC16IS7XX_MCR_CLKSEL_BIT, +- prescaler); ++ prescaler == 1 ? 0 : SC16IS7XX_MCR_CLKSEL_BIT); + + /* Open the LCR divisors for configuration */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, +@@ -551,7 +564,7 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud) + /* Put LCR back to the normal mode */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); + +- return DIV_ROUND_CLOSEST(clk / 16, div); ++ return DIV_ROUND_CLOSEST((clk / prescaler) / 16, div); + } + + static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen, +-- +2.43.0 + diff --git a/queue-5.10/serial-sc16is7xx-replace-hardcoded-divisor-value-wit.patch b/queue-5.10/serial-sc16is7xx-replace-hardcoded-divisor-value-wit.patch new file mode 100644 index 00000000000..47fa31b7628 --- /dev/null +++ b/queue-5.10/serial-sc16is7xx-replace-hardcoded-divisor-value-wit.patch @@ -0,0 +1,39 @@ +From bba559d382ae1020cf656eaac7e54c94dee375ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 Dec 2023 18:18:19 -0500 +Subject: serial: sc16is7xx: replace hardcoded divisor value with BIT() macro + +From: Hugo Villeneuve + +[ Upstream commit 2e57cefc4477659527f7adab1f87cdbf60ef1ae6 ] + +To better show why the limit is what it is, since we have only 16 bits for +the divisor. + +Reviewed-by: Andy Shevchenko +Suggested-by: Andy Shevchenko +Signed-off-by: Hugo Villeneuve +Link: https://lore.kernel.org/r/20231221231823.2327894-13-hugo@hugovil.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 8492bd91aa05 ("serial: sc16is7xx: fix bug in sc16is7xx_set_baud() when using prescaler") +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/sc16is7xx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c +index d751f8ce5cf6d..88b84d43c2d62 100644 +--- a/drivers/tty/serial/sc16is7xx.c ++++ b/drivers/tty/serial/sc16is7xx.c +@@ -497,7 +497,7 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud) + u8 prescaler = 0; + unsigned long clk = port->uartclk, div = clk / 16 / baud; + +- if (div > 0xffff) { ++ if (div >= BIT(16)) { + prescaler = SC16IS7XX_MCR_CLKSEL_BIT; + div /= 4; + } +-- +2.43.0 + diff --git a/queue-5.10/series b/queue-5.10/series index 1c71237920a..0fda1d09217 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -296,3 +296,61 @@ scsi-ufs-ufs-qcom-clear-qunipro_g4_sel-for-hw-major-version-5.patch f2fs-compress-fix-compression-chksum.patch rdma-hns-use-mutex-instead-of-spinlock-for-ida-allocation.patch rdma-hns-fix-cq-and-qp-cache-affinity.patch +wifi-mac80211-mesh-fix-leak-of-mesh_preq_queue-objec.patch +wifi-mac80211-fix-deadlock-in-ieee80211_sta_ps_deliv.patch +wifi-cfg80211-pmsr-use-correct-nla_get_ux-functions.patch +wifi-iwlwifi-mvm-revert-gen2-tx-a-mpdu-size-to-64.patch +wifi-iwlwifi-dbg_ini-move-iwl_dbg_tlv_free-outside-o.patch +wifi-iwlwifi-mvm-check-n_ssids-before-accessing-the-.patch +wifi-iwlwifi-mvm-don-t-read-past-the-mfuart-notifcat.patch +wifi-mac80211-correctly-parse-spatial-reuse-paramete.patch +net-ncsi-add-ncsi-intel-oem-command-to-keep-phy-up.patch +net-ncsi-simplify-kconfig-dts-control-flow.patch +net-ncsi-fix-the-multi-thread-manner-of-ncsi-driver.patch +ipv6-sr-block-bh-in-seg6_output_core-and-seg6_input_.patch +net-sched-sch_multiq-fix-possible-oob-write-in-multi.patch +vxlan-fix-regression-when-dropping-packets-due-to-in.patch +tcp-count-close-wait-sockets-for-tcp_mib_currestab.patch +net-sched-taprio-always-validate-tca_taprio_attr_pri.patch +ptp-fix-error-message-on-failed-pin-verification.patch +af_unix-annotate-data-race-of-sk-sk_state-in-unix_in.patch +af_unix-annotate-data-races-around-sk-sk_state-in-un.patch +af_unix-annotate-data-races-around-sk-sk_state-in-se.patch +af_unix-annotate-data-races-around-sk-sk_state-in-un.patch-31294 +af_unix-annotate-data-race-of-net-unx.sysctl_max_dgr.patch +af_unix-use-unix_recvq_full_lockless-in-unix_stream_.patch +af_unix-use-skb_queue_len_lockless-in-sk_diag_show_r.patch +af_unix-annotate-data-race-of-sk-sk_shutdown-in-sk_d.patch +ipv6-fix-possible-race-in-__fib6_drop_pcpu_from.patch +usb-gadget-f_fs-remove-likely-unlikely.patch +usb-gadget-f_fs-fix-race-between-aio_cancel-and-aio-.patch +pm-core-redefine-pm_ptr-macro.patch +pm-core-add-new-_pm_ops-macros-deprecate-old-ones.patch +mmc-jz4740-use-the-new-pm-macros.patch +mmc-mxc-use-the-new-pm-macros.patch +pm-core-remove-static-qualifier-in-define_simple_dev.patch +iio-accel-mxc4005-allow-module-autoloading-via-of-co.patch +iio-accel-mxc4005-reset-chip-on-probe-and-resume.patch +drm-amd-display-handle-y-carry-over-in-vcp-x.y-calcu.patch +serial-sc16is7xx-replace-hardcoded-divisor-value-wit.patch +serial-sc16is7xx-fix-bug-in-sc16is7xx_set_baud-when-.patch +driver-core-platform-reorder-functions.patch +driver-core-platform-change-logic-implementing-platf.patch +driver-core-platform-use-bus_type-functions.patch +driver-core-platform-emit-a-warning-if-a-remove-call.patch +platform-provide-a-remove-callback-that-returns-no-v.patch +mmc-davinci_mmc-convert-to-platform-remove-callback-.patch +mmc-davinci-don-t-strip-remove-function-when-driver-.patch +i2c-core-add-managed-function-for-adding-i2c-adapter.patch +i2c-add-fwnode-apis.patch +i2c-acpi-unbind-mux-adapters-before-delete.patch +selftests-mm-compaction_test-fix-incorrect-write-of-.patch +selftests-mm-conform-test-to-tap-format-output.patch +selftests-mm-log-a-consistent-test-name-for-check_co.patch +selftests-mm-compaction_test-fix-bogus-test-success-.patch +s390-cpacf-get-rid-of-register-asm.patch +s390-cpacf-split-and-rework-cpacf-query-functions.patch +btrfs-fix-leak-of-qgroup-extent-records-after-transa.patch +nilfs2-remove-check-for-pageerror.patch +nilfs2-return-the-mapped-address-from-nilfs_get_page.patch +nilfs2-fix-nilfs_empty_dir-misjudgment-and-long-loop.patch diff --git a/queue-5.10/tcp-count-close-wait-sockets-for-tcp_mib_currestab.patch b/queue-5.10/tcp-count-close-wait-sockets-for-tcp_mib_currestab.patch new file mode 100644 index 00000000000..585441e66b6 --- /dev/null +++ b/queue-5.10/tcp-count-close-wait-sockets-for-tcp_mib_currestab.patch @@ -0,0 +1,71 @@ +From 0e16c34abbaf3475779f879203d3abf233fa9e7e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Jun 2024 01:02:16 +0800 +Subject: tcp: count CLOSE-WAIT sockets for TCP_MIB_CURRESTAB + +From: Jason Xing + +[ Upstream commit a46d0ea5c94205f40ecf912d1bb7806a8a64704f ] + +According to RFC 1213, we should also take CLOSE-WAIT sockets into +consideration: + + "tcpCurrEstab OBJECT-TYPE + ... + The number of TCP connections for which the current state + is either ESTABLISHED or CLOSE- WAIT." + +After this, CurrEstab counter will display the total number of +ESTABLISHED and CLOSE-WAIT sockets. + +The logic of counting +When we increment the counter? +a) if we change the state to ESTABLISHED. +b) if we change the state from SYN-RECEIVED to CLOSE-WAIT. + +When we decrement the counter? +a) if the socket leaves ESTABLISHED and will never go into CLOSE-WAIT, +say, on the client side, changing from ESTABLISHED to FIN-WAIT-1. +b) if the socket leaves CLOSE-WAIT, say, on the server side, changing +from CLOSE-WAIT to LAST-ACK. + +Please note: there are two chances that old state of socket can be changed +to CLOSE-WAIT in tcp_fin(). One is SYN-RECV, the other is ESTABLISHED. +So we have to take care of the former case. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Jason Xing +Reviewed-by: Eric Dumazet +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 4ed0d303791a1..0a495b6edbc4b 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -2420,6 +2420,10 @@ void tcp_set_state(struct sock *sk, int state) + if (oldstate != TCP_ESTABLISHED) + TCP_INC_STATS(sock_net(sk), TCP_MIB_CURRESTAB); + break; ++ case TCP_CLOSE_WAIT: ++ if (oldstate == TCP_SYN_RECV) ++ TCP_INC_STATS(sock_net(sk), TCP_MIB_CURRESTAB); ++ break; + + case TCP_CLOSE: + if (oldstate == TCP_CLOSE_WAIT || oldstate == TCP_ESTABLISHED) +@@ -2431,7 +2435,7 @@ void tcp_set_state(struct sock *sk, int state) + inet_put_port(sk); + fallthrough; + default: +- if (oldstate == TCP_ESTABLISHED) ++ if (oldstate == TCP_ESTABLISHED || oldstate == TCP_CLOSE_WAIT) + TCP_DEC_STATS(sock_net(sk), TCP_MIB_CURRESTAB); + } + +-- +2.43.0 + diff --git a/queue-5.10/usb-gadget-f_fs-fix-race-between-aio_cancel-and-aio-.patch b/queue-5.10/usb-gadget-f_fs-fix-race-between-aio_cancel-and-aio-.patch new file mode 100644 index 00000000000..e273aa5c265 --- /dev/null +++ b/queue-5.10/usb-gadget-f_fs-fix-race-between-aio_cancel-and-aio-.patch @@ -0,0 +1,86 @@ +From 3c2189b8b4a78ba6dfeaa5df1483abfccc72459e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Apr 2024 18:40:59 -0700 +Subject: usb: gadget: f_fs: Fix race between aio_cancel() and AIO request + complete + +From: Wesley Cheng + +[ Upstream commit 24729b307eefcd7c476065cd7351c1a018082c19 ] + +FFS based applications can utilize the aio_cancel() callback to dequeue +pending USB requests submitted to the UDC. There is a scenario where the +FFS application issues an AIO cancel call, while the UDC is handling a +soft disconnect. For a DWC3 based implementation, the callstack looks +like the following: + + DWC3 Gadget FFS Application +dwc3_gadget_soft_disconnect() ... + --> dwc3_stop_active_transfers() + --> dwc3_gadget_giveback(-ESHUTDOWN) + --> ffs_epfile_async_io_complete() ffs_aio_cancel() + --> usb_ep_free_request() --> usb_ep_dequeue() + +There is currently no locking implemented between the AIO completion +handler and AIO cancel, so the issue occurs if the completion routine is +running in parallel to an AIO cancel call coming from the FFS application. +As the completion call frees the USB request (io_data->req) the FFS +application is also referencing it for the usb_ep_dequeue() call. This can +lead to accessing a stale/hanging pointer. + +commit b566d38857fc ("usb: gadget: f_fs: use io_data->status consistently") +relocated the usb_ep_free_request() into ffs_epfile_async_io_complete(). +However, in order to properly implement locking to mitigate this issue, the +spinlock can't be added to ffs_epfile_async_io_complete(), as +usb_ep_dequeue() (if successfully dequeuing a USB request) will call the +function driver's completion handler in the same context. Hence, leading +into a deadlock. + +Fix this issue by moving the usb_ep_free_request() back to +ffs_user_copy_worker(), and ensuring that it explicitly sets io_data->req +to NULL after freeing it within the ffs->eps_lock. This resolves the race +condition above, as the ffs_aio_cancel() routine will not continue +attempting to dequeue a request that has already been freed, or the +ffs_user_copy_work() not freeing the USB request until the AIO cancel is +done referencing it. + +This fix depends on + commit b566d38857fc ("usb: gadget: f_fs: use io_data->status + consistently") + +Fixes: 2e4c7553cd6f ("usb: gadget: f_fs: add aio support") +Cc: stable # b566d38857fc ("usb: gadget: f_fs: use io_data->status consistently") +Signed-off-by: Wesley Cheng +Link: https://lore.kernel.org/r/20240409014059.6740-1-quic_wcheng@quicinc.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/gadget/function/f_fs.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c +index 7fd6d97cdb063..6744e8c1f0d29 100644 +--- a/drivers/usb/gadget/function/f_fs.c ++++ b/drivers/usb/gadget/function/f_fs.c +@@ -827,6 +827,7 @@ static void ffs_user_copy_worker(struct work_struct *work) + int ret = io_data->req->status ? io_data->req->status : + io_data->req->actual; + bool kiocb_has_eventfd = io_data->kiocb->ki_flags & IOCB_EVENTFD; ++ unsigned long flags; + + if (io_data->read && ret > 0) { + kthread_use_mm(io_data->mm); +@@ -839,7 +840,10 @@ static void ffs_user_copy_worker(struct work_struct *work) + if (io_data->ffs->ffs_eventfd && !kiocb_has_eventfd) + eventfd_signal(io_data->ffs->ffs_eventfd, 1); + ++ spin_lock_irqsave(&io_data->ffs->eps_lock, flags); + usb_ep_free_request(io_data->ep, io_data->req); ++ io_data->req = NULL; ++ spin_unlock_irqrestore(&io_data->ffs->eps_lock, flags); + + if (io_data->read) + kfree(io_data->to_free); +-- +2.43.0 + diff --git a/queue-5.10/usb-gadget-f_fs-remove-likely-unlikely.patch b/queue-5.10/usb-gadget-f_fs-remove-likely-unlikely.patch new file mode 100644 index 00000000000..fae0052bfdf --- /dev/null +++ b/queue-5.10/usb-gadget-f_fs-remove-likely-unlikely.patch @@ -0,0 +1,740 @@ +From 07d9ac1068d8d3e68fad1590b9405aba16be30cf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Nov 2020 15:05:59 +0100 +Subject: USB: gadget: f_fs: remove likely/unlikely + +From: Greg Kroah-Hartman + +[ Upstream commit 8704fd73bf5658bf4b827643f7f526481082d83f ] + +They are used way too often in this file, in some ways that are actually +wrong. Almost all of these are already known by the compiler and CPU so +just remove them all as none of these should be on any "hot paths" where +it actually matters. + +Cc: Felipe Balbi +Reported-by: Peter Chen +Reviewed-by: Peter Chen +Link: https://lore.kernel.org/r/20201127140559.381351-6-gregkh@linuxfoundation.org +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 24729b307eef ("usb: gadget: f_fs: Fix race between aio_cancel() and AIO request complete") +Signed-off-by: Sasha Levin +--- + drivers/usb/gadget/function/f_fs.c | 177 ++++++++++++++--------------- + 1 file changed, 88 insertions(+), 89 deletions(-) + +diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c +index ad7df99f09a4c..7fd6d97cdb063 100644 +--- a/drivers/usb/gadget/function/f_fs.c ++++ b/drivers/usb/gadget/function/f_fs.c +@@ -301,11 +301,11 @@ static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len) + reinit_completion(&ffs->ep0req_completion); + + ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC); +- if (unlikely(ret < 0)) ++ if (ret < 0) + return ret; + + ret = wait_for_completion_interruptible(&ffs->ep0req_completion); +- if (unlikely(ret)) { ++ if (ret) { + usb_ep_dequeue(ffs->gadget->ep0, req); + return -EINTR; + } +@@ -342,7 +342,7 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, + + /* Acquire mutex */ + ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); +- if (unlikely(ret < 0)) ++ if (ret < 0) + return ret; + + /* Check state */ +@@ -350,7 +350,7 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, + case FFS_READ_DESCRIPTORS: + case FFS_READ_STRINGS: + /* Copy data */ +- if (unlikely(len < 16)) { ++ if (len < 16) { + ret = -EINVAL; + break; + } +@@ -365,7 +365,7 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, + if (ffs->state == FFS_READ_DESCRIPTORS) { + pr_info("read descriptors\n"); + ret = __ffs_data_got_descs(ffs, data, len); +- if (unlikely(ret < 0)) ++ if (ret < 0) + break; + + ffs->state = FFS_READ_STRINGS; +@@ -373,11 +373,11 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, + } else { + pr_info("read strings\n"); + ret = __ffs_data_got_strings(ffs, data, len); +- if (unlikely(ret < 0)) ++ if (ret < 0) + break; + + ret = ffs_epfiles_create(ffs); +- if (unlikely(ret)) { ++ if (ret) { + ffs->state = FFS_CLOSING; + break; + } +@@ -386,7 +386,7 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, + mutex_unlock(&ffs->mutex); + + ret = ffs_ready(ffs); +- if (unlikely(ret < 0)) { ++ if (ret < 0) { + ffs->state = FFS_CLOSING; + return ret; + } +@@ -500,7 +500,7 @@ static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf, + spin_unlock_irq(&ffs->ev.waitq.lock); + mutex_unlock(&ffs->mutex); + +- return unlikely(copy_to_user(buf, events, size)) ? -EFAULT : size; ++ return copy_to_user(buf, events, size) ? -EFAULT : size; + } + + static ssize_t ffs_ep0_read(struct file *file, char __user *buf, +@@ -519,7 +519,7 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf, + + /* Acquire mutex */ + ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); +- if (unlikely(ret < 0)) ++ if (ret < 0) + return ret; + + /* Check state */ +@@ -541,7 +541,7 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf, + + case FFS_NO_SETUP: + n = len / sizeof(struct usb_functionfs_event); +- if (unlikely(!n)) { ++ if (!n) { + ret = -EINVAL; + break; + } +@@ -572,9 +572,9 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf, + + spin_unlock_irq(&ffs->ev.waitq.lock); + +- if (likely(len)) { ++ if (len) { + data = kmalloc(len, GFP_KERNEL); +- if (unlikely(!data)) { ++ if (!data) { + ret = -ENOMEM; + goto done_mutex; + } +@@ -591,7 +591,7 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf, + + /* unlocks spinlock */ + ret = __ffs_ep0_queue_wait(ffs, data, len); +- if (likely(ret > 0) && unlikely(copy_to_user(buf, data, len))) ++ if ((ret > 0) && (copy_to_user(buf, data, len))) + ret = -EFAULT; + goto done_mutex; + +@@ -613,7 +613,7 @@ static int ffs_ep0_open(struct inode *inode, struct file *file) + + ENTER(); + +- if (unlikely(ffs->state == FFS_CLOSING)) ++ if (ffs->state == FFS_CLOSING) + return -EBUSY; + + file->private_data = ffs; +@@ -662,7 +662,7 @@ static __poll_t ffs_ep0_poll(struct file *file, poll_table *wait) + poll_wait(file, &ffs->ev.waitq, wait); + + ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); +- if (unlikely(ret < 0)) ++ if (ret < 0) + return mask; + + switch (ffs->state) { +@@ -711,7 +711,7 @@ static const struct file_operations ffs_ep0_operations = { + static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req) + { + ENTER(); +- if (likely(req->context)) { ++ if (req->context) { + struct ffs_ep *ep = _ep->driver_data; + ep->status = req->status ? req->status : req->actual; + complete(req->context); +@@ -721,10 +721,10 @@ static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req) + static ssize_t ffs_copy_to_iter(void *data, int data_len, struct iov_iter *iter) + { + ssize_t ret = copy_to_iter(data, data_len, iter); +- if (likely(ret == data_len)) ++ if (ret == data_len) + return ret; + +- if (unlikely(iov_iter_count(iter))) ++ if (iov_iter_count(iter)) + return -EFAULT; + + /* +@@ -890,7 +890,7 @@ static ssize_t __ffs_epfile_read_buffered(struct ffs_epfile *epfile, + return ret; + } + +- if (unlikely(iov_iter_count(iter))) { ++ if (iov_iter_count(iter)) { + ret = -EFAULT; + } else { + buf->length -= ret; +@@ -911,10 +911,10 @@ static ssize_t __ffs_epfile_read_data(struct ffs_epfile *epfile, + struct ffs_buffer *buf; + + ssize_t ret = copy_to_iter(data, data_len, iter); +- if (likely(data_len == ret)) ++ if (data_len == ret) + return ret; + +- if (unlikely(iov_iter_count(iter))) ++ if (iov_iter_count(iter)) + return -EFAULT; + + /* See ffs_copy_to_iter for more context. */ +@@ -935,7 +935,7 @@ static ssize_t __ffs_epfile_read_data(struct ffs_epfile *epfile, + * in struct ffs_epfile for full read_buffer pointer synchronisation + * story. + */ +- if (unlikely(cmpxchg(&epfile->read_buffer, NULL, buf))) ++ if (cmpxchg(&epfile->read_buffer, NULL, buf)) + kfree(buf); + + return ret; +@@ -973,7 +973,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) + + /* We will be using request and read_buffer */ + ret = ffs_mutex_lock(&epfile->mutex, file->f_flags & O_NONBLOCK); +- if (unlikely(ret)) ++ if (ret) + goto error; + + /* Allocate & copy */ +@@ -1018,7 +1018,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) + spin_unlock_irq(&epfile->ffs->eps_lock); + + data = ffs_alloc_buffer(io_data, data_len); +- if (unlikely(!data)) { ++ if (!data) { + ret = -ENOMEM; + goto error_mutex; + } +@@ -1038,7 +1038,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) + ret = usb_ep_set_halt(ep->ep); + if (!ret) + ret = -EBADMSG; +- } else if (unlikely(data_len == -EINVAL)) { ++ } else if (data_len == -EINVAL) { + /* + * Sanity Check: even though data_len can't be used + * uninitialized at the time I write this comment, some +@@ -1073,12 +1073,12 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) + req->complete = ffs_epfile_io_complete; + + ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); +- if (unlikely(ret < 0)) ++ if (ret < 0) + goto error_lock; + + spin_unlock_irq(&epfile->ffs->eps_lock); + +- if (unlikely(wait_for_completion_interruptible(&done))) { ++ if (wait_for_completion_interruptible(&done)) { + /* + * To avoid race condition with ffs_epfile_io_complete, + * dequeue the request first then check +@@ -1120,7 +1120,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) + req->complete = ffs_epfile_async_io_complete; + + ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); +- if (unlikely(ret)) { ++ if (ret) { + io_data->req = NULL; + usb_ep_free_request(ep->ep, req); + goto error_lock; +@@ -1171,7 +1171,7 @@ static int ffs_aio_cancel(struct kiocb *kiocb) + + spin_lock_irqsave(&epfile->ffs->eps_lock, flags); + +- if (likely(io_data && io_data->ep && io_data->req)) ++ if (io_data && io_data->ep && io_data->req) + value = usb_ep_dequeue(io_data->ep, io_data->req); + else + value = -EINVAL; +@@ -1190,7 +1190,7 @@ static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from) + + if (!is_sync_kiocb(kiocb)) { + p = kzalloc(sizeof(io_data), GFP_KERNEL); +- if (unlikely(!p)) ++ if (!p) + return -ENOMEM; + p->aio = true; + } else { +@@ -1227,7 +1227,7 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to) + + if (!is_sync_kiocb(kiocb)) { + p = kzalloc(sizeof(io_data), GFP_KERNEL); +- if (unlikely(!p)) ++ if (!p) + return -ENOMEM; + p->aio = true; + } else { +@@ -1391,7 +1391,7 @@ ffs_sb_make_inode(struct super_block *sb, void *data, + + inode = new_inode(sb); + +- if (likely(inode)) { ++ if (inode) { + struct timespec64 ts = current_time(inode); + + inode->i_ino = get_next_ino(); +@@ -1423,11 +1423,11 @@ static struct dentry *ffs_sb_create_file(struct super_block *sb, + ENTER(); + + dentry = d_alloc_name(sb->s_root, name); +- if (unlikely(!dentry)) ++ if (!dentry) + return NULL; + + inode = ffs_sb_make_inode(sb, data, fops, NULL, &ffs->file_perms); +- if (unlikely(!inode)) { ++ if (!inode) { + dput(dentry); + return NULL; + } +@@ -1474,12 +1474,11 @@ static int ffs_sb_fill(struct super_block *sb, struct fs_context *fc) + &simple_dir_inode_operations, + &data->perms); + sb->s_root = d_make_root(inode); +- if (unlikely(!sb->s_root)) ++ if (!sb->s_root) + return -ENOMEM; + + /* EP0 file */ +- if (unlikely(!ffs_sb_create_file(sb, "ep0", ffs, +- &ffs_ep0_operations))) ++ if (!ffs_sb_create_file(sb, "ep0", ffs, &ffs_ep0_operations)) + return -ENOMEM; + + return 0; +@@ -1567,13 +1566,13 @@ static int ffs_fs_get_tree(struct fs_context *fc) + return invalf(fc, "No source specified"); + + ffs = ffs_data_new(fc->source); +- if (unlikely(!ffs)) ++ if (!ffs) + return -ENOMEM; + ffs->file_perms = ctx->perms; + ffs->no_disconnect = ctx->no_disconnect; + + ffs->dev_name = kstrdup(fc->source, GFP_KERNEL); +- if (unlikely(!ffs->dev_name)) { ++ if (!ffs->dev_name) { + ffs_data_put(ffs); + return -ENOMEM; + } +@@ -1655,7 +1654,7 @@ static int functionfs_init(void) + ENTER(); + + ret = register_filesystem(&ffs_fs_type); +- if (likely(!ret)) ++ if (!ret) + pr_info("file system registered\n"); + else + pr_err("failed registering file system (%d)\n", ret); +@@ -1700,7 +1699,7 @@ static void ffs_data_put(struct ffs_data *ffs) + { + ENTER(); + +- if (unlikely(refcount_dec_and_test(&ffs->ref))) { ++ if (refcount_dec_and_test(&ffs->ref)) { + pr_info("%s(): freeing\n", __func__); + ffs_data_clear(ffs); + ffs_release_dev(ffs->private_data); +@@ -1751,7 +1750,7 @@ static void ffs_data_closed(struct ffs_data *ffs) + static struct ffs_data *ffs_data_new(const char *dev_name) + { + struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL); +- if (unlikely(!ffs)) ++ if (!ffs) + return NULL; + + ENTER(); +@@ -1857,11 +1856,11 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev) + return -EBADFD; + + first_id = usb_string_ids_n(cdev, ffs->strings_count); +- if (unlikely(first_id < 0)) ++ if (first_id < 0) + return first_id; + + ffs->ep0req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL); +- if (unlikely(!ffs->ep0req)) ++ if (!ffs->ep0req) + return -ENOMEM; + ffs->ep0req->complete = ffs_ep0_complete; + ffs->ep0req->context = ffs; +@@ -1921,7 +1920,7 @@ static int ffs_epfiles_create(struct ffs_data *ffs) + epfile->dentry = ffs_sb_create_file(ffs->sb, epfile->name, + epfile, + &ffs_epfile_operations); +- if (unlikely(!epfile->dentry)) { ++ if (!epfile->dentry) { + ffs_epfiles_destroy(epfiles, i - 1); + return -ENOMEM; + } +@@ -1962,7 +1961,7 @@ static void ffs_func_eps_disable(struct ffs_function *func) + ep = func->eps; + while (count--) { + /* pending requests get nuked */ +- if (likely(ep->ep)) ++ if (ep->ep) + usb_ep_disable(ep->ep); + ++ep; + +@@ -2000,7 +1999,7 @@ static int ffs_func_eps_enable(struct ffs_function *func) + } + + ret = usb_ep_enable(ep->ep); +- if (likely(!ret)) { ++ if (!ret) { + epfile->ep = ep; + epfile->in = usb_endpoint_dir_in(ep->ep->desc); + epfile->isoc = usb_endpoint_xfer_isoc(ep->ep->desc); +@@ -2073,12 +2072,12 @@ static int __must_check ffs_do_single_desc(char *data, unsigned len, + #define __entity_check_ENDPOINT(val) ((val) & USB_ENDPOINT_NUMBER_MASK) + #define __entity(type, val) do { \ + pr_vdebug("entity " #type "(%02x)\n", (val)); \ +- if (unlikely(!__entity_check_ ##type(val))) { \ ++ if (!__entity_check_ ##type(val)) { \ + pr_vdebug("invalid entity's value\n"); \ + return -EINVAL; \ + } \ + ret = entity(FFS_ ##type, &val, _ds, priv); \ +- if (unlikely(ret < 0)) { \ ++ if (ret < 0) { \ + pr_debug("entity " #type "(%02x); ret = %d\n", \ + (val), ret); \ + return ret; \ +@@ -2203,7 +2202,7 @@ static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len, + + /* Record "descriptor" entity */ + ret = entity(FFS_DESCRIPTOR, (u8 *)num, (void *)data, priv); +- if (unlikely(ret < 0)) { ++ if (ret < 0) { + pr_debug("entity DESCRIPTOR(%02lx); ret = %d\n", + num, ret); + return ret; +@@ -2214,7 +2213,7 @@ static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len, + + ret = ffs_do_single_desc(data, len, entity, priv, + ¤t_class); +- if (unlikely(ret < 0)) { ++ if (ret < 0) { + pr_debug("%s returns %d\n", __func__, ret); + return ret; + } +@@ -2320,7 +2319,7 @@ static int __must_check ffs_do_single_os_desc(char *data, unsigned len, + /* loop over all ext compat/ext prop descriptors */ + while (feature_count--) { + ret = entity(type, h, data, len, priv); +- if (unlikely(ret < 0)) { ++ if (ret < 0) { + pr_debug("bad OS descriptor, type: %d\n", type); + return ret; + } +@@ -2360,7 +2359,7 @@ static int __must_check ffs_do_os_descs(unsigned count, + return -EINVAL; + + ret = __ffs_do_os_desc_header(&type, desc); +- if (unlikely(ret < 0)) { ++ if (ret < 0) { + pr_debug("entity OS_DESCRIPTOR(%02lx); ret = %d\n", + num, ret); + return ret; +@@ -2381,7 +2380,7 @@ static int __must_check ffs_do_os_descs(unsigned count, + */ + ret = ffs_do_single_os_desc(data, len, type, + feature_count, entity, priv, desc); +- if (unlikely(ret < 0)) { ++ if (ret < 0) { + pr_debug("%s returns %d\n", __func__, ret); + return ret; + } +@@ -2613,20 +2612,20 @@ static int __ffs_data_got_strings(struct ffs_data *ffs, + + ENTER(); + +- if (unlikely(len < 16 || +- get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC || +- get_unaligned_le32(data + 4) != len)) ++ if (len < 16 || ++ get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC || ++ get_unaligned_le32(data + 4) != len) + goto error; + str_count = get_unaligned_le32(data + 8); + lang_count = get_unaligned_le32(data + 12); + + /* if one is zero the other must be zero */ +- if (unlikely(!str_count != !lang_count)) ++ if (!str_count != !lang_count) + goto error; + + /* Do we have at least as many strings as descriptors need? */ + needed_count = ffs->strings_count; +- if (unlikely(str_count < needed_count)) ++ if (str_count < needed_count) + goto error; + + /* +@@ -2650,7 +2649,7 @@ static int __ffs_data_got_strings(struct ffs_data *ffs, + + char *vlabuf = kmalloc(vla_group_size(d), GFP_KERNEL); + +- if (unlikely(!vlabuf)) { ++ if (!vlabuf) { + kfree(_data); + return -ENOMEM; + } +@@ -2678,7 +2677,7 @@ static int __ffs_data_got_strings(struct ffs_data *ffs, + unsigned needed = needed_count; + u32 str_per_lang = str_count; + +- if (unlikely(len < 3)) ++ if (len < 3) + goto error_free; + t->language = get_unaligned_le16(data); + t->strings = s; +@@ -2691,7 +2690,7 @@ static int __ffs_data_got_strings(struct ffs_data *ffs, + do { /* str_count > 0 so we can use do-while */ + size_t length = strnlen(data, len); + +- if (unlikely(length == len)) ++ if (length == len) + goto error_free; + + /* +@@ -2699,7 +2698,7 @@ static int __ffs_data_got_strings(struct ffs_data *ffs, + * if that's the case we simply ignore the + * rest + */ +- if (likely(needed)) { ++ if (needed) { + /* + * s->id will be set while adding + * function to configuration so for +@@ -2721,7 +2720,7 @@ static int __ffs_data_got_strings(struct ffs_data *ffs, + } while (--lang_count); + + /* Some garbage left? */ +- if (unlikely(len)) ++ if (len) + goto error_free; + + /* Done! */ +@@ -2868,7 +2867,7 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep, + + ffs_ep = func->eps + idx; + +- if (unlikely(ffs_ep->descs[ep_desc_id])) { ++ if (ffs_ep->descs[ep_desc_id]) { + pr_err("two %sspeed descriptors for EP %d\n", + speed_names[ep_desc_id], + ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); +@@ -2899,12 +2898,12 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep, + wMaxPacketSize = ds->wMaxPacketSize; + pr_vdebug("autoconfig\n"); + ep = usb_ep_autoconfig(func->gadget, ds); +- if (unlikely(!ep)) ++ if (!ep) + return -ENOTSUPP; + ep->driver_data = func->eps + idx; + + req = usb_ep_alloc_request(ep, GFP_KERNEL); +- if (unlikely(!req)) ++ if (!req) + return -ENOMEM; + + ffs_ep->ep = ep; +@@ -2946,7 +2945,7 @@ static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep, + idx = *valuep; + if (func->interfaces_nums[idx] < 0) { + int id = usb_interface_id(func->conf, &func->function); +- if (unlikely(id < 0)) ++ if (id < 0) + return id; + func->interfaces_nums[idx] = id; + } +@@ -2967,7 +2966,7 @@ static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep, + return 0; + + idx = (*valuep & USB_ENDPOINT_NUMBER_MASK) - 1; +- if (unlikely(!func->eps[idx].ep)) ++ if (!func->eps[idx].ep) + return -EINVAL; + + { +@@ -3152,12 +3151,12 @@ static int _ffs_func_bind(struct usb_configuration *c, + ENTER(); + + /* Has descriptors only for speeds gadget does not support */ +- if (unlikely(!(full | high | super))) ++ if (!(full | high | super)) + return -ENOTSUPP; + + /* Allocate a single chunk, less management later on */ + vlabuf = kzalloc(vla_group_size(d), GFP_KERNEL); +- if (unlikely(!vlabuf)) ++ if (!vlabuf) + return -ENOMEM; + + ffs->ms_os_descs_ext_prop_avail = vla_ptr(vlabuf, d, ext_prop); +@@ -3186,13 +3185,13 @@ static int _ffs_func_bind(struct usb_configuration *c, + * endpoints first, so that later we can rewrite the endpoint + * numbers without worrying that it may be described later on. + */ +- if (likely(full)) { ++ if (full) { + func->function.fs_descriptors = vla_ptr(vlabuf, d, fs_descs); + fs_len = ffs_do_descs(ffs->fs_descs_count, + vla_ptr(vlabuf, d, raw_descs), + d_raw_descs__sz, + __ffs_func_bind_do_descs, func); +- if (unlikely(fs_len < 0)) { ++ if (fs_len < 0) { + ret = fs_len; + goto error; + } +@@ -3200,13 +3199,13 @@ static int _ffs_func_bind(struct usb_configuration *c, + fs_len = 0; + } + +- if (likely(high)) { ++ if (high) { + func->function.hs_descriptors = vla_ptr(vlabuf, d, hs_descs); + hs_len = ffs_do_descs(ffs->hs_descs_count, + vla_ptr(vlabuf, d, raw_descs) + fs_len, + d_raw_descs__sz - fs_len, + __ffs_func_bind_do_descs, func); +- if (unlikely(hs_len < 0)) { ++ if (hs_len < 0) { + ret = hs_len; + goto error; + } +@@ -3214,14 +3213,14 @@ static int _ffs_func_bind(struct usb_configuration *c, + hs_len = 0; + } + +- if (likely(super)) { ++ if (super) { + func->function.ss_descriptors = func->function.ssp_descriptors = + vla_ptr(vlabuf, d, ss_descs); + ss_len = ffs_do_descs(ffs->ss_descs_count, + vla_ptr(vlabuf, d, raw_descs) + fs_len + hs_len, + d_raw_descs__sz - fs_len - hs_len, + __ffs_func_bind_do_descs, func); +- if (unlikely(ss_len < 0)) { ++ if (ss_len < 0) { + ret = ss_len; + goto error; + } +@@ -3239,7 +3238,7 @@ static int _ffs_func_bind(struct usb_configuration *c, + (super ? ffs->ss_descs_count : 0), + vla_ptr(vlabuf, d, raw_descs), d_raw_descs__sz, + __ffs_func_bind_do_nums, func); +- if (unlikely(ret < 0)) ++ if (ret < 0) + goto error; + + func->function.os_desc_table = vla_ptr(vlabuf, d, os_desc_table); +@@ -3260,7 +3259,7 @@ static int _ffs_func_bind(struct usb_configuration *c, + d_raw_descs__sz - fs_len - hs_len - + ss_len, + __ffs_func_bind_do_os_desc, func); +- if (unlikely(ret < 0)) ++ if (ret < 0) + goto error; + } + func->function.os_desc_n = +@@ -3311,7 +3310,7 @@ static int ffs_func_set_alt(struct usb_function *f, + + if (alt != (unsigned)-1) { + intf = ffs_func_revmap_intf(func, interface); +- if (unlikely(intf < 0)) ++ if (intf < 0) + return intf; + } + +@@ -3336,7 +3335,7 @@ static int ffs_func_set_alt(struct usb_function *f, + + ffs->func = func; + ret = ffs_func_eps_enable(func); +- if (likely(ret >= 0)) ++ if (ret >= 0) + ffs_event_add(ffs, FUNCTIONFS_ENABLE); + return ret; + } +@@ -3378,13 +3377,13 @@ static int ffs_func_setup(struct usb_function *f, + switch (creq->bRequestType & USB_RECIP_MASK) { + case USB_RECIP_INTERFACE: + ret = ffs_func_revmap_intf(func, le16_to_cpu(creq->wIndex)); +- if (unlikely(ret < 0)) ++ if (ret < 0) + return ret; + break; + + case USB_RECIP_ENDPOINT: + ret = ffs_func_revmap_ep(func, le16_to_cpu(creq->wIndex)); +- if (unlikely(ret < 0)) ++ if (ret < 0) + return ret; + if (func->ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR) + ret = func->ffs->eps_addrmap[ret]; +@@ -3643,7 +3642,7 @@ static struct usb_function *ffs_alloc(struct usb_function_instance *fi) + ENTER(); + + func = kzalloc(sizeof(*func), GFP_KERNEL); +- if (unlikely(!func)) ++ if (!func) + return ERR_PTR(-ENOMEM); + + func->function.name = "Function FS Gadget"; +@@ -3857,7 +3856,7 @@ static void ffs_closed(struct ffs_data *ffs) + static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock) + { + return nonblock +- ? likely(mutex_trylock(mutex)) ? 0 : -EAGAIN ++ ? mutex_trylock(mutex) ? 0 : -EAGAIN + : mutex_lock_interruptible(mutex); + } + +@@ -3865,14 +3864,14 @@ static char *ffs_prepare_buffer(const char __user *buf, size_t len) + { + char *data; + +- if (unlikely(!len)) ++ if (!len) + return NULL; + + data = kmalloc(len, GFP_KERNEL); +- if (unlikely(!data)) ++ if (!data) + return ERR_PTR(-ENOMEM); + +- if (unlikely(copy_from_user(data, buf, len))) { ++ if (copy_from_user(data, buf, len)) { + kfree(data); + return ERR_PTR(-EFAULT); + } +-- +2.43.0 + diff --git a/queue-5.10/vxlan-fix-regression-when-dropping-packets-due-to-in.patch b/queue-5.10/vxlan-fix-regression-when-dropping-packets-due-to-in.patch new file mode 100644 index 00000000000..e01e44e13ca --- /dev/null +++ b/queue-5.10/vxlan-fix-regression-when-dropping-packets-due-to-in.patch @@ -0,0 +1,65 @@ +From e5cb25603255ce56622859863cc61188d0c47ad8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Jun 2024 10:59:26 +0200 +Subject: vxlan: Fix regression when dropping packets due to invalid src + addresses + +From: Daniel Borkmann + +[ Upstream commit 1cd4bc987abb2823836cbb8f887026011ccddc8a ] + +Commit f58f45c1e5b9 ("vxlan: drop packets from invalid src-address") +has recently been added to vxlan mainly in the context of source +address snooping/learning so that when it is enabled, an entry in the +FDB is not being created for an invalid address for the corresponding +tunnel endpoint. + +Before commit f58f45c1e5b9 vxlan was similarly behaving as geneve in +that it passed through whichever macs were set in the L2 header. It +turns out that this change in behavior breaks setups, for example, +Cilium with netkit in L3 mode for Pods as well as tunnel mode has been +passing before the change in f58f45c1e5b9 for both vxlan and geneve. +After mentioned change it is only passing for geneve as in case of +vxlan packets are dropped due to vxlan_set_mac() returning false as +source and destination macs are zero which for E/W traffic via tunnel +is totally fine. + +Fix it by only opting into the is_valid_ether_addr() check in +vxlan_set_mac() when in fact source address snooping/learning is +actually enabled in vxlan. This is done by moving the check into +vxlan_snoop(). With this change, the Cilium connectivity test suite +passes again for both tunnel flavors. + +Fixes: f58f45c1e5b9 ("vxlan: drop packets from invalid src-address") +Signed-off-by: Daniel Borkmann +Cc: David Bauer +Cc: Ido Schimmel +Cc: Nikolay Aleksandrov +Cc: Martin KaFai Lau +Reviewed-by: Ido Schimmel +Reviewed-by: Nikolay Aleksandrov +Reviewed-by: David Bauer +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + drivers/net/vxlan/vxlan_core.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c +index 3096769e718ed..ec67d2eb05ecd 100644 +--- a/drivers/net/vxlan/vxlan_core.c ++++ b/drivers/net/vxlan/vxlan_core.c +@@ -1492,6 +1492,10 @@ static bool vxlan_snoop(struct net_device *dev, + struct vxlan_fdb *f; + u32 ifindex = 0; + ++ /* Ignore packets from invalid src-address */ ++ if (!is_valid_ether_addr(src_mac)) ++ return true; ++ + #if IS_ENABLED(CONFIG_IPV6) + if (src_ip->sa.sa_family == AF_INET6 && + (ipv6_addr_type(&src_ip->sin6.sin6_addr) & IPV6_ADDR_LINKLOCAL)) +-- +2.43.0 + diff --git a/queue-5.10/wifi-cfg80211-pmsr-use-correct-nla_get_ux-functions.patch b/queue-5.10/wifi-cfg80211-pmsr-use-correct-nla_get_ux-functions.patch new file mode 100644 index 00000000000..54d8a3c44ee --- /dev/null +++ b/queue-5.10/wifi-cfg80211-pmsr-use-correct-nla_get_ux-functions.patch @@ -0,0 +1,85 @@ +From a528ca0ccc81220c9b95f5ee10d3ed1cdc93630b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 May 2024 15:50:59 +0800 +Subject: wifi: cfg80211: pmsr: use correct nla_get_uX functions + +From: Lin Ma + +[ Upstream commit ab904521f4de52fef4f179d2dfc1877645ef5f5c ] + +The commit 9bb7e0f24e7e ("cfg80211: add peer measurement with FTM +initiator API") defines four attributes NL80211_PMSR_FTM_REQ_ATTR_ +{NUM_BURSTS_EXP}/{BURST_PERIOD}/{BURST_DURATION}/{FTMS_PER_BURST} in +following ways. + +static const struct nla_policy +nl80211_pmsr_ftm_req_attr_policy[NL80211_PMSR_FTM_REQ_ATTR_MAX + 1] = { + ... + [NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP] = + NLA_POLICY_MAX(NLA_U8, 15), + [NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD] = { .type = NLA_U16 }, + [NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION] = + NLA_POLICY_MAX(NLA_U8, 15), + [NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST] = + NLA_POLICY_MAX(NLA_U8, 31), + ... +}; + +That is, those attributes are expected to be NLA_U8 and NLA_U16 types. +However, the consumers of these attributes in `pmsr_parse_ftm` blindly +all use `nla_get_u32`, which is incorrect and causes functionality issues +on little-endian platforms. Hence, fix them with the correct `nla_get_u8` +and `nla_get_u16` functions. + +Fixes: 9bb7e0f24e7e ("cfg80211: add peer measurement with FTM initiator API") +Signed-off-by: Lin Ma +Link: https://msgid.link/20240521075059.47999-1-linma@zju.edu.cn +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/wireless/pmsr.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/net/wireless/pmsr.c b/net/wireless/pmsr.c +index a817d8e3e4b36..7503c7dd71ab5 100644 +--- a/net/wireless/pmsr.c ++++ b/net/wireless/pmsr.c +@@ -58,7 +58,7 @@ static int pmsr_parse_ftm(struct cfg80211_registered_device *rdev, + out->ftm.burst_period = 0; + if (tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD]) + out->ftm.burst_period = +- nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD]); ++ nla_get_u16(tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD]); + + out->ftm.asap = !!tb[NL80211_PMSR_FTM_REQ_ATTR_ASAP]; + if (out->ftm.asap && !capa->ftm.asap) { +@@ -77,7 +77,7 @@ static int pmsr_parse_ftm(struct cfg80211_registered_device *rdev, + out->ftm.num_bursts_exp = 0; + if (tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP]) + out->ftm.num_bursts_exp = +- nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP]); ++ nla_get_u8(tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP]); + + if (capa->ftm.max_bursts_exponent >= 0 && + out->ftm.num_bursts_exp > capa->ftm.max_bursts_exponent) { +@@ -90,7 +90,7 @@ static int pmsr_parse_ftm(struct cfg80211_registered_device *rdev, + out->ftm.burst_duration = 15; + if (tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION]) + out->ftm.burst_duration = +- nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION]); ++ nla_get_u8(tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION]); + + out->ftm.ftms_per_burst = 0; + if (tb[NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST]) +@@ -109,7 +109,7 @@ static int pmsr_parse_ftm(struct cfg80211_registered_device *rdev, + out->ftm.ftmr_retries = 3; + if (tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES]) + out->ftm.ftmr_retries = +- nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES]); ++ nla_get_u8(tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES]); + + out->ftm.request_lci = !!tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI]; + if (out->ftm.request_lci && !capa->ftm.request_lci) { +-- +2.43.0 + diff --git a/queue-5.10/wifi-iwlwifi-dbg_ini-move-iwl_dbg_tlv_free-outside-o.patch b/queue-5.10/wifi-iwlwifi-dbg_ini-move-iwl_dbg_tlv_free-outside-o.patch new file mode 100644 index 00000000000..346d9eb3d7c --- /dev/null +++ b/queue-5.10/wifi-iwlwifi-dbg_ini-move-iwl_dbg_tlv_free-outside-o.patch @@ -0,0 +1,41 @@ +From 52d8640a3aa89981462db28748277c8013d2a4be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 May 2024 17:06:39 +0300 +Subject: wifi: iwlwifi: dbg_ini: move iwl_dbg_tlv_free outside of debugfs + ifdef + +From: Shahar S Matityahu + +[ Upstream commit 87821b67dea87addbc4ab093ba752753b002176a ] + +The driver should call iwl_dbg_tlv_free even if debugfs is not defined +since ini mode does not depend on debugfs ifdef. + +Fixes: 68f6f492c4fa ("iwlwifi: trans: support loading ini TLVs from external file") +Signed-off-by: Shahar S Matityahu +Reviewed-by: Luciano Coelho +Signed-off-by: Miri Korenblit +Link: https://msgid.link/20240510170500.c8e3723f55b0.I5e805732b0be31ee6b83c642ec652a34e974ff10@changeid +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +index ab84ac3f8f03f..bf00c2fede746 100644 +--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c ++++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +@@ -1699,8 +1699,8 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans) + err_fw: + #ifdef CONFIG_IWLWIFI_DEBUGFS + debugfs_remove_recursive(drv->dbgfs_drv); +- iwl_dbg_tlv_free(drv->trans); + #endif ++ iwl_dbg_tlv_free(drv->trans); + kfree(drv); + err: + return ERR_PTR(ret); +-- +2.43.0 + diff --git a/queue-5.10/wifi-iwlwifi-mvm-check-n_ssids-before-accessing-the-.patch b/queue-5.10/wifi-iwlwifi-mvm-check-n_ssids-before-accessing-the-.patch new file mode 100644 index 00000000000..a1ef994b5a4 --- /dev/null +++ b/queue-5.10/wifi-iwlwifi-mvm-check-n_ssids-before-accessing-the-.patch @@ -0,0 +1,49 @@ +From a3fcbd28ff575241f277acd1865b4ed0aaff155a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 May 2024 13:27:12 +0300 +Subject: wifi: iwlwifi: mvm: check n_ssids before accessing the ssids + +From: Miri Korenblit + +[ Upstream commit 60d62757df30b74bf397a2847a6db7385c6ee281 ] + +In some versions of cfg80211, the ssids poinet might be a valid one even +though n_ssids is 0. Accessing the pointer in this case will cuase an +out-of-bound access. Fix this by checking n_ssids first. + +Fixes: c1a7515393e4 ("iwlwifi: mvm: add adaptive dwell support") +Signed-off-by: Miri Korenblit +Reviewed-by: Ilan Peer +Reviewed-by: Johannes Berg +Link: https://msgid.link/20240513132416.6e4d1762bf0d.I5a0e6cc8f02050a766db704d15594c61fe583d45@changeid +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +index 17b9925266947..a9df48c75155b 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +@@ -1354,7 +1354,7 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm, + if (IWL_MVM_ADWELL_MAX_BUDGET) + cmd->v7.adwell_max_budget = + cpu_to_le16(IWL_MVM_ADWELL_MAX_BUDGET); +- else if (params->ssids && params->ssids[0].ssid_len) ++ else if (params->n_ssids && params->ssids[0].ssid_len) + cmd->v7.adwell_max_budget = + cpu_to_le16(IWL_SCAN_ADWELL_MAX_BUDGET_DIRECTED_SCAN); + else +@@ -1456,7 +1456,7 @@ iwl_mvm_scan_umac_dwell_v10(struct iwl_mvm *mvm, + if (IWL_MVM_ADWELL_MAX_BUDGET) + general_params->adwell_max_budget = + cpu_to_le16(IWL_MVM_ADWELL_MAX_BUDGET); +- else if (params->ssids && params->ssids[0].ssid_len) ++ else if (params->n_ssids && params->ssids[0].ssid_len) + general_params->adwell_max_budget = + cpu_to_le16(IWL_SCAN_ADWELL_MAX_BUDGET_DIRECTED_SCAN); + else +-- +2.43.0 + diff --git a/queue-5.10/wifi-iwlwifi-mvm-don-t-read-past-the-mfuart-notifcat.patch b/queue-5.10/wifi-iwlwifi-mvm-don-t-read-past-the-mfuart-notifcat.patch new file mode 100644 index 00000000000..832b9f8d1a6 --- /dev/null +++ b/queue-5.10/wifi-iwlwifi-mvm-don-t-read-past-the-mfuart-notifcat.patch @@ -0,0 +1,55 @@ +From 5c6c4d97fdd87300f8ed069f2fef06fb6607d3e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 May 2024 13:27:14 +0300 +Subject: wifi: iwlwifi: mvm: don't read past the mfuart notifcation + +From: Emmanuel Grumbach + +[ Upstream commit 4bb95f4535489ed830cf9b34b0a891e384d1aee4 ] + +In case the firmware sends a notification that claims it has more data +than it has, we will read past that was allocated for the notification. +Remove the print of the buffer, we won't see it by default. If needed, +we can see the content with tracing. + +This was reported by KFENCE. + +Fixes: bdccdb854f2f ("iwlwifi: mvm: support MFUART dump in case of MFUART assert") +Signed-off-by: Emmanuel Grumbach +Reviewed-by: Johannes Berg +Signed-off-by: Miri Korenblit +Link: https://msgid.link/20240513132416.ba82a01a559e.Ia91dd20f5e1ca1ad380b95e68aebf2794f553d9b@changeid +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 10 ---------- + 1 file changed, 10 deletions(-) + +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +index 54b28f0932e25..793208d99b5f9 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +@@ -196,20 +196,10 @@ void iwl_mvm_mfu_assert_dump_notif(struct iwl_mvm *mvm, + { + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_mfu_assert_dump_notif *mfu_dump_notif = (void *)pkt->data; +- __le32 *dump_data = mfu_dump_notif->data; +- int n_words = le32_to_cpu(mfu_dump_notif->data_size) / sizeof(__le32); +- int i; + + if (mfu_dump_notif->index_num == 0) + IWL_INFO(mvm, "MFUART assert id 0x%x occurred\n", + le32_to_cpu(mfu_dump_notif->assert_id)); +- +- for (i = 0; i < n_words; i++) +- IWL_DEBUG_INFO(mvm, +- "MFUART assert dump, dword %u: 0x%08x\n", +- le16_to_cpu(mfu_dump_notif->index_num) * +- n_words + i, +- le32_to_cpu(dump_data[i])); + } + + static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, +-- +2.43.0 + diff --git a/queue-5.10/wifi-iwlwifi-mvm-revert-gen2-tx-a-mpdu-size-to-64.patch b/queue-5.10/wifi-iwlwifi-mvm-revert-gen2-tx-a-mpdu-size-to-64.patch new file mode 100644 index 00000000000..042377f4160 --- /dev/null +++ b/queue-5.10/wifi-iwlwifi-mvm-revert-gen2-tx-a-mpdu-size-to-64.patch @@ -0,0 +1,49 @@ +From 97e2f32158d1f24763aec651ee35359176d46add Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 May 2024 17:06:33 +0300 +Subject: wifi: iwlwifi: mvm: revert gen2 TX A-MPDU size to 64 + +From: Johannes Berg + +[ Upstream commit 4a7aace2899711592327463c1a29ffee44fcc66e ] + +We don't actually support >64 even for HE devices, so revert +back to 64. This fixes an issue where the session is refused +because the queue is configured differently from the actual +session later. + +Fixes: 514c30696fbc ("iwlwifi: add support for IEEE802.11ax") +Signed-off-by: Johannes Berg +Reviewed-by: Liad Kaufman +Reviewed-by: Luciano Coelho +Signed-off-by: Miri Korenblit +Link: https://msgid.link/20240510170500.52f7b4cf83aa.If47e43adddf7fe250ed7f5571fbb35d8221c7c47@changeid +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/intel/iwlwifi/mvm/rs.h | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h +index 32104c9f8f5ee..d59a47637d120 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h +@@ -133,13 +133,8 @@ enum { + + #define LINK_QUAL_AGG_FRAME_LIMIT_DEF (63) + #define LINK_QUAL_AGG_FRAME_LIMIT_MAX (63) +-/* +- * FIXME - various places in firmware API still use u8, +- * e.g. LQ command and SCD config command. +- * This should be 256 instead. +- */ +-#define LINK_QUAL_AGG_FRAME_LIMIT_GEN2_DEF (255) +-#define LINK_QUAL_AGG_FRAME_LIMIT_GEN2_MAX (255) ++#define LINK_QUAL_AGG_FRAME_LIMIT_GEN2_DEF (64) ++#define LINK_QUAL_AGG_FRAME_LIMIT_GEN2_MAX (64) + #define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0) + + #define LQ_SIZE 2 /* 2 mode tables: "Active" and "Search" */ +-- +2.43.0 + diff --git a/queue-5.10/wifi-mac80211-correctly-parse-spatial-reuse-paramete.patch b/queue-5.10/wifi-mac80211-correctly-parse-spatial-reuse-paramete.patch new file mode 100644 index 00000000000..06c78ad8cba --- /dev/null +++ b/queue-5.10/wifi-mac80211-correctly-parse-spatial-reuse-paramete.patch @@ -0,0 +1,65 @@ +From 200d1087f18a9827a918103418281508cce3b2ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 May 2024 10:18:54 +0800 +Subject: wifi: mac80211: correctly parse Spatial Reuse Parameter Set element + +From: Lingbo Kong + +[ Upstream commit a26d8dc5227f449a54518a8b40733a54c6600a8b ] + +Currently, the way of parsing Spatial Reuse Parameter Set element is +incorrect and some members of struct ieee80211_he_obss_pd are not assigned. + +To address this issue, it must be parsed in the order of the elements of +Spatial Reuse Parameter Set defined in the IEEE Std 802.11ax specification. + +The diagram of the Spatial Reuse Parameter Set element (IEEE Std 802.11ax +-2021-9.4.2.252). + +------------------------------------------------------------------------- +| | | | |Non-SRG| SRG | SRG | SRG | SRG | +|Element|Length| Element | SR |OBSS PD|OBSS PD|OBSS PD| BSS |Partial| +| ID | | ID |Control| Max | Min | Max |Color | BSSID | +| | |Extension| | Offset| Offset|Offset |Bitmap|Bitmap | +------------------------------------------------------------------------- + +Fixes: 1ced169cc1c2 ("mac80211: allow setting spatial reuse parameters from bss_conf") +Signed-off-by: Lingbo Kong +Link: https://msgid.link/20240516021854.5682-3-quic_lingbok@quicinc.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/he.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/net/mac80211/he.c b/net/mac80211/he.c +index cc26f239838ba..41413a4588db8 100644 +--- a/net/mac80211/he.c ++++ b/net/mac80211/he.c +@@ -127,15 +127,21 @@ ieee80211_he_spr_ie_to_bss_conf(struct ieee80211_vif *vif, + + if (!he_spr_ie_elem) + return; ++ ++ he_obss_pd->sr_ctrl = he_spr_ie_elem->he_sr_control; + data = he_spr_ie_elem->optional; + + if (he_spr_ie_elem->he_sr_control & + IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT) +- data++; ++ he_obss_pd->non_srg_max_offset = *data++; ++ + if (he_spr_ie_elem->he_sr_control & + IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT) { +- he_obss_pd->max_offset = *data++; + he_obss_pd->min_offset = *data++; ++ he_obss_pd->max_offset = *data++; ++ memcpy(he_obss_pd->bss_color_bitmap, data, 8); ++ data += 8; ++ memcpy(he_obss_pd->partial_bssid_bitmap, data, 8); + he_obss_pd->enable = true; + } + } +-- +2.43.0 + diff --git a/queue-5.10/wifi-mac80211-fix-deadlock-in-ieee80211_sta_ps_deliv.patch b/queue-5.10/wifi-mac80211-fix-deadlock-in-ieee80211_sta_ps_deliv.patch new file mode 100644 index 00000000000..fff1db62b95 --- /dev/null +++ b/queue-5.10/wifi-mac80211-fix-deadlock-in-ieee80211_sta_ps_deliv.patch @@ -0,0 +1,109 @@ +From 299a2af46894e367984c12a07a3d066346eaeee8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 May 2024 08:57:53 +0200 +Subject: wifi: mac80211: Fix deadlock in ieee80211_sta_ps_deliver_wakeup() + +From: Remi Pommarel + +[ Upstream commit 44c06bbde6443de206b30f513100b5670b23fc5e ] + +The ieee80211_sta_ps_deliver_wakeup() function takes sta->ps_lock to +synchronizes with ieee80211_tx_h_unicast_ps_buf() which is called from +softirq context. However using only spin_lock() to get sta->ps_lock in +ieee80211_sta_ps_deliver_wakeup() does not prevent softirq to execute +on this same CPU, to run ieee80211_tx_h_unicast_ps_buf() and try to +take this same lock ending in deadlock. Below is an example of rcu stall +that arises in such situation. + + rcu: INFO: rcu_sched self-detected stall on CPU + rcu: 2-....: (42413413 ticks this GP) idle=b154/1/0x4000000000000000 softirq=1763/1765 fqs=21206996 + rcu: (t=42586894 jiffies g=2057 q=362405 ncpus=4) + CPU: 2 PID: 719 Comm: wpa_supplicant Tainted: G W 6.4.0-02158-g1b062f552873 #742 + Hardware name: RPT (r1) (DT) + pstate: 00000005 (nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) + pc : queued_spin_lock_slowpath+0x58/0x2d0 + lr : invoke_tx_handlers_early+0x5b4/0x5c0 + sp : ffff00001ef64660 + x29: ffff00001ef64660 x28: ffff000009bc1070 x27: ffff000009bc0ad8 + x26: ffff000009bc0900 x25: ffff00001ef647a8 x24: 0000000000000000 + x23: ffff000009bc0900 x22: ffff000009bc0900 x21: ffff00000ac0e000 + x20: ffff00000a279e00 x19: ffff00001ef646e8 x18: 0000000000000000 + x17: ffff800016468000 x16: ffff00001ef608c0 x15: 0010533c93f64f80 + x14: 0010395c9faa3946 x13: 0000000000000000 x12: 00000000fa83b2da + x11: 000000012edeceea x10: ffff0000010fbe00 x9 : 0000000000895440 + x8 : 000000000010533c x7 : ffff00000ad8b740 x6 : ffff00000c350880 + x5 : 0000000000000007 x4 : 0000000000000001 x3 : 0000000000000000 + x2 : 0000000000000000 x1 : 0000000000000001 x0 : ffff00000ac0e0e8 + Call trace: + queued_spin_lock_slowpath+0x58/0x2d0 + ieee80211_tx+0x80/0x12c + ieee80211_tx_pending+0x110/0x278 + tasklet_action_common.constprop.0+0x10c/0x144 + tasklet_action+0x20/0x28 + _stext+0x11c/0x284 + ____do_softirq+0xc/0x14 + call_on_irq_stack+0x24/0x34 + do_softirq_own_stack+0x18/0x20 + do_softirq+0x74/0x7c + __local_bh_enable_ip+0xa0/0xa4 + _ieee80211_wake_txqs+0x3b0/0x4b8 + __ieee80211_wake_queue+0x12c/0x168 + ieee80211_add_pending_skbs+0xec/0x138 + ieee80211_sta_ps_deliver_wakeup+0x2a4/0x480 + ieee80211_mps_sta_status_update.part.0+0xd8/0x11c + ieee80211_mps_sta_status_update+0x18/0x24 + sta_apply_parameters+0x3bc/0x4c0 + ieee80211_change_station+0x1b8/0x2dc + nl80211_set_station+0x444/0x49c + genl_family_rcv_msg_doit.isra.0+0xa4/0xfc + genl_rcv_msg+0x1b0/0x244 + netlink_rcv_skb+0x38/0x10c + genl_rcv+0x34/0x48 + netlink_unicast+0x254/0x2bc + netlink_sendmsg+0x190/0x3b4 + ____sys_sendmsg+0x1e8/0x218 + ___sys_sendmsg+0x68/0x8c + __sys_sendmsg+0x44/0x84 + __arm64_sys_sendmsg+0x20/0x28 + do_el0_svc+0x6c/0xe8 + el0_svc+0x14/0x48 + el0t_64_sync_handler+0xb0/0xb4 + el0t_64_sync+0x14c/0x150 + +Using spin_lock_bh()/spin_unlock_bh() instead prevents softirq to raise +on the same CPU that is holding the lock. + +Fixes: 1d147bfa6429 ("mac80211: fix AP powersave TX vs. wakeup race") +Signed-off-by: Remi Pommarel +Link: https://msgid.link/8e36fe07d0fbc146f89196cd47a53c8a0afe84aa.1716910344.git.repk@triplefau.lt +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/sta_info.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c +index 44bd03c6b8473..f7637176d719d 100644 +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -1343,7 +1343,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) + skb_queue_head_init(&pending); + + /* sync with ieee80211_tx_h_unicast_ps_buf */ +- spin_lock(&sta->ps_lock); ++ spin_lock_bh(&sta->ps_lock); + /* Send all buffered frames to the station */ + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { + int count = skb_queue_len(&pending), tmp; +@@ -1372,7 +1372,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) + */ + clear_sta_flag(sta, WLAN_STA_PSPOLL); + clear_sta_flag(sta, WLAN_STA_UAPSD); +- spin_unlock(&sta->ps_lock); ++ spin_unlock_bh(&sta->ps_lock); + + atomic_dec(&ps->num_sta_ps); + +-- +2.43.0 + diff --git a/queue-5.10/wifi-mac80211-mesh-fix-leak-of-mesh_preq_queue-objec.patch b/queue-5.10/wifi-mac80211-mesh-fix-leak-of-mesh_preq_queue-objec.patch new file mode 100644 index 00000000000..239f6058cb8 --- /dev/null +++ b/queue-5.10/wifi-mac80211-mesh-fix-leak-of-mesh_preq_queue-objec.patch @@ -0,0 +1,100 @@ +From 4f8ca04ba4058413dd9012086f53f2dbe014a88c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 May 2024 16:26:05 +0200 +Subject: wifi: mac80211: mesh: Fix leak of mesh_preq_queue objects + +From: Nicolas Escande + +[ Upstream commit b7d7f11a291830fdf69d3301075dd0fb347ced84 ] + +The hwmp code use objects of type mesh_preq_queue, added to a list in +ieee80211_if_mesh, to keep track of mpath we need to resolve. If the mpath +gets deleted, ex mesh interface is removed, the entries in that list will +never get cleaned. Fix this by flushing all corresponding items of the +preq_queue in mesh_path_flush_pending(). + +This should take care of KASAN reports like this: + +unreferenced object 0xffff00000668d800 (size 128): + comm "kworker/u8:4", pid 67, jiffies 4295419552 (age 1836.444s) + hex dump (first 32 bytes): + 00 1f 05 09 00 00 ff ff 00 d5 68 06 00 00 ff ff ..........h..... + 8e 97 ea eb 3e b8 01 00 00 00 00 00 00 00 00 00 ....>........... + backtrace: + [<000000007302a0b6>] __kmem_cache_alloc_node+0x1e0/0x35c + [<00000000049bd418>] kmalloc_trace+0x34/0x80 + [<0000000000d792bb>] mesh_queue_preq+0x44/0x2a8 + [<00000000c99c3696>] mesh_nexthop_resolve+0x198/0x19c + [<00000000926bf598>] ieee80211_xmit+0x1d0/0x1f4 + [<00000000fc8c2284>] __ieee80211_subif_start_xmit+0x30c/0x764 + [<000000005926ee38>] ieee80211_subif_start_xmit+0x9c/0x7a4 + [<000000004c86e916>] dev_hard_start_xmit+0x174/0x440 + [<0000000023495647>] __dev_queue_xmit+0xe24/0x111c + [<00000000cfe9ca78>] batadv_send_skb_packet+0x180/0x1e4 + [<000000007bacc5d5>] batadv_v_elp_periodic_work+0x2f4/0x508 + [<00000000adc3cd94>] process_one_work+0x4b8/0xa1c + [<00000000b36425d1>] worker_thread+0x9c/0x634 + [<0000000005852dd5>] kthread+0x1bc/0x1c4 + [<000000005fccd770>] ret_from_fork+0x10/0x20 +unreferenced object 0xffff000009051f00 (size 128): + comm "kworker/u8:4", pid 67, jiffies 4295419553 (age 1836.440s) + hex dump (first 32 bytes): + 90 d6 92 0d 00 00 ff ff 00 d8 68 06 00 00 ff ff ..........h..... + 36 27 92 e4 02 e0 01 00 00 58 79 06 00 00 ff ff 6'.......Xy..... + backtrace: + [<000000007302a0b6>] __kmem_cache_alloc_node+0x1e0/0x35c + [<00000000049bd418>] kmalloc_trace+0x34/0x80 + [<0000000000d792bb>] mesh_queue_preq+0x44/0x2a8 + [<00000000c99c3696>] mesh_nexthop_resolve+0x198/0x19c + [<00000000926bf598>] ieee80211_xmit+0x1d0/0x1f4 + [<00000000fc8c2284>] __ieee80211_subif_start_xmit+0x30c/0x764 + [<000000005926ee38>] ieee80211_subif_start_xmit+0x9c/0x7a4 + [<000000004c86e916>] dev_hard_start_xmit+0x174/0x440 + [<0000000023495647>] __dev_queue_xmit+0xe24/0x111c + [<00000000cfe9ca78>] batadv_send_skb_packet+0x180/0x1e4 + [<000000007bacc5d5>] batadv_v_elp_periodic_work+0x2f4/0x508 + [<00000000adc3cd94>] process_one_work+0x4b8/0xa1c + [<00000000b36425d1>] worker_thread+0x9c/0x634 + [<0000000005852dd5>] kthread+0x1bc/0x1c4 + [<000000005fccd770>] ret_from_fork+0x10/0x20 + +Fixes: 050ac52cbe1f ("mac80211: code for on-demand Hybrid Wireless Mesh Protocol") +Signed-off-by: Nicolas Escande +Link: https://msgid.link/20240528142605.1060566-1-nico.escande@gmail.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/mesh_pathtbl.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c +index d936ef0c17a37..72ecce377d174 100644 +--- a/net/mac80211/mesh_pathtbl.c ++++ b/net/mac80211/mesh_pathtbl.c +@@ -723,10 +723,23 @@ void mesh_path_discard_frame(struct ieee80211_sub_if_data *sdata, + */ + void mesh_path_flush_pending(struct mesh_path *mpath) + { ++ struct ieee80211_sub_if_data *sdata = mpath->sdata; ++ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; ++ struct mesh_preq_queue *preq, *tmp; + struct sk_buff *skb; + + while ((skb = skb_dequeue(&mpath->frame_queue)) != NULL) + mesh_path_discard_frame(mpath->sdata, skb); ++ ++ spin_lock_bh(&ifmsh->mesh_preq_queue_lock); ++ list_for_each_entry_safe(preq, tmp, &ifmsh->preq_queue.list, list) { ++ if (ether_addr_equal(mpath->dst, preq->dst)) { ++ list_del(&preq->list); ++ kfree(preq); ++ --ifmsh->preq_queue_len; ++ } ++ } ++ spin_unlock_bh(&ifmsh->mesh_preq_queue_lock); + } + + /** +-- +2.43.0 +