]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 6.11
authorSasha Levin <sashal@kernel.org>
Wed, 2 Oct 2024 05:17:32 +0000 (01:17 -0400)
committerSasha Levin <sashal@kernel.org>
Wed, 2 Oct 2024 05:17:32 +0000 (01:17 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
14 files changed:
queue-6.11/lsm-infrastructure-management-of-the-sock-security.patch [new file with mode: 0644]
queue-6.11/serial-qcom-geni-fix-arg-types-for-qcom_geni_serial_.patch [new file with mode: 0644]
queue-6.11/serial-qcom-geni-fix-console-corruption.patch [new file with mode: 0644]
queue-6.11/serial-qcom-geni-introduce-qcom_geni_serial_poll_bit.patch [new file with mode: 0644]
queue-6.11/series
queue-6.11/soc-qcom-geni-se-add-gp_length-irq_en_set-irq_en_cle.patch [new file with mode: 0644]
queue-6.11/soc-versatile-realview-fix-memory-leak-during-device.patch [new file with mode: 0644]
queue-6.11/soc-versatile-realview-fix-soc_dev-leak-during-devic.patch [new file with mode: 0644]
queue-6.11/thermal-core-store-trip-sysfs-attributes-in-thermal_.patch [new file with mode: 0644]
queue-6.11/thermal-sysfs-add-sanity-checks-for-trip-temperature.patch [new file with mode: 0644]
queue-6.11/thermal-sysfs-get-to-trips-via-attribute-pointers.patch [new file with mode: 0644]
queue-6.11/thermal-sysfs-refine-the-handling-of-trip-hysteresis.patch [new file with mode: 0644]
queue-6.11/usb-typec-ucsi-call-cancel-from-single-location.patch [new file with mode: 0644]
queue-6.11/usb-typec-ucsi-fix-busy-loop-on-asus-vivobooks.patch [new file with mode: 0644]

diff --git a/queue-6.11/lsm-infrastructure-management-of-the-sock-security.patch b/queue-6.11/lsm-infrastructure-management-of-the-sock-security.patch
new file mode 100644 (file)
index 0000000..12efc1c
--- /dev/null
@@ -0,0 +1,933 @@
+From 4847334176513a6ac636ad17bc6e3c48e2f568ec Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 10 Jul 2024 14:32:25 -0700
+Subject: lsm: infrastructure management of the sock security
+
+From: Casey Schaufler <casey@schaufler-ca.com>
+
+[ Upstream commit 2aff9d20d50ac45dd13a013ef5231f4fb8912356 ]
+
+Move management of the sock->sk_security blob out
+of the individual security modules and into the security
+infrastructure. Instead of allocating the blobs from within
+the modules the modules tell the infrastructure how much
+space is required, and the space is allocated there.
+
+Acked-by: Paul Moore <paul@paul-moore.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+Reviewed-by: John Johansen <john.johansen@canonical.com>
+Acked-by: Stephen Smalley <stephen.smalley.work@gmail.com>
+Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
+[PM: subject tweak]
+Signed-off-by: Paul Moore <paul@paul-moore.com>
+Stable-dep-of: 63dff3e48871 ("lsm: add the inode_free_security_rcu() LSM implementation hook")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/lsm_hooks.h         |  1 +
+ security/apparmor/include/net.h   |  3 +-
+ security/apparmor/lsm.c           | 17 +------
+ security/apparmor/net.c           |  2 +-
+ security/security.c               | 36 +++++++++++++-
+ security/selinux/hooks.c          | 80 ++++++++++++++-----------------
+ security/selinux/include/objsec.h |  5 ++
+ security/selinux/netlabel.c       | 23 ++++-----
+ security/smack/smack.h            |  5 ++
+ security/smack/smack_lsm.c        | 70 +++++++++++++--------------
+ security/smack/smack_netfilter.c  |  4 +-
+ 11 files changed, 133 insertions(+), 113 deletions(-)
+
+diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
+index a2ade0ffe9e7d..efd4a0655159c 100644
+--- a/include/linux/lsm_hooks.h
++++ b/include/linux/lsm_hooks.h
+@@ -73,6 +73,7 @@ struct lsm_blob_sizes {
+       int     lbs_cred;
+       int     lbs_file;
+       int     lbs_inode;
++      int     lbs_sock;
+       int     lbs_superblock;
+       int     lbs_ipc;
+       int     lbs_msg_msg;
+diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
+index 67bf888c3bd6b..c42ed8a73f1ce 100644
+--- a/security/apparmor/include/net.h
++++ b/security/apparmor/include/net.h
+@@ -51,10 +51,9 @@ struct aa_sk_ctx {
+       struct aa_label *peer;
+ };
+-#define SK_CTX(X) ((X)->sk_security)
+ static inline struct aa_sk_ctx *aa_sock(const struct sock *sk)
+ {
+-      return sk->sk_security;
++      return sk->sk_security + apparmor_blob_sizes.lbs_sock;
+ }
+ #define DEFINE_AUDIT_NET(NAME, OP, SK, F, T, P)                                 \
+diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
+index 808060f9effb7..f5d05297d59ee 100644
+--- a/security/apparmor/lsm.c
++++ b/security/apparmor/lsm.c
+@@ -1058,27 +1058,12 @@ static int apparmor_userns_create(const struct cred *cred)
+       return error;
+ }
+-static int apparmor_sk_alloc_security(struct sock *sk, int family, gfp_t flags)
+-{
+-      struct aa_sk_ctx *ctx;
+-
+-      ctx = kzalloc(sizeof(*ctx), flags);
+-      if (!ctx)
+-              return -ENOMEM;
+-
+-      sk->sk_security = ctx;
+-
+-      return 0;
+-}
+-
+ static void apparmor_sk_free_security(struct sock *sk)
+ {
+       struct aa_sk_ctx *ctx = aa_sock(sk);
+-      sk->sk_security = NULL;
+       aa_put_label(ctx->label);
+       aa_put_label(ctx->peer);
+-      kfree(ctx);
+ }
+ /**
+@@ -1433,6 +1418,7 @@ struct lsm_blob_sizes apparmor_blob_sizes __ro_after_init = {
+       .lbs_cred = sizeof(struct aa_label *),
+       .lbs_file = sizeof(struct aa_file_ctx),
+       .lbs_task = sizeof(struct aa_task_ctx),
++      .lbs_sock = sizeof(struct aa_sk_ctx),
+ };
+ static const struct lsm_id apparmor_lsmid = {
+@@ -1478,7 +1464,6 @@ static struct security_hook_list apparmor_hooks[] __ro_after_init = {
+       LSM_HOOK_INIT(getprocattr, apparmor_getprocattr),
+       LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),
+-      LSM_HOOK_INIT(sk_alloc_security, apparmor_sk_alloc_security),
+       LSM_HOOK_INIT(sk_free_security, apparmor_sk_free_security),
+       LSM_HOOK_INIT(sk_clone_security, apparmor_sk_clone_security),
+diff --git a/security/apparmor/net.c b/security/apparmor/net.c
+index 87e934b2b5488..77413a5191179 100644
+--- a/security/apparmor/net.c
++++ b/security/apparmor/net.c
+@@ -151,7 +151,7 @@ static int aa_label_sk_perm(const struct cred *subj_cred,
+                           const char *op, u32 request,
+                           struct sock *sk)
+ {
+-      struct aa_sk_ctx *ctx = SK_CTX(sk);
++      struct aa_sk_ctx *ctx = aa_sock(sk);
+       int error = 0;
+       AA_BUG(!label);
+diff --git a/security/security.c b/security/security.c
+index 41ab07eafc7fa..43166e341526c 100644
+--- a/security/security.c
++++ b/security/security.c
+@@ -29,6 +29,7 @@
+ #include <linux/msg.h>
+ #include <linux/overflow.h>
+ #include <net/flow.h>
++#include <net/sock.h>
+ /* How many LSMs were built into the kernel? */
+ #define LSM_COUNT (__end_lsm_info - __start_lsm_info)
+@@ -227,6 +228,7 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
+       lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
+       lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
+       lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
++      lsm_set_blob_size(&needed->lbs_sock, &blob_sizes.lbs_sock);
+       lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
+       lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
+       lsm_set_blob_size(&needed->lbs_xattr_count,
+@@ -401,6 +403,7 @@ static void __init ordered_lsm_init(void)
+       init_debug("inode blob size      = %d\n", blob_sizes.lbs_inode);
+       init_debug("ipc blob size        = %d\n", blob_sizes.lbs_ipc);
+       init_debug("msg_msg blob size    = %d\n", blob_sizes.lbs_msg_msg);
++      init_debug("sock blob size       = %d\n", blob_sizes.lbs_sock);
+       init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
+       init_debug("task blob size       = %d\n", blob_sizes.lbs_task);
+       init_debug("xattr slots          = %d\n", blob_sizes.lbs_xattr_count);
+@@ -4673,6 +4676,28 @@ int security_socket_getpeersec_dgram(struct socket *sock,
+ }
+ EXPORT_SYMBOL(security_socket_getpeersec_dgram);
++/**
++ * lsm_sock_alloc - allocate a composite sock blob
++ * @sock: the sock that needs a blob
++ * @priority: allocation mode
++ *
++ * Allocate the sock blob for all the modules
++ *
++ * Returns 0, or -ENOMEM if memory can't be allocated.
++ */
++static int lsm_sock_alloc(struct sock *sock, gfp_t priority)
++{
++      if (blob_sizes.lbs_sock == 0) {
++              sock->sk_security = NULL;
++              return 0;
++      }
++
++      sock->sk_security = kzalloc(blob_sizes.lbs_sock, priority);
++      if (sock->sk_security == NULL)
++              return -ENOMEM;
++      return 0;
++}
++
+ /**
+  * security_sk_alloc() - Allocate and initialize a sock's LSM blob
+  * @sk: sock
+@@ -4686,7 +4711,14 @@ EXPORT_SYMBOL(security_socket_getpeersec_dgram);
+  */
+ int security_sk_alloc(struct sock *sk, int family, gfp_t priority)
+ {
+-      return call_int_hook(sk_alloc_security, sk, family, priority);
++      int rc = lsm_sock_alloc(sk, priority);
++
++      if (unlikely(rc))
++              return rc;
++      rc = call_int_hook(sk_alloc_security, sk, family, priority);
++      if (unlikely(rc))
++              security_sk_free(sk);
++      return rc;
+ }
+ /**
+@@ -4698,6 +4730,8 @@ int security_sk_alloc(struct sock *sk, int family, gfp_t priority)
+ void security_sk_free(struct sock *sk)
+ {
+       call_void_hook(sk_free_security, sk);
++      kfree(sk->sk_security);
++      sk->sk_security = NULL;
+ }
+ /**
+diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
+index 400eca4ad0fb6..c11303d662d80 100644
+--- a/security/selinux/hooks.c
++++ b/security/selinux/hooks.c
+@@ -4594,7 +4594,7 @@ static int socket_sockcreate_sid(const struct task_security_struct *tsec,
+ static int sock_has_perm(struct sock *sk, u32 perms)
+ {
+-      struct sk_security_struct *sksec = sk->sk_security;
++      struct sk_security_struct *sksec = selinux_sock(sk);
+       struct common_audit_data ad;
+       struct lsm_network_audit net;
+@@ -4662,7 +4662,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
+       isec->initialized = LABEL_INITIALIZED;
+       if (sock->sk) {
+-              sksec = sock->sk->sk_security;
++              sksec = selinux_sock(sock->sk);
+               sksec->sclass = sclass;
+               sksec->sid = sid;
+               /* Allows detection of the first association on this socket */
+@@ -4678,8 +4678,8 @@ static int selinux_socket_post_create(struct socket *sock, int family,
+ static int selinux_socket_socketpair(struct socket *socka,
+                                    struct socket *sockb)
+ {
+-      struct sk_security_struct *sksec_a = socka->sk->sk_security;
+-      struct sk_security_struct *sksec_b = sockb->sk->sk_security;
++      struct sk_security_struct *sksec_a = selinux_sock(socka->sk);
++      struct sk_security_struct *sksec_b = selinux_sock(sockb->sk);
+       sksec_a->peer_sid = sksec_b->sid;
+       sksec_b->peer_sid = sksec_a->sid;
+@@ -4694,7 +4694,7 @@ static int selinux_socket_socketpair(struct socket *socka,
+ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
+ {
+       struct sock *sk = sock->sk;
+-      struct sk_security_struct *sksec = sk->sk_security;
++      struct sk_security_struct *sksec = selinux_sock(sk);
+       u16 family;
+       int err;
+@@ -4834,7 +4834,7 @@ static int selinux_socket_connect_helper(struct socket *sock,
+                                        struct sockaddr *address, int addrlen)
+ {
+       struct sock *sk = sock->sk;
+-      struct sk_security_struct *sksec = sk->sk_security;
++      struct sk_security_struct *sksec = selinux_sock(sk);
+       int err;
+       err = sock_has_perm(sk, SOCKET__CONNECT);
+@@ -5012,9 +5012,9 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
+                                             struct sock *other,
+                                             struct sock *newsk)
+ {
+-      struct sk_security_struct *sksec_sock = sock->sk_security;
+-      struct sk_security_struct *sksec_other = other->sk_security;
+-      struct sk_security_struct *sksec_new = newsk->sk_security;
++      struct sk_security_struct *sksec_sock = selinux_sock(sock);
++      struct sk_security_struct *sksec_other = selinux_sock(other);
++      struct sk_security_struct *sksec_new = selinux_sock(newsk);
+       struct common_audit_data ad;
+       struct lsm_network_audit net;
+       int err;
+@@ -5043,8 +5043,8 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
+ static int selinux_socket_unix_may_send(struct socket *sock,
+                                       struct socket *other)
+ {
+-      struct sk_security_struct *ssec = sock->sk->sk_security;
+-      struct sk_security_struct *osec = other->sk->sk_security;
++      struct sk_security_struct *ssec = selinux_sock(sock->sk);
++      struct sk_security_struct *osec = selinux_sock(other->sk);
+       struct common_audit_data ad;
+       struct lsm_network_audit net;
+@@ -5081,7 +5081,7 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
+                                      u16 family)
+ {
+       int err = 0;
+-      struct sk_security_struct *sksec = sk->sk_security;
++      struct sk_security_struct *sksec = selinux_sock(sk);
+       u32 sk_sid = sksec->sid;
+       struct common_audit_data ad;
+       struct lsm_network_audit net;
+@@ -5110,7 +5110,7 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
+ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
+ {
+       int err, peerlbl_active, secmark_active;
+-      struct sk_security_struct *sksec = sk->sk_security;
++      struct sk_security_struct *sksec = selinux_sock(sk);
+       u16 family = sk->sk_family;
+       u32 sk_sid = sksec->sid;
+       struct common_audit_data ad;
+@@ -5178,7 +5178,7 @@ static int selinux_socket_getpeersec_stream(struct socket *sock,
+       int err = 0;
+       char *scontext = NULL;
+       u32 scontext_len;
+-      struct sk_security_struct *sksec = sock->sk->sk_security;
++      struct sk_security_struct *sksec = selinux_sock(sock->sk);
+       u32 peer_sid = SECSID_NULL;
+       if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
+@@ -5238,34 +5238,27 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock,
+ static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
+ {
+-      struct sk_security_struct *sksec;
+-
+-      sksec = kzalloc(sizeof(*sksec), priority);
+-      if (!sksec)
+-              return -ENOMEM;
++      struct sk_security_struct *sksec = selinux_sock(sk);
+       sksec->peer_sid = SECINITSID_UNLABELED;
+       sksec->sid = SECINITSID_UNLABELED;
+       sksec->sclass = SECCLASS_SOCKET;
+       selinux_netlbl_sk_security_reset(sksec);
+-      sk->sk_security = sksec;
+       return 0;
+ }
+ static void selinux_sk_free_security(struct sock *sk)
+ {
+-      struct sk_security_struct *sksec = sk->sk_security;
++      struct sk_security_struct *sksec = selinux_sock(sk);
+-      sk->sk_security = NULL;
+       selinux_netlbl_sk_security_free(sksec);
+-      kfree(sksec);
+ }
+ static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
+ {
+-      struct sk_security_struct *sksec = sk->sk_security;
+-      struct sk_security_struct *newsksec = newsk->sk_security;
++      struct sk_security_struct *sksec = selinux_sock(sk);
++      struct sk_security_struct *newsksec = selinux_sock(newsk);
+       newsksec->sid = sksec->sid;
+       newsksec->peer_sid = sksec->peer_sid;
+@@ -5279,7 +5272,7 @@ static void selinux_sk_getsecid(const struct sock *sk, u32 *secid)
+       if (!sk)
+               *secid = SECINITSID_ANY_SOCKET;
+       else {
+-              const struct sk_security_struct *sksec = sk->sk_security;
++              const struct sk_security_struct *sksec = selinux_sock(sk);
+               *secid = sksec->sid;
+       }
+@@ -5289,7 +5282,7 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent)
+ {
+       struct inode_security_struct *isec =
+               inode_security_novalidate(SOCK_INODE(parent));
+-      struct sk_security_struct *sksec = sk->sk_security;
++      struct sk_security_struct *sksec = selinux_sock(sk);
+       if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
+           sk->sk_family == PF_UNIX)
+@@ -5306,7 +5299,7 @@ static int selinux_sctp_process_new_assoc(struct sctp_association *asoc,
+ {
+       struct sock *sk = asoc->base.sk;
+       u16 family = sk->sk_family;
+-      struct sk_security_struct *sksec = sk->sk_security;
++      struct sk_security_struct *sksec = selinux_sock(sk);
+       struct common_audit_data ad;
+       struct lsm_network_audit net;
+       int err;
+@@ -5361,7 +5354,7 @@ static int selinux_sctp_process_new_assoc(struct sctp_association *asoc,
+ static int selinux_sctp_assoc_request(struct sctp_association *asoc,
+                                     struct sk_buff *skb)
+ {
+-      struct sk_security_struct *sksec = asoc->base.sk->sk_security;
++      struct sk_security_struct *sksec = selinux_sock(asoc->base.sk);
+       u32 conn_sid;
+       int err;
+@@ -5394,7 +5387,7 @@ static int selinux_sctp_assoc_request(struct sctp_association *asoc,
+ static int selinux_sctp_assoc_established(struct sctp_association *asoc,
+                                         struct sk_buff *skb)
+ {
+-      struct sk_security_struct *sksec = asoc->base.sk->sk_security;
++      struct sk_security_struct *sksec = selinux_sock(asoc->base.sk);
+       if (!selinux_policycap_extsockclass())
+               return 0;
+@@ -5493,8 +5486,8 @@ static int selinux_sctp_bind_connect(struct sock *sk, int optname,
+ static void selinux_sctp_sk_clone(struct sctp_association *asoc, struct sock *sk,
+                                 struct sock *newsk)
+ {
+-      struct sk_security_struct *sksec = sk->sk_security;
+-      struct sk_security_struct *newsksec = newsk->sk_security;
++      struct sk_security_struct *sksec = selinux_sock(sk);
++      struct sk_security_struct *newsksec = selinux_sock(newsk);
+       /* If policy does not support SECCLASS_SCTP_SOCKET then call
+        * the non-sctp clone version.
+@@ -5510,8 +5503,8 @@ static void selinux_sctp_sk_clone(struct sctp_association *asoc, struct sock *sk
+ static int selinux_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
+ {
+-      struct sk_security_struct *ssksec = ssk->sk_security;
+-      struct sk_security_struct *sksec = sk->sk_security;
++      struct sk_security_struct *ssksec = selinux_sock(ssk);
++      struct sk_security_struct *sksec = selinux_sock(sk);
+       ssksec->sclass = sksec->sclass;
+       ssksec->sid = sksec->sid;
+@@ -5526,7 +5519,7 @@ static int selinux_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
+ static int selinux_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
+                                    struct request_sock *req)
+ {
+-      struct sk_security_struct *sksec = sk->sk_security;
++      struct sk_security_struct *sksec = selinux_sock(sk);
+       int err;
+       u16 family = req->rsk_ops->family;
+       u32 connsid;
+@@ -5547,7 +5540,7 @@ static int selinux_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
+ static void selinux_inet_csk_clone(struct sock *newsk,
+                                  const struct request_sock *req)
+ {
+-      struct sk_security_struct *newsksec = newsk->sk_security;
++      struct sk_security_struct *newsksec = selinux_sock(newsk);
+       newsksec->sid = req->secid;
+       newsksec->peer_sid = req->peer_secid;
+@@ -5564,7 +5557,7 @@ static void selinux_inet_csk_clone(struct sock *newsk,
+ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
+ {
+       u16 family = sk->sk_family;
+-      struct sk_security_struct *sksec = sk->sk_security;
++      struct sk_security_struct *sksec = selinux_sock(sk);
+       /* handle mapped IPv4 packets arriving via IPv6 sockets */
+       if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
+@@ -5639,7 +5632,7 @@ static int selinux_tun_dev_attach_queue(void *security)
+ static int selinux_tun_dev_attach(struct sock *sk, void *security)
+ {
+       struct tun_security_struct *tunsec = security;
+-      struct sk_security_struct *sksec = sk->sk_security;
++      struct sk_security_struct *sksec = selinux_sock(sk);
+       /* we don't currently perform any NetLabel based labeling here and it
+        * isn't clear that we would want to do so anyway; while we could apply
+@@ -5762,7 +5755,7 @@ static unsigned int selinux_ip_output(void *priv, struct sk_buff *skb,
+                       return NF_ACCEPT;
+               /* standard practice, label using the parent socket */
+-              sksec = sk->sk_security;
++              sksec = selinux_sock(sk);
+               sid = sksec->sid;
+       } else
+               sid = SECINITSID_KERNEL;
+@@ -5785,7 +5778,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
+       sk = skb_to_full_sk(skb);
+       if (sk == NULL)
+               return NF_ACCEPT;
+-      sksec = sk->sk_security;
++      sksec = selinux_sock(sk);
+       ad_net_init_from_iif(&ad, &net, state->out->ifindex, state->pf);
+       if (selinux_parse_skb(skb, &ad, NULL, 0, &proto))
+@@ -5874,7 +5867,7 @@ static unsigned int selinux_ip_postroute(void *priv,
+               u32 skb_sid;
+               struct sk_security_struct *sksec;
+-              sksec = sk->sk_security;
++              sksec = selinux_sock(sk);
+               if (selinux_skb_peerlbl_sid(skb, family, &skb_sid))
+                       return NF_DROP;
+               /* At this point, if the returned skb peerlbl is SECSID_NULL
+@@ -5903,7 +5896,7 @@ static unsigned int selinux_ip_postroute(void *priv,
+       } else {
+               /* Locally generated packet, fetch the security label from the
+                * associated socket. */
+-              struct sk_security_struct *sksec = sk->sk_security;
++              struct sk_security_struct *sksec = selinux_sock(sk);
+               peer_sid = sksec->sid;
+               secmark_perm = PACKET__SEND;
+       }
+@@ -5946,7 +5939,7 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
+       unsigned int data_len = skb->len;
+       unsigned char *data = skb->data;
+       struct nlmsghdr *nlh;
+-      struct sk_security_struct *sksec = sk->sk_security;
++      struct sk_security_struct *sksec = selinux_sock(sk);
+       u16 sclass = sksec->sclass;
+       u32 perm;
+@@ -7004,6 +6997,7 @@ struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {
+       .lbs_inode = sizeof(struct inode_security_struct),
+       .lbs_ipc = sizeof(struct ipc_security_struct),
+       .lbs_msg_msg = sizeof(struct msg_security_struct),
++      .lbs_sock = sizeof(struct sk_security_struct),
+       .lbs_superblock = sizeof(struct superblock_security_struct),
+       .lbs_xattr_count = SELINUX_INODE_INIT_XATTRS,
+ };
+diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
+index dea1d6f3ed2d3..b074099acbaf7 100644
+--- a/security/selinux/include/objsec.h
++++ b/security/selinux/include/objsec.h
+@@ -195,4 +195,9 @@ selinux_superblock(const struct super_block *superblock)
+       return superblock->s_security + selinux_blob_sizes.lbs_superblock;
+ }
++static inline struct sk_security_struct *selinux_sock(const struct sock *sock)
++{
++      return sock->sk_security + selinux_blob_sizes.lbs_sock;
++}
++
+ #endif /* _SELINUX_OBJSEC_H_ */
+diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
+index 55885634e8804..fbe5f8c29f813 100644
+--- a/security/selinux/netlabel.c
++++ b/security/selinux/netlabel.c
+@@ -17,6 +17,7 @@
+ #include <linux/gfp.h>
+ #include <linux/ip.h>
+ #include <linux/ipv6.h>
++#include <linux/lsm_hooks.h>
+ #include <net/sock.h>
+ #include <net/netlabel.h>
+ #include <net/ip.h>
+@@ -68,7 +69,7 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
+ static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
+ {
+       int rc;
+-      struct sk_security_struct *sksec = sk->sk_security;
++      struct sk_security_struct *sksec = selinux_sock(sk);
+       struct netlbl_lsm_secattr *secattr;
+       if (sksec->nlbl_secattr != NULL)
+@@ -100,7 +101,7 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_getattr(
+                                                       const struct sock *sk,
+                                                       u32 sid)
+ {
+-      struct sk_security_struct *sksec = sk->sk_security;
++      struct sk_security_struct *sksec = selinux_sock(sk);
+       struct netlbl_lsm_secattr *secattr = sksec->nlbl_secattr;
+       if (secattr == NULL)
+@@ -240,7 +241,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
+        * being labeled by it's parent socket, if it is just exit */
+       sk = skb_to_full_sk(skb);
+       if (sk != NULL) {
+-              struct sk_security_struct *sksec = sk->sk_security;
++              struct sk_security_struct *sksec = selinux_sock(sk);
+               if (sksec->nlbl_state != NLBL_REQSKB)
+                       return 0;
+@@ -277,7 +278,7 @@ int selinux_netlbl_sctp_assoc_request(struct sctp_association *asoc,
+ {
+       int rc;
+       struct netlbl_lsm_secattr secattr;
+-      struct sk_security_struct *sksec = asoc->base.sk->sk_security;
++      struct sk_security_struct *sksec = selinux_sock(asoc->base.sk);
+       struct sockaddr_in addr4;
+       struct sockaddr_in6 addr6;
+@@ -356,7 +357,7 @@ int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
+  */
+ void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
+ {
+-      struct sk_security_struct *sksec = sk->sk_security;
++      struct sk_security_struct *sksec = selinux_sock(sk);
+       if (family == PF_INET)
+               sksec->nlbl_state = NLBL_LABELED;
+@@ -374,8 +375,8 @@ void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
+  */
+ void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk)
+ {
+-      struct sk_security_struct *sksec = sk->sk_security;
+-      struct sk_security_struct *newsksec = newsk->sk_security;
++      struct sk_security_struct *sksec = selinux_sock(sk);
++      struct sk_security_struct *newsksec = selinux_sock(newsk);
+       newsksec->nlbl_state = sksec->nlbl_state;
+ }
+@@ -393,7 +394,7 @@ void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk)
+ int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
+ {
+       int rc;
+-      struct sk_security_struct *sksec = sk->sk_security;
++      struct sk_security_struct *sksec = selinux_sock(sk);
+       struct netlbl_lsm_secattr *secattr;
+       if (family != PF_INET && family != PF_INET6)
+@@ -510,7 +511,7 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
+ {
+       int rc = 0;
+       struct sock *sk = sock->sk;
+-      struct sk_security_struct *sksec = sk->sk_security;
++      struct sk_security_struct *sksec = selinux_sock(sk);
+       struct netlbl_lsm_secattr secattr;
+       if (selinux_netlbl_option(level, optname) &&
+@@ -548,7 +549,7 @@ static int selinux_netlbl_socket_connect_helper(struct sock *sk,
+                                               struct sockaddr *addr)
+ {
+       int rc;
+-      struct sk_security_struct *sksec = sk->sk_security;
++      struct sk_security_struct *sksec = selinux_sock(sk);
+       struct netlbl_lsm_secattr *secattr;
+       /* connected sockets are allowed to disconnect when the address family
+@@ -587,7 +588,7 @@ static int selinux_netlbl_socket_connect_helper(struct sock *sk,
+ int selinux_netlbl_socket_connect_locked(struct sock *sk,
+                                        struct sockaddr *addr)
+ {
+-      struct sk_security_struct *sksec = sk->sk_security;
++      struct sk_security_struct *sksec = selinux_sock(sk);
+       if (sksec->nlbl_state != NLBL_REQSKB &&
+           sksec->nlbl_state != NLBL_CONNLABELED)
+diff --git a/security/smack/smack.h b/security/smack/smack.h
+index 041688e5a77a3..297f21446f456 100644
+--- a/security/smack/smack.h
++++ b/security/smack/smack.h
+@@ -355,6 +355,11 @@ static inline struct superblock_smack *smack_superblock(
+       return superblock->s_security + smack_blob_sizes.lbs_superblock;
+ }
++static inline struct socket_smack *smack_sock(const struct sock *sock)
++{
++      return sock->sk_security + smack_blob_sizes.lbs_sock;
++}
++
+ /*
+  * Is the directory transmuting?
+  */
+diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
+index 002a1b9ed83a5..6ec9a40f3ec59 100644
+--- a/security/smack/smack_lsm.c
++++ b/security/smack/smack_lsm.c
+@@ -1606,7 +1606,7 @@ static int smack_inode_getsecurity(struct mnt_idmap *idmap,
+               if (sock == NULL || sock->sk == NULL)
+                       return -EOPNOTSUPP;
+-              ssp = sock->sk->sk_security;
++              ssp = smack_sock(sock->sk);
+               if (strcmp(name, XATTR_SMACK_IPIN) == 0)
+                       isp = ssp->smk_in;
+@@ -1994,7 +1994,7 @@ static int smack_file_receive(struct file *file)
+       if (inode->i_sb->s_magic == SOCKFS_MAGIC) {
+               sock = SOCKET_I(inode);
+-              ssp = sock->sk->sk_security;
++              ssp = smack_sock(sock->sk);
+               tsp = smack_cred(current_cred());
+               /*
+                * If the receiving process can't write to the
+@@ -2409,11 +2409,7 @@ static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
+ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
+ {
+       struct smack_known *skp = smk_of_current();
+-      struct socket_smack *ssp;
+-
+-      ssp = kzalloc(sizeof(struct socket_smack), gfp_flags);
+-      if (ssp == NULL)
+-              return -ENOMEM;
++      struct socket_smack *ssp = smack_sock(sk);
+       /*
+        * Sockets created by kernel threads receive web label.
+@@ -2427,11 +2423,10 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
+       }
+       ssp->smk_packet = NULL;
+-      sk->sk_security = ssp;
+-
+       return 0;
+ }
++#ifdef SMACK_IPV6_PORT_LABELING
+ /**
+  * smack_sk_free_security - Free a socket blob
+  * @sk: the socket
+@@ -2440,7 +2435,6 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
+  */
+ static void smack_sk_free_security(struct sock *sk)
+ {
+-#ifdef SMACK_IPV6_PORT_LABELING
+       struct smk_port_label *spp;
+       if (sk->sk_family == PF_INET6) {
+@@ -2453,9 +2447,8 @@ static void smack_sk_free_security(struct sock *sk)
+               }
+               rcu_read_unlock();
+       }
+-#endif
+-      kfree(sk->sk_security);
+ }
++#endif
+ /**
+  * smack_sk_clone_security - Copy security context
+@@ -2466,8 +2459,8 @@ static void smack_sk_free_security(struct sock *sk)
+  */
+ static void smack_sk_clone_security(const struct sock *sk, struct sock *newsk)
+ {
+-      struct socket_smack *ssp_old = sk->sk_security;
+-      struct socket_smack *ssp_new = newsk->sk_security;
++      struct socket_smack *ssp_old = smack_sock(sk);
++      struct socket_smack *ssp_new = smack_sock(newsk);
+       *ssp_new = *ssp_old;
+ }
+@@ -2583,7 +2576,7 @@ static struct smack_known *smack_ipv6host_label(struct sockaddr_in6 *sip)
+  */
+ static int smack_netlbl_add(struct sock *sk)
+ {
+-      struct socket_smack *ssp = sk->sk_security;
++      struct socket_smack *ssp = smack_sock(sk);
+       struct smack_known *skp = ssp->smk_out;
+       int rc;
+@@ -2616,7 +2609,7 @@ static int smack_netlbl_add(struct sock *sk)
+  */
+ static void smack_netlbl_delete(struct sock *sk)
+ {
+-      struct socket_smack *ssp = sk->sk_security;
++      struct socket_smack *ssp = smack_sock(sk);
+       /*
+        * Take the label off the socket if one is set.
+@@ -2648,7 +2641,7 @@ static int smk_ipv4_check(struct sock *sk, struct sockaddr_in *sap)
+       struct smack_known *skp;
+       int rc = 0;
+       struct smack_known *hkp;
+-      struct socket_smack *ssp = sk->sk_security;
++      struct socket_smack *ssp = smack_sock(sk);
+       struct smk_audit_info ad;
+       rcu_read_lock();
+@@ -2721,7 +2714,7 @@ static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address)
+ {
+       struct sock *sk = sock->sk;
+       struct sockaddr_in6 *addr6;
+-      struct socket_smack *ssp = sock->sk->sk_security;
++      struct socket_smack *ssp = smack_sock(sock->sk);
+       struct smk_port_label *spp;
+       unsigned short port = 0;
+@@ -2809,7 +2802,7 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address,
+                               int act)
+ {
+       struct smk_port_label *spp;
+-      struct socket_smack *ssp = sk->sk_security;
++      struct socket_smack *ssp = smack_sock(sk);
+       struct smack_known *skp = NULL;
+       unsigned short port;
+       struct smack_known *object;
+@@ -2912,7 +2905,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
+       if (sock == NULL || sock->sk == NULL)
+               return -EOPNOTSUPP;
+-      ssp = sock->sk->sk_security;
++      ssp = smack_sock(sock->sk);
+       if (strcmp(name, XATTR_SMACK_IPIN) == 0)
+               ssp->smk_in = skp;
+@@ -2960,7 +2953,7 @@ static int smack_socket_post_create(struct socket *sock, int family,
+        * Sockets created by kernel threads receive web label.
+        */
+       if (unlikely(current->flags & PF_KTHREAD)) {
+-              ssp = sock->sk->sk_security;
++              ssp = smack_sock(sock->sk);
+               ssp->smk_in = &smack_known_web;
+               ssp->smk_out = &smack_known_web;
+       }
+@@ -2985,8 +2978,8 @@ static int smack_socket_post_create(struct socket *sock, int family,
+ static int smack_socket_socketpair(struct socket *socka,
+                                  struct socket *sockb)
+ {
+-      struct socket_smack *asp = socka->sk->sk_security;
+-      struct socket_smack *bsp = sockb->sk->sk_security;
++      struct socket_smack *asp = smack_sock(socka->sk);
++      struct socket_smack *bsp = smack_sock(sockb->sk);
+       asp->smk_packet = bsp->smk_out;
+       bsp->smk_packet = asp->smk_out;
+@@ -3049,7 +3042,7 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,
+               if (__is_defined(SMACK_IPV6_SECMARK_LABELING))
+                       rsp = smack_ipv6host_label(sip);
+               if (rsp != NULL) {
+-                      struct socket_smack *ssp = sock->sk->sk_security;
++                      struct socket_smack *ssp = smack_sock(sock->sk);
+                       rc = smk_ipv6_check(ssp->smk_out, rsp, sip,
+                                           SMK_CONNECTING);
+@@ -3844,9 +3837,9 @@ static int smack_unix_stream_connect(struct sock *sock,
+ {
+       struct smack_known *skp;
+       struct smack_known *okp;
+-      struct socket_smack *ssp = sock->sk_security;
+-      struct socket_smack *osp = other->sk_security;
+-      struct socket_smack *nsp = newsk->sk_security;
++      struct socket_smack *ssp = smack_sock(sock);
++      struct socket_smack *osp = smack_sock(other);
++      struct socket_smack *nsp = smack_sock(newsk);
+       struct smk_audit_info ad;
+       int rc = 0;
+ #ifdef CONFIG_AUDIT
+@@ -3898,8 +3891,8 @@ static int smack_unix_stream_connect(struct sock *sock,
+  */
+ static int smack_unix_may_send(struct socket *sock, struct socket *other)
+ {
+-      struct socket_smack *ssp = sock->sk->sk_security;
+-      struct socket_smack *osp = other->sk->sk_security;
++      struct socket_smack *ssp = smack_sock(sock->sk);
++      struct socket_smack *osp = smack_sock(other->sk);
+       struct smk_audit_info ad;
+       int rc;
+@@ -3936,7 +3929,7 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
+       struct sockaddr_in6 *sap = (struct sockaddr_in6 *) msg->msg_name;
+ #endif
+ #ifdef SMACK_IPV6_SECMARK_LABELING
+-      struct socket_smack *ssp = sock->sk->sk_security;
++      struct socket_smack *ssp = smack_sock(sock->sk);
+       struct smack_known *rsp;
+ #endif
+       int rc = 0;
+@@ -4148,7 +4141,7 @@ static struct smack_known *smack_from_netlbl(const struct sock *sk, u16 family,
+       netlbl_secattr_init(&secattr);
+       if (sk)
+-              ssp = sk->sk_security;
++              ssp = smack_sock(sk);
+       if (netlbl_skbuff_getattr(skb, family, &secattr) == 0) {
+               skp = smack_from_secattr(&secattr, ssp);
+@@ -4170,7 +4163,7 @@ static struct smack_known *smack_from_netlbl(const struct sock *sk, u16 family,
+  */
+ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
+ {
+-      struct socket_smack *ssp = sk->sk_security;
++      struct socket_smack *ssp = smack_sock(sk);
+       struct smack_known *skp = NULL;
+       int rc = 0;
+       struct smk_audit_info ad;
+@@ -4274,7 +4267,7 @@ static int smack_socket_getpeersec_stream(struct socket *sock,
+       u32 slen = 1;
+       int rc = 0;
+-      ssp = sock->sk->sk_security;
++      ssp = smack_sock(sock->sk);
+       if (ssp->smk_packet != NULL) {
+               rcp = ssp->smk_packet->smk_known;
+               slen = strlen(rcp) + 1;
+@@ -4324,7 +4317,7 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
+       switch (family) {
+       case PF_UNIX:
+-              ssp = sock->sk->sk_security;
++              ssp = smack_sock(sock->sk);
+               s = ssp->smk_out->smk_secid;
+               break;
+       case PF_INET:
+@@ -4373,7 +4366,7 @@ static void smack_sock_graft(struct sock *sk, struct socket *parent)
+           (sk->sk_family != PF_INET && sk->sk_family != PF_INET6))
+               return;
+-      ssp = sk->sk_security;
++      ssp = smack_sock(sk);
+       ssp->smk_in = skp;
+       ssp->smk_out = skp;
+       /* cssp->smk_packet is already set in smack_inet_csk_clone() */
+@@ -4393,7 +4386,7 @@ static int smack_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
+ {
+       u16 family = sk->sk_family;
+       struct smack_known *skp;
+-      struct socket_smack *ssp = sk->sk_security;
++      struct socket_smack *ssp = smack_sock(sk);
+       struct sockaddr_in addr;
+       struct iphdr *hdr;
+       struct smack_known *hskp;
+@@ -4479,7 +4472,7 @@ static int smack_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
+ static void smack_inet_csk_clone(struct sock *sk,
+                                const struct request_sock *req)
+ {
+-      struct socket_smack *ssp = sk->sk_security;
++      struct socket_smack *ssp = smack_sock(sk);
+       struct smack_known *skp;
+       if (req->peer_secid != 0) {
+@@ -5049,6 +5042,7 @@ struct lsm_blob_sizes smack_blob_sizes __ro_after_init = {
+       .lbs_inode = sizeof(struct inode_smack),
+       .lbs_ipc = sizeof(struct smack_known *),
+       .lbs_msg_msg = sizeof(struct smack_known *),
++      .lbs_sock = sizeof(struct socket_smack),
+       .lbs_superblock = sizeof(struct superblock_smack),
+       .lbs_xattr_count = SMACK_INODE_INIT_XATTRS,
+ };
+@@ -5173,7 +5167,9 @@ static struct security_hook_list smack_hooks[] __ro_after_init = {
+       LSM_HOOK_INIT(socket_getpeersec_stream, smack_socket_getpeersec_stream),
+       LSM_HOOK_INIT(socket_getpeersec_dgram, smack_socket_getpeersec_dgram),
+       LSM_HOOK_INIT(sk_alloc_security, smack_sk_alloc_security),
++#ifdef SMACK_IPV6_PORT_LABELING
+       LSM_HOOK_INIT(sk_free_security, smack_sk_free_security),
++#endif
+       LSM_HOOK_INIT(sk_clone_security, smack_sk_clone_security),
+       LSM_HOOK_INIT(sock_graft, smack_sock_graft),
+       LSM_HOOK_INIT(inet_conn_request, smack_inet_conn_request),
+diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c
+index b945c1d3a7431..bad71b7e648da 100644
+--- a/security/smack/smack_netfilter.c
++++ b/security/smack/smack_netfilter.c
+@@ -26,8 +26,8 @@ static unsigned int smack_ip_output(void *priv,
+       struct socket_smack *ssp;
+       struct smack_known *skp;
+-      if (sk && sk->sk_security) {
+-              ssp = sk->sk_security;
++      if (sk) {
++              ssp = smack_sock(sk);
+               skp = ssp->smk_out;
+               skb->secmark = skp->smk_secid;
+       }
+-- 
+2.43.0
+
diff --git a/queue-6.11/serial-qcom-geni-fix-arg-types-for-qcom_geni_serial_.patch b/queue-6.11/serial-qcom-geni-fix-arg-types-for-qcom_geni_serial_.patch
new file mode 100644 (file)
index 0000000..0a7b4e1
--- /dev/null
@@ -0,0 +1,48 @@
+From f138bd8383484d807836ba2e13d7a8960e792729 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 6 Sep 2024 15:13:32 +0200
+Subject: serial: qcom-geni: fix arg types for qcom_geni_serial_poll_bit()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Douglas Anderson <dianders@chromium.org>
+
+[ Upstream commit c2eaf5e01275ae13f1ec5b1434f6c49cfff57430 ]
+
+The "offset" passed in should be unsigned since it's always a positive
+offset from our memory mapped IO.
+
+The "field" should be u32 since we're anding it with a 32-bit value
+read from the device.
+
+Suggested-by: Stephen Boyd <swboyd@chromium.org>
+Signed-off-by: Douglas Anderson <dianders@chromium.org>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
+Link: https://lore.kernel.org/r/20240610152420.v4.4.I24a0de52dd7336908df180fa6b698e001f3aff82@changeid
+Tested-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Link: https://lore.kernel.org/r/20240906131336.23625-5-johan+linaro@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: cc4a0e5754a1 ("serial: qcom-geni: fix console corruption")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/qcom_geni_serial.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
+index b88435c0ea507..54052c68555d7 100644
+--- a/drivers/tty/serial/qcom_geni_serial.c
++++ b/drivers/tty/serial/qcom_geni_serial.c
+@@ -266,7 +266,7 @@ static bool qcom_geni_serial_secondary_active(struct uart_port *uport)
+ }
+ static bool qcom_geni_serial_poll_bit(struct uart_port *uport,
+-                              int offset, int field, bool set)
++                                    unsigned int offset, u32 field, bool set)
+ {
+       u32 reg;
+       struct qcom_geni_serial_port *port;
+-- 
+2.43.0
+
diff --git a/queue-6.11/serial-qcom-geni-fix-console-corruption.patch b/queue-6.11/serial-qcom-geni-fix-console-corruption.patch
new file mode 100644 (file)
index 0000000..fc017e1
--- /dev/null
@@ -0,0 +1,169 @@
+From 71284b18956d1f1c65074aa90c3fac15227bf583 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 6 Sep 2024 15:13:34 +0200
+Subject: serial: qcom-geni: fix console corruption
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Johan Hovold <johan+linaro@kernel.org>
+
+[ Upstream commit cc4a0e5754a16bbc1e215c091349a7c83a2c5e14 ]
+
+The Qualcomm serial console implementation is broken and can lose
+characters when the serial port is also used for tty output.
+
+Specifically, the console code only waits for the current tx command to
+complete when all data has already been written to the fifo. When there
+are on-going longer transfers this often means that console output is
+lost when the console code inadvertently "hijacks" the current tx
+command instead of starting a new one.
+
+This can, for example, be observed during boot when console output that
+should have been interspersed with init output is truncated:
+
+       [    9.462317] qcom-snps-eusb2-hsphy fde000.phy: Registered Qcom-eUSB2 phy
+       [  OK  ] Found device KBG50ZNS256G KIOXIA Wi[    9.471743ndows.
+       [    9.539915] xhci-hcd xhci-hcd.0.auto: xHCI Host Controller
+
+Add a new state variable to track how much data has been written to the
+fifo and use it to determine when the fifo and shift register are both
+empty. This is needed since there is currently no other known way to
+determine when the shift register is empty.
+
+This in turn allows the console code to interrupt long transfers without
+losing data.
+
+Note that the oops-in-progress case is similarly broken as it does not
+cancel any active command and also waits for the wrong status flag when
+attempting to drain the fifo (TX_FIFO_NOT_EMPTY_EN is only set when
+cancelling a command leaves data in the fifo).
+
+Fixes: c4f528795d1a ("tty: serial: msm_geni_serial: Add serial driver support for GENI based QUP")
+Fixes: a1fee899e5be ("tty: serial: qcom_geni_serial: Fix softlock")
+Fixes: 9e957a155005 ("serial: qcom-geni: Don't cancel/abort if we can't get the port lock")
+Cc: stable@vger.kernel.org     # 4.17
+Reviewed-by: Douglas Anderson <dianders@chromium.org>
+Tested-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Link: https://lore.kernel.org/r/20240906131336.23625-7-johan+linaro@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/qcom_geni_serial.c | 45 +++++++++++++--------------
+ 1 file changed, 22 insertions(+), 23 deletions(-)
+
+diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
+index 7bbd70c306201..f8f6e9466b400 100644
+--- a/drivers/tty/serial/qcom_geni_serial.c
++++ b/drivers/tty/serial/qcom_geni_serial.c
+@@ -131,6 +131,7 @@ struct qcom_geni_serial_port {
+       bool brk;
+       unsigned int tx_remaining;
++      unsigned int tx_queued;
+       int wakeup_irq;
+       bool rx_tx_swap;
+       bool cts_rts_swap;
+@@ -144,6 +145,8 @@ static const struct uart_ops qcom_geni_uart_pops;
+ static struct uart_driver qcom_geni_console_driver;
+ static struct uart_driver qcom_geni_uart_driver;
++static void qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport);
++
+ static inline struct qcom_geni_serial_port *to_dev_port(struct uart_port *uport)
+ {
+       return container_of(uport, struct qcom_geni_serial_port, uport);
+@@ -393,6 +396,14 @@ static void qcom_geni_serial_poll_put_char(struct uart_port *uport,
+ #endif
+ #ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE
++static void qcom_geni_serial_drain_fifo(struct uart_port *uport)
++{
++      struct qcom_geni_serial_port *port = to_dev_port(uport);
++
++      qcom_geni_serial_poll_bitfield(uport, SE_GENI_M_GP_LENGTH, GP_LENGTH,
++                      port->tx_queued);
++}
++
+ static void qcom_geni_serial_wr_char(struct uart_port *uport, unsigned char ch)
+ {
+       struct qcom_geni_private_data *private_data = uport->private_data;
+@@ -468,7 +479,6 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s,
+       struct qcom_geni_serial_port *port;
+       bool locked = true;
+       unsigned long flags;
+-      u32 geni_status;
+       WARN_ON(co->index < 0 || co->index >= GENI_UART_CONS_PORTS);
+@@ -482,34 +492,20 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s,
+       else
+               uart_port_lock_irqsave(uport, &flags);
+-      geni_status = readl(uport->membase + SE_GENI_STATUS);
++      if (qcom_geni_serial_main_active(uport)) {
++              /* Wait for completion or drain FIFO */
++              if (!locked || port->tx_remaining == 0)
++                      qcom_geni_serial_poll_tx_done(uport);
++              else
++                      qcom_geni_serial_drain_fifo(uport);
+-      if (!locked) {
+-              /*
+-               * We can only get here if an oops is in progress then we were
+-               * unable to get the lock. This means we can't safely access
+-               * our state variables like tx_remaining. About the best we
+-               * can do is wait for the FIFO to be empty before we start our
+-               * transfer, so we'll do that.
+-               */
+-              qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
+-                                        M_TX_FIFO_NOT_EMPTY_EN, false);
+-      } else if ((geni_status & M_GENI_CMD_ACTIVE) && !port->tx_remaining) {
+-              /*
+-               * It seems we can't interrupt existing transfers if all data
+-               * has been sent, in which case we need to look for done first.
+-               */
+-              qcom_geni_serial_poll_tx_done(uport);
++              qcom_geni_serial_cancel_tx_cmd(uport);
+       }
+       __qcom_geni_serial_console_write(uport, s, count);
+-
+-      if (locked) {
+-              if (port->tx_remaining)
+-                      qcom_geni_serial_setup_tx(uport, port->tx_remaining);
++      if (locked)
+               uart_port_unlock_irqrestore(uport, flags);
+-      }
+ }
+ static void handle_rx_console(struct uart_port *uport, u32 bytes, bool drop)
+@@ -690,6 +686,7 @@ static void qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport)
+       writel(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
+       port->tx_remaining = 0;
++      port->tx_queued = 0;
+ }
+ static void qcom_geni_serial_handle_rx_fifo(struct uart_port *uport, bool drop)
+@@ -916,6 +913,7 @@ static void qcom_geni_serial_handle_tx_fifo(struct uart_port *uport,
+       if (!port->tx_remaining) {
+               qcom_geni_serial_setup_tx(uport, pending);
+               port->tx_remaining = pending;
++              port->tx_queued = 0;
+               irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
+               if (!(irq_en & M_TX_FIFO_WATERMARK_EN))
+@@ -924,6 +922,7 @@ static void qcom_geni_serial_handle_tx_fifo(struct uart_port *uport,
+       }
+       qcom_geni_serial_send_chunk_fifo(uport, chunk);
++      port->tx_queued += chunk;
+       /*
+        * The tx fifo watermark is level triggered and latched. Though we had
+-- 
+2.43.0
+
diff --git a/queue-6.11/serial-qcom-geni-introduce-qcom_geni_serial_poll_bit.patch b/queue-6.11/serial-qcom-geni-introduce-qcom_geni_serial_poll_bit.patch
new file mode 100644 (file)
index 0000000..a8edeb9
--- /dev/null
@@ -0,0 +1,70 @@
+From 0827839650381c5b2b36673f556944af8bf27c70 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 6 Sep 2024 15:13:33 +0200
+Subject: serial: qcom-geni: introduce qcom_geni_serial_poll_bitfield()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Douglas Anderson <dianders@chromium.org>
+
+[ Upstream commit b26d1ad1221273c88c2c4f5b4080338b8ca23859 ]
+
+With a small modification the qcom_geni_serial_poll_bit() function
+could be used to poll more than just a single bit. Let's generalize
+it. We'll make the qcom_geni_serial_poll_bit() into just a wrapper of
+the general function.
+
+Signed-off-by: Douglas Anderson <dianders@chromium.org>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
+Link: https://lore.kernel.org/r/20240610152420.v4.5.Ic6411eab8d9d37acc451705f583fb535cd6dadb2@changeid
+Tested-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Link: https://lore.kernel.org/r/20240906131336.23625-6-johan+linaro@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: cc4a0e5754a1 ("serial: qcom-geni: fix console corruption")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/qcom_geni_serial.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
+index 54052c68555d7..7bbd70c306201 100644
+--- a/drivers/tty/serial/qcom_geni_serial.c
++++ b/drivers/tty/serial/qcom_geni_serial.c
+@@ -265,8 +265,8 @@ static bool qcom_geni_serial_secondary_active(struct uart_port *uport)
+       return readl(uport->membase + SE_GENI_STATUS) & S_GENI_CMD_ACTIVE;
+ }
+-static bool qcom_geni_serial_poll_bit(struct uart_port *uport,
+-                                    unsigned int offset, u32 field, bool set)
++static bool qcom_geni_serial_poll_bitfield(struct uart_port *uport,
++                                         unsigned int offset, u32 field, u32 val)
+ {
+       u32 reg;
+       struct qcom_geni_serial_port *port;
+@@ -286,7 +286,7 @@ static bool qcom_geni_serial_poll_bit(struct uart_port *uport,
+       timeout_us = DIV_ROUND_UP(timeout_us, 10) * 10;
+       while (timeout_us) {
+               reg = readl(uport->membase + offset);
+-              if ((bool)(reg & field) == set)
++              if ((reg & field) == val)
+                       return true;
+               udelay(10);
+               timeout_us -= 10;
+@@ -294,6 +294,12 @@ static bool qcom_geni_serial_poll_bit(struct uart_port *uport,
+       return false;
+ }
++static bool qcom_geni_serial_poll_bit(struct uart_port *uport,
++                                    unsigned int offset, u32 field, bool set)
++{
++      return qcom_geni_serial_poll_bitfield(uport, offset, field, set ? field : 0);
++}
++
+ static void qcom_geni_serial_setup_tx(struct uart_port *uport, u32 xmit_size)
+ {
+       u32 m_cmd;
+-- 
+2.43.0
+
index 74c00fd1f0ed323100b91d58ccc79bae95bb92ae..0126d44fa0b3385fcdc4970b0a01997137f7188e 100644 (file)
@@ -671,3 +671,16 @@ dt-bindings-spi-nxp-fspi-add-imx8ulp-support.patch
 arm-dts-imx6ul-geam-fix-fsl-pins-property-in-tscgrp-pinctrl.patch
 arm-dts-imx6ull-seeed-npi-fix-fsl-pins-property-in-tscgrp-pinctrl.patch
 tools-nolibc-include-arch.h-from-string.h.patch
+soc-versatile-realview-fix-memory-leak-during-device.patch
+soc-versatile-realview-fix-soc_dev-leak-during-devic.patch
+usb-typec-ucsi-call-cancel-from-single-location.patch
+usb-typec-ucsi-fix-busy-loop-on-asus-vivobooks.patch
+soc-qcom-geni-se-add-gp_length-irq_en_set-irq_en_cle.patch
+serial-qcom-geni-fix-arg-types-for-qcom_geni_serial_.patch
+serial-qcom-geni-introduce-qcom_geni_serial_poll_bit.patch
+serial-qcom-geni-fix-console-corruption.patch
+thermal-core-store-trip-sysfs-attributes-in-thermal_.patch
+thermal-sysfs-get-to-trips-via-attribute-pointers.patch
+thermal-sysfs-refine-the-handling-of-trip-hysteresis.patch
+thermal-sysfs-add-sanity-checks-for-trip-temperature.patch
+lsm-infrastructure-management-of-the-sock-security.patch
diff --git a/queue-6.11/soc-qcom-geni-se-add-gp_length-irq_en_set-irq_en_cle.patch b/queue-6.11/soc-qcom-geni-se-add-gp_length-irq_en_set-irq_en_cle.patch
new file mode 100644 (file)
index 0000000..ee157ee
--- /dev/null
@@ -0,0 +1,75 @@
+From fbe43be15e67d88a19e55a23e5c7a4db23951953 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 6 Sep 2024 15:13:31 +0200
+Subject: soc: qcom: geni-se: add GP_LENGTH/IRQ_EN_SET/IRQ_EN_CLEAR registers
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Douglas Anderson <dianders@chromium.org>
+
+[ Upstream commit b03ffc76b83c1a7d058454efbcf1bf0e345ef1c2 ]
+
+For UART devices the M_GP_LENGTH is the TX word count. For other
+devices this is the transaction word count.
+
+For UART devices the S_GP_LENGTH is the RX word count.
+
+The IRQ_EN set/clear registers allow you to set or clear bits in the
+IRQ_EN register without needing a read-modify-write.
+
+Acked-by: Bjorn Andersson <andersson@kernel.org>
+Signed-off-by: Douglas Anderson <dianders@chromium.org>
+Link: https://lore.kernel.org/r/20240610152420.v4.1.Ife7ced506aef1be3158712aa3ff34a006b973559@changeid
+Tested-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Link: https://lore.kernel.org/r/20240906131336.23625-4-johan+linaro@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: cc4a0e5754a1 ("serial: qcom-geni: fix console corruption")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/soc/qcom/geni-se.h | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/include/linux/soc/qcom/geni-se.h b/include/linux/soc/qcom/geni-se.h
+index 0f038a1a03309..c3bca9c0bf2cf 100644
+--- a/include/linux/soc/qcom/geni-se.h
++++ b/include/linux/soc/qcom/geni-se.h
+@@ -88,11 +88,15 @@ struct geni_se {
+ #define SE_GENI_M_IRQ_STATUS          0x610
+ #define SE_GENI_M_IRQ_EN              0x614
+ #define SE_GENI_M_IRQ_CLEAR           0x618
++#define SE_GENI_M_IRQ_EN_SET          0x61c
++#define SE_GENI_M_IRQ_EN_CLEAR                0x620
+ #define SE_GENI_S_CMD0                        0x630
+ #define SE_GENI_S_CMD_CTRL_REG                0x634
+ #define SE_GENI_S_IRQ_STATUS          0x640
+ #define SE_GENI_S_IRQ_EN              0x644
+ #define SE_GENI_S_IRQ_CLEAR           0x648
++#define SE_GENI_S_IRQ_EN_SET          0x64c
++#define SE_GENI_S_IRQ_EN_CLEAR                0x650
+ #define SE_GENI_TX_FIFOn              0x700
+ #define SE_GENI_RX_FIFOn              0x780
+ #define SE_GENI_TX_FIFO_STATUS                0x800
+@@ -101,6 +105,8 @@ struct geni_se {
+ #define SE_GENI_RX_WATERMARK_REG      0x810
+ #define SE_GENI_RX_RFR_WATERMARK_REG  0x814
+ #define SE_GENI_IOS                   0x908
++#define SE_GENI_M_GP_LENGTH           0x910
++#define SE_GENI_S_GP_LENGTH           0x914
+ #define SE_DMA_TX_IRQ_STAT            0xc40
+ #define SE_DMA_TX_IRQ_CLR             0xc44
+ #define SE_DMA_TX_FSM_RST             0xc58
+@@ -234,6 +240,9 @@ struct geni_se {
+ #define IO2_DATA_IN                   BIT(1)
+ #define RX_DATA_IN                    BIT(0)
++/* SE_GENI_M_GP_LENGTH and SE_GENI_S_GP_LENGTH fields */
++#define GP_LENGTH                     GENMASK(31, 0)
++
+ /* SE_DMA_TX_IRQ_STAT Register fields */
+ #define TX_DMA_DONE                   BIT(0)
+ #define TX_EOT                                BIT(1)
+-- 
+2.43.0
+
diff --git a/queue-6.11/soc-versatile-realview-fix-memory-leak-during-device.patch b/queue-6.11/soc-versatile-realview-fix-memory-leak-during-device.patch
new file mode 100644 (file)
index 0000000..503716a
--- /dev/null
@@ -0,0 +1,50 @@
+From 07d5b7e267b5c57be2a75f62b3ac1a85a709dc8e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 25 Aug 2024 20:05:23 +0200
+Subject: soc: versatile: realview: fix memory leak during device remove
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit 1c4f26a41f9d052f334f6ae629e01f598ed93508 ]
+
+If device is unbound, the memory allocated for soc_dev_attr should be
+freed to prevent leaks.
+
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Link: https://lore.kernel.org/20240825-soc-dev-fixes-v1-2-ff4b35abed83@linaro.org
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Stable-dep-of: c774f2564c00 ("soc: versatile: realview: fix soc_dev leak during device remove")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soc/versatile/soc-realview.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/soc/versatile/soc-realview.c b/drivers/soc/versatile/soc-realview.c
+index c6876d232d8fd..d304ee69287af 100644
+--- a/drivers/soc/versatile/soc-realview.c
++++ b/drivers/soc/versatile/soc-realview.c
+@@ -93,7 +93,7 @@ static int realview_soc_probe(struct platform_device *pdev)
+       if (IS_ERR(syscon_regmap))
+               return PTR_ERR(syscon_regmap);
+-      soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
++      soc_dev_attr = devm_kzalloc(&pdev->dev, sizeof(*soc_dev_attr), GFP_KERNEL);
+       if (!soc_dev_attr)
+               return -ENOMEM;
+@@ -106,10 +106,9 @@ static int realview_soc_probe(struct platform_device *pdev)
+       soc_dev_attr->family = "Versatile";
+       soc_dev_attr->custom_attr_group = realview_groups[0];
+       soc_dev = soc_device_register(soc_dev_attr);
+-      if (IS_ERR(soc_dev)) {
+-              kfree(soc_dev_attr);
++      if (IS_ERR(soc_dev))
+               return -ENODEV;
+-      }
++
+       ret = regmap_read(syscon_regmap, REALVIEW_SYS_ID_OFFSET,
+                         &realview_coreid);
+       if (ret)
+-- 
+2.43.0
+
diff --git a/queue-6.11/soc-versatile-realview-fix-soc_dev-leak-during-devic.patch b/queue-6.11/soc-versatile-realview-fix-soc_dev-leak-during-devic.patch
new file mode 100644 (file)
index 0000000..6cf2dbd
--- /dev/null
@@ -0,0 +1,63 @@
+From 386cb0f19b79d3c4f9b95effb883e409b28c8902 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 25 Aug 2024 20:05:24 +0200
+Subject: soc: versatile: realview: fix soc_dev leak during device remove
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit c774f2564c0086c23f5269fd4691f233756bf075 ]
+
+If device is unbound, the soc_dev should be unregistered to prevent
+memory leak.
+
+Fixes: a2974c9c1f83 ("soc: add driver for the ARM RealView")
+Cc: stable@vger.kernel.org
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Link: https://lore.kernel.org/20240825-soc-dev-fixes-v1-3-ff4b35abed83@linaro.org
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soc/versatile/soc-realview.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/drivers/soc/versatile/soc-realview.c b/drivers/soc/versatile/soc-realview.c
+index d304ee69287af..cf91abe07d38d 100644
+--- a/drivers/soc/versatile/soc-realview.c
++++ b/drivers/soc/versatile/soc-realview.c
+@@ -4,6 +4,7 @@
+  *
+  * Author: Linus Walleij <linus.walleij@linaro.org>
+  */
++#include <linux/device.h>
+ #include <linux/init.h>
+ #include <linux/io.h>
+ #include <linux/slab.h>
+@@ -81,6 +82,13 @@ static struct attribute *realview_attrs[] = {
+ ATTRIBUTE_GROUPS(realview);
++static void realview_soc_socdev_release(void *data)
++{
++      struct soc_device *soc_dev = data;
++
++      soc_device_unregister(soc_dev);
++}
++
+ static int realview_soc_probe(struct platform_device *pdev)
+ {
+       struct regmap *syscon_regmap;
+@@ -109,6 +117,11 @@ static int realview_soc_probe(struct platform_device *pdev)
+       if (IS_ERR(soc_dev))
+               return -ENODEV;
++      ret = devm_add_action_or_reset(&pdev->dev, realview_soc_socdev_release,
++                                     soc_dev);
++      if (ret)
++              return ret;
++
+       ret = regmap_read(syscon_regmap, REALVIEW_SYS_ID_OFFSET,
+                         &realview_coreid);
+       if (ret)
+-- 
+2.43.0
+
diff --git a/queue-6.11/thermal-core-store-trip-sysfs-attributes-in-thermal_.patch b/queue-6.11/thermal-core-store-trip-sysfs-attributes-in-thermal_.patch
new file mode 100644 (file)
index 0000000..d86726c
--- /dev/null
@@ -0,0 +1,224 @@
+From 20a223c4112b4b837451a103f6214b7f828e1536 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 29 Jul 2024 18:25:03 +0200
+Subject: thermal: core: Store trip sysfs attributes in thermal_trip_desc
+
+From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+[ Upstream commit 66b263306a86c0f2d3cdb44e3722db6cff3a32b3 ]
+
+Instead of allocating memory for trip point sysfs attributes separately,
+store them in struct thermal_trip_desc for each trip individually which
+allows a few extra memory allocations to be avoided.
+
+No intentional functional impact.
+
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Link: https://patch.msgid.link/46571375.fMDQidcC6G@rjwysocki.net
+Stable-dep-of: 874b6476fa88 ("thermal: sysfs: Add sanity checks for trip temperature and hysteresis")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/thermal/thermal_core.h  |  23 +++----
+ drivers/thermal/thermal_sysfs.c | 105 +++++++++++---------------------
+ 2 files changed, 46 insertions(+), 82 deletions(-)
+
+diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
+index 4cf2b7230d04b..5be8bef41b926 100644
+--- a/drivers/thermal/thermal_core.h
++++ b/drivers/thermal/thermal_core.h
+@@ -15,8 +15,20 @@
+ #include "thermal_netlink.h"
+ #include "thermal_debugfs.h"
++struct thermal_attr {
++      struct device_attribute attr;
++      char name[THERMAL_NAME_LENGTH];
++};
++
++struct thermal_trip_attrs {
++      struct thermal_attr type;
++      struct thermal_attr temp;
++      struct thermal_attr hyst;
++};
++
+ struct thermal_trip_desc {
+       struct thermal_trip trip;
++      struct thermal_trip_attrs trip_attrs;
+       struct list_head notify_list_node;
+       int notify_temp;
+       int threshold;
+@@ -56,9 +68,6 @@ struct thermal_governor {
+  * @device:   &struct device for this thermal zone
+  * @removal:  removal completion
+  * @resume:   resume completion
+- * @trip_temp_attrs:  attributes for trip points for sysfs: trip temperature
+- * @trip_type_attrs:  attributes for trip points for sysfs: trip type
+- * @trip_hyst_attrs:  attributes for trip points for sysfs: trip hysteresis
+  * @mode:             current mode of this thermal zone
+  * @devdata:  private pointer for device private data
+  * @num_trips:        number of trip points the thermal zone supports
+@@ -102,9 +111,6 @@ struct thermal_zone_device {
+       struct completion removal;
+       struct completion resume;
+       struct attribute_group trips_attribute_group;
+-      struct thermal_attr *trip_temp_attrs;
+-      struct thermal_attr *trip_type_attrs;
+-      struct thermal_attr *trip_hyst_attrs;
+       enum thermal_device_mode mode;
+       void *devdata;
+       int num_trips;
+@@ -188,11 +194,6 @@ int for_each_thermal_governor(int (*cb)(struct thermal_governor *, void *),
+ struct thermal_zone_device *thermal_zone_get_by_id(int id);
+-struct thermal_attr {
+-      struct device_attribute attr;
+-      char name[THERMAL_NAME_LENGTH];
+-};
+-
+ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)
+ {
+       return cdev->ops->get_requested_power && cdev->ops->state2power &&
+diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c
+index 72b302bf914e3..f12d5d47da9bd 100644
+--- a/drivers/thermal/thermal_sysfs.c
++++ b/drivers/thermal/thermal_sysfs.c
+@@ -382,87 +382,55 @@ static const struct attribute_group *thermal_zone_attribute_groups[] = {
+  */
+ static int create_trip_attrs(struct thermal_zone_device *tz)
+ {
+-      const struct thermal_trip_desc *td;
++      struct thermal_trip_desc *td;
+       struct attribute **attrs;
+-
+-      /* This function works only for zones with at least one trip */
+-      if (tz->num_trips <= 0)
+-              return -EINVAL;
+-
+-      tz->trip_type_attrs = kcalloc(tz->num_trips, sizeof(*tz->trip_type_attrs),
+-                                    GFP_KERNEL);
+-      if (!tz->trip_type_attrs)
+-              return -ENOMEM;
+-
+-      tz->trip_temp_attrs = kcalloc(tz->num_trips, sizeof(*tz->trip_temp_attrs),
+-                                    GFP_KERNEL);
+-      if (!tz->trip_temp_attrs) {
+-              kfree(tz->trip_type_attrs);
+-              return -ENOMEM;
+-      }
+-
+-      tz->trip_hyst_attrs = kcalloc(tz->num_trips,
+-                                    sizeof(*tz->trip_hyst_attrs),
+-                                    GFP_KERNEL);
+-      if (!tz->trip_hyst_attrs) {
+-              kfree(tz->trip_type_attrs);
+-              kfree(tz->trip_temp_attrs);
+-              return -ENOMEM;
+-      }
++      int i;
+       attrs = kcalloc(tz->num_trips * 3 + 1, sizeof(*attrs), GFP_KERNEL);
+-      if (!attrs) {
+-              kfree(tz->trip_type_attrs);
+-              kfree(tz->trip_temp_attrs);
+-              kfree(tz->trip_hyst_attrs);
++      if (!attrs)
+               return -ENOMEM;
+-      }
++      i = 0;
+       for_each_trip_desc(tz, td) {
+-              int indx = thermal_zone_trip_id(tz, &td->trip);
++              struct thermal_trip_attrs *trip_attrs = &td->trip_attrs;
+               /* create trip type attribute */
+-              snprintf(tz->trip_type_attrs[indx].name, THERMAL_NAME_LENGTH,
+-                       "trip_point_%d_type", indx);
++              snprintf(trip_attrs->type.name, THERMAL_NAME_LENGTH,
++                       "trip_point_%d_type", i);
+-              sysfs_attr_init(&tz->trip_type_attrs[indx].attr.attr);
+-              tz->trip_type_attrs[indx].attr.attr.name =
+-                                              tz->trip_type_attrs[indx].name;
+-              tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
+-              tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
+-              attrs[indx] = &tz->trip_type_attrs[indx].attr.attr;
++              sysfs_attr_init(&trip_attrs->type.attr.attr);
++              trip_attrs->type.attr.attr.name = trip_attrs->type.name;
++              trip_attrs->type.attr.attr.mode = S_IRUGO;
++              trip_attrs->type.attr.show = trip_point_type_show;
++              attrs[i] = &trip_attrs->type.attr.attr;
+               /* create trip temp attribute */
+-              snprintf(tz->trip_temp_attrs[indx].name, THERMAL_NAME_LENGTH,
+-                       "trip_point_%d_temp", indx);
+-
+-              sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
+-              tz->trip_temp_attrs[indx].attr.attr.name =
+-                                              tz->trip_temp_attrs[indx].name;
+-              tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
+-              tz->trip_temp_attrs[indx].attr.show = trip_point_temp_show;
++              snprintf(trip_attrs->temp.name, THERMAL_NAME_LENGTH,
++                       "trip_point_%d_temp", i);
++
++              sysfs_attr_init(&trip_attrs->temp.attr.attr);
++              trip_attrs->temp.attr.attr.name = trip_attrs->temp.name;
++              trip_attrs->temp.attr.attr.mode = S_IRUGO;
++              trip_attrs->temp.attr.show = trip_point_temp_show;
+               if (td->trip.flags & THERMAL_TRIP_FLAG_RW_TEMP) {
+-                      tz->trip_temp_attrs[indx].attr.attr.mode |= S_IWUSR;
+-                      tz->trip_temp_attrs[indx].attr.store =
+-                                                      trip_point_temp_store;
++                      trip_attrs->temp.attr.attr.mode |= S_IWUSR;
++                      trip_attrs->temp.attr.store = trip_point_temp_store;
+               }
+-              attrs[indx + tz->num_trips] = &tz->trip_temp_attrs[indx].attr.attr;
++              attrs[i + tz->num_trips] = &trip_attrs->temp.attr.attr;
+-              snprintf(tz->trip_hyst_attrs[indx].name, THERMAL_NAME_LENGTH,
+-                       "trip_point_%d_hyst", indx);
++              snprintf(trip_attrs->hyst.name, THERMAL_NAME_LENGTH,
++                       "trip_point_%d_hyst", i);
+-              sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr);
+-              tz->trip_hyst_attrs[indx].attr.attr.name =
+-                                      tz->trip_hyst_attrs[indx].name;
+-              tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
+-              tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
++              sysfs_attr_init(&trip_attrs->hyst.attr.attr);
++              trip_attrs->hyst.attr.attr.name = trip_attrs->hyst.name;
++              trip_attrs->hyst.attr.attr.mode = S_IRUGO;
++              trip_attrs->hyst.attr.show = trip_point_hyst_show;
+               if (td->trip.flags & THERMAL_TRIP_FLAG_RW_HYST) {
+-                      tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
+-                      tz->trip_hyst_attrs[indx].attr.store =
+-                                      trip_point_hyst_store;
++                      trip_attrs->hyst.attr.attr.mode |= S_IWUSR;
++                      trip_attrs->hyst.attr.store = trip_point_hyst_store;
+               }
+-              attrs[indx + tz->num_trips * 2] =
+-                                      &tz->trip_hyst_attrs[indx].attr.attr;
++              attrs[i + 2 * tz->num_trips] = &trip_attrs->hyst.attr.attr;
++              i++;
+       }
+       attrs[tz->num_trips * 3] = NULL;
+@@ -479,13 +447,8 @@ static int create_trip_attrs(struct thermal_zone_device *tz)
+  */
+ static void destroy_trip_attrs(struct thermal_zone_device *tz)
+ {
+-      if (!tz)
+-              return;
+-
+-      kfree(tz->trip_type_attrs);
+-      kfree(tz->trip_temp_attrs);
+-      kfree(tz->trip_hyst_attrs);
+-      kfree(tz->trips_attribute_group.attrs);
++      if (tz)
++              kfree(tz->trips_attribute_group.attrs);
+ }
+ int thermal_zone_create_device_groups(struct thermal_zone_device *tz)
+-- 
+2.43.0
+
diff --git a/queue-6.11/thermal-sysfs-add-sanity-checks-for-trip-temperature.patch b/queue-6.11/thermal-sysfs-add-sanity-checks-for-trip-temperature.patch
new file mode 100644 (file)
index 0000000..617b291
--- /dev/null
@@ -0,0 +1,111 @@
+From 872ec8f8250f0f8f01157681c72b813f987f4009 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 26 Aug 2024 18:21:59 +0200
+Subject: thermal: sysfs: Add sanity checks for trip temperature and hysteresis
+
+From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+[ Upstream commit 874b6476fa888e79e41daf7653384c8d70927b90 ]
+
+Add sanity checks for new trip temperature and hysteresis values to
+trip_point_temp_store() and trip_point_hyst_store() to prevent trip
+point threshold from falling below THERMAL_TEMP_INVALID.
+
+However, still allow user space to pass THERMAL_TEMP_INVALID as the
+new trip temperature value to invalidate the trip if necessary.
+
+Also allow the hysteresis to be updated when the temperature is invalid
+to allow user space to avoid having to adjust hysteresis after a valid
+temperature has been set, but in that case just change the value and do
+nothing else.
+
+Fixes: be0a3600aa1e ("thermal: sysfs: Rework the handling of trip point updates")
+Cc: 6.8+ <stable@vger.kernel.org> # 6.8+
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Reviewed-by: Lukasz Luba <lukasz.luba@arm.com>
+Link: https://patch.msgid.link/12528772.O9o76ZdvQC@rjwysocki.net
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/thermal/thermal_sysfs.c | 50 +++++++++++++++++++++++++--------
+ 1 file changed, 38 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c
+index 2709455486776..d628dd67be5cc 100644
+--- a/drivers/thermal/thermal_sysfs.c
++++ b/drivers/thermal/thermal_sysfs.c
+@@ -111,18 +111,26 @@ trip_point_temp_store(struct device *dev, struct device_attribute *attr,
+       mutex_lock(&tz->lock);
+-      if (temp != trip->temperature) {
+-              if (tz->ops.set_trip_temp) {
+-                      ret = tz->ops.set_trip_temp(tz, trip, temp);
+-                      if (ret)
+-                              goto unlock;
+-              }
++      if (temp == trip->temperature)
++              goto unlock;
+-              thermal_zone_set_trip_temp(tz, trip, temp);
++      /* Arrange the condition to avoid integer overflows. */
++      if (temp != THERMAL_TEMP_INVALID &&
++          temp <= trip->hysteresis + THERMAL_TEMP_INVALID) {
++              ret = -EINVAL;
++              goto unlock;
++      }
+-              __thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED);
++      if (tz->ops.set_trip_temp) {
++              ret = tz->ops.set_trip_temp(tz, trip, temp);
++              if (ret)
++                      goto unlock;
+       }
++      thermal_zone_set_trip_temp(tz, trip, temp);
++
++      __thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED);
++
+ unlock:
+       mutex_unlock(&tz->lock);
+@@ -152,15 +160,33 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
+       mutex_lock(&tz->lock);
+-      if (hyst != trip->hysteresis) {
+-              thermal_zone_set_trip_hyst(tz, trip, hyst);
++      if (hyst == trip->hysteresis)
++              goto unlock;
++
++      /*
++       * Allow the hysteresis to be updated when the temperature is invalid
++       * to allow user space to avoid having to adjust hysteresis after a
++       * valid temperature has been set, but in that case just change the
++       * value and do nothing else.
++       */
++      if (trip->temperature == THERMAL_TEMP_INVALID) {
++              WRITE_ONCE(trip->hysteresis, hyst);
++              goto unlock;
++      }
+-              __thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED);
++      if (trip->temperature - hyst <= THERMAL_TEMP_INVALID) {
++              ret = -EINVAL;
++              goto unlock;
+       }
++      thermal_zone_set_trip_hyst(tz, trip, hyst);
++
++      __thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED);
++
++unlock:
+       mutex_unlock(&tz->lock);
+-      return count;
++      return ret ? ret : count;
+ }
+ static ssize_t
+-- 
+2.43.0
+
diff --git a/queue-6.11/thermal-sysfs-get-to-trips-via-attribute-pointers.patch b/queue-6.11/thermal-sysfs-get-to-trips-via-attribute-pointers.patch
new file mode 100644 (file)
index 0000000..e6ff954
--- /dev/null
@@ -0,0 +1,152 @@
+From 4d6569d10c6f8d6d634fd8a2b2dc2af1ce9191dc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 29 Jul 2024 18:25:59 +0200
+Subject: thermal: sysfs: Get to trips via attribute pointers
+
+From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+[ Upstream commit afd84fb10ced3caf53769ba734ea237bde0f69e3 ]
+
+The  _store() and _show() functions for sysfs attributes corresponding
+to trip point parameters (type, temperature and hysteresis) read the
+trip ID from the attribute name and then use the trip ID as the index
+in the given thermal zone's trips table to get to the trip object they
+want.
+
+Instead of doing this, make them use the attribute pointer they get
+as the second argument to get to the trip object embedded in the same
+struct thermal_trip_desc as the struct device_attribute pointed to by
+it, which is much more straightforward and less overhead.
+
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Link: https://patch.msgid.link/114841552.nniJfEyVGO@rjwysocki.net
+Stable-dep-of: 874b6476fa88 ("thermal: sysfs: Add sanity checks for trip temperature and hysteresis")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/thermal/thermal_sysfs.c | 54 ++++++++++++---------------------
+ 1 file changed, 20 insertions(+), 34 deletions(-)
+
+diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c
+index f12d5d47da9bd..11a34b9fe153d 100644
+--- a/drivers/thermal/thermal_sysfs.c
++++ b/drivers/thermal/thermal_sysfs.c
+@@ -12,6 +12,7 @@
+ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++#include <linux/container_of.h>
+ #include <linux/sysfs.h>
+ #include <linux/device.h>
+ #include <linux/err.h>
+@@ -78,39 +79,38 @@ mode_store(struct device *dev, struct device_attribute *attr,
+       return count;
+ }
++#define thermal_trip_of_attr(_ptr_, _attr_)                           \
++      ({                                                              \
++              struct thermal_trip_desc *td;                           \
++                                                                      \
++              td = container_of(_ptr_, struct thermal_trip_desc,      \
++                                trip_attrs._attr_.attr);              \
++              &td->trip;                                              \
++      })
++
+ static ssize_t
+ trip_point_type_show(struct device *dev, struct device_attribute *attr,
+                    char *buf)
+ {
+-      struct thermal_zone_device *tz = to_thermal_zone(dev);
+-      int trip_id;
+-
+-      if (sscanf(attr->attr.name, "trip_point_%d_type", &trip_id) != 1)
+-              return -EINVAL;
++      struct thermal_trip *trip = thermal_trip_of_attr(attr, type);
+-      return sprintf(buf, "%s\n", thermal_trip_type_name(tz->trips[trip_id].trip.type));
++      return sprintf(buf, "%s\n", thermal_trip_type_name(trip->type));
+ }
+ static ssize_t
+ trip_point_temp_store(struct device *dev, struct device_attribute *attr,
+                     const char *buf, size_t count)
+ {
++      struct thermal_trip *trip = thermal_trip_of_attr(attr, temp);
+       struct thermal_zone_device *tz = to_thermal_zone(dev);
+-      struct thermal_trip *trip;
+-      int trip_id, ret;
+-      int temp;
++      int ret, temp;
+       ret = kstrtoint(buf, 10, &temp);
+       if (ret)
+               return -EINVAL;
+-      if (sscanf(attr->attr.name, "trip_point_%d_temp", &trip_id) != 1)
+-              return -EINVAL;
+-
+       mutex_lock(&tz->lock);
+-      trip = &tz->trips[trip_id].trip;
+-
+       if (temp != trip->temperature) {
+               if (tz->ops.set_trip_temp) {
+                       ret = tz->ops.set_trip_temp(tz, trip, temp);
+@@ -133,35 +133,25 @@ static ssize_t
+ trip_point_temp_show(struct device *dev, struct device_attribute *attr,
+                    char *buf)
+ {
+-      struct thermal_zone_device *tz = to_thermal_zone(dev);
+-      int trip_id;
++      struct thermal_trip *trip = thermal_trip_of_attr(attr, temp);
+-      if (sscanf(attr->attr.name, "trip_point_%d_temp", &trip_id) != 1)
+-              return -EINVAL;
+-
+-      return sprintf(buf, "%d\n", READ_ONCE(tz->trips[trip_id].trip.temperature));
++      return sprintf(buf, "%d\n", READ_ONCE(trip->temperature));
+ }
+ static ssize_t
+ trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
+                     const char *buf, size_t count)
+ {
++      struct thermal_trip *trip = thermal_trip_of_attr(attr, hyst);
+       struct thermal_zone_device *tz = to_thermal_zone(dev);
+-      struct thermal_trip *trip;
+-      int trip_id, ret;
+-      int hyst;
++      int ret, hyst;
+       ret = kstrtoint(buf, 10, &hyst);
+       if (ret || hyst < 0)
+               return -EINVAL;
+-      if (sscanf(attr->attr.name, "trip_point_%d_hyst", &trip_id) != 1)
+-              return -EINVAL;
+-
+       mutex_lock(&tz->lock);
+-      trip = &tz->trips[trip_id].trip;
+-
+       if (hyst != trip->hysteresis) {
+               WRITE_ONCE(trip->hysteresis, hyst);
+@@ -177,13 +167,9 @@ static ssize_t
+ trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
+                    char *buf)
+ {
+-      struct thermal_zone_device *tz = to_thermal_zone(dev);
+-      int trip_id;
+-
+-      if (sscanf(attr->attr.name, "trip_point_%d_hyst", &trip_id) != 1)
+-              return -EINVAL;
++      struct thermal_trip *trip = thermal_trip_of_attr(attr, hyst);
+-      return sprintf(buf, "%d\n", READ_ONCE(tz->trips[trip_id].trip.hysteresis));
++      return sprintf(buf, "%d\n", READ_ONCE(trip->hysteresis));
+ }
+ static ssize_t
+-- 
+2.43.0
+
diff --git a/queue-6.11/thermal-sysfs-refine-the-handling-of-trip-hysteresis.patch b/queue-6.11/thermal-sysfs-refine-the-handling-of-trip-hysteresis.patch
new file mode 100644 (file)
index 0000000..9c84cb8
--- /dev/null
@@ -0,0 +1,81 @@
+From 2f9e752579ecf6f424af7bf7ca656b4458084cfc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 29 Jul 2024 18:27:25 +0200
+Subject: thermal: sysfs: Refine the handling of trip hysteresis changes
+
+From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+[ Upstream commit 107280e1371f1ba183be1ac88e91ec60cad33c18 ]
+
+Change trip_point_hyst_store() and replace thermal_zone_trip_updated()
+with thermal_zone_set_trip_hyst() to follow the trip_point_temp_store()
+code pattern for more consistency.
+
+No intentional functional impact.
+
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Link: https://patch.msgid.link/5508466.Sb9uPGUboI@rjwysocki.net
+Stable-dep-of: 874b6476fa88 ("thermal: sysfs: Add sanity checks for trip temperature and hysteresis")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/thermal/thermal_core.h  | 4 ++--
+ drivers/thermal/thermal_sysfs.c | 4 ++--
+ drivers/thermal/thermal_trip.c  | 6 +++---
+ 3 files changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
+index 5be8bef41b926..3c8e2bca87f2d 100644
+--- a/drivers/thermal/thermal_core.h
++++ b/drivers/thermal/thermal_core.h
+@@ -263,11 +263,11 @@ const char *thermal_trip_type_name(enum thermal_trip_type trip_type);
+ void thermal_zone_set_trips(struct thermal_zone_device *tz);
+ int thermal_zone_trip_id(const struct thermal_zone_device *tz,
+                        const struct thermal_trip *trip);
+-void thermal_zone_trip_updated(struct thermal_zone_device *tz,
+-                             const struct thermal_trip *trip);
+ int __thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp);
+ void thermal_zone_trip_down(struct thermal_zone_device *tz,
+                           const struct thermal_trip *trip);
++void thermal_zone_set_trip_hyst(struct thermal_zone_device *tz,
++                              struct thermal_trip *trip, int hyst);
+ /* sysfs I/F */
+ int thermal_zone_create_device_groups(struct thermal_zone_device *tz);
+diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c
+index 11a34b9fe153d..2709455486776 100644
+--- a/drivers/thermal/thermal_sysfs.c
++++ b/drivers/thermal/thermal_sysfs.c
+@@ -153,9 +153,9 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
+       mutex_lock(&tz->lock);
+       if (hyst != trip->hysteresis) {
+-              WRITE_ONCE(trip->hysteresis, hyst);
++              thermal_zone_set_trip_hyst(tz, trip, hyst);
+-              thermal_zone_trip_updated(tz, trip);
++              __thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED);
+       }
+       mutex_unlock(&tz->lock);
+diff --git a/drivers/thermal/thermal_trip.c b/drivers/thermal/thermal_trip.c
+index 06a0554ddc389..fa5ac9b512312 100644
+--- a/drivers/thermal/thermal_trip.c
++++ b/drivers/thermal/thermal_trip.c
+@@ -138,11 +138,11 @@ int thermal_zone_trip_id(const struct thermal_zone_device *tz,
+       return trip_to_trip_desc(trip) - tz->trips;
+ }
+-void thermal_zone_trip_updated(struct thermal_zone_device *tz,
+-                             const struct thermal_trip *trip)
++void thermal_zone_set_trip_hyst(struct thermal_zone_device *tz,
++                              struct thermal_trip *trip, int hyst)
+ {
++      WRITE_ONCE(trip->hysteresis, hyst);
+       thermal_notify_tz_trip_change(tz, trip);
+-      __thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED);
+ }
+ void thermal_zone_set_trip_temp(struct thermal_zone_device *tz,
+-- 
+2.43.0
+
diff --git a/queue-6.11/usb-typec-ucsi-call-cancel-from-single-location.patch b/queue-6.11/usb-typec-ucsi-call-cancel-from-single-location.patch
new file mode 100644 (file)
index 0000000..12a7d98
--- /dev/null
@@ -0,0 +1,67 @@
+From 0da7831d0033b0d96195c9ea26b6b8feea0dd65a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 16 Aug 2024 16:58:58 +0300
+Subject: usb: typec: ucsi: Call CANCEL from single location
+
+From: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+
+[ Upstream commit 4f322657ade1b784bb2b1ba8761469ae87520681 ]
+
+The command cancellation can be done right after detecting
+that the PPM is busy. There is no need to do it separately
+in ucsi_read_error() and ucsi_send_command_common().
+
+Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Link: https://lore.kernel.org/r/20240816135859.3499351-6-heikki.krogerus@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 7fa6b25dfb43 ("usb: typec: ucsi: Fix busy loop on ASUS VivoBooks")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/typec/ucsi/ucsi.c | 17 ++++-------------
+ 1 file changed, 4 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
+index 17155ed17fdf8..26a28c7b680b1 100644
+--- a/drivers/usb/typec/ucsi/ucsi.c
++++ b/drivers/usb/typec/ucsi/ucsi.c
+@@ -115,7 +115,7 @@ static int ucsi_run_command(struct ucsi *ucsi, u64 command, u32 *cci,
+               return ret;
+       if (*cci & UCSI_CCI_BUSY)
+-              return -EBUSY;
++              return ucsi_run_command(ucsi, UCSI_CANCEL, cci, NULL, 0, false) ?: -EBUSY;
+       if (!(*cci & UCSI_CCI_COMMAND_COMPLETE))
+               return -EIO;
+@@ -148,15 +148,7 @@ static int ucsi_read_error(struct ucsi *ucsi, u8 connector_num)
+       int ret;
+       command = UCSI_GET_ERROR_STATUS | UCSI_CONNECTOR_NUMBER(connector_num);
+-      ret = ucsi_run_command(ucsi, command, &cci,
+-                             &error, sizeof(error), false);
+-
+-      if (cci & UCSI_CCI_BUSY) {
+-              ret = ucsi_run_command(ucsi, UCSI_CANCEL, &cci, NULL, 0, false);
+-
+-              return ret ? ret : -EBUSY;
+-      }
+-
++      ret = ucsi_run_command(ucsi, command, &cci, &error, sizeof(error), false);
+       if (ret < 0)
+               return ret;
+@@ -238,9 +230,8 @@ static int ucsi_send_command_common(struct ucsi *ucsi, u64 cmd,
+       mutex_lock(&ucsi->ppm_lock);
+       ret = ucsi_run_command(ucsi, cmd, &cci, data, size, conn_ack);
+-      if (cci & UCSI_CCI_BUSY)
+-              ret = ucsi_run_command(ucsi, UCSI_CANCEL, &cci, NULL, 0, false) ?: -EBUSY;
+-      else if (cci & UCSI_CCI_ERROR)
++
++      if (cci & UCSI_CCI_ERROR)
+               ret = ucsi_read_error(ucsi, connector_num);
+       mutex_unlock(&ucsi->ppm_lock);
+-- 
+2.43.0
+
diff --git a/queue-6.11/usb-typec-ucsi-fix-busy-loop-on-asus-vivobooks.patch b/queue-6.11/usb-typec-ucsi-fix-busy-loop-on-asus-vivobooks.patch
new file mode 100644 (file)
index 0000000..630ac69
--- /dev/null
@@ -0,0 +1,89 @@
+From 98db8c27a9d4377d2710270b36252171c05a3da3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Sep 2024 09:41:32 +0200
+Subject: usb: typec: ucsi: Fix busy loop on ASUS VivoBooks
+
+From: Christian A. Ehrhardt <lk@c--e.de>
+
+[ Upstream commit 7fa6b25dfb43dafc0e16510e2fcfd63634fc95c2 ]
+
+If the busy indicator is set, all other fields in CCI should be
+clear according to the spec. However, some UCSI implementations do
+not follow this rule and report bogus data in CCI along with the
+busy indicator. Ignore the contents of CCI if the busy indicator is
+set.
+
+If a command timeout is hit it is possible that the EVENT_PENDING
+bit is cleared while connector work is still scheduled which can
+cause the EVENT_PENDING bit to go out of sync with scheduled connector
+work. Check and set the EVENT_PENDING bit on entry to
+ucsi_handle_connector_change() to fix this.
+
+Finally, check UCSI_CCI_BUSY before the return code of ->sync_control.
+This ensures that the command is cancelled even if ->sync_control
+returns an error (most likely -ETIMEDOUT).
+
+Reported-by: Anurag Bijea <icaliberdev@gmail.com>
+Closes: https://bugzilla.kernel.org/show_bug.cgi?id=219108
+Bisected-by: Christian Heusel <christian@heusel.eu>
+Tested-by: Anurag Bijea <icaliberdev@gmail.com>
+Fixes: de52aca4d9d5 ("usb: typec: ucsi: Never send a lone connector change ack")
+Cc: stable@vger.kernel.org
+Signed-off-by: Christian A. Ehrhardt <lk@c--e.de>
+Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Link: https://lore.kernel.org/r/20240912074132.722855-1-lk@c--e.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/typec/ucsi/ucsi.c | 18 ++++++++++++------
+ 1 file changed, 12 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
+index 26a28c7b680b1..8cc43c866130a 100644
+--- a/drivers/usb/typec/ucsi/ucsi.c
++++ b/drivers/usb/typec/ucsi/ucsi.c
+@@ -38,6 +38,10 @@
+ void ucsi_notify_common(struct ucsi *ucsi, u32 cci)
+ {
++      /* Ignore bogus data in CCI if busy indicator is set. */
++      if (cci & UCSI_CCI_BUSY)
++              return;
++
+       if (UCSI_CCI_CONNECTOR(cci))
+               ucsi_connector_change(ucsi, UCSI_CCI_CONNECTOR(cci));
+@@ -107,15 +111,13 @@ static int ucsi_run_command(struct ucsi *ucsi, u64 command, u32 *cci,
+               size = clamp(size, 0, 16);
+       ret = ucsi->ops->sync_control(ucsi, command);
+-      if (ret)
+-              return ret;
+-
+-      ret = ucsi->ops->read_cci(ucsi, cci);
+-      if (ret)
+-              return ret;
++      if (ucsi->ops->read_cci(ucsi, cci))
++              return -EIO;
+       if (*cci & UCSI_CCI_BUSY)
+               return ucsi_run_command(ucsi, UCSI_CANCEL, cci, NULL, 0, false) ?: -EBUSY;
++      if (ret)
++              return ret;
+       if (!(*cci & UCSI_CCI_COMMAND_COMPLETE))
+               return -EIO;
+@@ -1240,6 +1242,10 @@ static void ucsi_handle_connector_change(struct work_struct *work)
+       mutex_lock(&con->lock);
++      if (!test_and_set_bit(EVENT_PENDING, &ucsi->flags))
++              dev_err_once(ucsi->dev, "%s entered without EVENT_PENDING\n",
++                           __func__);
++
+       command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num);
+       ret = ucsi_send_command_common(ucsi, command, &con->status,
+-- 
+2.43.0
+