From: Sasha Levin Date: Wed, 2 Oct 2024 05:17:32 +0000 (-0400) Subject: Fixes for 6.11 X-Git-Tag: v6.6.54~51 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5e3de310ca88ffe5e58672b3bb41ef0fd4e13f0c;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 6.11 Signed-off-by: Sasha Levin --- 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 index 00000000000..12efc1cdb8b --- /dev/null +++ b/queue-6.11/lsm-infrastructure-management-of-the-sock-security.patch @@ -0,0 +1,933 @@ +From 4847334176513a6ac636ad17bc6e3c48e2f568ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Jul 2024 14:32:25 -0700 +Subject: lsm: infrastructure management of the sock security + +From: Casey Schaufler + +[ 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 +Reviewed-by: Kees Cook +Reviewed-by: John Johansen +Acked-by: Stephen Smalley +Signed-off-by: Casey Schaufler +[PM: subject tweak] +Signed-off-by: Paul Moore +Stable-dep-of: 63dff3e48871 ("lsm: add the inode_free_security_rcu() LSM implementation hook") +Signed-off-by: Sasha Levin +--- + 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 + #include + #include ++#include + + /* 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 + #include + #include ++#include + #include + #include + #include +@@ -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 index 00000000000..0a7b4e13923 --- /dev/null +++ b/queue-6.11/serial-qcom-geni-fix-arg-types-for-qcom_geni_serial_.patch @@ -0,0 +1,48 @@ +From f138bd8383484d807836ba2e13d7a8960e792729 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Douglas Anderson +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20240610152420.v4.4.I24a0de52dd7336908df180fa6b698e001f3aff82@changeid +Tested-by: Nícolas F. R. A. Prado +Signed-off-by: Johan Hovold +Link: https://lore.kernel.org/r/20240906131336.23625-5-johan+linaro@kernel.org +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: cc4a0e5754a1 ("serial: qcom-geni: fix console corruption") +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..fc017e1407e --- /dev/null +++ b/queue-6.11/serial-qcom-geni-fix-console-corruption.patch @@ -0,0 +1,169 @@ +From 71284b18956d1f1c65074aa90c3fac15227bf583 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Tested-by: Nícolas F. R. A. Prado +Signed-off-by: Johan Hovold +Link: https://lore.kernel.org/r/20240906131336.23625-7-johan+linaro@kernel.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..a8edeb9182e --- /dev/null +++ b/queue-6.11/serial-qcom-geni-introduce-qcom_geni_serial_poll_bit.patch @@ -0,0 +1,70 @@ +From 0827839650381c5b2b36673f556944af8bf27c70 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20240610152420.v4.5.Ic6411eab8d9d37acc451705f583fb535cd6dadb2@changeid +Tested-by: Nícolas F. R. A. Prado +Signed-off-by: Johan Hovold +Link: https://lore.kernel.org/r/20240906131336.23625-6-johan+linaro@kernel.org +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: cc4a0e5754a1 ("serial: qcom-geni: fix console corruption") +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.11/series b/queue-6.11/series index 74c00fd1f0e..0126d44fa0b 100644 --- a/queue-6.11/series +++ b/queue-6.11/series @@ -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 index 00000000000..ee157ee85af --- /dev/null +++ b/queue-6.11/soc-qcom-geni-se-add-gp_length-irq_en_set-irq_en_cle.patch @@ -0,0 +1,75 @@ +From fbe43be15e67d88a19e55a23e5c7a4db23951953 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Douglas Anderson +Link: https://lore.kernel.org/r/20240610152420.v4.1.Ife7ced506aef1be3158712aa3ff34a006b973559@changeid +Tested-by: Nícolas F. R. A. Prado +Signed-off-by: Johan Hovold +Link: https://lore.kernel.org/r/20240906131336.23625-4-johan+linaro@kernel.org +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: cc4a0e5754a1 ("serial: qcom-geni: fix console corruption") +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..503716a617a --- /dev/null +++ b/queue-6.11/soc-versatile-realview-fix-memory-leak-during-device.patch @@ -0,0 +1,50 @@ +From 07d5b7e267b5c57be2a75f62b3ac1a85a709dc8e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 25 Aug 2024 20:05:23 +0200 +Subject: soc: versatile: realview: fix memory leak during device remove + +From: Krzysztof Kozlowski + +[ 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 +Link: https://lore.kernel.org/20240825-soc-dev-fixes-v1-2-ff4b35abed83@linaro.org +Signed-off-by: Linus Walleij +Stable-dep-of: c774f2564c00 ("soc: versatile: realview: fix soc_dev leak during device remove") +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..6cf2dbd4e64 --- /dev/null +++ b/queue-6.11/soc-versatile-realview-fix-soc_dev-leak-during-devic.patch @@ -0,0 +1,63 @@ +From 386cb0f19b79d3c4f9b95effb883e409b28c8902 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 25 Aug 2024 20:05:24 +0200 +Subject: soc: versatile: realview: fix soc_dev leak during device remove + +From: Krzysztof Kozlowski + +[ 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 +Link: https://lore.kernel.org/20240825-soc-dev-fixes-v1-3-ff4b35abed83@linaro.org +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + 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 + */ ++#include + #include + #include + #include +@@ -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 index 00000000000..d86726c0c4e --- /dev/null +++ b/queue-6.11/thermal-core-store-trip-sysfs-attributes-in-thermal_.patch @@ -0,0 +1,224 @@ +From 20a223c4112b4b837451a103f6214b7f828e1536 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Jul 2024 18:25:03 +0200 +Subject: thermal: core: Store trip sysfs attributes in thermal_trip_desc + +From: Rafael J. Wysocki + +[ 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 +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 +--- + 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 index 00000000000..617b29105c1 --- /dev/null +++ b/queue-6.11/thermal-sysfs-add-sanity-checks-for-trip-temperature.patch @@ -0,0 +1,111 @@ +From 872ec8f8250f0f8f01157681c72b813f987f4009 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Aug 2024 18:21:59 +0200 +Subject: thermal: sysfs: Add sanity checks for trip temperature and hysteresis + +From: Rafael J. Wysocki + +[ 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+ # 6.8+ +Signed-off-by: Rafael J. Wysocki +Reviewed-by: Lukasz Luba +Link: https://patch.msgid.link/12528772.O9o76ZdvQC@rjwysocki.net +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..e6ff954ebe0 --- /dev/null +++ b/queue-6.11/thermal-sysfs-get-to-trips-via-attribute-pointers.patch @@ -0,0 +1,152 @@ +From 4d6569d10c6f8d6d634fd8a2b2dc2af1ce9191dc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Jul 2024 18:25:59 +0200 +Subject: thermal: sysfs: Get to trips via attribute pointers + +From: Rafael J. Wysocki + +[ 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 +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 +--- + 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 + #include + #include + #include +@@ -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 index 00000000000..9c84cb811c8 --- /dev/null +++ b/queue-6.11/thermal-sysfs-refine-the-handling-of-trip-hysteresis.patch @@ -0,0 +1,81 @@ +From 2f9e752579ecf6f424af7bf7ca656b4458084cfc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Jul 2024 18:27:25 +0200 +Subject: thermal: sysfs: Refine the handling of trip hysteresis changes + +From: Rafael J. Wysocki + +[ 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 +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 +--- + 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 index 00000000000..12a7d986594 --- /dev/null +++ b/queue-6.11/usb-typec-ucsi-call-cancel-from-single-location.patch @@ -0,0 +1,67 @@ +From 0da7831d0033b0d96195c9ea26b6b8feea0dd65a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Aug 2024 16:58:58 +0300 +Subject: usb: typec: ucsi: Call CANCEL from single location + +From: Heikki Krogerus + +[ 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 +Link: https://lore.kernel.org/r/20240816135859.3499351-6-heikki.krogerus@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 7fa6b25dfb43 ("usb: typec: ucsi: Fix busy loop on ASUS VivoBooks") +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..630ac695ade --- /dev/null +++ b/queue-6.11/usb-typec-ucsi-fix-busy-loop-on-asus-vivobooks.patch @@ -0,0 +1,89 @@ +From 98db8c27a9d4377d2710270b36252171c05a3da3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Sep 2024 09:41:32 +0200 +Subject: usb: typec: ucsi: Fix busy loop on ASUS VivoBooks + +From: Christian A. Ehrhardt + +[ 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 +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=219108 +Bisected-by: Christian Heusel +Tested-by: Anurag Bijea +Fixes: de52aca4d9d5 ("usb: typec: ucsi: Never send a lone connector change ack") +Cc: stable@vger.kernel.org +Signed-off-by: Christian A. Ehrhardt +Reviewed-by: Heikki Krogerus +Link: https://lore.kernel.org/r/20240912074132.722855-1-lk@c--e.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + 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 +