From 2cf002d194977c4ec8848496a9a9804a317099dd Mon Sep 17 00:00:00 2001 From: Mauricio Faria de Oliveira Date: Tue, 2 Jun 2020 18:15:16 -0300 Subject: apparmor: check/put label on apparmor_sk_clone_security() Currently apparmor_sk_clone_security() does not check for existing label/peer in the 'new' struct sock; it just overwrites it, if any (with another reference to the label of the source sock.) static void apparmor_sk_clone_security(const struct sock *sk, struct sock *newsk) { struct aa_sk_ctx *ctx = SK_CTX(sk); struct aa_sk_ctx *new = SK_CTX(newsk); new->label = aa_get_label(ctx->label); new->peer = aa_get_label(ctx->peer); } This might leak label references, which might overflow under load. Thus, check for and put labels, to prevent such errors. Note this is similarly done on: static int apparmor_socket_post_create(struct socket *sock, ...) ... if (sock->sk) { struct aa_sk_ctx *ctx = SK_CTX(sock->sk); aa_put_label(ctx->label); ctx->label = aa_get_label(label); } ... Context: ------- The label reference count leak is observed if apparmor_sock_graft() is called previously: this sets the 'ctx->label' field by getting a reference to the current label (later overwritten, without put.) static void apparmor_sock_graft(struct sock *sk, ...) { struct aa_sk_ctx *ctx = SK_CTX(sk); if (!ctx->label) ctx->label = aa_get_current_label(); } And that is the case on crypto/af_alg.c:af_alg_accept(): int af_alg_accept(struct sock *sk, struct socket *newsock, ...) ... struct sock *sk2; ... sk2 = sk_alloc(...); ... security_sock_graft(sk2, newsock); security_sk_clone(sk, sk2); ... Apparently both calls are done on their own right, especially for other LSMs, being introduced in 2010/2014, before apparmor socket mediation in 2017 (see commits [1,2,3,4]). So, it looks OK there! Let's fix the reference leak in apparmor. Test-case: --------- Exercise that code path enough to overflow label reference count. $ cat aa-refcnt-af_alg.c #include #include #include #include #include int main() { int sockfd; struct sockaddr_alg sa; /* Setup the crypto API socket */ sockfd = socket(AF_ALG, SOCK_SEQPACKET, 0); if (sockfd < 0) { perror("socket"); return 1; } memset(&sa, 0, sizeof(sa)); sa.salg_family = AF_ALG; strcpy((char *) sa.salg_type, "rng"); strcpy((char *) sa.salg_name, "stdrng"); if (bind(sockfd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { perror("bind"); return 1; } /* Accept a "connection" and close it; repeat. */ while (!close(accept(sockfd, NULL, 0))); return 0; } $ gcc -o aa-refcnt-af_alg aa-refcnt-af_alg.c $ ./aa-refcnt-af_alg [ 9928.475953] refcount_t overflow at apparmor_sk_clone_security+0x37/0x70 in aa-refcnt-af_alg[1322], uid/euid: 1000/1000 ... [ 9928.507443] RIP: 0010:apparmor_sk_clone_security+0x37/0x70 ... [ 9928.514286] security_sk_clone+0x33/0x50 [ 9928.514807] af_alg_accept+0x81/0x1c0 [af_alg] [ 9928.516091] alg_accept+0x15/0x20 [af_alg] [ 9928.516682] SYSC_accept4+0xff/0x210 [ 9928.519609] SyS_accept+0x10/0x20 [ 9928.520190] do_syscall_64+0x73/0x130 [ 9928.520808] entry_SYSCALL_64_after_hwframe+0x3d/0xa2 Note that other messages may be seen, not just overflow, depending on the value being incremented by kref_get(); on another run: [ 7273.182666] refcount_t: saturated; leaking memory. ... [ 7273.185789] refcount_t: underflow; use-after-free. Kprobes: ------- Using kprobe events to monitor sk -> sk_security -> label -> count (kref): Original v5.7 (one reference leak every iteration) ... (af_alg_accept+0x0/0x1c0) label=0xffff8a0f36c25eb0 label_refcnt=0x11fd2 ... (af_alg_release_parent+0x0/0xd0) label=0xffff8a0f36c25eb0 label_refcnt=0x11fd4 ... (af_alg_accept+0x0/0x1c0) label=0xffff8a0f36c25eb0 label_refcnt=0x11fd3 ... (af_alg_release_parent+0x0/0xd0) label=0xffff8a0f36c25eb0 label_refcnt=0x11fd5 ... (af_alg_accept+0x0/0x1c0) label=0xffff8a0f36c25eb0 label_refcnt=0x11fd4 ... (af_alg_release_parent+0x0/0xd0) label=0xffff8a0f36c25eb0 label_refcnt=0x11fd6 Patched v5.7 (zero reference leak per iteration) ... (af_alg_accept+0x0/0x1c0) label=0xffff9ff376c25eb0 label_refcnt=0x593 ... (af_alg_release_parent+0x0/0xd0) label=0xffff9ff376c25eb0 label_refcnt=0x594 ... (af_alg_accept+0x0/0x1c0) label=0xffff9ff376c25eb0 label_refcnt=0x593 ... (af_alg_release_parent+0x0/0xd0) label=0xffff9ff376c25eb0 label_refcnt=0x594 ... (af_alg_accept+0x0/0x1c0) label=0xffff9ff376c25eb0 label_refcnt=0x593 ... (af_alg_release_parent+0x0/0xd0) label=0xffff9ff376c25eb0 label_refcnt=0x594 Commits: ------- [1] commit 507cad355fc9 ("crypto: af_alg - Make sure sk_security is initialized on accept()ed sockets") [2] commit 4c63f83c2c2e ("crypto: af_alg - properly label AF_ALG socket") [3] commit 2acce6aa9f65 ("Networking") a.k.a ("crypto: af_alg - Avoid sock_graft call warning) [4] commit 56974a6fcfef ("apparmor: add base infastructure for socket mediation") Reported-by: Brian Moyles Signed-off-by: Mauricio Faria de Oliveira Signed-off-by: John Johansen --- security/apparmor/lsm.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index b621ad74f54a..66a8504c8bea 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -804,7 +804,12 @@ static void apparmor_sk_clone_security(const struct sock *sk, struct aa_sk_ctx *ctx = SK_CTX(sk); struct aa_sk_ctx *new = SK_CTX(newsk); + if (new->label) + aa_put_label(new->label); new->label = aa_get_label(ctx->label); + + if (new->peer) + aa_put_label(new->peer); new->peer = aa_get_label(ctx->peer); } -- cgit From 5268d795d6888b202ad9f2b16a254cd00d0de77b Mon Sep 17 00:00:00 2001 From: John Johansen Date: Fri, 5 Jun 2020 18:12:21 -0700 Subject: apparmor: fix introspection of of task mode for unconfined tasks Fix two issues with introspecting the task mode. 1. If a task is attached to a unconfined profile that is not the ns->unconfined profile then. Mode the mode is always reported as - $ ps -Z LABEL PID TTY TIME CMD unconfined 1287 pts/0 00:00:01 bash test (-) 1892 pts/0 00:00:00 ps instead of the correct value of (unconfined) as shown below $ ps -Z LABEL PID TTY TIME CMD unconfined 2483 pts/0 00:00:01 bash test (unconfined) 3591 pts/0 00:00:00 ps 2. if a task is confined by a stack of profiles that are unconfined the output of label mode is again the incorrect value of (-) like above, instead of (unconfined). This is because the visibile profile count increment is skipped by the special casing of unconfined. Signed-off-by: John Johansen --- security/apparmor/label.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/security/apparmor/label.c b/security/apparmor/label.c index 676eebcbfd68..23f7a193df4f 100644 --- a/security/apparmor/label.c +++ b/security/apparmor/label.c @@ -1558,13 +1558,13 @@ static const char *label_modename(struct aa_ns *ns, struct aa_label *label, label_for_each(i, label, profile) { if (aa_ns_visible(ns, profile->ns, flags & FLAG_VIEW_SUBNS)) { - if (profile->mode == APPARMOR_UNCONFINED) + count++; + if (profile == profile->ns->unconfined) /* special case unconfined so stacks with * unconfined don't report as mixed. ie. * profile_foo//&:ns1:unconfined (mixed) */ continue; - count++; if (mode == -1) mode = profile->mode; else if (mode != profile->mode) -- cgit From 92de220a7f336367127351da58cff691da5bb17b Mon Sep 17 00:00:00 2001 From: John Johansen Date: Tue, 30 Jun 2020 17:00:11 -0700 Subject: apparmor: update policy capable checks to use a label Previously the policy capable checks assumed they were using the current task. Make them take the task label so the query can be made against an arbitrary task. Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 4 ++-- security/apparmor/include/label.h | 1 + security/apparmor/include/policy.h | 6 ++++-- security/apparmor/lsm.c | 22 ++++++++++---------- security/apparmor/policy.c | 41 ++++++++++++++++++++++++++++++-------- 5 files changed, 51 insertions(+), 23 deletions(-) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index d65324415980..3275e074e5f8 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -1357,7 +1357,7 @@ static int rawdata_open(struct inode *inode, struct file *file) struct aa_loaddata *loaddata; struct rawdata_f_data *private; - if (!policy_view_capable(NULL)) + if (!aa_current_policy_view_capable(NULL)) return -EACCES; loaddata = __aa_get_loaddata(inode->i_private); @@ -2266,7 +2266,7 @@ static const struct seq_operations aa_sfs_profiles_op = { static int profiles_open(struct inode *inode, struct file *file) { - if (!policy_view_capable(NULL)) + if (!aa_current_policy_view_capable(NULL)) return -EACCES; return seq_open(file, &aa_sfs_profiles_op); diff --git a/security/apparmor/include/label.h b/security/apparmor/include/label.h index 255764ab06e2..f5b5485e20c9 100644 --- a/security/apparmor/include/label.h +++ b/security/apparmor/include/label.h @@ -148,6 +148,7 @@ do { \ #define __label_make_stale(X) ((X)->flags |= FLAG_STALE) #define labels_ns(X) (vec_ns(&((X)->vec[0]), (X)->size)) #define labels_set(X) (&labels_ns(X)->labels) +#define labels_view(X) labels_ns(X) #define labels_profile(X) ((X)->vec[(X)->size - 1]) diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index b5b4b8190e65..cb5ef21991b7 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -301,9 +301,11 @@ static inline int AUDIT_MODE(struct aa_profile *profile) return profile->audit; } -bool policy_view_capable(struct aa_ns *ns); -bool policy_admin_capable(struct aa_ns *ns); +bool aa_policy_view_capable(struct aa_label *label, struct aa_ns *ns); +bool aa_policy_admin_capable(struct aa_label *label, struct aa_ns *ns); int aa_may_manage_policy(struct aa_label *label, struct aa_ns *ns, u32 mask); +bool aa_current_policy_view_capable(struct aa_ns *ns); +bool aa_current_policy_admin_capable(struct aa_ns *ns); #endif /* __AA_POLICY_H */ diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 66a8504c8bea..64d6020ffd50 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -1392,7 +1392,7 @@ static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp { if (!apparmor_enabled) return -EINVAL; - if (apparmor_initialized && !policy_admin_capable(NULL)) + if (apparmor_initialized && !aa_current_policy_admin_capable(NULL)) return -EPERM; return param_set_bool(val, kp); } @@ -1401,7 +1401,7 @@ static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp) { if (!apparmor_enabled) return -EINVAL; - if (apparmor_initialized && !policy_view_capable(NULL)) + if (apparmor_initialized && !aa_current_policy_view_capable(NULL)) return -EPERM; return param_get_bool(buffer, kp); } @@ -1410,7 +1410,7 @@ static int param_set_aabool(const char *val, const struct kernel_param *kp) { if (!apparmor_enabled) return -EINVAL; - if (apparmor_initialized && !policy_admin_capable(NULL)) + if (apparmor_initialized && !aa_current_policy_admin_capable(NULL)) return -EPERM; return param_set_bool(val, kp); } @@ -1419,7 +1419,7 @@ static int param_get_aabool(char *buffer, const struct kernel_param *kp) { if (!apparmor_enabled) return -EINVAL; - if (apparmor_initialized && !policy_view_capable(NULL)) + if (apparmor_initialized && !aa_current_policy_view_capable(NULL)) return -EPERM; return param_get_bool(buffer, kp); } @@ -1445,7 +1445,7 @@ static int param_get_aauint(char *buffer, const struct kernel_param *kp) { if (!apparmor_enabled) return -EINVAL; - if (apparmor_initialized && !policy_view_capable(NULL)) + if (apparmor_initialized && !aa_current_policy_view_capable(NULL)) return -EPERM; return param_get_uint(buffer, kp); } @@ -1516,7 +1516,7 @@ static int param_get_aacompressionlevel(char *buffer, { if (!apparmor_enabled) return -EINVAL; - if (apparmor_initialized && !policy_view_capable(NULL)) + if (apparmor_initialized && !aa_current_policy_view_capable(NULL)) return -EPERM; return param_get_int(buffer, kp); } @@ -1525,7 +1525,7 @@ static int param_get_audit(char *buffer, const struct kernel_param *kp) { if (!apparmor_enabled) return -EINVAL; - if (apparmor_initialized && !policy_view_capable(NULL)) + if (apparmor_initialized && !aa_current_policy_view_capable(NULL)) return -EPERM; return sprintf(buffer, "%s", audit_mode_names[aa_g_audit]); } @@ -1538,7 +1538,7 @@ static int param_set_audit(const char *val, const struct kernel_param *kp) return -EINVAL; if (!val) return -EINVAL; - if (apparmor_initialized && !policy_admin_capable(NULL)) + if (apparmor_initialized && !aa_current_policy_admin_capable(NULL)) return -EPERM; i = match_string(audit_mode_names, AUDIT_MAX_INDEX, val); @@ -1553,7 +1553,7 @@ static int param_get_mode(char *buffer, const struct kernel_param *kp) { if (!apparmor_enabled) return -EINVAL; - if (apparmor_initialized && !policy_view_capable(NULL)) + if (apparmor_initialized && !aa_current_policy_view_capable(NULL)) return -EPERM; return sprintf(buffer, "%s", aa_profile_mode_names[aa_g_profile_mode]); @@ -1567,7 +1567,7 @@ static int param_set_mode(const char *val, const struct kernel_param *kp) return -EINVAL; if (!val) return -EINVAL; - if (apparmor_initialized && !policy_admin_capable(NULL)) + if (apparmor_initialized && !aa_current_policy_admin_capable(NULL)) return -EPERM; i = match_string(aa_profile_mode_names, APPARMOR_MODE_NAMES_MAX_INDEX, @@ -1703,7 +1703,7 @@ static int __init alloc_buffers(void) static int apparmor_dointvec(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { - if (!policy_admin_capable(NULL)) + if (!aa_current_policy_admin_capable(NULL)) return -EPERM; if (!apparmor_enabled) return -EINVAL; diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 269f2f53c0b1..e680121e013e 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -632,17 +632,18 @@ static int audit_policy(struct aa_label *label, const char *op, } /** - * policy_view_capable - check if viewing policy in at @ns is allowed - * ns: namespace being viewed by current task (may be NULL) + * aa_policy_view_capable - check if viewing policy in at @ns is allowed + * label: label that is trying to view policy in ns + * ns: namespace being viewed by @label (may be NULL if @label's ns) * Returns: true if viewing policy is allowed * * If @ns is NULL then the namespace being viewed is assumed to be the * tasks current namespace. */ -bool policy_view_capable(struct aa_ns *ns) +bool aa_policy_view_capable(struct aa_label *label, struct aa_ns *ns) { struct user_namespace *user_ns = current_user_ns(); - struct aa_ns *view_ns = aa_get_current_ns(); + struct aa_ns *view_ns = labels_view(label); bool root_in_user_ns = uid_eq(current_euid(), make_kuid(user_ns, 0)) || in_egroup_p(make_kgid(user_ns, 0)); bool response = false; @@ -654,12 +655,11 @@ bool policy_view_capable(struct aa_ns *ns) (unprivileged_userns_apparmor_policy != 0 && user_ns->level == view_ns->level))) response = true; - aa_put_ns(view_ns); return response; } -bool policy_admin_capable(struct aa_ns *ns) +bool aa_policy_admin_capable(struct aa_label *label, struct aa_ns *ns) { struct user_namespace *user_ns = current_user_ns(); bool capable = ns_capable(user_ns, CAP_MAC_ADMIN); @@ -667,7 +667,32 @@ bool policy_admin_capable(struct aa_ns *ns) AA_DEBUG("cap_mac_admin? %d\n", capable); AA_DEBUG("policy locked? %d\n", aa_g_lock_policy); - return policy_view_capable(ns) && capable && !aa_g_lock_policy; + return aa_policy_view_capable(label, ns) && capable && + !aa_g_lock_policy; +} + +bool aa_current_policy_view_capable(struct aa_ns *ns) +{ + struct aa_label *label; + bool res; + + label = __begin_current_label_crit_section(); + res = aa_policy_view_capable(label, ns); + __end_current_label_crit_section(label); + + return res; +} + +bool aa_current_policy_admin_capable(struct aa_ns *ns) +{ + struct aa_label *label; + bool res; + + label = __begin_current_label_crit_section(); + res = aa_policy_admin_capable(label, ns); + __end_current_label_crit_section(label); + + return res; } /** @@ -693,7 +718,7 @@ int aa_may_manage_policy(struct aa_label *label, struct aa_ns *ns, u32 mask) return audit_policy(label, op, NULL, NULL, "policy_locked", -EACCES); - if (!policy_admin_capable(ns)) + if (!aa_policy_admin_capable(label, ns)) return audit_policy(label, op, NULL, NULL, "not policy admin", -EACCES); -- cgit From 31ec99e13346c22a7c8ca18e044684a870063cef Mon Sep 17 00:00:00 2001 From: John Johansen Date: Wed, 1 Jul 2020 02:18:18 -0700 Subject: apparmor: switch to apparmor to internal capable check for policy management With LSM stacking calling back into capable to check for MAC_ADMIN for apparmor policy results in asking the other stacked LSMs for MAC_ADMIN resulting in the other LSMs answering based on their policy management. For apparmor policy management we just need to call apparmor's capability fn directly. Signed-off-by: John Johansen --- security/apparmor/policy.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index e680121e013e..9ce93966401a 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -631,6 +631,22 @@ static int audit_policy(struct aa_label *label, const char *op, return error; } +/* don't call out to other LSMs in the stack for apparmor policy admin + * permissions + */ +static int policy_ns_capable(struct aa_label *label, + struct user_namespace *userns, int cap) +{ + int err; + + /* check for MAC_ADMIN cap in cred */ + err = cap_capable(current_cred(), userns, cap, CAP_OPT_NONE); + if (!err) + err = aa_capable(label, cap, CAP_OPT_NONE); + + return err; +} + /** * aa_policy_view_capable - check if viewing policy in at @ns is allowed * label: label that is trying to view policy in ns @@ -662,7 +678,7 @@ bool aa_policy_view_capable(struct aa_label *label, struct aa_ns *ns) bool aa_policy_admin_capable(struct aa_label *label, struct aa_ns *ns) { struct user_namespace *user_ns = current_user_ns(); - bool capable = ns_capable(user_ns, CAP_MAC_ADMIN); + bool capable = policy_ns_capable(label, user_ns, CAP_MAC_ADMIN); AA_DEBUG("cap_mac_admin? %d\n", capable); AA_DEBUG("policy locked? %d\n", aa_g_lock_policy); -- cgit From ef70454508c00a415a41156a19cb771a186c55d0 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 25 Jan 2021 11:53:50 -0800 Subject: security: apparmor: file.h: delete duplicated word Delete the doubled word "then" in a comment. Signed-off-by: Randy Dunlap Reviewed-by: Seth Arnold Signed-off-by: John Johansen --- security/apparmor/include/file.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h index aff26fc71407..a7672dacd001 100644 --- a/security/apparmor/include/file.h +++ b/security/apparmor/include/file.h @@ -167,7 +167,7 @@ int aa_audit_file(struct aa_profile *profile, struct aa_perms *perms, * @perms: permission table indexed by the matched state accept entry of @dfa * @trans: transition table for indexed by named x transitions * - * File permission are determined by matching a path against @dfa and then + * File permission are determined by matching a path against @dfa and * then using the value of the accept entry for the matching state as * an index into @perms. If a named exec transition is required it is * looked up in the transition table. -- cgit From 4af7c863fc85ad756b7a978fe1096b80a855543c Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 7 Aug 2020 09:50:55 -0700 Subject: security: apparmor: delete repeated words in comments Drop repeated words in comments. {a, then, to} Signed-off-by: Randy Dunlap Reviewed-by: Seth Arnold Signed-off-by: John Johansen --- security/apparmor/path.c | 2 +- security/apparmor/policy_unpack.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/security/apparmor/path.c b/security/apparmor/path.c index b02dfdbff7cd..45ec994b558d 100644 --- a/security/apparmor/path.c +++ b/security/apparmor/path.c @@ -83,7 +83,7 @@ static int disconnect(const struct path *path, char *buf, char **name, * * Returns: %0 else error code if path lookup fails * When no error the path name is returned in @name which points to - * to a position in @buf + * a position in @buf */ static int d_namespace_path(const struct path *path, char *buf, char **name, int flags, const char *disconnected) diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index d9ef9a99c26e..12e6677868c3 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -39,7 +39,7 @@ /* * The AppArmor interface treats data as a type byte followed by the - * actual data. The interface has the notion of a a named entry + * actual data. The interface has the notion of a named entry * which has a name (AA_NAME typecode followed by name string) followed by * the entries typecode and data. Named types allow for optional * elements and extensions to be added and tested for without breaking -- cgit From d108370c644b153382632b3e5511ade575c91c86 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Sun, 4 Oct 2020 07:24:22 -0700 Subject: apparmor: fix error check clang static analysis reports this representative problem: label.c:1463:16: warning: Assigned value is garbage or undefined label->hname = name; ^ ~~~~ In aa_update_label_name(), this the problem block of code if (aa_label_acntsxprint(&name, ...) == -1) return res; On failure, aa_label_acntsxprint() has a more complicated return that just -1. So check for a negative return. It was also noted that the aa_label_acntsxprint() main comment refers to a nonexistent parameter, so clean up the comment. Fixes: f1bd904175e8 ("apparmor: add the base fns() for domain labels") Signed-off-by: Tom Rix Reviewed-by: Nick Desaulniers Signed-off-by: John Johansen --- security/apparmor/label.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/security/apparmor/label.c b/security/apparmor/label.c index 23f7a193df4f..f5eb9ac07e9b 100644 --- a/security/apparmor/label.c +++ b/security/apparmor/label.c @@ -1453,7 +1453,7 @@ bool aa_update_label_name(struct aa_ns *ns, struct aa_label *label, gfp_t gfp) if (label->hname || labels_ns(label) != ns) return res; - if (aa_label_acntsxprint(&name, ns, label, FLAGS_NONE, gfp) == -1) + if (aa_label_acntsxprint(&name, ns, label, FLAGS_NONE, gfp) < 0) return res; ls = labels_set(label); @@ -1703,7 +1703,7 @@ int aa_label_asxprint(char **strp, struct aa_ns *ns, struct aa_label *label, /** * aa_label_acntsxprint - allocate a __counted string buffer and print label - * @strp: buffer to write to. (MAY BE NULL if @size == 0) + * @strp: buffer to write to. * @ns: namespace profile is being viewed from * @label: label to view (NOT NULL) * @flags: flags controlling what label info is printed -- cgit From 58ae4004b9c4bb040958cf73986b687a5ea4d85d Mon Sep 17 00:00:00 2001 From: Tang Bin Date: Sun, 5 Sep 2021 18:57:32 -0700 Subject: Input: cpcap-pwrbutton - handle errors from platform_get_irq() The function cpcap_power_button_probe() does not perform sufficient error checking after executing platform_get_irq(), thus fix it. Signed-off-by: Tang Bin Link: https://lore.kernel.org/r/20210802121740.8700-1-tangbin@cmss.chinamobile.com Signed-off-by: Dmitry Torokhov --- drivers/input/misc/cpcap-pwrbutton.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/input/misc/cpcap-pwrbutton.c b/drivers/input/misc/cpcap-pwrbutton.c index 0abef63217e2..372cb44d0635 100644 --- a/drivers/input/misc/cpcap-pwrbutton.c +++ b/drivers/input/misc/cpcap-pwrbutton.c @@ -54,9 +54,13 @@ static irqreturn_t powerbutton_irq(int irq, void *_button) static int cpcap_power_button_probe(struct platform_device *pdev) { struct cpcap_power_button *button; - int irq = platform_get_irq(pdev, 0); + int irq; int err; + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + button = devm_kmalloc(&pdev->dev, sizeof(*button), GFP_KERNEL); if (!button) return -ENOMEM; -- cgit From d5f9c43d41effc3c884e0139ca52015e451039b1 Mon Sep 17 00:00:00 2001 From: "simba.hsu" Date: Tue, 1 Jun 2021 21:38:38 -0700 Subject: Input: raydium_i2c_ts - read device version in bootloader mode Add support reading device ID when controller is in bootloader mode, which may happen if firmware update has been interrupted. Signed-off-by: simba.hsu Link: https://lore.kernel.org/r/20210818063644.8654-1-simba.hsu@rad-ic.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/raydium_i2c_ts.c | 50 +++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/drivers/input/touchscreen/raydium_i2c_ts.c b/drivers/input/touchscreen/raydium_i2c_ts.c index 4d2d22a86977..92c48d8e35a4 100644 --- a/drivers/input/touchscreen/raydium_i2c_ts.c +++ b/drivers/input/touchscreen/raydium_i2c_ts.c @@ -37,6 +37,7 @@ #define RM_CMD_BOOT_READ 0x44 /* send wait bl data ready*/ #define RM_BOOT_RDY 0xFF /* bl data ready */ +#define RM_BOOT_CMD_READHWID 0x0E /* read hwid */ /* I2C main commands */ #define RM_CMD_QUERY_BANK 0x2B @@ -290,6 +291,44 @@ static int raydium_i2c_sw_reset(struct i2c_client *client) return 0; } +static int raydium_i2c_query_ts_bootloader_info(struct raydium_data *ts) +{ + struct i2c_client *client = ts->client; + static const u8 get_hwid[] = { RM_BOOT_CMD_READHWID, + 0x10, 0xc0, 0x01, 0x00, 0x04, 0x00 }; + u8 rbuf[5] = { 0 }; + u32 hw_ver; + int error; + + error = raydium_i2c_send(client, RM_CMD_BOOT_WRT, + get_hwid, sizeof(get_hwid)); + if (error) { + dev_err(&client->dev, "WRT HWID command failed: %d\n", error); + return error; + } + + error = raydium_i2c_send(client, RM_CMD_BOOT_ACK, rbuf, 1); + if (error) { + dev_err(&client->dev, "Ack HWID command failed: %d\n", error); + return error; + } + + error = raydium_i2c_read(client, RM_CMD_BOOT_CHK, rbuf, sizeof(rbuf)); + if (error) { + dev_err(&client->dev, "Read HWID command failed: %d (%4ph)\n", + error, rbuf + 1); + hw_ver = 0xffffffffUL; + } else { + hw_ver = get_unaligned_be32(rbuf + 1); + } + + ts->info.hw_ver = cpu_to_le32(hw_ver); + ts->info.main_ver = 0xff; + ts->info.sub_ver = 0xff; + + return error; +} + static int raydium_i2c_query_ts_info(struct raydium_data *ts) { struct i2c_client *client = ts->client; @@ -388,13 +427,10 @@ static int raydium_i2c_initialize(struct raydium_data *ts) if (error) ts->boot_mode = RAYDIUM_TS_BLDR; - if (ts->boot_mode == RAYDIUM_TS_BLDR) { - ts->info.hw_ver = cpu_to_le32(0xffffffffUL); - ts->info.main_ver = 0xff; - ts->info.sub_ver = 0xff; - } else { + if (ts->boot_mode == RAYDIUM_TS_BLDR) + raydium_i2c_query_ts_bootloader_info(ts); + else raydium_i2c_query_ts_info(ts); - } return error; } @@ -1218,7 +1254,7 @@ static SIMPLE_DEV_PM_OPS(raydium_i2c_pm_ops, raydium_i2c_suspend, raydium_i2c_resume); static const struct i2c_device_id raydium_i2c_id[] = { - { "raydium_i2c" , 0 }, + { "raydium_i2c", 0 }, { "rm32380", 0 }, { /* sentinel */ } }; -- cgit From daf87bffd02e35387a62c77eb32337c934cf631a Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Fri, 17 Nov 2017 12:31:11 -0800 Subject: Input: palmas-pwrbutton - handle return value of platform_get_irq() platform_get_irq() can fail here and we must check its return value. Signed-off-by: Arvind Yadav Signed-off-by: Dmitry Torokhov --- drivers/input/misc/palmas-pwrbutton.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/input/misc/palmas-pwrbutton.c b/drivers/input/misc/palmas-pwrbutton.c index 1e1baed63929..f9b05cf09ff5 100644 --- a/drivers/input/misc/palmas-pwrbutton.c +++ b/drivers/input/misc/palmas-pwrbutton.c @@ -210,6 +210,11 @@ static int palmas_pwron_probe(struct platform_device *pdev) INIT_DELAYED_WORK(&pwron->input_work, palmas_power_button_work); pwron->irq = platform_get_irq(pdev, 0); + if (pwron->irq < 0) { + error = pwron->irq; + goto err_free_input; + } + error = request_threaded_irq(pwron->irq, NULL, pwron_irq, IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW | -- cgit From de609b56b8322be0cd242ae364dc49bad0dfa89d Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 9 Sep 2021 17:59:43 -0700 Subject: Input: ads7846 - add short-hand for spi->dev in probe() function This will make the code a bit more terse. No functional change intended. Signed-off-by: Daniel Mack Reviewed-by: Marco Felsch Link: https://lore.kernel.org/r/20210907200726.2034962-2-daniel@zonque.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 45 +++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index f113a27aeb1e..ce2e14816af5 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -1216,20 +1216,21 @@ static int ads7846_probe(struct spi_device *spi) { const struct ads7846_platform_data *pdata; struct ads7846 *ts; + struct device *dev = &spi->dev; struct ads7846_packet *packet; struct input_dev *input_dev; unsigned long irq_flags; int err; if (!spi->irq) { - dev_dbg(&spi->dev, "no IRQ?\n"); + dev_dbg(dev, "no IRQ?\n"); return -EINVAL; } /* don't exceed max specified sample rate */ if (spi->max_speed_hz > (125000 * SAMPLE_BITS)) { - dev_err(&spi->dev, "f(sample) %d KHz?\n", - (spi->max_speed_hz/SAMPLE_BITS)/1000); + dev_err(dev, "f(sample) %d KHz?\n", + (spi->max_speed_hz/SAMPLE_BITS)/1000); return -EINVAL; } @@ -1262,9 +1263,9 @@ static int ads7846_probe(struct spi_device *spi) mutex_init(&ts->lock); init_waitqueue_head(&ts->wait); - pdata = dev_get_platdata(&spi->dev); + pdata = dev_get_platdata(dev); if (!pdata) { - pdata = ads7846_probe_dt(&spi->dev); + pdata = ads7846_probe_dt(dev); if (IS_ERR(pdata)) { err = PTR_ERR(pdata); goto err_free_mem; @@ -1306,12 +1307,12 @@ static int ads7846_probe(struct spi_device *spi) ts->wait_for_sync = pdata->wait_for_sync ? : null_wait_for_sync; - snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev)); + snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev)); snprintf(ts->name, sizeof(ts->name), "ADS%d Touchscreen", ts->model); input_dev->name = ts->name; input_dev->phys = ts->phys; - input_dev->dev.parent = &spi->dev; + input_dev->dev.parent = dev; input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); @@ -1345,16 +1346,16 @@ static int ads7846_probe(struct spi_device *spi) ads7846_setup_spi_msg(ts, pdata); - ts->reg = regulator_get(&spi->dev, "vcc"); + ts->reg = regulator_get(dev, "vcc"); if (IS_ERR(ts->reg)) { err = PTR_ERR(ts->reg); - dev_err(&spi->dev, "unable to get regulator: %d\n", err); + dev_err(dev, "unable to get regulator: %d\n", err); goto err_free_gpio; } err = regulator_enable(ts->reg); if (err) { - dev_err(&spi->dev, "unable to enable regulator: %d\n", err); + dev_err(dev, "unable to enable regulator: %d\n", err); goto err_put_regulator; } @@ -1362,18 +1363,18 @@ static int ads7846_probe(struct spi_device *spi) irq_flags |= IRQF_ONESHOT; err = request_threaded_irq(spi->irq, ads7846_hard_irq, ads7846_irq, - irq_flags, spi->dev.driver->name, ts); + irq_flags, dev->driver->name, ts); if (err && !pdata->irq_flags) { - dev_info(&spi->dev, + dev_info(dev, "trying pin change workaround on irq %d\n", spi->irq); irq_flags |= IRQF_TRIGGER_RISING; err = request_threaded_irq(spi->irq, ads7846_hard_irq, ads7846_irq, - irq_flags, spi->dev.driver->name, ts); + irq_flags, dev->driver->name, ts); } if (err) { - dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); + dev_dbg(dev, "irq %d busy?\n", spi->irq); goto err_disable_regulator; } @@ -1381,18 +1382,18 @@ static int ads7846_probe(struct spi_device *spi) if (err) goto err_free_irq; - dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq); + dev_info(dev, "touchscreen, irq %d\n", spi->irq); /* * Take a first sample, leaving nPENIRQ active and vREF off; avoid * the touchscreen, in case it's not connected. */ if (ts->model == 7845) - ads7845_read12_ser(&spi->dev, PWRDOWN); + ads7845_read12_ser(dev, PWRDOWN); else - (void) ads7846_read12_ser(&spi->dev, READ_12BIT_SER(vaux)); + (void) ads7846_read12_ser(dev, READ_12BIT_SER(vaux)); - err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group); + err = sysfs_create_group(&dev->kobj, &ads784x_attr_group); if (err) goto err_remove_hwmon; @@ -1400,19 +1401,19 @@ static int ads7846_probe(struct spi_device *spi) if (err) goto err_remove_attr_group; - device_init_wakeup(&spi->dev, pdata->wakeup); + device_init_wakeup(dev, pdata->wakeup); /* * If device does not carry platform data we must have allocated it * when parsing DT data. */ - if (!dev_get_platdata(&spi->dev)) - devm_kfree(&spi->dev, (void *)pdata); + if (!dev_get_platdata(dev)) + devm_kfree(dev, (void *)pdata); return 0; err_remove_attr_group: - sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group); + sysfs_remove_group(&dev->kobj, &ads784x_attr_group); err_remove_hwmon: ads784x_hwmon_unregister(spi, ts); err_free_irq: -- cgit From 937f5d5ec642501d2dd3c91918685de30a932b34 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 9 Sep 2021 18:01:28 -0700 Subject: Input: ads7846 - remove custom filter handling functions from pdata The functions in the platform data struct to initialize, cleanup and apply custom filters are not in use by any mainline board. Remove support for them to pave the road for more cleanups to come. The enum was moved as it has no users outside of the driver code itself. Signed-off-by: Daniel Mack Reviewed-by: Marco Felsch Link: https://lore.kernel.org/r/20210907200726.2034962-3-daniel@zonque.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 25 ++++++++----------------- include/linux/spi/ads7846.h | 15 --------------- 2 files changed, 8 insertions(+), 32 deletions(-) diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index ce2e14816af5..b9c8496155b7 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -142,13 +142,18 @@ struct ads7846 { int (*filter)(void *data, int data_idx, int *val); void *filter_data; - void (*filter_cleanup)(void *data); int (*get_pendown_state)(void); int gpio_pendown; void (*wait_for_sync)(void); }; +enum ads7846_filter { + ADS7846_FILTER_OK, + ADS7846_FILTER_REPEAT, + ADS7846_FILTER_IGNORE, +}; + /* leave chip selected when we're done, for quicker re-select? */ #if 0 #define CS_CHANGE(xfer) ((xfer).cs_change = 1) @@ -1277,15 +1282,7 @@ static int ads7846_probe(struct spi_device *spi) ts->x_plate_ohms = pdata->x_plate_ohms ? : 400; ts->vref_mv = pdata->vref_mv; - if (pdata->filter != NULL) { - if (pdata->filter_init != NULL) { - err = pdata->filter_init(pdata, &ts->filter_data); - if (err < 0) - goto err_free_mem; - } - ts->filter = pdata->filter; - ts->filter_cleanup = pdata->filter_cleanup; - } else if (pdata->debounce_max) { + if (pdata->debounce_max) { ts->debounce_max = pdata->debounce_max; if (ts->debounce_max < 2) ts->debounce_max = 2; @@ -1299,7 +1296,7 @@ static int ads7846_probe(struct spi_device *spi) err = ads7846_setup_pendown(spi, ts, pdata); if (err) - goto err_cleanup_filter; + goto err_free_mem; if (pdata->penirq_recheck_delay_usecs) ts->penirq_recheck_delay_usecs = @@ -1425,9 +1422,6 @@ static int ads7846_probe(struct spi_device *spi) err_free_gpio: if (!ts->get_pendown_state) gpio_free(ts->gpio_pendown); - err_cleanup_filter: - if (ts->filter_cleanup) - ts->filter_cleanup(ts->filter_data); err_free_mem: input_free_device(input_dev); kfree(packet); @@ -1458,9 +1452,6 @@ static int ads7846_remove(struct spi_device *spi) gpio_free(ts->gpio_pendown); } - if (ts->filter_cleanup) - ts->filter_cleanup(ts->filter_data); - kfree(ts->packet); kfree(ts); diff --git a/include/linux/spi/ads7846.h b/include/linux/spi/ads7846.h index 1a5eaef3b7f2..d424c1aadf38 100644 --- a/include/linux/spi/ads7846.h +++ b/include/linux/spi/ads7846.h @@ -1,17 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* linux/spi/ads7846.h */ -/* Touchscreen characteristics vary between boards and models. The - * platform_data for the device's "struct device" holds this information. - * - * It's OK if the min/max values are zero. - */ -enum ads7846_filter { - ADS7846_FILTER_OK, - ADS7846_FILTER_REPEAT, - ADS7846_FILTER_IGNORE, -}; - struct ads7846_platform_data { u16 model; /* 7843, 7845, 7846, 7873. */ u16 vref_delay_usecs; /* 0 for external vref; etc */ @@ -51,10 +40,6 @@ struct ads7846_platform_data { int gpio_pendown_debounce; /* platform specific debounce time for * the gpio_pendown */ int (*get_pendown_state)(void); - int (*filter_init) (const struct ads7846_platform_data *pdata, - void **filter_data); - int (*filter) (void *filter_data, int data_idx, int *val); - void (*filter_cleanup)(void *filter_data); void (*wait_for_sync)(void); bool wakeup; unsigned long irq_flags; -- cgit From 845ef3a7ce5773638a8c5e9a6e7be6538c107ae1 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 9 Sep 2021 18:03:01 -0700 Subject: Input: ads7846 - switch to devm initialization This simplies the code a lot and fixes some potential resource leaks in the error return paths. Signed-off-by: Daniel Mack Link: https://lore.kernel.org/r/20210907200726.2034962-4-daniel@zonque.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 136 +++++++++++++----------------------- 1 file changed, 47 insertions(+), 89 deletions(-) diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index b9c8496155b7..eaa8714ad19d 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -101,10 +101,6 @@ struct ads7846 { struct spi_device *spi; struct regulator *reg; -#if IS_ENABLED(CONFIG_HWMON) - struct device *hwmon; -#endif - u16 model; u16 vref_mv; u16 vref_delay_usecs; @@ -554,6 +550,8 @@ __ATTRIBUTE_GROUPS(ads7846_attr); static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts) { + struct device *hwmon; + /* hwmon sensors need a reference voltage */ switch (ts->model) { case 7846: @@ -574,17 +572,11 @@ static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts) break; } - ts->hwmon = hwmon_device_register_with_groups(&spi->dev, spi->modalias, - ts, ads7846_attr_groups); + hwmon = devm_hwmon_device_register_with_groups(&spi->dev, + spi->modalias, ts, + ads7846_attr_groups); - return PTR_ERR_OR_ZERO(ts->hwmon); -} - -static void ads784x_hwmon_unregister(struct spi_device *spi, - struct ads7846 *ts) -{ - if (ts->hwmon) - hwmon_device_unregister(ts->hwmon); + return PTR_ERR_OR_ZERO(hwmon); } #else @@ -593,11 +585,6 @@ static inline int ads784x_hwmon_register(struct spi_device *spi, { return 0; } - -static inline void ads784x_hwmon_unregister(struct spi_device *spi, - struct ads7846 *ts) -{ -} #endif static ssize_t ads7846_pen_down_show(struct device *dev, @@ -1019,8 +1006,8 @@ static int ads7846_setup_pendown(struct spi_device *spi, ts->get_pendown_state = pdata->get_pendown_state; } else if (gpio_is_valid(pdata->gpio_pendown)) { - err = gpio_request_one(pdata->gpio_pendown, GPIOF_IN, - "ads7846_pendown"); + err = devm_gpio_request_one(&spi->dev, pdata->gpio_pendown, + GPIOF_IN, "ads7846_pendown"); if (err) { dev_err(&spi->dev, "failed to request/setup pendown GPIO%d: %d\n", @@ -1217,6 +1204,11 @@ static const struct ads7846_platform_data *ads7846_probe_dt(struct device *dev) } #endif +static void ads7846_regulator_disable(void *regulator) +{ + regulator_disable(regulator); +} + static int ads7846_probe(struct spi_device *spi) { const struct ads7846_platform_data *pdata; @@ -1251,13 +1243,17 @@ static int ads7846_probe(struct spi_device *spi) if (err < 0) return err; - ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL); - packet = kzalloc(sizeof(struct ads7846_packet), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!ts || !packet || !input_dev) { - err = -ENOMEM; - goto err_free_mem; - } + ts = devm_kzalloc(dev, sizeof(struct ads7846), GFP_KERNEL); + if (!ts) + return -ENOMEM; + + packet = devm_kzalloc(dev, sizeof(struct ads7846_packet), GFP_KERNEL); + if (!packet) + return -ENOMEM; + + input_dev = devm_input_allocate_device(dev); + if (!input_dev) + return -ENOMEM; spi_set_drvdata(spi, ts); @@ -1271,10 +1267,8 @@ static int ads7846_probe(struct spi_device *spi) pdata = dev_get_platdata(dev); if (!pdata) { pdata = ads7846_probe_dt(dev); - if (IS_ERR(pdata)) { - err = PTR_ERR(pdata); - goto err_free_mem; - } + if (IS_ERR(pdata)) + return PTR_ERR(pdata); } ts->model = pdata->model ? : 7846; @@ -1296,7 +1290,7 @@ static int ads7846_probe(struct spi_device *spi) err = ads7846_setup_pendown(spi, ts, pdata); if (err) - goto err_free_mem; + return err; if (pdata->penirq_recheck_delay_usecs) ts->penirq_recheck_delay_usecs = @@ -1309,7 +1303,6 @@ static int ads7846_probe(struct spi_device *spi) input_dev->name = ts->name; input_dev->phys = ts->phys; - input_dev->dev.parent = dev; input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); @@ -1343,41 +1336,47 @@ static int ads7846_probe(struct spi_device *spi) ads7846_setup_spi_msg(ts, pdata); - ts->reg = regulator_get(dev, "vcc"); + ts->reg = devm_regulator_get(dev, "vcc"); if (IS_ERR(ts->reg)) { err = PTR_ERR(ts->reg); dev_err(dev, "unable to get regulator: %d\n", err); - goto err_free_gpio; + return err; } err = regulator_enable(ts->reg); if (err) { dev_err(dev, "unable to enable regulator: %d\n", err); - goto err_put_regulator; + return err; } + err = devm_add_action_or_reset(dev, ads7846_regulator_disable, ts->reg); + if (err) + return err; + irq_flags = pdata->irq_flags ? : IRQF_TRIGGER_FALLING; irq_flags |= IRQF_ONESHOT; - err = request_threaded_irq(spi->irq, ads7846_hard_irq, ads7846_irq, - irq_flags, dev->driver->name, ts); + err = devm_request_threaded_irq(dev, spi->irq, + ads7846_hard_irq, ads7846_irq, + irq_flags, dev->driver->name, ts); if (err && !pdata->irq_flags) { dev_info(dev, "trying pin change workaround on irq %d\n", spi->irq); irq_flags |= IRQF_TRIGGER_RISING; - err = request_threaded_irq(spi->irq, - ads7846_hard_irq, ads7846_irq, - irq_flags, dev->driver->name, ts); + err = devm_request_threaded_irq(dev, spi->irq, + ads7846_hard_irq, ads7846_irq, + irq_flags, dev->driver->name, + ts); } if (err) { dev_dbg(dev, "irq %d busy?\n", spi->irq); - goto err_disable_regulator; + return err; } err = ads784x_hwmon_register(spi, ts); if (err) - goto err_free_irq; + return err; dev_info(dev, "touchscreen, irq %d\n", spi->irq); @@ -1390,13 +1389,13 @@ static int ads7846_probe(struct spi_device *spi) else (void) ads7846_read12_ser(dev, READ_12BIT_SER(vaux)); - err = sysfs_create_group(&dev->kobj, &ads784x_attr_group); + err = devm_device_add_group(dev, &ads784x_attr_group); if (err) - goto err_remove_hwmon; + return err; err = input_register_device(input_dev); if (err) - goto err_remove_attr_group; + return err; device_init_wakeup(dev, pdata->wakeup); @@ -1408,54 +1407,13 @@ static int ads7846_probe(struct spi_device *spi) devm_kfree(dev, (void *)pdata); return 0; - - err_remove_attr_group: - sysfs_remove_group(&dev->kobj, &ads784x_attr_group); - err_remove_hwmon: - ads784x_hwmon_unregister(spi, ts); - err_free_irq: - free_irq(spi->irq, ts); - err_disable_regulator: - regulator_disable(ts->reg); - err_put_regulator: - regulator_put(ts->reg); - err_free_gpio: - if (!ts->get_pendown_state) - gpio_free(ts->gpio_pendown); - err_free_mem: - input_free_device(input_dev); - kfree(packet); - kfree(ts); - return err; } static int ads7846_remove(struct spi_device *spi) { struct ads7846 *ts = spi_get_drvdata(spi); - sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group); - - ads7846_disable(ts); - free_irq(ts->spi->irq, ts); - - input_unregister_device(ts->input); - - ads784x_hwmon_unregister(spi, ts); - - regulator_put(ts->reg); - - if (!ts->get_pendown_state) { - /* - * If we are not using specialized pendown method we must - * have been relying on gpio we set up ourselves. - */ - gpio_free(ts->gpio_pendown); - } - - kfree(ts->packet); - kfree(ts); - - dev_dbg(&spi->dev, "unregistered touchscreen\n"); + ads7846_stop(ts); return 0; } -- cgit From fcc28e0bfcfd2d98f2d096a185f0263759661c94 Mon Sep 17 00:00:00 2001 From: Yassine Oudjana Date: Thu, 9 Sep 2021 22:12:29 -0700 Subject: Input: cypress-sf - add Cypress StreetFighter touchkey driver This adds support for Cypress StreetFighter touchkey controllers such as sf3155. This driver supports managing regulators and generating input events. Due to lack of documentation, this driver is entirely based on information gathered from a driver written for an old Android kernel fork[1][2]. [1] https://github.com/LineageOS/android_kernel_xiaomi_msm8996/blob/lineage-18.1/drivers/input/touchscreen/cyttsp_button.c [2] https://github.com/LineageOS/android_kernel_xiaomi_msm8996/blob/lineage-18.1/arch/arm/boot/dts/qcom/a4-msm8996-mtp.dtsi#L291-L314 Signed-off-by: Yassine Oudjana Link: https://lore.kernel.org/r/20210907174341.422013-2-y.oudjana@protonmail.com Signed-off-by: Dmitry Torokhov --- MAINTAINERS | 6 + drivers/input/keyboard/Kconfig | 10 ++ drivers/input/keyboard/Makefile | 1 + drivers/input/keyboard/cypress-sf.c | 224 ++++++++++++++++++++++++++++++++++++ 4 files changed, 241 insertions(+) create mode 100644 drivers/input/keyboard/cypress-sf.c diff --git a/MAINTAINERS b/MAINTAINERS index b03c68cebe4c..f72af66b2889 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5006,6 +5006,12 @@ L: linux-input@vger.kernel.org S: Maintained F: drivers/input/touchscreen/cy8ctma140.c +CYPRESS STREETFIGHTER TOUCHKEYS DRIVER +M: Yassine Oudjana +L: linux-input@vger.kernel.org +S: Maintained +F: drivers/input/keyboard/cypress-sf.c + CYTTSP TOUCHSCREEN DRIVER M: Linus Walleij L: linux-input@vger.kernel.org diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 1b0afc8bf841..d3bf5c3f9add 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -791,4 +791,14 @@ config KEYBOARD_MTK_PMIC To compile this driver as a module, choose M here: the module will be called pmic-keys. +config KEYBOARD_CYPRESS_SF + tristate "Cypress StreetFighter touchkey support" + depends on I2C + help + Say Y here if you want to enable support for Cypress StreetFighter + touchkeys. + + To compile this driver as a module, choose M here: the + module will be called cypress-sf. + endif diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 1d689fdd5c00..e3c8648f834e 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_KEYBOARD_BCM) += bcm-keypad.o obj-$(CONFIG_KEYBOARD_CAP11XX) += cap11xx.o obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o +obj-$(CONFIG_KEYBOARD_CYPRESS_SF) += cypress-sf.o obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o obj-$(CONFIG_KEYBOARD_DLINK_DIR685) += dlink-dir685-touchkeys.o obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o diff --git a/drivers/input/keyboard/cypress-sf.c b/drivers/input/keyboard/cypress-sf.c new file mode 100644 index 000000000000..c28996028e80 --- /dev/null +++ b/drivers/input/keyboard/cypress-sf.c @@ -0,0 +1,224 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Cypress StreetFighter Touchkey Driver + * + * Copyright (c) 2021 Yassine Oudjana + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CYPRESS_SF_DEV_NAME "cypress-sf" + +#define CYPRESS_SF_REG_BUTTON_STATUS 0x4a + +struct cypress_sf_data { + struct i2c_client *client; + struct input_dev *input_dev; + struct regulator_bulk_data regulators[2]; + u32 *keycodes; + unsigned long keystates; + int num_keys; +}; + +static irqreturn_t cypress_sf_irq_handler(int irq, void *devid) +{ + struct cypress_sf_data *touchkey = devid; + unsigned long keystates, changed; + bool new_state; + int val, key; + + val = i2c_smbus_read_byte_data(touchkey->client, + CYPRESS_SF_REG_BUTTON_STATUS); + if (val < 0) { + dev_err(&touchkey->client->dev, + "Failed to read button status: %d", val); + return IRQ_NONE; + } + keystates = val; + + bitmap_xor(&changed, &keystates, &touchkey->keystates, + touchkey->num_keys); + + for_each_set_bit(key, &changed, touchkey->num_keys) { + new_state = keystates & BIT(key); + dev_dbg(&touchkey->client->dev, + "Key %d changed to %d", key, new_state); + input_report_key(touchkey->input_dev, + touchkey->keycodes[key], new_state); + } + + input_sync(touchkey->input_dev); + touchkey->keystates = keystates; + + return IRQ_HANDLED; +} + +static int cypress_sf_probe(struct i2c_client *client) +{ + struct cypress_sf_data *touchkey; + int key, error; + + touchkey = devm_kzalloc(&client->dev, sizeof(*touchkey), GFP_KERNEL); + if (!touchkey) + return -ENOMEM; + + touchkey->client = client; + i2c_set_clientdata(client, touchkey); + + touchkey->regulators[0].supply = "vdd"; + touchkey->regulators[1].supply = "avdd"; + + error = devm_regulator_bulk_get(&client->dev, + ARRAY_SIZE(touchkey->regulators), + touchkey->regulators); + if (error) { + dev_err(&client->dev, "Failed to get regulators: %d\n", error); + return error; + } + + touchkey->num_keys = device_property_read_u32_array(&client->dev, + "linux,keycodes", + NULL, 0); + if (touchkey->num_keys < 0) { + /* Default key count */ + touchkey->num_keys = 2; + } + + touchkey->keycodes = devm_kcalloc(&client->dev, + touchkey->num_keys, + sizeof(*touchkey->keycodes), + GFP_KERNEL); + if (!touchkey->keycodes) + return -ENOMEM; + + error = device_property_read_u32_array(&client->dev, "linux,keycodes", + touchkey->keycodes, + touchkey->num_keys); + + if (error) { + dev_warn(&client->dev, + "Failed to read keycodes: %d, using defaults\n", + error); + + /* Default keycodes */ + touchkey->keycodes[0] = KEY_BACK; + touchkey->keycodes[1] = KEY_MENU; + } + + error = regulator_bulk_enable(ARRAY_SIZE(touchkey->regulators), + touchkey->regulators); + if (error) { + dev_err(&client->dev, + "Failed to enable regulators: %d\n", error); + return error; + } + + touchkey->input_dev = devm_input_allocate_device(&client->dev); + if (!touchkey->input_dev) { + dev_err(&client->dev, "Failed to allocate input device\n"); + return -ENOMEM; + } + + touchkey->input_dev->name = CYPRESS_SF_DEV_NAME; + touchkey->input_dev->id.bustype = BUS_I2C; + + for (key = 0; key < touchkey->num_keys; ++key) + input_set_capability(touchkey->input_dev, + EV_KEY, touchkey->keycodes[key]); + + error = input_register_device(touchkey->input_dev); + if (error) { + dev_err(&client->dev, + "Failed to register input device: %d\n", error); + return error; + } + + error = devm_request_threaded_irq(&client->dev, client->irq, + NULL, cypress_sf_irq_handler, + IRQF_ONESHOT, + CYPRESS_SF_DEV_NAME, touchkey); + if (error) { + dev_err(&client->dev, + "Failed to register threaded irq: %d", error); + return error; + } + + return 0; +}; + +static int __maybe_unused cypress_sf_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct cypress_sf_data *touchkey = i2c_get_clientdata(client); + int error; + + disable_irq(client->irq); + + error = regulator_bulk_disable(ARRAY_SIZE(touchkey->regulators), + touchkey->regulators); + if (error) { + dev_err(dev, "Failed to disable regulators: %d", error); + enable_irq(client->irq); + return error; + } + + return 0; +} + +static int __maybe_unused cypress_sf_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct cypress_sf_data *touchkey = i2c_get_clientdata(client); + int error; + + error = regulator_bulk_enable(ARRAY_SIZE(touchkey->regulators), + touchkey->regulators); + if (error) { + dev_err(dev, "Failed to enable regulators: %d", error); + return error; + } + + enable_irq(client->irq); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(cypress_sf_pm_ops, + cypress_sf_suspend, cypress_sf_resume); + +static struct i2c_device_id cypress_sf_id_table[] = { + { CYPRESS_SF_DEV_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, cypress_sf_id_table); + +#ifdef CONFIG_OF +static const struct of_device_id cypress_sf_of_match[] = { + { .compatible = "cypress,sf3155", }, + { }, +}; +MODULE_DEVICE_TABLE(of, cypress_sf_of_match); +#endif + +static struct i2c_driver cypress_sf_driver = { + .driver = { + .name = CYPRESS_SF_DEV_NAME, + .pm = &cypress_sf_pm_ops, + .of_match_table = of_match_ptr(cypress_sf_of_match), + }, + .id_table = cypress_sf_id_table, + .probe_new = cypress_sf_probe, +}; +module_i2c_driver(cypress_sf_driver); + +MODULE_AUTHOR("Yassine Oudjana "); +MODULE_DESCRIPTION("Cypress StreetFighter Touchkey Driver"); +MODULE_LICENSE("GPL v2"); -- cgit From e2afe95a87a268bcdca2fb489d9c8a485e3aca85 Mon Sep 17 00:00:00 2001 From: Yassine Oudjana Date: Thu, 9 Sep 2021 22:23:39 -0700 Subject: dt-bindings: input: Add binding for cypress-sf Add a device tree binding for Cypress StreetFighter. Signed-off-by: Yassine Oudjana Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210907174341.422013-3-y.oudjana@protonmail.com Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/cypress-sf.yaml | 61 ++++++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 62 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/cypress-sf.yaml diff --git a/Documentation/devicetree/bindings/input/cypress-sf.yaml b/Documentation/devicetree/bindings/input/cypress-sf.yaml new file mode 100644 index 000000000000..c0b051466272 --- /dev/null +++ b/Documentation/devicetree/bindings/input/cypress-sf.yaml @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/cypress-sf.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Cypress StreetFighter touchkey controller + +maintainers: + - Yassine Oudjana + +allOf: + - $ref: input.yaml# + +properties: + compatible: + const: cypress,sf3155 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + avdd-supply: + description: Regulator for AVDD analog voltage + + vdd-supply: + description: Regulator for VDD digital voltage + + linux,keycodes: + minItems: 1 + maxItems: 8 + +required: + - compatible + - reg + - interrupts + - avdd-supply + - vdd-supply + +additionalProperties: false + +examples: + - | + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + touchkey@28 { + compatible = "cypress,sf3155"; + reg = <0x28>; + interrupt-parent = <&msmgpio>; + interrupts = <77 IRQ_TYPE_EDGE_FALLING>; + avdd-supply = <&vreg_l6a_1p8>; + vdd-supply = <&vdd_3v2_tp>; + linux,keycodes = ; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index f72af66b2889..44e6c428703e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5010,6 +5010,7 @@ CYPRESS STREETFIGHTER TOUCHKEYS DRIVER M: Yassine Oudjana L: linux-input@vger.kernel.org S: Maintained +F: Documentation/devicetree/bindings/input/cypress-sf.yaml F: drivers/input/keyboard/cypress-sf.c CYTTSP TOUCHSCREEN DRIVER -- cgit From ac5f313624d876b41d4a1292181d17e80d44159c Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Fri, 10 Jan 2020 21:15:26 +0800 Subject: coccinelle: semantic patch to check for inappropriate do_div() calls do_div() does a 64-by-32 division. When the divisor is unsigned long, u64, or s64, do_div() truncates it to 32 bits, this means it can test non-zero and be truncated to zero for division. This semantic patch is inspired by Mateusz Guzik's patch: commit b0ab99e7736a ("sched: Fix possible divide by zero in avg_atom() calculation") Signed-off-by: Wen Yang Signed-off-by: Julia Lawall Cc: Gilles Muller Cc: Nicolas Palix Cc: Michal Marek Cc: Matthias Maennich Cc: Greg Kroah-Hartman Cc: Masahiro Yamada Cc: Thomas Gleixner Cc: cocci@systeme.lip6.fr Cc: linux-kernel@vger.kernel.org --- scripts/coccinelle/misc/do_div.cocci | 155 +++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 scripts/coccinelle/misc/do_div.cocci diff --git a/scripts/coccinelle/misc/do_div.cocci b/scripts/coccinelle/misc/do_div.cocci new file mode 100644 index 000000000000..79db083c5208 --- /dev/null +++ b/scripts/coccinelle/misc/do_div.cocci @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: GPL-2.0-only +/// do_div() does a 64-by-32 division. +/// When the divisor is long, unsigned long, u64, or s64, +/// do_div() truncates it to 32 bits, this means it can test +/// non-zero and be truncated to 0 for division on 64bit platforms. +/// +//# This makes an effort to find those inappropriate do_div() calls. +// +// Confidence: Moderate +// Copyright: (C) 2020 Wen Yang, Alibaba. +// Comments: +// Options: --no-includes --include-headers + +virtual context +virtual org +virtual report + +@initialize:python@ +@@ + +def get_digit_type_and_value(str): + is_digit = False + value = 0 + + try: + if (str.isdigit()): + is_digit = True + value = int(str, 0) + elif (str.upper().endswith('ULL')): + is_digit = True + value = int(str[:-3], 0) + elif (str.upper().endswith('LL')): + is_digit = True + value = int(str[:-2], 0) + elif (str.upper().endswith('UL')): + is_digit = True + value = int(str[:-2], 0) + elif (str.upper().endswith('L')): + is_digit = True + value = int(str[:-1], 0) + elif (str.upper().endswith('U')): + is_digit = True + value = int(str[:-1], 0) + except Exception as e: + print('Error:',e) + is_digit = False + value = 0 + finally: + return is_digit, value + +def filter_out_safe_constants(str): + is_digit, value = get_digit_type_and_value(str) + if (is_digit): + if (value >= 0x100000000): + return True + else: + return False + else: + return True + +def construct_warnings(suggested_fun): + msg="WARNING: do_div() does a 64-by-32 division, please consider using %s instead." + return msg % suggested_fun + +@depends on context@ +expression f; +long l: script:python() { filter_out_safe_constants(l) }; +unsigned long ul : script:python() { filter_out_safe_constants(ul) }; +u64 ul64 : script:python() { filter_out_safe_constants(ul64) }; +s64 sl64 : script:python() { filter_out_safe_constants(sl64) }; + +@@ +( +* do_div(f, l); +| +* do_div(f, ul); +| +* do_div(f, ul64); +| +* do_div(f, sl64); +) + +@r depends on (org || report)@ +expression f; +position p; +long l: script:python() { filter_out_safe_constants(l) }; +unsigned long ul : script:python() { filter_out_safe_constants(ul) }; +u64 ul64 : script:python() { filter_out_safe_constants(ul64) }; +s64 sl64 : script:python() { filter_out_safe_constants(sl64) }; +@@ +( +do_div@p(f, l); +| +do_div@p(f, ul); +| +do_div@p(f, ul64); +| +do_div@p(f, sl64); +) + +@script:python depends on org@ +p << r.p; +ul << r.ul; +@@ + +coccilib.org.print_todo(p[0], construct_warnings("div64_ul")) + +@script:python depends on org@ +p << r.p; +l << r.l; +@@ + +coccilib.org.print_todo(p[0], construct_warnings("div64_long")) + +@script:python depends on org@ +p << r.p; +ul64 << r.ul64; +@@ + +coccilib.org.print_todo(p[0], construct_warnings("div64_u64")) + +@script:python depends on org@ +p << r.p; +sl64 << r.sl64; +@@ + +coccilib.org.print_todo(p[0], construct_warnings("div64_s64")) + +@script:python depends on report@ +p << r.p; +ul << r.ul; +@@ + +coccilib.report.print_report(p[0], construct_warnings("div64_ul")) + +@script:python depends on report@ +p << r.p; +l << r.l; +@@ + +coccilib.report.print_report(p[0], construct_warnings("div64_long")) + +@script:python depends on report@ +p << r.p; +sl64 << r.sl64; +@@ + +coccilib.report.print_report(p[0], construct_warnings("div64_s64")) + +@script:python depends on report@ +p << r.p; +ul64 << r.ul64; +@@ + +coccilib.report.print_report(p[0], construct_warnings("div64_u64")) -- cgit From 7629254054820bead6e18f8c3ae65c2bb01a5ae2 Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Thu, 5 Aug 2021 00:54:46 +0530 Subject: dt-bindings: at24: add ON Semi CAT24C04 and CAT24C05 Add bindings for ON Semi CAT24C04 and CAT24C05 eeproms, which are compatible with Atmel AT24C04. Signed-off-by: Raag Jadav Signed-off-by: Bartosz Golaszewski --- Documentation/devicetree/bindings/eeprom/at24.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/eeprom/at24.yaml b/Documentation/devicetree/bindings/eeprom/at24.yaml index 914a423ec449..4c5396a9744f 100644 --- a/Documentation/devicetree/bindings/eeprom/at24.yaml +++ b/Documentation/devicetree/bindings/eeprom/at24.yaml @@ -97,6 +97,12 @@ properties: - items: - const: nxp,se97b - const: atmel,24c02 + - items: + - const: onnn,cat24c04 + - const: atmel,24c04 + - items: + - const: onnn,cat24c05 + - const: atmel,24c04 - items: - const: renesas,r1ex24002 - const: atmel,24c02 -- cgit From 3ea046564039b7f20b3974adbea9271af64a4295 Mon Sep 17 00:00:00 2001 From: Johan Jonker Date: Sat, 28 Aug 2021 14:10:07 +0200 Subject: dt-bindings: gpio: add gpio-line-names to rockchip,gpio-bank.yaml Some people and companies may want to add more description to there gpio pins. Add a gpio-line-names property to the rockchip,gpio-bank.yaml file to reduce the notifications from the existing mainline DT. Signed-off-by: Johan Jonker Acked-by: Rob Herring Signed-off-by: Bartosz Golaszewski --- Documentation/devicetree/bindings/gpio/rockchip,gpio-bank.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/gpio/rockchip,gpio-bank.yaml b/Documentation/devicetree/bindings/gpio/rockchip,gpio-bank.yaml index 0d62c28fb58d..d4e42c2b995b 100644 --- a/Documentation/devicetree/bindings/gpio/rockchip,gpio-bank.yaml +++ b/Documentation/devicetree/bindings/gpio/rockchip,gpio-bank.yaml @@ -29,6 +29,8 @@ properties: gpio-controller: true + gpio-line-names: true + "#gpio-cells": const: 2 -- cgit From d4d47ba71df51ad737bc129e12ce40739fcd93d6 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 23 Aug 2021 16:51:19 -0700 Subject: remoteproc: qcom: wcnss: Drop unused smd include This include isn't used anymore because the smd functions have been moved to the qcom_common.c file. Signed-off-by: Stephen Boyd Link: https://lore.kernel.org/r/20210823235120.1203512-1-swboyd@chromium.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_wcnss.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c index ebadc6c08e11..80bbafee9846 100644 --- a/drivers/remoteproc/qcom_wcnss.c +++ b/drivers/remoteproc/qcom_wcnss.c @@ -25,7 +25,6 @@ #include #include #include -#include #include "qcom_common.h" #include "remoteproc_internal.h" -- cgit From fc1b6b6439588329ca3de77ca0c68c1b5bc3c7d0 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 23 Aug 2021 16:51:20 -0700 Subject: remoteproc: qcom: Loosen dependency on RPMSG_QCOM_SMD There doesn't seem to be any actual build time dependency on the RPMSG_QCOM_SMD, besides that these drivers should be a module if the smd rpmsg code is a module. Drop the compile test dependency so that these drivers can be used without RPMSG_QCOM_SMD being enabled. This is useful for the qcom SoCs that are using RPMSG_QCOM_GLINK_SMEM instead of RPMSG_QCOM_SMD and thus don't want to enable the SMD driver when it is never used. Signed-off-by: Stephen Boyd Link: https://lore.kernel.org/r/20210823235120.1203512-2-swboyd@chromium.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/Kconfig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 9a6eedc3994a..f30d00a3aabe 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -154,7 +154,7 @@ config QCOM_Q6V5_ADSP tristate "Qualcomm Technology Inc ADSP Peripheral Image Loader" depends on OF && ARCH_QCOM depends on QCOM_SMEM - depends on RPMSG_QCOM_SMD || (COMPILE_TEST && RPMSG_QCOM_SMD=n) + depends on RPMSG_QCOM_SMD || RPMSG_QCOM_SMD=n depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n depends on QCOM_SYSMON || QCOM_SYSMON=n depends on RPMSG_QCOM_GLINK || RPMSG_QCOM_GLINK=n @@ -173,7 +173,7 @@ config QCOM_Q6V5_MSS tristate "Qualcomm Hexagon V5 self-authenticating modem subsystem support" depends on OF && ARCH_QCOM depends on QCOM_SMEM - depends on RPMSG_QCOM_SMD || (COMPILE_TEST && RPMSG_QCOM_SMD=n) + depends on RPMSG_QCOM_SMD || RPMSG_QCOM_SMD=n depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n depends on QCOM_SYSMON || QCOM_SYSMON=n depends on RPMSG_QCOM_GLINK || RPMSG_QCOM_GLINK=n @@ -192,7 +192,7 @@ config QCOM_Q6V5_PAS tristate "Qualcomm Hexagon v5 Peripheral Authentication Service support" depends on OF && ARCH_QCOM depends on QCOM_SMEM - depends on RPMSG_QCOM_SMD || (COMPILE_TEST && RPMSG_QCOM_SMD=n) + depends on RPMSG_QCOM_SMD || RPMSG_QCOM_SMD=n depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n depends on QCOM_SYSMON || QCOM_SYSMON=n depends on RPMSG_QCOM_GLINK || RPMSG_QCOM_GLINK=n @@ -213,7 +213,7 @@ config QCOM_Q6V5_WCSS tristate "Qualcomm Hexagon based WCSS Peripheral Image Loader" depends on OF && ARCH_QCOM depends on QCOM_SMEM - depends on RPMSG_QCOM_SMD || (COMPILE_TEST && RPMSG_QCOM_SMD=n) + depends on RPMSG_QCOM_SMD || RPMSG_QCOM_SMD=n depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n depends on QCOM_SYSMON || QCOM_SYSMON=n depends on RPMSG_QCOM_GLINK || RPMSG_QCOM_GLINK=n @@ -246,7 +246,7 @@ config QCOM_SYSMON config QCOM_WCNSS_PIL tristate "Qualcomm WCNSS Peripheral Image Loader" depends on OF && ARCH_QCOM - depends on RPMSG_QCOM_SMD || (COMPILE_TEST && RPMSG_QCOM_SMD=n) + depends on RPMSG_QCOM_SMD || RPMSG_QCOM_SMD=n depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n depends on QCOM_SMEM depends on QCOM_SYSMON || QCOM_SYSMON=n -- cgit From 08de420a8014ed3fd83b2436f7e8bd9c4fcd9afe Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 17 Aug 2021 23:04:33 -0700 Subject: rpmsg: glink: Replace strncpy() with strscpy_pad() The use of strncpy() is considered deprecated for NUL-terminated strings[1]. Replace strncpy() with strscpy_pad() (as it seems this case expects the NUL padding to fill the allocation following the flexible array). This additionally silences a warning seen when building under -Warray-bounds: ./include/linux/fortify-string.h:38:30: warning: '__builtin_strncpy' offset 24 from the object at '__mptr' is out of the bounds of referenced subobject 'data' with type 'u8[]' {aka 'unsigned char[]'} at offset 24 [-Warray-bounds] 38 | #define __underlying_strncpy __builtin_strncpy | ^ ./include/linux/fortify-string.h:50:9: note: in expansion of macro '__underlying_strncpy' 50 | return __underlying_strncpy(p, q, size); | ^~~~~~~~~~~~~~~~~~~~ drivers/rpmsg/qcom_glink_native.c: In function 'qcom_glink_work': drivers/rpmsg/qcom_glink_native.c:36:5: note: subobject 'data' declared here 36 | u8 data[]; | ^~~~ [1] https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings Cc: Andy Gross Cc: Bjorn Andersson Cc: Ohad Ben-Cohen Cc: Mathieu Poirier Cc: linux-arm-msm@vger.kernel.org Cc: linux-remoteproc@vger.kernel.org Signed-off-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Link: https://lore.kernel.org/lkml/20210728020745.GB35706@embeddedor Link: https://lore.kernel.org/r/20210818060533.3569517-4-keescook@chromium.org Signed-off-by: Bjorn Andersson --- drivers/rpmsg/qcom_glink_native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 05533c71b10e..c7b9de655080 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1440,7 +1440,7 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid, } rpdev->ept = &channel->ept; - strncpy(rpdev->id.name, name, RPMSG_NAME_SIZE); + strscpy_pad(rpdev->id.name, name, RPMSG_NAME_SIZE); rpdev->src = RPMSG_ADDR_ANY; rpdev->dst = RPMSG_ADDR_ANY; rpdev->ops = &glink_device_ops; -- cgit From 537d3af1bee8ad1415fda9b622d1ea6d1ae76dfa Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Mon, 12 Jul 2021 14:39:12 +0200 Subject: rpmsg: Fix rpmsg_create_ept return when RPMSG config is not defined According to the description of the rpmsg_create_ept in rpmsg_core.c the function should return NULL on error. Fixes: 2c8a57088045 ("rpmsg: Provide function stubs for API") Signed-off-by: Arnaud Pouliquen Reviewed-by: Mathieu Poirier Link: https://lore.kernel.org/r/20210712123912.10672-1-arnaud.pouliquen@foss.st.com Signed-off-by: Bjorn Andersson --- include/linux/rpmsg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h index d97dcd049f18..a8dcf8a9ae88 100644 --- a/include/linux/rpmsg.h +++ b/include/linux/rpmsg.h @@ -231,7 +231,7 @@ static inline struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *rpdev /* This shouldn't be possible */ WARN_ON(1); - return ERR_PTR(-ENXIO); + return NULL; } static inline int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len) -- cgit From e80704272f5c3f80d315144b5eeaf867082c94ad Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Mon, 9 Aug 2021 13:25:09 +0200 Subject: kcsan: test: Defer kcsan_test_init() after kunit initialization When the test is built into the kernel (not a module), kcsan_test_init() and kunit_init() both use late_initcall(), which means kcsan_test_init() might see a NULL debugfs_rootdir as parent dentry, resulting in kcsan_test_init() and kcsan_debugfs_init() both trying to create a debugfs node named "kcsan" in debugfs root. One of them will show an error and be unsuccessful. Defer kcsan_test_init() until we're sure kunit was initialized. Signed-off-by: Marco Elver Signed-off-by: Paul E. McKenney --- kernel/kcsan/kcsan_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/kcsan/kcsan_test.c b/kernel/kcsan/kcsan_test.c index dc55fd5a36fc..df041bdb6088 100644 --- a/kernel/kcsan/kcsan_test.c +++ b/kernel/kcsan/kcsan_test.c @@ -1224,7 +1224,7 @@ static void kcsan_test_exit(void) tracepoint_synchronize_unregister(); } -late_initcall(kcsan_test_init); +late_initcall_sync(kcsan_test_init); module_exit(kcsan_test_exit); MODULE_LICENSE("GPL v2"); -- cgit From 80804284103ab95e1fe92f167af690ef4c9a6560 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Mon, 9 Aug 2021 13:25:10 +0200 Subject: kcsan: test: Use kunit_skip() to skip tests Use the new kunit_skip() to skip tests if requirements were not met. Signed-off-by: Marco Elver Signed-off-by: Paul E. McKenney --- kernel/kcsan/kcsan_test.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/kernel/kcsan/kcsan_test.c b/kernel/kcsan/kcsan_test.c index df041bdb6088..d93f226327af 100644 --- a/kernel/kcsan/kcsan_test.c +++ b/kernel/kcsan/kcsan_test.c @@ -29,6 +29,11 @@ #include #include +#define KCSAN_TEST_REQUIRES(test, cond) do { \ + if (!(cond)) \ + kunit_skip((test), "Test requires: " #cond); \ +} while (0) + #ifdef CONFIG_CC_HAS_TSAN_COMPOUND_READ_BEFORE_WRITE #define __KCSAN_ACCESS_RW(alt) (KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_WRITE) #else @@ -642,8 +647,7 @@ static void test_read_plain_atomic_write(struct kunit *test) }; bool match_expect = false; - if (IS_ENABLED(CONFIG_KCSAN_IGNORE_ATOMICS)) - return; + KCSAN_TEST_REQUIRES(test, !IS_ENABLED(CONFIG_KCSAN_IGNORE_ATOMICS)); begin_test_checks(test_kernel_read, test_kernel_write_atomic); do { @@ -665,8 +669,7 @@ static void test_read_plain_atomic_rmw(struct kunit *test) }; bool match_expect = false; - if (IS_ENABLED(CONFIG_KCSAN_IGNORE_ATOMICS)) - return; + KCSAN_TEST_REQUIRES(test, !IS_ENABLED(CONFIG_KCSAN_IGNORE_ATOMICS)); begin_test_checks(test_kernel_read, test_kernel_atomic_rmw); do { -- cgit From ade3a58b2d40555701143930ead3d44d0b52ca9e Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Mon, 9 Aug 2021 13:25:11 +0200 Subject: kcsan: test: Fix flaky test case If CONFIG_KCSAN_REPORT_VALUE_CHANGE_ONLY=n, then we may also see data races between the writers only. If we get unlucky and never capture a read-write data race, but only the write-write data races, then the test_no_value_change* test cases may incorrectly fail. The second problem is that the initial value needs to be reset, as otherwise we might actually observe a value change at the start. Fix it by also looking for the write-write data races, and resetting the value to what will be written. Signed-off-by: Marco Elver Signed-off-by: Paul E. McKenney --- kernel/kcsan/kcsan_test.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/kernel/kcsan/kcsan_test.c b/kernel/kcsan/kcsan_test.c index d93f226327af..e282c1166373 100644 --- a/kernel/kcsan/kcsan_test.c +++ b/kernel/kcsan/kcsan_test.c @@ -493,17 +493,24 @@ static void test_concurrent_races(struct kunit *test) __no_kcsan static void test_novalue_change(struct kunit *test) { - const struct expect_report expect = { + const struct expect_report expect_rw = { .access = { { test_kernel_write_nochange, &test_var, sizeof(test_var), KCSAN_ACCESS_WRITE }, { test_kernel_read, &test_var, sizeof(test_var), 0 }, }, }; + const struct expect_report expect_ww = { + .access = { + { test_kernel_write_nochange, &test_var, sizeof(test_var), KCSAN_ACCESS_WRITE }, + { test_kernel_write_nochange, &test_var, sizeof(test_var), KCSAN_ACCESS_WRITE }, + }, + }; bool match_expect = false; + test_kernel_write_nochange(); /* Reset value. */ begin_test_checks(test_kernel_write_nochange, test_kernel_read); do { - match_expect = report_matches(&expect); + match_expect = report_matches(&expect_rw) || report_matches(&expect_ww); } while (!end_test_checks(match_expect)); if (IS_ENABLED(CONFIG_KCSAN_REPORT_VALUE_CHANGE_ONLY)) KUNIT_EXPECT_FALSE(test, match_expect); @@ -518,17 +525,24 @@ static void test_novalue_change(struct kunit *test) __no_kcsan static void test_novalue_change_exception(struct kunit *test) { - const struct expect_report expect = { + const struct expect_report expect_rw = { .access = { { test_kernel_write_nochange_rcu, &test_var, sizeof(test_var), KCSAN_ACCESS_WRITE }, { test_kernel_read, &test_var, sizeof(test_var), 0 }, }, }; + const struct expect_report expect_ww = { + .access = { + { test_kernel_write_nochange_rcu, &test_var, sizeof(test_var), KCSAN_ACCESS_WRITE }, + { test_kernel_write_nochange_rcu, &test_var, sizeof(test_var), KCSAN_ACCESS_WRITE }, + }, + }; bool match_expect = false; + test_kernel_write_nochange_rcu(); /* Reset value. */ begin_test_checks(test_kernel_write_nochange_rcu, test_kernel_read); do { - match_expect = report_matches(&expect); + match_expect = report_matches(&expect_rw) || report_matches(&expect_ww); } while (!end_test_checks(match_expect)); KUNIT_EXPECT_TRUE(test, match_expect); } -- cgit From 55a55fec5015b326235873b925a5882ac56ecaa2 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Mon, 9 Aug 2021 13:25:12 +0200 Subject: kcsan: Add ability to pass instruction pointer of access to reporting Add the ability to pass an explicitly set instruction pointer of access from check_access() all the way through to reporting. In preparation of using it in reporting. Signed-off-by: Marco Elver Signed-off-by: Paul E. McKenney --- kernel/kcsan/core.c | 55 ++++++++++++++++++++++++++++----------------------- kernel/kcsan/kcsan.h | 8 ++++---- kernel/kcsan/report.c | 20 ++++++++++--------- 3 files changed, 45 insertions(+), 38 deletions(-) diff --git a/kernel/kcsan/core.c b/kernel/kcsan/core.c index 76e67d1e02d4..bffd1d95addb 100644 --- a/kernel/kcsan/core.c +++ b/kernel/kcsan/core.c @@ -350,6 +350,7 @@ void kcsan_restore_irqtrace(struct task_struct *task) static noinline void kcsan_found_watchpoint(const volatile void *ptr, size_t size, int type, + unsigned long ip, atomic_long_t *watchpoint, long encoded_watchpoint) { @@ -396,7 +397,7 @@ static noinline void kcsan_found_watchpoint(const volatile void *ptr, if (consumed) { kcsan_save_irqtrace(current); - kcsan_report_set_info(ptr, size, type, watchpoint - watchpoints); + kcsan_report_set_info(ptr, size, type, ip, watchpoint - watchpoints); kcsan_restore_irqtrace(current); } else { /* @@ -416,7 +417,7 @@ static noinline void kcsan_found_watchpoint(const volatile void *ptr, } static noinline void -kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type) +kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type, unsigned long ip) { const bool is_write = (type & KCSAN_ACCESS_WRITE) != 0; const bool is_assert = (type & KCSAN_ACCESS_ASSERT) != 0; @@ -568,8 +569,8 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type) if (is_assert && value_change == KCSAN_VALUE_CHANGE_TRUE) atomic_long_inc(&kcsan_counters[KCSAN_COUNTER_ASSERT_FAILURES]); - kcsan_report_known_origin(ptr, size, type, value_change, - watchpoint - watchpoints, + kcsan_report_known_origin(ptr, size, type, ip, + value_change, watchpoint - watchpoints, old, new, access_mask); } else if (value_change == KCSAN_VALUE_CHANGE_TRUE) { /* Inferring a race, since the value should not have changed. */ @@ -578,8 +579,10 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type) if (is_assert) atomic_long_inc(&kcsan_counters[KCSAN_COUNTER_ASSERT_FAILURES]); - if (IS_ENABLED(CONFIG_KCSAN_REPORT_RACE_UNKNOWN_ORIGIN) || is_assert) - kcsan_report_unknown_origin(ptr, size, type, old, new, access_mask); + if (IS_ENABLED(CONFIG_KCSAN_REPORT_RACE_UNKNOWN_ORIGIN) || is_assert) { + kcsan_report_unknown_origin(ptr, size, type, ip, + old, new, access_mask); + } } /* @@ -596,8 +599,8 @@ out: user_access_restore(ua_flags); } -static __always_inline void check_access(const volatile void *ptr, size_t size, - int type) +static __always_inline void +check_access(const volatile void *ptr, size_t size, int type, unsigned long ip) { const bool is_write = (type & KCSAN_ACCESS_WRITE) != 0; atomic_long_t *watchpoint; @@ -625,13 +628,12 @@ static __always_inline void check_access(const volatile void *ptr, size_t size, */ if (unlikely(watchpoint != NULL)) - kcsan_found_watchpoint(ptr, size, type, watchpoint, - encoded_watchpoint); + kcsan_found_watchpoint(ptr, size, type, ip, watchpoint, encoded_watchpoint); else { struct kcsan_ctx *ctx = get_ctx(); /* Call only once in fast-path. */ if (unlikely(should_watch(ptr, size, type, ctx))) - kcsan_setup_watchpoint(ptr, size, type); + kcsan_setup_watchpoint(ptr, size, type, ip); else if (unlikely(ctx->scoped_accesses.prev)) kcsan_check_scoped_accesses(); } @@ -757,7 +759,7 @@ kcsan_begin_scoped_access(const volatile void *ptr, size_t size, int type, { struct kcsan_ctx *ctx = get_ctx(); - __kcsan_check_access(ptr, size, type); + check_access(ptr, size, type, _RET_IP_); ctx->disable_count++; /* Disable KCSAN, in case list debugging is on. */ @@ -802,7 +804,7 @@ EXPORT_SYMBOL(kcsan_end_scoped_access); void __kcsan_check_access(const volatile void *ptr, size_t size, int type) { - check_access(ptr, size, type); + check_access(ptr, size, type, _RET_IP_); } EXPORT_SYMBOL(__kcsan_check_access); @@ -823,7 +825,7 @@ EXPORT_SYMBOL(__kcsan_check_access); void __tsan_read##size(void *ptr); \ void __tsan_read##size(void *ptr) \ { \ - check_access(ptr, size, 0); \ + check_access(ptr, size, 0, _RET_IP_); \ } \ EXPORT_SYMBOL(__tsan_read##size); \ void __tsan_unaligned_read##size(void *ptr) \ @@ -832,7 +834,7 @@ EXPORT_SYMBOL(__kcsan_check_access); void __tsan_write##size(void *ptr); \ void __tsan_write##size(void *ptr) \ { \ - check_access(ptr, size, KCSAN_ACCESS_WRITE); \ + check_access(ptr, size, KCSAN_ACCESS_WRITE, _RET_IP_); \ } \ EXPORT_SYMBOL(__tsan_write##size); \ void __tsan_unaligned_write##size(void *ptr) \ @@ -842,7 +844,8 @@ EXPORT_SYMBOL(__kcsan_check_access); void __tsan_read_write##size(void *ptr) \ { \ check_access(ptr, size, \ - KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_WRITE); \ + KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_WRITE, \ + _RET_IP_); \ } \ EXPORT_SYMBOL(__tsan_read_write##size); \ void __tsan_unaligned_read_write##size(void *ptr) \ @@ -858,14 +861,14 @@ DEFINE_TSAN_READ_WRITE(16); void __tsan_read_range(void *ptr, size_t size); void __tsan_read_range(void *ptr, size_t size) { - check_access(ptr, size, 0); + check_access(ptr, size, 0, _RET_IP_); } EXPORT_SYMBOL(__tsan_read_range); void __tsan_write_range(void *ptr, size_t size); void __tsan_write_range(void *ptr, size_t size) { - check_access(ptr, size, KCSAN_ACCESS_WRITE); + check_access(ptr, size, KCSAN_ACCESS_WRITE, _RET_IP_); } EXPORT_SYMBOL(__tsan_write_range); @@ -886,7 +889,8 @@ EXPORT_SYMBOL(__tsan_write_range); IS_ALIGNED((unsigned long)ptr, size); \ if (IS_ENABLED(CONFIG_KCSAN_IGNORE_ATOMICS) && is_atomic) \ return; \ - check_access(ptr, size, is_atomic ? KCSAN_ACCESS_ATOMIC : 0); \ + check_access(ptr, size, is_atomic ? KCSAN_ACCESS_ATOMIC : 0, \ + _RET_IP_); \ } \ EXPORT_SYMBOL(__tsan_volatile_read##size); \ void __tsan_unaligned_volatile_read##size(void *ptr) \ @@ -901,7 +905,8 @@ EXPORT_SYMBOL(__tsan_write_range); return; \ check_access(ptr, size, \ KCSAN_ACCESS_WRITE | \ - (is_atomic ? KCSAN_ACCESS_ATOMIC : 0)); \ + (is_atomic ? KCSAN_ACCESS_ATOMIC : 0), \ + _RET_IP_); \ } \ EXPORT_SYMBOL(__tsan_volatile_write##size); \ void __tsan_unaligned_volatile_write##size(void *ptr) \ @@ -955,7 +960,7 @@ EXPORT_SYMBOL(__tsan_init); u##bits __tsan_atomic##bits##_load(const u##bits *ptr, int memorder) \ { \ if (!IS_ENABLED(CONFIG_KCSAN_IGNORE_ATOMICS)) { \ - check_access(ptr, bits / BITS_PER_BYTE, KCSAN_ACCESS_ATOMIC); \ + check_access(ptr, bits / BITS_PER_BYTE, KCSAN_ACCESS_ATOMIC, _RET_IP_); \ } \ return __atomic_load_n(ptr, memorder); \ } \ @@ -965,7 +970,7 @@ EXPORT_SYMBOL(__tsan_init); { \ if (!IS_ENABLED(CONFIG_KCSAN_IGNORE_ATOMICS)) { \ check_access(ptr, bits / BITS_PER_BYTE, \ - KCSAN_ACCESS_WRITE | KCSAN_ACCESS_ATOMIC); \ + KCSAN_ACCESS_WRITE | KCSAN_ACCESS_ATOMIC, _RET_IP_); \ } \ __atomic_store_n(ptr, v, memorder); \ } \ @@ -978,7 +983,7 @@ EXPORT_SYMBOL(__tsan_init); if (!IS_ENABLED(CONFIG_KCSAN_IGNORE_ATOMICS)) { \ check_access(ptr, bits / BITS_PER_BYTE, \ KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_WRITE | \ - KCSAN_ACCESS_ATOMIC); \ + KCSAN_ACCESS_ATOMIC, _RET_IP_); \ } \ return __atomic_##op##suffix(ptr, v, memorder); \ } \ @@ -1010,7 +1015,7 @@ EXPORT_SYMBOL(__tsan_init); if (!IS_ENABLED(CONFIG_KCSAN_IGNORE_ATOMICS)) { \ check_access(ptr, bits / BITS_PER_BYTE, \ KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_WRITE | \ - KCSAN_ACCESS_ATOMIC); \ + KCSAN_ACCESS_ATOMIC, _RET_IP_); \ } \ return __atomic_compare_exchange_n(ptr, exp, val, weak, mo, fail_mo); \ } \ @@ -1025,7 +1030,7 @@ EXPORT_SYMBOL(__tsan_init); if (!IS_ENABLED(CONFIG_KCSAN_IGNORE_ATOMICS)) { \ check_access(ptr, bits / BITS_PER_BYTE, \ KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_WRITE | \ - KCSAN_ACCESS_ATOMIC); \ + KCSAN_ACCESS_ATOMIC, _RET_IP_); \ } \ __atomic_compare_exchange_n(ptr, &exp, val, 0, mo, fail_mo); \ return exp; \ diff --git a/kernel/kcsan/kcsan.h b/kernel/kcsan/kcsan.h index f36e25c497ed..ae33c2a7f07e 100644 --- a/kernel/kcsan/kcsan.h +++ b/kernel/kcsan/kcsan.h @@ -121,7 +121,7 @@ enum kcsan_value_change { * to be consumed by the reporting thread. No report is printed yet. */ void kcsan_report_set_info(const volatile void *ptr, size_t size, int access_type, - int watchpoint_idx); + unsigned long ip, int watchpoint_idx); /* * The calling thread observed that the watchpoint it set up was hit and @@ -129,14 +129,14 @@ void kcsan_report_set_info(const volatile void *ptr, size_t size, int access_typ * thread. */ void kcsan_report_known_origin(const volatile void *ptr, size_t size, int access_type, - enum kcsan_value_change value_change, int watchpoint_idx, - u64 old, u64 new, u64 mask); + unsigned long ip, enum kcsan_value_change value_change, + int watchpoint_idx, u64 old, u64 new, u64 mask); /* * No other thread was observed to race with the access, but the data value * before and after the stall differs. Reports a race of "unknown origin". */ void kcsan_report_unknown_origin(const volatile void *ptr, size_t size, int access_type, - u64 old, u64 new, u64 mask); + unsigned long ip, u64 old, u64 new, u64 mask); #endif /* _KERNEL_KCSAN_KCSAN_H */ diff --git a/kernel/kcsan/report.c b/kernel/kcsan/report.c index 21137929d428..50c4119f5cc0 100644 --- a/kernel/kcsan/report.c +++ b/kernel/kcsan/report.c @@ -31,6 +31,7 @@ struct access_info { int access_type; int task_pid; int cpu_id; + unsigned long ip; }; /* @@ -576,21 +577,22 @@ discard: } static struct access_info prepare_access_info(const volatile void *ptr, size_t size, - int access_type) + int access_type, unsigned long ip) { return (struct access_info) { .ptr = ptr, .size = size, .access_type = access_type, .task_pid = in_task() ? task_pid_nr(current) : -1, - .cpu_id = raw_smp_processor_id() + .cpu_id = raw_smp_processor_id(), + .ip = ip, }; } void kcsan_report_set_info(const volatile void *ptr, size_t size, int access_type, - int watchpoint_idx) + unsigned long ip, int watchpoint_idx) { - const struct access_info ai = prepare_access_info(ptr, size, access_type); + const struct access_info ai = prepare_access_info(ptr, size, access_type, ip); unsigned long flags; kcsan_disable_current(); @@ -603,10 +605,10 @@ void kcsan_report_set_info(const volatile void *ptr, size_t size, int access_typ } void kcsan_report_known_origin(const volatile void *ptr, size_t size, int access_type, - enum kcsan_value_change value_change, int watchpoint_idx, - u64 old, u64 new, u64 mask) + unsigned long ip, enum kcsan_value_change value_change, + int watchpoint_idx, u64 old, u64 new, u64 mask) { - const struct access_info ai = prepare_access_info(ptr, size, access_type); + const struct access_info ai = prepare_access_info(ptr, size, access_type, ip); struct other_info *other_info = &other_infos[watchpoint_idx]; unsigned long flags = 0; @@ -637,9 +639,9 @@ out: } void kcsan_report_unknown_origin(const volatile void *ptr, size_t size, int access_type, - u64 old, u64 new, u64 mask) + unsigned long ip, u64 old, u64 new, u64 mask) { - const struct access_info ai = prepare_access_info(ptr, size, access_type); + const struct access_info ai = prepare_access_info(ptr, size, access_type, ip); unsigned long flags; kcsan_disable_current(); -- cgit From f4c87dbbef2638f6da6e29b5e998e3b1dcdb08ee Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Mon, 9 Aug 2021 13:25:13 +0200 Subject: kcsan: Save instruction pointer for scoped accesses Save the instruction pointer for scoped accesses, so that it becomes possible for the reporting code to construct more accurate stack traces that will show the start of the scope. Signed-off-by: Marco Elver Signed-off-by: Paul E. McKenney --- include/linux/kcsan-checks.h | 3 +++ kernel/kcsan/core.c | 12 +++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/include/linux/kcsan-checks.h b/include/linux/kcsan-checks.h index 9fd0ad80fef6..5f5965246877 100644 --- a/include/linux/kcsan-checks.h +++ b/include/linux/kcsan-checks.h @@ -100,9 +100,12 @@ void kcsan_set_access_mask(unsigned long mask); /* Scoped access information. */ struct kcsan_scoped_access { struct list_head list; + /* Access information. */ const volatile void *ptr; size_t size; int type; + /* Location where scoped access was set up. */ + unsigned long ip; }; /* * Automatically call kcsan_end_scoped_access() when kcsan_scoped_access goes diff --git a/kernel/kcsan/core.c b/kernel/kcsan/core.c index bffd1d95addb..8b20af541776 100644 --- a/kernel/kcsan/core.c +++ b/kernel/kcsan/core.c @@ -202,6 +202,9 @@ static __always_inline struct kcsan_ctx *get_ctx(void) return in_task() ? ¤t->kcsan_ctx : raw_cpu_ptr(&kcsan_cpu_ctx); } +static __always_inline void +check_access(const volatile void *ptr, size_t size, int type, unsigned long ip); + /* Check scoped accesses; never inline because this is a slow-path! */ static noinline void kcsan_check_scoped_accesses(void) { @@ -210,8 +213,10 @@ static noinline void kcsan_check_scoped_accesses(void) struct kcsan_scoped_access *scoped_access; ctx->scoped_accesses.prev = NULL; /* Avoid recursion. */ - list_for_each_entry(scoped_access, &ctx->scoped_accesses, list) - __kcsan_check_access(scoped_access->ptr, scoped_access->size, scoped_access->type); + list_for_each_entry(scoped_access, &ctx->scoped_accesses, list) { + check_access(scoped_access->ptr, scoped_access->size, + scoped_access->type, scoped_access->ip); + } ctx->scoped_accesses.prev = prev_save; } @@ -767,6 +772,7 @@ kcsan_begin_scoped_access(const volatile void *ptr, size_t size, int type, sa->ptr = ptr; sa->size = size; sa->type = type; + sa->ip = _RET_IP_; if (!ctx->scoped_accesses.prev) /* Lazy initialize list head. */ INIT_LIST_HEAD(&ctx->scoped_accesses); @@ -798,7 +804,7 @@ void kcsan_end_scoped_access(struct kcsan_scoped_access *sa) ctx->disable_count--; - __kcsan_check_access(sa->ptr, sa->size, sa->type); + check_access(sa->ptr, sa->size, sa->type, sa->ip); } EXPORT_SYMBOL(kcsan_end_scoped_access); -- cgit From 6c65eb75686fc2068c926a73c9c3631b5f0e4c9c Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Mon, 9 Aug 2021 13:25:14 +0200 Subject: kcsan: Start stack trace with explicit location if provided If an explicit access address is set, as is done for scoped accesses, always start the stack trace from that location. get_stack_skipnr() is changed into sanitize_stack_entries(), which if given an address, scans the stack trace for a matching function and then replaces that entry with the explicitly provided address. The previous reports for scoped accesses were all over the place, which could be quite confusing. We now always point at the start of the scope. Signed-off-by: Marco Elver Signed-off-by: Paul E. McKenney --- kernel/kcsan/kcsan_test.c | 19 +++++++++------- kernel/kcsan/report.c | 55 ++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 61 insertions(+), 13 deletions(-) diff --git a/kernel/kcsan/kcsan_test.c b/kernel/kcsan/kcsan_test.c index e282c1166373..a3b12429e1d3 100644 --- a/kernel/kcsan/kcsan_test.c +++ b/kernel/kcsan/kcsan_test.c @@ -338,7 +338,10 @@ static noinline void test_kernel_assert_bits_nochange(void) ASSERT_EXCLUSIVE_BITS(test_var, ~TEST_CHANGE_BITS); } -/* To check that scoped assertions do trigger anywhere in scope. */ +/* + * Scoped assertions do trigger anywhere in scope. However, the report should + * still only point at the start of the scope. + */ static noinline void test_enter_scope(void) { int x = 0; @@ -845,22 +848,22 @@ static void test_assert_exclusive_writer_scoped(struct kunit *test) { test_kernel_write_nochange, &test_var, sizeof(test_var), KCSAN_ACCESS_WRITE }, }, }; - const struct expect_report expect_anywhere = { + const struct expect_report expect_inscope = { .access = { { test_enter_scope, &test_var, sizeof(test_var), KCSAN_ACCESS_ASSERT | KCSAN_ACCESS_SCOPED }, { test_kernel_write_nochange, &test_var, sizeof(test_var), KCSAN_ACCESS_WRITE }, }, }; bool match_expect_start = false; - bool match_expect_anywhere = false; + bool match_expect_inscope = false; begin_test_checks(test_kernel_assert_writer_scoped, test_kernel_write_nochange); do { match_expect_start |= report_matches(&expect_start); - match_expect_anywhere |= report_matches(&expect_anywhere); - } while (!end_test_checks(match_expect_start && match_expect_anywhere)); + match_expect_inscope |= report_matches(&expect_inscope); + } while (!end_test_checks(match_expect_inscope)); KUNIT_EXPECT_TRUE(test, match_expect_start); - KUNIT_EXPECT_TRUE(test, match_expect_anywhere); + KUNIT_EXPECT_FALSE(test, match_expect_inscope); } __no_kcsan @@ -889,9 +892,9 @@ static void test_assert_exclusive_access_scoped(struct kunit *test) do { match_expect_start |= report_matches(&expect_start1) || report_matches(&expect_start2); match_expect_inscope |= report_matches(&expect_inscope); - } while (!end_test_checks(match_expect_start && match_expect_inscope)); + } while (!end_test_checks(match_expect_inscope)); KUNIT_EXPECT_TRUE(test, match_expect_start); - KUNIT_EXPECT_TRUE(test, match_expect_inscope); + KUNIT_EXPECT_FALSE(test, match_expect_inscope); } /* diff --git a/kernel/kcsan/report.c b/kernel/kcsan/report.c index 50c4119f5cc0..4849cde9db9b 100644 --- a/kernel/kcsan/report.c +++ b/kernel/kcsan/report.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -301,6 +302,48 @@ static int get_stack_skipnr(const unsigned long stack_entries[], int num_entries return skip; } +/* + * Skips to the first entry that matches the function of @ip, and then replaces + * that entry with @ip, returning the entries to skip. + */ +static int +replace_stack_entry(unsigned long stack_entries[], int num_entries, unsigned long ip) +{ + unsigned long symbolsize, offset; + unsigned long target_func; + int skip; + + if (kallsyms_lookup_size_offset(ip, &symbolsize, &offset)) + target_func = ip - offset; + else + goto fallback; + + for (skip = 0; skip < num_entries; ++skip) { + unsigned long func = stack_entries[skip]; + + if (!kallsyms_lookup_size_offset(func, &symbolsize, &offset)) + goto fallback; + func -= offset; + + if (func == target_func) { + stack_entries[skip] = ip; + return skip; + } + } + +fallback: + /* Should not happen; the resulting stack trace is likely misleading. */ + WARN_ONCE(1, "Cannot find frame for %pS in stack trace", (void *)ip); + return get_stack_skipnr(stack_entries, num_entries); +} + +static int +sanitize_stack_entries(unsigned long stack_entries[], int num_entries, unsigned long ip) +{ + return ip ? replace_stack_entry(stack_entries, num_entries, ip) : + get_stack_skipnr(stack_entries, num_entries); +} + /* Compares symbolized strings of addr1 and addr2. */ static int sym_strcmp(void *addr1, void *addr2) { @@ -328,12 +371,12 @@ static void print_verbose_info(struct task_struct *task) static void print_report(enum kcsan_value_change value_change, const struct access_info *ai, - const struct other_info *other_info, + struct other_info *other_info, u64 old, u64 new, u64 mask) { unsigned long stack_entries[NUM_STACK_ENTRIES] = { 0 }; int num_stack_entries = stack_trace_save(stack_entries, NUM_STACK_ENTRIES, 1); - int skipnr = get_stack_skipnr(stack_entries, num_stack_entries); + int skipnr = sanitize_stack_entries(stack_entries, num_stack_entries, ai->ip); unsigned long this_frame = stack_entries[skipnr]; unsigned long other_frame = 0; int other_skipnr = 0; /* silence uninit warnings */ @@ -345,8 +388,9 @@ static void print_report(enum kcsan_value_change value_change, return; if (other_info) { - other_skipnr = get_stack_skipnr(other_info->stack_entries, - other_info->num_stack_entries); + other_skipnr = sanitize_stack_entries(other_info->stack_entries, + other_info->num_stack_entries, + other_info->ai.ip); other_frame = other_info->stack_entries[other_skipnr]; /* @value_change is only known for the other thread */ @@ -585,7 +629,8 @@ static struct access_info prepare_access_info(const volatile void *ptr, size_t s .access_type = access_type, .task_pid = in_task() ? task_pid_nr(current) : -1, .cpu_id = raw_smp_processor_id(), - .ip = ip, + /* Only replace stack entry with @ip if scoped access. */ + .ip = (access_type & KCSAN_ACCESS_SCOPED) ? ip : 0, }; } -- cgit From d627c537c2585875bba071bbfa7cda20328f982b Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Mon, 9 Aug 2021 13:25:15 +0200 Subject: kcsan: Support reporting scoped read-write access type Support generating the string representation of scoped read-write accesses for completeness. They will become required in planned changes. Signed-off-by: Marco Elver Signed-off-by: Paul E. McKenney --- kernel/kcsan/kcsan_test.c | 8 +++++--- kernel/kcsan/report.c | 4 ++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/kernel/kcsan/kcsan_test.c b/kernel/kcsan/kcsan_test.c index a3b12429e1d3..660729238588 100644 --- a/kernel/kcsan/kcsan_test.c +++ b/kernel/kcsan/kcsan_test.c @@ -210,10 +210,12 @@ static bool report_matches(const struct expect_report *r) "read-write" : "write") : "read"); + const bool is_atomic = (ty & KCSAN_ACCESS_ATOMIC); + const bool is_scoped = (ty & KCSAN_ACCESS_SCOPED); const char *const access_type_aux = - (ty & KCSAN_ACCESS_ATOMIC) ? - " (marked)" : - ((ty & KCSAN_ACCESS_SCOPED) ? " (scoped)" : ""); + (is_atomic && is_scoped) ? " (marked, scoped)" + : (is_atomic ? " (marked)" + : (is_scoped ? " (scoped)" : "")); if (i == 1) { /* Access 2 */ diff --git a/kernel/kcsan/report.c b/kernel/kcsan/report.c index 4849cde9db9b..fc15077991c4 100644 --- a/kernel/kcsan/report.c +++ b/kernel/kcsan/report.c @@ -247,6 +247,10 @@ static const char *get_access_type(int type) return "write (scoped)"; case KCSAN_ACCESS_SCOPED | KCSAN_ACCESS_WRITE | KCSAN_ACCESS_ATOMIC: return "write (marked, scoped)"; + case KCSAN_ACCESS_SCOPED | KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_WRITE: + return "read-write (scoped)"; + case KCSAN_ACCESS_SCOPED | KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_WRITE | KCSAN_ACCESS_ATOMIC: + return "read-write (marked, scoped)"; default: BUG(); } -- cgit From 78c3d954e2b3c323d6ba0a7294a490fef43efc57 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Mon, 9 Aug 2021 13:25:16 +0200 Subject: kcsan: Move ctx to start of argument list It is clearer if ctx is at the start of the function argument list; it'll be more consistent when adding functions with varying arguments but all requiring ctx. No functional change intended. Signed-off-by: Marco Elver Signed-off-by: Paul E. McKenney --- kernel/kcsan/core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel/kcsan/core.c b/kernel/kcsan/core.c index 8b20af541776..4b84c8e7884b 100644 --- a/kernel/kcsan/core.c +++ b/kernel/kcsan/core.c @@ -222,7 +222,7 @@ static noinline void kcsan_check_scoped_accesses(void) /* Rules for generic atomic accesses. Called from fast-path. */ static __always_inline bool -is_atomic(const volatile void *ptr, size_t size, int type, struct kcsan_ctx *ctx) +is_atomic(struct kcsan_ctx *ctx, const volatile void *ptr, size_t size, int type) { if (type & KCSAN_ACCESS_ATOMIC) return true; @@ -259,7 +259,7 @@ is_atomic(const volatile void *ptr, size_t size, int type, struct kcsan_ctx *ctx } static __always_inline bool -should_watch(const volatile void *ptr, size_t size, int type, struct kcsan_ctx *ctx) +should_watch(struct kcsan_ctx *ctx, const volatile void *ptr, size_t size, int type) { /* * Never set up watchpoints when memory operations are atomic. @@ -268,7 +268,7 @@ should_watch(const volatile void *ptr, size_t size, int type, struct kcsan_ctx * * should not count towards skipped instructions, and (2) to actually * decrement kcsan_atomic_next for consecutive instruction stream. */ - if (is_atomic(ptr, size, type, ctx)) + if (is_atomic(ctx, ptr, size, type)) return false; if (this_cpu_dec_return(kcsan_skip) >= 0) @@ -637,7 +637,7 @@ check_access(const volatile void *ptr, size_t size, int type, unsigned long ip) else { struct kcsan_ctx *ctx = get_ctx(); /* Call only once in fast-path. */ - if (unlikely(should_watch(ptr, size, type, ctx))) + if (unlikely(should_watch(ctx, ptr, size, type))) kcsan_setup_watchpoint(ptr, size, type, ip); else if (unlikely(ctx->scoped_accesses.prev)) kcsan_check_scoped_accesses(); -- cgit From ac20e39e8d254da3f82b5ed2afc7bb1e804d32c9 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Fri, 13 Aug 2021 10:10:55 +0200 Subject: kcsan: selftest: Cleanup and add missing __init Make test_encode_decode() more readable and add missing __init. Signed-off-by: Marco Elver Signed-off-by: Paul E. McKenney --- kernel/kcsan/selftest.c | 72 +++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 42 deletions(-) diff --git a/kernel/kcsan/selftest.c b/kernel/kcsan/selftest.c index 7f29cb0f5e63..b4295a3892b7 100644 --- a/kernel/kcsan/selftest.c +++ b/kernel/kcsan/selftest.c @@ -18,7 +18,7 @@ #define ITERS_PER_TEST 2000 /* Test requirements. */ -static bool test_requires(void) +static bool __init test_requires(void) { /* random should be initialized for the below tests */ return prandom_u32() + prandom_u32() != 0; @@ -28,14 +28,18 @@ static bool test_requires(void) * Test watchpoint encode and decode: check that encoding some access's info, * and then subsequent decode preserves the access's info. */ -static bool test_encode_decode(void) +static bool __init test_encode_decode(void) { int i; for (i = 0; i < ITERS_PER_TEST; ++i) { size_t size = prandom_u32_max(MAX_ENCODABLE_SIZE) + 1; bool is_write = !!prandom_u32_max(2); + unsigned long verif_masked_addr; + long encoded_watchpoint; + bool verif_is_write; unsigned long addr; + size_t verif_size; prandom_bytes(&addr, sizeof(addr)); if (addr < PAGE_SIZE) @@ -44,53 +48,37 @@ static bool test_encode_decode(void) if (WARN_ON(!check_encodable(addr, size))) return false; - /* Encode and decode */ - { - const long encoded_watchpoint = - encode_watchpoint(addr, size, is_write); - unsigned long verif_masked_addr; - size_t verif_size; - bool verif_is_write; - - /* Check special watchpoints */ - if (WARN_ON(decode_watchpoint( - INVALID_WATCHPOINT, &verif_masked_addr, - &verif_size, &verif_is_write))) - return false; - if (WARN_ON(decode_watchpoint( - CONSUMED_WATCHPOINT, &verif_masked_addr, - &verif_size, &verif_is_write))) - return false; - - /* Check decoding watchpoint returns same data */ - if (WARN_ON(!decode_watchpoint( - encoded_watchpoint, &verif_masked_addr, - &verif_size, &verif_is_write))) - return false; - if (WARN_ON(verif_masked_addr != - (addr & WATCHPOINT_ADDR_MASK))) - goto fail; - if (WARN_ON(verif_size != size)) - goto fail; - if (WARN_ON(is_write != verif_is_write)) - goto fail; - - continue; -fail: - pr_err("%s fail: %s %zu bytes @ %lx -> encoded: %lx -> %s %zu bytes @ %lx\n", - __func__, is_write ? "write" : "read", size, - addr, encoded_watchpoint, - verif_is_write ? "write" : "read", verif_size, - verif_masked_addr); + encoded_watchpoint = encode_watchpoint(addr, size, is_write); + + /* Check special watchpoints */ + if (WARN_ON(decode_watchpoint(INVALID_WATCHPOINT, &verif_masked_addr, &verif_size, &verif_is_write))) return false; - } + if (WARN_ON(decode_watchpoint(CONSUMED_WATCHPOINT, &verif_masked_addr, &verif_size, &verif_is_write))) + return false; + + /* Check decoding watchpoint returns same data */ + if (WARN_ON(!decode_watchpoint(encoded_watchpoint, &verif_masked_addr, &verif_size, &verif_is_write))) + return false; + if (WARN_ON(verif_masked_addr != (addr & WATCHPOINT_ADDR_MASK))) + goto fail; + if (WARN_ON(verif_size != size)) + goto fail; + if (WARN_ON(is_write != verif_is_write)) + goto fail; + + continue; +fail: + pr_err("%s fail: %s %zu bytes @ %lx -> encoded: %lx -> %s %zu bytes @ %lx\n", + __func__, is_write ? "write" : "read", size, addr, encoded_watchpoint, + verif_is_write ? "write" : "read", verif_size, verif_masked_addr); + return false; } return true; } /* Test access matching function. */ -static bool test_matching_access(void) +static bool __init test_matching_access(void) { if (WARN_ON(!matching_access(10, 1, 10, 1))) return false; -- cgit From 4f6094f1663e2ed26a940f1842cdaa15c1dd649a Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Tue, 24 Aug 2021 18:00:56 +0800 Subject: scsi: hisi_sas: Use managed PCI functions Use managed PCI functions such as pcim_enable_device() and pcim_iomap_regions() to simplify exception handling code. Link: https://lore.kernel.org/r/1629799260-120116-2-git-send-email-john.garry@huawei.com Signed-off-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 3ab669dc806f..e3be5743e77b 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -518,6 +518,8 @@ struct hisi_sas_err_record_v3 { #define CHNL_INT_STS_INT2_MSK BIT(3) #define CHNL_WIDTH 4 +#define BAR_NO_V3_HW 5 + enum { DSM_FUNC_ERR_HANDLE_MSI = 0, }; @@ -4676,15 +4678,15 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct sas_ha_struct *sha; int rc, phy_nr, port_nr, i; - rc = pci_enable_device(pdev); + rc = pcim_enable_device(pdev); if (rc) goto err_out; pci_set_master(pdev); - rc = pci_request_regions(pdev, DRV_NAME); + rc = pcim_iomap_regions(pdev, 1 << BAR_NO_V3_HW, DRV_NAME); if (rc) - goto err_out_disable_device; + goto err_out; rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); if (rc) @@ -4692,20 +4694,20 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (rc) { dev_err(dev, "No usable DMA addressing method\n"); rc = -ENODEV; - goto err_out_regions; + goto err_out; } shost = hisi_sas_shost_alloc_pci(pdev); if (!shost) { rc = -ENOMEM; - goto err_out_regions; + goto err_out; } sha = SHOST_TO_SAS_HA(shost); hisi_hba = shost_priv(shost); dev_set_drvdata(dev, sha); - hisi_hba->regs = pcim_iomap(pdev, 5, 0); + hisi_hba->regs = pcim_iomap_table(pdev)[BAR_NO_V3_HW]; if (!hisi_hba->regs) { dev_err(dev, "cannot map register\n"); rc = -ENOMEM; @@ -4799,10 +4801,6 @@ err_out_debugfs: err_out_ha: hisi_sas_free(hisi_hba); scsi_host_put(shost); -err_out_regions: - pci_release_regions(pdev); -err_out_disable_device: - pci_disable_device(pdev); err_out: return rc; } @@ -4840,8 +4838,6 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev) sas_remove_host(sha->core.shost); hisi_sas_v3_destroy_irqs(pdev, hisi_hba); - pci_release_regions(pdev); - pci_disable_device(pdev); hisi_sas_free(hisi_hba); debugfs_exit_v3_hw(hisi_hba); scsi_host_put(shost); -- cgit From 089226ef6a084470f4665a68ad7eb48fb48db093 Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 24 Aug 2021 18:00:57 +0800 Subject: scsi: hisi_sas: Stop printing queue count in v3 hardware probe The number of hardware queues is available from sysfs. Remove the print in the v3 hardware probe function. Link: https://lore.kernel.org/r/1629799260-120116-3-git-send-email-john.garry@huawei.com Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index e3be5743e77b..f57d9f488a42 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -4762,7 +4762,7 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id) rc = interrupt_preinit_v3_hw(hisi_hba); if (rc) goto err_out_debugfs; - dev_err(dev, "%d hw queues\n", shost->nr_hw_queues); + rc = scsi_add_host(shost, dev); if (rc) goto err_out_free_irq_vectors; -- cgit From b5a9fa20e3bf59d89b5f48315a0c0c32963796ed Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Tue, 24 Aug 2021 18:00:58 +0800 Subject: scsi: hisi_sas: Rename HISI_SAS_{RESET -> RESETTING}_BIT HISI_SAS_RESET_BIT means that the controller is being reset, and so the name is a bit vague. Rename it to HISI_SAS_RESETTING_BIT. Link: https://lore.kernel.org/r/1629799260-120116-4-git-send-email-john.garry@huawei.com Signed-off-by: Luo Jiaxing Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 2 +- drivers/scsi/hisi_sas/hisi_sas_main.c | 12 ++++++------ drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 2 +- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 2 +- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 10 +++++----- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 436d174f2194..57be32ba0109 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -35,7 +35,7 @@ #define HISI_SAS_QUEUE_SLOTS 4096 #define HISI_SAS_MAX_ITCT_ENTRIES 1024 #define HISI_SAS_MAX_DEVICES HISI_SAS_MAX_ITCT_ENTRIES -#define HISI_SAS_RESET_BIT 0 +#define HISI_SAS_RESETTING_BIT 0 #define HISI_SAS_REJECT_CMD_BIT 1 #define HISI_SAS_PM_BIT 2 #define HISI_SAS_HW_FAULT_BIT 3 diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 9515c45affa5..fec4db46c76c 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -724,7 +724,7 @@ static int hisi_sas_init_device(struct domain_device *device) */ local_phy = sas_get_local_phy(device); if (!scsi_is_sas_phy_local(local_phy) && - !test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) { + !test_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags)) { unsigned long deadline = ata_deadline(jiffies, 20000); struct sata_device *sata_dev = &device->sata_dev; struct ata_host *ata_host = sata_dev->ata_host; @@ -1072,7 +1072,7 @@ static void hisi_sas_dev_gone(struct domain_device *device) sas_dev->device_id, sas_dev->dev_type); down(&hisi_hba->sem); - if (!test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) { + if (!test_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags)) { hisi_sas_internal_task_abort(hisi_hba, device, HISI_SAS_INT_ABT_DEV, 0, true); @@ -1576,7 +1576,7 @@ void hisi_sas_controller_reset_done(struct hisi_hba *hisi_hba) hisi_sas_reset_init_all_devices(hisi_hba); up(&hisi_hba->sem); scsi_unblock_requests(shost); - clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags); + clear_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags); hisi_sas_rescan_topology(hisi_hba, hisi_hba->phy_state); } @@ -1587,7 +1587,7 @@ static int hisi_sas_controller_prereset(struct hisi_hba *hisi_hba) if (!hisi_hba->hw->soft_reset) return -1; - if (test_and_set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) + if (test_and_set_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags)) return -1; if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct[0].itct) @@ -1611,7 +1611,7 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba) clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); up(&hisi_hba->sem); scsi_unblock_requests(shost); - clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags); + clear_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags); return rc; } @@ -2251,7 +2251,7 @@ void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy, } else { struct hisi_sas_port *port = phy->port; - if (test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags) || + if (test_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags) || phy->in_reset) { dev_info(dev, "ignore flutter phy%d down\n", phy_no); return; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index afe639994f3d..862f4e8b7eb5 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -1422,7 +1422,7 @@ static irqreturn_t int_bcast_v1_hw(int irq, void *p) goto end; } - if (!test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) + if (!test_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags)) sas_notify_port_event(sas_phy, PORTE_BROADCAST_RCVD, GFP_ATOMIC); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index b0b2361e63fe..a5fc79b3f732 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -2824,7 +2824,7 @@ static void phy_bcast_v2_hw(int phy_no, struct hisi_hba *hisi_hba) hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 1); bcast_status = hisi_sas_phy_read32(hisi_hba, phy_no, RX_PRIMS_STATUS); if ((bcast_status & RX_BCAST_CHG_MSK) && - !test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) + !test_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags)) sas_notify_port_event(sas_phy, PORTE_BROADCAST_RCVD, GFP_ATOMIC); hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index f57d9f488a42..b137e5619da1 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -1617,7 +1617,7 @@ static irqreturn_t phy_bcast_v3_hw(int phy_no, struct hisi_hba *hisi_hba) hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 1); bcast_status = hisi_sas_phy_read32(hisi_hba, phy_no, RX_PRIMS_STATUS); if ((bcast_status & RX_BCAST_CHG_MSK) && - !test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) + !test_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags)) sas_notify_port_event(sas_phy, PORTE_BROADCAST_RCVD, GFP_ATOMIC); hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, @@ -4851,7 +4851,7 @@ static void hisi_sas_reset_prepare_v3_hw(struct pci_dev *pdev) int rc; dev_info(dev, "FLR prepare\n"); - set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags); + set_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags); hisi_sas_controller_reset_prepare(hisi_hba); rc = disable_host_v3_hw(hisi_hba); @@ -4897,7 +4897,7 @@ static int _suspend_v3_hw(struct device *device) return -ENODEV; } - if (test_and_set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) + if (test_and_set_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags)) return -1; scsi_block_requests(shost); @@ -4908,7 +4908,7 @@ static int _suspend_v3_hw(struct device *device) if (rc) { dev_err(dev, "PM suspend: disable host failed rc=%d\n", rc); clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); - clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags); + clear_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags); scsi_unblock_requests(shost); return rc; } @@ -4947,7 +4947,7 @@ static int _resume_v3_hw(struct device *device) } phys_init_v3_hw(hisi_hba); sas_resume_ha(sha); - clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags); + clear_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags); return 0; } -- cgit From 080b4f976bf7a61ae082d5ae1d2cee83b097b63a Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Tue, 24 Aug 2021 18:00:59 +0800 Subject: scsi: hisi_sas: Replace del_timer() calls with del_timer_sync() Some usage of del_timer() in the driver is potentially unsafe. When running the sas_task->slow_task timer in hisi_sas_exec_internal_tmf_task(), execution may be blocked in function hisi_sas_task_exec(); so it is possible that the timer is running when the callback to disable the timer is running. This could be dangerous, as we immediately release resources which the timer callback uses after disabling the timer. The same situation may be found at other sites, such as _hisi_sas_internal_task_abort(). Change calls to del_timer() to del_timer_sync() as necessary, to ensure any timer has finished when disabling. Also remove calls to timer_pending() prior to del_timer() as it is not necessary. Link: https://lore.kernel.org/r/1629799260-120116-5-git-send-email-john.garry@huawei.com Signed-off-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 12 +++++------- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 6 +++--- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 3 +-- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index fec4db46c76c..bb1c8ef3a76f 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1171,7 +1171,7 @@ static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func, static void hisi_sas_task_done(struct sas_task *task) { - del_timer(&task->slow_task->timer); + del_timer_sync(&task->slow_task->timer); complete(&task->slow_task->completion); } @@ -1229,7 +1229,7 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device, res = hisi_sas_task_exec(task, GFP_KERNEL, 1, tmf); if (res) { - del_timer(&task->slow_task->timer); + del_timer_sync(&task->slow_task->timer); dev_err(dev, "abort tmf: executing internal task failed: %d\n", res); goto ex_err; @@ -1554,8 +1554,7 @@ void hisi_sas_controller_reset_prepare(struct hisi_hba *hisi_hba) scsi_block_requests(shost); hisi_hba->hw->wait_cmds_complete_timeout(hisi_hba, 100, 5000); - if (timer_pending(&hisi_hba->timer)) - del_timer_sync(&hisi_hba->timer); + del_timer_sync(&hisi_hba->timer); set_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); } @@ -2097,7 +2096,7 @@ _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, res = hisi_sas_internal_abort_task_exec(hisi_hba, sas_dev->device_id, task, abort_flag, tag, dq); if (res) { - del_timer(&task->slow_task->timer); + del_timer_sync(&task->slow_task->timer); dev_err(dev, "internal task abort: executing internal task failed: %d\n", res); goto exit; @@ -2769,8 +2768,7 @@ int hisi_sas_remove(struct platform_device *pdev) struct hisi_hba *hisi_hba = sha->lldd_ha; struct Scsi_Host *shost = sha->core.shost; - if (timer_pending(&hisi_hba->timer)) - del_timer(&hisi_hba->timer); + del_timer_sync(&hisi_hba->timer); sas_unregister_ha(sha); sas_remove_host(sha->core.shost); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index a5fc79b3f732..236cf65c2f97 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -2368,18 +2368,18 @@ static void slot_complete_v2_hw(struct hisi_hba *hisi_hba, case STAT_IO_COMPLETE: /* internal abort command complete */ ts->stat = TMF_RESP_FUNC_SUCC; - del_timer(&slot->internal_abort_timer); + del_timer_sync(&slot->internal_abort_timer); goto out; case STAT_IO_NO_DEVICE: ts->stat = TMF_RESP_FUNC_COMPLETE; - del_timer(&slot->internal_abort_timer); + del_timer_sync(&slot->internal_abort_timer); goto out; case STAT_IO_NOT_VALID: /* abort single io, controller don't find * the io need to abort */ ts->stat = TMF_RESP_FUNC_FAILED; - del_timer(&slot->internal_abort_timer); + del_timer_sync(&slot->internal_abort_timer); goto out; default: break; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index b137e5619da1..cbc6c2d86745 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -4830,8 +4830,7 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev) struct Scsi_Host *shost = sha->core.shost; pm_runtime_get_noresume(dev); - if (timer_pending(&hisi_hba->timer)) - del_timer(&hisi_hba->timer); + del_timer_sync(&hisi_hba->timer); sas_unregister_ha(sha); flush_workqueue(hisi_hba->wq); -- cgit From 9aec5ffa6e39926cff1a6b576c815a9cee90e259 Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Tue, 24 Aug 2021 18:01:00 +0800 Subject: scsi: hisi_sas: Increase debugfs_dump_index after dump is completed The hisi_hba debugfs_dump_index member should increased after a dump insertion completed, and not before it has started, so fix the code to do so. Link: https://lore.kernel.org/r/1629799260-120116-6-git-send-email-john.garry@huawei.com Signed-off-by: Luo Jiaxing Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index cbc6c2d86745..f4517f3eb922 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -3688,7 +3688,6 @@ static void debugfs_snapshot_regs_v3_hw(struct hisi_hba *hisi_hba) do_div(timestamp, NSEC_PER_MSEC); hisi_hba->debugfs_timestamp[debugfs_dump_index] = timestamp; - hisi_hba->debugfs_dump_index++; debugfs_snapshot_prepare_v3_hw(hisi_hba); @@ -3704,6 +3703,7 @@ static void debugfs_snapshot_regs_v3_hw(struct hisi_hba *hisi_hba) debugfs_create_files_v3_hw(hisi_hba); debugfs_snapshot_restore_v3_hw(hisi_hba); + hisi_hba->debugfs_dump_index++; } static ssize_t debugfs_trigger_dump_v3_hw_write(struct file *file, -- cgit From ce4fc333e599c19973455c9d8f6fbb1e7c140dc8 Mon Sep 17 00:00:00 2001 From: John Garry Date: Mon, 13 Sep 2021 18:51:36 +0800 Subject: scsi: libsas: Co-locate exports with symbols It is standard practice to co-locate export declarations with the symbol which is being exported. Or at least in the same file - see sas_phy_reset(). Modify libsas to follow this practice consistently. Link: https://lore.kernel.org/r/1631530296-32358-1-git-send-email-john.garry@huawei.com Reviewed-by: Jason Yan Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_init.c | 5 +++-- drivers/scsi/libsas/sas_scsi_host.c | 23 +++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index 80592f53017a..37cc92837fdf 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -147,6 +147,7 @@ Undo_phys: return error; } +EXPORT_SYMBOL_GPL(sas_register_ha); static void sas_disable_events(struct sas_ha_struct *sas_ha) { @@ -176,6 +177,7 @@ int sas_unregister_ha(struct sas_ha_struct *sas_ha) return 0; } +EXPORT_SYMBOL_GPL(sas_unregister_ha); static int sas_get_linkerrors(struct sas_phy *phy) { @@ -313,6 +315,7 @@ int sas_phy_reset(struct sas_phy *phy, int hard_reset) } return ret; } +EXPORT_SYMBOL_GPL(sas_phy_reset); int sas_set_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) @@ -659,5 +662,3 @@ MODULE_LICENSE("GPL v2"); module_init(sas_class_init); module_exit(sas_class_exit); -EXPORT_SYMBOL_GPL(sas_register_ha); -EXPORT_SYMBOL_GPL(sas_unregister_ha); diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 08ffb8788290..2bf37151623e 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -201,6 +201,7 @@ out_done: cmd->scsi_done(cmd); return 0; } +EXPORT_SYMBOL_GPL(sas_queuecommand); static void sas_eh_finish_cmd(struct scsi_cmnd *cmd) { @@ -511,6 +512,7 @@ int sas_eh_device_reset_handler(struct scsi_cmnd *cmd) return FAILED; } +EXPORT_SYMBOL_GPL(sas_eh_device_reset_handler); int sas_eh_target_reset_handler(struct scsi_cmnd *cmd) { @@ -532,6 +534,7 @@ int sas_eh_target_reset_handler(struct scsi_cmnd *cmd) return FAILED; } +EXPORT_SYMBOL_GPL(sas_eh_target_reset_handler); /* Try to reset a device */ static int try_to_reset_cmd_device(struct scsi_cmnd *cmd) @@ -790,6 +793,7 @@ int sas_ioctl(struct scsi_device *sdev, unsigned int cmd, void __user *arg) return -EINVAL; } +EXPORT_SYMBOL_GPL(sas_ioctl); struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy) { @@ -832,6 +836,7 @@ int sas_target_alloc(struct scsi_target *starget) starget->hostdata = found_dev; return 0; } +EXPORT_SYMBOL_GPL(sas_target_alloc); #define SAS_DEF_QD 256 @@ -860,6 +865,7 @@ int sas_slave_configure(struct scsi_device *scsi_dev) return 0; } +EXPORT_SYMBOL_GPL(sas_slave_configure); int sas_change_queue_depth(struct scsi_device *sdev, int depth) { @@ -872,6 +878,7 @@ int sas_change_queue_depth(struct scsi_device *sdev, int depth) depth = 1; return scsi_change_queue_depth(sdev, depth); } +EXPORT_SYMBOL_GPL(sas_change_queue_depth); int sas_bios_param(struct scsi_device *scsi_dev, struct block_device *bdev, @@ -884,6 +891,7 @@ int sas_bios_param(struct scsi_device *scsi_dev, return 0; } +EXPORT_SYMBOL_GPL(sas_bios_param); /* * Tell an upper layer that it needs to initiate an abort for a given task. @@ -910,6 +918,7 @@ void sas_task_abort(struct sas_task *task) else blk_abort_request(scsi_cmd_to_rq(sc)); } +EXPORT_SYMBOL_GPL(sas_task_abort); int sas_slave_alloc(struct scsi_device *sdev) { @@ -918,6 +927,7 @@ int sas_slave_alloc(struct scsi_device *sdev) return 0; } +EXPORT_SYMBOL_GPL(sas_slave_alloc); void sas_target_destroy(struct scsi_target *starget) { @@ -929,6 +939,7 @@ void sas_target_destroy(struct scsi_target *starget) starget->hostdata = NULL; sas_put_device(found_dev); } +EXPORT_SYMBOL_GPL(sas_target_destroy); #define SAS_STRING_ADDR_SIZE 16 @@ -956,15 +967,3 @@ out: } EXPORT_SYMBOL_GPL(sas_request_addr); -EXPORT_SYMBOL_GPL(sas_queuecommand); -EXPORT_SYMBOL_GPL(sas_target_alloc); -EXPORT_SYMBOL_GPL(sas_slave_configure); -EXPORT_SYMBOL_GPL(sas_change_queue_depth); -EXPORT_SYMBOL_GPL(sas_bios_param); -EXPORT_SYMBOL_GPL(sas_task_abort); -EXPORT_SYMBOL_GPL(sas_phy_reset); -EXPORT_SYMBOL_GPL(sas_eh_device_reset_handler); -EXPORT_SYMBOL_GPL(sas_eh_target_reset_handler); -EXPORT_SYMBOL_GPL(sas_slave_alloc); -EXPORT_SYMBOL_GPL(sas_target_destroy); -EXPORT_SYMBOL_GPL(sas_ioctl); -- cgit From e018f03d6ccbd9c3ce6a9fae4f582113f2a2906b Mon Sep 17 00:00:00 2001 From: Ding Hui Date: Sat, 11 Sep 2021 21:51:59 +0800 Subject: scsi: libiscsi: Move ehwait initialization to iscsi_session_setup() Commit ec29d0ac29be ("scsi: iscsi: Fix conn use after free during resets") moved member ehwait from 'conn' to 'session', but left the initialization of ehwait in iscsi_conn_setup(). Although a session can only have 1 conn currently, it is better to initialize ehwait in iscsi_session_setup() in case we implement handling multiple conns in the future. Link: https://lore.kernel.org/r/20210911135159.20543-1-dinghui@sangfor.com.cn Reviewed-by: Mike Christie Signed-off-by: Ding Hui Signed-off-by: Martin K. Petersen --- drivers/scsi/libiscsi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 4683c183e9d4..712a45368385 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -2947,6 +2947,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost, session->tmf_state = TMF_INITIAL; timer_setup(&session->tmf_timer, iscsi_tmf_timedout, 0); mutex_init(&session->eh_mutex); + init_waitqueue_head(&session->ehwait); spin_lock_init(&session->frwd_lock); spin_lock_init(&session->back_lock); @@ -3074,8 +3075,6 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size, goto login_task_data_alloc_fail; conn->login_task->data = conn->data = data; - init_waitqueue_head(&session->ehwait); - return cls_conn; login_task_data_alloc_fail: -- cgit From c119e7d00c916881913011e6f4c6ac349a41e4e2 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 23 Aug 2021 23:41:40 +0200 Subject: i2c: xiic: Fix broken locking on tx_msg The tx_msg is set from multiple places, sometimes without locking, which fall apart on any SMP system. Only ever access tx_msg inside the driver mutex. Signed-off-by: Marek Vasut Acked-by: Michal Simek Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xiic.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index bb93db98404e..50320dd32eea 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -170,7 +170,7 @@ struct xiic_i2c { #define xiic_tx_space(i2c) ((i2c)->tx_msg->len - (i2c)->tx_pos) #define xiic_rx_space(i2c) ((i2c)->rx_msg->len - (i2c)->rx_pos) -static int xiic_start_xfer(struct xiic_i2c *i2c); +static int xiic_start_xfer(struct xiic_i2c *i2c, struct i2c_msg *msgs, int num); static void __xiic_start_xfer(struct xiic_i2c *i2c); /* @@ -684,15 +684,25 @@ static void __xiic_start_xfer(struct xiic_i2c *i2c) } -static int xiic_start_xfer(struct xiic_i2c *i2c) +static int xiic_start_xfer(struct xiic_i2c *i2c, struct i2c_msg *msgs, int num) { int ret; + mutex_lock(&i2c->lock); + ret = xiic_busy(i2c); + if (ret) + goto out; + + i2c->tx_msg = msgs; + i2c->rx_msg = NULL; + i2c->nmsgs = num; + ret = xiic_reinit(i2c); if (!ret) __xiic_start_xfer(i2c); +out: mutex_unlock(&i2c->lock); return ret; @@ -710,14 +720,7 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) if (err < 0) return err; - err = xiic_busy(i2c); - if (err) - goto out; - - i2c->tx_msg = msgs; - i2c->nmsgs = num; - - err = xiic_start_xfer(i2c); + err = xiic_start_xfer(i2c, msgs, num); if (err < 0) { dev_err(adap->dev.parent, "Error xiic_start_xfer\n"); goto out; @@ -725,9 +728,11 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) || (i2c->state == STATE_DONE), HZ)) { + mutex_lock(&i2c->lock); err = (i2c->state == STATE_DONE) ? num : -EIO; goto out; } else { + mutex_lock(&i2c->lock); i2c->tx_msg = NULL; i2c->rx_msg = NULL; i2c->nmsgs = 0; @@ -735,6 +740,7 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) goto out; } out: + mutex_unlock(&i2c->lock); pm_runtime_mark_last_busy(i2c->dev); pm_runtime_put_autosuspend(i2c->dev); return err; -- cgit From 861dcffe1b9e986d254ea0d7e9f0a542bfc5ab11 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 23 Aug 2021 23:41:41 +0200 Subject: i2c: xiic: Drop broken interrupt handler The interrupt handler is missing locking when reading out registers and is racing with other threads which might access the driver. Drop it altogether, so that the threaded interrupt is always executed, as that one is already serialized by the driver mutex. This also allows dropping local_irq_save()/local_irq_restore() in xiic_start_recv(). Signed-off-by: Marek Vasut Acked-by: Michal Simek Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xiic.c | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 50320dd32eea..b13166e94d89 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -554,7 +554,6 @@ static void xiic_start_recv(struct xiic_i2c *i2c) { u8 rx_watermark; struct i2c_msg *msg = i2c->rx_msg = i2c->tx_msg; - unsigned long flags; /* Clear and enable Rx full interrupt. */ xiic_irq_clr_en(i2c, XIIC_INTR_RX_FULL_MASK | XIIC_INTR_TX_ERROR_MASK); @@ -570,7 +569,6 @@ static void xiic_start_recv(struct xiic_i2c *i2c) rx_watermark = IIC_RX_FIFO_DEPTH; xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, rx_watermark - 1); - local_irq_save(flags); if (!(msg->flags & I2C_M_NOSTART)) /* write the address */ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, @@ -580,7 +578,6 @@ static void xiic_start_recv(struct xiic_i2c *i2c) xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, msg->len | ((i2c->nmsgs == 1) ? XIIC_TX_DYN_STOP_MASK : 0)); - local_irq_restore(flags); if (i2c->nmsgs == 1) /* very last, enable bus not busy as well */ @@ -620,26 +617,6 @@ static void xiic_start_send(struct xiic_i2c *i2c) XIIC_INTR_BNB_MASK); } -static irqreturn_t xiic_isr(int irq, void *dev_id) -{ - struct xiic_i2c *i2c = dev_id; - u32 pend, isr, ier; - irqreturn_t ret = IRQ_NONE; - /* Do not processes a devices interrupts if the device has no - * interrupts pending - */ - - dev_dbg(i2c->adap.dev.parent, "%s entry\n", __func__); - - isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET); - ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET); - pend = isr & ier; - if (pend) - ret = IRQ_WAKE_THREAD; - - return ret; -} - static void __xiic_start_xfer(struct xiic_i2c *i2c) { int first = 1; @@ -818,7 +795,7 @@ static int xiic_i2c_probe(struct platform_device *pdev) pm_runtime_use_autosuspend(i2c->dev); pm_runtime_set_active(i2c->dev); pm_runtime_enable(i2c->dev); - ret = devm_request_threaded_irq(&pdev->dev, irq, xiic_isr, + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, xiic_process, IRQF_ONESHOT, pdev->name, i2c); -- cgit From 743e227a895923c37a333eb2ebf3e391f00c406d Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 23 Aug 2021 23:41:42 +0200 Subject: i2c: xiic: Defer xiic_wakeup() and __xiic_start_xfer() in xiic_process() The __xiic_start_xfer() manipulates the interrupt flags, xiic_wakeup() may result in return from xiic_xfer() early. Defer both to the end of the xiic_process() interrupt thread, so that they are executed after all the other interrupt bits handling completed and once it completely safe to perform changes to the interrupt bits in the hardware. Signed-off-by: Marek Vasut Acked-by: Michal Simek Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xiic.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index b13166e94d89..aecdeec57997 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -375,6 +375,9 @@ static irqreturn_t xiic_process(int irq, void *dev_id) struct xiic_i2c *i2c = dev_id; u32 pend, isr, ier; u32 clr = 0; + int xfer_more = 0; + int wakeup_req = 0; + int wakeup_code = 0; /* Get the interrupt Status from the IPIF. There is no clearing of * interrupts in the IPIF. Interrupts must be cleared at the source. @@ -411,10 +414,14 @@ static irqreturn_t xiic_process(int irq, void *dev_id) */ xiic_reinit(i2c); - if (i2c->rx_msg) - xiic_wakeup(i2c, STATE_ERROR); - if (i2c->tx_msg) - xiic_wakeup(i2c, STATE_ERROR); + if (i2c->rx_msg) { + wakeup_req = 1; + wakeup_code = STATE_ERROR; + } + if (i2c->tx_msg) { + wakeup_req = 1; + wakeup_code = STATE_ERROR; + } } if (pend & XIIC_INTR_RX_FULL_MASK) { /* Receive register/FIFO is full */ @@ -448,8 +455,7 @@ static irqreturn_t xiic_process(int irq, void *dev_id) i2c->tx_msg++; dev_dbg(i2c->adap.dev.parent, "%s will start next...\n", __func__); - - __xiic_start_xfer(i2c); + xfer_more = 1; } } } @@ -463,11 +469,13 @@ static irqreturn_t xiic_process(int irq, void *dev_id) if (!i2c->tx_msg) goto out; - if ((i2c->nmsgs == 1) && !i2c->rx_msg && - xiic_tx_space(i2c) == 0) - xiic_wakeup(i2c, STATE_DONE); + wakeup_req = 1; + + if (i2c->nmsgs == 1 && !i2c->rx_msg && + xiic_tx_space(i2c) == 0) + wakeup_code = STATE_DONE; else - xiic_wakeup(i2c, STATE_ERROR); + wakeup_code = STATE_ERROR; } if (pend & (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK)) { /* Transmit register/FIFO is empty or ½ empty */ @@ -491,7 +499,7 @@ static irqreturn_t xiic_process(int irq, void *dev_id) if (i2c->nmsgs > 1) { i2c->nmsgs--; i2c->tx_msg++; - __xiic_start_xfer(i2c); + xfer_more = 1; } else { xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK); @@ -509,6 +517,13 @@ out: dev_dbg(i2c->adap.dev.parent, "%s clr: 0x%x\n", __func__, clr); xiic_setreg32(i2c, XIIC_IISR_OFFSET, clr); + if (xfer_more) + __xiic_start_xfer(i2c); + if (wakeup_req) + xiic_wakeup(i2c, wakeup_code); + + WARN_ON(xfer_more && wakeup_req); + mutex_unlock(&i2c->lock); return IRQ_HANDLED; } -- cgit From fdacc3c7405d1fc33c1f2771699a4fc24551e480 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 23 Aug 2021 23:41:43 +0200 Subject: i2c: xiic: Switch from waitqueue to completion There will never be threads queueing up in the xiic_xmit(), use completion synchronization primitive to wait for the interrupt handler thread to complete instead as it is much better fit and there is no need to overload it for this purpose. Signed-off-by: Marek Vasut Acked-by: Michal Simek Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xiic.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index aecdeec57997..f7277629923f 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include @@ -48,7 +48,7 @@ enum xiic_endian { * struct xiic_i2c - Internal representation of the XIIC I2C bus * @dev: Pointer to device structure * @base: Memory base of the HW registers - * @wait: Wait queue for callers + * @completion: Completion for callers * @adap: Kernel adapter representation * @tx_msg: Messages from above to be sent * @lock: Mutual exclusion @@ -64,7 +64,7 @@ enum xiic_endian { struct xiic_i2c { struct device *dev; void __iomem *base; - wait_queue_head_t wait; + struct completion completion; struct i2c_adapter adap; struct i2c_msg *tx_msg; struct mutex lock; @@ -160,6 +160,9 @@ struct xiic_i2c { #define XIIC_PM_TIMEOUT 1000 /* ms */ /* timeout waiting for the controller to respond */ #define XIIC_I2C_TIMEOUT (msecs_to_jiffies(1000)) +/* timeout waiting for the controller finish transfers */ +#define XIIC_XFER_TIMEOUT (msecs_to_jiffies(10000)) + /* * The following constant is used for the device global interrupt enable * register, to enable all interrupts for the device, this is the only bit @@ -367,7 +370,7 @@ static void xiic_wakeup(struct xiic_i2c *i2c, int code) i2c->rx_msg = NULL; i2c->nmsgs = 0; i2c->state = code; - wake_up(&i2c->wait); + complete(&i2c->completion); } static irqreturn_t xiic_process(int irq, void *dev_id) @@ -689,6 +692,7 @@ static int xiic_start_xfer(struct xiic_i2c *i2c, struct i2c_msg *msgs, int num) i2c->tx_msg = msgs; i2c->rx_msg = NULL; i2c->nmsgs = num; + init_completion(&i2c->completion); ret = xiic_reinit(i2c); if (!ret) @@ -715,23 +719,23 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) err = xiic_start_xfer(i2c, msgs, num); if (err < 0) { dev_err(adap->dev.parent, "Error xiic_start_xfer\n"); - goto out; + return err; } - if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) || - (i2c->state == STATE_DONE), HZ)) { - mutex_lock(&i2c->lock); - err = (i2c->state == STATE_DONE) ? num : -EIO; - goto out; - } else { - mutex_lock(&i2c->lock); + err = wait_for_completion_timeout(&i2c->completion, XIIC_XFER_TIMEOUT); + mutex_lock(&i2c->lock); + if (err == 0) { /* Timeout */ i2c->tx_msg = NULL; i2c->rx_msg = NULL; i2c->nmsgs = 0; err = -ETIMEDOUT; - goto out; + } else if (err < 0) { /* Completion error */ + i2c->tx_msg = NULL; + i2c->rx_msg = NULL; + i2c->nmsgs = 0; + } else { + err = (i2c->state == STATE_DONE) ? num : -EIO; } -out: mutex_unlock(&i2c->lock); pm_runtime_mark_last_busy(i2c->dev); pm_runtime_put_autosuspend(i2c->dev); @@ -793,7 +797,6 @@ static int xiic_i2c_probe(struct platform_device *pdev) i2c->adap.dev.of_node = pdev->dev.of_node; mutex_init(&i2c->lock); - init_waitqueue_head(&i2c->wait); i2c->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(i2c->clk)) -- cgit From d12e4bbb190b9edb47b31511e624f2a90f35f443 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 23 Aug 2021 23:41:44 +0200 Subject: i2c: xiic: Only ever transfer single message Transferring multiple messages via XIIC suffers from strange interaction between the interrupt status/enable register flags. These flags are being reused in the hardware to indicate different things for read and write transfer, and doing multiple transactions becomes horribly complex. Just send a single transaction and reload the controller with another message once the transaction is done in the interrupt handler thread. Signed-off-by: Marek Vasut Acked-by: Michal Simek Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xiic.c | 44 ++++++++++--------------------------------- 1 file changed, 10 insertions(+), 34 deletions(-) diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index f7277629923f..6cd7830fe489 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -609,8 +609,6 @@ static void xiic_start_send(struct xiic_i2c *i2c) { struct i2c_msg *msg = i2c->tx_msg; - xiic_irq_clr(i2c, XIIC_INTR_TX_ERROR_MASK); - dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, len: %d", __func__, msg, msg->len); dev_dbg(i2c->adap.dev.parent, "%s entry, ISR: 0x%x, CR: 0x%x\n", @@ -628,16 +626,17 @@ static void xiic_start_send(struct xiic_i2c *i2c) xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data); } - xiic_fill_tx_fifo(i2c); - /* Clear any pending Tx empty, Tx Error and then enable them. */ xiic_irq_clr_en(i2c, XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_ERROR_MASK | - XIIC_INTR_BNB_MASK); + XIIC_INTR_BNB_MASK | + ((i2c->nmsgs > 1 || xiic_tx_space(i2c)) ? + XIIC_INTR_TX_HALF_MASK : 0)); + + xiic_fill_tx_fifo(i2c); } static void __xiic_start_xfer(struct xiic_i2c *i2c) { - int first = 1; int fifo_space = xiic_tx_fifo_space(i2c); dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, fifos space: %d\n", __func__, i2c->tx_msg, fifo_space); @@ -648,35 +647,12 @@ static void __xiic_start_xfer(struct xiic_i2c *i2c) i2c->rx_pos = 0; i2c->tx_pos = 0; i2c->state = STATE_START; - while ((fifo_space >= 2) && (first || (i2c->nmsgs > 1))) { - if (!first) { - i2c->nmsgs--; - i2c->tx_msg++; - i2c->tx_pos = 0; - } else - first = 0; - - if (i2c->tx_msg->flags & I2C_M_RD) { - /* we dont date putting several reads in the FIFO */ - xiic_start_recv(i2c); - return; - } else { - xiic_start_send(i2c); - if (xiic_tx_space(i2c) != 0) { - /* the message could not be completely sent */ - break; - } - } - - fifo_space = xiic_tx_fifo_space(i2c); + if (i2c->tx_msg->flags & I2C_M_RD) { + /* we dont date putting several reads in the FIFO */ + xiic_start_recv(i2c); + } else { + xiic_start_send(i2c); } - - /* there are more messages or the current one could not be completely - * put into the FIFO, also enable the half empty interrupt - */ - if (i2c->nmsgs > 1 || xiic_tx_space(i2c)) - xiic_irq_clr_en(i2c, XIIC_INTR_TX_HALF_MASK); - } static int xiic_start_xfer(struct xiic_i2c *i2c, struct i2c_msg *msgs, int num) -- cgit From 294b29f15469e90893c2b72a738a962ee02a12eb Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 23 Aug 2021 23:41:45 +0200 Subject: i2c: xiic: Fix RX IRQ busy check In case the XIIC does TX/RX transfer, make sure no other kernel thread can start another TX transfer at the same time. This could happen since the driver only checks tx_msg for being non-NULL and returns -EBUSY in that case, however it is necessary to check also rx_msg for the same. Signed-off-by: Marek Vasut Acked-by: Michal Simek Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xiic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 6cd7830fe489..eb789cfb9973 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -543,7 +543,7 @@ static int xiic_busy(struct xiic_i2c *i2c) int tries = 3; int err; - if (i2c->tx_msg) + if (i2c->tx_msg || i2c->rx_msg) return -EBUSY; /* In single master mode bus can only be busy, when in use by this -- cgit From 7962c2eddbfe7cce879acb06f9b4f205789e57b7 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Mon, 13 Sep 2021 15:24:47 -0700 Subject: arch: remove unused function syscall_set_arguments() This function appears to have been unused since it was first introduced in commit 828c365cc8b8 ("tracehook: asm/syscall.h"). Signed-off-by: Peter Collingbourne Link: https://linux-review.googlesource.com/id/I8ce04f002903a37c0b6c1d16e9b2a3afa716c097 Signed-off-by: Arnd Bergmann --- arch/arm/include/asm/syscall.h | 10 ---------- arch/arm64/include/asm/syscall.h | 10 ---------- arch/csky/include/asm/syscall.h | 9 --------- arch/ia64/include/asm/syscall.h | 17 ++--------------- arch/ia64/kernel/ptrace.c | 31 ++++++++++++------------------- arch/microblaze/include/asm/syscall.h | 33 --------------------------------- arch/nds32/include/asm/syscall.h | 22 ---------------------- arch/nios2/include/asm/syscall.h | 11 ----------- arch/openrisc/include/asm/syscall.h | 7 ------- arch/powerpc/include/asm/syscall.h | 10 ---------- arch/riscv/include/asm/syscall.h | 9 --------- arch/s390/include/asm/syscall.h | 12 ------------ arch/sh/include/asm/syscall_32.h | 12 ------------ arch/sparc/include/asm/syscall.h | 10 ---------- arch/um/include/asm/syscall-generic.h | 14 -------------- arch/x86/include/asm/syscall.h | 33 --------------------------------- arch/xtensa/include/asm/syscall.h | 11 ----------- include/asm-generic/syscall.h | 16 ---------------- 18 files changed, 14 insertions(+), 263 deletions(-) diff --git a/arch/arm/include/asm/syscall.h b/arch/arm/include/asm/syscall.h index 24c19d63ff0a..dfeed440254a 100644 --- a/arch/arm/include/asm/syscall.h +++ b/arch/arm/include/asm/syscall.h @@ -77,16 +77,6 @@ static inline void syscall_get_arguments(struct task_struct *task, memcpy(args, ®s->ARM_r0 + 1, 5 * sizeof(args[0])); } -static inline void syscall_set_arguments(struct task_struct *task, - struct pt_regs *regs, - const unsigned long *args) -{ - regs->ARM_ORIG_r0 = args[0]; - args++; - - memcpy(®s->ARM_r0 + 1, args, 5 * sizeof(args[0])); -} - static inline int syscall_get_arch(struct task_struct *task) { /* ARM tasks don't change audit architectures on the fly. */ diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h index 03e20895453a..4cfe9b49709b 100644 --- a/arch/arm64/include/asm/syscall.h +++ b/arch/arm64/include/asm/syscall.h @@ -73,16 +73,6 @@ static inline void syscall_get_arguments(struct task_struct *task, memcpy(args, ®s->regs[1], 5 * sizeof(args[0])); } -static inline void syscall_set_arguments(struct task_struct *task, - struct pt_regs *regs, - const unsigned long *args) -{ - regs->orig_x0 = args[0]; - args++; - - memcpy(®s->regs[1], args, 5 * sizeof(args[0])); -} - /* * We don't care about endianness (__AUDIT_ARCH_LE bit) here because * AArch64 has the same system calls both on little- and big- endian. diff --git a/arch/csky/include/asm/syscall.h b/arch/csky/include/asm/syscall.h index f624fa3bbc22..0de5734950bf 100644 --- a/arch/csky/include/asm/syscall.h +++ b/arch/csky/include/asm/syscall.h @@ -59,15 +59,6 @@ syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, memcpy(args, ®s->a1, 5 * sizeof(args[0])); } -static inline void -syscall_set_arguments(struct task_struct *task, struct pt_regs *regs, - const unsigned long *args) -{ - regs->orig_a0 = args[0]; - args++; - memcpy(®s->a1, args, 5 * sizeof(regs->a1)); -} - static inline int syscall_get_arch(struct task_struct *task) { diff --git a/arch/ia64/include/asm/syscall.h b/arch/ia64/include/asm/syscall.h index 0d23c0049301..2b02a3fb862a 100644 --- a/arch/ia64/include/asm/syscall.h +++ b/arch/ia64/include/asm/syscall.h @@ -55,21 +55,8 @@ static inline void syscall_set_return_value(struct task_struct *task, } } -extern void ia64_syscall_get_set_arguments(struct task_struct *task, - struct pt_regs *regs, unsigned long *args, int rw); -static inline void syscall_get_arguments(struct task_struct *task, - struct pt_regs *regs, - unsigned long *args) -{ - ia64_syscall_get_set_arguments(task, regs, args, 0); -} - -static inline void syscall_set_arguments(struct task_struct *task, - struct pt_regs *regs, - unsigned long *args) -{ - ia64_syscall_get_set_arguments(task, regs, args, 1); -} +extern void syscall_get_arguments(struct task_struct *task, + struct pt_regs *regs, unsigned long *args); static inline int syscall_get_arch(struct task_struct *task) { diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index df28c7dd164f..6a1439eaa050 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -2001,17 +2001,16 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *tsk) return &user_ia64_view; } -struct syscall_get_set_args { +struct syscall_get_args { unsigned int i; unsigned int n; unsigned long *args; struct pt_regs *regs; - int rw; }; -static void syscall_get_set_args_cb(struct unw_frame_info *info, void *data) +static void syscall_get_args_cb(struct unw_frame_info *info, void *data) { - struct syscall_get_set_args *args = data; + struct syscall_get_args *args = data; struct pt_regs *pt = args->regs; unsigned long *krbs, cfm, ndirty, nlocals, nouts; int i, count; @@ -2042,37 +2041,31 @@ static void syscall_get_set_args_cb(struct unw_frame_info *info, void *data) /* Iterate over outs. */ for (i = 0; i < count; i++) { int j = ndirty + nlocals + i + args->i; - if (args->rw) - *ia64_rse_skip_regs(krbs, j) = args->args[i]; - else - args->args[i] = *ia64_rse_skip_regs(krbs, j); + args->args[i] = *ia64_rse_skip_regs(krbs, j); } - if (!args->rw) { - while (i < args->n) { - args->args[i] = 0; - i++; - } + while (i < args->n) { + args->args[i] = 0; + i++; } } -void ia64_syscall_get_set_arguments(struct task_struct *task, - struct pt_regs *regs, unsigned long *args, int rw) +void syscall_get_arguments(struct task_struct *task, + struct pt_regs *regs, unsigned long *args) { - struct syscall_get_set_args data = { + struct syscall_get_args data = { .i = 0, .n = 6, .args = args, .regs = regs, - .rw = rw, }; if (task == current) - unw_init_running(syscall_get_set_args_cb, &data); + unw_init_running(syscall_get_args_cb, &data); else { struct unw_frame_info ufi; memset(&ufi, 0, sizeof(ufi)); unw_init_from_blocked_task(&ufi, task); - syscall_get_set_args_cb(&ufi, &data); + syscall_get_args_cb(&ufi, &data); } } diff --git a/arch/microblaze/include/asm/syscall.h b/arch/microblaze/include/asm/syscall.h index 3a6924f3cbde..5eb3f624cc59 100644 --- a/arch/microblaze/include/asm/syscall.h +++ b/arch/microblaze/include/asm/syscall.h @@ -58,28 +58,6 @@ static inline microblaze_reg_t microblaze_get_syscall_arg(struct pt_regs *regs, return ~0; } -static inline void microblaze_set_syscall_arg(struct pt_regs *regs, - unsigned int n, - unsigned long val) -{ - switch (n) { - case 5: - regs->r10 = val; - case 4: - regs->r9 = val; - case 3: - regs->r8 = val; - case 2: - regs->r7 = val; - case 1: - regs->r6 = val; - case 0: - regs->r5 = val; - default: - BUG(); - } -} - static inline void syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, unsigned long *args) @@ -91,17 +69,6 @@ static inline void syscall_get_arguments(struct task_struct *task, *args++ = microblaze_get_syscall_arg(regs, i++); } -static inline void syscall_set_arguments(struct task_struct *task, - struct pt_regs *regs, - const unsigned long *args) -{ - unsigned int i = 0; - unsigned int n = 6; - - while (n--) - microblaze_set_syscall_arg(regs, i++, *args++); -} - asmlinkage unsigned long do_syscall_trace_enter(struct pt_regs *regs); asmlinkage void do_syscall_trace_leave(struct pt_regs *regs); diff --git a/arch/nds32/include/asm/syscall.h b/arch/nds32/include/asm/syscall.h index 7b5180d78e20..90aa56c94af1 100644 --- a/arch/nds32/include/asm/syscall.h +++ b/arch/nds32/include/asm/syscall.h @@ -132,28 +132,6 @@ syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, memcpy(args, ®s->uregs[0] + 1, 5 * sizeof(args[0])); } -/** - * syscall_set_arguments - change system call parameter value - * @task: task of interest, must be in system call entry tracing - * @regs: task_pt_regs() of @task - * @args: array of argument values to store - * - * Changes 6 arguments to the system call. The first argument gets value - * @args[0], and so on. - * - * It's only valid to call this when @task is stopped for tracing on - * entry to a system call, due to %TIF_SYSCALL_TRACE or %TIF_SYSCALL_AUDIT. - */ -static inline void -syscall_set_arguments(struct task_struct *task, struct pt_regs *regs, - const unsigned long *args) -{ - regs->orig_r0 = args[0]; - args++; - - memcpy(®s->uregs[0] + 1, args, 5 * sizeof(args[0])); -} - static inline int syscall_get_arch(struct task_struct *task) { diff --git a/arch/nios2/include/asm/syscall.h b/arch/nios2/include/asm/syscall.h index 526449edd768..fff52205fb65 100644 --- a/arch/nios2/include/asm/syscall.h +++ b/arch/nios2/include/asm/syscall.h @@ -58,17 +58,6 @@ static inline void syscall_get_arguments(struct task_struct *task, *args = regs->r9; } -static inline void syscall_set_arguments(struct task_struct *task, - struct pt_regs *regs, const unsigned long *args) -{ - regs->r4 = *args++; - regs->r5 = *args++; - regs->r6 = *args++; - regs->r7 = *args++; - regs->r8 = *args++; - regs->r9 = *args; -} - static inline int syscall_get_arch(struct task_struct *task) { return AUDIT_ARCH_NIOS2; diff --git a/arch/openrisc/include/asm/syscall.h b/arch/openrisc/include/asm/syscall.h index e6383be2a195..903ed882bdec 100644 --- a/arch/openrisc/include/asm/syscall.h +++ b/arch/openrisc/include/asm/syscall.h @@ -57,13 +57,6 @@ syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, memcpy(args, ®s->gpr[3], 6 * sizeof(args[0])); } -static inline void -syscall_set_arguments(struct task_struct *task, struct pt_regs *regs, - const unsigned long *args) -{ - memcpy(®s->gpr[3], args, 6 * sizeof(args[0])); -} - static inline int syscall_get_arch(struct task_struct *task) { return AUDIT_ARCH_OPENRISC; diff --git a/arch/powerpc/include/asm/syscall.h b/arch/powerpc/include/asm/syscall.h index c60ebd04b2ed..52d05b465e3e 100644 --- a/arch/powerpc/include/asm/syscall.h +++ b/arch/powerpc/include/asm/syscall.h @@ -103,16 +103,6 @@ static inline void syscall_get_arguments(struct task_struct *task, } } -static inline void syscall_set_arguments(struct task_struct *task, - struct pt_regs *regs, - const unsigned long *args) -{ - memcpy(®s->gpr[3], args, 6 * sizeof(args[0])); - - /* Also copy the first argument into orig_gpr3 */ - regs->orig_gpr3 = args[0]; -} - static inline int syscall_get_arch(struct task_struct *task) { if (is_32bit_task()) diff --git a/arch/riscv/include/asm/syscall.h b/arch/riscv/include/asm/syscall.h index b933b1583c9f..f8686ac98235 100644 --- a/arch/riscv/include/asm/syscall.h +++ b/arch/riscv/include/asm/syscall.h @@ -64,15 +64,6 @@ static inline void syscall_get_arguments(struct task_struct *task, memcpy(args, ®s->a1, 5 * sizeof(args[0])); } -static inline void syscall_set_arguments(struct task_struct *task, - struct pt_regs *regs, - const unsigned long *args) -{ - regs->orig_a0 = args[0]; - args++; - memcpy(®s->a1, args, 5 * sizeof(regs->a1)); -} - static inline int syscall_get_arch(struct task_struct *task) { #ifdef CONFIG_64BIT diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h index b3dd883699e7..27e3d804b311 100644 --- a/arch/s390/include/asm/syscall.h +++ b/arch/s390/include/asm/syscall.h @@ -78,18 +78,6 @@ static inline void syscall_get_arguments(struct task_struct *task, args[0] = regs->orig_gpr2 & mask; } -static inline void syscall_set_arguments(struct task_struct *task, - struct pt_regs *regs, - const unsigned long *args) -{ - unsigned int n = 6; - - while (n-- > 0) - if (n > 0) - regs->gprs[2 + n] = args[n]; - regs->orig_gpr2 = args[0]; -} - static inline int syscall_get_arch(struct task_struct *task) { #ifdef CONFIG_COMPAT diff --git a/arch/sh/include/asm/syscall_32.h b/arch/sh/include/asm/syscall_32.h index cb51a7528384..d87738eebe30 100644 --- a/arch/sh/include/asm/syscall_32.h +++ b/arch/sh/include/asm/syscall_32.h @@ -57,18 +57,6 @@ static inline void syscall_get_arguments(struct task_struct *task, args[0] = regs->regs[4]; } -static inline void syscall_set_arguments(struct task_struct *task, - struct pt_regs *regs, - const unsigned long *args) -{ - regs->regs[1] = args[5]; - regs->regs[0] = args[4]; - regs->regs[7] = args[3]; - regs->regs[6] = args[2]; - regs->regs[5] = args[1]; - regs->regs[4] = args[0]; -} - static inline int syscall_get_arch(struct task_struct *task) { int arch = AUDIT_ARCH_SH; diff --git a/arch/sparc/include/asm/syscall.h b/arch/sparc/include/asm/syscall.h index 62a5a78804c4..20c109ac8cc9 100644 --- a/arch/sparc/include/asm/syscall.h +++ b/arch/sparc/include/asm/syscall.h @@ -117,16 +117,6 @@ static inline void syscall_get_arguments(struct task_struct *task, } } -static inline void syscall_set_arguments(struct task_struct *task, - struct pt_regs *regs, - const unsigned long *args) -{ - unsigned int i; - - for (i = 0; i < 6; i++) - regs->u_regs[UREG_I0 + i] = args[i]; -} - static inline int syscall_get_arch(struct task_struct *task) { #if defined(CONFIG_SPARC64) && defined(CONFIG_COMPAT) diff --git a/arch/um/include/asm/syscall-generic.h b/arch/um/include/asm/syscall-generic.h index 2984feb9d576..172b74143c4b 100644 --- a/arch/um/include/asm/syscall-generic.h +++ b/arch/um/include/asm/syscall-generic.h @@ -62,20 +62,6 @@ static inline void syscall_get_arguments(struct task_struct *task, *args = UPT_SYSCALL_ARG6(r); } -static inline void syscall_set_arguments(struct task_struct *task, - struct pt_regs *regs, - const unsigned long *args) -{ - struct uml_pt_regs *r = ®s->regs; - - UPT_SYSCALL_ARG1(r) = *args++; - UPT_SYSCALL_ARG2(r) = *args++; - UPT_SYSCALL_ARG3(r) = *args++; - UPT_SYSCALL_ARG4(r) = *args++; - UPT_SYSCALL_ARG5(r) = *args++; - UPT_SYSCALL_ARG6(r) = *args; -} - /* See arch/x86/um/asm/syscall.h for syscall_get_arch() definition. */ #endif /* __UM_SYSCALL_GENERIC_H */ diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h index f7e2d82d24fb..5b85987a5e97 100644 --- a/arch/x86/include/asm/syscall.h +++ b/arch/x86/include/asm/syscall.h @@ -87,15 +87,6 @@ static inline void syscall_get_arguments(struct task_struct *task, memcpy(args, ®s->bx, 6 * sizeof(args[0])); } -static inline void syscall_set_arguments(struct task_struct *task, - struct pt_regs *regs, - unsigned int i, unsigned int n, - const unsigned long *args) -{ - BUG_ON(i + n > 6); - memcpy(®s->bx + i, args, n * sizeof(args[0])); -} - static inline int syscall_get_arch(struct task_struct *task) { return AUDIT_ARCH_I386; @@ -127,30 +118,6 @@ static inline void syscall_get_arguments(struct task_struct *task, } } -static inline void syscall_set_arguments(struct task_struct *task, - struct pt_regs *regs, - const unsigned long *args) -{ -# ifdef CONFIG_IA32_EMULATION - if (task->thread_info.status & TS_COMPAT) { - regs->bx = *args++; - regs->cx = *args++; - regs->dx = *args++; - regs->si = *args++; - regs->di = *args++; - regs->bp = *args; - } else -# endif - { - regs->di = *args++; - regs->si = *args++; - regs->dx = *args++; - regs->r10 = *args++; - regs->r8 = *args++; - regs->r9 = *args; - } -} - static inline int syscall_get_arch(struct task_struct *task) { /* x32 tasks should be considered AUDIT_ARCH_X86_64. */ diff --git a/arch/xtensa/include/asm/syscall.h b/arch/xtensa/include/asm/syscall.h index f9a671cbf933..5ee974bf8330 100644 --- a/arch/xtensa/include/asm/syscall.h +++ b/arch/xtensa/include/asm/syscall.h @@ -68,17 +68,6 @@ static inline void syscall_get_arguments(struct task_struct *task, args[i] = regs->areg[reg[i]]; } -static inline void syscall_set_arguments(struct task_struct *task, - struct pt_regs *regs, - const unsigned long *args) -{ - static const unsigned int reg[] = XTENSA_SYSCALL_ARGUMENT_REGS; - unsigned int i; - - for (i = 0; i < 6; ++i) - regs->areg[reg[i]] = args[i]; -} - asmlinkage long xtensa_rt_sigreturn(void); asmlinkage long xtensa_shmat(int, char __user *, int); asmlinkage long xtensa_fadvise64_64(int, int, diff --git a/include/asm-generic/syscall.h b/include/asm-generic/syscall.h index 524218ae3825..81695eb02a12 100644 --- a/include/asm-generic/syscall.h +++ b/include/asm-generic/syscall.h @@ -117,22 +117,6 @@ void syscall_set_return_value(struct task_struct *task, struct pt_regs *regs, void syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, unsigned long *args); -/** - * syscall_set_arguments - change system call parameter value - * @task: task of interest, must be in system call entry tracing - * @regs: task_pt_regs() of @task - * @args: array of argument values to store - * - * Changes 6 arguments to the system call. - * The first argument gets value @args[0], and so on. - * - * It's only valid to call this when @task is stopped for tracing on - * entry to a system call, due to %SYSCALL_WORK_SYSCALL_TRACE or - * %SYSCALL_WORK_SYSCALL_AUDIT. - */ -void syscall_set_arguments(struct task_struct *task, struct pt_regs *regs, - const unsigned long *args); - /** * syscall_get_arch - return the AUDIT_ARCH for the current system call * @task: task of interest, must be blocked -- cgit From a2aec2c86ef0cad0fd6be718cfeb5cf5eefbfca9 Mon Sep 17 00:00:00 2001 From: "GONG, Ruiqi" Date: Mon, 30 Aug 2021 16:33:56 +0800 Subject: mtd: Remove obsolete macros only used by the old nand_ecclayout struct All uses of MTD_MAX_{OOBFREE,ECCPOS}_ENTRIES_LARGE have been removed as commit ef5eeea6e911 ("mtd: nand: brcm: switch to mtd_ooblayout_ops") and commit aab616e31d1c ("mtd: kill the nand_ecclayout struct") replaced struct nand_ecclayout by the new mtd_ooblayout_ops interface. Remove these two macros therefore. Reported-by: Yi Yang Signed-off-by: GONG, Ruiqi Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210830083356.31702-1-gongruiqi1@huawei.com --- include/linux/mtd/mtd.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 88227044fc86..f5e7dfc2e4e9 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -72,8 +72,6 @@ struct mtd_oob_ops { uint8_t *oobbuf; }; -#define MTD_MAX_OOBFREE_ENTRIES_LARGE 32 -#define MTD_MAX_ECCPOS_ENTRIES_LARGE 640 /** * struct mtd_oob_region - oob region definition * @offset: region offset -- cgit From c606d4f77c8a637c0563a206b080c5663f72b61a Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 15:40:30 +0800 Subject: mtd: rawnand: atmel: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Reviewed-by: Nicolas Ferre Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210901074031.8883-1-caihuoqing@baidu.com --- drivers/mtd/nand/raw/atmel/pmecc.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/raw/atmel/pmecc.c b/drivers/mtd/nand/raw/atmel/pmecc.c index cbb023bf00f7..498e41ccabbd 100644 --- a/drivers/mtd/nand/raw/atmel/pmecc.c +++ b/drivers/mtd/nand/raw/atmel/pmecc.c @@ -834,7 +834,6 @@ static struct atmel_pmecc *atmel_pmecc_create(struct platform_device *pdev, { struct device *dev = &pdev->dev; struct atmel_pmecc *pmecc; - struct resource *res; pmecc = devm_kzalloc(dev, sizeof(*pmecc), GFP_KERNEL); if (!pmecc) @@ -844,13 +843,11 @@ static struct atmel_pmecc *atmel_pmecc_create(struct platform_device *pdev, pmecc->dev = dev; mutex_init(&pmecc->lock); - res = platform_get_resource(pdev, IORESOURCE_MEM, pmecc_res_idx); - pmecc->regs.base = devm_ioremap_resource(dev, res); + pmecc->regs.base = devm_platform_ioremap_resource(pdev, pmecc_res_idx); if (IS_ERR(pmecc->regs.base)) return ERR_CAST(pmecc->regs.base); - res = platform_get_resource(pdev, IORESOURCE_MEM, errloc_res_idx); - pmecc->regs.errloc = devm_ioremap_resource(dev, res); + pmecc->regs.errloc = devm_platform_ioremap_resource(pdev, errloc_res_idx); if (IS_ERR(pmecc->regs.errloc)) return ERR_CAST(pmecc->regs.errloc); -- cgit From df9e5170bc4d2d96a0c5dcfd3960c3e248a37218 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 15:40:38 +0800 Subject: mtd: rawnand: bcm6368: Make use of the helper function devm_platform_ioremap_resource_byname() Use the devm_platform_ioremap_resource_byname() helper instead of calling platform_get_resource_byname() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210901074108.8933-1-caihuoqing@baidu.com --- drivers/mtd/nand/raw/brcmnand/bcm6368_nand.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/mtd/nand/raw/brcmnand/bcm6368_nand.c b/drivers/mtd/nand/raw/brcmnand/bcm6368_nand.c index 7c17ec4ce8b6..a06cd87f839a 100644 --- a/drivers/mtd/nand/raw/brcmnand/bcm6368_nand.c +++ b/drivers/mtd/nand/raw/brcmnand/bcm6368_nand.c @@ -88,16 +88,13 @@ static int bcm6368_nand_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct bcm6368_nand_soc *priv; struct brcmnand_soc *soc; - struct resource *res; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; soc = &priv->soc; - res = platform_get_resource_byname(pdev, - IORESOURCE_MEM, "nand-int-base"); - priv->base = devm_ioremap_resource(dev, res); + priv->base = devm_platform_ioremap_resource_byname(pdev, "nand-int-base"); if (IS_ERR(priv->base)) return PTR_ERR(priv->base); -- cgit From 5f14a8ca1b493a3c633ff549fb7d494887d7804a Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 15:41:15 +0800 Subject: mtd: rawnand: denali: Make use of the helper function devm_platform_ioremap_resource_byname() Use the devm_platform_ioremap_resource_byname() helper instead of calling platform_get_resource_byname() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210901074116.8983-1-caihuoqing@baidu.com --- drivers/mtd/nand/raw/denali_dt.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/raw/denali_dt.c b/drivers/mtd/nand/raw/denali_dt.c index f08740ae282b..8513bb9fcfcc 100644 --- a/drivers/mtd/nand/raw/denali_dt.c +++ b/drivers/mtd/nand/raw/denali_dt.c @@ -113,7 +113,6 @@ static int denali_dt_chip_init(struct denali_controller *denali, static int denali_dt_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct resource *res; struct denali_dt *dt; const struct denali_dt_data *data; struct denali_controller *denali; @@ -139,13 +138,11 @@ static int denali_dt_probe(struct platform_device *pdev) if (denali->irq < 0) return denali->irq; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "denali_reg"); - denali->reg = devm_ioremap_resource(dev, res); + denali->reg = devm_platform_ioremap_resource_byname(pdev, "denali_reg"); if (IS_ERR(denali->reg)) return PTR_ERR(denali->reg); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data"); - denali->host = devm_ioremap_resource(dev, res); + denali->host = devm_platform_ioremap_resource_byname(pdev, "nand_data"); if (IS_ERR(denali->host)) return PTR_ERR(denali->host); -- cgit From 557de1cfabd6ea5476e5364a00d23d26bdfa3d4d Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 15:41:22 +0800 Subject: mtd: rawnand: gpio: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210901074123.9033-1-caihuoqing@baidu.com --- drivers/mtd/nand/raw/gpio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/gpio.c b/drivers/mtd/nand/raw/gpio.c index fb7a086de35e..8901c4aa0c21 100644 --- a/drivers/mtd/nand/raw/gpio.c +++ b/drivers/mtd/nand/raw/gpio.c @@ -303,8 +303,7 @@ static int gpio_nand_probe(struct platform_device *pdev) chip = &gpiomtd->nand_chip; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - gpiomtd->io = devm_ioremap_resource(dev, res); + gpiomtd->io = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(gpiomtd->io)) return PTR_ERR(gpiomtd->io); -- cgit From fe6b7a9f9159a3a55f5227e03c97f65b4d81dc71 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 15:41:30 +0800 Subject: mtd: rawnand: gpmi: Make use of the helper function devm_platform_ioremap_resource_byname() Use the devm_platform_ioremap_resource_byname() helper instead of calling platform_get_resource_byname() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210901074130.9083-1-caihuoqing@baidu.com --- drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c index 4d08e4ab5c1b..10cc71829dcb 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -951,11 +951,9 @@ static int acquire_register_block(struct gpmi_nand_data *this, { struct platform_device *pdev = this->pdev; struct resources *res = &this->resources; - struct resource *r; void __iomem *p; - r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name); - p = devm_ioremap_resource(&pdev->dev, r); + p = devm_platform_ioremap_resource_byname(pdev, res_name); if (IS_ERR(p)) return PTR_ERR(p); -- cgit From 1cda2633999a9431bc00d7881e2ea96cff5da22f Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 15:41:37 +0800 Subject: mtd: rawnand: hisi504: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210901074138.9133-1-caihuoqing@baidu.com --- drivers/mtd/nand/raw/hisi504_nand.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/raw/hisi504_nand.c b/drivers/mtd/nand/raw/hisi504_nand.c index 78c4e05434e2..c74f6b2192fc 100644 --- a/drivers/mtd/nand/raw/hisi504_nand.c +++ b/drivers/mtd/nand/raw/hisi504_nand.c @@ -738,7 +738,6 @@ static int hisi_nfc_probe(struct platform_device *pdev) struct hinfc_host *host; struct nand_chip *chip; struct mtd_info *mtd; - struct resource *res; struct device_node *np = dev->of_node; host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); @@ -754,13 +753,11 @@ static int hisi_nfc_probe(struct platform_device *pdev) if (irq < 0) return -ENXIO; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - host->iobase = devm_ioremap_resource(dev, res); + host->iobase = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(host->iobase)) return PTR_ERR(host->iobase); - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - host->mmio = devm_ioremap_resource(dev, res); + host->mmio = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(host->mmio)) return PTR_ERR(host->mmio); -- cgit From 5da7bb27a582b8f232c09dd1067eb7a254c4d4ee Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 15:41:44 +0800 Subject: mtd: rawnand: mtk: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210901074145.9183-1-caihuoqing@baidu.com --- drivers/mtd/nand/raw/mtk_nand.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c index 5c5c92132287..66f04c693c87 100644 --- a/drivers/mtd/nand/raw/mtk_nand.c +++ b/drivers/mtd/nand/raw/mtk_nand.c @@ -1520,7 +1520,6 @@ static int mtk_nfc_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct mtk_nfc *nfc; - struct resource *res; int ret, irq; nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL); @@ -1541,8 +1540,7 @@ static int mtk_nfc_probe(struct platform_device *pdev) nfc->caps = of_device_get_match_data(dev); nfc->dev = dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - nfc->regs = devm_ioremap_resource(dev, res); + nfc->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(nfc->regs)) { ret = PTR_ERR(nfc->regs); goto release_ecc; -- cgit From 8826e1107236d8668cfbcf8b31caea3ac943de1e Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 15:41:52 +0800 Subject: mtd: rawnand: mtk_ecc: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210901074153.9233-1-caihuoqing@baidu.com --- drivers/mtd/nand/raw/mtk_ecc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mtd/nand/raw/mtk_ecc.c b/drivers/mtd/nand/raw/mtk_ecc.c index c437d97debb8..1b47964cb6da 100644 --- a/drivers/mtd/nand/raw/mtk_ecc.c +++ b/drivers/mtd/nand/raw/mtk_ecc.c @@ -495,7 +495,6 @@ static int mtk_ecc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct mtk_ecc *ecc; - struct resource *res; u32 max_eccdata_size; int irq, ret; @@ -513,8 +512,7 @@ static int mtk_ecc_probe(struct platform_device *pdev) if (!ecc->eccdata) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ecc->regs = devm_ioremap_resource(dev, res); + ecc->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ecc->regs)) return PTR_ERR(ecc->regs); -- cgit From 7b7be21861819afcc0b82cd6f0fe5baef40374cd Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 15:41:59 +0800 Subject: mtd: rawnand: omap_elm: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210901074200.9283-1-caihuoqing@baidu.com --- drivers/mtd/nand/raw/omap_elm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/raw/omap_elm.c b/drivers/mtd/nand/raw/omap_elm.c index 2b21ce04b3ec..8bab753211e9 100644 --- a/drivers/mtd/nand/raw/omap_elm.c +++ b/drivers/mtd/nand/raw/omap_elm.c @@ -384,7 +384,7 @@ static irqreturn_t elm_isr(int this_irq, void *dev_id) static int elm_probe(struct platform_device *pdev) { int ret = 0; - struct resource *res, *irq; + struct resource *irq; struct elm_info *info; info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); @@ -399,8 +399,7 @@ static int elm_probe(struct platform_device *pdev) return -ENODEV; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - info->elm_base = devm_ioremap_resource(&pdev->dev, res); + info->elm_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(info->elm_base)) return PTR_ERR(info->elm_base); -- cgit From f47dca43c51f6d1fa0cc1574badc748724d9286c Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 15:42:07 +0800 Subject: mtd: rawnand: oxnas: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Reviewed-by: Neil Armstrong Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210901074207.9333-1-caihuoqing@baidu.com --- drivers/mtd/nand/raw/oxnas_nand.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mtd/nand/raw/oxnas_nand.c b/drivers/mtd/nand/raw/oxnas_nand.c index f44947043e5a..cd112d45e0b5 100644 --- a/drivers/mtd/nand/raw/oxnas_nand.c +++ b/drivers/mtd/nand/raw/oxnas_nand.c @@ -79,7 +79,6 @@ static int oxnas_nand_probe(struct platform_device *pdev) struct oxnas_nand_ctrl *oxnas; struct nand_chip *chip; struct mtd_info *mtd; - struct resource *res; int count = 0; int err = 0; int i; @@ -92,8 +91,7 @@ static int oxnas_nand_probe(struct platform_device *pdev) nand_controller_init(&oxnas->base); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - oxnas->io_base = devm_ioremap_resource(&pdev->dev, res); + oxnas->io_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(oxnas->io_base)) return PTR_ERR(oxnas->io_base); -- cgit From 7e2561430dff0a1bb9ab794e70fcaa56852e10f9 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 15:42:14 +0800 Subject: mtd: rawnand: plat_nand: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210901074215.9383-1-caihuoqing@baidu.com --- drivers/mtd/nand/raw/plat_nand.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mtd/nand/raw/plat_nand.c b/drivers/mtd/nand/raw/plat_nand.c index 7711e1020c21..c1b2072cb507 100644 --- a/drivers/mtd/nand/raw/plat_nand.c +++ b/drivers/mtd/nand/raw/plat_nand.c @@ -41,7 +41,6 @@ static int plat_nand_probe(struct platform_device *pdev) struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev); struct plat_nand_data *data; struct mtd_info *mtd; - struct resource *res; const char **part_types; int err = 0; @@ -65,8 +64,7 @@ static int plat_nand_probe(struct platform_device *pdev) nand_controller_init(&data->controller); data->chip.controller = &data->controller; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - data->io_base = devm_ioremap_resource(&pdev->dev, res); + data->io_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(data->io_base)) return PTR_ERR(data->io_base); -- cgit From 8d77c55f090def05f450df8aa6ee16ec6f4d01ba Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 15:42:22 +0800 Subject: mtd: rawnand: stm32_fmc2: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Reviewed-by: Christophe Kerello Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210901074222.9433-1-caihuoqing@baidu.com --- drivers/mtd/nand/raw/stm32_fmc2_nand.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c index 1c277fbb91f2..97b4e02e43e4 100644 --- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c +++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c @@ -1899,15 +1899,11 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev) nfc->data_phys_addr[chip_cs] = res->start; - res = platform_get_resource(pdev, IORESOURCE_MEM, - mem_region + 1); - nfc->cmd_base[chip_cs] = devm_ioremap_resource(dev, res); + nfc->cmd_base[chip_cs] = devm_platform_ioremap_resource(pdev, mem_region + 1); if (IS_ERR(nfc->cmd_base[chip_cs])) return PTR_ERR(nfc->cmd_base[chip_cs]); - res = platform_get_resource(pdev, IORESOURCE_MEM, - mem_region + 2); - nfc->addr_base[chip_cs] = devm_ioremap_resource(dev, res); + nfc->addr_base[chip_cs] = devm_platform_ioremap_resource(pdev, mem_region + 2); if (IS_ERR(nfc->addr_base[chip_cs])) return PTR_ERR(nfc->addr_base[chip_cs]); } -- cgit From 2f597bc45e47e245e30265de8494423c3a1a7900 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 15:42:29 +0800 Subject: mtd: rawnand: tegra: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Acked-by: Stefan Agner Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210901074230.9483-1-caihuoqing@baidu.com --- drivers/mtd/nand/raw/tegra_nand.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mtd/nand/raw/tegra_nand.c b/drivers/mtd/nand/raw/tegra_nand.c index fbf67722a049..32431bbe69b8 100644 --- a/drivers/mtd/nand/raw/tegra_nand.c +++ b/drivers/mtd/nand/raw/tegra_nand.c @@ -1144,7 +1144,6 @@ static int tegra_nand_probe(struct platform_device *pdev) { struct reset_control *rst; struct tegra_nand_controller *ctrl; - struct resource *res; int err = 0; ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL); @@ -1155,8 +1154,7 @@ static int tegra_nand_probe(struct platform_device *pdev) nand_controller_init(&ctrl->controller); ctrl->controller.ops = &tegra_nand_controller_ops; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ctrl->regs = devm_ioremap_resource(&pdev->dev, res); + ctrl->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ctrl->regs)) return PTR_ERR(ctrl->regs); -- cgit From 524bd02a6ff8c25a88077747020c1d0a7a94594b Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 15:42:37 +0800 Subject: mtd: rawnand: txx9ndfm: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210901074237.9533-1-caihuoqing@baidu.com --- drivers/mtd/nand/raw/txx9ndfmc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mtd/nand/raw/txx9ndfmc.c b/drivers/mtd/nand/raw/txx9ndfmc.c index b8894ac27073..b42d61b30c0b 100644 --- a/drivers/mtd/nand/raw/txx9ndfmc.c +++ b/drivers/mtd/nand/raw/txx9ndfmc.c @@ -284,13 +284,11 @@ static int __init txx9ndfmc_probe(struct platform_device *dev) int i; struct txx9ndfmc_drvdata *drvdata; unsigned long gbusclk = plat->gbus_clock; - struct resource *res; drvdata = devm_kzalloc(&dev->dev, sizeof(*drvdata), GFP_KERNEL); if (!drvdata) return -ENOMEM; - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - drvdata->base = devm_ioremap_resource(&dev->dev, res); + drvdata->base = devm_platform_ioremap_resource(dev, 0); if (IS_ERR(drvdata->base)) return PTR_ERR(drvdata->base); -- cgit From 2d77b08eaf0b2f269512c200c441bb1cda59d978 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 15:42:44 +0800 Subject: mtd: rawnand: vf610: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Acked-by: Stefan Agner Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210901074245.9583-1-caihuoqing@baidu.com --- drivers/mtd/nand/raw/vf610_nfc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c index 40d70f991d89..a2b89b75073f 100644 --- a/drivers/mtd/nand/raw/vf610_nfc.c +++ b/drivers/mtd/nand/raw/vf610_nfc.c @@ -807,7 +807,6 @@ static const struct nand_controller_ops vf610_nfc_controller_ops = { static int vf610_nfc_probe(struct platform_device *pdev) { struct vf610_nfc *nfc; - struct resource *res; struct mtd_info *mtd; struct nand_chip *chip; struct device_node *child; @@ -831,8 +830,7 @@ static int vf610_nfc_probe(struct platform_device *pdev) if (irq <= 0) return -EINVAL; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - nfc->regs = devm_ioremap_resource(nfc->dev, res); + nfc->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(nfc->regs)) return PTR_ERR(nfc->regs); -- cgit From abac656349cb9f081bc3b0a4c75d98486ade77f0 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 1 Sep 2021 15:42:51 +0800 Subject: mtd: rawnand: xway: Make use of the helper function devm_platform_ioremap_resource() Use the devm_platform_ioremap_resource() helper instead of calling platform_get_resource() and devm_ioremap_resource() separately Signed-off-by: Cai Huoqing Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210901074252.9633-1-caihuoqing@baidu.com --- drivers/mtd/nand/raw/xway_nand.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mtd/nand/raw/xway_nand.c b/drivers/mtd/nand/raw/xway_nand.c index 26751976e502..92067bd55384 100644 --- a/drivers/mtd/nand/raw/xway_nand.c +++ b/drivers/mtd/nand/raw/xway_nand.c @@ -167,7 +167,6 @@ static int xway_nand_probe(struct platform_device *pdev) { struct xway_nand_data *data; struct mtd_info *mtd; - struct resource *res; int err; u32 cs; u32 cs_flag = 0; @@ -178,8 +177,7 @@ static int xway_nand_probe(struct platform_device *pdev) if (!data) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - data->nandaddr = devm_ioremap_resource(&pdev->dev, res); + data->nandaddr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(data->nandaddr)) return PTR_ERR(data->nandaddr); -- cgit From 46a0dc10fb32bec3e765e51bf71fbc070dc77ca3 Mon Sep 17 00:00:00 2001 From: Evgeny Novikov Date: Fri, 3 Sep 2021 11:26:53 +0300 Subject: mtd: rawnand: intel: Fix potential buffer overflow in probe ebu_nand_probe() read the value of u32 variable "cs" from the device firmware description and used it as the index for array ebu_host->cs that can contain MAX_CS (2) elements at most. That could result in a buffer overflow and various bad consequences later. Fix the potential buffer overflow by restricting values of "cs" with MAX_CS in probe. Found by Linux Driver Verification project (linuxtesting.org). Fixes: 0b1039f016e8 ("mtd: rawnand: Add NAND controller support on Intel LGM SoC") Signed-off-by: Evgeny Novikov Co-developed-by: Kirill Shilimanov Signed-off-by: Kirill Shilimanov Co-developed-by: Anton Vasilyev Signed-off-by: Anton Vasilyev Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210903082653.16441-1-novikov@ispras.ru --- drivers/mtd/nand/raw/intel-nand-controller.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/mtd/nand/raw/intel-nand-controller.c b/drivers/mtd/nand/raw/intel-nand-controller.c index b9784f3da7a1..7c1c80dae826 100644 --- a/drivers/mtd/nand/raw/intel-nand-controller.c +++ b/drivers/mtd/nand/raw/intel-nand-controller.c @@ -609,6 +609,11 @@ static int ebu_nand_probe(struct platform_device *pdev) dev_err(dev, "failed to get chip select: %d\n", ret); return ret; } + if (cs >= MAX_CS) { + dev_err(dev, "got invalid chip select: %d\n", cs); + return -EINVAL; + } + ebu_host->cs_num = cs; resname = devm_kasprintf(dev, GFP_KERNEL, "nand_cs%d", cs); -- cgit From b72841e4dcd54de486fca2e4ffa00b8defc1eecc Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 10 Sep 2021 13:00:23 +0100 Subject: mtd: mtdswap: Remove redundant assignment of pointer eb The pointer eb is being assigned a value that is never read, it is being updated later on. The assignment is redundant and can be removed. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210910120023.46308-1-colin.king@canonical.com --- drivers/mtd/mtdswap.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index 7e309270ddd4..e86b04bc1d6b 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -716,7 +716,6 @@ retry: return ret; } - eb = d->eb_data + *newblock / d->pages_per_eblk; d->page_data[page] = *newblock; d->revmap[oldblock] = PAGE_UNDEF; eb = d->eb_data + oldblock / d->pages_per_eblk; -- cgit From 08d0a992131a4db7328b0c2f5a0259732e4d0d12 Mon Sep 17 00:00:00 2001 From: Ajish Koshy Date: Mon, 6 Sep 2021 22:34:01 +0530 Subject: scsi: pm80xx: Fix incorrect port value when registering a device During phyup event, the firmware provides the phy_id and port_id and driver is supposed to use these during device handle registration. Previously the driver was using the port id value from libsas during device handle registration. Since id can be different from the one assigned by firmware, this can lead to wrong device registration and drives not showing up. Use firmware assigned port id during device registration. Link: https://lore.kernel.org/r/20210906170404.5682-2-Ajish.Koshy@microchip.com Acked-by: Jack Wang Signed-off-by: Ajish Koshy Signed-off-by: Viswas G Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_hwi.c | 7 ++++++- drivers/scsi/pm8001/pm8001_init.c | 1 + drivers/scsi/pm8001/pm8001_sas.c | 15 +++++++++++++++ drivers/scsi/pm8001/pm8001_sas.h | 2 ++ drivers/scsi/pm8001/pm80xx_hwi.c | 7 ++++++- 5 files changed, 30 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 63690508313b..c9ecddd0d719 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -3358,6 +3358,8 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; unsigned long flags; u8 deviceType = pPayload->sas_identify.dev_type; + phy->port = port; + port->port_id = port_id; port->port_state = portstate; phy->phy_state = PHY_STATE_LINK_UP_SPC; pm8001_dbg(pm8001_ha, MSG, @@ -3434,6 +3436,8 @@ hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) unsigned long flags; pm8001_dbg(pm8001_ha, DEVIO, "HW_EVENT_SATA_PHY_UP port id = %d, phy id = %d\n", port_id, phy_id); + phy->port = port; + port->port_id = port_id; port->port_state = portstate; phy->phy_state = PHY_STATE_LINK_UP_SPC; port->port_attached = 1; @@ -4460,6 +4464,7 @@ static int pm8001_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, u16 ITNT = 2000; struct domain_device *dev = pm8001_dev->sas_device; struct domain_device *parent_dev = dev->parent; + struct pm8001_port *port = dev->port->lldd_port; circularQ = &pm8001_ha->inbnd_q_tbl[0]; memset(&payload, 0, sizeof(payload)); @@ -4488,7 +4493,7 @@ static int pm8001_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, linkrate = (pm8001_dev->sas_device->linkrate < dev->port->linkrate) ? pm8001_dev->sas_device->linkrate : dev->port->linkrate; payload.phyid_portid = - cpu_to_le32(((pm8001_dev->sas_device->port->id) & 0x0F) | + cpu_to_le32(((port->port_id) & 0x0F) | ((phy_id & 0x0F) << 4)); payload.dtype_dlr_retry = cpu_to_le32((retryFlag & 0x01) | ((linkrate & 0x0F) * 0x1000000) | diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index 47db7e0beae6..613455a3e686 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -128,6 +128,7 @@ static struct sas_domain_function_template pm8001_transport_ops = { .lldd_I_T_nexus_reset = pm8001_I_T_nexus_reset, .lldd_lu_reset = pm8001_lu_reset, .lldd_query_task = pm8001_query_task, + .lldd_port_formed = pm8001_port_formed, }; /** diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 32e60f0c3b14..83e73009db5c 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -1355,3 +1355,18 @@ int pm8001_clear_task_set(struct domain_device *dev, u8 *lun) tmf_task.tmf = TMF_CLEAR_TASK_SET; return pm8001_issue_ssp_tmf(dev, lun, &tmf_task); } + +void pm8001_port_formed(struct asd_sas_phy *sas_phy) +{ + struct sas_ha_struct *sas_ha = sas_phy->ha; + struct pm8001_hba_info *pm8001_ha = sas_ha->lldd_ha; + struct pm8001_phy *phy = sas_phy->lldd_phy; + struct asd_sas_port *sas_port = sas_phy->port; + struct pm8001_port *port = phy->port; + + if (!sas_port) { + pm8001_dbg(pm8001_ha, FAIL, "Received null port\n"); + return; + } + sas_port->lldd_port = port; +} diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index 62d08b535a4b..1a016a421280 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -230,6 +230,7 @@ struct pm8001_port { u8 port_attached; u16 wide_port_phymap; u8 port_state; + u8 port_id; struct list_head list; }; @@ -651,6 +652,7 @@ int pm8001_lu_reset(struct domain_device *dev, u8 *lun); int pm8001_I_T_nexus_reset(struct domain_device *dev); int pm8001_I_T_nexus_event_handler(struct domain_device *dev); int pm8001_query_task(struct sas_task *task); +void pm8001_port_formed(struct asd_sas_phy *sas_phy); void pm8001_open_reject_retry( struct pm8001_hba_info *pm8001_ha, struct sas_task *task_to_close, diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 6ffe17b849ae..cec932f830b8 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -3299,6 +3299,8 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; unsigned long flags; u8 deviceType = pPayload->sas_identify.dev_type; + phy->port = port; + port->port_id = port_id; port->port_state = portstate; port->wide_port_phymap |= (1U << phy_id); phy->phy_state = PHY_STATE_LINK_UP_SPCV; @@ -3380,6 +3382,8 @@ hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) "port id %d, phy id %d link_rate %d portstate 0x%x\n", port_id, phy_id, link_rate, portstate); + phy->port = port; + port->port_id = port_id; port->port_state = portstate; phy->phy_state = PHY_STATE_LINK_UP_SPCV; port->port_attached = 1; @@ -4808,6 +4812,7 @@ static int pm80xx_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, u16 ITNT = 2000; struct domain_device *dev = pm8001_dev->sas_device; struct domain_device *parent_dev = dev->parent; + struct pm8001_port *port = dev->port->lldd_port; circularQ = &pm8001_ha->inbnd_q_tbl[0]; memset(&payload, 0, sizeof(payload)); @@ -4840,7 +4845,7 @@ static int pm80xx_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, pm8001_dev->sas_device->linkrate : dev->port->linkrate; payload.phyid_portid = - cpu_to_le32(((pm8001_dev->sas_device->port->id) & 0xFF) | + cpu_to_le32(((port->port_id) & 0xFF) | ((phy_id & 0xFF) << 8)); payload.dtype_dlr_mcn_ir_retry = cpu_to_le32((retryFlag & 0x01) | -- cgit From b27a40534ef76a22628a5c12f98ea489823a8ba5 Mon Sep 17 00:00:00 2001 From: Ajish Koshy Date: Mon, 6 Sep 2021 22:34:02 +0530 Subject: scsi: pm80xx: Fix lockup in outbound queue management Commit 1f02beff224e ("scsi: pm80xx: Remove global lock from outbound queue processing") introduced a lock per outbound queue. Prior to that change the driver was using a global lock for all outbound queues. While processing the I/O responses and events the driver takes the outbound queue spinlock and is supposed to release it in pm8001_ccb_task_free_done() before calling command done(). Since the older code was using a global lock, pm8001_ccb_task_free_done() was releasing the global spin lock. The change that split the lock per outbound queue did not consider this and pm8001_ccb_task_free_done() was still releasing the global lock. Link: https://lore.kernel.org/r/20210906170404.5682-3-Ajish.Koshy@microchip.com Fixes: 1f02beff224e ("scsi: pm80xx: Remove global lock from outbound queue processing") Acked-by: Jack Wang Signed-off-by: Ajish Koshy Signed-off-by: Viswas G Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_sas.h | 3 +-- drivers/scsi/pm8001/pm80xx_hwi.c | 53 +++++++++++++++++++++++++++++++++------- 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index 1a016a421280..3274d88a9ccc 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -458,6 +458,7 @@ struct outbound_queue_table { __le32 producer_index; u32 consumer_idx; spinlock_t oq_lock; + unsigned long lock_flags; }; struct pm8001_hba_memspace { void __iomem *memvirtaddr; @@ -740,9 +741,7 @@ pm8001_ccb_task_free_done(struct pm8001_hba_info *pm8001_ha, { pm8001_ccb_task_free(pm8001_ha, task, ccb, ccb_idx); smp_mb(); /*in order to force CPU ordering*/ - spin_unlock(&pm8001_ha->lock); task->task_done(task); - spin_lock(&pm8001_ha->lock); } #endif diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index cec932f830b8..1ae2f5c6042c 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -2379,7 +2379,8 @@ static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha, void *piomb) /*See the comments for mpi_ssp_completion */ static void -mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) +mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, + struct outbound_queue_table *circularQ, void *piomb) { struct sas_task *t; struct pm8001_ccb_info *ccb; @@ -2616,7 +2617,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_QUEUE_FULL; + spin_unlock_irqrestore(&circularQ->oq_lock, + circularQ->lock_flags); pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag); + spin_lock_irqsave(&circularQ->oq_lock, + circularQ->lock_flags); return; } break; @@ -2632,7 +2637,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_QUEUE_FULL; + spin_unlock_irqrestore(&circularQ->oq_lock, + circularQ->lock_flags); pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag); + spin_lock_irqsave(&circularQ->oq_lock, + circularQ->lock_flags); return; } break; @@ -2656,7 +2665,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY); ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_QUEUE_FULL; + spin_unlock_irqrestore(&circularQ->oq_lock, + circularQ->lock_flags); pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag); + spin_lock_irqsave(&circularQ->oq_lock, + circularQ->lock_flags); return; } break; @@ -2727,7 +2740,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) IO_DS_NON_OPERATIONAL); ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_QUEUE_FULL; + spin_unlock_irqrestore(&circularQ->oq_lock, + circularQ->lock_flags); pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag); + spin_lock_irqsave(&circularQ->oq_lock, + circularQ->lock_flags); return; } break; @@ -2747,7 +2764,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) IO_DS_IN_ERROR); ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_QUEUE_FULL; + spin_unlock_irqrestore(&circularQ->oq_lock, + circularQ->lock_flags); pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag); + spin_lock_irqsave(&circularQ->oq_lock, + circularQ->lock_flags); return; } break; @@ -2785,12 +2806,17 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); } else { spin_unlock_irqrestore(&t->task_state_lock, flags); + spin_unlock_irqrestore(&circularQ->oq_lock, + circularQ->lock_flags); pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag); + spin_lock_irqsave(&circularQ->oq_lock, + circularQ->lock_flags); } } /*See the comments for mpi_ssp_completion */ -static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, void *piomb) +static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, + struct outbound_queue_table *circularQ, void *piomb) { struct sas_task *t; struct task_status_struct *ts; @@ -2890,7 +2916,11 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, void *piomb) IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_QUEUE_FULL; + spin_unlock_irqrestore(&circularQ->oq_lock, + circularQ->lock_flags); pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag); + spin_lock_irqsave(&circularQ->oq_lock, + circularQ->lock_flags); return; } break; @@ -3002,7 +3032,11 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, void *piomb) pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); } else { spin_unlock_irqrestore(&t->task_state_lock, flags); + spin_unlock_irqrestore(&circularQ->oq_lock, + circularQ->lock_flags); pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag); + spin_lock_irqsave(&circularQ->oq_lock, + circularQ->lock_flags); } } @@ -3906,7 +3940,8 @@ static int ssp_coalesced_comp_resp(struct pm8001_hba_info *pm8001_ha, * @pm8001_ha: our hba card information * @piomb: IO message buffer */ -static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb) +static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, + struct outbound_queue_table *circularQ, void *piomb) { __le32 pHeader = *(__le32 *)piomb; u32 opc = (u32)((le32_to_cpu(pHeader)) & 0xFFF); @@ -3948,11 +3983,11 @@ static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb) break; case OPC_OUB_SATA_COMP: pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SATA_COMP\n"); - mpi_sata_completion(pm8001_ha, piomb); + mpi_sata_completion(pm8001_ha, circularQ, piomb); break; case OPC_OUB_SATA_EVENT: pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SATA_EVENT\n"); - mpi_sata_event(pm8001_ha, piomb); + mpi_sata_event(pm8001_ha, circularQ, piomb); break; case OPC_OUB_SSP_EVENT: pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_EVENT\n"); @@ -4121,7 +4156,6 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec) void *pMsg1 = NULL; u8 bc; u32 ret = MPI_IO_STATUS_FAIL; - unsigned long flags; u32 regval; if (vec == (pm8001_ha->max_q_num - 1)) { @@ -4138,7 +4172,7 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec) } } circularQ = &pm8001_ha->outbnd_q_tbl[vec]; - spin_lock_irqsave(&circularQ->oq_lock, flags); + spin_lock_irqsave(&circularQ->oq_lock, circularQ->lock_flags); do { /* spurious interrupt during setup if kexec-ing and * driver doing a doorbell access w/ the pre-kexec oq @@ -4149,7 +4183,8 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec) ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc); if (MPI_IO_STATUS_SUCCESS == ret) { /* process the outbound message */ - process_one_iomb(pm8001_ha, (void *)(pMsg1 - 4)); + process_one_iomb(pm8001_ha, circularQ, + (void *)(pMsg1 - 4)); /* free the message from the outbound circular buffer */ pm8001_mpi_msg_free_set(pm8001_ha, pMsg1, circularQ, bc); @@ -4164,7 +4199,7 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec) break; } } while (1); - spin_unlock_irqrestore(&circularQ->oq_lock, flags); + spin_unlock_irqrestore(&circularQ->oq_lock, circularQ->lock_flags); return ret; } -- cgit From c29737d03c74fbaf69ea50d355b25e43d0bacc73 Mon Sep 17 00:00:00 2001 From: Viswas G Date: Mon, 6 Sep 2021 22:34:03 +0530 Subject: scsi: pm80xx: Correct inbound and outbound queue logging Correct inbound queue and outbound queue size in 'ib_log' and 'ob_log' sysfs entries. Link: https://lore.kernel.org/r/20210906170404.5682-4-Ajish.Koshy@microchip.com Acked-by: Jack Wang Signed-off-by: Viswas G Signed-off-by: Ajish Koshy Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_ctl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c index ec05c42e8ee6..b25e447aa3bd 100644 --- a/drivers/scsi/pm8001/pm8001_ctl.c +++ b/drivers/scsi/pm8001/pm8001_ctl.c @@ -409,6 +409,7 @@ static ssize_t pm8001_ctl_ib_queue_log_show(struct device *cdev, char *str = buf; int start = 0; u32 ib_offset = pm8001_ha->ib_offset; + u32 queue_size = pm8001_ha->max_q_num * PM8001_MPI_QUEUE * 128; #define IB_MEMMAP(c) \ (*(u32 *)((u8 *)pm8001_ha-> \ memoryMap.region[ib_offset].virt_ptr + \ @@ -419,7 +420,7 @@ static ssize_t pm8001_ctl_ib_queue_log_show(struct device *cdev, start = start + 4; } pm8001_ha->evtlog_ib_offset += SYSFS_OFFSET; - if (((pm8001_ha->evtlog_ib_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0) + if (((pm8001_ha->evtlog_ib_offset) % queue_size) == 0) pm8001_ha->evtlog_ib_offset = 0; return str - buf; @@ -445,6 +446,7 @@ static ssize_t pm8001_ctl_ob_queue_log_show(struct device *cdev, char *str = buf; int start = 0; u32 ob_offset = pm8001_ha->ob_offset; + u32 queue_size = pm8001_ha->max_q_num * PM8001_MPI_QUEUE * 128; #define OB_MEMMAP(c) \ (*(u32 *)((u8 *)pm8001_ha-> \ memoryMap.region[ob_offset].virt_ptr + \ @@ -455,7 +457,7 @@ static ssize_t pm8001_ctl_ob_queue_log_show(struct device *cdev, start = start + 4; } pm8001_ha->evtlog_ob_offset += SYSFS_OFFSET; - if (((pm8001_ha->evtlog_ob_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0) + if (((pm8001_ha->evtlog_ob_offset) % queue_size) == 0) pm8001_ha->evtlog_ob_offset = 0; return str - buf; -- cgit From 51e6ed83bb4ade7c360551fa4ae55c4eacea354b Mon Sep 17 00:00:00 2001 From: Ajish Koshy Date: Mon, 6 Sep 2021 22:34:04 +0530 Subject: scsi: pm80xx: Fix memory leak during rmmod Driver failed to release all memory allocated. This would lead to memory leak during driver removal. Properly free memory when the module is removed. Link: https://lore.kernel.org/r/20210906170404.5682-5-Ajish.Koshy@microchip.com Acked-by: Jack Wang Signed-off-by: Ajish Koshy Signed-off-by: Viswas G Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_init.c | 11 +++++++++++ drivers/scsi/pm8001/pm8001_sas.h | 1 + 2 files changed, 12 insertions(+) diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index 613455a3e686..7082fecf7ce8 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -1199,6 +1199,7 @@ pm8001_init_ccb_tag(struct pm8001_hba_info *pm8001_ha, struct Scsi_Host *shost, goto err_out; /* Memory region for ccb_info*/ + pm8001_ha->ccb_count = ccb_count; pm8001_ha->ccb_info = kcalloc(ccb_count, sizeof(struct pm8001_ccb_info), GFP_KERNEL); if (!pm8001_ha->ccb_info) { @@ -1260,6 +1261,16 @@ static void pm8001_pci_remove(struct pci_dev *pdev) tasklet_kill(&pm8001_ha->tasklet[j]); #endif scsi_host_put(pm8001_ha->shost); + + for (i = 0; i < pm8001_ha->ccb_count; i++) { + dma_free_coherent(&pm8001_ha->pdev->dev, + sizeof(struct pm8001_prd) * PM8001_MAX_DMA_SG, + pm8001_ha->ccb_info[i].buf_prd, + pm8001_ha->ccb_info[i].ccb_dma_handle); + } + kfree(pm8001_ha->ccb_info); + kfree(pm8001_ha->devices); + pm8001_free(pm8001_ha); kfree(sha->sas_phy); kfree(sha->sas_port); diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index 3274d88a9ccc..7e999768bfd2 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -518,6 +518,7 @@ struct pm8001_hba_info { u32 iomb_size; /* SPC and SPCV IOMB size */ struct pm8001_device *devices; struct pm8001_ccb_info *ccb_info; + u32 ccb_count; #ifdef PM8001_USE_MSIX int number_of_intr;/*will be used in remove()*/ char intr_drvname[PM8001_MAX_MSIX_VEC] -- cgit From 9e1c3206960f8e0a5b6a42d3e6693f10c5ca10ac Mon Sep 17 00:00:00 2001 From: Bikash Hazarika Date: Wed, 8 Sep 2021 09:46:13 -0700 Subject: scsi: qla2xxx: Add support for mailbox passthru This interface will allow user space applications to send a mailbox command to the firmware. Link: https://lore.kernel.org/r/20210908164622.19240-2-njavali@marvell.com Reviewed-by: Himanshu Madhani Signed-off-by: Bikash Hazarika Signed-off-by: Nilesh Javali Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_bsg.c | 48 ++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/qla2xxx/qla_bsg.h | 7 ++++++ drivers/scsi/qla2xxx/qla_gbl.h | 4 ++++ drivers/scsi/qla2xxx/qla_mbx.c | 33 +++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index 4b5d28d89d69..0c33fb0de21a 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -2877,6 +2877,9 @@ qla2x00_process_vendor_specific(struct scsi_qla_host *vha, struct bsg_job *bsg_j case QL_VND_MANAGE_HOST_PORT: return qla2x00_manage_host_port(bsg_job); + case QL_VND_MBX_PASSTHRU: + return qla2x00_mailbox_passthru(bsg_job); + default: return -ENOSYS; } @@ -3013,3 +3016,48 @@ done: sp->free(sp); return 0; } + +int qla2x00_mailbox_passthru(struct bsg_job *bsg_job) +{ + struct fc_bsg_reply *bsg_reply = bsg_job->reply; + scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job)); + int ret = -EINVAL; + int ptsize = sizeof(struct qla_mbx_passthru); + struct qla_mbx_passthru *req_data = NULL; + uint32_t req_data_len; + + req_data_len = bsg_job->request_payload.payload_len; + if (req_data_len != ptsize) { + ql_log(ql_log_warn, vha, 0xf0a3, "req_data_len invalid.\n"); + return -EIO; + } + req_data = kzalloc(ptsize, GFP_KERNEL); + if (!req_data) { + ql_log(ql_log_warn, vha, 0xf0a4, + "req_data memory allocation failure.\n"); + return -ENOMEM; + } + + /* Copy the request buffer in req_data */ + sg_copy_to_buffer(bsg_job->request_payload.sg_list, + bsg_job->request_payload.sg_cnt, req_data, ptsize); + ret = qla_mailbox_passthru(vha, req_data->mbx_in, req_data->mbx_out); + + /* Copy the req_data in request buffer */ + sg_copy_from_buffer(bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, req_data, ptsize); + + bsg_reply->reply_payload_rcv_len = ptsize; + if (ret == QLA_SUCCESS) + bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK; + else + bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_ERR; + + bsg_job->reply_len = sizeof(*bsg_job->reply); + bsg_reply->result = DID_OK << 16; + bsg_job_done(bsg_job, bsg_reply->result, bsg_reply->reply_payload_rcv_len); + + kfree(req_data); + + return ret; +} diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h index dd793cf8bc1e..0f8a4c7e52a2 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.h +++ b/drivers/scsi/qla2xxx/qla_bsg.h @@ -36,6 +36,7 @@ #define QL_VND_GET_HOST_STATS 0x24 #define QL_VND_GET_TGT_STATS 0x25 #define QL_VND_MANAGE_HOST_PORT 0x26 +#define QL_VND_MBX_PASSTHRU 0x2B /* BSG Vendor specific subcode returns */ #define EXT_STATUS_OK 0 @@ -187,6 +188,12 @@ struct qla_port_param { uint16_t speed; } __attribute__ ((packed)); +struct qla_mbx_passthru { + uint16_t reserved1[2]; + uint16_t mbx_in[32]; + uint16_t mbx_out[32]; + uint32_t reserved2[16]; +} __packed; /* FRU VPD */ diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 1c3f055d41b8..8aadcdeca6cb 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -662,9 +662,13 @@ extern int qla2xxx_get_vpd_field(scsi_qla_host_t *, char *, char *, size_t); extern void qla2xxx_flash_npiv_conf(scsi_qla_host_t *); extern int qla24xx_read_fcp_prio_cfg(scsi_qla_host_t *); +extern int qla2x00_mailbox_passthru(struct bsg_job *bsg_job); int __qla_copy_purex_to_buffer(struct scsi_qla_host *vha, void **pkt, struct rsp_que **rsp, u8 *buf, u32 buf_len); +int qla_mailbox_passthru(scsi_qla_host_t *vha, uint16_t *mbx_in, + uint16_t *mbx_out); + /* * Global Function Prototypes in qla_dbg.c source file. */ diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 7811c4952035..9eb41dd39043 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -7011,3 +7011,36 @@ void qla_no_op_mb(struct scsi_qla_host *vha) "Failed %s %x\n", __func__, rval); } } + +int qla_mailbox_passthru(scsi_qla_host_t *vha, + uint16_t *mbx_in, uint16_t *mbx_out) +{ + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + int rval = -EINVAL; + + memset(&mc, 0, sizeof(mc)); + /* Receiving all 32 register's contents */ + memcpy(&mcp->mb, (char *)mbx_in, (32 * sizeof(uint16_t))); + + mcp->out_mb = 0xFFFFFFFF; + mcp->in_mb = 0xFFFFFFFF; + + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = 0; + mcp->bufp = NULL; + + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + ql_dbg(ql_dbg_mbx, vha, 0xf0a2, + "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); + } else { + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0xf0a3, "Done %s.\n", + __func__); + /* passing all 32 register's contents */ + memcpy(mbx_out, &mcp->mb, 32 * sizeof(uint16_t)); + } + + return rval; +} -- cgit From 52cca50d35f814e737791e2c2cf8c279219a9f29 Mon Sep 17 00:00:00 2001 From: Saurav Kashyap Date: Wed, 8 Sep 2021 09:46:14 -0700 Subject: scsi: qla2xxx: Display 16G only as supported speeds for 3830c card This card is unique and doesn't support lower speeds, hence update the fdmi field to display 16G only. Link: https://lore.kernel.org/r/20210908164622.19240-3-njavali@marvell.com Reviewed-by: Himanshu Madhani Signed-off-by: Saurav Kashyap Signed-off-by: Nilesh Javali Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_gs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index ebc8fdb0b43d..28b574e20ef3 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -1537,7 +1537,8 @@ qla25xx_fdmi_port_speed_capability(struct qla_hw_data *ha) } if (IS_QLA2031(ha)) { if ((ha->pdev->subsystem_vendor == 0x103C) && - (ha->pdev->subsystem_device == 0x8002)) { + ((ha->pdev->subsystem_device == 0x8002) || + (ha->pdev->subsystem_device == 0x8086))) { speeds = FDMI_PORT_SPEED_16GB; } else { speeds = FDMI_PORT_SPEED_16GB|FDMI_PORT_SPEED_8GB| -- cgit From 8192817efbc34e9ca482edf340d41c5ca0d4dad0 Mon Sep 17 00:00:00 2001 From: Saurav Kashyap Date: Wed, 8 Sep 2021 09:46:15 -0700 Subject: scsi: qla2xxx: Check for firmware capability before creating QPair Add firmware capability check of multiQ specifically for ISP25XX before creating qpair. Link: https://lore.kernel.org/r/20210908164622.19240-4-njavali@marvell.com Reviewed-by: Himanshu Madhani Signed-off-by: Saurav Kashyap Signed-off-by: Nilesh Javali Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_os.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index d2e40aaba734..a1e861ecfc01 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -3364,6 +3364,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) host->can_queue, base_vha->req, base_vha->mgmt_svr_loop_id, host->sg_tablesize); + /* Check if FW supports MQ or not for ISP25xx */ + if (IS_QLA25XX(ha) && !(ha->fw_attributes & BIT_6)) + ha->mqenable = 0; + if (ha->mqenable) { bool startit = false; -- cgit From e6e22e6cc2962d3f3d71914b47f7fbc454670e8a Mon Sep 17 00:00:00 2001 From: Arun Easi Date: Wed, 8 Sep 2021 09:46:16 -0700 Subject: scsi: qla2xxx: Fix crash in NVMe abort path System crash was seen when I/O was run against an NVMe target and aborts were occurring. Crash stack is: -- relevant crash stack -- BUG: kernel NULL pointer dereference, address: 0000000000000010 : #6 [ffffae1f8666bdd0] page_fault at ffffffffa740122e [exception RIP: qla_nvme_abort_work+339] RIP: ffffffffc0f592e3 RSP: ffffae1f8666be80 RFLAGS: 00010297 RAX: 0000000000000000 RBX: ffff9b581fc8af80 RCX: ffffffffc0f83bd0 RDX: 0000000000000001 RSI: ffff9b5839c6c7c8 RDI: 0000000008000000 RBP: ffff9b6832f85000 R8: ffffffffc0f68160 R9: ffffffffc0f70652 R10: ffffae1f862ffdc8 R11: 0000000000000300 R12: 000000000000010d R13: 0000000000000000 R14: ffff9b5839cea000 R15: 0ffff9b583fab170 ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 #7 [ffffae1f8666be98] process_one_work at ffffffffa6aba184 #8 [ffffae1f8666bed8] worker_thread at ffffffffa6aba39d #9 [ffffae1f8666bf10] kthread at ffffffffa6ac06ed The crash was due to a stale SRB structure access after it was aborted. Fix the issue by removing stale access. Link: https://lore.kernel.org/r/20210908164622.19240-5-njavali@marvell.com Fixes: 2cabf10dbbe3 ("scsi: qla2xxx: Fix hang on NVMe command timeouts") Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani Signed-off-by: Arun Easi Signed-off-by: Nilesh Javali Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_nvme.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index 1c5da2dbd6f9..877b2b625020 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -228,6 +228,8 @@ static void qla_nvme_abort_work(struct work_struct *work) fc_port_t *fcport = sp->fcport; struct qla_hw_data *ha = fcport->vha->hw; int rval, abts_done_called = 1; + bool io_wait_for_abort_done; + uint32_t handle; ql_dbg(ql_dbg_io, fcport->vha, 0xffff, "%s called for sp=%p, hndl=%x on fcport=%p desc=%p deleted=%d\n", @@ -244,12 +246,20 @@ static void qla_nvme_abort_work(struct work_struct *work) goto out; } + /* + * sp may not be valid after abort_command if return code is either + * SUCCESS or ERR_FROM_FW codes, so cache the value here. + */ + io_wait_for_abort_done = ql2xabts_wait_nvme && + QLA_ABTS_WAIT_ENABLED(sp); + handle = sp->handle; + rval = ha->isp_ops->abort_command(sp); ql_dbg(ql_dbg_io, fcport->vha, 0x212b, "%s: %s command for sp=%p, handle=%x on fcport=%p rval=%x\n", __func__, (rval != QLA_SUCCESS) ? "Failed to abort" : "Aborted", - sp, sp->handle, fcport, rval); + sp, handle, fcport, rval); /* * If async tmf is enabled, the abort callback is called only on @@ -264,7 +274,7 @@ static void qla_nvme_abort_work(struct work_struct *work) * are waited until ABTS complete. This kref is decreased * at qla24xx_abort_sp_done function. */ - if (abts_done_called && ql2xabts_wait_nvme && QLA_ABTS_WAIT_ENABLED(sp)) + if (abts_done_called && io_wait_for_abort_done) return; out: /* kref_get was done before work was schedule. */ -- cgit From 527d46e0b0147f2b32b78ba49c6a231835b24a41 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Wed, 8 Sep 2021 09:46:17 -0700 Subject: scsi: qla2xxx: edif: Use link event to wake up app Authentication application may be running and in the past tried to probe driver (app_start) but was unsuccessful. This could be due to the bsg layer not being ready to service the request. On a successful link up, driver will use the netlink Link Up event to notify the app to retry the app_start call. In another case, app does not poll for new NPIV host. This link up event would notify app of the presence of a new SCSI host. Link: https://lore.kernel.org/r/20210908164622.19240-6-njavali@marvell.com Fixes: 4de067e5df12 ("scsi: qla2xxx: edif: Add N2N support for EDIF") Reviewed-by: Himanshu Madhani Signed-off-by: Quinn Tran Signed-off-by: Nilesh Javali Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 1e4e3e83b5c7..c6b3d0e7489e 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -5335,15 +5335,14 @@ qla2x00_configure_loop(scsi_qla_host_t *vha) "LOOP READY.\n"); ha->flags.fw_init_done = 1; + /* + * use link up to wake up app to get ready for + * authentication. + */ if (ha->flags.edif_enabled && - !(vha->e_dbell.db_flags & EDB_ACTIVE) && - N2N_TOPO(vha->hw)) { - /* - * use port online to wake up app to get ready - * for authentication - */ - qla2x00_post_aen_work(vha, FCH_EVT_PORT_ONLINE, 0); - } + !(vha->e_dbell.db_flags & EDB_ACTIVE)) + qla2x00_post_aen_work(vha, FCH_EVT_LINKUP, + ha->link_data_rate); /* * Process any ATIO queue entries that came in -- cgit From 3ef68d4f0c9e7cb589ae8b70f07d77f528105331 Mon Sep 17 00:00:00 2001 From: Arun Easi Date: Wed, 8 Sep 2021 09:46:18 -0700 Subject: scsi: qla2xxx: Fix kernel crash when accessing port_speed sysfs file Kernel crashes when accessing port_speed sysfs file. The issue happens on a CNA when the local array was accessed beyond bounds. Fix this by changing the lookup. BUG: unable to handle kernel paging request at 0000000000004000 PGD 0 P4D 0 Oops: 0000 [#1] SMP PTI CPU: 15 PID: 455213 Comm: sosreport Kdump: loaded Not tainted 4.18.0-305.7.1.el8_4.x86_64 #1 RIP: 0010:string_nocheck+0x12/0x70 Code: 00 00 4c 89 e2 be 20 00 00 00 48 89 ef e8 86 9a 00 00 4c 01 e3 eb 81 90 49 89 f2 48 89 ce 48 89 f8 48 c1 fe 30 66 85 f6 74 4f <44> 0f b6 0a 45 84 c9 74 46 83 ee 01 41 b8 01 00 00 00 48 8d 7c 37 RSP: 0018:ffffb5141c1afcf0 EFLAGS: 00010286 RAX: ffff8bf4009f8000 RBX: ffff8bf4009f9000 RCX: ffff0a00ffffff04 RDX: 0000000000004000 RSI: ffffffffffffffff RDI: ffff8bf4009f8000 RBP: 0000000000004000 R08: 0000000000000001 R09: ffffb5141c1afb84 R10: ffff8bf4009f9000 R11: ffffb5141c1afce6 R12: ffff0a00ffffff04 R13: ffffffffc08e21aa R14: 0000000000001000 R15: ffffffffc08e21aa FS: 00007fc4ebfff700(0000) GS:ffff8c717f7c0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000004000 CR3: 000000edfdee6006 CR4: 00000000001706e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: string+0x40/0x50 vsnprintf+0x33c/0x520 scnprintf+0x4d/0x90 qla2x00_port_speed_show+0xb5/0x100 [qla2xxx] dev_attr_show+0x1c/0x40 sysfs_kf_seq_show+0x9b/0x100 seq_read+0x153/0x410 vfs_read+0x91/0x140 ksys_read+0x4f/0xb0 do_syscall_64+0x5b/0x1a0 entry_SYSCALL_64_after_hwframe+0x65/0xca Link: https://lore.kernel.org/r/20210908164622.19240-7-njavali@marvell.com Fixes: 4910b524ac9e ("scsi: qla2xxx: Add support for setting port speed") Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani Signed-off-by: Arun Easi Signed-off-by: Nilesh Javali Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_attr.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index d09776b77af2..cb5f2ecb652d 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1868,6 +1868,18 @@ qla2x00_port_speed_store(struct device *dev, struct device_attribute *attr, return strlen(buf); } +static const struct { + u16 rate; + char *str; +} port_speed_str[] = { + { PORT_SPEED_4GB, "4" }, + { PORT_SPEED_8GB, "8" }, + { PORT_SPEED_16GB, "16" }, + { PORT_SPEED_32GB, "32" }, + { PORT_SPEED_64GB, "64" }, + { PORT_SPEED_10GB, "10" }, +}; + static ssize_t qla2x00_port_speed_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -1875,7 +1887,8 @@ qla2x00_port_speed_show(struct device *dev, struct device_attribute *attr, struct scsi_qla_host *vha = shost_priv(dev_to_shost(dev)); struct qla_hw_data *ha = vha->hw; ssize_t rval; - char *spd[7] = {"0", "0", "0", "4", "8", "16", "32"}; + u16 i; + char *speed = "Unknown"; rval = qla2x00_get_data_rate(vha); if (rval != QLA_SUCCESS) { @@ -1884,7 +1897,14 @@ qla2x00_port_speed_show(struct device *dev, struct device_attribute *attr, return -EINVAL; } - return scnprintf(buf, PAGE_SIZE, "%s\n", spd[ha->link_data_rate]); + for (i = 0; i < ARRAY_SIZE(port_speed_str); i++) { + if (port_speed_str[i].rate != ha->link_data_rate) + continue; + speed = port_speed_str[i].str; + break; + } + + return scnprintf(buf, PAGE_SIZE, "%s\n", speed); } static ssize_t -- cgit From 38c61709e66294f33e474eaafd6ae3be381030da Mon Sep 17 00:00:00 2001 From: Shreyas Deodhar Date: Wed, 8 Sep 2021 09:46:19 -0700 Subject: scsi: qla2xxx: Call process_response_queue() in Tx path Process responses in Tx path if any available for better performance. Link: https://lore.kernel.org/r/20210908164622.19240-8-njavali@marvell.com Reviewed-by: Himanshu Madhani Signed-off-by: Shreyas Deodhar Signed-off-by: Nilesh Javali Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_nvme.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index 877b2b625020..0ae1e081cb03 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -399,6 +399,7 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp) uint16_t avail_dsds; struct dsd64 *cur_dsd; struct req_que *req = NULL; + struct rsp_que *rsp = NULL; struct scsi_qla_host *vha = sp->fcport->vha; struct qla_hw_data *ha = vha->hw; struct qla_qpair *qpair = sp->qpair; @@ -410,6 +411,7 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp) /* Setup qpair pointers */ req = qpair->req; + rsp = qpair->rsp; tot_dsds = fd->sg_cnt; /* Acquire qpair specific lock */ @@ -571,6 +573,10 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp) /* Set chip new ring index. */ wrt_reg_dword(req->req_q_in, req->ring_index); + if (vha->flags.process_response_queue && + rsp->ring_ptr->signature != RESPONSE_PROCESSED) + qla24xx_process_response_queue(vha, rsp); + queuing_error: spin_unlock_irqrestore(&qpair->qp_lock, flags); -- cgit From 3a4e1f3b3a3c733de3b82b9b522e54803e1165ae Mon Sep 17 00:00:00 2001 From: Manish Rangankar Date: Wed, 8 Sep 2021 09:46:20 -0700 Subject: scsi: qla2xxx: Move heartbeat handling from DPC thread to workqueue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DPC thread gets restricted due to a no-op mailbox, which is a blocking call and has a high execution frequency. To free up the DPC thread we move no-op handling to the workqueue. Also, modified qla_do_heartbeat() to send no-op MBC if we don’t have any active interrupts, but there are still I/Os outstanding with firmware. Link: https://lore.kernel.org/r/20210908164622.19240-9-njavali@marvell.com Fixes: d94d8158e184 ("scsi: qla2xxx: Add heartbeat check") Reviewed-by: Himanshu Madhani Signed-off-by: Manish Rangankar Signed-off-by: Nilesh Javali Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 4 +-- drivers/scsi/qla2xxx/qla_init.c | 2 ++ drivers/scsi/qla2xxx/qla_os.c | 78 +++++++++++++++++++---------------------- 3 files changed, 40 insertions(+), 44 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index be2eb75ee1a3..8924eeb9367d 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -3750,6 +3750,7 @@ struct qla_qpair { struct qla_fw_resources fwres ____cacheline_aligned; u32 cmd_cnt; u32 cmd_completion_cnt; + u32 prev_completion_cnt; }; /* Place holder for FW buffer parameters */ @@ -4607,6 +4608,7 @@ struct qla_hw_data { struct qla_chip_state_84xx *cs84xx; struct isp_operations *isp_ops; struct workqueue_struct *wq; + struct work_struct heartbeat_work; struct qlfc_fw fw_buf; /* FCP_CMND priority support */ @@ -4708,7 +4710,6 @@ struct qla_hw_data { struct qla_hw_data_stat stat; pci_error_state_t pci_error_state; - u64 prev_cmd_cnt; struct dma_pool *purex_dma_pool; struct btree_head32 host_map; @@ -4854,7 +4855,6 @@ typedef struct scsi_qla_host { #define SET_ZIO_THRESHOLD_NEEDED 32 #define ISP_ABORT_TO_ROM 33 #define VPORT_DELETE 34 -#define HEARTBEAT_CHK 38 #define PROCESS_PUREX_IOCB 63 diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index c6b3d0e7489e..a9a4243cb15a 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -7025,12 +7025,14 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha) ha->chip_reset++; ha->base_qpair->chip_reset = ha->chip_reset; ha->base_qpair->cmd_cnt = ha->base_qpair->cmd_completion_cnt = 0; + ha->base_qpair->prev_completion_cnt = 0; for (i = 0; i < ha->max_qpairs; i++) { if (ha->queue_pair_map[i]) { ha->queue_pair_map[i]->chip_reset = ha->base_qpair->chip_reset; ha->queue_pair_map[i]->cmd_cnt = ha->queue_pair_map[i]->cmd_completion_cnt = 0; + ha->base_qpair->prev_completion_cnt = 0; } } diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index a1e861ecfc01..0c446438dcd3 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2794,6 +2794,16 @@ qla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time) return atomic_read(&vha->loop_state) == LOOP_READY; } +static void qla_heartbeat_work_fn(struct work_struct *work) +{ + struct qla_hw_data *ha = container_of(work, + struct qla_hw_data, heartbeat_work); + struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); + + if (!ha->flags.mbox_busy && base_vha->flags.init_done) + qla_no_op_mb(base_vha); +} + static void qla2x00_iocb_work_fn(struct work_struct *work) { struct scsi_qla_host *vha = container_of(work, @@ -3232,6 +3242,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) host->transportt, sht->vendor_id); INIT_WORK(&base_vha->iocb_work, qla2x00_iocb_work_fn); + INIT_WORK(&ha->heartbeat_work, qla_heartbeat_work_fn); /* Set up the irqs */ ret = qla2x00_request_irqs(ha, rsp); @@ -7118,17 +7129,6 @@ intr_on_check: qla2x00_lip_reset(base_vha); } - if (test_bit(HEARTBEAT_CHK, &base_vha->dpc_flags)) { - /* - * if there is a mb in progress then that's - * enough of a check to see if fw is still ticking. - */ - if (!ha->flags.mbox_busy && base_vha->flags.init_done) - qla_no_op_mb(base_vha); - - clear_bit(HEARTBEAT_CHK, &base_vha->dpc_flags); - } - ha->dpc_active = 0; end_loop: set_current_state(TASK_INTERRUPTIBLE); @@ -7187,57 +7187,51 @@ qla2x00_rst_aen(scsi_qla_host_t *vha) static bool qla_do_heartbeat(struct scsi_qla_host *vha) { - u64 cmd_cnt, prev_cmd_cnt; - bool do_hb = false; struct qla_hw_data *ha = vha->hw; - int i; + u32 cmpl_cnt; + u16 i; + bool do_heartbeat = false; - /* if cmds are still pending down in fw, then do hb */ - if (ha->base_qpair->cmd_cnt != ha->base_qpair->cmd_completion_cnt) { - do_hb = true; + /* + * Allow do_heartbeat only if we don’t have any active interrupts, + * but there are still IOs outstanding with firmware. + */ + cmpl_cnt = ha->base_qpair->cmd_completion_cnt; + if (cmpl_cnt == ha->base_qpair->prev_completion_cnt && + cmpl_cnt != ha->base_qpair->cmd_cnt) { + do_heartbeat = true; goto skip; } + ha->base_qpair->prev_completion_cnt = cmpl_cnt; for (i = 0; i < ha->max_qpairs; i++) { - if (ha->queue_pair_map[i] && - ha->queue_pair_map[i]->cmd_cnt != - ha->queue_pair_map[i]->cmd_completion_cnt) { - do_hb = true; - break; + if (ha->queue_pair_map[i]) { + cmpl_cnt = ha->queue_pair_map[i]->cmd_completion_cnt; + if (cmpl_cnt == ha->queue_pair_map[i]->prev_completion_cnt && + cmpl_cnt != ha->queue_pair_map[i]->cmd_cnt) { + do_heartbeat = true; + break; + } + ha->queue_pair_map[i]->prev_completion_cnt = cmpl_cnt; } } skip: - prev_cmd_cnt = ha->prev_cmd_cnt; - cmd_cnt = ha->base_qpair->cmd_cnt; - for (i = 0; i < ha->max_qpairs; i++) { - if (ha->queue_pair_map[i]) - cmd_cnt += ha->queue_pair_map[i]->cmd_cnt; - } - ha->prev_cmd_cnt = cmd_cnt; - - if (!do_hb && ((cmd_cnt - prev_cmd_cnt) > 50)) - /* - * IOs are completing before periodic hb check. - * IOs seems to be running, do hb for sanity check. - */ - do_hb = true; - - return do_hb; + return do_heartbeat; } static void qla_heart_beat(struct scsi_qla_host *vha) { + struct qla_hw_data *ha = vha->hw; + if (vha->vp_idx) return; if (vha->hw->flags.eeh_busy || qla2x00_chip_is_down(vha)) return; - if (qla_do_heartbeat(vha)) { - set_bit(HEARTBEAT_CHK, &vha->dpc_flags); - qla2xxx_wake_dpc(vha); - } + if (qla_do_heartbeat(vha)) + queue_work(ha->wq, &ha->heartbeat_work); } /************************************************************************** -- cgit From 3d33b303d4f3b74a71bede5639ebba3cfd2a2b4d Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Wed, 8 Sep 2021 09:46:21 -0700 Subject: scsi: qla2xxx: Fix use after free in eh_abort path In eh_abort path driver prematurely exits the call to upper layer. Check whether command is aborted / completed by firmware before exiting the call. 9 [ffff8b1ebf803c00] page_fault at ffffffffb0389778 [exception RIP: qla2x00_status_entry+0x48d] RIP: ffffffffc04fa62d RSP: ffff8b1ebf803cb0 RFLAGS: 00010082 RAX: 00000000ffffffff RBX: 00000000000e0000 RCX: 0000000000000000 RDX: 0000000000000000 RSI: 00000000000013d8 RDI: fffff3253db78440 RBP: ffff8b1ebf803dd0 R8: ffff8b1ebcd9b0c0 R9: 0000000000000000 R10: ffff8b1e38a30808 R11: 0000000000001000 R12: 00000000000003e9 R13: 0000000000000000 R14: ffff8b1ebcd9d740 R15: 0000000000000028 ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 10 [ffff8b1ebf803cb0] enqueue_entity at ffffffffafce708f 11 [ffff8b1ebf803d00] enqueue_task_fair at ffffffffafce7b88 12 [ffff8b1ebf803dd8] qla24xx_process_response_queue at ffffffffc04fc9a6 [qla2xxx] 13 [ffff8b1ebf803e78] qla24xx_msix_rsp_q at ffffffffc04ff01b [qla2xxx] 14 [ffff8b1ebf803eb0] __handle_irq_event_percpu at ffffffffafd50714 Link: https://lore.kernel.org/r/20210908164622.19240-10-njavali@marvell.com Fixes: f45bca8c5052 ("scsi: qla2xxx: Fix double scsi_done for abort path") Cc: stable@vger.kernel.org Reviewed-by: Himanshu Madhani Co-developed-by: David Jeffery Signed-off-by: David Jeffery Co-developed-by: Laurence Oberman Signed-off-by: Laurence Oberman Signed-off-by: Quinn Tran Signed-off-by: Nilesh Javali Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_os.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 0c446438dcd3..03ff2596715b 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1258,6 +1258,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) uint32_t ratov_j; struct qla_qpair *qpair; unsigned long flags; + int fast_fail_status = SUCCESS; if (qla2x00_isp_reg_stat(ha)) { ql_log(ql_log_info, vha, 0x8042, @@ -1266,9 +1267,10 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) return FAILED; } + /* Save any FAST_IO_FAIL value to return later if abort succeeds */ ret = fc_block_scsi_eh(cmd); if (ret != 0) - return ret; + fast_fail_status = ret; sp = scsi_cmd_priv(cmd); qpair = sp->qpair; @@ -1276,7 +1278,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) vha->cmd_timeout_cnt++; if ((sp->fcport && sp->fcport->deleted) || !qpair) - return SUCCESS; + return fast_fail_status != SUCCESS ? fast_fail_status : FAILED; spin_lock_irqsave(qpair->qp_lock_ptr, flags); sp->comp = ∁ @@ -1311,7 +1313,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) __func__, ha->r_a_tov/10); ret = FAILED; } else { - ret = SUCCESS; + ret = fast_fail_status; } break; default: -- cgit From b0fe235dad775d267d75aa19c0ce61fa527a287f Mon Sep 17 00:00:00 2001 From: Nilesh Javali Date: Wed, 8 Sep 2021 09:46:22 -0700 Subject: scsi: qla2xxx: Update version to 10.02.07.100-k Link: https://lore.kernel.org/r/20210908164622.19240-11-njavali@marvell.com Reviewed-by: Himanshu Madhani Signed-off-by: Nilesh Javali Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_version.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 055040cbef9b..4b117165bf8b 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -6,9 +6,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "10.02.06.200-k" +#define QLA2XXX_VERSION "10.02.07.100-k" #define QLA_DRIVER_MAJOR_VER 10 #define QLA_DRIVER_MINOR_VER 2 -#define QLA_DRIVER_PATCH_VER 6 -#define QLA_DRIVER_BETA_VER 200 +#define QLA_DRIVER_PATCH_VER 7 +#define QLA_DRIVER_BETA_VER 100 -- cgit From 914418f3690177b600f5b0d91e1902ab7332536d Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 10 Sep 2021 12:46:10 +0100 Subject: scsi: qla2xxx: Remove redundant initialization of pointer req The pointer req is being initialized with a value that is never read, it is being updated later on. The assignment is redundant and can be removed. Link: https://lore.kernel.org/r/20210910114610.44752-1-colin.king@canonical.com Reviewed-by: Himanshu Madhani Signed-off-by: Colin Ian King Signed-off-by: Martin K. Petersen Addresses-Coverity: ("Unused value") --- drivers/scsi/qla2xxx/qla_mbx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 9eb41dd39043..73a353153d33 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -3236,7 +3236,7 @@ qla24xx_abort_command(srb_t *sp) fc_port_t *fcport = sp->fcport; struct scsi_qla_host *vha = fcport->vha; struct qla_hw_data *ha = vha->hw; - struct req_que *req = vha->req; + struct req_que *req; struct qla_qpair *qpair = sp->qpair; ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x108c, -- cgit From 99154581b05c8fb22607afb7c3d66c1bace6aa5d Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 10 Sep 2021 16:31:46 -0700 Subject: scsi: lpfc: Fix list_add() corruption in lpfc_drain_txq() When parsing the txq list in lpfc_drain_txq(), the driver attempts to pass the requests to the adapter. If such an attempt fails, a local "fail_msg" string is set and a log message output. The job is then added to a completions list for cancellation. Processing of any further jobs from the txq list continues, but since "fail_msg" remains set, jobs are added to the completions list regardless of whether a wqe was passed to the adapter. If successfully added to txcmplq, jobs are added to both lists resulting in list corruption. Fix by clearing the fail_msg string after adding a job to the completions list. This stops the subsequent jobs from being added to the completions list unless they had an appropriate failure. Link: https://lore.kernel.org/r/20210910233159.115896-2-jsmart2021@gmail.com Co-developed-by: Justin Tee Signed-off-by: Justin Tee Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index ffd8a140638c..546c851938bc 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -21104,6 +21104,7 @@ lpfc_drain_txq(struct lpfc_hba *phba) fail_msg, piocbq->iotag, piocbq->sli4_xritag); list_add_tail(&piocbq->list, &completions); + fail_msg = NULL; } spin_unlock_irqrestore(&pring->ring_lock, iflags); } -- cgit From 982fc3965d1350d3332e04046b0e101006184ba9 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 10 Sep 2021 16:31:47 -0700 Subject: scsi: lpfc: Don't release final kref on Fport node while ABTS outstanding In a rarely executed path, FLOGI failure, there is a refcounting error. If FLOGI completed with an error, typically a timeout, the initial completion handler would remove the job reference. However, the job completion isn't the actual end of the job/exchange as the timeout usually initiates an ABTS, and upon that ABTS completion, a final completion is sent. The driver removes the reference again in the final completion. Thus the imbalance. In the buggy cases, if there was a link bounce while the delayed response is outstanding, the fport node may be referenced again but there was no additional reference as it is already present. The delayed completion then occurs and removes the last reference freeing the node and causing issues in the link up processed that is using the node. Fix this scenario by removing the snippet that removed the reference in the initial FLOGI completion. The bad snippet was poorly trying to identify the FLOGI as OK to do so by realizing the node was not registered with either SCSI or NVMe transport. Link: https://lore.kernel.org/r/20210910233159.115896-3-jsmart2021@gmail.com Fixes: 618e2ee146d4 ("scsi: lpfc: Fix FLOGI failure due to accessing a freed node") Cc: # v5.13+ Co-developed-by: Justin Tee Signed-off-by: Justin Tee Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 11 +++++------ drivers/scsi/lpfc/lpfc_hbadisc.c | 10 ++++++---- drivers/scsi/lpfc/lpfc_nvme.c | 5 +++-- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 1254a575fd47..df5fc223ddb2 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1059,9 +1059,10 @@ stop_rr_fcf_flogi: lpfc_printf_vlog(vport, KERN_WARNING, LOG_TRACE_EVENT, "0150 FLOGI failure Status:x%x/x%x " - "xri x%x TMO:x%x\n", + "xri x%x TMO:x%x refcnt %d\n", irsp->ulpStatus, irsp->un.ulpWord[4], - cmdiocb->sli4_xritag, irsp->ulpTimeout); + cmdiocb->sli4_xritag, irsp->ulpTimeout, + kref_read(&ndlp->kref)); /* If this is not a loop open failure, bail out */ if (!(irsp->ulpStatus == IOSTAT_LOCAL_REJECT && @@ -1122,12 +1123,12 @@ stop_rr_fcf_flogi: /* FLOGI completes successfully */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0101 FLOGI completes successfully, I/O tag:x%x, " - "xri x%x Data: x%x x%x x%x x%x x%x x%x x%x\n", + "xri x%x Data: x%x x%x x%x x%x x%x x%x x%x %d\n", cmdiocb->iotag, cmdiocb->sli4_xritag, irsp->un.ulpWord[4], sp->cmn.e_d_tov, sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution, vport->port_state, vport->fc_flag, - sp->cmn.priority_tagging); + sp->cmn.priority_tagging, kref_read(&ndlp->kref)); if (sp->cmn.priority_tagging) vport->vmid_flag |= LPFC_VMID_ISSUE_QFPA; @@ -1205,8 +1206,6 @@ flogifail: phba->fcf.fcf_flag &= ~FCF_DISCOVERY; spin_unlock_irq(&phba->hbalock); - if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD))) - lpfc_nlp_put(ndlp); if (!lpfc_error_lost_link(irsp)) { /* FLOGI failed, so just use loop map to make discovery list */ lpfc_disc_list_loopmap(vport); diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 7195ca0275f9..6f2e07c30f98 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -4449,8 +4449,9 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) fc_remote_port_rolechg(rport, rport_ids.roles); lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, - "3183 %s rport x%px DID x%x, role x%x\n", - __func__, rport, rport->port_id, rport->roles); + "3183 %s rport x%px DID x%x, role x%x refcnt %d\n", + __func__, rport, rport->port_id, rport->roles, + kref_read(&ndlp->kref)); if ((rport->scsi_target_id != -1) && (rport->scsi_target_id < LPFC_MAX_TARGET)) { @@ -4475,8 +4476,9 @@ lpfc_unregister_remote_port(struct lpfc_nodelist *ndlp) lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, "3184 rport unregister x%06x, rport x%px " - "xptflg x%x\n", - ndlp->nlp_DID, rport, ndlp->fc4_xpt_flags); + "xptflg x%x refcnt %d\n", + ndlp->nlp_DID, rport, ndlp->fc4_xpt_flags, + kref_read(&ndlp->kref)); fc_remote_port_delete(rport); lpfc_nlp_put(ndlp); diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index 73a3568ff17e..bd88477f9b82 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -209,8 +209,9 @@ lpfc_nvme_remoteport_delete(struct nvme_fc_remote_port *remoteport) * calling state machine to remove the node. */ lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, - "6146 remoteport delete of remoteport x%px\n", - remoteport); + "6146 remoteport delete of remoteport x%px, ndlp x%px " + "DID x%x xflags x%x\n", + remoteport, ndlp, ndlp->nlp_DID, ndlp->fc4_xpt_flags); spin_lock_irq(&ndlp->lock); /* The register rebind might have occurred before the delete -- cgit From 20d2279f90ce87f1d08d2e7ad885a3dcc0678331 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 10 Sep 2021 16:31:48 -0700 Subject: scsi: lpfc: Fix premature rpi release for unsolicited TPLS and LS_RJT A test scenario has a target issuing a TPLS after accepting the driver's PRLI. TPLS is not supported by the driver so it rejects the ELS. However, the reject was only happening on the primary N_Port. If the TPLS was to a NPIV vport, not only would it reject the ELS, but it would act on the TPLS, starting devloss, then unregister from the SCSI transport and release the node. When devloss expired, it would access the node again and cause a page faul. Fix by altering the NPIV code to recognize that a correctly registered node can reject unsolicited ELS I/O and to not unregister with the SCSI transport and tear the node down. Add a check of the fc4_xpt_flags so that only a zero value allows the unreg and teardown. Link: https://lore.kernel.org/r/20210910233159.115896-4-jsmart2021@gmail.com Co-developed-by: Justin Tee Signed-off-by: Justin Tee Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index df5fc223ddb2..262101e172ad 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -5295,6 +5295,7 @@ out: */ if (phba->sli_rev == LPFC_SLI_REV4 && (vport && vport->port_type == LPFC_NPIV_PORT) && + !(ndlp->fc4_xpt_flags & SCSI_XPT_REGD) && ndlp->nlp_flag & NLP_RELEASE_RPI) { lpfc_sli4_free_rpi(phba, ndlp->nlp_rpi); spin_lock_irq(&ndlp->lock); @@ -5598,11 +5599,12 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError, } /* The NPIV instance is rejecting this unsolicited ELS. Make sure the - * node's assigned RPI needs to be released as this node will get - * freed. + * node's assigned RPI gets released provided this node is not already + * registered with the transport. */ if (phba->sli_rev == LPFC_SLI_REV4 && - vport->port_type == LPFC_NPIV_PORT) { + vport->port_type == LPFC_NPIV_PORT && + !(ndlp->fc4_xpt_flags & SCSI_XPT_REGD)) { spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_RELEASE_RPI; spin_unlock_irq(&ndlp->lock); -- cgit From 88f7702984e6e562223ecc07c38ac4e61713780a Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 10 Sep 2021 16:31:49 -0700 Subject: scsi: lpfc: Fix hang on unload due to stuck fport node A test scenario encountered an unload hang while an FLOGI ELS was in flight when a link down condition occurred. The driver fails unload as it never releases the fport node. For most nodes, when the link drops, devloss tmo is started and the timeout will cause the final node release. For the Fport, as it has not yet registered with the SCSI transport, there is no devloss timer to be started, so there is no final release. Additionally, the link down sequence causes ABORTS to be issued for pending ELS's. The completions from the ABORTS perform the release of node references. However, as the adapter is being reset to be unloaded, those completions will never occur. Fix by the following: - In the ELS cleanup, recognize when unloading and place the ELS's on a different list that immediately cleans up/completes the ELS's. It's recognized that this condition primarily affects only the fport, with other ports having normal clean up logic that handles things. - Resolve the devloss issue by, when cleaning up nodes on after link down, recognizing when the fabric node does not have a completed state (its state is UNUSED) and removing a reference so the node can delete after the ELS reference is released. Link: https://lore.kernel.org/r/20210910233159.115896-5-jsmart2021@gmail.com Co-developed-by: Justin Tee Signed-off-by: Justin Tee Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 14 ++++++++++++++ drivers/scsi/lpfc/lpfc_hbadisc.c | 14 +++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 262101e172ad..6c9cb87ef174 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -11386,6 +11386,7 @@ lpfc_sli4_vport_delete_els_xri_aborted(struct lpfc_vport *vport) { struct lpfc_hba *phba = vport->phba; struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL; + struct lpfc_nodelist *ndlp = NULL; unsigned long iflag = 0; spin_lock_irqsave(&phba->sli4_hba.sgl_list_lock, iflag); @@ -11393,7 +11394,20 @@ lpfc_sli4_vport_delete_els_xri_aborted(struct lpfc_vport *vport) &phba->sli4_hba.lpfc_abts_els_sgl_list, list) { if (sglq_entry->ndlp && sglq_entry->ndlp->vport == vport) { lpfc_nlp_put(sglq_entry->ndlp); + ndlp = sglq_entry->ndlp; sglq_entry->ndlp = NULL; + + /* If the xri on the abts_els_sgl list is for the Fport + * node and the vport is unloading, the xri aborted wcqe + * likely isn't coming back. Just release the sgl. + */ + if ((vport->load_flag & FC_UNLOADING) && + ndlp->nlp_DID == Fabric_DID) { + list_del(&sglq_entry->list); + sglq_entry->state = SGL_FREED; + list_add_tail(&sglq_entry->list, + &phba->sli4_hba.lpfc_els_sgl_list); + } } } spin_unlock_irqrestore(&phba->sli4_hba.sgl_list_lock, iflag); diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 6f2e07c30f98..4ff93aef3295 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -966,8 +966,20 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) struct lpfc_nodelist *ndlp, *next_ndlp; list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) + if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) { + /* It's possible the FLOGI to the fabric node never + * successfully completed and never registered with the + * transport. In this case there is no way to clean up + * the node. + */ + if (ndlp->nlp_DID == Fabric_DID) { + if (ndlp->nlp_prev_state == + NLP_STE_UNUSED_NODE && + !ndlp->fc4_xpt_flags) + lpfc_nlp_put(ndlp); + } continue; + } if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) || ((vport->port_type == LPFC_NPIV_PORT) && -- cgit From 3a874488d2e936340e165070a41508208d816fc3 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 10 Sep 2021 16:31:50 -0700 Subject: scsi: lpfc: Fix rediscovery of tape device after LIP On link up and node discovery, a remote port is registered with the SCSI transport and the driver sets fc4_xpt_flags to track transport registration. A link down event causes the driver to deregister with the SCSI transport, starting the devloss timer, and calls a local unreg routine to clear the login state. Part of the login state is the fc4_xpt_flags. However, with tape devices that support sequence level error recovery, which wants to preserve the login, the local unreg routine is skipped, thus the flags aren't cleared. A subsequent link up, ADISC is performed and the lpfc_nlp_reg_node() routine is called. As the fc4_xpt_flags is not clear, it's believed the node is already registered with the transport. Unfortunately, the registration was already terminated. Eventually the devloss tmo timer expires and tears down the device. Fix by ensuring the tape device, known by the ADISC flag, is always unregistered if the link drops. Link: https://lore.kernel.org/r/20210910233159.115896-6-jsmart2021@gmail.com Co-developed-by: Justin Tee Signed-off-by: Justin Tee Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_hbadisc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 4ff93aef3295..12abfc027a67 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -4693,8 +4693,11 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* Reg/Unreg for FCP and NVME Transport interface */ if ((old_state == NLP_STE_MAPPED_NODE || old_state == NLP_STE_UNMAPPED_NODE)) { - /* For nodes marked for ADISC, Handle unreg in ADISC cmpl */ - if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) + /* For nodes marked for ADISC, Handle unreg in ADISC cmpl + * if linkup. In linkdown do unreg_node + */ + if (!(ndlp->nlp_flag & NLP_NPR_ADISC) || + !lpfc_is_link_up(vport->phba)) lpfc_nlp_unreg_node(vport, ndlp); } -- cgit From a864ee709bc06095463c61fc22a4dc899fba1758 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 10 Sep 2021 16:31:51 -0700 Subject: scsi: lpfc: Don't remove ndlp on PRLI errors in P2P mode In pt-2-pt mode, the initiator does not log into the target after a PRLI error. In pt-2-pt mode, the target responded to the PRLI by sending a LOGO. The LOGO causes all ELS and I/Os to be aborted. This caused the PRLI to fail. The PRLI completion path caused the discovery node to be dropped to avoid being stick in an UNUSED (not logged in) state. As the node was dropped there is no retry of the login and as it is pt-2-pt, there is no RSCN to retrigger discovery. Thus the other end is not seen by the OS. Fix by ensuring the discovery node is not dropped if connecting pt-2-pt. This will cause PLOGI to be retried. Link: https://lore.kernel.org/r/20210910233159.115896-7-jsmart2021@gmail.com Co-developed-by: Justin Tee Signed-off-by: Justin Tee Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 6c9cb87ef174..c6eae545aabf 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -2329,6 +2329,13 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_disc_state_machine(vport, ndlp, cmdiocb, NLP_EVT_CMPL_PRLI); + /* + * For P2P topology, retain the node so that PLOGI can be + * attempted on it again. + */ + if (vport->fc_flag & FC_PT2PT) + goto out; + /* As long as this node is not registered with the SCSI * or NVMe transport and no other PRLIs are outstanding, * it is no longer an active node. Otherwise devloss -- cgit From b507357f79171fb4fb4e732ca43a1f30bc5aab1d Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 10 Sep 2021 16:31:52 -0700 Subject: scsi: lpfc: Fix NVMe I/O failover to non-optimized path Currently, we hold off unregistering with NVMe transport layer until GID_FT or ADISC completes upon receipt of RSCN. In the ADISC discovery routine, for nodes not found in the GID_FT response, the nodes are unregistered from the SCSI transport but not UNREG_RPI'd. Meaning outstanding WQEs continue to be outstanding and were not failed back to the OS. If an NVMe device, this mean there wasn't initial termination of the I/Os so they could be issued on a different NVMe path. Fix by unregistering the RPI so that I/O is cancelled. Link: https://lore.kernel.org/r/20210910233159.115896-8-jsmart2021@gmail.com Fixes: 0614568361b0 ("scsi: lpfc: Delay unregistering from transport until GIDFT or ADISC completes") Co-developed-by: Justin Tee Signed-off-by: Justin Tee Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index c6eae545aabf..40d166aeb466 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -6224,6 +6224,7 @@ lpfc_els_disc_adisc(struct lpfc_vport *vport) * from backend */ lpfc_nlp_unreg_node(vport, ndlp); + lpfc_unreg_rpi(vport, ndlp); continue; } -- cgit From cd8a36a90babf958082b87bc6b4df5dd70901eba Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 10 Sep 2021 16:31:53 -0700 Subject: scsi: lpfc: Fix FCP I/O flush functionality for TMF routines A prior patch inadvertently caused lpfc_sli_sum_iocb() to exclude counting of outstanding aborted I/Os and ABORT IOCBs. Thus, lpfc_reset_flush_io_context() called from any TMF routine does not properly wait to flush all outstanding FCP IOCBs leading to a block layer crash on an invalid scsi_cmnd->request pointer. kernel BUG at ../block/blk-core.c:1489! RIP: 0010:blk_requeue_request+0xaf/0xc0 ... Call Trace: __scsi_queue_insert+0x90/0xe0 [scsi_mod] blk_done_softirq+0x7e/0x90 __do_softirq+0xd2/0x280 irq_exit+0xd5/0xe0 do_IRQ+0x4c/0xd0 common_interrupt+0x87/0x87 Fix by separating out the LPFC_IO_FCP, LPFC_IO_ON_TXCMPLQ, LPFC_DRIVER_ABORTED, and CMD_ABORT_XRI_CN || CMD_CLOSE_XRI_CN checks into a new lpfc_sli_validate_fcp_iocb_for_abort() routine when determining to build an ABORT iocb. Restore lpfc_reset_flush_io_context() functionality by including counting of outstanding aborted IOCBs and ABORT IOCBs in lpfc_sli_sum_iocb(). Link: https://lore.kernel.org/r/20210910233159.115896-9-jsmart2021@gmail.com Fixes: e1364711359f ("scsi: lpfc: Fix illegal memory access on Abort IOCBs") Cc: # v5.12+ Co-developed-by: Justin Tee Signed-off-by: Justin Tee Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 101 +++++++++++++++++++++++++++++++++---------- 1 file changed, 78 insertions(+), 23 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 546c851938bc..e8f6ad484768 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -12485,15 +12485,54 @@ lpfc_sli_hba_iocb_abort(struct lpfc_hba *phba) } /** - * lpfc_sli_validate_fcp_iocb - find commands associated with a vport or LUN + * lpfc_sli_validate_fcp_iocb_for_abort - filter iocbs appropriate for FCP aborts + * @iocbq: Pointer to iocb object. + * @vport: Pointer to driver virtual port object. + * + * This function acts as an iocb filter for functions which abort FCP iocbs. + * + * Return values + * -ENODEV, if a null iocb or vport ptr is encountered + * -EINVAL, if the iocb is not an FCP I/O, not on the TX cmpl queue, premarked as + * driver already started the abort process, or is an abort iocb itself + * 0, passes criteria for aborting the FCP I/O iocb + **/ +static int +lpfc_sli_validate_fcp_iocb_for_abort(struct lpfc_iocbq *iocbq, + struct lpfc_vport *vport) +{ + IOCB_t *icmd = NULL; + + /* No null ptr vports */ + if (!iocbq || iocbq->vport != vport) + return -ENODEV; + + /* iocb must be for FCP IO, already exists on the TX cmpl queue, + * can't be premarked as driver aborted, nor be an ABORT iocb itself + */ + icmd = &iocbq->iocb; + if (!(iocbq->iocb_flag & LPFC_IO_FCP) || + !(iocbq->iocb_flag & LPFC_IO_ON_TXCMPLQ) || + (iocbq->iocb_flag & LPFC_DRIVER_ABORTED) || + (icmd->ulpCommand == CMD_ABORT_XRI_CN || + icmd->ulpCommand == CMD_CLOSE_XRI_CN)) + return -EINVAL; + + return 0; +} + +/** + * lpfc_sli_validate_fcp_iocb - validate commands associated with a SCSI target * @iocbq: Pointer to driver iocb object. * @vport: Pointer to driver virtual port object. * @tgt_id: SCSI ID of the target. * @lun_id: LUN ID of the scsi device. * @ctx_cmd: LPFC_CTX_LUN/LPFC_CTX_TGT/LPFC_CTX_HOST * - * This function acts as an iocb filter for functions which abort or count - * all FCP iocbs pending on a lun/SCSI target/SCSI host. It will return + * This function acts as an iocb filter for validating a lun/SCSI target/SCSI + * host. + * + * It will return * 0 if the filtering criteria is met for the given iocb and will return * 1 if the filtering criteria is not met. * If ctx_cmd == LPFC_CTX_LUN, the function returns 0 only if the @@ -12512,22 +12551,8 @@ lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, struct lpfc_vport *vport, lpfc_ctx_cmd ctx_cmd) { struct lpfc_io_buf *lpfc_cmd; - IOCB_t *icmd = NULL; int rc = 1; - if (!iocbq || iocbq->vport != vport) - return rc; - - if (!(iocbq->iocb_flag & LPFC_IO_FCP) || - !(iocbq->iocb_flag & LPFC_IO_ON_TXCMPLQ) || - iocbq->iocb_flag & LPFC_DRIVER_ABORTED) - return rc; - - icmd = &iocbq->iocb; - if (icmd->ulpCommand == CMD_ABORT_XRI_CN || - icmd->ulpCommand == CMD_CLOSE_XRI_CN) - return rc; - lpfc_cmd = container_of(iocbq, struct lpfc_io_buf, cur_iocbq); if (lpfc_cmd->pCmd == NULL) @@ -12582,17 +12607,33 @@ lpfc_sli_sum_iocb(struct lpfc_vport *vport, uint16_t tgt_id, uint64_t lun_id, { struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *iocbq; + IOCB_t *icmd = NULL; int sum, i; + unsigned long iflags; - spin_lock_irq(&phba->hbalock); + spin_lock_irqsave(&phba->hbalock, iflags); for (i = 1, sum = 0; i <= phba->sli.last_iotag; i++) { iocbq = phba->sli.iocbq_lookup[i]; - if (lpfc_sli_validate_fcp_iocb (iocbq, vport, tgt_id, lun_id, - ctx_cmd) == 0) + if (!iocbq || iocbq->vport != vport) + continue; + if (!(iocbq->iocb_flag & LPFC_IO_FCP) || + !(iocbq->iocb_flag & LPFC_IO_ON_TXCMPLQ)) + continue; + + /* Include counting outstanding aborts */ + icmd = &iocbq->iocb; + if (icmd->ulpCommand == CMD_ABORT_XRI_CN || + icmd->ulpCommand == CMD_CLOSE_XRI_CN) { + sum++; + continue; + } + + if (lpfc_sli_validate_fcp_iocb(iocbq, vport, tgt_id, lun_id, + ctx_cmd) == 0) sum++; } - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, iflags); return sum; } @@ -12659,7 +12700,11 @@ lpfc_sli_abort_fcp_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * * This function sends an abort command for every SCSI command * associated with the given virtual port pending on the ring - * filtered by lpfc_sli_validate_fcp_iocb function. + * filtered by lpfc_sli_validate_fcp_iocb_for_abort and then + * lpfc_sli_validate_fcp_iocb function. The ordering for validation before + * submitting abort iocbs must be lpfc_sli_validate_fcp_iocb_for_abort + * followed by lpfc_sli_validate_fcp_iocb. + * * When abort_cmd == LPFC_CTX_LUN, the function sends abort only to the * FCP iocbs associated with lun specified by tgt_id and lun_id * parameters @@ -12691,6 +12736,9 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, u16 tgt_id, u64 lun_id, for (i = 1; i <= phba->sli.last_iotag; i++) { iocbq = phba->sli.iocbq_lookup[i]; + if (lpfc_sli_validate_fcp_iocb_for_abort(iocbq, vport)) + continue; + if (lpfc_sli_validate_fcp_iocb(iocbq, vport, tgt_id, lun_id, abort_cmd) != 0) continue; @@ -12723,7 +12771,11 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, u16 tgt_id, u64 lun_id, * * This function sends an abort command for every SCSI command * associated with the given virtual port pending on the ring - * filtered by lpfc_sli_validate_fcp_iocb function. + * filtered by lpfc_sli_validate_fcp_iocb_for_abort and then + * lpfc_sli_validate_fcp_iocb function. The ordering for validation before + * submitting abort iocbs must be lpfc_sli_validate_fcp_iocb_for_abort + * followed by lpfc_sli_validate_fcp_iocb. + * * When taskmgmt_cmd == LPFC_CTX_LUN, the function sends abort only to the * FCP iocbs associated with lun specified by tgt_id and lun_id * parameters @@ -12761,6 +12813,9 @@ lpfc_sli_abort_taskmgmt(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, for (i = 1; i <= phba->sli.last_iotag; i++) { iocbq = phba->sli.iocbq_lookup[i]; + if (lpfc_sli_validate_fcp_iocb_for_abort(iocbq, vport)) + continue; + if (lpfc_sli_validate_fcp_iocb(iocbq, vport, tgt_id, lun_id, cmd) != 0) continue; -- cgit From 25ac2c970be32993f1dff607f8354f3c053d42bc Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 10 Sep 2021 16:31:54 -0700 Subject: scsi: lpfc: Fix EEH support for NVMe I/O Injecting errors on the PCI slot while the driver is handling NVMe I/O will cause crashes and hangs. There are several rather difficult scenarios occurring. The main issue is that the adapter can report a PCI error before or simultaneously to the PCI subsystem reporting the error. Both paths have different entry points and currently there is no interlock between them. Thus multiple teardown paths are competing and all heck breaks loose. Complicating things is the NVMs path. To a large degree, I/O was able to be shutdown for a full FC port on the SCSI stack. But on NVMe, there isn't a similar call. At best, it works on a per-controller basis, but even at the controller level, it's a controller "reset" call. All of which means I/O is still flowing on different CPUs with reset paths expecting hw access (mailbox commands) to execute properly. The following modifications are made: - A new flag is set in PCI error entrypoints so the driver can track being called by that path. - An interlock is added in the SLI hw error path and the PCI error path such that only one of the paths proceeds with the teardown logic. - RPI cleanup is patched such that RPIs are marked unregistered w/o mbx cmds in cases of hw error. - If entering the SLI port re-init calls, a case where SLI error teardown was quick and beat the PCI calls now reporting error, check whether the SLI port is still live on the PCI bus. - In the PCI reset code to bring the adapter back, recheck the IRQ settings. Different checks for SLI3 vs SLI4. - In I/O completions, that may be called as part of the cleanup or underway just before the hw error, check the state of the adapter. If in error, shortcut handling that would expect further adapter completions as the hw error won't be sending them. - In routines waiting on I/O completions, which may have been in progress prior to the hw error, detect the device is being torn down and abort from their waits and just give up. This points to a larger issue in the driver on ref-counting for data structures, as it doesn't have ref-counting on q and port structures. We'll do this fix for now as it would be a major rework to be done differently. - Fix the NVMe cleanup to simulate NVMe I/O completions if I/O is being failed back due to hw error. - In I/O buf allocation, done at the start of new I/Os, check hw state and fail if hw error. Link: https://lore.kernel.org/r/20210910233159.115896-10-jsmart2021@gmail.com Co-developed-by: Justin Tee Signed-off-by: Justin Tee Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 1 + drivers/scsi/lpfc/lpfc_hbadisc.c | 1 + drivers/scsi/lpfc/lpfc_init.c | 31 ++++++++++++++++++-- drivers/scsi/lpfc/lpfc_nvme.c | 53 +++++++++++++++++++++++++++++++-- drivers/scsi/lpfc/lpfc_scsi.c | 63 ++++++++++++++++++++++++++-------------- drivers/scsi/lpfc/lpfc_sli.c | 31 ++++++++++++++++++-- drivers/scsi/lpfc/lpfc_sli4.h | 2 ++ 7 files changed, 154 insertions(+), 28 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index befeb7c34290..2f6b81bc2451 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -1028,6 +1028,7 @@ struct lpfc_hba { * Firmware supports Forced Link Speed * capability */ +#define HBA_PCI_ERR 0x80000 /* The PCI slot is offline */ #define HBA_FLOGI_ISSUED 0x100000 /* FLOGI was issued */ #define HBA_CGN_RSVD1 0x200000 /* Reserved CGN flag */ #define HBA_CGN_DAY_WRAP 0x400000 /* HBA Congestion info day wraps */ diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 12abfc027a67..0b1e1cc00e01 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -5250,6 +5250,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { + ndlp->nlp_flag &= ~NLP_UNREG_INP; mempool_free(mbox, phba->mbox_mem_pool); acc_plogi = 1; } diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 0ec322f0e3cb..3fd730613de3 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1606,6 +1606,11 @@ void lpfc_sli4_offline_eratt(struct lpfc_hba *phba) { spin_lock_irq(&phba->hbalock); + if (phba->link_state == LPFC_HBA_ERROR && + phba->hba_flag & HBA_PCI_ERR) { + spin_unlock_irq(&phba->hbalock); + return; + } phba->link_state = LPFC_HBA_ERROR; spin_unlock_irq(&phba->hbalock); @@ -1945,7 +1950,6 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) if (pci_channel_offline(phba->pcidev)) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3166 pci channel is offline\n"); - lpfc_sli4_offline_eratt(phba); return; } @@ -3643,6 +3647,7 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action) struct lpfc_vport **vports; struct Scsi_Host *shost; int i; + int offline = 0; if (vport->fc_flag & FC_OFFLINE_MODE) return; @@ -3651,6 +3656,8 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action) lpfc_linkdown(phba); + offline = pci_channel_offline(phba->pcidev); + /* Issue an unreg_login to all nodes on all vports */ vports = lpfc_create_vport_work_array(phba); if (vports != NULL) { @@ -3673,7 +3680,14 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action) ndlp->nlp_flag &= ~NLP_NPR_ADISC; spin_unlock_irq(&ndlp->lock); - lpfc_unreg_rpi(vports[i], ndlp); + if (offline) { + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag &= ~(NLP_UNREG_INP | + NLP_RPI_REGISTERED); + spin_unlock_irq(&ndlp->lock); + } else { + lpfc_unreg_rpi(vports[i], ndlp); + } /* * Whenever an SLI4 port goes offline, free the * RPI. Get a new RPI when the adapter port @@ -14080,6 +14094,10 @@ lpfc_pci_resume_one_s3(struct device *dev_d) return error; } + /* Init cpu_map array */ + lpfc_cpu_map_array_init(phba); + /* Init hba_eq_hdl array */ + lpfc_hba_eq_hdl_array_init(phba); /* Configure and enable interrupt */ intr_mode = lpfc_sli_enable_intr(phba, phba->intr_mode); if (intr_mode == LPFC_INTR_ERROR) { @@ -15033,14 +15051,17 @@ lpfc_io_error_detected_s4(struct pci_dev *pdev, pci_channel_state_t state) lpfc_sli4_prep_dev_for_recover(phba); return PCI_ERS_RESULT_CAN_RECOVER; case pci_channel_io_frozen: + phba->hba_flag |= HBA_PCI_ERR; /* Fatal error, prepare for slot reset */ lpfc_sli4_prep_dev_for_reset(phba); return PCI_ERS_RESULT_NEED_RESET; case pci_channel_io_perm_failure: + phba->hba_flag |= HBA_PCI_ERR; /* Permanent failure, prepare for device down */ lpfc_sli4_prep_dev_for_perm_failure(phba); return PCI_ERS_RESULT_DISCONNECT; default: + phba->hba_flag |= HBA_PCI_ERR; /* Unknown state, prepare and request slot reset */ lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2825 Unknown PCI error state: x%x\n", state); @@ -15084,6 +15105,7 @@ lpfc_io_slot_reset_s4(struct pci_dev *pdev) pci_restore_state(pdev); + phba->hba_flag &= ~HBA_PCI_ERR; /* * As the new kernel behavior of pci_restore_state() API call clears * device saved_state flag, need to save the restored state again. @@ -15106,6 +15128,7 @@ lpfc_io_slot_reset_s4(struct pci_dev *pdev) return PCI_ERS_RESULT_DISCONNECT; } else phba->intr_mode = intr_mode; + lpfc_cpu_affinity_check(phba, phba->cfg_irq_chann); /* Log the current active interrupt mode */ lpfc_log_intr_mode(phba, phba->intr_mode); @@ -15307,6 +15330,10 @@ lpfc_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; pci_ers_result_t rc = PCI_ERS_RESULT_DISCONNECT; + if (phba->link_state == LPFC_HBA_ERROR && + phba->hba_flag & HBA_IOQ_FLUSH) + return PCI_ERS_RESULT_NEED_RESET; + switch (phba->pci_dev_grp) { case LPFC_PCI_DEV_LP: rc = lpfc_io_error_detected_s3(pdev, state); diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index bd88477f9b82..33266e1b24ab 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -937,6 +937,7 @@ lpfc_nvme_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, #ifdef CONFIG_SCSI_LPFC_DEBUG_FS int cpu; #endif + int offline = 0; /* Sanity check on return of outstanding command */ if (!lpfc_ncmd) { @@ -1098,11 +1099,12 @@ out_err: nCmd->transferred_length = 0; nCmd->rcv_rsplen = 0; nCmd->status = NVME_SC_INTERNAL; + offline = pci_channel_offline(vport->phba->pcidev); } } /* pick up SLI4 exhange busy condition */ - if (bf_get(lpfc_wcqe_c_xb, wcqe)) + if (bf_get(lpfc_wcqe_c_xb, wcqe) && !offline) lpfc_ncmd->flags |= LPFC_SBUF_XBUSY; else lpfc_ncmd->flags &= ~LPFC_SBUF_XBUSY; @@ -2169,6 +2171,10 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, abts_nvme = 0; for (i = 0; i < phba->cfg_hdw_queue; i++) { qp = &phba->sli4_hba.hdwq[i]; + if (!vport || !vport->localport || + !qp || !qp->io_wq) + return; + pring = qp->io_wq->pring; if (!pring) continue; @@ -2176,6 +2182,10 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, abts_scsi += qp->abts_scsi_io_bufs; abts_nvme += qp->abts_nvme_io_bufs; } + if (!vport || !vport->localport || + vport->phba->hba_flag & HBA_PCI_ERR) + return; + lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6176 Lport x%px Localport x%px wait " "timed out. Pending %d [%d:%d]. " @@ -2215,6 +2225,8 @@ lpfc_nvme_destroy_localport(struct lpfc_vport *vport) return; localport = vport->localport; + if (!localport) + return; lport = (struct lpfc_nvme_lport *)localport->private; lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME, @@ -2531,7 +2543,8 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * return values is ignored. The upcall is a courtesy to the * transport. */ - if (vport->load_flag & FC_UNLOADING) + if (vport->load_flag & FC_UNLOADING || + unlikely(vport->phba->hba_flag & HBA_PCI_ERR)) (void)nvme_fc_set_remoteport_devloss(remoteport, 0); ret = nvme_fc_unregister_remoteport(remoteport); @@ -2559,6 +2572,42 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) vport->localport, ndlp->rport, ndlp->nlp_DID); } +/** + * lpfc_sli4_nvme_pci_offline_aborted - Fast-path process of NVME xri abort + * @phba: pointer to lpfc hba data structure. + * @lpfc_ncmd: The nvme job structure for the request being aborted. + * + * This routine is invoked by the worker thread to process a SLI4 fast-path + * NVME aborted xri. Aborted NVME IO commands are completed to the transport + * here. + **/ +void +lpfc_sli4_nvme_pci_offline_aborted(struct lpfc_hba *phba, + struct lpfc_io_buf *lpfc_ncmd) +{ + struct nvmefc_fcp_req *nvme_cmd = NULL; + + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, + "6533 %s nvme_cmd %p tag x%x abort complete and " + "xri released\n", __func__, + lpfc_ncmd->nvmeCmd, + lpfc_ncmd->cur_iocbq.iotag); + + /* Aborted NVME commands are required to not complete + * before the abort exchange command fully completes. + * Once completed, it is available via the put list. + */ + if (lpfc_ncmd->nvmeCmd) { + nvme_cmd = lpfc_ncmd->nvmeCmd; + nvme_cmd->transferred_length = 0; + nvme_cmd->rcv_rsplen = 0; + nvme_cmd->status = NVME_SC_INTERNAL; + nvme_cmd->done(nvme_cmd); + lpfc_ncmd->nvmeCmd = NULL; + } + lpfc_release_nvme_buf(phba, lpfc_ncmd); +} + /** * lpfc_sli4_nvme_xri_aborted - Fast-path process of NVME xri abort * @phba: pointer to lpfc hba data structure. diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 0fde1e874c7a..b70f71b5c1f7 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -493,8 +493,8 @@ void lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba, struct sli4_wcqe_xri_aborted *axri, int idx) { - uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri); - uint16_t rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri); + u16 xri = 0; + u16 rxid = 0; struct lpfc_io_buf *psb, *next_psb; struct lpfc_sli4_hdw_queue *qp; unsigned long iflag = 0; @@ -504,15 +504,22 @@ lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba, int rrq_empty = 0; struct lpfc_sli_ring *pring = phba->sli4_hba.els_wq->pring; struct scsi_cmnd *cmd; + int offline = 0; if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP)) return; - + offline = pci_channel_offline(phba->pcidev); + if (!offline) { + xri = bf_get(lpfc_wcqe_xa_xri, axri); + rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri); + } qp = &phba->sli4_hba.hdwq[idx]; spin_lock_irqsave(&phba->hbalock, iflag); spin_lock(&qp->abts_io_buf_list_lock); list_for_each_entry_safe(psb, next_psb, &qp->lpfc_abts_io_buf_list, list) { + if (offline) + xri = psb->cur_iocbq.sli4_xritag; if (psb->cur_iocbq.sli4_xritag == xri) { list_del_init(&psb->list); psb->flags &= ~LPFC_SBUF_XBUSY; @@ -521,8 +528,15 @@ lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba, qp->abts_nvme_io_bufs--; spin_unlock(&qp->abts_io_buf_list_lock); spin_unlock_irqrestore(&phba->hbalock, iflag); - lpfc_sli4_nvme_xri_aborted(phba, axri, psb); - return; + if (!offline) { + lpfc_sli4_nvme_xri_aborted(phba, axri, + psb); + return; + } + lpfc_sli4_nvme_pci_offline_aborted(phba, psb); + spin_lock_irqsave(&phba->hbalock, iflag); + spin_lock(&qp->abts_io_buf_list_lock); + continue; } qp->abts_scsi_io_bufs--; spin_unlock(&qp->abts_io_buf_list_lock); @@ -534,13 +548,13 @@ lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba, rrq_empty = list_empty(&phba->active_rrq_list); spin_unlock_irqrestore(&phba->hbalock, iflag); - if (ndlp) { + if (ndlp && !offline) { lpfc_set_rrq_active(phba, ndlp, psb->cur_iocbq.sli4_lxritag, rxid, 1); lpfc_sli4_abts_err_handler(phba, ndlp, axri); } - if (phba->cfg_fcp_wait_abts_rsp) { + if (phba->cfg_fcp_wait_abts_rsp || offline) { spin_lock_irqsave(&psb->buf_lock, iflag); cmd = psb->pCmd; psb->pCmd = NULL; @@ -567,25 +581,30 @@ lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba, lpfc_release_scsi_buf_s4(phba, psb); if (rrq_empty) lpfc_worker_wake_up(phba); - return; + if (!offline) + return; + spin_lock_irqsave(&phba->hbalock, iflag); + spin_lock(&qp->abts_io_buf_list_lock); + continue; } } spin_unlock(&qp->abts_io_buf_list_lock); - for (i = 1; i <= phba->sli.last_iotag; i++) { - iocbq = phba->sli.iocbq_lookup[i]; - - if (!(iocbq->iocb_flag & LPFC_IO_FCP) || - (iocbq->iocb_flag & LPFC_IO_LIBDFC)) - continue; - if (iocbq->sli4_xritag != xri) - continue; - psb = container_of(iocbq, struct lpfc_io_buf, cur_iocbq); - psb->flags &= ~LPFC_SBUF_XBUSY; - spin_unlock_irqrestore(&phba->hbalock, iflag); - if (!list_empty(&pring->txq)) - lpfc_worker_wake_up(phba); - return; + if (!offline) { + for (i = 1; i <= phba->sli.last_iotag; i++) { + iocbq = phba->sli.iocbq_lookup[i]; + if (!(iocbq->iocb_flag & LPFC_IO_FCP) || + (iocbq->iocb_flag & LPFC_IO_LIBDFC)) + continue; + if (iocbq->sli4_xritag != xri) + continue; + psb = container_of(iocbq, struct lpfc_io_buf, cur_iocbq); + psb->flags &= ~LPFC_SBUF_XBUSY; + spin_unlock_irqrestore(&phba->hbalock, iflag); + if (!list_empty(&pring->txq)) + lpfc_worker_wake_up(phba); + return; + } } spin_unlock_irqrestore(&phba->hbalock, iflag); } diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index e8f6ad484768..651e6ee64e88 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1404,7 +1404,8 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) } if ((iocbq->iocb_flag & LPFC_EXCHANGE_BUSY) && - (sglq->state != SGL_XRI_ABORTED)) { + (!(unlikely(pci_channel_offline(phba->pcidev)))) && + sglq->state != SGL_XRI_ABORTED) { spin_lock_irqsave(&phba->sli4_hba.sgl_list_lock, iflag); @@ -4583,10 +4584,12 @@ lpfc_sli_flush_io_rings(struct lpfc_hba *phba) lpfc_sli_cancel_iocbs(phba, &txq, IOSTAT_LOCAL_REJECT, IOERR_SLI_DOWN); - /* Flush the txcmpq */ + /* Flush the txcmplq */ lpfc_sli_cancel_iocbs(phba, &txcmplq, IOSTAT_LOCAL_REJECT, IOERR_SLI_DOWN); + if (unlikely(pci_channel_offline(phba->pcidev))) + lpfc_sli4_io_xri_aborted(phba, NULL, 0); } } else { pring = &psli->sli3_ring[LPFC_FCP_RING]; @@ -22019,8 +22022,26 @@ lpfc_get_io_buf_from_multixri_pools(struct lpfc_hba *phba, qp = &phba->sli4_hba.hdwq[hwqid]; lpfc_ncmd = NULL; + if (!qp) { + lpfc_printf_log(phba, KERN_INFO, + LOG_SLI | LOG_NVME_ABTS | LOG_FCP, + "5556 NULL qp for hwqid x%x\n", hwqid); + return lpfc_ncmd; + } multixri_pool = qp->p_multixri_pool; + if (!multixri_pool) { + lpfc_printf_log(phba, KERN_INFO, + LOG_SLI | LOG_NVME_ABTS | LOG_FCP, + "5557 NULL multixri for hwqid x%x\n", hwqid); + return lpfc_ncmd; + } pvt_pool = &multixri_pool->pvt_pool; + if (!pvt_pool) { + lpfc_printf_log(phba, KERN_INFO, + LOG_SLI | LOG_NVME_ABTS | LOG_FCP, + "5558 NULL pvt_pool for hwqid x%x\n", hwqid); + return lpfc_ncmd; + } multixri_pool->io_req_count++; /* If pvt_pool is empty, move some XRIs from public to private pool */ @@ -22096,6 +22117,12 @@ struct lpfc_io_buf *lpfc_get_io_buf(struct lpfc_hba *phba, qp = &phba->sli4_hba.hdwq[hwqid]; lpfc_cmd = NULL; + if (!qp) { + lpfc_printf_log(phba, KERN_WARNING, + LOG_SLI | LOG_NVME_ABTS | LOG_FCP, + "5555 NULL qp for hwqid x%x\n", hwqid); + return lpfc_cmd; + } if (phba->cfg_xri_rebalancing) lpfc_cmd = lpfc_get_io_buf_from_multixri_pools( diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 99c5d1e4da5e..5962cf508842 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -1116,6 +1116,8 @@ void lpfc_sli4_fcf_redisc_event_proc(struct lpfc_hba *); int lpfc_sli4_resume_rpi(struct lpfc_nodelist *, void (*)(struct lpfc_hba *, LPFC_MBOXQ_t *), void *); void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *phba); +void lpfc_sli4_nvme_pci_offline_aborted(struct lpfc_hba *phba, + struct lpfc_io_buf *lpfc_ncmd); void lpfc_sli4_nvme_xri_aborted(struct lpfc_hba *phba, struct sli4_wcqe_xri_aborted *axri, struct lpfc_io_buf *lpfc_ncmd); -- cgit From d5ac69b332d8859d1f8bd5d4dee31f3267f6b0d2 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 10 Sep 2021 16:31:55 -0700 Subject: scsi: lpfc: Adjust bytes received vales during cmf timer interval The newly added congestion mgmt framework is seeing unexpected congestion FPINs and signals. In analysis, time values given to the adapter are not at hard time intervals. Thus the drift vs the transfer count seen is affecting how the framework manages things. Adjust counters to cover the drift. Link: https://lore.kernel.org/r/20210910233159.115896-11-jsmart2021@gmail.com Co-developed-by: Justin Tee Signed-off-by: Justin Tee Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_init.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 3fd730613de3..d3a2281cb48b 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -5876,7 +5876,7 @@ lpfc_cmf_timer(struct hrtimer *timer) uint32_t io_cnt; uint32_t head, tail; uint32_t busy, max_read; - uint64_t total, rcv, lat, mbpi; + uint64_t total, rcv, lat, mbpi, extra; int timer_interval = LPFC_CMF_INTERVAL; uint32_t ms; struct lpfc_cgn_stat *cgs; @@ -5943,7 +5943,19 @@ lpfc_cmf_timer(struct hrtimer *timer) phba->hba_flag & HBA_SETUP) { mbpi = phba->cmf_last_sync_bw; phba->cmf_last_sync_bw = 0; - lpfc_issue_cmf_sync_wqe(phba, LPFC_CMF_INTERVAL, total); + extra = 0; + + /* Calculate any extra bytes needed to account for the + * timer accuracy. If we are less than LPFC_CMF_INTERVAL + * add an extra 3% slop factor, equal to LPFC_CMF_INTERVAL + * add an extra 2%. The goal is to equalize total with a + * time > LPFC_CMF_INTERVAL or <= LPFC_CMF_INTERVAL + 1 + */ + if (ms == LPFC_CMF_INTERVAL) + extra = div_u64(total, 50); + else if (ms < LPFC_CMF_INTERVAL) + extra = div_u64(total, 33); + lpfc_issue_cmf_sync_wqe(phba, LPFC_CMF_INTERVAL, total + extra); } else { /* For Monitor mode or link down we want mbpi * to be the full link speed -- cgit From 3ea998cbf9e781b6d16250fab1e6121dce32790b Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 10 Sep 2021 16:31:56 -0700 Subject: scsi: lpfc: Fix I/O block after enabling managed congestion mode If the congestion management framework dynamically enables, it may do so while I/O is in flight. The updates of cmf info due to inflight I/O completing may happen before values have been initialized. Fix by ensure cmf_max_bytes_per_interval is initialized when checking bandwidth utilization for SCSI layer blocking. Link: https://lore.kernel.org/r/20210910233159.115896-12-jsmart2021@gmail.com Co-developed-by: Justin Tee Signed-off-by: Justin Tee Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_scsi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index b70f71b5c1f7..a2cd22728b0f 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -3961,7 +3961,8 @@ lpfc_update_cmf_cmd(struct lpfc_hba *phba, uint32_t size) int cpu; /* At this point we are either LPFC_CFG_MANAGED or LPFC_CFG_MONITOR */ - if (phba->cmf_active_mode == LPFC_CFG_MANAGED) { + if (phba->cmf_active_mode == LPFC_CFG_MANAGED && + phba->cmf_max_bytes_per_interval) { total = 0; for_each_present_cpu(cpu) { cgs = per_cpu_ptr(phba->cmf_stat, cpu); -- cgit From afd63fa511494d7215120be7d25c20502aed4d89 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 10 Sep 2021 16:31:57 -0700 Subject: scsi: lpfc: Zero CGN stats only during initial driver load and stat reset Currently congestion management framework results are cleared whenever the framework settings changed (such as it being turned off then back on). This unfortunately means prior stats, rolled up to higher time windows lose meaning. Change such that stats are not cleared. Thus they pause and resume with prior values still being considered. Link: https://lore.kernel.org/r/20210910233159.115896-13-jsmart2021@gmail.com Co-developed-by: Justin Tee Signed-off-by: Justin Tee Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_init.c | 2 -- drivers/scsi/lpfc/lpfc_sli.c | 6 ++++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index d3a2281cb48b..ff2a4e387523 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -13394,8 +13394,6 @@ lpfc_init_congestion_buf(struct lpfc_hba *phba) atomic_set(&phba->cgn_sync_alarm_cnt, 0); atomic_set(&phba->cgn_sync_warn_cnt, 0); - atomic64_set(&phba->cgn_acqe_stat.alarm, 0); - atomic64_set(&phba->cgn_acqe_stat.warn, 0); atomic_set(&phba->cgn_driver_evt_cnt, 0); atomic_set(&phba->cgn_latency_evt_cnt, 0); atomic64_set(&phba->cgn_latency_evt, 0); diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 651e6ee64e88..34cf2bfcce07 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -7764,8 +7764,6 @@ lpfc_mbx_cmpl_cgn_set_ftrs(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) /* Zero out Congestion Signal ACQE counter */ phba->cgn_acqe_cnt = 0; - atomic64_set(&phba->cgn_acqe_stat.warn, 0); - atomic64_set(&phba->cgn_acqe_stat.alarm, 0); acqe = bf_get(lpfc_mbx_set_feature_CGN_acqe_freq, &pmb->u.mqe.un.set_feature); @@ -8017,6 +8015,10 @@ lpfc_cmf_setup(struct lpfc_hba *phba) /* initialize congestion buffer info */ lpfc_init_congestion_buf(phba); lpfc_init_congestion_stat(phba); + + /* Zero out Congestion Signal counters */ + atomic64_set(&phba->cgn_acqe_stat.alarm, 0); + atomic64_set(&phba->cgn_acqe_stat.warn, 0); } rc = lpfc_sli4_cgn_params_read(phba); -- cgit From 315b3fd13521fb44d97572eb24b7c8670ec7fd97 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 10 Sep 2021 16:31:58 -0700 Subject: scsi: lpfc: Improve PBDE checks during SGL processing The PBDE feature, setting payload buffer address explicitly in the WQE so it doesn't have to be fetched from the SGL, only makes sense when there is a single buffer for the I/O. When there are multiple buffers it actually hurts performance as the SGL subsequently has to be fetched. Rework the SGL logic to only use PBDE when a single buffer. Link: https://lore.kernel.org/r/20210910233159.115896-14-jsmart2021@gmail.com Co-developed-by: Justin Tee Signed-off-by: Justin Tee Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_nvme.c | 12 ++++++------ drivers/scsi/lpfc/lpfc_nvmet.c | 44 ++++++++++++++++++++---------------------- drivers/scsi/lpfc/lpfc_scsi.c | 26 ++++++++++++------------- 3 files changed, 40 insertions(+), 42 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index 33266e1b24ab..69d3758dd8dc 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -1299,7 +1299,6 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, struct sli4_sge *first_data_sgl; struct ulp_bde64 *bde; dma_addr_t physaddr = 0; - uint32_t num_bde = 0; uint32_t dma_len = 0; uint32_t dma_offset = 0; int nseg, i, j; @@ -1353,7 +1352,7 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, } sgl->word2 = 0; - if ((num_bde + 1) == nseg) { + if (nseg == 1) { bf_set(lpfc_sli4_sge_last, sgl, 1); bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DATA); @@ -1422,8 +1421,9 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, j++; } - if (phba->cfg_enable_pbde) { - /* Use PBDE support for first SGL only, offset == 0 */ + + /* PBDE support for first data SGE only */ + if (nseg == 1 && phba->cfg_enable_pbde) { /* Words 13-15 */ bde = (struct ulp_bde64 *) &wqe->words[13]; @@ -1434,11 +1434,11 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64; bde->tus.w = cpu_to_le32(bde->tus.w); - /* Word 11 */ + /* Word 11 - set PBDE bit */ bf_set(wqe_pbde, &wqe->generic.wqe_com, 1); } else { memset(&wqe->words[13], 0, (sizeof(uint32_t) * 3)); - bf_set(wqe_pbde, &wqe->generic.wqe_com, 0); + /* Word 11 - PBDE bit disabled by default template */ } } else { diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index 6e3dd0b9bcfa..731802527b81 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -2708,7 +2708,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, struct ulp_bde64 *bde; dma_addr_t physaddr; int i, cnt, nsegs; - int do_pbde; + bool use_pbde = false; int xc = 1; if (!lpfc_is_link_up(phba)) { @@ -2816,9 +2816,6 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, if (!xc) bf_set(wqe_xc, &wqe->fcp_tsend.wqe_com, 0); - /* Word 11 - set sup, irsp, irsplen later */ - do_pbde = 0; - /* Word 12 */ wqe->fcp_tsend.fcp_data_len = rsp->transfer_length; @@ -2896,12 +2893,13 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, if (!xc) bf_set(wqe_xc, &wqe->fcp_treceive.wqe_com, 0); - /* Word 11 - set pbde later */ - if (phba->cfg_enable_pbde) { - do_pbde = 1; + /* Word 11 - check for pbde */ + if (nsegs == 1 && phba->cfg_enable_pbde) { + use_pbde = true; + /* Word 11 - PBDE bit already preset by template */ } else { + /* Overwrite default template setting */ bf_set(wqe_pbde, &wqe->fcp_treceive.wqe_com, 0); - do_pbde = 0; } /* Word 12 */ @@ -2972,7 +2970,6 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, ((rsp->rsplen >> 2) - 1)); memcpy(&wqe->words[16], rsp->rspaddr, rsp->rsplen); } - do_pbde = 0; /* Word 12 */ wqe->fcp_trsp.rsvd_12_15[0] = 0; @@ -3007,23 +3004,24 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, bf_set(lpfc_sli4_sge_last, sgl, 1); sgl->word2 = cpu_to_le32(sgl->word2); sgl->sge_len = cpu_to_le32(cnt); - if (i == 0) { - bde = (struct ulp_bde64 *)&wqe->words[13]; - if (do_pbde) { - /* Words 13-15 (PBDE) */ - bde->addrLow = sgl->addr_lo; - bde->addrHigh = sgl->addr_hi; - bde->tus.f.bdeSize = - le32_to_cpu(sgl->sge_len); - bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64; - bde->tus.w = cpu_to_le32(bde->tus.w); - } else { - memset(bde, 0, sizeof(struct ulp_bde64)); - } - } sgl++; ctxp->offset += cnt; } + + bde = (struct ulp_bde64 *)&wqe->words[13]; + if (use_pbde) { + /* decrement sgl ptr backwards once to first data sge */ + sgl--; + + /* Words 13-15 (PBDE) */ + bde->addrLow = sgl->addr_lo; + bde->addrHigh = sgl->addr_hi; + bde->tus.f.bdeSize = le32_to_cpu(sgl->sge_len); + bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64; + bde->tus.w = cpu_to_le32(bde->tus.w); + } else { + memset(bde, 0, sizeof(struct ulp_bde64)); + } ctxp->state = LPFC_NVME_STE_DATA; ctxp->entry_cnt++; return nvmewqe; diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index a2cd22728b0f..078fbea3f436 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -3235,7 +3235,6 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) struct lpfc_vport *vport = phba->pport; union lpfc_wqe128 *wqe = &pwqeq->wqe; dma_addr_t physaddr; - uint32_t num_bde = 0; uint32_t dma_len; uint32_t dma_offset = 0; int nseg, i, j; @@ -3297,7 +3296,7 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) j = 2; for (i = 0; i < nseg; i++) { sgl->word2 = 0; - if ((num_bde + 1) == nseg) { + if (nseg == 1) { bf_set(lpfc_sli4_sge_last, sgl, 1); bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DATA); @@ -3366,13 +3365,15 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) j++; } - /* - * Setup the first Payload BDE. For FCoE we just key off - * Performance Hints, for FC we use lpfc_enable_pbde. - * We populate words 13-15 of IOCB/WQE. + + /* PBDE support for first data SGE only. + * For FCoE, we key off Performance Hints. + * For FC, we key off lpfc_enable_pbde. */ - if ((phba->sli3_options & LPFC_SLI4_PERFH_ENABLED) || - phba->cfg_enable_pbde) { + if (nseg == 1 && + ((phba->sli3_options & LPFC_SLI4_PERFH_ENABLED) || + phba->cfg_enable_pbde)) { + /* Words 13-15 */ bde = (struct ulp_bde64 *) &wqe->words[13]; bde->addrLow = first_data_sgl->addr_lo; @@ -3382,12 +3383,15 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64; bde->tus.w = cpu_to_le32(bde->tus.w); + /* Word 11 - set PBDE bit */ + bf_set(wqe_pbde, &wqe->generic.wqe_com, 1); } else { memset(&wqe->words[13], 0, (sizeof(uint32_t) * 3)); + /* Word 11 - PBDE bit disabled by default template */ } } else { sgl += 1; - /* clear the last flag in the fcp_rsp map entry */ + /* set the last flag in the fcp_rsp map entry */ sgl->word2 = le32_to_cpu(sgl->word2); bf_set(lpfc_sli4_sge_last, sgl, 1); sgl->word2 = cpu_to_le32(sgl->word2); @@ -3400,10 +3404,6 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) } } - /* Word 11 */ - if (phba->cfg_enable_pbde) - bf_set(wqe_pbde, &wqe->generic.wqe_com, 1); - /* * Finish initializing those IOCB fields that are dependent on the * scsi_cmnd request_buffer. Note that for SLI-2 the bdeSize is -- cgit From 0d6b26795bd2b9f1d7f0d43a21a386438586bc69 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 10 Sep 2021 16:31:59 -0700 Subject: scsi: lpfc: Update lpfc version to 14.0.0.2 Update lpfc version to 14.0.0.2. Link: https://lore.kernel.org/r/20210910233159.115896-15-jsmart2021@gmail.com Co-developed-by: Justin Tee Signed-off-by: Justin Tee Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index a7aba7833425..dec71775f677 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -20,7 +20,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "14.0.0.1" +#define LPFC_DRIVER_VERSION "14.0.0.2" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ -- cgit From 0a5e20fc8ca7ed10b8865421a7c1e8d460840956 Mon Sep 17 00:00:00 2001 From: Len Baker Date: Sun, 5 Sep 2021 08:24:48 +0200 Subject: scsi: elx: libefc: Prefer kcalloc() over open coded arithmetic As noted in the "Deprecated Interfaces, Language Features, Attributes, and Conventions" documentation [1], size calculations (especially multiplication) should not be performed in memory allocator (or similar) function arguments due to the risk of them overflowing. This could lead to values wrapping around and a smaller allocation being made than the caller was expecting. Using those allocations could lead to linear overflows of heap memory and other misbehaviors. Use the purpose specific kcalloc() function instead of the argument count * size in the kzalloc() function. [1] https://www.kernel.org/doc/html/v5.14/process/deprecated.html#open-coded-arithmetic-in-allocator-arguments Link: https://lore.kernel.org/r/20210905062448.6587-1-len.baker@gmx.com Reviewed-by: James Smart Signed-off-by: Len Baker Signed-off-by: Martin K. Petersen --- drivers/scsi/elx/libefc/efc_fabric.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/elx/libefc/efc_fabric.c b/drivers/scsi/elx/libefc/efc_fabric.c index d397220d9e54..f9412437ad47 100644 --- a/drivers/scsi/elx/libefc/efc_fabric.c +++ b/drivers/scsi/elx/libefc/efc_fabric.c @@ -686,7 +686,7 @@ efc_process_gidpt_payload(struct efc_node *node, } /* Allocate a buffer for all nodes */ - active_nodes = kzalloc(port_count * sizeof(*active_nodes), GFP_ATOMIC); + active_nodes = kcalloc(port_count, sizeof(*active_nodes), GFP_ATOMIC); if (!active_nodes) { node_printf(node, "efc_malloc failed\n"); return -EIO; -- cgit From e9d73bfa8e047fbb078213e607019c701cd9f888 Mon Sep 17 00:00:00 2001 From: Muneendra Kumar Date: Sun, 12 Sep 2021 18:58:53 -0700 Subject: scsi: documentation: Document Fibre Channel sysfs node for appid Update documentation for sysfs node within /sys/class/fc/fc_udev_device/. Link: https://lore.kernel.org/r/20210913015853.2086512-1-muneendra.kumar@broadcom.com Reviewed-by: Himanshu Madhani Signed-off-by: Muneendra Kumar Signed-off-by: Martin K. Petersen --- Documentation/ABI/testing/sysfs-class-fc | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-class-fc diff --git a/Documentation/ABI/testing/sysfs-class-fc b/Documentation/ABI/testing/sysfs-class-fc new file mode 100644 index 000000000000..3057a6d3b8cf --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-fc @@ -0,0 +1,27 @@ +What: /sys/class/fc/fc_udev_device/appid_store +Date: Aug 2021 +Contact: Muneendra Kumar +Description: + This interface allows an admin to set an FC application + identifier in the blkcg associated with a cgroup id. The + identifier is typically a UUID that is associated with + an application or logical entity such as a virtual + machine or container group. The application or logical + entity utilizes a block device via the cgroup id. + FC adapter drivers may query the identifier and tag FC + traffic based on the identifier. FC host and FC fabric + entities can utilize the application id and FC traffic + tag to identify traffic sources. + + The interface expects a string ":" where: + is inode of the cgroup in hexadecimal + is user provided string upto 128 characters + in length. + + If an appid_store is done for a cgroup id that already + has an appid set, the new value will override the + previous value. + + If an admin wants to remove an FC application identifier + from a cgroup, an appid_store should be done with the + following string: ":" -- cgit From c4adf171e834dab8ca72676ca7264c5b50a542a8 Mon Sep 17 00:00:00 2001 From: ChanWoo Lee Date: Tue, 7 Sep 2021 13:41:11 +0900 Subject: scsi: ufs: ufs-qcom: Remove unneeded variable 'err' 'err' is never set in this functon. Remove the declaration and just return 0. Link: https://lore.kernel.org/r/20210907044111.29632-1-cw9316.lee@samsung.com Signed-off-by: ChanWoo Lee Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs-qcom.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 9d9770f1db4f..92d4c61fc9d0 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -888,7 +888,6 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, enum ufs_notify_change_status status) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); - int err = 0; /* * In case ufs_qcom_init() is not yet done, simply ignore. @@ -916,7 +915,7 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, break; } - return err; + return 0; } static int -- cgit From 351b3a849ac7d92449dc75c43db8a857b38387ea Mon Sep 17 00:00:00 2001 From: Daejun Park Date: Thu, 2 Sep 2021 09:35:34 +0900 Subject: scsi: ufs: ufshpb: Use proper power management API In ufshpb, pm_runtime_{get,put}_sync() are used to avoid unwanted runtime suspend during query requests. Whereas commit b294ff3e3449 ("scsi: ufs: core: Enable power management for wlun") modified the driver core to use ufshcd_rpm_{get,put}_sync() APIs. Switch to these APIs in HPB module as well. Link: https://lore.kernel.org/r/20210902003534epcms2p1937a0f0eeb48a441cb69f5ef13ff8430@epcms2p1 Reviewed-by: Avri Altman Signed-off-by: Daejun Park Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshpb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c index 02fb51ae8b25..9ea639bf6a59 100644 --- a/drivers/scsi/ufs/ufshpb.c +++ b/drivers/scsi/ufs/ufshpb.c @@ -2650,11 +2650,11 @@ static int ufshpb_get_lu_info(struct ufs_hba *hba, int lun, ufshcd_map_desc_id_to_length(hba, QUERY_DESC_IDN_UNIT, &size); - pm_runtime_get_sync(hba->dev); + ufshcd_rpm_get_sync(hba); ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC, QUERY_DESC_IDN_UNIT, lun, 0, desc_buf, &size); - pm_runtime_put_sync(hba->dev); + ufshcd_rpm_put_sync(hba); if (ret) { dev_err(hba->dev, @@ -2877,10 +2877,10 @@ void ufshpb_get_dev_info(struct ufs_hba *hba, u8 *desc_buf) if (version == HPB_SUPPORT_LEGACY_VERSION) hpb_dev_info->is_legacy = true; - pm_runtime_get_sync(hba->dev); + ufshcd_rpm_get_sync(hba); ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR, QUERY_ATTR_IDN_MAX_HPB_SINGLE_CMD, 0, 0, &max_hpb_single_cmd); - pm_runtime_put_sync(hba->dev); + ufshcd_rpm_put_sync(hba); if (ret) dev_err(hba->dev, "%s: idn: read max size of single hpb cmd query request failed", -- cgit From aba3b0757b6cba37953bb1d7e71c460d37fd496a Mon Sep 17 00:00:00 2001 From: Peter Wang Date: Mon, 6 Sep 2021 16:53:07 +0800 Subject: scsi: ufs: ufs-mediatek: Change dbg select by check IP version Mediatek UFS dbg select setting is changed in new IP version. Check the IP version before setting dbg select. Link: https://lore.kernel.org/r/1630918387-8333-1-git-send-email-peter.wang@mediatek.com Signed-off-by: Peter Wang Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs-mediatek.c | 21 +++++++++++++++++++-- drivers/scsi/ufs/ufs-mediatek.h | 6 ++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/ufs/ufs-mediatek.c b/drivers/scsi/ufs/ufs-mediatek.c index 80b3545dd17d..d2d7e76c5ec8 100644 --- a/drivers/scsi/ufs/ufs-mediatek.c +++ b/drivers/scsi/ufs/ufs-mediatek.c @@ -296,6 +296,21 @@ static void ufs_mtk_setup_ref_clk_wait_us(struct ufs_hba *hba, host->ref_clk_ungating_wait_us = ungating_us; } +static void ufs_mtk_dbg_sel(struct ufs_hba *hba) +{ + struct ufs_mtk_host *host = ufshcd_get_variant(hba); + + if (((host->ip_ver >> 16) & 0xFF) >= 0x36) { + ufshcd_writel(hba, 0x820820, REG_UFS_DEBUG_SEL); + ufshcd_writel(hba, 0x0, REG_UFS_DEBUG_SEL_B0); + ufshcd_writel(hba, 0x55555555, REG_UFS_DEBUG_SEL_B1); + ufshcd_writel(hba, 0xaaaaaaaa, REG_UFS_DEBUG_SEL_B2); + ufshcd_writel(hba, 0xffffffff, REG_UFS_DEBUG_SEL_B3); + } else { + ufshcd_writel(hba, 0x20, REG_UFS_DEBUG_SEL); + } +} + static int ufs_mtk_wait_link_state(struct ufs_hba *hba, u32 state, unsigned long max_wait_ms) { @@ -305,7 +320,7 @@ static int ufs_mtk_wait_link_state(struct ufs_hba *hba, u32 state, timeout = ktime_add_ms(ktime_get(), max_wait_ms); do { time_checked = ktime_get(); - ufshcd_writel(hba, 0x20, REG_UFS_DEBUG_SEL); + ufs_mtk_dbg_sel(hba); val = ufshcd_readl(hba, REG_UFS_PROBE); val = val >> 28; @@ -689,6 +704,8 @@ static int ufs_mtk_init(struct ufs_hba *hba) ufs_mtk_mphy_power_on(hba, true); ufs_mtk_setup_clocks(hba, true, POST_CHANGE); + host->ip_ver = ufshcd_readl(hba, REG_UFS_MTK_IP_VER); + goto out; out_variant_clear: @@ -1001,7 +1018,7 @@ static void ufs_mtk_dbg_register_dump(struct ufs_hba *hba) "MPHY Ctrl "); /* Direct debugging information to REG_MTK_PROBE */ - ufshcd_writel(hba, 0x20, REG_UFS_DEBUG_SEL); + ufs_mtk_dbg_sel(hba); ufshcd_dump_regs(hba, REG_UFS_PROBE, 0x4, "Debug Probe "); } diff --git a/drivers/scsi/ufs/ufs-mediatek.h b/drivers/scsi/ufs/ufs-mediatek.h index 3f0d3bb769e8..524c8e2c1e6f 100644 --- a/drivers/scsi/ufs/ufs-mediatek.h +++ b/drivers/scsi/ufs/ufs-mediatek.h @@ -15,9 +15,14 @@ #define REG_UFS_REFCLK_CTRL 0x144 #define REG_UFS_EXTREG 0x2100 #define REG_UFS_MPHYCTRL 0x2200 +#define REG_UFS_MTK_IP_VER 0x2240 #define REG_UFS_REJECT_MON 0x22AC #define REG_UFS_DEBUG_SEL 0x22C0 #define REG_UFS_PROBE 0x22C8 +#define REG_UFS_DEBUG_SEL_B0 0x22D0 +#define REG_UFS_DEBUG_SEL_B1 0x22D4 +#define REG_UFS_DEBUG_SEL_B2 0x22D8 +#define REG_UFS_DEBUG_SEL_B3 0x22DC /* * Ref-clk control @@ -113,6 +118,7 @@ struct ufs_mtk_host { bool ref_clk_enabled; u16 ref_clk_ungating_wait_us; u16 ref_clk_gating_wait_us; + u32 ip_ver; }; #endif /* !_UFS_MEDIATEK_H */ -- cgit From 7e642ca0375b95072ab6240c8eb9f0b4f013fb24 Mon Sep 17 00:00:00 2001 From: Li Feng Date: Mon, 13 Sep 2021 16:30:45 +0800 Subject: scsi: target: Remove unused function arguments The se_cmd is unused in these functions, just remove it. Link: https://lore.kernel.org/r/20210913083045.3670648-1-fengli@smartx.com Reviewed-by: Himanshu Madhani Signed-off-by: Li Feng Signed-off-by: Martin K. Petersen --- drivers/target/target_core_xcopy.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index d4fe7cb2bd00..6bb20aa9c5bc 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -295,8 +295,7 @@ out: return -EINVAL; } -static int target_xcopy_parse_segdesc_02(struct se_cmd *se_cmd, struct xcopy_op *xop, - unsigned char *p) +static int target_xcopy_parse_segdesc_02(struct xcopy_op *xop, unsigned char *p) { unsigned char *desc = p; int dc = (desc[1] & 0x02); @@ -332,9 +331,9 @@ static int target_xcopy_parse_segdesc_02(struct se_cmd *se_cmd, struct xcopy_op return 0; } -static int target_xcopy_parse_segment_descriptors(struct se_cmd *se_cmd, - struct xcopy_op *xop, unsigned char *p, - unsigned int sdll, sense_reason_t *sense_ret) +static int target_xcopy_parse_segment_descriptors(struct xcopy_op *xop, + unsigned char *p, unsigned int sdll, + sense_reason_t *sense_ret) { unsigned char *desc = p; unsigned int start = 0; @@ -362,7 +361,7 @@ static int target_xcopy_parse_segment_descriptors(struct se_cmd *se_cmd, */ switch (desc[0]) { case 0x02: - rc = target_xcopy_parse_segdesc_02(se_cmd, xop, desc); + rc = target_xcopy_parse_segdesc_02(xop, desc); if (rc < 0) goto out; @@ -840,8 +839,7 @@ static sense_reason_t target_parse_xcopy_cmd(struct xcopy_op *xop) */ seg_desc = &p[16] + tdll; - rc = target_xcopy_parse_segment_descriptors(se_cmd, xop, seg_desc, - sdll, &ret); + rc = target_xcopy_parse_segment_descriptors(xop, seg_desc, sdll, &ret); if (rc <= 0) goto out; -- cgit From 3149733584c8f0ab828eada539df7aa488c023a9 Mon Sep 17 00:00:00 2001 From: Ravi Bangoria Date: Sat, 11 Sep 2021 10:08:54 +0530 Subject: perf annotate: Add fusion logic for AMD microarchs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AMD family 15h and above microarchs fuse a subset of cmp/test/ALU instructions with branch instructions[1][2]. Add perf annotate fused instruction support for these microarchs. Before: │ testb $0x80,0x51(%rax) │ ┌──jne 5b3 0.78 │ │ mov %r13,%rdi │ │→ callq mark_page_accessed 1.08 │5b3:└─→mov 0x8(%r13),%rax After: │ ┌──testb $0x80,0x51(%rax) │ ├──jne 5b3 0.78 │ │ mov %r13,%rdi │ │→ callq mark_page_accessed 1.08 │5b3:└─→mov 0x8(%r13),%rax [1] https://bugzilla.kernel.org/attachment.cgi?id=298553 [2] https://bugzilla.kernel.org/attachment.cgi?id=298555 Committer testing: On a: $ grep -m1 "model name" /proc/cpuinfo model name : AMD Ryzen 9 3900X 12-Core Processor $ Samples: 44K of event 'cycles', 4000 Hz, Event count (approx.): 7533249650 _int_malloc /usr/lib64/libc-2.33.so [Percent: local period] Percent│ ┌──test %eax,%eax │ ├──jne 884 │ │↓ jmpq 943 │ │ nop │878:│ add $0x10,%rdx 0.64 │ │ add %eax,%eax 0.57 │ │↓ je cc9 0.77 │884:└─→test %esi,%eax │ ↑ je 878 │ mov 0x18(%rdx),%r15 Reported-by: Kim Phillips Signed-off-by: Ravi Bangoria Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Jin Yao Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Link: https //lore.kernel.org/r/20210911043854.8373-2-ravi.bangoria@amd.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/annotate/instructions.c | 28 +++++++++++++++++++++++++++- tools/perf/util/annotate.c | 1 - 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/tools/perf/arch/x86/annotate/instructions.c b/tools/perf/arch/x86/annotate/instructions.c index 24ea12ec7e02..305872692bfd 100644 --- a/tools/perf/arch/x86/annotate/instructions.c +++ b/tools/perf/arch/x86/annotate/instructions.c @@ -144,8 +144,31 @@ static struct ins x86__instructions[] = { { .name = "xorps", .ops = &mov_ops, }, }; -static bool x86__ins_is_fused(struct arch *arch, const char *ins1, +static bool amd__ins_is_fused(struct arch *arch, const char *ins1, const char *ins2) +{ + if (strstr(ins2, "jmp")) + return false; + + /* Family >= 15h supports cmp/test + branch fusion */ + if (arch->family >= 0x15 && (strstarts(ins1, "test") || + (strstarts(ins1, "cmp") && !strstr(ins1, "xchg")))) { + return true; + } + + /* Family >= 19h supports some ALU + branch fusion */ + if (arch->family >= 0x19 && (strstarts(ins1, "add") || + strstarts(ins1, "sub") || strstarts(ins1, "and") || + strstarts(ins1, "inc") || strstarts(ins1, "dec") || + strstarts(ins1, "or") || strstarts(ins1, "xor"))) { + return true; + } + + return false; +} + +static bool intel__ins_is_fused(struct arch *arch, const char *ins1, + const char *ins2) { if (arch->family != 6 || arch->model < 0x1e || strstr(ins2, "jmp")) return false; @@ -184,6 +207,9 @@ static int x86__cpuid_parse(struct arch *arch, char *cpuid) if (ret == 3) { arch->family = family; arch->model = model; + arch->ins_is_fused = strstarts(cpuid, "AuthenticAMD") ? + amd__ins_is_fused : + intel__ins_is_fused; return 0; } diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 0bae061b2d6d..b55f35485e43 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -183,7 +183,6 @@ static struct arch architectures[] = { .init = x86__annotate_init, .instructions = x86__instructions, .nr_instructions = ARRAY_SIZE(x86__instructions), - .ins_is_fused = x86__ins_is_fused, .objdump = { .comment_char = '#', }, -- cgit From ddf0d4dee4cbcabdf5161da3fe744b6cb149db88 Mon Sep 17 00:00:00 2001 From: Muhammad Falak R Wani Date: Sun, 15 Aug 2021 16:06:10 +0530 Subject: perf bpf: Deprecate bpf_map__resize() in favor of bpf_map_set_max_entries() As a part of libbpf 1.0 plan[0], this patch deprecates use of bpf_map__resize in favour of bpf_map__set_max_entries. Reference: https://github.com/libbpf/libbpf/issues/304 [0]: https://github.com/libbpf/libbpf/wiki/Libbpf:-the-road-to-v1.0#libbpfh-high-level-apis Signed-off-by: Muhammad Falak R Wani Acked-by: Andrii Nakryiko Cc: Alexander Shishkin Cc: Alexei Starovoitov Cc: Daniel Borkmann Cc: Jiri Olsa Cc: John Fastabend Cc: KP Singh Cc: Mark Rutland Cc: Martin KaFai Lau Cc: Muhammad Falak R Wani Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Quentin Monnet Cc: Song Liu Cc: Yu Kuai Link: http //lore.kernel.org/lkml/20210815103610.27887-1-falakreyaz@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/bpf_counter.c | 8 ++++---- tools/perf/util/bpf_counter_cgroup.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/perf/util/bpf_counter.c b/tools/perf/util/bpf_counter.c index ba0f20853651..ced2dac31dcf 100644 --- a/tools/perf/util/bpf_counter.c +++ b/tools/perf/util/bpf_counter.c @@ -127,9 +127,9 @@ static int bpf_program_profiler_load_one(struct evsel *evsel, u32 prog_id) skel->rodata->num_cpu = evsel__nr_cpus(evsel); - bpf_map__resize(skel->maps.events, evsel__nr_cpus(evsel)); - bpf_map__resize(skel->maps.fentry_readings, 1); - bpf_map__resize(skel->maps.accum_readings, 1); + bpf_map__set_max_entries(skel->maps.events, evsel__nr_cpus(evsel)); + bpf_map__set_max_entries(skel->maps.fentry_readings, 1); + bpf_map__set_max_entries(skel->maps.accum_readings, 1); prog_name = bpf_target_prog_name(prog_fd); if (!prog_name) { @@ -399,7 +399,7 @@ static int bperf_reload_leader_program(struct evsel *evsel, int attr_map_fd, return -1; } - bpf_map__resize(skel->maps.events, libbpf_num_possible_cpus()); + bpf_map__set_max_entries(skel->maps.events, libbpf_num_possible_cpus()); err = bperf_leader_bpf__load(skel); if (err) { pr_err("Failed to load leader skeleton\n"); diff --git a/tools/perf/util/bpf_counter_cgroup.c b/tools/perf/util/bpf_counter_cgroup.c index 89aa5e71db1a..cbc6c2bca488 100644 --- a/tools/perf/util/bpf_counter_cgroup.c +++ b/tools/perf/util/bpf_counter_cgroup.c @@ -65,14 +65,14 @@ static int bperf_load_program(struct evlist *evlist) /* we need one copy of events per cpu for reading */ map_size = total_cpus * evlist->core.nr_entries / nr_cgroups; - bpf_map__resize(skel->maps.events, map_size); - bpf_map__resize(skel->maps.cgrp_idx, nr_cgroups); + bpf_map__set_max_entries(skel->maps.events, map_size); + bpf_map__set_max_entries(skel->maps.cgrp_idx, nr_cgroups); /* previous result is saved in a per-cpu array */ map_size = evlist->core.nr_entries / nr_cgroups; - bpf_map__resize(skel->maps.prev_readings, map_size); + bpf_map__set_max_entries(skel->maps.prev_readings, map_size); /* cgroup result needs all events (per-cpu) */ map_size = evlist->core.nr_entries; - bpf_map__resize(skel->maps.cgrp_readings, map_size); + bpf_map__set_max_entries(skel->maps.cgrp_readings, map_size); set_max_rlimit(); -- cgit From 00e0ca3721cf2ddcb38cf676a3de61933640d31d Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 14 Sep 2021 10:00:04 -0700 Subject: perf bpf: Ignore deprecation warning when using libbpf's btf__get_from_id() Perf code re-implements libbpf's btf__load_from_kernel_by_id() API as a weak function, presumably to dynamically link against old version of libbpf shared library. Unfortunately this causes compilation warning when perf is compiled against libbpf v0.6+. For now, just ignore deprecation warning, but there might be a better solution, depending on perf's needs. Signed-off-by: Andrii Nakryiko Cc: Alexei Starovoitov Cc: Daniel Borkmann Cc: kernel-team@fb.com LPU-Reference: 20210914170004.4185659-1-andrii@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/bpf-event.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c index 683f6d63560e..1a7112a87736 100644 --- a/tools/perf/util/bpf-event.c +++ b/tools/perf/util/bpf-event.c @@ -24,7 +24,10 @@ struct btf * __weak btf__load_from_kernel_by_id(__u32 id) { struct btf *btf; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" int err = btf__get_from_id(id, &btf); +#pragma GCC diagnostic pop return err ? ERR_PTR(err) : btf; } -- cgit From 8228e9361e2a7447eaed87499123e85871c8bc18 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 15 Sep 2021 14:14:28 -0700 Subject: perf parse-events: Avoid enum forward declaration. Enum forward declarations aren't allowed as the size can't be implied. Switch to just using an int. This fixes a clang warning: In file included from tools/perf/bench/evlist-open-close.c:13: tools/perf/bench/../util/parse-events.h:185:6: error: redeclaration of already-defined enum 'perf_tool_event' is a GNU extension [-Werror,-Wgnu-redeclared-enum] enum perf_tool_event; ^ tools/perf/bench/../util/evsel.h:28:6: note: previous definition is here enum perf_tool_event { ^ Signed-off-by: Ian Rogers Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Nathan Chancellor Cc: Nick Desaulniers Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/20210915211428.1773567-1-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 2 +- tools/perf/util/parse-events.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 51a2219df601..5d1346aa0627 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1471,7 +1471,7 @@ out_free_terms: int parse_events_add_tool(struct parse_events_state *parse_state, struct list_head *list, - enum perf_tool_event tool_event) + int tool_event) { return add_event_tool(list, &parse_state->idx, tool_event); } diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index bf6e41aa9b6a..b32ed3064c49 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -182,10 +182,9 @@ int parse_events_add_numeric(struct parse_events_state *parse_state, struct list_head *list, u32 type, u64 config, struct list_head *head_config); -enum perf_tool_event; int parse_events_add_tool(struct parse_events_state *parse_state, struct list_head *list, - enum perf_tool_event tool_event); + int tool_event); int parse_events_add_cache(struct list_head *list, int *idx, char *type, char *op_result1, char *op_result2, struct parse_events_error *error, -- cgit From 92d602bc7177325e7453189a22e0c8764ed3453e Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Tue, 7 Sep 2021 10:24:21 -0700 Subject: f2fs: should use GFP_NOFS for directory inodes We use inline_dentry which requires to allocate dentry page when adding a link. If we allow to reclaim memory from filesystem, we do down_read(&sbi->cp_rwsem) twice by f2fs_lock_op(). I think this should be okay, but how about stopping the lockdep complaint [1]? f2fs_create() - f2fs_lock_op() - f2fs_do_add_link() - __f2fs_find_entry - f2fs_get_read_data_page() -> kswapd - shrink_node - f2fs_evict_inode - f2fs_lock_op() [1] fs_reclaim ){+.+.}-{0:0} : kswapd0: lock_acquire+0x114/0x394 kswapd0: __fs_reclaim_acquire+0x40/0x50 kswapd0: prepare_alloc_pages+0x94/0x1ec kswapd0: __alloc_pages_nodemask+0x78/0x1b0 kswapd0: pagecache_get_page+0x2e0/0x57c kswapd0: f2fs_get_read_data_page+0xc0/0x394 kswapd0: f2fs_find_data_page+0xa4/0x23c kswapd0: find_in_level+0x1a8/0x36c kswapd0: __f2fs_find_entry+0x70/0x100 kswapd0: f2fs_do_add_link+0x84/0x1ec kswapd0: f2fs_mkdir+0xe4/0x1e4 kswapd0: vfs_mkdir+0x110/0x1c0 kswapd0: do_mkdirat+0xa4/0x160 kswapd0: __arm64_sys_mkdirat+0x24/0x34 kswapd0: el0_svc_common.llvm.17258447499513131576+0xc4/0x1e8 kswapd0: do_el0_svc+0x28/0xa0 kswapd0: el0_svc+0x24/0x38 kswapd0: el0_sync_handler+0x88/0xec kswapd0: el0_sync+0x1c0/0x200 kswapd0: -> #1 ( &sbi->cp_rwsem ){++++}-{3:3} : kswapd0: lock_acquire+0x114/0x394 kswapd0: down_read+0x7c/0x98 kswapd0: f2fs_do_truncate_blocks+0x78/0x3dc kswapd0: f2fs_truncate+0xc8/0x128 kswapd0: f2fs_evict_inode+0x2b8/0x8b8 kswapd0: evict+0xd4/0x2f8 kswapd0: iput+0x1c0/0x258 kswapd0: do_unlinkat+0x170/0x2a0 kswapd0: __arm64_sys_unlinkat+0x4c/0x68 kswapd0: el0_svc_common.llvm.17258447499513131576+0xc4/0x1e8 kswapd0: do_el0_svc+0x28/0xa0 kswapd0: el0_svc+0x24/0x38 kswapd0: el0_sync_handler+0x88/0xec kswapd0: el0_sync+0x1c0/0x200 Cc: stable@vger.kernel.org Fixes: bdbc90fa55af ("f2fs: don't put dentry page in pagecache into highmem") Reviewed-by: Chao Yu Reviewed-by: Stanley Chu Reviewed-by: Light Hsieh Tested-by: Light Hsieh Signed-off-by: Jaegeuk Kim --- fs/f2fs/inode.c | 2 +- fs/f2fs/namei.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 9141147b5bb0..1213f15ffd68 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -527,7 +527,7 @@ make_now: inode->i_op = &f2fs_dir_inode_operations; inode->i_fop = &f2fs_dir_operations; inode->i_mapping->a_ops = &f2fs_dblock_aops; - inode_nohighmem(inode); + mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS); } else if (S_ISLNK(inode->i_mode)) { if (file_is_encrypt(inode)) inode->i_op = &f2fs_encrypted_symlink_inode_operations; diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 9c528e583c9d..ae0838001480 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -757,7 +757,7 @@ static int f2fs_mkdir(struct user_namespace *mnt_userns, struct inode *dir, inode->i_op = &f2fs_dir_inode_operations; inode->i_fop = &f2fs_dir_operations; inode->i_mapping->a_ops = &f2fs_dblock_aops; - inode_nohighmem(inode); + mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS); set_inode_flag(inode, FI_INC_LINK); f2fs_lock_op(sbi); -- cgit From a5c0042200b28fff3bde6fa128ddeaef97990f8d Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Fri, 3 Sep 2021 10:38:11 +0800 Subject: f2fs: quota: fix potential deadlock As Yi Zhuang reported in bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=214299 There is potential deadlock during quota data flush as below: Thread A: Thread B: f2fs_dquot_acquire down_read(&sbi->quota_sem) f2fs_write_checkpoint block_operations f2fs_look_all down_write(&sbi->cp_rwsem) f2fs_quota_write f2fs_write_begin __do_map_lock f2fs_lock_op down_read(&sbi->cp_rwsem) __need_flush_qutoa down_write(&sbi->quota_sem) This patch changes block_operations() to use trylock, if it fails, it means there is potential quota data updater, in this condition, let's flush quota data first and then trylock again to check dirty status of quota data. The side effect is: in heavy race condition (e.g. multi quota data upaters vs quota data flusher), it may decrease the probability of synchronizing quota data successfully in checkpoint() due to limited retry time of quota flush. Reported-by: Yi Zhuang Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/checkpoint.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 83e9bc0f91ff..7b0282724231 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -1162,7 +1162,8 @@ static bool __need_flush_quota(struct f2fs_sb_info *sbi) if (!is_journalled_quota(sbi)) return false; - down_write(&sbi->quota_sem); + if (!down_write_trylock(&sbi->quota_sem)) + return true; if (is_sbi_flag_set(sbi, SBI_QUOTA_SKIP_FLUSH)) { ret = false; } else if (is_sbi_flag_set(sbi, SBI_QUOTA_NEED_REPAIR)) { -- cgit From c02599f210d90c76e42e2eb544511a47cceb60c9 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 1 Sep 2021 16:06:21 +0800 Subject: f2fs: avoid attaching SB_ACTIVE flag during mount Quoted from [1] "I do remember that I've added this code back then because otherwise orphan cleanup was losing updates to quota files. But you're right that now I don't see how that could be happening and it would be nice if we could get rid of this hack" [1] https://lore.kernel.org/linux-ext4/99cce8ca-e4a0-7301-840f-2ace67c551f3@huawei.com/T/#m04990cfbc4f44592421736b504afcc346b2a7c00 Related fix in ext4 by commit 72ffb49a7b62 ("ext4: do not set SB_ACTIVE in ext4_orphan_cleanup()"). f2fs has the same hack implementation in - f2fs_recover_orphan_inodes() - f2fs_recover_fsync_data() Let's get rid of this hack as well in f2fs. Cc: Zhang Yi Cc: Jan Kara Acked-by: Jan Kara Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/checkpoint.c | 3 --- fs/f2fs/recovery.c | 8 ++------ 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 7b0282724231..6f6a7d812d60 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -705,9 +705,6 @@ int f2fs_recover_orphan_inodes(struct f2fs_sb_info *sbi) } #ifdef CONFIG_QUOTA - /* Needed for iput() to work correctly and not trash data */ - sbi->sb->s_flags |= SB_ACTIVE; - /* * Turn on quotas which were not enabled for read-only mounts if * filesystem has quota feature, so that they are updated correctly. diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index 04655511d7f5..706ddb3c95c0 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -787,8 +787,6 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only) } #ifdef CONFIG_QUOTA - /* Needed for iput() to work correctly and not trash data */ - sbi->sb->s_flags |= SB_ACTIVE; /* Turn on quotas so that they are updated correctly */ quota_enabled = f2fs_enable_quota_files(sbi, s_flags & SB_RDONLY); #endif @@ -816,10 +814,8 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only) err = recover_data(sbi, &inode_list, &tmp_inode_list, &dir_list); if (!err) f2fs_bug_on(sbi, !list_empty(&inode_list)); - else { - /* restore s_flags to let iput() trash data */ - sbi->sb->s_flags = s_flags; - } + else + f2fs_bug_on(sbi, sbi->sb->s_flags & SB_ACTIVE); skip: fix_curseg_write_pointer = !check_only || list_empty(&inode_list); -- cgit From 84111b9c950ec9a8b31166973e79aa77ddcee7e3 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 10 Aug 2021 21:46:57 -0700 Subject: perf tools: Allow controlling synthesizing PERF_RECORD_ metadata events during record Depending on the use case, it might require some kind of synthesizing and some not. Make it controllable to turn off heavy operations like MMAP for all tasks. Currently all users are converted to enable all the synthesis by default. It'll be updated in the later patch. Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Andi Kleen Cc: Ian Rogers Cc: Ingo Molnar Cc: Jin Yao Cc: Peter Zijlstra Cc: Stephane Eranian Link: https //lore.kernel.org/r/20210811044658.1313391-1-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/bench/synthesize.c | 4 ++-- tools/perf/builtin-kvm.c | 2 +- tools/perf/builtin-record.c | 6 +++-- tools/perf/builtin-top.c | 2 +- tools/perf/builtin-trace.c | 4 ++-- tools/perf/tests/code-reading.c | 3 ++- tools/perf/tests/mmap-thread-lookup.c | 4 ++-- tools/perf/util/synthetic-events.c | 45 ++++++++++++++++++++--------------- tools/perf/util/synthetic-events.h | 8 +++---- 9 files changed, 44 insertions(+), 34 deletions(-) diff --git a/tools/perf/bench/synthesize.c b/tools/perf/bench/synthesize.c index 05f7c923c745..7401ebbac100 100644 --- a/tools/perf/bench/synthesize.c +++ b/tools/perf/bench/synthesize.c @@ -80,7 +80,7 @@ static int do_run_single_threaded(struct perf_session *session, NULL, target, threads, process_synthesized_event, - data_mmap, + true, data_mmap, nr_threads_synthesize); if (err) return err; @@ -171,7 +171,7 @@ static int do_run_multi_threaded(struct target *target, NULL, target, NULL, process_synthesized_event, - false, + true, false, nr_threads_synthesize); if (err) { perf_session__delete(session); diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index aa1b127ffb5b..c6f352ee57e6 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -1456,7 +1456,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm, perf_session__set_id_hdr_size(kvm->session); ordered_events__set_copy_on_queue(&kvm->session->ordered_events, true); machine__synthesize_threads(&kvm->session->machines.host, &kvm->opts.target, - kvm->evlist->core.threads, false, 1); + kvm->evlist->core.threads, true, false, 1); err = kvm_live_open_events(kvm); if (err) goto out; diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index b3509d9d20cc..0263e383332f 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -1266,6 +1266,7 @@ static int record__synthesize_workload(struct record *rec, bool tail) err = perf_event__synthesize_thread_map(&rec->tool, thread_map, process_synthesized_event, &rec->session->machines.host, + true, rec->opts.sample_address); perf_thread_map__put(thread_map); return err; @@ -1480,8 +1481,9 @@ static int record__synthesize(struct record *rec, bool tail) f = process_locked_synthesized_event; } - err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->core.threads, - f, opts->sample_address, + err = __machine__synthesize_threads(machine, tool, &opts->target, + rec->evlist->core.threads, + f, true, opts->sample_address, rec->opts.nr_threads_synthesize); if (rec->opts.nr_threads_synthesize > 1) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index a3ae9176a83e..020c4f110c10 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1271,7 +1271,7 @@ static int __cmd_top(struct perf_top *top) pr_debug("Couldn't synthesize cgroup events.\n"); machine__synthesize_threads(&top->session->machines.host, &opts->target, - top->evlist->core.threads, false, + top->evlist->core.threads, true, false, top->nr_threads_synthesize); if (top->nr_threads_synthesize > 1) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 2bf21194c7b3..2f1d20553a0a 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -1628,8 +1628,8 @@ static int trace__symbols_init(struct trace *trace, struct evlist *evlist) goto out; err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target, - evlist->core.threads, trace__tool_process, false, - 1); + evlist->core.threads, trace__tool_process, + true, false, 1); out: if (err) symbol__exit(); diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index 9866cddebf23..3a4d932e7ffc 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -606,7 +606,8 @@ static int do_test_code_reading(bool try_kcore) } ret = perf_event__synthesize_thread_map(NULL, threads, - perf_event__process, machine, false); + perf_event__process, machine, + true, false); if (ret < 0) { pr_debug("perf_event__synthesize_thread_map failed\n"); goto out_err; diff --git a/tools/perf/tests/mmap-thread-lookup.c b/tools/perf/tests/mmap-thread-lookup.c index 8d9d4cbff76d..6f2da7a72f67 100644 --- a/tools/perf/tests/mmap-thread-lookup.c +++ b/tools/perf/tests/mmap-thread-lookup.c @@ -135,7 +135,7 @@ static int synth_all(struct machine *machine) { return perf_event__synthesize_threads(NULL, perf_event__process, - machine, 0, 1); + machine, 1, 0, 1); } static int synth_process(struct machine *machine) @@ -147,7 +147,7 @@ static int synth_process(struct machine *machine) err = perf_event__synthesize_thread_map(NULL, map, perf_event__process, - machine, 0); + machine, 1, 0); perf_thread_map__put(map); return err; diff --git a/tools/perf/util/synthetic-events.c b/tools/perf/util/synthetic-events.c index a7e981b2d7de..a7a2825356d6 100644 --- a/tools/perf/util/synthetic-events.c +++ b/tools/perf/util/synthetic-events.c @@ -715,7 +715,8 @@ static int __event__synthesize_thread(union perf_event *comm_event, union perf_event *fork_event, union perf_event *namespaces_event, pid_t pid, int full, perf_event__handler_t process, - struct perf_tool *tool, struct machine *machine, bool mmap_data) + struct perf_tool *tool, struct machine *machine, + bool needs_mmap, bool mmap_data) { char filename[PATH_MAX]; struct dirent **dirent; @@ -739,7 +740,7 @@ static int __event__synthesize_thread(union perf_event *comm_event, * send mmap only for thread group leader * see thread__init_maps() */ - if (pid == tgid && + if (pid == tgid && needs_mmap && perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, process, machine, mmap_data)) return -1; @@ -786,7 +787,7 @@ static int __event__synthesize_thread(union perf_event *comm_event, break; rc = 0; - if (_pid == pid && !kernel_thread) { + if (_pid == pid && !kernel_thread && needs_mmap) { /* process the parent's maps too */ rc = perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, process, machine, mmap_data); @@ -806,7 +807,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool, struct perf_thread_map *threads, perf_event__handler_t process, struct machine *machine, - bool mmap_data) + bool needs_mmap, bool mmap_data) { union perf_event *comm_event, *mmap_event, *fork_event; union perf_event *namespaces_event; @@ -836,7 +837,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool, fork_event, namespaces_event, perf_thread_map__pid(threads, thread), 0, process, tool, machine, - mmap_data)) { + needs_mmap, mmap_data)) { err = -1; break; } @@ -862,7 +863,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool, fork_event, namespaces_event, comm_event->comm.pid, 0, process, tool, machine, - mmap_data)) { + needs_mmap, mmap_data)) { err = -1; break; } @@ -882,6 +883,7 @@ out: static int __perf_event__synthesize_threads(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine, + bool needs_mmap, bool mmap_data, struct dirent **dirent, int start, @@ -926,7 +928,7 @@ static int __perf_event__synthesize_threads(struct perf_tool *tool, */ __event__synthesize_thread(comm_event, mmap_event, fork_event, namespaces_event, pid, 1, process, - tool, machine, mmap_data); + tool, machine, needs_mmap, mmap_data); } err = 0; @@ -945,6 +947,7 @@ struct synthesize_threads_arg { struct perf_tool *tool; perf_event__handler_t process; struct machine *machine; + bool needs_mmap; bool mmap_data; struct dirent **dirent; int num; @@ -956,7 +959,8 @@ static void *synthesize_threads_worker(void *arg) struct synthesize_threads_arg *args = arg; __perf_event__synthesize_threads(args->tool, args->process, - args->machine, args->mmap_data, + args->machine, + args->needs_mmap, args->mmap_data, args->dirent, args->start, args->num); return NULL; @@ -965,7 +969,7 @@ static void *synthesize_threads_worker(void *arg) int perf_event__synthesize_threads(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine, - bool mmap_data, + bool needs_mmap, bool mmap_data, unsigned int nr_threads_synthesize) { struct synthesize_threads_arg *args = NULL; @@ -994,7 +998,8 @@ int perf_event__synthesize_threads(struct perf_tool *tool, if (thread_nr <= 1) { err = __perf_event__synthesize_threads(tool, process, - machine, mmap_data, + machine, + needs_mmap, mmap_data, dirent, base, n); goto free_dirent; } @@ -1015,6 +1020,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool, args[i].tool = tool; args[i].process = process; args[i].machine = machine; + args[i].needs_mmap = needs_mmap; args[i].mmap_data = mmap_data; args[i].dirent = dirent; } @@ -1775,26 +1781,27 @@ out_err: int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, struct target *target, struct perf_thread_map *threads, - perf_event__handler_t process, bool data_mmap, - unsigned int nr_threads_synthesize) + perf_event__handler_t process, bool needs_mmap, + bool data_mmap, unsigned int nr_threads_synthesize) { if (target__has_task(target)) - return perf_event__synthesize_thread_map(tool, threads, process, machine, data_mmap); + return perf_event__synthesize_thread_map(tool, threads, process, machine, + needs_mmap, data_mmap); else if (target__has_cpu(target)) - return perf_event__synthesize_threads(tool, process, - machine, data_mmap, + return perf_event__synthesize_threads(tool, process, machine, + needs_mmap, data_mmap, nr_threads_synthesize); /* command specified */ return 0; } int machine__synthesize_threads(struct machine *machine, struct target *target, - struct perf_thread_map *threads, bool data_mmap, - unsigned int nr_threads_synthesize) + struct perf_thread_map *threads, bool needs_mmap, + bool data_mmap, unsigned int nr_threads_synthesize) { return __machine__synthesize_threads(machine, NULL, target, threads, - perf_event__process, data_mmap, - nr_threads_synthesize); + perf_event__process, needs_mmap, + data_mmap, nr_threads_synthesize); } static struct perf_record_event_update *event_update_event__new(size_t size, u64 type, u64 id) diff --git a/tools/perf/util/synthetic-events.h b/tools/perf/util/synthetic-events.h index c845e2b9b444..44f72d56ca4d 100644 --- a/tools/perf/util/synthetic-events.h +++ b/tools/perf/util/synthetic-events.h @@ -53,8 +53,8 @@ int perf_event__synthesize_stat_events(struct perf_stat_config *config, struct p int perf_event__synthesize_stat_round(struct perf_tool *tool, u64 time, u64 type, perf_event__handler_t process, struct machine *machine); int perf_event__synthesize_stat(struct perf_tool *tool, u32 cpu, u32 thread, u64 id, struct perf_counts_values *count, perf_event__handler_t process, struct machine *machine); int perf_event__synthesize_thread_map2(struct perf_tool *tool, struct perf_thread_map *threads, perf_event__handler_t process, struct machine *machine); -int perf_event__synthesize_thread_map(struct perf_tool *tool, struct perf_thread_map *threads, perf_event__handler_t process, struct machine *machine, bool mmap_data); -int perf_event__synthesize_threads(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine, bool mmap_data, unsigned int nr_threads_synthesize); +int perf_event__synthesize_thread_map(struct perf_tool *tool, struct perf_thread_map *threads, perf_event__handler_t process, struct machine *machine, bool needs_mmap, bool mmap_data); +int perf_event__synthesize_threads(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine, bool needs_mmap, bool mmap_data, unsigned int nr_threads_synthesize); int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, struct evlist *evlist, perf_event__handler_t process); int perf_event__synth_time_conv(const struct perf_event_mmap_page *pc, struct perf_tool *tool, perf_event__handler_t process, struct machine *machine); pid_t perf_event__synthesize_comm(struct perf_tool *tool, union perf_event *event, pid_t pid, perf_event__handler_t process, struct machine *machine); @@ -65,10 +65,10 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, struct target *target, struct perf_thread_map *threads, - perf_event__handler_t process, bool data_mmap, + perf_event__handler_t process, bool needs_mmap, bool data_mmap, unsigned int nr_threads_synthesize); int machine__synthesize_threads(struct machine *machine, struct target *target, - struct perf_thread_map *threads, bool data_mmap, + struct perf_thread_map *threads, bool needs_mmap, bool data_mmap, unsigned int nr_threads_synthesize); #ifdef HAVE_AUXTRACE_SUPPORT -- cgit From 41b740b6e8a994e5830daa5e15785522874f7456 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 10 Aug 2021 21:46:58 -0700 Subject: perf record: Add --synth option Add an option to control the synthesizing behavior. --synth Fine-tune event synthesis: default=all This can be useful when we know it doesn't need some synthesis like in a specific usecase and/or when using pipe: $ perf record -a --all-cgroups --synth cgroup -o- sleep 1 | \ > perf report -i- -s cgroup Committer notes: Added a clarification to the man page entry for --synth that this is about pre-existing threads. Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Andi Kleen Cc: Ian Rogers Cc: Ingo Molnar Cc: Jin Yao Cc: Peter Zijlstra Cc: Stephane Eranian Link: https //lore.kernel.org/r/20210811044658.1313391-2-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-record.txt | 16 +++++++++++ tools/perf/builtin-record.c | 48 ++++++++++++++++++++++++++------ tools/perf/util/record.h | 1 + tools/perf/util/synthetic-events.c | 28 +++++++++++++++++++ tools/perf/util/synthetic-events.h | 12 ++++++++ 5 files changed, 96 insertions(+), 9 deletions(-) diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index f1079ee7f2ec..2d7df8703cf2 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -596,6 +596,22 @@ options. 'perf record --dry-run -e' can act as a BPF script compiler if llvm.dump-obj in config file is set to true. +--synth=TYPE:: +Collect and synthesize given type of events (comma separated). Note that +this option controls the synthesis from the /proc filesystem which represent +task status for pre-existing threads. + +Kernel (and some other) events are recorded regardless of the +choice in this option. For example, --synth=no would have MMAP events for +kernel and modules. + +Available types are: + 'task' - synthesize FORK and COMM events for each task + 'mmap' - synthesize MMAP events for each process (implies 'task') + 'cgroup' - synthesize CGROUP events for each cgroup + 'all' - synthesize all events (default) + 'no' - do not synthesize any of the above events + --tail-synthesize:: Instead of collecting non-sample events (for example, fork, comm, mmap) at the beginning of record, collect them during finalizing an output file. diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 0263e383332f..41bb884f5a74 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -1255,6 +1255,7 @@ static int record__synthesize_workload(struct record *rec, bool tail) { int err; struct perf_thread_map *thread_map; + bool needs_mmap = rec->opts.synth & PERF_SYNTH_MMAP; if (rec->opts.tail_synthesize != tail) return 0; @@ -1266,7 +1267,7 @@ static int record__synthesize_workload(struct record *rec, bool tail) err = perf_event__synthesize_thread_map(&rec->tool, thread_map, process_synthesized_event, &rec->session->machines.host, - true, + needs_mmap, rec->opts.sample_address); perf_thread_map__put(thread_map); return err; @@ -1471,20 +1472,26 @@ static int record__synthesize(struct record *rec, bool tail) if (err < 0) pr_warning("Couldn't synthesize bpf events.\n"); - err = perf_event__synthesize_cgroups(tool, process_synthesized_event, - machine); - if (err < 0) - pr_warning("Couldn't synthesize cgroup events.\n"); + if (rec->opts.synth & PERF_SYNTH_CGROUP) { + err = perf_event__synthesize_cgroups(tool, process_synthesized_event, + machine); + if (err < 0) + pr_warning("Couldn't synthesize cgroup events.\n"); + } if (rec->opts.nr_threads_synthesize > 1) { perf_set_multithreaded(); f = process_locked_synthesized_event; } - err = __machine__synthesize_threads(machine, tool, &opts->target, - rec->evlist->core.threads, - f, true, opts->sample_address, - rec->opts.nr_threads_synthesize); + if (rec->opts.synth & PERF_SYNTH_TASK) { + bool needs_mmap = rec->opts.synth & PERF_SYNTH_MMAP; + + err = __machine__synthesize_threads(machine, tool, &opts->target, + rec->evlist->core.threads, + f, needs_mmap, opts->sample_address, + rec->opts.nr_threads_synthesize); + } if (rec->opts.nr_threads_synthesize > 1) perf_set_singlethreaded(); @@ -2393,6 +2400,26 @@ static int process_timestamp_boundary(struct perf_tool *tool, return 0; } +static int parse_record_synth_option(const struct option *opt, + const char *str, + int unset __maybe_unused) +{ + struct record_opts *opts = opt->value; + char *p = strdup(str); + + if (p == NULL) + return -1; + + opts->synth = parse_synth_opt(p); + free(p); + + if (opts->synth < 0) { + pr_err("Invalid synth option: %s\n", str); + return -1; + } + return 0; +} + /* * XXX Ideally would be local to cmd_record() and passed to a record__new * because we need to have access to it in record__exit, that is called @@ -2418,6 +2445,7 @@ static struct record record = { .nr_threads_synthesize = 1, .ctl_fd = -1, .ctl_fd_ack = -1, + .synth = PERF_SYNTH_ALL, }, .tool = { .sample = process_sample_event, @@ -2633,6 +2661,8 @@ static struct option __record_options[] = { "\t\t\t Optionally send control command completion ('ack\\n') to ack-fd descriptor.\n" "\t\t\t Alternatively, ctl-fifo / ack-fifo will be opened and used as ctl-fd / ack-fd.", parse_control_option), + OPT_CALLBACK(0, "synth", &record.opts, "no|all|task|mmap|cgroup", + "Fine-tune event synthesis: default=all", parse_record_synth_option), OPT_END() }; diff --git a/tools/perf/util/record.h b/tools/perf/util/record.h index 68f471d9a88b..ef6c2715fdd9 100644 --- a/tools/perf/util/record.h +++ b/tools/perf/util/record.h @@ -77,6 +77,7 @@ struct record_opts { int ctl_fd; int ctl_fd_ack; bool ctl_fd_close; + int synth; }; extern const char * const *record_usage; diff --git a/tools/perf/util/synthetic-events.c b/tools/perf/util/synthetic-events.c index a7a2825356d6..198982109f0f 100644 --- a/tools/perf/util/synthetic-events.c +++ b/tools/perf/util/synthetic-events.c @@ -2237,3 +2237,31 @@ int perf_event__synthesize_for_pipe(struct perf_tool *tool, return ret; } + +int parse_synth_opt(char *synth) +{ + char *p, *q; + int ret = 0; + + if (synth == NULL) + return -1; + + for (q = synth; (p = strsep(&q, ",")); p = q) { + if (!strcasecmp(p, "no") || !strcasecmp(p, "none")) + return 0; + + if (!strcasecmp(p, "all")) + return PERF_SYNTH_ALL; + + if (!strcasecmp(p, "task")) + ret |= PERF_SYNTH_TASK; + else if (!strcasecmp(p, "mmap")) + ret |= PERF_SYNTH_TASK | PERF_SYNTH_MMAP; + else if (!strcasecmp(p, "cgroup")) + ret |= PERF_SYNTH_CGROUP; + else + return -1; + } + + return ret; +} diff --git a/tools/perf/util/synthetic-events.h b/tools/perf/util/synthetic-events.h index 44f72d56ca4d..c931433bacbf 100644 --- a/tools/perf/util/synthetic-events.h +++ b/tools/perf/util/synthetic-events.h @@ -27,6 +27,18 @@ struct target; union perf_event; +enum perf_record_synth { + PERF_SYNTH_TASK = 1 << 0, + PERF_SYNTH_MMAP = 1 << 1, + PERF_SYNTH_CGROUP = 1 << 2, + + /* last element */ + PERF_SYNTH_MAX = 1 << 3, +}; +#define PERF_SYNTH_ALL (PERF_SYNTH_MAX - 1) + +int parse_synth_opt(char *str); + typedef int (*perf_event__handler_t)(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine); -- cgit From ca42bc4b7bda7c6d68f1cc97c27fc8ff7385c4c7 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 31 Dec 2020 23:23:01 +0000 Subject: sh: fix trivial misannotations Trivial misannotations in * get_user() (__gu_addr is a userland pointer there) * ip_fast_csum() (sum is __wsum, not unsigned int) * csum_and_copy_to_user() (destination is void *, not const void * - mea culpa) * __clear_user() (to is a userland pointer) * several places in kernel/traps_32.c (regs->pc is a userland pointer when regs is a userland pt_regs) * math-emu/math.c: READ() and WRITE() casts of address should be to userland pointer. No changes in code generation and those take care of the majority of noise from sparse on sh builds. Signed-off-by: Al Viro Tested-by: John Paul Adrian Glaubitz Signed-off-by: Rich Felker --- arch/sh/include/asm/checksum_32.h | 5 +++-- arch/sh/include/asm/uaccess.h | 4 ++-- arch/sh/kernel/traps_32.c | 8 ++++---- arch/sh/math-emu/math.c | 4 ++-- arch/sh/mm/nommu.c | 4 ++-- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/arch/sh/include/asm/checksum_32.h b/arch/sh/include/asm/checksum_32.h index 1a391e3a7659..a6501b856f3e 100644 --- a/arch/sh/include/asm/checksum_32.h +++ b/arch/sh/include/asm/checksum_32.h @@ -84,7 +84,8 @@ static inline __sum16 csum_fold(__wsum sum) */ static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl) { - unsigned int sum, __dummy0, __dummy1; + __wsum sum; + unsigned int __dummy0, __dummy1; __asm__ __volatile__( "mov.l @%1+, %0\n\t" @@ -197,6 +198,6 @@ static inline __wsum csum_and_copy_to_user(const void *src, { if (!access_ok(dst, len)) return 0; - return csum_partial_copy_generic((__force const void *)src, dst, len); + return csum_partial_copy_generic(src, (__force void *)dst, len); } #endif /* __ASM_SH_CHECKSUM_H */ diff --git a/arch/sh/include/asm/uaccess.h b/arch/sh/include/asm/uaccess.h index 73f3b48d4a34..8867bb04b00e 100644 --- a/arch/sh/include/asm/uaccess.h +++ b/arch/sh/include/asm/uaccess.h @@ -68,7 +68,7 @@ struct __large_struct { unsigned long buf[100]; }; ({ \ long __gu_err = -EFAULT; \ unsigned long __gu_val = 0; \ - const __typeof__(*(ptr)) *__gu_addr = (ptr); \ + const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ if (likely(access_ok(__gu_addr, (size)))) \ __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \ (x) = (__force __typeof__(*(ptr)))__gu_val; \ @@ -124,7 +124,7 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long n) * Clear the area and return remaining number of bytes * (on failure. Usually it's 0.) */ -__kernel_size_t __clear_user(void *addr, __kernel_size_t size); +__kernel_size_t __clear_user(void __user *addr, __kernel_size_t size); #define clear_user(addr,n) \ ({ \ diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c index b62ad0ba2395..b3c715bc254b 100644 --- a/arch/sh/kernel/traps_32.c +++ b/arch/sh/kernel/traps_32.c @@ -490,7 +490,7 @@ asmlinkage void do_address_error(struct pt_regs *regs, inc_unaligned_user_access(); oldfs = force_uaccess_begin(); - if (copy_from_user(&instruction, (insn_size_t *)(regs->pc & ~1), + if (copy_from_user(&instruction, (insn_size_t __user *)(regs->pc & ~1), sizeof(instruction))) { force_uaccess_end(oldfs); goto uspace_segv; @@ -614,7 +614,7 @@ asmlinkage void do_reserved_inst(void) unsigned short inst = 0; int err; - get_user(inst, (unsigned short*)regs->pc); + get_user(inst, (unsigned short __user *)regs->pc); err = do_fpu_inst(inst, regs); if (!err) { @@ -699,9 +699,9 @@ asmlinkage void do_illegal_slot_inst(void) return; #ifdef CONFIG_SH_FPU_EMU - get_user(inst, (unsigned short *)regs->pc + 1); + get_user(inst, (unsigned short __user *)regs->pc + 1); if (!do_fpu_inst(inst, regs)) { - get_user(inst, (unsigned short *)regs->pc); + get_user(inst, (unsigned short __user *)regs->pc); if (!emulate_branch(inst, regs)) return; /* fault in branch.*/ diff --git a/arch/sh/math-emu/math.c b/arch/sh/math-emu/math.c index e8be0eca0444..3495a48b7713 100644 --- a/arch/sh/math-emu/math.c +++ b/arch/sh/math-emu/math.c @@ -51,8 +51,8 @@ #define Rn (regs->regs[n]) #define Rm (regs->regs[m]) -#define WRITE(d,a) ({if(put_user(d, (typeof (d)*)a)) return -EFAULT;}) -#define READ(d,a) ({if(get_user(d, (typeof (d)*)a)) return -EFAULT;}) +#define WRITE(d,a) ({if(put_user(d, (typeof (d) __user *)a)) return -EFAULT;}) +#define READ(d,a) ({if(get_user(d, (typeof (d) __user *)a)) return -EFAULT;}) #define PACK_S(r,f) FP_PACK_SP(&r,f) #define UNPACK_S(f,r) FP_UNPACK_SP(f,&r) diff --git a/arch/sh/mm/nommu.c b/arch/sh/mm/nommu.c index 8b4504413c5f..78c4b6e6d33b 100644 --- a/arch/sh/mm/nommu.c +++ b/arch/sh/mm/nommu.c @@ -28,9 +28,9 @@ __kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n) return 0; } -__kernel_size_t __clear_user(void *to, __kernel_size_t n) +__kernel_size_t __clear_user(void __user *to, __kernel_size_t n) { - memset(to, 0, n); + memset((__force void *)to, 0, n); return 0; } -- cgit From 0e38225c92c7964482a8bb6b3e37fde4319e965c Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Tue, 22 Dec 2020 12:54:01 -0800 Subject: sh: check return code of request_irq request_irq is marked __must_check, but the call in shx3_prepare_cpus has a void return type, so it can't propagate failure to the caller. Follow cues from hexagon and just print an error. Fixes: c7936b9abcf5 ("sh: smp: Hook in to the generic IPI handler for SH-X3 SMP.") Cc: Miguel Ojeda Cc: Paul Mundt Reported-by: Guenter Roeck Signed-off-by: Nick Desaulniers Tested-by: John Paul Adrian Glaubitz Reviewed-by: Miguel Ojeda Signed-off-by: Rich Felker --- arch/sh/kernel/cpu/sh4a/smp-shx3.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/sh/kernel/cpu/sh4a/smp-shx3.c b/arch/sh/kernel/cpu/sh4a/smp-shx3.c index f8a2bec0f260..1261dc7b84e8 100644 --- a/arch/sh/kernel/cpu/sh4a/smp-shx3.c +++ b/arch/sh/kernel/cpu/sh4a/smp-shx3.c @@ -73,8 +73,9 @@ static void shx3_prepare_cpus(unsigned int max_cpus) BUILD_BUG_ON(SMP_MSG_NR >= 8); for (i = 0; i < SMP_MSG_NR; i++) - request_irq(104 + i, ipi_interrupt_handler, - IRQF_PERCPU, "IPI", (void *)(long)i); + if (request_irq(104 + i, ipi_interrupt_handler, + IRQF_PERCPU, "IPI", (void *)(long)i)) + pr_err("Failed to request irq %d\n", i); for (i = 0; i < max_cpus; i++) set_cpu_present(i, true); -- cgit From 0341bd3915f85784132fc76df7dfe6aaffba6d14 Mon Sep 17 00:00:00 2001 From: Tang Bin Date: Thu, 19 Nov 2020 18:56:56 +0800 Subject: sh: boards: Fix the cacography in irq.c The word 'swtich' is wrong, so fix it. Signed-off-by: Tang Bin Reviewed-by: John Paul Adrian Glaubitz Signed-off-by: Rich Felker --- arch/sh/boards/mach-landisk/irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sh/boards/mach-landisk/irq.c b/arch/sh/boards/mach-landisk/irq.c index 29b8b1f85246..0b672b80c561 100644 --- a/arch/sh/boards/mach-landisk/irq.c +++ b/arch/sh/boards/mach-landisk/irq.c @@ -26,8 +26,8 @@ enum { PCI_INTD, /* PCI int D */ ATA, /* ATA */ FATA, /* CF */ - POWER, /* Power swtich */ - BUTTON, /* Button swtich */ + POWER, /* Power switch */ + BUTTON, /* Button switch */ }; /* Vectors for LANDISK */ -- cgit From 7b6ef6e570eab9714f9b2374e0bad179bff99fdd Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 17 Jan 2021 20:16:31 +0900 Subject: sh: boot: add intermediate vmlinux.bin* to targets instead of extra-y You do not need to build all of vmlinux.bin* They are built on demand as prerequsites of uImage.bin*, hence should be added to targets instead of extra-y. Signed-off-by: Masahiro Yamada Tested-by: John Paul Adrian Glaubitz Signed-off-by: Rich Felker --- arch/sh/boot/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sh/boot/Makefile b/arch/sh/boot/Makefile index 58592dfa5cb6..dded61296c9a 100644 --- a/arch/sh/boot/Makefile +++ b/arch/sh/boot/Makefile @@ -27,8 +27,8 @@ suffix-$(CONFIG_KERNEL_XZ) := xz suffix-$(CONFIG_KERNEL_LZO) := lzo targets := zImage vmlinux.srec romImage uImage uImage.srec uImage.gz \ - uImage.bz2 uImage.lzma uImage.xz uImage.lzo uImage.bin -extra-y += vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \ + uImage.bz2 uImage.lzma uImage.xz uImage.lzo uImage.bin \ + vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \ vmlinux.bin.xz vmlinux.bin.lzo subdir- := compressed romimage -- cgit From 7fe859eef99b6fac655416d5bb01c82bd0da2ada Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 17 Jan 2021 20:16:32 +0900 Subject: sh: boot: avoid unneeded rebuilds under arch/sh/boot/compressed/ Even if none of source code is updated, the following are every time rebuilt: CC arch/sh/boot/compressed/cache.o SHIPPED arch/sh/boot/compressed/ashiftrt.S AS arch/sh/boot/compressed/ashiftrt.o SHIPPED arch/sh/boot/compressed/ashldi3.c CC arch/sh/boot/compressed/ashldi3.o SHIPPED arch/sh/boot/compressed/ashrsi3.S AS arch/sh/boot/compressed/ashrsi3.o SHIPPED arch/sh/boot/compressed/ashlsi3.S AS arch/sh/boot/compressed/ashlsi3.o SHIPPED arch/sh/boot/compressed/lshrsi3.S AS arch/sh/boot/compressed/lshrsi3.o LD arch/sh/boot/compressed/vmlinux OBJCOPY arch/sh/boot/zImage Add build artifacts to 'targets' as needed. I turned the library files to check-in files. It is simpler than copying from arch/sh/lib/ at build-time. Signed-off-by: Masahiro Yamada Tested-by: John Paul Adrian Glaubitz Signed-off-by: Rich Felker --- arch/sh/boot/compressed/.gitignore | 5 ----- arch/sh/boot/compressed/Makefile | 32 +++++++++++++------------------- arch/sh/boot/compressed/ashiftrt.S | 2 ++ arch/sh/boot/compressed/ashldi3.c | 2 ++ arch/sh/boot/compressed/ashlsi3.S | 2 ++ arch/sh/boot/compressed/ashrsi3.S | 2 ++ arch/sh/boot/compressed/lshrsi3.S | 2 ++ 7 files changed, 23 insertions(+), 24 deletions(-) create mode 100644 arch/sh/boot/compressed/ashiftrt.S create mode 100644 arch/sh/boot/compressed/ashldi3.c create mode 100644 arch/sh/boot/compressed/ashlsi3.S create mode 100644 arch/sh/boot/compressed/ashrsi3.S create mode 100644 arch/sh/boot/compressed/lshrsi3.S diff --git a/arch/sh/boot/compressed/.gitignore b/arch/sh/boot/compressed/.gitignore index 37aa53057369..cd16663bc7c8 100644 --- a/arch/sh/boot/compressed/.gitignore +++ b/arch/sh/boot/compressed/.gitignore @@ -1,7 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only -ashiftrt.S -ashldi3.c -ashlsi3.S -ashrsi3.S -lshrsi3.S vmlinux.bin.* diff --git a/arch/sh/boot/compressed/Makefile b/arch/sh/boot/compressed/Makefile index 589d2d8a573d..cf3174df7859 100644 --- a/arch/sh/boot/compressed/Makefile +++ b/arch/sh/boot/compressed/Makefile @@ -5,12 +5,18 @@ # create a compressed vmlinux image from the original vmlinux # -targets := vmlinux vmlinux.bin vmlinux.bin.gz \ - vmlinux.bin.bz2 vmlinux.bin.lzma \ - vmlinux.bin.xz vmlinux.bin.lzo \ - head_32.o misc.o piggy.o +OBJECTS := head_32.o misc.o cache.o piggy.o \ + ashiftrt.o ashldi3.o ashrsi3.o ashlsi3.o lshrsi3.o + +# These were previously generated files. When you are building the kernel +# with O=, make sure to remove the stale files in the output tree. Otherwise, +# the build system wrongly compiles the stale ones. +ifdef building_out_of_srctree +$(shell rm -f $(addprefix $(obj)/, ashiftrt.S ashldi3.c ashrsi3.S ashlsi3.S lshrsi3.S)) +endif -OBJECTS = $(obj)/head_32.o $(obj)/misc.o $(obj)/cache.o +targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 \ + vmlinux.bin.lzma vmlinux.bin.xz vmlinux.bin.lzo $(OBJECTS) GCOV_PROFILE := n @@ -33,21 +39,9 @@ ccflags-remove-$(CONFIG_MCOUNT) += -pg LDFLAGS_vmlinux := --oformat $(ld-bfd) -Ttext $(IMAGE_OFFSET) -e startup \ -T $(obj)/../../kernel/vmlinux.lds -# -# Pull in the necessary libgcc bits from the in-kernel implementation. -# -lib1funcs-y := ashiftrt.S ashldi3.c ashrsi3.S ashlsi3.S lshrsi3.S -lib1funcs-obj := \ - $(addsuffix .o, $(basename $(addprefix $(obj)/, $(lib1funcs-y)))) - -lib1funcs-dir := $(srctree)/arch/$(SRCARCH)/lib - -KBUILD_CFLAGS += -I$(lib1funcs-dir) -DDISABLE_BRANCH_PROFILING - -$(addprefix $(obj)/,$(lib1funcs-y)): $(obj)/%: $(lib1funcs-dir)/% FORCE - $(call cmd,shipped) +KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING -$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o $(lib1funcs-obj) FORCE +$(obj)/vmlinux: $(addprefix $(obj)/, $(OBJECTS)) FORCE $(call if_changed,ld) $(obj)/vmlinux.bin: vmlinux FORCE diff --git a/arch/sh/boot/compressed/ashiftrt.S b/arch/sh/boot/compressed/ashiftrt.S new file mode 100644 index 000000000000..0f3b291a3f4b --- /dev/null +++ b/arch/sh/boot/compressed/ashiftrt.S @@ -0,0 +1,2 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#include "../../lib/ashiftrt.S" diff --git a/arch/sh/boot/compressed/ashldi3.c b/arch/sh/boot/compressed/ashldi3.c new file mode 100644 index 000000000000..7cebd646df83 --- /dev/null +++ b/arch/sh/boot/compressed/ashldi3.c @@ -0,0 +1,2 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include "../../lib/ashldi3.c" diff --git a/arch/sh/boot/compressed/ashlsi3.S b/arch/sh/boot/compressed/ashlsi3.S new file mode 100644 index 000000000000..e354262b275f --- /dev/null +++ b/arch/sh/boot/compressed/ashlsi3.S @@ -0,0 +1,2 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#include "../../lib/ashlsi3.S" diff --git a/arch/sh/boot/compressed/ashrsi3.S b/arch/sh/boot/compressed/ashrsi3.S new file mode 100644 index 000000000000..e564be9a4dcd --- /dev/null +++ b/arch/sh/boot/compressed/ashrsi3.S @@ -0,0 +1,2 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#include "../../lib/ashrsi3.S" diff --git a/arch/sh/boot/compressed/lshrsi3.S b/arch/sh/boot/compressed/lshrsi3.S new file mode 100644 index 000000000000..5a8281b7e516 --- /dev/null +++ b/arch/sh/boot/compressed/lshrsi3.S @@ -0,0 +1,2 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#include "../../lib/lshrsi3.S" -- cgit From bde82ee391fa6d3ad054313c4aa7b726d32515ce Mon Sep 17 00:00:00 2001 From: Lu Wei Date: Thu, 26 Nov 2020 10:43:11 +0800 Subject: maple: fix wrong return value of maple_bus_init(). If KMEM_CACHE or maple_alloc_dev failed, the maple_bus_init() will return 0 rather than error, because the retval is not changed after KMEM_CACHE or maple_alloc_dev failed. Fixes: 17be2d2b1c33 ("sh: Add maple bus support for the SEGA Dreamcast.") Reported-by: Hulk Robot Signed-off-by: Lu Wei Acked-by: John Paul Adrian Glaubitz Signed-off-by: Rich Felker --- drivers/sh/maple/maple.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/sh/maple/maple.c b/drivers/sh/maple/maple.c index bd0fbcdbdefe..e24e220e56ee 100644 --- a/drivers/sh/maple/maple.c +++ b/drivers/sh/maple/maple.c @@ -834,8 +834,10 @@ static int __init maple_bus_init(void) maple_queue_cache = KMEM_CACHE(maple_buffer, SLAB_HWCACHE_ALIGN); - if (!maple_queue_cache) + if (!maple_queue_cache) { + retval = -ENOMEM; goto cleanup_bothirqs; + } INIT_LIST_HEAD(&maple_waitq); INIT_LIST_HEAD(&maple_sentq); @@ -848,6 +850,7 @@ static int __init maple_bus_init(void) if (!mdev[i]) { while (i-- > 0) maple_free_dev(mdev[i]); + retval = -ENOMEM; goto cleanup_cache; } baseunits[i] = mdev[i]; -- cgit From 12285ff8667bf06c168113c10d3619834e423ae6 Mon Sep 17 00:00:00 2001 From: Yejune Deng Date: Thu, 10 Dec 2020 14:49:58 +0800 Subject: sh: kdump: add some attribute to function add '__iomem' for ioremap() and '__user' for copy_to_user(). Signed-off-by: Yejune Deng Tested-by: John Paul Adrian Glaubitz Signed-off-by: Rich Felker --- arch/sh/kernel/crash_dump.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sh/kernel/crash_dump.c b/arch/sh/kernel/crash_dump.c index a9086127b16d..5b41b59698c1 100644 --- a/arch/sh/kernel/crash_dump.c +++ b/arch/sh/kernel/crash_dump.c @@ -26,7 +26,7 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf, size_t csize, unsigned long offset, int userbuf) { - void *vaddr; + void __iomem *vaddr; if (!csize) return 0; @@ -34,7 +34,7 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf, vaddr = ioremap(pfn << PAGE_SHIFT, PAGE_SIZE); if (userbuf) { - if (copy_to_user(buf, (vaddr + offset), csize)) { + if (copy_to_user((void __user *)buf, (vaddr + offset), csize)) { iounmap(vaddr); return -EFAULT; } -- cgit From 3a19407913e8e43d6b799a59bc0f6cae889b5446 Mon Sep 17 00:00:00 2001 From: Wang Lu Date: Thu, 9 Sep 2021 11:25:28 +0800 Subject: PCI/P2PDMA: Apply bus offset correctly in DMA address calculation The bus offset is bus address - physical address, so the calculation in __pci_p2pdma_map_sg should be: bus address = physical address + bus offset. Correct the dma_address computation in __pci_p2pdma_map_sg(). Link: https://lore.kernel.org/r/20210909032528.24517-1-wanglu@dapustor.com Signed-off-by: Wang Lu Signed-off-by: Bjorn Helgaas Reviewed-by: Logan Gunthorpe --- drivers/pci/p2pdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c index 50cdde3e9a8b..327882638b30 100644 --- a/drivers/pci/p2pdma.c +++ b/drivers/pci/p2pdma.c @@ -874,7 +874,7 @@ static int __pci_p2pdma_map_sg(struct pci_p2pdma_pagemap *p2p_pgmap, int i; for_each_sg(sg, s, nents, i) { - s->dma_address = sg_phys(s) - p2p_pgmap->bus_offset; + s->dma_address = sg_phys(s) + p2p_pgmap->bus_offset; sg_dma_len(s) = s->length; } -- cgit From e3f4bd3462f6f796594ecc0dda7144ed2d1e5a26 Mon Sep 17 00:00:00 2001 From: Ingmar Klein Date: Fri, 9 Apr 2021 11:26:33 +0200 Subject: PCI: Mark Atheros QCA6174 to avoid bus reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When passing the Atheros QCA6174 through to a virtual machine, the VM hangs at the point where the ath10k driver loads. Add a quirk to avoid bus resets on this device, which avoids the hang. [bhelgaas: commit log] Link: https://lore.kernel.org/r/08982e05-b6e8-5a8d-24ab-da1488ee50a8@web.de Signed-off-by: Ingmar Klein Signed-off-by: Bjorn Helgaas Reviewed-by: Pali Rohár Cc: stable@vger.kernel.org --- drivers/pci/quirks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 4537d1ea14fd..6c957124f84d 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3612,6 +3612,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0032, quirk_no_bus_reset); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x003c, quirk_no_bus_reset); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0033, quirk_no_bus_reset); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0034, quirk_no_bus_reset); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x003e, quirk_no_bus_reset); /* * Root port on some Cavium CN8xxx chips do not successfully complete a bus -- cgit From 0e8ae5a6ff5952253cd7cc0260df838ab4c21009 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 30 Aug 2021 10:08:10 +0200 Subject: PCI/portdrv: Do not setup up IRQs if there are no users Avoid registering service IRQs if there is no service that offers them or no driver to register a handler against them. This saves IRQ vectors when they are limited (e.g. on x86) and also avoids that spurious events could hit a missing handler. Such spurious events need to be generated by the Jailhouse hypervisor for active MSI vectors when enabling or disabling itself. Link: https://lore.kernel.org/r/8f9a13ac-8ab1-15ac-06cb-c131b488a36f@siemens.com Signed-off-by: Jan Kiszka Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/portdrv_core.c | 47 ++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 3ee63968deaa..bf5440c3ca8a 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -166,9 +166,6 @@ static int pcie_init_service_irqs(struct pci_dev *dev, int *irqs, int mask) { int ret, i; - for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) - irqs[i] = -1; - /* * If we support PME but can't use MSI/MSI-X for it, we have to * fall back to INTx or other interrupts, e.g., a system shared @@ -317,8 +314,10 @@ static int pcie_device_init(struct pci_dev *pdev, int service, int irq) */ int pcie_port_device_register(struct pci_dev *dev) { - int status, capabilities, i, nr_service; - int irqs[PCIE_PORT_DEVICE_MAXSERVICES]; + int status, capabilities, irq_services, i, nr_service; + int irqs[PCIE_PORT_DEVICE_MAXSERVICES] = { + [0 ... PCIE_PORT_DEVICE_MAXSERVICES-1] = -1 + }; /* Enable PCI Express port device */ status = pci_enable_device(dev); @@ -331,18 +330,32 @@ int pcie_port_device_register(struct pci_dev *dev) return 0; pci_set_master(dev); - /* - * Initialize service irqs. Don't use service devices that - * require interrupts if there is no way to generate them. - * However, some drivers may have a polling mode (e.g. pciehp_poll_mode) - * that can be used in the absence of irqs. Allow them to determine - * if that is to be used. - */ - status = pcie_init_service_irqs(dev, irqs, capabilities); - if (status) { - capabilities &= PCIE_PORT_SERVICE_HP; - if (!capabilities) - goto error_disable; + + irq_services = 0; + if (IS_ENABLED(CONFIG_PCIE_PME)) + irq_services |= PCIE_PORT_SERVICE_PME; + if (IS_ENABLED(CONFIG_PCIEAER)) + irq_services |= PCIE_PORT_SERVICE_AER; + if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)) + irq_services |= PCIE_PORT_SERVICE_HP; + if (IS_ENABLED(CONFIG_PCIE_DPC)) + irq_services |= PCIE_PORT_SERVICE_DPC; + irq_services &= capabilities; + + if (irq_services) { + /* + * Initialize service IRQs. Don't use service devices that + * require interrupts if there is no way to generate them. + * However, some drivers may have a polling mode (e.g. + * pciehp_poll_mode) that can be used in the absence of IRQs. + * Allow them to determine if that is to be used. + */ + status = pcie_init_service_irqs(dev, irqs, irq_services); + if (status) { + irq_services &= PCIE_PORT_SERVICE_HP; + if (!irq_services) + goto error_disable; + } } /* Allocate child services if any */ -- cgit From 287b1406dde2bc80f468c73708e7f7a87be390ea Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 16 Sep 2021 17:09:03 +0800 Subject: f2fs: introduce excess_dirty_threshold() This patch enables f2fs_balance_fs_bg() to check all metadatas' dirty threshold rather than just checking node block's, so that checkpoint() from background can be triggered more frequently to avoid heaping up too much dirty metadatas. Threshold value by default: race with foreground ops single type global No 16MB 24MB Yes 24MB 36MB In addtion, let f2fs_balance_fs_bg() be aware of roll-forward sapce as well as fsync(). Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/f2fs.h | 3 +++ fs/f2fs/node.h | 5 ----- fs/f2fs/segment.c | 23 +++++++++++++++++++++-- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index b339ae89c1ad..039a229e11c9 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -561,6 +561,9 @@ enum { #define MAX_DIR_RA_PAGES 4 /* maximum ra pages of dir */ +/* dirty segments threshold for triggering CP */ +#define DEFAULT_DIRTY_THRESHOLD 4 + /* for in-memory extent cache entry */ #define F2FS_MIN_EXTENT_LEN 64 /* minimum extent length */ diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h index ff14a6e5ac1c..18b98cf0465b 100644 --- a/fs/f2fs/node.h +++ b/fs/f2fs/node.h @@ -138,11 +138,6 @@ static inline bool excess_cached_nats(struct f2fs_sb_info *sbi) return NM_I(sbi)->nat_cnt[TOTAL_NAT] >= DEF_NAT_CACHE_THRESHOLD; } -static inline bool excess_dirty_nodes(struct f2fs_sb_info *sbi) -{ - return get_pages(sbi, F2FS_DIRTY_NODES) >= sbi->blocks_per_seg * 8; -} - enum mem_type { FREE_NIDS, /* indicates the free nid list */ NAT_ENTRIES, /* indicates the cached nat entry */ diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index a135d2247415..f3f4dee43985 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -529,6 +529,25 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need) } } +static inline bool excess_dirty_threshold(struct f2fs_sb_info *sbi) +{ + int factor = rwsem_is_locked(&sbi->cp_rwsem) ? 3 : 2; + unsigned int dents = get_pages(sbi, F2FS_DIRTY_DENTS); + unsigned int qdata = get_pages(sbi, F2FS_DIRTY_QDATA); + unsigned int nodes = get_pages(sbi, F2FS_DIRTY_NODES); + unsigned int meta = get_pages(sbi, F2FS_DIRTY_META); + unsigned int imeta = get_pages(sbi, F2FS_DIRTY_IMETA); + unsigned int threshold = sbi->blocks_per_seg * factor * + DEFAULT_DIRTY_THRESHOLD; + unsigned int global_threshold = threshold * 3 / 2; + + if (dents >= threshold || qdata >= threshold || + nodes >= threshold || meta >= threshold || + imeta >= threshold) + return true; + return dents + qdata + nodes + meta + imeta > global_threshold; +} + void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi, bool from_bg) { if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) @@ -547,8 +566,8 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi, bool from_bg) else f2fs_build_free_nids(sbi, false, false); - if (excess_dirty_nats(sbi) || excess_dirty_nodes(sbi) || - excess_prefree_segs(sbi)) + if (excess_dirty_nats(sbi) || excess_dirty_threshold(sbi) || + excess_prefree_segs(sbi) || !f2fs_space_for_roll_forward(sbi)) goto do_sync; /* there is background inflight IO or foreground operation recently */ -- cgit From 6663b138ded1a59e630c9e605e42aa7fde490cdc Mon Sep 17 00:00:00 2001 From: Weichao Guo Date: Sat, 18 Sep 2021 20:46:36 +0800 Subject: f2fs: set SBI_NEED_FSCK flag when inconsistent node block found Inconsistent node block will cause a file fail to open or read, which could make the user process crashes or stucks. Let's mark SBI_NEED_FSCK flag to trigger a fix at next fsck time. After unlinking the corrupted file, the user process could regenerate a new one and work correctly. Signed-off-by: Weichao Guo Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/node.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index e863136081b4..556fcd8457f3 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1443,6 +1443,7 @@ page_hit: nid, nid_of_node(page), ino_of_node(page), ofs_of_node(page), cpver_of_node(page), next_blkaddr_of_node(page)); + set_sbi_flag(sbi, SBI_NEED_FSCK); err = -EINVAL; out_err: ClearPageUptodate(page); -- cgit From cef6f5cc140852fcb6c75f85b8e6ba00d7de1bad Mon Sep 17 00:00:00 2001 From: Len Baker Date: Sat, 11 Sep 2021 15:55:27 -0700 Subject: Input: omap-keypad - prefer struct_size over open coded arithmetic As noted in the "Deprecated Interfaces, Language Features, Attributes, and Conventions" documentation [1], size calculations (especially multiplication) should not be performed in memory allocator (or similar) function arguments due to the risk of them overflowing. This could lead to values wrapping around and a smaller allocation being made than the caller was expecting. Using those allocations could lead to linear overflows of heap memory and other misbehaviors. So, use the struct_size() helper to do the arithmetic instead of the argument "size + count * size" in the kzalloc() function. [1] https://www.kernel.org/doc/html/v5.14/process/deprecated.html#open-coded-arithmetic-in-allocator-arguments Signed-off-by: Len Baker Link: https://lore.kernel.org/r/20210911112716.10067-1-len.baker@gmx.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/omap-keypad.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c index dbe836c7ff47..eb3a687796e7 100644 --- a/drivers/input/keyboard/omap-keypad.c +++ b/drivers/input/keyboard/omap-keypad.c @@ -190,8 +190,7 @@ static int omap_kp_probe(struct platform_device *pdev) row_shift = get_count_order(pdata->cols); keycodemax = pdata->rows << row_shift; - omap_kp = kzalloc(sizeof(struct omap_kp) + - keycodemax * sizeof(unsigned short), GFP_KERNEL); + omap_kp = kzalloc(struct_size(omap_kp, keymap, keycodemax), GFP_KERNEL); input_dev = input_allocate_device(); if (!omap_kp || !input_dev) { kfree(omap_kp); -- cgit From f1c80ba0cc8e7ae015a4b4828564e22f0b583ad5 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 20 Sep 2021 18:15:07 -0700 Subject: Input: tmdc - fix spelling mistake "Millenium" -> "Millennium" There is a spelling mistake in the name of a joystick. Fix it. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20210920184748.18519-1-colin.king@canonical.com Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/tmdc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c index f89e9aa6d328..7416de84b955 100644 --- a/drivers/input/joystick/tmdc.c +++ b/drivers/input/joystick/tmdc.c @@ -83,7 +83,7 @@ static const struct tmdc_model { const signed char *axes; const short *buttons; } tmdc_models[] = { - { 1, "ThrustMaster Millenium 3D Inceptor", 6, 2, { 4, 2 }, { 4, 6 }, tmdc_abs, tmdc_btn_joy }, + { 1, "ThrustMaster Millennium 3D Inceptor", 6, 2, { 4, 2 }, { 4, 6 }, tmdc_abs, tmdc_btn_joy }, { 3, "ThrustMaster Rage 3D Gamepad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad }, { 4, "ThrustMaster Attack Throttle", 5, 2, { 4, 6 }, { 4, 2 }, tmdc_abs_at, tmdc_btn_at }, { 8, "ThrustMaster FragMaster", 4, 0, { 8, 2 }, { 0, 0 }, tmdc_abs_fm, tmdc_btn_fm }, -- cgit From 31ae0102a34ed863c7d32b10e768036324991679 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 20 Sep 2021 21:08:02 -0700 Subject: Input: goodix - change goodix_i2c_write() len parameter type to int Change the type of the goodix_i2c_write() len parameter to from 'unsigned' to 'int' to avoid bare use of 'unsigned', changing it to 'int' makes goodix_i2c_write()' prototype consistent with goodix_i2c_read(). Reviewed-by: Bastien Nocera Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210920150643.155872-2-hdegoede@redhat.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/goodix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index c682b028f0a2..00536064f45e 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -290,7 +290,7 @@ static int goodix_i2c_read(struct i2c_client *client, * @len: length of the buffer to write */ static int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf, - unsigned len) + int len) { u8 *addr_buf; struct i2c_msg msg; -- cgit From a2233cb7b65a017067e2f2703375ecc930a0ab30 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 20 Sep 2021 21:08:18 -0700 Subject: Input: goodix - add a goodix.h header file Add a goodix.h header file, and move the register definitions, and struct declarations there and add prototypes for various helper functions. This is a preparation patch for adding support for controllers without flash, which need to have their firmware uploaded and need some other special handling too. Since MAINTAINERS needs updating because of this change anyways, also add myself as co-maintainer. Reviewed-by: Bastien Nocera Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210920150643.155872-3-hdegoede@redhat.com Signed-off-by: Dmitry Torokhov --- MAINTAINERS | 3 +- drivers/input/touchscreen/goodix.c | 74 ++++---------------------------------- drivers/input/touchscreen/goodix.h | 73 +++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 69 deletions(-) create mode 100644 drivers/input/touchscreen/goodix.h diff --git a/MAINTAINERS b/MAINTAINERS index 44e6c428703e..7ab4a058fe4d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7716,9 +7716,10 @@ F: drivers/media/usb/go7007/ GOODIX TOUCHSCREEN M: Bastien Nocera +M: Hans de Goede L: linux-input@vger.kernel.org S: Maintained -F: drivers/input/touchscreen/goodix.c +F: drivers/input/touchscreen/goodix* GOOGLE ETHERNET DRIVERS M: Catherine Sullivan diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index 00536064f45e..76e93bc8389a 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -14,20 +14,15 @@ #include #include #include -#include -#include -#include -#include -#include #include #include #include #include -#include #include #include #include #include +#include "goodix.h" #define GOODIX_GPIO_INT_NAME "irq" #define GOODIX_GPIO_RST_NAME "reset" @@ -38,22 +33,11 @@ #define GOODIX_CONTACT_SIZE 8 #define GOODIX_MAX_CONTACT_SIZE 9 #define GOODIX_MAX_CONTACTS 10 -#define GOODIX_MAX_KEYS 7 #define GOODIX_CONFIG_MIN_LENGTH 186 #define GOODIX_CONFIG_911_LENGTH 186 #define GOODIX_CONFIG_967_LENGTH 228 #define GOODIX_CONFIG_GT9X_LENGTH 240 -#define GOODIX_CONFIG_MAX_LENGTH 240 - -/* Register defines */ -#define GOODIX_REG_COMMAND 0x8040 -#define GOODIX_CMD_SCREEN_OFF 0x05 - -#define GOODIX_READ_COOR_ADDR 0x814E -#define GOODIX_GT1X_REG_CONFIG_DATA 0x8050 -#define GOODIX_GT9X_REG_CONFIG_DATA 0x8047 -#define GOODIX_REG_ID 0x8140 #define GOODIX_BUFFER_STATUS_READY BIT(7) #define GOODIX_HAVE_KEY BIT(4) @@ -68,55 +52,11 @@ #define ACPI_GPIO_SUPPORT #endif -struct goodix_ts_data; - -enum goodix_irq_pin_access_method { - IRQ_PIN_ACCESS_NONE, - IRQ_PIN_ACCESS_GPIO, - IRQ_PIN_ACCESS_ACPI_GPIO, - IRQ_PIN_ACCESS_ACPI_METHOD, -}; - -struct goodix_chip_data { - u16 config_addr; - int config_len; - int (*check_config)(struct goodix_ts_data *ts, const u8 *cfg, int len); - void (*calc_config_checksum)(struct goodix_ts_data *ts); -}; - struct goodix_chip_id { const char *id; const struct goodix_chip_data *data; }; -#define GOODIX_ID_MAX_LEN 4 - -struct goodix_ts_data { - struct i2c_client *client; - struct input_dev *input_dev; - const struct goodix_chip_data *chip; - struct touchscreen_properties prop; - unsigned int max_touch_num; - unsigned int int_trigger_type; - struct regulator *avdd28; - struct regulator *vddio; - struct gpio_desc *gpiod_int; - struct gpio_desc *gpiod_rst; - int gpio_count; - int gpio_int_idx; - char id[GOODIX_ID_MAX_LEN + 1]; - u16 version; - const char *cfg_name; - bool reset_controller_at_probe; - bool load_cfg_from_disk; - struct completion firmware_loading_complete; - unsigned long irq_flags; - enum goodix_irq_pin_access_method irq_pin_access_method; - unsigned int contact_size; - u8 config[GOODIX_CONFIG_MAX_LENGTH]; - unsigned short keymap[GOODIX_MAX_KEYS]; -}; - static int goodix_check_cfg_8(struct goodix_ts_data *ts, const u8 *cfg, int len); static int goodix_check_cfg_16(struct goodix_ts_data *ts, @@ -260,8 +200,7 @@ static const struct dmi_system_id inverted_x_screen[] = { * @buf: raw write data buffer. * @len: length of the buffer to write */ -static int goodix_i2c_read(struct i2c_client *client, - u16 reg, u8 *buf, int len) +int goodix_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len) { struct i2c_msg msgs[2]; __be16 wbuf = cpu_to_be16(reg); @@ -289,8 +228,7 @@ static int goodix_i2c_read(struct i2c_client *client, * @buf: raw data buffer to write. * @len: length of the buffer to write */ -static int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf, - int len) +int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf, int len) { u8 *addr_buf; struct i2c_msg msg; @@ -314,7 +252,7 @@ static int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf, return ret < 0 ? ret : (ret != 1 ? -EIO : 0); } -static int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value) +int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value) { return goodix_i2c_write(client, reg, &value, sizeof(value)); } @@ -598,7 +536,7 @@ static int goodix_check_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len) * @cfg: config firmware to write to device * @len: config data length */ -static int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len) +int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len) { int error; @@ -696,7 +634,7 @@ static int goodix_irq_direction_input(struct goodix_ts_data *ts) return -EINVAL; /* Never reached */ } -static int goodix_int_sync(struct goodix_ts_data *ts) +int goodix_int_sync(struct goodix_ts_data *ts) { int error; diff --git a/drivers/input/touchscreen/goodix.h b/drivers/input/touchscreen/goodix.h new file mode 100644 index 000000000000..cdaced4f2980 --- /dev/null +++ b/drivers/input/touchscreen/goodix.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __GOODIX_H__ +#define __GOODIX_H__ + +#include +#include +#include +#include +#include +#include + +/* Register defines */ +#define GOODIX_REG_COMMAND 0x8040 +#define GOODIX_CMD_SCREEN_OFF 0x05 + +#define GOODIX_GT1X_REG_CONFIG_DATA 0x8050 +#define GOODIX_GT9X_REG_CONFIG_DATA 0x8047 +#define GOODIX_REG_ID 0x8140 +#define GOODIX_READ_COOR_ADDR 0x814E + +#define GOODIX_ID_MAX_LEN 4 +#define GOODIX_CONFIG_MAX_LENGTH 240 +#define GOODIX_MAX_KEYS 7 + +enum goodix_irq_pin_access_method { + IRQ_PIN_ACCESS_NONE, + IRQ_PIN_ACCESS_GPIO, + IRQ_PIN_ACCESS_ACPI_GPIO, + IRQ_PIN_ACCESS_ACPI_METHOD, +}; + +struct goodix_ts_data; + +struct goodix_chip_data { + u16 config_addr; + int config_len; + int (*check_config)(struct goodix_ts_data *ts, const u8 *cfg, int len); + void (*calc_config_checksum)(struct goodix_ts_data *ts); +}; + +struct goodix_ts_data { + struct i2c_client *client; + struct input_dev *input_dev; + const struct goodix_chip_data *chip; + struct touchscreen_properties prop; + unsigned int max_touch_num; + unsigned int int_trigger_type; + struct regulator *avdd28; + struct regulator *vddio; + struct gpio_desc *gpiod_int; + struct gpio_desc *gpiod_rst; + int gpio_count; + int gpio_int_idx; + char id[GOODIX_ID_MAX_LEN + 1]; + u16 version; + const char *cfg_name; + bool reset_controller_at_probe; + bool load_cfg_from_disk; + struct completion firmware_loading_complete; + unsigned long irq_flags; + enum goodix_irq_pin_access_method irq_pin_access_method; + unsigned int contact_size; + u8 config[GOODIX_CONFIG_MAX_LENGTH]; + unsigned short keymap[GOODIX_MAX_KEYS]; +}; + +int goodix_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len); +int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf, int len); +int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value); +int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len); +int goodix_int_sync(struct goodix_ts_data *ts); + +#endif -- cgit From 209bda4741f68f102cf2f272227bfc938e387b51 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 20 Sep 2021 21:08:26 -0700 Subject: Input: goodix - refactor reset handling Refactor reset handling a bit, change the main reset handler into a new goodix_reset_no_int_sync() helper and add a goodix_reset() wrapper which calls goodix_int_sync() separately. Also push the dev_err() call on reset failure into the goodix_reset_no_int_sync() and goodix_int_sync() functions, so that we don't need to have separate dev_err() calls in all their callers. This is a preparation patch for adding support for controllers without flash, which need to have their firmware uploaded and need some other special handling too. Reviewed-by: Bastien Nocera Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210920150643.155872-4-hdegoede@redhat.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/goodix.c | 48 +++++++++++++++++++++++++------------- drivers/input/touchscreen/goodix.h | 1 + 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index 76e93bc8389a..e5ec64036f06 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -640,56 +640,76 @@ int goodix_int_sync(struct goodix_ts_data *ts) error = goodix_irq_direction_output(ts, 0); if (error) - return error; + goto error; msleep(50); /* T5: 50ms */ error = goodix_irq_direction_input(ts); if (error) - return error; + goto error; return 0; + +error: + dev_err(&ts->client->dev, "Controller irq sync failed.\n"); + return error; } /** - * goodix_reset - Reset device during power on + * goodix_reset_no_int_sync - Reset device, leaving interrupt line in output mode * * @ts: goodix_ts_data pointer */ -static int goodix_reset(struct goodix_ts_data *ts) +int goodix_reset_no_int_sync(struct goodix_ts_data *ts) { int error; /* begin select I2C slave addr */ error = gpiod_direction_output(ts->gpiod_rst, 0); if (error) - return error; + goto error; msleep(20); /* T2: > 10ms */ /* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */ error = goodix_irq_direction_output(ts, ts->client->addr == 0x14); if (error) - return error; + goto error; usleep_range(100, 2000); /* T3: > 100us */ error = gpiod_direction_output(ts->gpiod_rst, 1); if (error) - return error; + goto error; usleep_range(6000, 10000); /* T4: > 5ms */ /* end select I2C slave addr */ error = gpiod_direction_input(ts->gpiod_rst); if (error) - return error; + goto error; - error = goodix_int_sync(ts); + return 0; + +error: + dev_err(&ts->client->dev, "Controller reset failed.\n"); + return error; +} + +/** + * goodix_reset - Reset device during power on + * + * @ts: goodix_ts_data pointer + */ +static int goodix_reset(struct goodix_ts_data *ts) +{ + int error; + + error = goodix_reset_no_int_sync(ts); if (error) return error; - return 0; + return goodix_int_sync(ts); } #ifdef ACPI_GPIO_SUPPORT @@ -1195,10 +1215,8 @@ reset: if (ts->reset_controller_at_probe) { /* reset the controller */ error = goodix_reset(ts); - if (error) { - dev_err(&client->dev, "Controller reset failed.\n"); + if (error) return error; - } } error = goodix_i2c_test(client); @@ -1340,10 +1358,8 @@ static int __maybe_unused goodix_resume(struct device *dev) if (error != 0 || config_ver != ts->config[0]) { error = goodix_reset(ts); - if (error) { - dev_err(dev, "Controller reset failed.\n"); + if (error) return error; - } error = goodix_send_cfg(ts, ts->config, ts->chip->config_len); if (error) diff --git a/drivers/input/touchscreen/goodix.h b/drivers/input/touchscreen/goodix.h index cdaced4f2980..0b88554ba2ae 100644 --- a/drivers/input/touchscreen/goodix.h +++ b/drivers/input/touchscreen/goodix.h @@ -69,5 +69,6 @@ int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf, int len) int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value); int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len); int goodix_int_sync(struct goodix_ts_data *ts); +int goodix_reset_no_int_sync(struct goodix_ts_data *ts); #endif -- cgit From 7642f29c731e383623d368a234a99ff9fb2eb97b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 20 Sep 2021 21:08:35 -0700 Subject: Input: goodix - push error logging up into i2c_read and i2c_write helpers Make the goodix_i2c_read() and goodix_i2c_write*() helpers log errors themselves. This allows removing all the error logging from their callers. This already results in a nice cleanup with the current code and it also helps to make the upcoming support for controllers without flash cleaner. Reviewed-by: Bastien Nocera Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210920150643.155872-5-hdegoede@redhat.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/goodix.c | 53 +++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index e5ec64036f06..f91a92c998a2 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -217,7 +217,13 @@ int goodix_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len) msgs[1].buf = buf; ret = i2c_transfer(client->adapter, msgs, 2); - return ret < 0 ? ret : (ret != ARRAY_SIZE(msgs) ? -EIO : 0); + if (ret >= 0) + ret = (ret == ARRAY_SIZE(msgs) ? 0 : -EIO); + + if (ret) + dev_err(&client->dev, "Error reading %d bytes from 0x%04x: %d\n", + len, reg, ret); + return ret; } /** @@ -248,8 +254,15 @@ int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf, int len) msg.len = len + 2; ret = i2c_transfer(client->adapter, &msg, 1); + if (ret >= 0) + ret = (ret == 1 ? 0 : -EIO); + kfree(addr_buf); - return ret < 0 ? ret : (ret != 1 ? -EIO : 0); + + if (ret) + dev_err(&client->dev, "Error writing %d bytes to 0x%04x: %d\n", + len, reg, ret); + return ret; } int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value) @@ -291,11 +304,8 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data) do { error = goodix_i2c_read(ts->client, addr, data, header_contact_keycode_size); - if (error) { - dev_err(&ts->client->dev, "I2C transfer error: %d\n", - error); + if (error) return error; - } if (data[0] & GOODIX_BUFFER_STATUS_READY) { touch_num = data[0] & 0x0f; @@ -418,9 +428,7 @@ static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id) struct goodix_ts_data *ts = dev_id; goodix_process_events(ts); - - if (goodix_i2c_write_u8(ts->client, GOODIX_READ_COOR_ADDR, 0) < 0) - dev_err(&ts->client->dev, "I2C write end_cmd error\n"); + goodix_i2c_write_u8(ts->client, GOODIX_READ_COOR_ADDR, 0); return IRQ_HANDLED; } @@ -545,11 +553,9 @@ int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len) return error; error = goodix_i2c_write(ts->client, ts->chip->config_addr, cfg, len); - if (error) { - dev_err(&ts->client->dev, "Failed to write config data: %d", - error); + if (error) return error; - } + dev_dbg(&ts->client->dev, "Config sent successfully."); /* Let the firmware reconfigure itself, so sleep for 10ms */ @@ -937,8 +943,6 @@ static void goodix_read_config(struct goodix_ts_data *ts) error = goodix_i2c_read(ts->client, ts->chip->config_addr, ts->config, ts->chip->config_len); if (error) { - dev_warn(&ts->client->dev, "Error reading config: %d\n", - error); ts->int_trigger_type = GOODIX_INT_TRIGGER; ts->max_touch_num = GOODIX_MAX_CONTACTS; return; @@ -969,10 +973,8 @@ static int goodix_read_version(struct goodix_ts_data *ts) char id_str[GOODIX_ID_MAX_LEN + 1]; error = goodix_i2c_read(ts->client, GOODIX_REG_ID, buf, sizeof(buf)); - if (error) { - dev_err(&ts->client->dev, "read version failed: %d\n", error); + if (error) return error; - } memcpy(id_str, buf, GOODIX_ID_MAX_LEN); id_str[GOODIX_ID_MAX_LEN] = 0; @@ -998,13 +1000,10 @@ static int goodix_i2c_test(struct i2c_client *client) u8 test; while (retry++ < 2) { - error = goodix_i2c_read(client, GOODIX_REG_ID, - &test, 1); + error = goodix_i2c_read(client, GOODIX_REG_ID, &test, 1); if (!error) return 0; - dev_err(&client->dev, "i2c test failed attempt %d: %d\n", - retry, error); msleep(20); } @@ -1232,10 +1231,8 @@ reset: } error = goodix_read_version(ts); - if (error) { - dev_err(&client->dev, "Read version failed.\n"); + if (error) return error; - } ts->chip = goodix_get_chip_data(ts->id); @@ -1306,7 +1303,6 @@ static int __maybe_unused goodix_suspend(struct device *dev) error = goodix_i2c_write_u8(ts->client, GOODIX_REG_COMMAND, GOODIX_CMD_SCREEN_OFF); if (error) { - dev_err(&ts->client->dev, "Screen off command failed\n"); goodix_irq_direction_input(ts); goodix_request_irq(ts); return -EAGAIN; @@ -1349,10 +1345,7 @@ static int __maybe_unused goodix_resume(struct device *dev) error = goodix_i2c_read(ts->client, ts->chip->config_addr, &config_ver, 1); - if (error) - dev_warn(dev, "Error reading config version: %d, resetting controller\n", - error); - else if (config_ver != ts->config[0]) + if (!error && config_ver != ts->config[0]) dev_info(dev, "Config version mismatch %d != %d, resetting controller\n", config_ver, ts->config[0]); -- cgit From 20e317222eeabd74e9ff76cf4daf85f961f608dc Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 20 Sep 2021 21:08:44 -0700 Subject: Input: goodix - allow specifying the config filename The config which needs to be send to the controller on some device-models is model-specific. Allow specifying a model-specific filename through a device-property, rather then always using a fixed filename. Note the "goodix,config-name" device-property used by this is *not* documented in the Documentation/devicetree/bindings/input/touchscreen/goodix.yaml device-tree bindings for now. Not documenting these is intentional. This is done because this code has only been tested on x86/ACPI so far, where devicetree is not used. Instead these properties are set through a software-fwnode attached to the device by the drivers/platform/x86/touchscreen_dmi.c code. This means that the use of this property for now is purely a kernel-internal thing and the name/working of the property may still be changed for now. Reviewed-by: Bastien Nocera Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210920150643.155872-6-hdegoede@redhat.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/goodix.c | 14 ++++++++++---- drivers/input/touchscreen/goodix.h | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index f91a92c998a2..75c53786516f 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -1165,6 +1165,7 @@ static int goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct goodix_ts_data *ts; + const char *cfg_name; int error; dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr); @@ -1238,10 +1239,15 @@ reset: if (ts->load_cfg_from_disk) { /* update device config */ - ts->cfg_name = devm_kasprintf(&client->dev, GFP_KERNEL, - "goodix_%s_cfg.bin", ts->id); - if (!ts->cfg_name) - return -ENOMEM; + error = device_property_read_string(&client->dev, + "goodix,config-name", + &cfg_name); + if (!error) + snprintf(ts->cfg_name, sizeof(ts->cfg_name), + "goodix/%s", cfg_name); + else + snprintf(ts->cfg_name, sizeof(ts->cfg_name), + "goodix_%s_cfg.bin", ts->id); error = request_firmware_nowait(THIS_MODULE, true, ts->cfg_name, &client->dev, GFP_KERNEL, ts, diff --git a/drivers/input/touchscreen/goodix.h b/drivers/input/touchscreen/goodix.h index 0b88554ba2ae..b1d1bc004091 100644 --- a/drivers/input/touchscreen/goodix.h +++ b/drivers/input/touchscreen/goodix.h @@ -52,8 +52,8 @@ struct goodix_ts_data { int gpio_count; int gpio_int_idx; char id[GOODIX_ID_MAX_LEN + 1]; + char cfg_name[64]; u16 version; - const char *cfg_name; bool reset_controller_at_probe; bool load_cfg_from_disk; struct completion firmware_loading_complete; -- cgit From 09182ed20c04d1b3a3a0d232d7748e745a438acd Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 20 Sep 2021 21:08:53 -0700 Subject: Input: goodix - add support for controllers without flash Some Goodix touchscreen controllers, such as for example the GT912, don't have flash-storage for their firmware. These models require the OS to load the firmware at runtime, as well as some other special handling. Add support for this to the goodix driver. This patch was developed and tested on a Glavey TM800A550L tablet. Note the "goodix,main-clk" and "firmware-name" device-properties used by the new code are *not* documented in the Documentation/devicetree/bindings/input/touchscreen/goodix.yaml device-tree bindings for now. Not documenting these is intentional. This is done because this code has only been tested on x86/ACPI so far, where devicetree is not used. Instead these properties are set through a software-fwnode attached to the device by the drivers/platform/x86/touchscreen_dmi.c code. This means that the use of this properties for now is purely a kernel-internal thing and the name/working of the properties may still be changed for now. Reviewed-by: Bastien Nocera Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210920150643.155872-7-hdegoede@redhat.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Makefile | 3 +- drivers/input/touchscreen/goodix.c | 42 ++- drivers/input/touchscreen/goodix.h | 43 +++ drivers/input/touchscreen/goodix_fwupload.c | 427 ++++++++++++++++++++++++++++ 4 files changed, 507 insertions(+), 8 deletions(-) create mode 100644 drivers/input/touchscreen/goodix_fwupload.c diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 7d34100f7f22..39a8127cf6a5 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -6,6 +6,7 @@ # Each configuration option enables a list of files. wm97xx-ts-y := wm97xx-core.o +goodix_ts-y := goodix.o goodix_fwupload.o obj-$(CONFIG_TOUCHSCREEN_88PM860X) += 88pm860x-ts.o obj-$(CONFIG_TOUCHSCREEN_AD7877) += ad7877.o @@ -44,7 +45,7 @@ obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL) += egalax_ts_serial.o obj-$(CONFIG_TOUCHSCREEN_EXC3000) += exc3000.o obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o -obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o +obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix_ts.o obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o obj-$(CONFIG_TOUCHSCREEN_ILITEK) += ilitek_ts_i2c.o diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index 75c53786516f..906b5a6b52d1 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -326,6 +326,11 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data) return touch_num; } + if (data[0] == 0 && ts->firmware_name) { + if (goodix_handle_fw_request(ts)) + return 0; + } + usleep_range(1000, 2000); /* Poll every 1 - 2 ms */ } while (time_before(jiffies, max_timeout)); @@ -940,12 +945,19 @@ static void goodix_read_config(struct goodix_ts_data *ts) int x_max, y_max; int error; - error = goodix_i2c_read(ts->client, ts->chip->config_addr, - ts->config, ts->chip->config_len); - if (error) { - ts->int_trigger_type = GOODIX_INT_TRIGGER; - ts->max_touch_num = GOODIX_MAX_CONTACTS; - return; + /* + * On controllers where we need to upload the firmware + * (controllers without flash) ts->config already has the config + * at this point and the controller itself does not have it yet! + */ + if (!ts->firmware_name) { + error = goodix_i2c_read(ts->client, ts->chip->config_addr, + ts->config, ts->chip->config_len); + if (error) { + ts->int_trigger_type = GOODIX_INT_TRIGGER; + ts->max_touch_num = GOODIX_MAX_CONTACTS; + return; + } } ts->int_trigger_type = ts->config[TRIGGER_LOC] & 0x03; @@ -1139,7 +1151,16 @@ static void goodix_config_cb(const struct firmware *cfg, void *ctx) struct goodix_ts_data *ts = ctx; int error; - if (cfg) { + if (ts->firmware_name) { + if (!cfg) + goto err_release_cfg; + + error = goodix_check_cfg(ts, cfg->data, cfg->size); + if (error) + goto err_release_cfg; + + memcpy(ts->config, cfg->data, cfg->size); + } else if (cfg) { /* send device configuration to the firmware */ error = goodix_send_cfg(ts, cfg->data, cfg->size); if (error) @@ -1231,6 +1252,10 @@ reset: return error; } + error = goodix_firmware_check(ts); + if (error) + return error; + error = goodix_read_version(ts); if (error) return error; @@ -1297,6 +1322,9 @@ static int __maybe_unused goodix_suspend(struct device *dev) /* Free IRQ as IRQ pin is used as output in the suspend sequence */ goodix_free_irq(ts); + /* Save reference (calibration) info if necessary */ + goodix_save_bak_ref(ts); + /* Output LOW on the INT pin for 5 ms */ error = goodix_irq_direction_output(ts, 0); if (error) { diff --git a/drivers/input/touchscreen/goodix.h b/drivers/input/touchscreen/goodix.h index b1d1bc004091..62138f930d1a 100644 --- a/drivers/input/touchscreen/goodix.h +++ b/drivers/input/touchscreen/goodix.h @@ -10,13 +10,48 @@ #include /* Register defines */ +#define GOODIX_REG_MISCTL_DSP_CTL 0x4010 +#define GOODIX_REG_MISCTL_SRAM_BANK 0x4048 +#define GOODIX_REG_MISCTL_MEM_CD_EN 0x4049 +#define GOODIX_REG_MISCTL_CACHE_EN 0x404B +#define GOODIX_REG_MISCTL_TMR0_EN 0x40B0 +#define GOODIX_REG_MISCTL_SWRST 0x4180 +#define GOODIX_REG_MISCTL_CPU_SWRST_PULSE 0x4184 +#define GOODIX_REG_MISCTL_BOOTCTL 0x4190 +#define GOODIX_REG_MISCTL_BOOT_OPT 0x4218 +#define GOODIX_REG_MISCTL_BOOT_CTL 0x5094 + +#define GOODIX_REG_FW_SIG 0x8000 +#define GOODIX_FW_SIG_LEN 10 + +#define GOODIX_REG_MAIN_CLK 0x8020 +#define GOODIX_MAIN_CLK_LEN 6 + #define GOODIX_REG_COMMAND 0x8040 #define GOODIX_CMD_SCREEN_OFF 0x05 +#define GOODIX_REG_SW_WDT 0x8041 + +#define GOODIX_REG_REQUEST 0x8043 +#define GOODIX_RQST_RESPONDED 0x00 +#define GOODIX_RQST_CONFIG 0x01 +#define GOODIX_RQST_BAK_REF 0x02 +#define GOODIX_RQST_RESET 0x03 +#define GOODIX_RQST_MAIN_CLOCK 0x04 +/* + * Unknown request which gets send by the controller aprox. + * every 34 seconds once it is up and running. + */ +#define GOODIX_RQST_UNKNOWN 0x06 +#define GOODIX_RQST_IDLE 0xFF + +#define GOODIX_REG_STATUS 0x8044 + #define GOODIX_GT1X_REG_CONFIG_DATA 0x8050 #define GOODIX_GT9X_REG_CONFIG_DATA 0x8047 #define GOODIX_REG_ID 0x8140 #define GOODIX_READ_COOR_ADDR 0x814E +#define GOODIX_REG_BAK_REF 0x99D0 #define GOODIX_ID_MAX_LEN 4 #define GOODIX_CONFIG_MAX_LENGTH 240 @@ -42,6 +77,7 @@ struct goodix_ts_data { struct i2c_client *client; struct input_dev *input_dev; const struct goodix_chip_data *chip; + const char *firmware_name; struct touchscreen_properties prop; unsigned int max_touch_num; unsigned int int_trigger_type; @@ -62,6 +98,9 @@ struct goodix_ts_data { unsigned int contact_size; u8 config[GOODIX_CONFIG_MAX_LENGTH]; unsigned short keymap[GOODIX_MAX_KEYS]; + u8 main_clk[GOODIX_MAIN_CLK_LEN]; + int bak_ref_len; + u8 *bak_ref; }; int goodix_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len); @@ -71,4 +110,8 @@ int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len); int goodix_int_sync(struct goodix_ts_data *ts); int goodix_reset_no_int_sync(struct goodix_ts_data *ts); +int goodix_firmware_check(struct goodix_ts_data *ts); +bool goodix_handle_fw_request(struct goodix_ts_data *ts); +void goodix_save_bak_ref(struct goodix_ts_data *ts); + #endif diff --git a/drivers/input/touchscreen/goodix_fwupload.c b/drivers/input/touchscreen/goodix_fwupload.c new file mode 100644 index 000000000000..c1e7a2413078 --- /dev/null +++ b/drivers/input/touchscreen/goodix_fwupload.c @@ -0,0 +1,427 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Goodix Touchscreen firmware upload support + * + * Copyright (c) 2021 Hans de Goede + * + * This is a rewrite of gt9xx_update.c from the Allwinner H3 BSP which is: + * Copyright (c) 2010 - 2012 Goodix Technology. + * Author: andrew@goodix.com + */ + +#include +#include +#include +#include "goodix.h" + +#define GOODIX_FW_HEADER_LENGTH sizeof(struct goodix_fw_header) +#define GOODIX_FW_SECTION_LENGTH 0x2000 +#define GOODIX_FW_DSP_LENGTH 0x1000 +#define GOODIX_FW_UPLOAD_ADDRESS 0xc000 + +#define GOODIX_CFG_LOC_HAVE_KEY 7 +#define GOODIX_CFG_LOC_DRVA_NUM 27 +#define GOODIX_CFG_LOC_DRVB_NUM 28 +#define GOODIX_CFG_LOC_SENS_NUM 29 + +struct goodix_fw_header { + u8 hw_info[4]; + u8 pid[8]; + u8 vid[2]; +} __packed; + +static u16 goodix_firmware_checksum(const u8 *data, int size) +{ + u16 checksum = 0; + int i; + + for (i = 0; i < size; i += 2) + checksum += (data[i] << 8) + data[i + 1]; + + return checksum; +} + +static int goodix_firmware_verify(struct device *dev, const struct firmware *fw) +{ + const struct goodix_fw_header *fw_header; + size_t expected_size; + const u8 *data; + u16 checksum; + char buf[9]; + + expected_size = GOODIX_FW_HEADER_LENGTH + 4 * GOODIX_FW_SECTION_LENGTH + + GOODIX_FW_DSP_LENGTH; + if (fw->size != expected_size) { + dev_err(dev, "Firmware has wrong size, expected %zu got %zu\n", + expected_size, fw->size); + return -EINVAL; + } + + data = fw->data + GOODIX_FW_HEADER_LENGTH; + checksum = goodix_firmware_checksum(data, 4 * GOODIX_FW_SECTION_LENGTH); + if (checksum) { + dev_err(dev, "Main firmware checksum error\n"); + return -EINVAL; + } + + data += 4 * GOODIX_FW_SECTION_LENGTH; + checksum = goodix_firmware_checksum(data, GOODIX_FW_DSP_LENGTH); + if (checksum) { + dev_err(dev, "DSP firmware checksum error\n"); + return -EINVAL; + } + + fw_header = (const struct goodix_fw_header *)fw->data; + dev_info(dev, "Firmware hardware info %02x%02x%02x%02x\n", + fw_header->hw_info[0], fw_header->hw_info[1], + fw_header->hw_info[2], fw_header->hw_info[3]); + /* pid is a 8 byte buffer containing a string, weird I know */ + memcpy(buf, fw_header->pid, 8); + buf[8] = 0; + dev_info(dev, "Firmware PID: %s VID: %02x%02x\n", buf, + fw_header->vid[0], fw_header->vid[1]); + return 0; +} + +static int goodix_enter_upload_mode(struct i2c_client *client) +{ + int tries, error; + u8 val; + + tries = 200; + do { + error = goodix_i2c_write_u8(client, + GOODIX_REG_MISCTL_SWRST, 0x0c); + if (error) + return error; + + error = goodix_i2c_read(client, + GOODIX_REG_MISCTL_SWRST, &val, 1); + if (error) + return error; + + if (val == 0x0c) + break; + } while (--tries); + + if (!tries) { + dev_err(&client->dev, "Error could not hold ss51 & dsp\n"); + return -EIO; + } + + /* DSP_CK and DSP_ALU_CK PowerOn */ + error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_DSP_CTL, 0x00); + if (error) + return error; + + /* Disable watchdog */ + error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_TMR0_EN, 0x00); + if (error) + return error; + + /* Clear cache enable */ + error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_CACHE_EN, 0x00); + if (error) + return error; + + /* Set boot from SRAM */ + error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_BOOTCTL, 0x02); + if (error) + return error; + + /* Software reboot */ + error = goodix_i2c_write_u8(client, + GOODIX_REG_MISCTL_CPU_SWRST_PULSE, 0x01); + if (error) + return error; + + /* Clear control flag */ + error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_BOOTCTL, 0x00); + if (error) + return error; + + /* Set scramble */ + error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_BOOT_OPT, 0x00); + if (error) + return error; + + /* Enable accessing code */ + error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_MEM_CD_EN, 0x01); + if (error) + return error; + + return 0; +} + +static int goodix_start_firmware(struct i2c_client *client) +{ + int error; + u8 val; + + /* Init software watchdog */ + error = goodix_i2c_write_u8(client, GOODIX_REG_SW_WDT, 0xaa); + if (error) + return error; + + /* Release SS51 & DSP */ + error = goodix_i2c_write_u8(client, GOODIX_REG_MISCTL_SWRST, 0x00); + if (error) + return error; + + error = goodix_i2c_read(client, GOODIX_REG_SW_WDT, &val, 1); + if (error) + return error; + + /* The value we've written to SW_WDT should have been cleared now */ + if (val == 0xaa) { + dev_err(&client->dev, "Error SW_WDT reg not cleared on fw startup\n"); + return -EIO; + } + + /* Re-init software watchdog */ + error = goodix_i2c_write_u8(client, GOODIX_REG_SW_WDT, 0xaa); + if (error) + return error; + + return 0; +} + +static int goodix_firmware_upload(struct goodix_ts_data *ts) +{ + const struct firmware *fw; + char fw_name[64]; + const u8 *data; + int error; + + snprintf(fw_name, sizeof(fw_name), "goodix/%s", ts->firmware_name); + + error = request_firmware(&fw, fw_name, &ts->client->dev); + if (error) { + dev_err(&ts->client->dev, "Firmware request error %d\n", error); + return error; + } + + error = goodix_firmware_verify(&ts->client->dev, fw); + if (error) + goto release; + + error = goodix_reset_no_int_sync(ts); + if (error) + return error; + + error = goodix_enter_upload_mode(ts->client); + if (error) + goto release; + + /* Select SRAM bank 0 and upload section 1 & 2 */ + error = goodix_i2c_write_u8(ts->client, + GOODIX_REG_MISCTL_SRAM_BANK, 0x00); + if (error) + goto release; + + data = fw->data + GOODIX_FW_HEADER_LENGTH; + error = goodix_i2c_write(ts->client, GOODIX_FW_UPLOAD_ADDRESS, + data, 2 * GOODIX_FW_SECTION_LENGTH); + if (error) + goto release; + + /* Select SRAM bank 1 and upload section 3 & 4 */ + error = goodix_i2c_write_u8(ts->client, + GOODIX_REG_MISCTL_SRAM_BANK, 0x01); + if (error) + goto release; + + data += 2 * GOODIX_FW_SECTION_LENGTH; + error = goodix_i2c_write(ts->client, GOODIX_FW_UPLOAD_ADDRESS, + data, 2 * GOODIX_FW_SECTION_LENGTH); + if (error) + goto release; + + /* Select SRAM bank 2 and upload the DSP firmware */ + error = goodix_i2c_write_u8(ts->client, + GOODIX_REG_MISCTL_SRAM_BANK, 0x02); + if (error) + goto release; + + data += 2 * GOODIX_FW_SECTION_LENGTH; + error = goodix_i2c_write(ts->client, GOODIX_FW_UPLOAD_ADDRESS, + data, GOODIX_FW_DSP_LENGTH); + if (error) + goto release; + + error = goodix_start_firmware(ts->client); + if (error) + goto release; + + error = goodix_int_sync(ts); +release: + release_firmware(fw); + return error; +} + +static int goodix_prepare_bak_ref(struct goodix_ts_data *ts) +{ + u8 have_key, driver_num, sensor_num; + + if (ts->bak_ref) + return 0; /* Already done */ + + have_key = (ts->config[GOODIX_CFG_LOC_HAVE_KEY] & 0x01); + + driver_num = (ts->config[GOODIX_CFG_LOC_DRVA_NUM] & 0x1f) + + (ts->config[GOODIX_CFG_LOC_DRVB_NUM] & 0x1f); + if (have_key) + driver_num--; + + sensor_num = (ts->config[GOODIX_CFG_LOC_SENS_NUM] & 0x0f) + + ((ts->config[GOODIX_CFG_LOC_SENS_NUM] >> 4) & 0x0f); + + dev_dbg(&ts->client->dev, "Drv %d Sen %d Key %d\n", + driver_num, sensor_num, have_key); + + ts->bak_ref_len = (driver_num * (sensor_num - 2) + 2) * 2; + + ts->bak_ref = devm_kzalloc(&ts->client->dev, + ts->bak_ref_len, GFP_KERNEL); + if (!ts->bak_ref) + return -ENOMEM; + + /* + * The bak_ref array contains the backup of an array of (self/auto) + * calibration related values which the Android version of the driver + * stores on the filesystem so that it can be restored after reboot. + * The mainline kernel never writes directly to the filesystem like + * this, we always start will all the values which give a correction + * factor in approx. the -20 - +20 range (in 2s complement) set to 0. + * + * Note the touchscreen works fine without restoring the reference + * values after a reboot / power-cycle. + * + * The last 2 bytes are a 16 bits unsigned checksum which is expected + * to make the addition al all 16 bit unsigned values in the array add + * up to 1 (rather then the usual 0), so we must set the last byte to 1. + */ + ts->bak_ref[ts->bak_ref_len - 1] = 1; + + return 0; +} + +static int goodix_send_main_clock(struct goodix_ts_data *ts) +{ + u32 main_clk = 54; /* Default main clock */ + u8 checksum = 0; + int i; + + device_property_read_u32(&ts->client->dev, + "goodix,main-clk", &main_clk); + + for (i = 0; i < (GOODIX_MAIN_CLK_LEN - 1); i++) { + ts->main_clk[i] = main_clk; + checksum += main_clk; + } + + /* The value of all bytes combines must be 0 */ + ts->main_clk[GOODIX_MAIN_CLK_LEN - 1] = 256 - checksum; + + return goodix_i2c_write(ts->client, GOODIX_REG_MAIN_CLK, + ts->main_clk, GOODIX_MAIN_CLK_LEN); +} + +int goodix_firmware_check(struct goodix_ts_data *ts) +{ + device_property_read_string(&ts->client->dev, + "firmware-name", &ts->firmware_name); + if (!ts->firmware_name) + return 0; + + if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) { + dev_err(&ts->client->dev, "Error no IRQ-pin access method, cannot upload fw.\n"); + return -EINVAL; + } + + dev_info(&ts->client->dev, "Touchscreen controller needs fw-upload\n"); + ts->load_cfg_from_disk = true; + + return goodix_firmware_upload(ts); +} + +bool goodix_handle_fw_request(struct goodix_ts_data *ts) +{ + int error; + u8 val; + + error = goodix_i2c_read(ts->client, GOODIX_REG_REQUEST, &val, 1); + if (error) + return false; + + switch (val) { + case GOODIX_RQST_RESPONDED: + /* + * If we read back our own last ack the IRQ was not for + * a request. + */ + return false; + case GOODIX_RQST_CONFIG: + error = goodix_send_cfg(ts, ts->config, ts->chip->config_len); + if (error) + return false; + + break; + case GOODIX_RQST_BAK_REF: + error = goodix_prepare_bak_ref(ts); + if (error) + return false; + + error = goodix_i2c_write(ts->client, GOODIX_REG_BAK_REF, + ts->bak_ref, ts->bak_ref_len); + if (error) + return false; + + break; + case GOODIX_RQST_RESET: + error = goodix_firmware_upload(ts); + if (error) + return false; + + break; + case GOODIX_RQST_MAIN_CLOCK: + error = goodix_send_main_clock(ts); + if (error) + return false; + + break; + case GOODIX_RQST_UNKNOWN: + case GOODIX_RQST_IDLE: + break; + default: + dev_err_ratelimited(&ts->client->dev, "Unknown Request: 0x%02x\n", val); + } + + /* Ack the request */ + goodix_i2c_write_u8(ts->client, + GOODIX_REG_REQUEST, GOODIX_RQST_RESPONDED); + return true; +} + +void goodix_save_bak_ref(struct goodix_ts_data *ts) +{ + int error; + u8 val; + + if (!ts->firmware_name) + return; + + error = goodix_i2c_read(ts->client, GOODIX_REG_STATUS, &val, 1); + if (error) + return; + + if (!(val & 0x80)) + return; + + error = goodix_i2c_read(ts->client, GOODIX_REG_BAK_REF, + ts->bak_ref, ts->bak_ref_len); + if (error) { + memset(ts->bak_ref, 0, ts->bak_ref_len); + ts->bak_ref[ts->bak_ref_len - 1] = 1; + } +} -- cgit From 5135b2139212f55c07c47e9af5e22f5874514011 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Mon, 20 Sep 2021 13:54:02 -0700 Subject: MAINTAINERS: Add Prashant's maintainership of cros_ec drivers Prashant maintains the cros_usbpd_notify driver as well as the cros_ec_type_c driver. Link: https://lore.kernel.org/r/20210920205402.3818320-1-bleung@chromium.org Signed-off-by: Benson Leung Acked-by: Enric Balletbo i Serra --- MAINTAINERS | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index eeb4c70b3d5b..16573a2d2fe3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4429,6 +4429,17 @@ F: drivers/power/supply/cros_usbpd-charger.c N: cros_ec N: cros-ec +CHROMEOS EC USB TYPE-C DRIVER +M: Prashant Malani +S: Maintained +F: drivers/platform/chrome/cros_ec_typec.c + +CHROMEOS EC USB PD NOTIFY DRIVER +M: Prashant Malani +S: Maintained +F: drivers/platform/chrome/cros_usbpd_notify.c +F: include/linux/platform_data/cros_usbpd_notify.h + CHRONTEL CH7322 CEC DRIVER M: Jeff Chase L: linux-media@vger.kernel.org -- cgit From b28e5e439109fe6fd9fa047654ae99d0b7bc5ccc Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 16 Jun 2021 22:55:54 -0700 Subject: perf daemon: Avoid msan warnings on send_cmd As a full union is always sent, ensure all bytes of the union are initialized with memset to avoid msan warnings of use of uninitialized memory. An example warning from the daemon test: Uninitialized bytes in __interceptor_write at offset 71 inside [0x7ffd98da6280, 72) ==11602==WARNING: MemorySanitizer: use-of-uninitialized-value #0 0x5597edccdbe4 in ion tools/lib/perf/lib.c:18:6 #1 0x5597edccdbe4 in writen tools/lib/perf/lib.c:47:9 #2 0x5597ed221d30 in send_cmd tools/perf/builtin-daemon.c:1376:22 #3 0x5597ed21b48c in cmd_daemon tools/perf/builtin-daemon.c #4 0x5597ed1d6b67 in run_builtin tools/perf/perf.c:313:11 #5 0x5597ed1d6036 in handle_internal_command tools/perf/perf.c:365:8 #6 0x5597ed1d6036 in run_argv tools/perf/perf.c:409:2 #7 0x5597ed1d6036 in main tools/perf/perf.c:539:3 SUMMARY: MemorySanitizer: use-of-uninitialized-value tools/lib/perf/lib.c:18:6 in ion Exiting Signed-off-by: Ian Rogers Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/20210617055554.1917997-1-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-daemon.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tools/perf/builtin-daemon.c b/tools/perf/builtin-daemon.c index 61929f63a047..c13201fb09c3 100644 --- a/tools/perf/builtin-daemon.c +++ b/tools/perf/builtin-daemon.c @@ -1403,8 +1403,10 @@ out: static int send_cmd_list(struct daemon *daemon) { - union cmd cmd = { .cmd = CMD_LIST, }; + union cmd cmd; + memset(&cmd, 0, sizeof(cmd)); + cmd.list.cmd = CMD_LIST; cmd.list.verbose = verbose; cmd.list.csv_sep = daemon->csv_sep ? *daemon->csv_sep : 0; @@ -1432,6 +1434,7 @@ static int __cmd_signal(struct daemon *daemon, struct option parent_options[], return -1; } + memset(&cmd, 0, sizeof(cmd)); cmd.signal.cmd = CMD_SIGNAL, cmd.signal.sig = SIGUSR2; strncpy(cmd.signal.name, name, sizeof(cmd.signal.name) - 1); @@ -1446,7 +1449,7 @@ static int __cmd_stop(struct daemon *daemon, struct option parent_options[], OPT_PARENT(parent_options), OPT_END() }; - union cmd cmd = { .cmd = CMD_STOP, }; + union cmd cmd; argc = parse_options(argc, argv, start_options, daemon_usage, 0); if (argc) @@ -1457,6 +1460,8 @@ static int __cmd_stop(struct daemon *daemon, struct option parent_options[], return -1; } + memset(&cmd, 0, sizeof(cmd)); + cmd.cmd = CMD_STOP; return send_cmd(daemon, &cmd); } @@ -1470,7 +1475,7 @@ static int __cmd_ping(struct daemon *daemon, struct option parent_options[], OPT_PARENT(parent_options), OPT_END() }; - union cmd cmd = { .cmd = CMD_PING, }; + union cmd cmd; argc = parse_options(argc, argv, ping_options, daemon_usage, 0); if (argc) @@ -1481,6 +1486,8 @@ static int __cmd_ping(struct daemon *daemon, struct option parent_options[], return -1; } + memset(&cmd, 0, sizeof(cmd)); + cmd.cmd = CMD_PING; scnprintf(cmd.ping.name, sizeof(cmd.ping.name), "%s", name); return send_cmd(daemon, &cmd); } -- cgit From 06dc660e6eb8817c4c379d2ca290ae0b3f77c69f Mon Sep 17 00:00:00 2001 From: Oliver O'Halloran Date: Tue, 14 Sep 2021 01:27:08 +1000 Subject: PCI: Rename pcibios_add_device() to pcibios_device_add() The general convention for pcibios_* hooks is that they're named after the corresponding pci_* function they provide a hook for. The exception is pcibios_add_device() which provides a hook for pci_device_add(). Rename pcibios_add_device() to pcibios_device_add() so it matches pci_device_add(). Also, remove the export of the microblaze version. The only caller must be compiled as a built-in so there's no reason for the export. Link: https://lore.kernel.org/r/20210913152709.48013-1-oohall@gmail.com Signed-off-by: Oliver O'Halloran Signed-off-by: Bjorn Helgaas Acked-by: Niklas Schnelle # s390 --- arch/microblaze/pci/pci-common.c | 3 +-- arch/powerpc/kernel/pci-common.c | 2 +- arch/powerpc/platforms/powernv/pci-sriov.c | 2 +- arch/s390/pci/pci.c | 2 +- arch/sparc/kernel/pci.c | 2 +- arch/x86/pci/common.c | 2 +- drivers/pci/pci.c | 4 ++-- drivers/pci/probe.c | 4 ++-- include/linux/pci.h | 2 +- 9 files changed, 11 insertions(+), 12 deletions(-) diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c index 557585f1be41..622a4867f9e9 100644 --- a/arch/microblaze/pci/pci-common.c +++ b/arch/microblaze/pci/pci-common.c @@ -587,13 +587,12 @@ static void pcibios_fixup_resources(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources); -int pcibios_add_device(struct pci_dev *dev) +int pcibios_device_add(struct pci_dev *dev) { dev->irq = of_irq_parse_and_map_pci(dev, 0, 0); return 0; } -EXPORT_SYMBOL(pcibios_add_device); /* * Reparent resource children of pr that conflict with res diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index c3573430919d..6749905932f4 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -1059,7 +1059,7 @@ void pcibios_bus_add_device(struct pci_dev *dev) ppc_md.pcibios_bus_add_device(dev); } -int pcibios_add_device(struct pci_dev *dev) +int pcibios_device_add(struct pci_dev *dev) { struct irq_domain *d; diff --git a/arch/powerpc/platforms/powernv/pci-sriov.c b/arch/powerpc/platforms/powernv/pci-sriov.c index 28aac933a439..486c2937b159 100644 --- a/arch/powerpc/platforms/powernv/pci-sriov.c +++ b/arch/powerpc/platforms/powernv/pci-sriov.c @@ -54,7 +54,7 @@ * to "new_size", calculated above. Implementing this is a convoluted process * which requires several hooks in the PCI core: * - * 1. In pcibios_add_device() we call pnv_pci_ioda_fixup_iov(). + * 1. In pcibios_device_add() we call pnv_pci_ioda_fixup_iov(). * * At this point the device has been probed and the device's BARs are sized, * but no resource allocations have been done. The SR-IOV BARs are sized diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index e7e6788d75a8..ded3321b7208 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -561,7 +561,7 @@ static void zpci_cleanup_bus_resources(struct zpci_dev *zdev) zdev->has_resources = 0; } -int pcibios_add_device(struct pci_dev *pdev) +int pcibios_device_add(struct pci_dev *pdev) { struct zpci_dev *zdev = to_zpci(pdev); struct resource *res; diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c index 9c2b720bfd20..31b0c1983286 100644 --- a/arch/sparc/kernel/pci.c +++ b/arch/sparc/kernel/pci.c @@ -1010,7 +1010,7 @@ void pcibios_set_master(struct pci_dev *dev) } #ifdef CONFIG_PCI_IOV -int pcibios_add_device(struct pci_dev *dev) +int pcibios_device_add(struct pci_dev *dev) { struct pci_dev *pdev; diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 3507f456fcd0..9e1e6b8d8876 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c @@ -632,7 +632,7 @@ static void set_dev_domain_options(struct pci_dev *pdev) pdev->hotplug_user_indicators = 1; } -int pcibios_add_device(struct pci_dev *dev) +int pcibios_device_add(struct pci_dev *dev) { struct pci_setup_rom *rom; struct irq_domain *msidom; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index ce2ab62b64cf..c63598c1cdd8 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2091,14 +2091,14 @@ void pcim_pin_device(struct pci_dev *pdev) EXPORT_SYMBOL(pcim_pin_device); /* - * pcibios_add_device - provide arch specific hooks when adding device dev + * pcibios_device_add - provide arch specific hooks when adding device dev * @dev: the PCI device being added * * Permits the platform to provide architecture specific functionality when * devices are added. This is the default implementation. Architecture * implementations can override this. */ -int __weak pcibios_add_device(struct pci_dev *dev) +int __weak pcibios_device_add(struct pci_dev *dev) { return 0; } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index d9fc02a71baa..2ba43b6adf31 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2450,7 +2450,7 @@ static struct irq_domain *pci_dev_msi_domain(struct pci_dev *dev) struct irq_domain *d; /* - * If a domain has been set through the pcibios_add_device() + * If a domain has been set through the pcibios_device_add() * callback, then this is the one (platform code knows best). */ d = dev_get_msi_domain(&dev->dev); @@ -2518,7 +2518,7 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) list_add_tail(&dev->bus_list, &bus->devices); up_write(&pci_bus_sem); - ret = pcibios_add_device(dev); + ret = pcibios_device_add(dev); WARN_ON(ret < 0); /* Set up MSI IRQ domain */ diff --git a/include/linux/pci.h b/include/linux/pci.h index cd8aa6fce204..7e0ce3a4d5a1 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -2126,7 +2126,7 @@ void pcibios_disable_device(struct pci_dev *dev); void pcibios_set_master(struct pci_dev *dev); int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state); -int pcibios_add_device(struct pci_dev *dev); +int pcibios_device_add(struct pci_dev *dev); void pcibios_release_device(struct pci_dev *dev); #ifdef CONFIG_PCI void pcibios_penalize_isa_irq(int irq, int active); -- cgit From d1c6e08e7503649e4a4f3f9e700e2c05300b6379 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 8 Sep 2021 22:11:37 -0700 Subject: libnvdimm/labels: Add uuid helpers In preparation for CXL labels that move the uuid to a different offset in the label, add nsl_{ref,get,validate}_uuid(). These helpers use the proper uuid_t type. That type definition predated the libnvdimm subsystem, so now is as a good a time as any to convert all the uuid handling in the subsystem to uuid_t to match the helpers. Note that the uuid fields in the label data and superblocks is not replaced per Andy's expectation that uuid_t is a kernel internal type not to appear in external ABI interfaces. So, in those case {import,export}_uuid() is used to go between the 2 types. Also note that this rework uncovered some unnecessary copies for label comparisons, those are cleaned up with nsl_uuid_equal(). As for the whitespace changes, all new code is clang-format compliant. Reported-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/163116429748.2460985.15659993454313919977.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/nvdimm/btt.c | 11 ++--- drivers/nvdimm/btt_devs.c | 14 ++++--- drivers/nvdimm/core.c | 40 ++---------------- drivers/nvdimm/label.c | 34 +++++++--------- drivers/nvdimm/namespace_devs.c | 90 +++++++++++++++++++++++------------------ drivers/nvdimm/nd-core.h | 5 ++- drivers/nvdimm/nd.h | 40 ++++++++++++++++-- drivers/nvdimm/pfn_devs.c | 2 +- include/linux/nd.h | 4 +- 9 files changed, 124 insertions(+), 116 deletions(-) diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c index 92dec4952297..52de60b7adee 100644 --- a/drivers/nvdimm/btt.c +++ b/drivers/nvdimm/btt.c @@ -973,7 +973,7 @@ static int btt_arena_write_layout(struct arena_info *arena) u64 sum; struct btt_sb *super; struct nd_btt *nd_btt = arena->nd_btt; - const u8 *parent_uuid = nd_dev_to_uuid(&nd_btt->ndns->dev); + const uuid_t *parent_uuid = nd_dev_to_uuid(&nd_btt->ndns->dev); ret = btt_map_init(arena); if (ret) @@ -988,8 +988,8 @@ static int btt_arena_write_layout(struct arena_info *arena) return -ENOMEM; strncpy(super->signature, BTT_SIG, BTT_SIG_LEN); - memcpy(super->uuid, nd_btt->uuid, 16); - memcpy(super->parent_uuid, parent_uuid, 16); + export_uuid(super->uuid, nd_btt->uuid); + export_uuid(super->parent_uuid, parent_uuid); super->flags = cpu_to_le32(arena->flags); super->version_major = cpu_to_le16(arena->version_major); super->version_minor = cpu_to_le16(arena->version_minor); @@ -1575,7 +1575,8 @@ static void btt_blk_cleanup(struct btt *btt) * Pointer to a new struct btt on success, NULL on failure. */ static struct btt *btt_init(struct nd_btt *nd_btt, unsigned long long rawsize, - u32 lbasize, u8 *uuid, struct nd_region *nd_region) + u32 lbasize, uuid_t *uuid, + struct nd_region *nd_region) { int ret; struct btt *btt; @@ -1694,7 +1695,7 @@ int nvdimm_namespace_attach_btt(struct nd_namespace_common *ndns) } nd_region = to_nd_region(nd_btt->dev.parent); btt = btt_init(nd_btt, rawsize, nd_btt->lbasize, nd_btt->uuid, - nd_region); + nd_region); if (!btt) return -ENOMEM; nd_btt->btt = btt; diff --git a/drivers/nvdimm/btt_devs.c b/drivers/nvdimm/btt_devs.c index 05feb97e11ce..8b52e5144f08 100644 --- a/drivers/nvdimm/btt_devs.c +++ b/drivers/nvdimm/btt_devs.c @@ -180,8 +180,8 @@ bool is_nd_btt(struct device *dev) EXPORT_SYMBOL(is_nd_btt); static struct device *__nd_btt_create(struct nd_region *nd_region, - unsigned long lbasize, u8 *uuid, - struct nd_namespace_common *ndns) + unsigned long lbasize, uuid_t *uuid, + struct nd_namespace_common *ndns) { struct nd_btt *nd_btt; struct device *dev; @@ -244,14 +244,16 @@ struct device *nd_btt_create(struct nd_region *nd_region) */ bool nd_btt_arena_is_valid(struct nd_btt *nd_btt, struct btt_sb *super) { - const u8 *parent_uuid = nd_dev_to_uuid(&nd_btt->ndns->dev); + const uuid_t *ns_uuid = nd_dev_to_uuid(&nd_btt->ndns->dev); + uuid_t parent_uuid; u64 checksum; if (memcmp(super->signature, BTT_SIG, BTT_SIG_LEN) != 0) return false; - if (!guid_is_null((guid_t *)&super->parent_uuid)) - if (memcmp(super->parent_uuid, parent_uuid, 16) != 0) + import_uuid(&parent_uuid, super->parent_uuid); + if (!uuid_is_null(&parent_uuid)) + if (!uuid_equal(&parent_uuid, ns_uuid)) return false; checksum = le64_to_cpu(super->checksum); @@ -319,7 +321,7 @@ static int __nd_btt_probe(struct nd_btt *nd_btt, return rc; nd_btt->lbasize = le32_to_cpu(btt_sb->external_lbasize); - nd_btt->uuid = kmemdup(btt_sb->uuid, 16, GFP_KERNEL); + nd_btt->uuid = kmemdup(&btt_sb->uuid, sizeof(uuid_t), GFP_KERNEL); if (!nd_btt->uuid) return -ENOMEM; diff --git a/drivers/nvdimm/core.c b/drivers/nvdimm/core.c index 7de592d7eff4..690152d62bf0 100644 --- a/drivers/nvdimm/core.c +++ b/drivers/nvdimm/core.c @@ -206,38 +206,6 @@ struct device *to_nvdimm_bus_dev(struct nvdimm_bus *nvdimm_bus) } EXPORT_SYMBOL_GPL(to_nvdimm_bus_dev); -static bool is_uuid_sep(char sep) -{ - if (sep == '\n' || sep == '-' || sep == ':' || sep == '\0') - return true; - return false; -} - -static int nd_uuid_parse(struct device *dev, u8 *uuid_out, const char *buf, - size_t len) -{ - const char *str = buf; - u8 uuid[16]; - int i; - - for (i = 0; i < 16; i++) { - if (!isxdigit(str[0]) || !isxdigit(str[1])) { - dev_dbg(dev, "pos: %d buf[%zd]: %c buf[%zd]: %c\n", - i, str - buf, str[0], - str + 1 - buf, str[1]); - return -EINVAL; - } - - uuid[i] = (hex_to_bin(str[0]) << 4) | hex_to_bin(str[1]); - str += 2; - if (is_uuid_sep(*str)) - str++; - } - - memcpy(uuid_out, uuid, sizeof(uuid)); - return 0; -} - /** * nd_uuid_store: common implementation for writing 'uuid' sysfs attributes * @dev: container device for the uuid property @@ -248,21 +216,21 @@ static int nd_uuid_parse(struct device *dev, u8 *uuid_out, const char *buf, * (driver detached) * LOCKING: expects nd_device_lock() is held on entry */ -int nd_uuid_store(struct device *dev, u8 **uuid_out, const char *buf, +int nd_uuid_store(struct device *dev, uuid_t **uuid_out, const char *buf, size_t len) { - u8 uuid[16]; + uuid_t uuid; int rc; if (dev->driver) return -EBUSY; - rc = nd_uuid_parse(dev, uuid, buf, len); + rc = uuid_parse(buf, &uuid); if (rc) return rc; kfree(*uuid_out); - *uuid_out = kmemdup(uuid, sizeof(uuid), GFP_KERNEL); + *uuid_out = kmemdup(&uuid, sizeof(uuid), GFP_KERNEL); if (!(*uuid_out)) return -ENOMEM; diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c index 7f473f9db300..e7fdb718ebf0 100644 --- a/drivers/nvdimm/label.c +++ b/drivers/nvdimm/label.c @@ -321,7 +321,8 @@ static bool preamble_index(struct nvdimm_drvdata *ndd, int idx, return true; } -char *nd_label_gen_id(struct nd_label_id *label_id, u8 *uuid, u32 flags) +char *nd_label_gen_id(struct nd_label_id *label_id, const uuid_t *uuid, + u32 flags) { if (!label_id || !uuid) return NULL; @@ -400,9 +401,9 @@ int nd_label_reserve_dpa(struct nvdimm_drvdata *ndd) struct nvdimm *nvdimm = to_nvdimm(ndd->dev); struct nd_namespace_label *nd_label; struct nd_region *nd_region = NULL; - u8 label_uuid[NSLABEL_UUID_LEN]; struct nd_label_id label_id; struct resource *res; + uuid_t label_uuid; u32 flags; nd_label = to_label(ndd, slot); @@ -410,11 +411,11 @@ int nd_label_reserve_dpa(struct nvdimm_drvdata *ndd) if (!slot_valid(ndd, nd_label, slot)) continue; - memcpy(label_uuid, nd_label->uuid, NSLABEL_UUID_LEN); + nsl_get_uuid(ndd, nd_label, &label_uuid); flags = nsl_get_flags(ndd, nd_label); if (test_bit(NDD_NOBLK, &nvdimm->flags)) flags &= ~NSLABEL_FLAG_LOCAL; - nd_label_gen_id(&label_id, label_uuid, flags); + nd_label_gen_id(&label_id, &label_uuid, flags); res = nvdimm_allocate_dpa(ndd, &label_id, nsl_get_dpa(ndd, nd_label), nsl_get_rawsize(ndd, nd_label)); @@ -851,7 +852,7 @@ static int __pmem_label_update(struct nd_region *nd_region, nd_label = to_label(ndd, slot); memset(nd_label, 0, sizeof_namespace_label(ndd)); - memcpy(nd_label->uuid, nspm->uuid, NSLABEL_UUID_LEN); + nsl_set_uuid(ndd, nd_label, nspm->uuid); nsl_set_name(ndd, nd_label, nspm->alt_name); nsl_set_flags(ndd, nd_label, flags); nsl_set_nlabel(ndd, nd_label, nd_region->ndr_mappings); @@ -878,9 +879,8 @@ static int __pmem_label_update(struct nd_region *nd_region, list_for_each_entry(label_ent, &nd_mapping->labels, list) { if (!label_ent->label) continue; - if (test_and_clear_bit(ND_LABEL_REAP, &label_ent->flags) - || memcmp(nspm->uuid, label_ent->label->uuid, - NSLABEL_UUID_LEN) == 0) + if (test_and_clear_bit(ND_LABEL_REAP, &label_ent->flags) || + nsl_uuid_equal(ndd, label_ent->label, nspm->uuid)) reap_victim(nd_mapping, label_ent); } @@ -1005,7 +1005,6 @@ static int __blk_label_update(struct nd_region *nd_region, unsigned long *free, *victim_map = NULL; struct resource *res, **old_res_list; struct nd_label_id label_id; - u8 uuid[NSLABEL_UUID_LEN]; int min_dpa_idx = 0; LIST_HEAD(list); u32 nslot, slot; @@ -1043,8 +1042,7 @@ static int __blk_label_update(struct nd_region *nd_region, /* mark unused labels for garbage collection */ for_each_clear_bit_le(slot, free, nslot) { nd_label = to_label(ndd, slot); - memcpy(uuid, nd_label->uuid, NSLABEL_UUID_LEN); - if (memcmp(uuid, nsblk->uuid, NSLABEL_UUID_LEN) != 0) + if (!nsl_uuid_equal(ndd, nd_label, nsblk->uuid)) continue; res = to_resource(ndd, nd_label); if (res && is_old_resource(res, old_res_list, @@ -1113,7 +1111,7 @@ static int __blk_label_update(struct nd_region *nd_region, nd_label = to_label(ndd, slot); memset(nd_label, 0, sizeof_namespace_label(ndd)); - memcpy(nd_label->uuid, nsblk->uuid, NSLABEL_UUID_LEN); + nsl_set_uuid(ndd, nd_label, nsblk->uuid); nsl_set_name(ndd, nd_label, nsblk->alt_name); nsl_set_flags(ndd, nd_label, NSLABEL_FLAG_LOCAL); @@ -1161,8 +1159,7 @@ static int __blk_label_update(struct nd_region *nd_region, if (!nd_label) continue; nlabel++; - memcpy(uuid, nd_label->uuid, NSLABEL_UUID_LEN); - if (memcmp(uuid, nsblk->uuid, NSLABEL_UUID_LEN) != 0) + if (!nsl_uuid_equal(ndd, nd_label, nsblk->uuid)) continue; nlabel--; list_move(&label_ent->list, &list); @@ -1192,8 +1189,7 @@ static int __blk_label_update(struct nd_region *nd_region, } for_each_clear_bit_le(slot, free, nslot) { nd_label = to_label(ndd, slot); - memcpy(uuid, nd_label->uuid, NSLABEL_UUID_LEN); - if (memcmp(uuid, nsblk->uuid, NSLABEL_UUID_LEN) != 0) + if (!nsl_uuid_equal(ndd, nd_label, nsblk->uuid)) continue; res = to_resource(ndd, nd_label); res->flags &= ~DPA_RESOURCE_ADJUSTED; @@ -1273,12 +1269,11 @@ static int init_labels(struct nd_mapping *nd_mapping, int num_labels) return max(num_labels, old_num_labels); } -static int del_labels(struct nd_mapping *nd_mapping, u8 *uuid) +static int del_labels(struct nd_mapping *nd_mapping, uuid_t *uuid) { struct nvdimm_drvdata *ndd = to_ndd(nd_mapping); struct nd_label_ent *label_ent, *e; struct nd_namespace_index *nsindex; - u8 label_uuid[NSLABEL_UUID_LEN]; unsigned long *free; LIST_HEAD(list); u32 nslot, slot; @@ -1298,8 +1293,7 @@ static int del_labels(struct nd_mapping *nd_mapping, u8 *uuid) if (!nd_label) continue; active++; - memcpy(label_uuid, nd_label->uuid, NSLABEL_UUID_LEN); - if (memcmp(label_uuid, uuid, NSLABEL_UUID_LEN) != 0) + if (!nsl_uuid_equal(ndd, nd_label, uuid)) continue; active--; slot = to_slot(ndd, nd_label); diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index 4cec171c934d..1415d543c3e3 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c @@ -51,7 +51,7 @@ static bool is_namespace_io(const struct device *dev); static int is_uuid_busy(struct device *dev, void *data) { - u8 *uuid1 = data, *uuid2 = NULL; + uuid_t *uuid1 = data, *uuid2 = NULL; if (is_namespace_pmem(dev)) { struct nd_namespace_pmem *nspm = to_nd_namespace_pmem(dev); @@ -71,7 +71,7 @@ static int is_uuid_busy(struct device *dev, void *data) uuid2 = nd_pfn->uuid; } - if (uuid2 && memcmp(uuid1, uuid2, NSLABEL_UUID_LEN) == 0) + if (uuid2 && uuid_equal(uuid1, uuid2)) return -EBUSY; return 0; @@ -89,7 +89,7 @@ static int is_namespace_uuid_busy(struct device *dev, void *data) * @dev: any device on a nvdimm_bus * @uuid: uuid to check */ -bool nd_is_uuid_unique(struct device *dev, u8 *uuid) +bool nd_is_uuid_unique(struct device *dev, uuid_t *uuid) { struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); @@ -192,12 +192,10 @@ const char *nvdimm_namespace_disk_name(struct nd_namespace_common *ndns, } EXPORT_SYMBOL(nvdimm_namespace_disk_name); -const u8 *nd_dev_to_uuid(struct device *dev) +const uuid_t *nd_dev_to_uuid(struct device *dev) { - static const u8 null_uuid[16]; - if (!dev) - return null_uuid; + return &uuid_null; if (is_namespace_pmem(dev)) { struct nd_namespace_pmem *nspm = to_nd_namespace_pmem(dev); @@ -208,7 +206,7 @@ const u8 *nd_dev_to_uuid(struct device *dev) return nsblk->uuid; } else - return null_uuid; + return &uuid_null; } EXPORT_SYMBOL(nd_dev_to_uuid); @@ -938,7 +936,8 @@ static void nd_namespace_pmem_set_resource(struct nd_region *nd_region, res->end = res->start + size - 1; } -static bool uuid_not_set(const u8 *uuid, struct device *dev, const char *where) +static bool uuid_not_set(const uuid_t *uuid, struct device *dev, + const char *where) { if (!uuid) { dev_dbg(dev, "%s: uuid not set\n", where); @@ -957,7 +956,7 @@ static ssize_t __size_store(struct device *dev, unsigned long long val) struct nd_label_id label_id; u32 flags = 0, remainder; int rc, i, id = -1; - u8 *uuid = NULL; + uuid_t *uuid = NULL; if (dev->driver || ndns->claim) return -EBUSY; @@ -1050,7 +1049,7 @@ static ssize_t size_store(struct device *dev, { struct nd_region *nd_region = to_nd_region(dev->parent); unsigned long long val; - u8 **uuid = NULL; + uuid_t **uuid = NULL; int rc; rc = kstrtoull(buf, 0, &val); @@ -1147,7 +1146,7 @@ static ssize_t size_show(struct device *dev, } static DEVICE_ATTR(size, 0444, size_show, size_store); -static u8 *namespace_to_uuid(struct device *dev) +static uuid_t *namespace_to_uuid(struct device *dev) { if (is_namespace_pmem(dev)) { struct nd_namespace_pmem *nspm = to_nd_namespace_pmem(dev); @@ -1161,10 +1160,10 @@ static u8 *namespace_to_uuid(struct device *dev) return ERR_PTR(-ENXIO); } -static ssize_t uuid_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t uuid_show(struct device *dev, struct device_attribute *attr, + char *buf) { - u8 *uuid = namespace_to_uuid(dev); + uuid_t *uuid = namespace_to_uuid(dev); if (IS_ERR(uuid)) return PTR_ERR(uuid); @@ -1181,7 +1180,8 @@ static ssize_t uuid_show(struct device *dev, * @old_uuid: reference to the uuid storage location in the namespace object */ static int namespace_update_uuid(struct nd_region *nd_region, - struct device *dev, u8 *new_uuid, u8 **old_uuid) + struct device *dev, uuid_t *new_uuid, + uuid_t **old_uuid) { u32 flags = is_namespace_blk(dev) ? NSLABEL_FLAG_LOCAL : 0; struct nd_label_id old_label_id; @@ -1231,10 +1231,12 @@ static int namespace_update_uuid(struct nd_region *nd_region, list_for_each_entry(label_ent, &nd_mapping->labels, list) { struct nd_namespace_label *nd_label = label_ent->label; struct nd_label_id label_id; + uuid_t uuid; if (!nd_label) continue; - nd_label_gen_id(&label_id, nd_label->uuid, + nsl_get_uuid(ndd, nd_label, &uuid); + nd_label_gen_id(&label_id, &uuid, nsl_get_flags(ndd, nd_label)); if (strcmp(old_label_id.id, label_id.id) == 0) set_bit(ND_LABEL_REAP, &label_ent->flags); @@ -1251,9 +1253,9 @@ static ssize_t uuid_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { struct nd_region *nd_region = to_nd_region(dev->parent); - u8 *uuid = NULL; + uuid_t *uuid = NULL; + uuid_t **ns_uuid; ssize_t rc = 0; - u8 **ns_uuid; if (is_namespace_pmem(dev)) { struct nd_namespace_pmem *nspm = to_nd_namespace_pmem(dev); @@ -1378,8 +1380,8 @@ static ssize_t dpa_extents_show(struct device *dev, { struct nd_region *nd_region = to_nd_region(dev->parent); struct nd_label_id label_id; + uuid_t *uuid = NULL; int count = 0, i; - u8 *uuid = NULL; u32 flags = 0; nvdimm_bus_lock(dev); @@ -1831,8 +1833,8 @@ static struct device **create_namespace_io(struct nd_region *nd_region) return devs; } -static bool has_uuid_at_pos(struct nd_region *nd_region, u8 *uuid, - u64 cookie, u16 pos) +static bool has_uuid_at_pos(struct nd_region *nd_region, const uuid_t *uuid, + u64 cookie, u16 pos) { struct nd_namespace_label *found = NULL; int i; @@ -1856,7 +1858,7 @@ static bool has_uuid_at_pos(struct nd_region *nd_region, u8 *uuid, if (!nsl_validate_isetcookie(ndd, nd_label, cookie)) continue; - if (memcmp(nd_label->uuid, uuid, NSLABEL_UUID_LEN) != 0) + if (!nsl_uuid_equal(ndd, nd_label, uuid)) continue; if (!nsl_validate_type_guid(ndd, nd_label, @@ -1881,7 +1883,7 @@ static bool has_uuid_at_pos(struct nd_region *nd_region, u8 *uuid, return found != NULL; } -static int select_pmem_id(struct nd_region *nd_region, u8 *pmem_id) +static int select_pmem_id(struct nd_region *nd_region, const uuid_t *pmem_id) { int i; @@ -1900,7 +1902,7 @@ static int select_pmem_id(struct nd_region *nd_region, u8 *pmem_id) nd_label = label_ent->label; if (!nd_label) continue; - if (memcmp(nd_label->uuid, pmem_id, NSLABEL_UUID_LEN) == 0) + if (nsl_uuid_equal(ndd, nd_label, pmem_id)) break; nd_label = NULL; } @@ -1923,7 +1925,8 @@ static int select_pmem_id(struct nd_region *nd_region, u8 *pmem_id) /* pass */; else { dev_dbg(&nd_region->dev, "%s invalid label for %pUb\n", - dev_name(ndd->dev), nd_label->uuid); + dev_name(ndd->dev), + nsl_uuid_raw(ndd, nd_label)); return -EINVAL; } @@ -1953,6 +1956,7 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region, resource_size_t size = 0; struct resource *res; struct device *dev; + uuid_t uuid; int rc = 0; u16 i; @@ -1963,12 +1967,12 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region, if (!nsl_validate_isetcookie(ndd, nd_label, cookie)) { dev_dbg(&nd_region->dev, "invalid cookie in label: %pUb\n", - nd_label->uuid); + nsl_uuid_raw(ndd, nd_label)); if (!nsl_validate_isetcookie(ndd, nd_label, altcookie)) return ERR_PTR(-EAGAIN); dev_dbg(&nd_region->dev, "valid altcookie in label: %pUb\n", - nd_label->uuid); + nsl_uuid_raw(ndd, nd_label)); } nspm = kzalloc(sizeof(*nspm), GFP_KERNEL); @@ -1984,9 +1988,12 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region, res->flags = IORESOURCE_MEM; for (i = 0; i < nd_region->ndr_mappings; i++) { - if (has_uuid_at_pos(nd_region, nd_label->uuid, cookie, i)) + uuid_t uuid; + + nsl_get_uuid(ndd, nd_label, &uuid); + if (has_uuid_at_pos(nd_region, &uuid, cookie, i)) continue; - if (has_uuid_at_pos(nd_region, nd_label->uuid, altcookie, i)) + if (has_uuid_at_pos(nd_region, &uuid, altcookie, i)) continue; break; } @@ -2000,7 +2007,7 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region, * find a dimm with two instances of the same uuid. */ dev_err(&nd_region->dev, "%s missing label for %pUb\n", - nvdimm_name(nvdimm), nd_label->uuid); + nvdimm_name(nvdimm), nsl_uuid_raw(ndd, nd_label)); rc = -EINVAL; goto err; } @@ -2013,7 +2020,8 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region, * the dimm being enabled (i.e. nd_label_reserve_dpa() * succeeded). */ - rc = select_pmem_id(nd_region, nd_label->uuid); + nsl_get_uuid(ndd, nd_label, &uuid); + rc = select_pmem_id(nd_region, &uuid); if (rc) goto err; @@ -2039,8 +2047,8 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region, WARN_ON(nspm->alt_name || nspm->uuid); nspm->alt_name = kmemdup(nsl_ref_name(ndd, label0), NSLABEL_NAME_LEN, GFP_KERNEL); - nspm->uuid = kmemdup((void __force *) label0->uuid, - NSLABEL_UUID_LEN, GFP_KERNEL); + nsl_get_uuid(ndd, label0, &uuid); + nspm->uuid = kmemdup(&uuid, sizeof(uuid_t), GFP_KERNEL); nspm->lbasize = nsl_get_lbasize(ndd, label0); nspm->nsio.common.claim_class = nsl_get_claim_class(ndd, label0); @@ -2217,15 +2225,15 @@ static int add_namespace_resource(struct nd_region *nd_region, int i; for (i = 0; i < count; i++) { - u8 *uuid = namespace_to_uuid(devs[i]); + uuid_t *uuid = namespace_to_uuid(devs[i]); struct resource *res; - if (IS_ERR_OR_NULL(uuid)) { + if (IS_ERR(uuid)) { WARN_ON(1); continue; } - if (memcmp(uuid, nd_label->uuid, NSLABEL_UUID_LEN) != 0) + if (!nsl_uuid_equal(ndd, nd_label, uuid)) continue; if (is_namespace_blk(devs[i])) { res = nsblk_add_resource(nd_region, ndd, @@ -2236,8 +2244,8 @@ static int add_namespace_resource(struct nd_region *nd_region, nd_dbg_dpa(nd_region, ndd, res, "%d assign\n", count); } else { dev_err(&nd_region->dev, - "error: conflicting extents for uuid: %pUb\n", - nd_label->uuid); + "error: conflicting extents for uuid: %pUb\n", + uuid); return -ENXIO; } break; @@ -2257,6 +2265,7 @@ static struct device *create_namespace_blk(struct nd_region *nd_region, char name[NSLABEL_NAME_LEN]; struct device *dev = NULL; struct resource *res; + uuid_t uuid; if (!nsl_validate_type_guid(ndd, nd_label, &nd_set->type_guid)) return ERR_PTR(-EAGAIN); @@ -2271,7 +2280,8 @@ static struct device *create_namespace_blk(struct nd_region *nd_region, dev->parent = &nd_region->dev; nsblk->id = -1; nsblk->lbasize = nsl_get_lbasize(ndd, nd_label); - nsblk->uuid = kmemdup(nd_label->uuid, NSLABEL_UUID_LEN, GFP_KERNEL); + nsl_get_uuid(ndd, nd_label, &uuid); + nsblk->uuid = kmemdup(&uuid, sizeof(uuid_t), GFP_KERNEL); nsblk->common.claim_class = nsl_get_claim_class(ndd, nd_label); if (!nsblk->uuid) goto blk_err; diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h index 564faa36a3ca..a11850dd475d 100644 --- a/drivers/nvdimm/nd-core.h +++ b/drivers/nvdimm/nd-core.h @@ -126,8 +126,9 @@ void nvdimm_bus_destroy_ndctl(struct nvdimm_bus *nvdimm_bus); void nd_synchronize(void); void __nd_device_register(struct device *dev); struct nd_label_id; -char *nd_label_gen_id(struct nd_label_id *label_id, u8 *uuid, u32 flags); -bool nd_is_uuid_unique(struct device *dev, u8 *uuid); +char *nd_label_gen_id(struct nd_label_id *label_id, const uuid_t *uuid, + u32 flags); +bool nd_is_uuid_unique(struct device *dev, uuid_t *uuid); struct nd_region; struct nvdimm_drvdata; struct nd_mapping; diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index 5467ebbb4a6b..ec3c9aad7f50 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -177,6 +177,38 @@ static inline void nsl_set_lbasize(struct nvdimm_drvdata *ndd, nd_label->lbasize = __cpu_to_le64(lbasize); } +static inline const uuid_t *nsl_get_uuid(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label, + uuid_t *uuid) +{ + import_uuid(uuid, nd_label->uuid); + return uuid; +} + +static inline const uuid_t *nsl_set_uuid(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label, + const uuid_t *uuid) +{ + export_uuid(nd_label->uuid, uuid); + return uuid; +} + +static inline bool nsl_uuid_equal(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label, + const uuid_t *uuid) +{ + uuid_t tmp; + + import_uuid(&tmp, nd_label->uuid); + return uuid_equal(&tmp, uuid); +} + +static inline const u8 *nsl_uuid_raw(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label) +{ + return nd_label->uuid; +} + bool nsl_validate_blk_isetcookie(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, u64 isetcookie); @@ -335,7 +367,7 @@ struct nd_btt { struct btt *btt; unsigned long lbasize; u64 size; - u8 *uuid; + uuid_t *uuid; int id; int initial_offset; u16 version_major; @@ -350,7 +382,7 @@ enum nd_pfn_mode { struct nd_pfn { int id; - u8 *uuid; + uuid_t *uuid; struct device dev; unsigned long align; unsigned long npfns; @@ -378,7 +410,7 @@ void wait_nvdimm_bus_probe_idle(struct device *dev); void nd_device_register(struct device *dev); void nd_device_unregister(struct device *dev, enum nd_async_mode mode); void nd_device_notify(struct device *dev, enum nvdimm_event event); -int nd_uuid_store(struct device *dev, u8 **uuid_out, const char *buf, +int nd_uuid_store(struct device *dev, uuid_t **uuid_out, const char *buf, size_t len); ssize_t nd_size_select_show(unsigned long current_size, const unsigned long *supported, char *buf); @@ -561,6 +593,6 @@ static inline bool is_bad_pmem(struct badblocks *bb, sector_t sector, return false; } resource_size_t nd_namespace_blk_validate(struct nd_namespace_blk *nsblk); -const u8 *nd_dev_to_uuid(struct device *dev); +const uuid_t *nd_dev_to_uuid(struct device *dev); bool pmem_should_map_pages(struct device *dev); #endif /* __ND_H__ */ diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c index b499df630d4d..58eda16f5c53 100644 --- a/drivers/nvdimm/pfn_devs.c +++ b/drivers/nvdimm/pfn_devs.c @@ -452,7 +452,7 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig) unsigned long align, start_pad; struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb; struct nd_namespace_common *ndns = nd_pfn->ndns; - const u8 *parent_uuid = nd_dev_to_uuid(&ndns->dev); + const uuid_t *parent_uuid = nd_dev_to_uuid(&ndns->dev); if (!pfn_sb || !ndns) return -ENODEV; diff --git a/include/linux/nd.h b/include/linux/nd.h index ee9ad76afbba..8a8c63edb1b2 100644 --- a/include/linux/nd.h +++ b/include/linux/nd.h @@ -88,7 +88,7 @@ struct nd_namespace_pmem { struct nd_namespace_io nsio; unsigned long lbasize; char *alt_name; - u8 *uuid; + uuid_t *uuid; int id; }; @@ -105,7 +105,7 @@ struct nd_namespace_pmem { struct nd_namespace_blk { struct nd_namespace_common common; char *alt_name; - u8 *uuid; + uuid_t *uuid; int id; unsigned long lbasize; resource_size_t size; -- cgit From 8172db92527c936c638b52274fbd06a0a624a56b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 8 Sep 2021 22:11:42 -0700 Subject: libnvdimm/label: Add a helper for nlabel validation In the CXL namespace label there is no need for nlabel since that is inferred from the region. Add a helper that moves nsl_get_label() behind a helper that validates the number of labels relative to the region. Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/163116430293.2460985.12693942353621355232.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/nvdimm/namespace_devs.c | 5 ++--- drivers/nvdimm/nd.h | 7 +++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index 1415d543c3e3..b57a2d36c517 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c @@ -1848,12 +1848,11 @@ static bool has_uuid_at_pos(struct nd_region *nd_region, const uuid_t *uuid, list_for_each_entry(label_ent, &nd_mapping->labels, list) { struct nd_namespace_label *nd_label = label_ent->label; - u16 position, nlabel; + u16 position; if (!nd_label) continue; position = nsl_get_position(ndd, nd_label); - nlabel = nsl_get_nlabel(ndd, nd_label); if (!nsl_validate_isetcookie(ndd, nd_label, cookie)) continue; @@ -1870,7 +1869,7 @@ static bool has_uuid_at_pos(struct nd_region *nd_region, const uuid_t *uuid, return false; } found_uuid = true; - if (nlabel != nd_region->ndr_mappings) + if (!nsl_validate_nlabel(nd_region, ndd, nd_label)) continue; if (position != pos) continue; diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index ec3c9aad7f50..036638bdb7e3 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -342,6 +342,13 @@ struct nd_region { struct nd_mapping mapping[]; }; +static inline bool nsl_validate_nlabel(struct nd_region *nd_region, + struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label) +{ + return nsl_get_nlabel(ndd, nd_label) == nd_region->ndr_mappings; +} + struct nd_blk_region { int (*enable)(struct nvdimm_bus *nvdimm_bus, struct device *dev); int (*do_io)(struct nd_blk_region *ndbr, resource_size_t dpa, -- cgit From 42e192aa9891f196bc1adaaeab9a23d975618e5e Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 8 Sep 2021 22:11:48 -0700 Subject: libnvdimm/labels: Introduce the concept of multi-range namespace labels The CXL specification defines a mechanism for namespaces to be comprised of multiple dis-contiguous ranges. Introduce that concept to the legacy NVDIMM namespace implementation with a new nsl_set_nrange() helper, that sets the number of ranges to 1. Once the NVDIMM subsystem supports CXL labels and updates its namespace capacity provisioning for dis-contiguous support nsl_set_nrange() can be updated, but in the meantime CXL label validation requires nrange be non-zero. Reported-by: Jonathan Cameron Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/163116430804.2460985.5482188351381597529.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/nvdimm/label.c | 1 + drivers/nvdimm/nd.h | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c index e7fdb718ebf0..7832b190efd7 100644 --- a/drivers/nvdimm/label.c +++ b/drivers/nvdimm/label.c @@ -856,6 +856,7 @@ static int __pmem_label_update(struct nd_region *nd_region, nsl_set_name(ndd, nd_label, nspm->alt_name); nsl_set_flags(ndd, nd_label, flags); nsl_set_nlabel(ndd, nd_label, nd_region->ndr_mappings); + nsl_set_nrange(ndd, nd_label, 1); nsl_set_position(ndd, nd_label, pos); nsl_set_isetcookie(ndd, nd_label, cookie); nsl_set_rawsize(ndd, nd_label, resource_size(res)); diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index 036638bdb7e3..d57f95a48fe1 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -164,6 +164,19 @@ static inline void nsl_set_nlabel(struct nvdimm_drvdata *ndd, nd_label->nlabel = __cpu_to_le16(nlabel); } +static inline u16 nsl_get_nrange(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label) +{ + /* EFI labels do not have an nrange field */ + return 1; +} + +static inline void nsl_set_nrange(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label, + u16 nrange) +{ +} + static inline u64 nsl_get_lbasize(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label) { -- cgit From 999c993a85f1cab8c37752db71b1f841a5d2c190 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 8 Sep 2021 22:11:53 -0700 Subject: libnvdimm/labels: Fix kernel-doc for label.h Clean up existing kernel-doc warnings before adding new CXL label data structures. drivers/nvdimm/label.h:66: warning: Function parameter or member 'labelsize' not described in 'nd_namespace_index' drivers/nvdimm/label.h:66: warning: Function parameter or member 'free' not described in 'nd_namespace_index' drivers/nvdimm/label.h:103: warning: Function parameter or member 'align' not described in 'nd_namespace_label' drivers/nvdimm/label.h:103: warning: Function parameter or member 'reserved' not described in 'nd_namespace_label' drivers/nvdimm/label.h:103: warning: Function parameter or member 'type_guid' not described in 'nd_namespace_label' drivers/nvdimm/label.h:103: warning: Function parameter or member 'abstraction_guid' not described in 'nd_namespace_label' drivers/nvdimm/label.h:103: warning: Function parameter or member 'reserved2' not described in 'nd_namespace_label' drivers/nvdimm/label.h:103: warning: Function parameter or member 'checksum' not described in 'nd_namespace_label' Reported-by: Jonathan Cameron Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/163116431381.2460985.6990754901097922099.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/nvdimm/label.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/nvdimm/label.h b/drivers/nvdimm/label.h index 31f94fad7b92..7fa757d47846 100644 --- a/drivers/nvdimm/label.h +++ b/drivers/nvdimm/label.h @@ -34,6 +34,7 @@ enum { * struct nd_namespace_index - label set superblock * @sig: NAMESPACE_INDEX\0 * @flags: placeholder + * @labelsize: log2 size (v1 labels 128 bytes v2 labels 256 bytes) * @seq: sequence number for this index * @myoff: offset of this index in label area * @mysize: size of this index struct @@ -43,7 +44,7 @@ enum { * @major: label area major version * @minor: label area minor version * @checksum: fletcher64 of all fields - * @free[0]: bitmap, nlabel bits + * @free: bitmap, nlabel bits * * The size of free[] is rounded up so the total struct size is a * multiple of NSINDEX_ALIGN bytes. Any bits this allocates beyond @@ -77,7 +78,12 @@ struct nd_namespace_index { * @dpa: DPA of NVM range on this DIMM * @rawsize: size of namespace * @slot: slot of this label in label area - * @unused: must be zero + * @align: physical address alignment of the namespace + * @reserved: reserved + * @type_guid: copy of struct acpi_nfit_system_address.range_guid + * @abstraction_guid: personality id (btt, btt2, fsdax, devdax....) + * @reserved2: reserved + * @checksum: fletcher64 sum of this object */ struct nd_namespace_label { u8 uuid[NSLABEL_UUID_LEN]; -- cgit From 540ccaa2e4dd6d44dcd9305a007078fda597af02 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 8 Sep 2021 22:11:58 -0700 Subject: libnvdimm/label: Define CXL region labels Add a definition of the CXL 2.0 region label format. Note this is done as a separate patch to make the next patch that adds namespace label support easier to read. Reported-by: Jonathan Cameron Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/163116431893.2460985.4003511000574373922.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/nvdimm/label.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/nvdimm/label.h b/drivers/nvdimm/label.h index 7fa757d47846..0519aacc2926 100644 --- a/drivers/nvdimm/label.h +++ b/drivers/nvdimm/label.h @@ -66,6 +66,38 @@ struct nd_namespace_index { u8 free[]; }; +/** + * struct cxl_region_label - CXL 2.0 Table 211 + * @type: uuid identifying this label format (region) + * @uuid: uuid for the region this label describes + * @flags: NSLABEL_FLAG_UPDATING (all other flags reserved) + * @nlabel: 1 per interleave-way in the region + * @position: this label's position in the set + * @dpa: start address in device-local capacity for this label + * @rawsize: size of this label's contribution to region + * @hpa: mandatory system physical address to map this region + * @slot: slot id of this label in label area + * @ig: interleave granularity (1 << @ig) * 256 bytes + * @align: alignment in SZ_256M blocks + * @reserved: reserved + * @checksum: fletcher64 sum of this label + */ +struct cxl_region_label { + u8 type[NSLABEL_UUID_LEN]; + u8 uuid[NSLABEL_UUID_LEN]; + __le32 flags; + __le16 nlabel; + __le16 position; + __le64 dpa; + __le64 rawsize; + __le64 hpa; + __le32 slot; + __le32 ig; + __le32 align; + u8 reserved[0xac]; + __le64 checksum; +}; + /** * struct nd_namespace_label - namespace superblock * @uuid: UUID per RFC 4122 -- cgit From 5af96835e4dafd21a766fd7a8e583ec7abbfe98c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 8 Sep 2021 22:12:04 -0700 Subject: libnvdimm/labels: Introduce CXL labels Now that all of use sites of label data have been converted to nsl_* helpers, introduce the CXL label format. The ->cxl flag in nvdimm_drvdata indicates the label format the device expects. A follow-on patch allows a bus provider to select the label style. Note that the EFI definition of the labels represents the Linux "claim class" with a GUID. The CXL definition of the labels stores the same identifier in UUID byte order. Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/163116432405.2460985.5547867384570123403.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/nvdimm/label.c | 104 ++++++++++++++++++++++++++++++------- drivers/nvdimm/label.h | 52 +++++++++++++++++-- drivers/nvdimm/nd.h | 135 ++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 241 insertions(+), 50 deletions(-) diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c index 7832b190efd7..5ec9a4023df9 100644 --- a/drivers/nvdimm/label.c +++ b/drivers/nvdimm/label.c @@ -17,6 +17,14 @@ static guid_t nvdimm_btt2_guid; static guid_t nvdimm_pfn_guid; static guid_t nvdimm_dax_guid; +static uuid_t nvdimm_btt_uuid; +static uuid_t nvdimm_btt2_uuid; +static uuid_t nvdimm_pfn_uuid; +static uuid_t nvdimm_dax_uuid; + +static uuid_t cxl_region_uuid; +static uuid_t cxl_namespace_uuid; + static const char NSINDEX_SIGNATURE[] = "NAMESPACE_INDEX\0"; static u32 best_seq(u32 a, u32 b) @@ -352,7 +360,7 @@ static bool nsl_validate_checksum(struct nvdimm_drvdata *ndd, { u64 sum, sum_save; - if (!namespace_label_has(ndd, checksum)) + if (!ndd->cxl && !efi_namespace_label_has(ndd, checksum)) return true; sum_save = nsl_get_checksum(ndd, nd_label); @@ -367,7 +375,7 @@ static void nsl_calculate_checksum(struct nvdimm_drvdata *ndd, { u64 sum; - if (!namespace_label_has(ndd, checksum)) + if (!ndd->cxl && !efi_namespace_label_has(ndd, checksum)) return; nsl_set_checksum(ndd, nd_label, 0); sum = nd_fletcher64(nd_label, sizeof_namespace_label(ndd), 1); @@ -725,7 +733,7 @@ static unsigned long nd_label_offset(struct nvdimm_drvdata *ndd, - (unsigned long) to_namespace_index(ndd, 0); } -static enum nvdimm_claim_class to_nvdimm_cclass(guid_t *guid) +static enum nvdimm_claim_class guid_to_nvdimm_cclass(guid_t *guid) { if (guid_equal(guid, &nvdimm_btt_guid)) return NVDIMM_CCLASS_BTT; @@ -741,6 +749,23 @@ static enum nvdimm_claim_class to_nvdimm_cclass(guid_t *guid) return NVDIMM_CCLASS_UNKNOWN; } +/* CXL labels store UUIDs instead of GUIDs for the same data */ +static enum nvdimm_claim_class uuid_to_nvdimm_cclass(uuid_t *uuid) +{ + if (uuid_equal(uuid, &nvdimm_btt_uuid)) + return NVDIMM_CCLASS_BTT; + else if (uuid_equal(uuid, &nvdimm_btt2_uuid)) + return NVDIMM_CCLASS_BTT2; + else if (uuid_equal(uuid, &nvdimm_pfn_uuid)) + return NVDIMM_CCLASS_PFN; + else if (uuid_equal(uuid, &nvdimm_dax_uuid)) + return NVDIMM_CCLASS_DAX; + else if (uuid_equal(uuid, &uuid_null)) + return NVDIMM_CCLASS_NONE; + + return NVDIMM_CCLASS_UNKNOWN; +} + static const guid_t *to_abstraction_guid(enum nvdimm_claim_class claim_class, guid_t *target) { @@ -762,6 +787,28 @@ static const guid_t *to_abstraction_guid(enum nvdimm_claim_class claim_class, return &guid_null; } +/* CXL labels store UUIDs instead of GUIDs for the same data */ +static const uuid_t *to_abstraction_uuid(enum nvdimm_claim_class claim_class, + uuid_t *target) +{ + if (claim_class == NVDIMM_CCLASS_BTT) + return &nvdimm_btt_uuid; + else if (claim_class == NVDIMM_CCLASS_BTT2) + return &nvdimm_btt2_uuid; + else if (claim_class == NVDIMM_CCLASS_PFN) + return &nvdimm_pfn_uuid; + else if (claim_class == NVDIMM_CCLASS_DAX) + return &nvdimm_dax_uuid; + else if (claim_class == NVDIMM_CCLASS_UNKNOWN) { + /* + * If we're modifying a namespace for which we don't + * know the claim_class, don't touch the existing uuid. + */ + return target; + } else + return &uuid_null; +} + static void reap_victim(struct nd_mapping *nd_mapping, struct nd_label_ent *victim) { @@ -776,18 +823,18 @@ static void reap_victim(struct nd_mapping *nd_mapping, static void nsl_set_type_guid(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, guid_t *guid) { - if (namespace_label_has(ndd, type_guid)) - guid_copy(&nd_label->type_guid, guid); + if (efi_namespace_label_has(ndd, type_guid)) + guid_copy(&nd_label->efi.type_guid, guid); } bool nsl_validate_type_guid(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, guid_t *guid) { - if (!namespace_label_has(ndd, type_guid)) + if (ndd->cxl || !efi_namespace_label_has(ndd, type_guid)) return true; - if (!guid_equal(&nd_label->type_guid, guid)) { + if (!guid_equal(&nd_label->efi.type_guid, guid)) { dev_dbg(ndd->dev, "expect type_guid %pUb got %pUb\n", guid, - &nd_label->type_guid); + &nd_label->efi.type_guid); return false; } return true; @@ -797,19 +844,34 @@ static void nsl_set_claim_class(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, enum nvdimm_claim_class claim_class) { - if (!namespace_label_has(ndd, abstraction_guid)) + if (ndd->cxl) { + uuid_t uuid; + + import_uuid(&uuid, nd_label->cxl.abstraction_uuid); + export_uuid(nd_label->cxl.abstraction_uuid, + to_abstraction_uuid(claim_class, &uuid)); + return; + } + + if (!efi_namespace_label_has(ndd, abstraction_guid)) return; - guid_copy(&nd_label->abstraction_guid, + guid_copy(&nd_label->efi.abstraction_guid, to_abstraction_guid(claim_class, - &nd_label->abstraction_guid)); + &nd_label->efi.abstraction_guid)); } enum nvdimm_claim_class nsl_get_claim_class(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label) { - if (!namespace_label_has(ndd, abstraction_guid)) + if (ndd->cxl) { + uuid_t uuid; + + import_uuid(&uuid, nd_label->cxl.abstraction_uuid); + return uuid_to_nvdimm_cclass(&uuid); + } + if (!efi_namespace_label_has(ndd, abstraction_guid)) return NVDIMM_CCLASS_NONE; - return to_nvdimm_cclass(&nd_label->abstraction_guid); + return guid_to_nvdimm_cclass(&nd_label->efi.abstraction_guid); } static int __pmem_label_update(struct nd_region *nd_region, @@ -942,7 +1004,7 @@ static void nsl_set_blk_isetcookie(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, u64 isetcookie) { - if (namespace_label_has(ndd, type_guid)) { + if (efi_namespace_label_has(ndd, type_guid)) { nsl_set_isetcookie(ndd, nd_label, isetcookie); return; } @@ -953,7 +1015,7 @@ bool nsl_validate_blk_isetcookie(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, u64 isetcookie) { - if (!namespace_label_has(ndd, type_guid)) + if (!efi_namespace_label_has(ndd, type_guid)) return true; if (nsl_get_isetcookie(ndd, nd_label) != isetcookie) { @@ -969,7 +1031,7 @@ static void nsl_set_blk_nlabel(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, int nlabel, bool first) { - if (!namespace_label_has(ndd, type_guid)) { + if (!efi_namespace_label_has(ndd, type_guid)) { nsl_set_nlabel(ndd, nd_label, 0); /* N/A */ return; } @@ -980,7 +1042,7 @@ static void nsl_set_blk_position(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, bool first) { - if (!namespace_label_has(ndd, type_guid)) { + if (!efi_namespace_label_has(ndd, type_guid)) { nsl_set_position(ndd, nd_label, 0); return; } @@ -1390,5 +1452,13 @@ int __init nd_label_init(void) WARN_ON(guid_parse(NVDIMM_PFN_GUID, &nvdimm_pfn_guid)); WARN_ON(guid_parse(NVDIMM_DAX_GUID, &nvdimm_dax_guid)); + WARN_ON(uuid_parse(NVDIMM_BTT_GUID, &nvdimm_btt_uuid)); + WARN_ON(uuid_parse(NVDIMM_BTT2_GUID, &nvdimm_btt2_uuid)); + WARN_ON(uuid_parse(NVDIMM_PFN_GUID, &nvdimm_pfn_uuid)); + WARN_ON(uuid_parse(NVDIMM_DAX_GUID, &nvdimm_dax_uuid)); + + WARN_ON(uuid_parse(CXL_REGION_UUID, &cxl_region_uuid)); + WARN_ON(uuid_parse(CXL_NAMESPACE_UUID, &cxl_namespace_uuid)); + return 0; } diff --git a/drivers/nvdimm/label.h b/drivers/nvdimm/label.h index 0519aacc2926..8ee248fc214f 100644 --- a/drivers/nvdimm/label.h +++ b/drivers/nvdimm/label.h @@ -99,7 +99,7 @@ struct cxl_region_label { }; /** - * struct nd_namespace_label - namespace superblock + * struct nvdimm_efi_label - namespace superblock * @uuid: UUID per RFC 4122 * @name: optional name (NULL-terminated) * @flags: see NSLABEL_FLAG_* @@ -117,7 +117,7 @@ struct cxl_region_label { * @reserved2: reserved * @checksum: fletcher64 sum of this object */ -struct nd_namespace_label { +struct nvdimm_efi_label { u8 uuid[NSLABEL_UUID_LEN]; u8 name[NSLABEL_NAME_LEN]; __le32 flags; @@ -130,7 +130,7 @@ struct nd_namespace_label { __le32 slot; /* * Accessing fields past this point should be gated by a - * namespace_label_has() check. + * efi_namespace_label_has() check. */ u8 align; u8 reserved[3]; @@ -140,11 +140,57 @@ struct nd_namespace_label { __le64 checksum; }; +/** + * struct nvdimm_cxl_label - CXL 2.0 Table 212 + * @type: uuid identifying this label format (namespace) + * @uuid: uuid for the namespace this label describes + * @name: friendly name for the namespace + * @flags: NSLABEL_FLAG_UPDATING (all other flags reserved) + * @nrange: discontiguous namespace support + * @position: this label's position in the set + * @dpa: start address in device-local capacity for this label + * @rawsize: size of this label's contribution to namespace + * @slot: slot id of this label in label area + * @align: alignment in SZ_256M blocks + * @region_uuid: host interleave set identifier + * @abstraction_uuid: personality driver for this namespace + * @lbasize: address geometry for disk-like personalities + * @reserved: reserved + * @checksum: fletcher64 sum of this label + */ +struct nvdimm_cxl_label { + u8 type[NSLABEL_UUID_LEN]; + u8 uuid[NSLABEL_UUID_LEN]; + u8 name[NSLABEL_NAME_LEN]; + __le32 flags; + __le16 nrange; + __le16 position; + __le64 dpa; + __le64 rawsize; + __le32 slot; + __le32 align; + u8 region_uuid[16]; + u8 abstraction_uuid[16]; + __le16 lbasize; + u8 reserved[0x56]; + __le64 checksum; +}; + +struct nd_namespace_label { + union { + struct nvdimm_cxl_label cxl; + struct nvdimm_efi_label efi; + }; +}; + #define NVDIMM_BTT_GUID "8aed63a2-29a2-4c66-8b12-f05d15d3922a" #define NVDIMM_BTT2_GUID "18633bfc-1735-4217-8ac9-17239282d3f8" #define NVDIMM_PFN_GUID "266400ba-fb9f-4677-bcb0-968f11d0d225" #define NVDIMM_DAX_GUID "97a86d9c-3cdd-4eda-986f-5068b4f80088" +#define CXL_REGION_UUID "529d7c61-da07-47c4-a93f-ecdf2c06f444" +#define CXL_NAMESPACE_UUID "68bb2c0a-5a77-4937-9f85-3caf41a0f93c" + /** * struct nd_label_id - identifier string for dpa allocation * @id: "{blk|pmem}-" diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index d57f95a48fe1..6f8ce114032d 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -30,6 +30,7 @@ struct nvdimm_drvdata { int nslabel_size; struct nd_cmd_get_config_size nsarea; void *data; + bool cxl; int ns_current, ns_next; struct resource dpa; struct kref kref; @@ -38,13 +39,17 @@ struct nvdimm_drvdata { static inline const u8 *nsl_ref_name(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label) { - return nd_label->name; + if (ndd->cxl) + return nd_label->cxl.name; + return nd_label->efi.name; } static inline u8 *nsl_get_name(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, u8 *name) { - return memcpy(name, nd_label->name, NSLABEL_NAME_LEN); + if (ndd->cxl) + return memcpy(name, nd_label->cxl.name, NSLABEL_NAME_LEN); + return memcpy(name, nd_label->efi.name, NSLABEL_NAME_LEN); } static inline u8 *nsl_set_name(struct nvdimm_drvdata *ndd, @@ -52,122 +57,168 @@ static inline u8 *nsl_set_name(struct nvdimm_drvdata *ndd, { if (!name) return NULL; - return memcpy(nd_label->name, name, NSLABEL_NAME_LEN); + if (ndd->cxl) + return memcpy(nd_label->cxl.name, name, NSLABEL_NAME_LEN); + return memcpy(nd_label->efi.name, name, NSLABEL_NAME_LEN); } static inline u32 nsl_get_slot(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label) { - return __le32_to_cpu(nd_label->slot); + if (ndd->cxl) + return __le32_to_cpu(nd_label->cxl.slot); + return __le32_to_cpu(nd_label->efi.slot); } static inline void nsl_set_slot(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, u32 slot) { - nd_label->slot = __cpu_to_le32(slot); + if (ndd->cxl) + nd_label->cxl.slot = __cpu_to_le32(slot); + else + nd_label->efi.slot = __cpu_to_le32(slot); } static inline u64 nsl_get_checksum(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label) { - return __le64_to_cpu(nd_label->checksum); + if (ndd->cxl) + return __le64_to_cpu(nd_label->cxl.checksum); + return __le64_to_cpu(nd_label->efi.checksum); } static inline void nsl_set_checksum(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, u64 checksum) { - nd_label->checksum = __cpu_to_le64(checksum); + if (ndd->cxl) + nd_label->cxl.checksum = __cpu_to_le64(checksum); + else + nd_label->efi.checksum = __cpu_to_le64(checksum); } static inline u32 nsl_get_flags(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label) { - return __le32_to_cpu(nd_label->flags); + if (ndd->cxl) + return __le32_to_cpu(nd_label->cxl.flags); + return __le32_to_cpu(nd_label->efi.flags); } static inline void nsl_set_flags(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, u32 flags) { - nd_label->flags = __cpu_to_le32(flags); + if (ndd->cxl) + nd_label->cxl.flags = __cpu_to_le32(flags); + else + nd_label->efi.flags = __cpu_to_le32(flags); } static inline u64 nsl_get_dpa(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label) { - return __le64_to_cpu(nd_label->dpa); + if (ndd->cxl) + return __le64_to_cpu(nd_label->cxl.dpa); + return __le64_to_cpu(nd_label->efi.dpa); } static inline void nsl_set_dpa(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, u64 dpa) { - nd_label->dpa = __cpu_to_le64(dpa); + if (ndd->cxl) + nd_label->cxl.dpa = __cpu_to_le64(dpa); + else + nd_label->efi.dpa = __cpu_to_le64(dpa); } static inline u64 nsl_get_rawsize(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label) { - return __le64_to_cpu(nd_label->rawsize); + if (ndd->cxl) + return __le64_to_cpu(nd_label->cxl.rawsize); + return __le64_to_cpu(nd_label->efi.rawsize); } static inline void nsl_set_rawsize(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, u64 rawsize) { - nd_label->rawsize = __cpu_to_le64(rawsize); + if (ndd->cxl) + nd_label->cxl.rawsize = __cpu_to_le64(rawsize); + else + nd_label->efi.rawsize = __cpu_to_le64(rawsize); } static inline u64 nsl_get_isetcookie(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label) { - return __le64_to_cpu(nd_label->isetcookie); + /* WARN future refactor attempts that break this assumption */ + if (dev_WARN_ONCE(ndd->dev, ndd->cxl, + "CXL labels do not use the isetcookie concept\n")) + return 0; + return __le64_to_cpu(nd_label->efi.isetcookie); } static inline void nsl_set_isetcookie(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, u64 isetcookie) { - nd_label->isetcookie = __cpu_to_le64(isetcookie); + if (!ndd->cxl) + nd_label->efi.isetcookie = __cpu_to_le64(isetcookie); } static inline bool nsl_validate_isetcookie(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, u64 cookie) { - return cookie == __le64_to_cpu(nd_label->isetcookie); + /* + * Let the EFI and CXL validation comingle, where fields that + * don't matter to CXL always validate. + */ + if (ndd->cxl) + return true; + return cookie == __le64_to_cpu(nd_label->efi.isetcookie); } static inline u16 nsl_get_position(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label) { - return __le16_to_cpu(nd_label->position); + if (ndd->cxl) + return __le16_to_cpu(nd_label->cxl.position); + return __le16_to_cpu(nd_label->efi.position); } static inline void nsl_set_position(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, u16 position) { - nd_label->position = __cpu_to_le16(position); + if (ndd->cxl) + nd_label->cxl.position = __cpu_to_le16(position); + else + nd_label->efi.position = __cpu_to_le16(position); } - static inline u16 nsl_get_nlabel(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label) { - return __le16_to_cpu(nd_label->nlabel); + if (ndd->cxl) + return 0; + return __le16_to_cpu(nd_label->efi.nlabel); } static inline void nsl_set_nlabel(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, u16 nlabel) { - nd_label->nlabel = __cpu_to_le16(nlabel); + if (!ndd->cxl) + nd_label->efi.nlabel = __cpu_to_le16(nlabel); } static inline u16 nsl_get_nrange(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label) { - /* EFI labels do not have an nrange field */ + if (ndd->cxl) + return __le16_to_cpu(nd_label->cxl.nrange); return 1; } @@ -175,26 +226,40 @@ static inline void nsl_set_nrange(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, u16 nrange) { + if (ndd->cxl) + nd_label->cxl.nrange = __cpu_to_le16(nrange); } static inline u64 nsl_get_lbasize(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label) { - return __le64_to_cpu(nd_label->lbasize); + /* + * Yes, for some reason the EFI labels convey a massive 64-bit + * lbasize, that got fixed for CXL. + */ + if (ndd->cxl) + return __le16_to_cpu(nd_label->cxl.lbasize); + return __le64_to_cpu(nd_label->efi.lbasize); } static inline void nsl_set_lbasize(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, u64 lbasize) { - nd_label->lbasize = __cpu_to_le64(lbasize); + if (ndd->cxl) + nd_label->cxl.lbasize = __cpu_to_le16(lbasize); + else + nd_label->efi.lbasize = __cpu_to_le64(lbasize); } static inline const uuid_t *nsl_get_uuid(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, uuid_t *uuid) { - import_uuid(uuid, nd_label->uuid); + if (ndd->cxl) + import_uuid(uuid, nd_label->cxl.uuid); + else + import_uuid(uuid, nd_label->efi.uuid); return uuid; } @@ -202,7 +267,10 @@ static inline const uuid_t *nsl_set_uuid(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, const uuid_t *uuid) { - export_uuid(nd_label->uuid, uuid); + if (ndd->cxl) + export_uuid(nd_label->cxl.uuid, uuid); + else + export_uuid(nd_label->efi.uuid, uuid); return uuid; } @@ -212,14 +280,19 @@ static inline bool nsl_uuid_equal(struct nvdimm_drvdata *ndd, { uuid_t tmp; - import_uuid(&tmp, nd_label->uuid); + if (ndd->cxl) + import_uuid(&tmp, nd_label->cxl.uuid); + else + import_uuid(&tmp, nd_label->efi.uuid); return uuid_equal(&tmp, uuid); } static inline const u8 *nsl_uuid_raw(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label) { - return nd_label->uuid; + if (ndd->cxl) + return nd_label->cxl.uuid; + return nd_label->efi.uuid; } bool nsl_validate_blk_isetcookie(struct nvdimm_drvdata *ndd, @@ -278,8 +351,8 @@ static inline struct nd_namespace_index *to_next_namespace_index( unsigned sizeof_namespace_label(struct nvdimm_drvdata *ndd); -#define namespace_label_has(ndd, field) \ - (offsetof(struct nd_namespace_label, field) \ +#define efi_namespace_label_has(ndd, field) \ + (!ndd->cxl && offsetof(struct nvdimm_efi_label, field) \ < sizeof_namespace_label(ndd)) #define nd_dbg_dpa(r, d, res, fmt, arg...) \ @@ -359,6 +432,8 @@ static inline bool nsl_validate_nlabel(struct nd_region *nd_region, struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label) { + if (ndd->cxl) + return true; return nsl_get_nlabel(ndd, nd_label) == nd_region->ndr_mappings; } -- cgit From 99e222a5f1b67dd17c2c780f4eb9a694707d3bf7 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 8 Sep 2021 22:12:09 -0700 Subject: cxl/pci: Make 'struct cxl_mem' device type generic In preparation for adding a unit test provider of a cxl_memdev, convert the 'struct cxl_mem' driver context to carry a generic device rather than a pci device. Note, some dev_dbg() lines needed extra reformatting per clang-format. This conversion also allows the cxl_mem_create() and devm_cxl_add_memdev() calling conventions to be simplified. The "host" for a cxl_memdev, must be the same device for the driver that allocated @cxlm. Acked-by: Ben Widawsky Reviewed-by: Jonathan Cameron Reviewed-by: Ben Widawsky Link: https://lore.kernel.org/r/163116432973.2460985.7553504957932024222.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/cxl/core/memdev.c | 7 ++--- drivers/cxl/cxlmem.h | 6 ++-- drivers/cxl/pci.c | 75 ++++++++++++++++++++++------------------------- 3 files changed, 41 insertions(+), 47 deletions(-) diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c index a9c317e32010..331ef7d6c598 100644 --- a/drivers/cxl/core/memdev.c +++ b/drivers/cxl/core/memdev.c @@ -149,7 +149,6 @@ static void cxl_memdev_unregister(void *_cxlmd) static struct cxl_memdev *cxl_memdev_alloc(struct cxl_mem *cxlm, const struct file_operations *fops) { - struct pci_dev *pdev = cxlm->pdev; struct cxl_memdev *cxlmd; struct device *dev; struct cdev *cdev; @@ -166,7 +165,7 @@ static struct cxl_memdev *cxl_memdev_alloc(struct cxl_mem *cxlm, dev = &cxlmd->dev; device_initialize(dev); - dev->parent = &pdev->dev; + dev->parent = cxlm->dev; dev->bus = &cxl_bus_type; dev->devt = MKDEV(cxl_mem_major, cxlmd->id); dev->type = &cxl_memdev_type; @@ -182,7 +181,7 @@ err: } struct cxl_memdev * -devm_cxl_add_memdev(struct device *host, struct cxl_mem *cxlm, +devm_cxl_add_memdev(struct cxl_mem *cxlm, const struct cdevm_file_operations *cdevm_fops) { struct cxl_memdev *cxlmd; @@ -210,7 +209,7 @@ devm_cxl_add_memdev(struct device *host, struct cxl_mem *cxlm, if (rc) goto err; - rc = devm_add_action_or_reset(host, cxl_memdev_unregister, cxlmd); + rc = devm_add_action_or_reset(cxlm->dev, cxl_memdev_unregister, cxlmd); if (rc) return ERR_PTR(rc); return cxlmd; diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index 6c0b1e2ea97c..d5334df83fb2 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -63,12 +63,12 @@ static inline struct cxl_memdev *to_cxl_memdev(struct device *dev) } struct cxl_memdev * -devm_cxl_add_memdev(struct device *host, struct cxl_mem *cxlm, +devm_cxl_add_memdev(struct cxl_mem *cxlm, const struct cdevm_file_operations *cdevm_fops); /** * struct cxl_mem - A CXL memory device - * @pdev: The PCI device associated with this CXL device. + * @dev: The device associated with this CXL device. * @cxlmd: Logical memory device chardev / interface * @regs: Parsed register blocks * @payload_size: Size of space for payload @@ -82,7 +82,7 @@ devm_cxl_add_memdev(struct device *host, struct cxl_mem *cxlm, * @ram_range: Volatile memory capacity information. */ struct cxl_mem { - struct pci_dev *pdev; + struct device *dev; struct cxl_memdev *cxlmd; struct cxl_regs regs; diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index 8e45aa07d662..c1e1d12e24b6 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -250,7 +250,7 @@ static int cxl_mem_wait_for_doorbell(struct cxl_mem *cxlm) cpu_relax(); } - dev_dbg(&cxlm->pdev->dev, "Doorbell wait took %dms", + dev_dbg(cxlm->dev, "Doorbell wait took %dms", jiffies_to_msecs(end) - jiffies_to_msecs(start)); return 0; } @@ -268,7 +268,7 @@ static bool cxl_is_security_command(u16 opcode) static void cxl_mem_mbox_timeout(struct cxl_mem *cxlm, struct mbox_cmd *mbox_cmd) { - struct device *dev = &cxlm->pdev->dev; + struct device *dev = cxlm->dev; dev_dbg(dev, "Mailbox command (opcode: %#x size: %zub) timed out\n", mbox_cmd->opcode, mbox_cmd->size_in); @@ -300,6 +300,7 @@ static int __cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm, struct mbox_cmd *mbox_cmd) { void __iomem *payload = cxlm->regs.mbox + CXLDEV_MBOX_PAYLOAD_OFFSET; + struct device *dev = cxlm->dev; u64 cmd_reg, status_reg; size_t out_len; int rc; @@ -325,8 +326,7 @@ static int __cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm, /* #1 */ if (cxl_doorbell_busy(cxlm)) { - dev_err_ratelimited(&cxlm->pdev->dev, - "Mailbox re-busy after acquiring\n"); + dev_err_ratelimited(dev, "Mailbox re-busy after acquiring\n"); return -EBUSY; } @@ -345,7 +345,7 @@ static int __cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm, writeq(cmd_reg, cxlm->regs.mbox + CXLDEV_MBOX_CMD_OFFSET); /* #4 */ - dev_dbg(&cxlm->pdev->dev, "Sending command\n"); + dev_dbg(dev, "Sending command\n"); writel(CXLDEV_MBOX_CTRL_DOORBELL, cxlm->regs.mbox + CXLDEV_MBOX_CTRL_OFFSET); @@ -362,7 +362,7 @@ static int __cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm, FIELD_GET(CXLDEV_MBOX_STATUS_RET_CODE_MASK, status_reg); if (mbox_cmd->return_code != 0) { - dev_dbg(&cxlm->pdev->dev, "Mailbox operation had an error\n"); + dev_dbg(dev, "Mailbox operation had an error\n"); return 0; } @@ -399,7 +399,7 @@ static int __cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm, */ static int cxl_mem_mbox_get(struct cxl_mem *cxlm) { - struct device *dev = &cxlm->pdev->dev; + struct device *dev = cxlm->dev; u64 md_status; int rc; @@ -502,7 +502,7 @@ static int handle_mailbox_cmd_from_user(struct cxl_mem *cxlm, u64 in_payload, u64 out_payload, s32 *size_out, u32 *retval) { - struct device *dev = &cxlm->pdev->dev; + struct device *dev = cxlm->dev; struct mbox_cmd mbox_cmd = { .opcode = cmd->opcode, .size_in = cmd->info.size_in, @@ -925,20 +925,19 @@ static int cxl_mem_setup_mailbox(struct cxl_mem *cxlm) */ cxlm->payload_size = min_t(size_t, cxlm->payload_size, SZ_1M); if (cxlm->payload_size < 256) { - dev_err(&cxlm->pdev->dev, "Mailbox is too small (%zub)", + dev_err(cxlm->dev, "Mailbox is too small (%zub)", cxlm->payload_size); return -ENXIO; } - dev_dbg(&cxlm->pdev->dev, "Mailbox payload sized %zu", + dev_dbg(cxlm->dev, "Mailbox payload sized %zu", cxlm->payload_size); return 0; } -static struct cxl_mem *cxl_mem_create(struct pci_dev *pdev) +static struct cxl_mem *cxl_mem_create(struct device *dev) { - struct device *dev = &pdev->dev; struct cxl_mem *cxlm; cxlm = devm_kzalloc(dev, sizeof(*cxlm), GFP_KERNEL); @@ -948,7 +947,7 @@ static struct cxl_mem *cxl_mem_create(struct pci_dev *pdev) } mutex_init(&cxlm->mbox_mutex); - cxlm->pdev = pdev; + cxlm->dev = dev; cxlm->enabled_cmds = devm_kmalloc_array(dev, BITS_TO_LONGS(cxl_cmd_count), sizeof(unsigned long), @@ -964,9 +963,9 @@ static struct cxl_mem *cxl_mem_create(struct pci_dev *pdev) static void __iomem *cxl_mem_map_regblock(struct cxl_mem *cxlm, u8 bar, u64 offset) { - struct pci_dev *pdev = cxlm->pdev; - struct device *dev = &pdev->dev; void __iomem *addr; + struct device *dev = cxlm->dev; + struct pci_dev *pdev = to_pci_dev(dev); /* Basic sanity check that BAR is big enough */ if (pci_resource_len(pdev, bar) < offset) { @@ -989,7 +988,7 @@ static void __iomem *cxl_mem_map_regblock(struct cxl_mem *cxlm, static void cxl_mem_unmap_regblock(struct cxl_mem *cxlm, void __iomem *base) { - pci_iounmap(cxlm->pdev, base); + pci_iounmap(to_pci_dev(cxlm->dev), base); } static int cxl_mem_dvsec(struct pci_dev *pdev, int dvsec) @@ -1018,10 +1017,9 @@ static int cxl_mem_dvsec(struct pci_dev *pdev, int dvsec) static int cxl_probe_regs(struct cxl_mem *cxlm, void __iomem *base, struct cxl_register_map *map) { - struct pci_dev *pdev = cxlm->pdev; - struct device *dev = &pdev->dev; struct cxl_component_reg_map *comp_map; struct cxl_device_reg_map *dev_map; + struct device *dev = cxlm->dev; switch (map->reg_type) { case CXL_REGLOC_RBI_COMPONENT: @@ -1057,8 +1055,8 @@ static int cxl_probe_regs(struct cxl_mem *cxlm, void __iomem *base, static int cxl_map_regs(struct cxl_mem *cxlm, struct cxl_register_map *map) { - struct pci_dev *pdev = cxlm->pdev; - struct device *dev = &pdev->dev; + struct device *dev = cxlm->dev; + struct pci_dev *pdev = to_pci_dev(dev); switch (map->reg_type) { case CXL_REGLOC_RBI_COMPONENT: @@ -1096,13 +1094,12 @@ static void cxl_decode_register_block(u32 reg_lo, u32 reg_hi, */ static int cxl_mem_setup_regs(struct cxl_mem *cxlm) { - struct pci_dev *pdev = cxlm->pdev; - struct device *dev = &pdev->dev; - u32 regloc_size, regblocks; void __iomem *base; - int regloc, i, n_maps; + u32 regloc_size, regblocks; + int regloc, i, n_maps, ret = 0; + struct device *dev = cxlm->dev; + struct pci_dev *pdev = to_pci_dev(dev); struct cxl_register_map *map, maps[CXL_REGLOC_RBI_TYPES]; - int ret = 0; regloc = cxl_mem_dvsec(pdev, PCI_DVSEC_ID_CXL_REGLOC_DVSEC_ID); if (!regloc) { @@ -1226,7 +1223,7 @@ static void cxl_walk_cel(struct cxl_mem *cxlm, size_t size, u8 *cel) struct cxl_mem_command *cmd = cxl_mem_find_command(opcode); if (!cmd) { - dev_dbg(&cxlm->pdev->dev, + dev_dbg(cxlm->dev, "Opcode 0x%04x unsupported by driver", opcode); continue; } @@ -1323,7 +1320,7 @@ static int cxl_mem_get_partition_info(struct cxl_mem *cxlm, static int cxl_mem_enumerate_cmds(struct cxl_mem *cxlm) { struct cxl_mbox_get_supported_logs *gsl; - struct device *dev = &cxlm->pdev->dev; + struct device *dev = cxlm->dev; struct cxl_mem_command *cmd; int i, rc; @@ -1418,15 +1415,14 @@ static int cxl_mem_identify(struct cxl_mem *cxlm) cxlm->partition_align_bytes = le64_to_cpu(id.partition_align); cxlm->partition_align_bytes *= CXL_CAPACITY_MULTIPLIER; - dev_dbg(&cxlm->pdev->dev, "Identify Memory Device\n" + dev_dbg(cxlm->dev, + "Identify Memory Device\n" " total_bytes = %#llx\n" " volatile_only_bytes = %#llx\n" " persistent_only_bytes = %#llx\n" " partition_align_bytes = %#llx\n", - cxlm->total_bytes, - cxlm->volatile_only_bytes, - cxlm->persistent_only_bytes, - cxlm->partition_align_bytes); + cxlm->total_bytes, cxlm->volatile_only_bytes, + cxlm->persistent_only_bytes, cxlm->partition_align_bytes); cxlm->lsa_size = le32_to_cpu(id.lsa_size); memcpy(cxlm->firmware_version, id.fw_revision, sizeof(id.fw_revision)); @@ -1453,19 +1449,18 @@ static int cxl_mem_create_range_info(struct cxl_mem *cxlm) &cxlm->next_volatile_bytes, &cxlm->next_persistent_bytes); if (rc < 0) { - dev_err(&cxlm->pdev->dev, "Failed to query partition information\n"); + dev_err(cxlm->dev, "Failed to query partition information\n"); return rc; } - dev_dbg(&cxlm->pdev->dev, "Get Partition Info\n" + dev_dbg(cxlm->dev, + "Get Partition Info\n" " active_volatile_bytes = %#llx\n" " active_persistent_bytes = %#llx\n" " next_volatile_bytes = %#llx\n" " next_persistent_bytes = %#llx\n", - cxlm->active_volatile_bytes, - cxlm->active_persistent_bytes, - cxlm->next_volatile_bytes, - cxlm->next_persistent_bytes); + cxlm->active_volatile_bytes, cxlm->active_persistent_bytes, + cxlm->next_volatile_bytes, cxlm->next_persistent_bytes); cxlm->ram_range.start = 0; cxlm->ram_range.end = cxlm->active_volatile_bytes - 1; @@ -1487,7 +1482,7 @@ static int cxl_mem_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (rc) return rc; - cxlm = cxl_mem_create(pdev); + cxlm = cxl_mem_create(&pdev->dev); if (IS_ERR(cxlm)) return PTR_ERR(cxlm); @@ -1511,7 +1506,7 @@ static int cxl_mem_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (rc) return rc; - cxlmd = devm_cxl_add_memdev(&pdev->dev, cxlm, &cxl_memdev_fops); + cxlmd = devm_cxl_add_memdev(cxlm, &cxl_memdev_fops); if (IS_ERR(cxlmd)) return PTR_ERR(cxlmd); -- cgit From 13e7749d06b335774bbb341c65a0232484beb457 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 13 Sep 2021 15:24:32 -0700 Subject: cxl/pci: Clean up cxl_mem_get_partition_info() Commit 0b9159d0ff21 ("cxl/pci: Store memory capacity values") missed updating the kernel-doc for 'struct cxl_mem' leading to the following warnings: ./scripts/kernel-doc -v drivers/cxl/cxlmem.h 2>&1 | grep warn drivers/cxl/cxlmem.h:107: warning: Function parameter or member 'total_bytes' not described in 'cxl_mem' drivers/cxl/cxlmem.h:107: warning: Function parameter or member 'volatile_only_bytes' not described in 'cxl_mem' drivers/cxl/cxlmem.h:107: warning: Function parameter or member 'persistent_only_bytes' not described in 'cxl_mem' drivers/cxl/cxlmem.h:107: warning: Function parameter or member 'partition_align_bytes' not described in 'cxl_mem' drivers/cxl/cxlmem.h:107: warning: Function parameter or member 'active_volatile_bytes' not described in 'cxl_mem' drivers/cxl/cxlmem.h:107: warning: Function parameter or member 'active_persistent_bytes' not described in 'cxl_mem' drivers/cxl/cxlmem.h:107: warning: Function parameter or member 'next_volatile_bytes' not described in 'cxl_mem' drivers/cxl/cxlmem.h:107: warning: Function parameter or member 'next_persistent_bytes' not described in 'cxl_mem' Also, it is redundant to describe those same parameters in the kernel-doc for cxl_mem_get_partition_info(). Given the only user of that routine updates the values in @cxlm, just do that implicitly internal to the helper. Cc: Ira Weiny Reported-by: Ben Widawsky Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/163157174216.2653013.1277706528753990974.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/cxl/cxlmem.h | 15 +++++++++++++-- drivers/cxl/pci.c | 35 +++++++++++------------------------ 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index d5334df83fb2..e14bcd7a1ba1 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -78,8 +78,19 @@ devm_cxl_add_memdev(struct cxl_mem *cxlm, * @mbox_mutex: Mutex to synchronize mailbox access. * @firmware_version: Firmware version for the memory device. * @enabled_cmds: Hardware commands found enabled in CEL. - * @pmem_range: Persistent memory capacity information. - * @ram_range: Volatile memory capacity information. + * @pmem_range: Active Persistent memory capacity configuration + * @ram_range: Active Volatile memory capacity configuration + * @total_bytes: sum of all possible capacities + * @volatile_only_bytes: hard volatile capacity + * @persistent_only_bytes: hard persistent capacity + * @partition_align_bytes: alignment size for partition-able capacity + * @active_volatile_bytes: sum of hard + soft volatile + * @active_persistent_bytes: sum of hard + soft persistent + * @next_volatile_bytes: volatile capacity change pending device reset + * @next_persistent_bytes: persistent capacity change pending device reset + * + * See section 8.2.9.5.2 Capacity Configuration and Label Storage for + * details on capacity parameters. */ struct cxl_mem { struct device *dev; diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index c1e1d12e24b6..8077d907e7d3 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -1262,11 +1262,7 @@ static struct cxl_mbox_get_supported_logs *cxl_get_gsl(struct cxl_mem *cxlm) /** * cxl_mem_get_partition_info - Get partition info - * @cxlm: The device to act on - * @active_volatile_bytes: returned active volatile capacity - * @active_persistent_bytes: returned active persistent capacity - * @next_volatile_bytes: return next volatile capacity - * @next_persistent_bytes: return next persistent capacity + * @cxlm: cxl_mem instance to update partition info * * Retrieve the current partition info for the device specified. If not 0, the * 'next' values are pending and take affect on next cold reset. @@ -1275,11 +1271,7 @@ static struct cxl_mbox_get_supported_logs *cxl_get_gsl(struct cxl_mem *cxlm) * * See CXL @8.2.9.5.2.1 Get Partition Info */ -static int cxl_mem_get_partition_info(struct cxl_mem *cxlm, - u64 *active_volatile_bytes, - u64 *active_persistent_bytes, - u64 *next_volatile_bytes, - u64 *next_persistent_bytes) +static int cxl_mem_get_partition_info(struct cxl_mem *cxlm) { struct cxl_mbox_get_partition_info { __le64 active_volatile_cap; @@ -1294,15 +1286,14 @@ static int cxl_mem_get_partition_info(struct cxl_mem *cxlm, if (rc) return rc; - *active_volatile_bytes = le64_to_cpu(pi.active_volatile_cap); - *active_persistent_bytes = le64_to_cpu(pi.active_persistent_cap); - *next_volatile_bytes = le64_to_cpu(pi.next_volatile_cap); - *next_persistent_bytes = le64_to_cpu(pi.next_volatile_cap); - - *active_volatile_bytes *= CXL_CAPACITY_MULTIPLIER; - *active_persistent_bytes *= CXL_CAPACITY_MULTIPLIER; - *next_volatile_bytes *= CXL_CAPACITY_MULTIPLIER; - *next_persistent_bytes *= CXL_CAPACITY_MULTIPLIER; + cxlm->active_volatile_bytes = + le64_to_cpu(pi.active_volatile_cap) * CXL_CAPACITY_MULTIPLIER; + cxlm->active_persistent_bytes = + le64_to_cpu(pi.active_persistent_cap) * CXL_CAPACITY_MULTIPLIER; + cxlm->next_volatile_bytes = + le64_to_cpu(pi.next_volatile_cap) * CXL_CAPACITY_MULTIPLIER; + cxlm->next_persistent_bytes = + le64_to_cpu(pi.next_volatile_cap) * CXL_CAPACITY_MULTIPLIER; return 0; } @@ -1443,11 +1434,7 @@ static int cxl_mem_create_range_info(struct cxl_mem *cxlm) return 0; } - rc = cxl_mem_get_partition_info(cxlm, - &cxlm->active_volatile_bytes, - &cxlm->active_persistent_bytes, - &cxlm->next_volatile_bytes, - &cxlm->next_persistent_bytes); + rc = cxl_mem_get_partition_info(cxlm); if (rc < 0) { dev_err(cxlm->dev, "Failed to query partition information\n"); return rc; -- cgit From b64955a92929346f16df058ad2bb53630eb80466 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 8 Sep 2021 22:12:21 -0700 Subject: cxl/mbox: Introduce the mbox_send operation In preparation for implementing a unit test backend transport for ioctl operations, and making the mailbox available to the cxl/pmem infrastructure, move the existing PCI specific portion of mailbox handling to an "mbox_send" operation. With this split all the PCI-specific transport details are comprehended by a single operation and the rest of the mailbox infrastructure is 'struct cxl_mem' and 'struct cxl_memdev' generic. Acked-by: Ben Widawsky Reviewed-by: Jonathan Cameron Reviewed-by: Ben Widawsky Link: https://lore.kernel.org/r/163116434098.2460985.9004760022659400540.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/cxl/cxlmem.h | 42 +++++++++++++++++++++++++++++ drivers/cxl/pci.c | 76 +++++++++++++++------------------------------------- 2 files changed, 63 insertions(+), 55 deletions(-) diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index e14bcd7a1ba1..c142532db8cb 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -66,6 +66,45 @@ struct cxl_memdev * devm_cxl_add_memdev(struct cxl_mem *cxlm, const struct cdevm_file_operations *cdevm_fops); +/** + * struct cxl_mbox_cmd - A command to be submitted to hardware. + * @opcode: (input) The command set and command submitted to hardware. + * @payload_in: (input) Pointer to the input payload. + * @payload_out: (output) Pointer to the output payload. Must be allocated by + * the caller. + * @size_in: (input) Number of bytes to load from @payload_in. + * @size_out: (input) Max number of bytes loaded into @payload_out. + * (output) Number of bytes generated by the device. For fixed size + * outputs commands this is always expected to be deterministic. For + * variable sized output commands, it tells the exact number of bytes + * written. + * @return_code: (output) Error code returned from hardware. + * + * This is the primary mechanism used to send commands to the hardware. + * All the fields except @payload_* correspond exactly to the fields described in + * Command Register section of the CXL 2.0 8.2.8.4.5. @payload_in and + * @payload_out are written to, and read from the Command Payload Registers + * defined in CXL 2.0 8.2.8.4.8. + */ +struct cxl_mbox_cmd { + u16 opcode; + void *payload_in; + void *payload_out; + size_t size_in; + size_t size_out; + u16 return_code; +#define CXL_MBOX_SUCCESS 0 +}; + +/* + * CXL 2.0 - Memory capacity multiplier + * See Section 8.2.9.5 + * + * Volatile, Persistent, and Partition capacities are specified to be in + * multiples of 256MB - define a multiplier to convert to/from bytes. + */ +#define CXL_CAPACITY_MULTIPLIER SZ_256M + /** * struct cxl_mem - A CXL memory device * @dev: The device associated with this CXL device. @@ -88,6 +127,7 @@ devm_cxl_add_memdev(struct cxl_mem *cxlm, * @active_persistent_bytes: sum of hard + soft persistent * @next_volatile_bytes: volatile capacity change pending device reset * @next_persistent_bytes: persistent capacity change pending device reset + * @mbox_send: @dev specific transport for transmitting mailbox commands * * See section 8.2.9.5.2 Capacity Configuration and Label Storage for * details on capacity parameters. @@ -115,5 +155,7 @@ struct cxl_mem { u64 active_persistent_bytes; u64 next_volatile_bytes; u64 next_persistent_bytes; + + int (*mbox_send)(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd); }; #endif /* __CXL_MEM_H__ */ diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index 8077d907e7d3..e2f27671c6b2 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -64,45 +64,6 @@ enum opcode { CXL_MBOX_OP_MAX = 0x10000 }; -/* - * CXL 2.0 - Memory capacity multiplier - * See Section 8.2.9.5 - * - * Volatile, Persistent, and Partition capacities are specified to be in - * multiples of 256MB - define a multiplier to convert to/from bytes. - */ -#define CXL_CAPACITY_MULTIPLIER SZ_256M - -/** - * struct mbox_cmd - A command to be submitted to hardware. - * @opcode: (input) The command set and command submitted to hardware. - * @payload_in: (input) Pointer to the input payload. - * @payload_out: (output) Pointer to the output payload. Must be allocated by - * the caller. - * @size_in: (input) Number of bytes to load from @payload_in. - * @size_out: (input) Max number of bytes loaded into @payload_out. - * (output) Number of bytes generated by the device. For fixed size - * outputs commands this is always expected to be deterministic. For - * variable sized output commands, it tells the exact number of bytes - * written. - * @return_code: (output) Error code returned from hardware. - * - * This is the primary mechanism used to send commands to the hardware. - * All the fields except @payload_* correspond exactly to the fields described in - * Command Register section of the CXL 2.0 8.2.8.4.5. @payload_in and - * @payload_out are written to, and read from the Command Payload Registers - * defined in CXL 2.0 8.2.8.4.8. - */ -struct mbox_cmd { - u16 opcode; - void *payload_in; - void *payload_out; - size_t size_in; - size_t size_out; - u16 return_code; -#define CXL_MBOX_SUCCESS 0 -}; - static DECLARE_RWSEM(cxl_memdev_rwsem); static struct dentry *cxl_debugfs; static bool cxl_raw_allow_all; @@ -266,7 +227,7 @@ static bool cxl_is_security_command(u16 opcode) } static void cxl_mem_mbox_timeout(struct cxl_mem *cxlm, - struct mbox_cmd *mbox_cmd) + struct cxl_mbox_cmd *mbox_cmd) { struct device *dev = cxlm->dev; @@ -297,7 +258,7 @@ static void cxl_mem_mbox_timeout(struct cxl_mem *cxlm, * mailbox. */ static int __cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm, - struct mbox_cmd *mbox_cmd) + struct cxl_mbox_cmd *mbox_cmd) { void __iomem *payload = cxlm->regs.mbox + CXLDEV_MBOX_PAYLOAD_OFFSET; struct device *dev = cxlm->dev; @@ -472,6 +433,20 @@ static void cxl_mem_mbox_put(struct cxl_mem *cxlm) mutex_unlock(&cxlm->mbox_mutex); } +static int cxl_pci_mbox_send(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) +{ + int rc; + + rc = cxl_mem_mbox_get(cxlm); + if (rc) + return rc; + + rc = __cxl_mem_mbox_send_cmd(cxlm, cmd); + cxl_mem_mbox_put(cxlm); + + return rc; +} + /** * handle_mailbox_cmd_from_user() - Dispatch a mailbox command for userspace. * @cxlm: The CXL memory device to communicate with. @@ -503,7 +478,7 @@ static int handle_mailbox_cmd_from_user(struct cxl_mem *cxlm, s32 *size_out, u32 *retval) { struct device *dev = cxlm->dev; - struct mbox_cmd mbox_cmd = { + struct cxl_mbox_cmd mbox_cmd = { .opcode = cmd->opcode, .size_in = cmd->info.size_in, .size_out = cmd->info.size_out, @@ -525,10 +500,6 @@ static int handle_mailbox_cmd_from_user(struct cxl_mem *cxlm, } } - rc = cxl_mem_mbox_get(cxlm); - if (rc) - goto out; - dev_dbg(dev, "Submitting %s command for user\n" "\topcode: %x\n" @@ -539,8 +510,7 @@ static int handle_mailbox_cmd_from_user(struct cxl_mem *cxlm, dev_WARN_ONCE(dev, cmd->info.id == CXL_MEM_COMMAND_ID_RAW, "raw command path used\n"); - rc = __cxl_mem_mbox_send_cmd(cxlm, &mbox_cmd); - cxl_mem_mbox_put(cxlm); + rc = cxlm->mbox_send(cxlm, &mbox_cmd); if (rc) goto out; @@ -874,7 +844,7 @@ static int cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm, u16 opcode, void *out, size_t out_size) { const struct cxl_mem_command *cmd = cxl_mem_find_command(opcode); - struct mbox_cmd mbox_cmd = { + struct cxl_mbox_cmd mbox_cmd = { .opcode = opcode, .payload_in = in, .size_in = in_size, @@ -886,12 +856,7 @@ static int cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm, u16 opcode, if (out_size > cxlm->payload_size) return -E2BIG; - rc = cxl_mem_mbox_get(cxlm); - if (rc) - return rc; - - rc = __cxl_mem_mbox_send_cmd(cxlm, &mbox_cmd); - cxl_mem_mbox_put(cxlm); + rc = cxlm->mbox_send(cxlm, &mbox_cmd); if (rc) return rc; @@ -913,6 +878,7 @@ static int cxl_mem_setup_mailbox(struct cxl_mem *cxlm) { const int cap = readl(cxlm->regs.mbox + CXLDEV_MBOX_CAPS_OFFSET); + cxlm->mbox_send = cxl_pci_mbox_send; cxlm->payload_size = 1 << FIELD_GET(CXLDEV_MBOX_CAP_PAYLOAD_SIZE_MASK, cap); -- cgit From 4cb35f1ca05a42acbc4a3c8cf7de1029a06558d0 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 8 Sep 2021 22:12:26 -0700 Subject: cxl/pci: Drop idr.h Commit 3d135db51024 ("cxl/core: Move memdev management to core") left this straggling include for cxl_memdev setup. Clean it up. Cc: Ben Widawsky Reported-by: Jonathan Cameron Reviewed-by: Jonathan Cameron Reviewed-by: Ben Widawsky Link: https://lore.kernel.org/r/163116434668.2460985.12264757586266849616.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/cxl/pci.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index e2f27671c6b2..9d8050fdd69c 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include -- cgit From 4faf31b43468c58e2c8c91cc5fa26f08a6b733be Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 8 Sep 2021 22:12:32 -0700 Subject: cxl/mbox: Move mailbox and other non-PCI specific infrastructure to the core Now that the internals of mailbox operations are abstracted from the PCI specifics a bulk of infrastructure can move to the core. The CXL_PMEM driver intends to proxy LIBNVDIMM UAPI and driver requests to the equivalent functionality provided by the CXL hardware mailbox interface. In support of that intent move the mailbox implementation to a shared location for the CXL_PCI driver native IOCTL path and CXL_PMEM nvdimm command proxy path to share. A unit test framework seeks to implement a unit test backend transport for mailbox commands to communicate mocked up payloads. It can reuse all of the mailbox infrastructure minus the PCI specifics, so that also gets moved to the core. Finally with the mailbox infrastructure and ioctl handling being transport generic there is no longer any need to pass file file_operations to devm_cxl_add_memdev(). That allows all the ioctl boilerplate to move into the core for unit test reuse. No functional change intended, just code movement. Acked-by: Ben Widawsky Reported-by: kernel test robot Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/163116435233.2460985.16197340449713287180.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- Documentation/driver-api/cxl/memory-devices.rst | 3 + drivers/cxl/core/Makefile | 1 + drivers/cxl/core/bus.c | 4 + drivers/cxl/core/core.h | 8 + drivers/cxl/core/mbox.c | 825 +++++++++++++++++++++ drivers/cxl/core/memdev.c | 81 ++- drivers/cxl/cxlmem.h | 78 +- drivers/cxl/pci.c | 924 +----------------------- 8 files changed, 975 insertions(+), 949 deletions(-) create mode 100644 drivers/cxl/core/mbox.c diff --git a/Documentation/driver-api/cxl/memory-devices.rst b/Documentation/driver-api/cxl/memory-devices.rst index 50ebcda17ad0..4624951b5c38 100644 --- a/Documentation/driver-api/cxl/memory-devices.rst +++ b/Documentation/driver-api/cxl/memory-devices.rst @@ -45,6 +45,9 @@ CXL Core .. kernel-doc:: drivers/cxl/core/regs.c :doc: cxl registers +.. kernel-doc:: drivers/cxl/core/mbox.c + :doc: cxl mbox + External Interfaces =================== diff --git a/drivers/cxl/core/Makefile b/drivers/cxl/core/Makefile index 0fdbf3c6ac1a..07eb8e1fb8a6 100644 --- a/drivers/cxl/core/Makefile +++ b/drivers/cxl/core/Makefile @@ -6,3 +6,4 @@ cxl_core-y := bus.o cxl_core-y += pmem.o cxl_core-y += regs.o cxl_core-y += memdev.o +cxl_core-y += mbox.o diff --git a/drivers/cxl/core/bus.c b/drivers/cxl/core/bus.c index 267d8042bec2..9a8fa88b634c 100644 --- a/drivers/cxl/core/bus.c +++ b/drivers/cxl/core/bus.c @@ -635,6 +635,8 @@ static __init int cxl_core_init(void) { int rc; + cxl_mbox_init(); + rc = cxl_memdev_init(); if (rc) return rc; @@ -646,6 +648,7 @@ static __init int cxl_core_init(void) err: cxl_memdev_exit(); + cxl_mbox_exit(); return rc; } @@ -653,6 +656,7 @@ static void cxl_core_exit(void) { bus_unregister(&cxl_bus_type); cxl_memdev_exit(); + cxl_mbox_exit(); } module_init(cxl_core_init); diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h index 036a3c8106b4..c85b7fbad02d 100644 --- a/drivers/cxl/core/core.h +++ b/drivers/cxl/core/core.h @@ -14,7 +14,15 @@ static inline void unregister_cxl_dev(void *dev) device_unregister(dev); } +struct cxl_send_command; +struct cxl_mem_query_commands; +int cxl_query_cmd(struct cxl_memdev *cxlmd, + struct cxl_mem_query_commands __user *q); +int cxl_send_cmd(struct cxl_memdev *cxlmd, struct cxl_send_command __user *s); + int cxl_memdev_init(void); void cxl_memdev_exit(void); +void cxl_mbox_init(void); +void cxl_mbox_exit(void); #endif /* __CXL_CORE_H__ */ diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c new file mode 100644 index 000000000000..31e183991726 --- /dev/null +++ b/drivers/cxl/core/mbox.c @@ -0,0 +1,825 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2020 Intel Corporation. All rights reserved. */ +#include +#include +#include +#include +#include +#include + +#include "core.h" + +static bool cxl_raw_allow_all; + +/** + * DOC: cxl mbox + * + * Core implementation of the CXL 2.0 Type-3 Memory Device Mailbox. The + * implementation is used by the cxl_pci driver to initialize the device + * and implement the cxl_mem.h IOCTL UAPI. It also implements the + * backend of the cxl_pmem_ctl() transport for LIBNVDIMM. + */ + +#define cxl_for_each_cmd(cmd) \ + for ((cmd) = &cxl_mem_commands[0]; \ + ((cmd) - cxl_mem_commands) < ARRAY_SIZE(cxl_mem_commands); (cmd)++) + +#define CXL_CMD(_id, sin, sout, _flags) \ + [CXL_MEM_COMMAND_ID_##_id] = { \ + .info = { \ + .id = CXL_MEM_COMMAND_ID_##_id, \ + .size_in = sin, \ + .size_out = sout, \ + }, \ + .opcode = CXL_MBOX_OP_##_id, \ + .flags = _flags, \ + } + +/* + * This table defines the supported mailbox commands for the driver. This table + * is made up of a UAPI structure. Non-negative values as parameters in the + * table will be validated against the user's input. For example, if size_in is + * 0, and the user passed in 1, it is an error. + */ +static struct cxl_mem_command cxl_mem_commands[CXL_MEM_COMMAND_ID_MAX] = { + CXL_CMD(IDENTIFY, 0, 0x43, CXL_CMD_FLAG_FORCE_ENABLE), +#ifdef CONFIG_CXL_MEM_RAW_COMMANDS + CXL_CMD(RAW, ~0, ~0, 0), +#endif + CXL_CMD(GET_SUPPORTED_LOGS, 0, ~0, CXL_CMD_FLAG_FORCE_ENABLE), + CXL_CMD(GET_FW_INFO, 0, 0x50, 0), + CXL_CMD(GET_PARTITION_INFO, 0, 0x20, 0), + CXL_CMD(GET_LSA, 0x8, ~0, 0), + CXL_CMD(GET_HEALTH_INFO, 0, 0x12, 0), + CXL_CMD(GET_LOG, 0x18, ~0, CXL_CMD_FLAG_FORCE_ENABLE), + CXL_CMD(SET_PARTITION_INFO, 0x0a, 0, 0), + CXL_CMD(SET_LSA, ~0, 0, 0), + CXL_CMD(GET_ALERT_CONFIG, 0, 0x10, 0), + CXL_CMD(SET_ALERT_CONFIG, 0xc, 0, 0), + CXL_CMD(GET_SHUTDOWN_STATE, 0, 0x1, 0), + CXL_CMD(SET_SHUTDOWN_STATE, 0x1, 0, 0), + CXL_CMD(GET_POISON, 0x10, ~0, 0), + CXL_CMD(INJECT_POISON, 0x8, 0, 0), + CXL_CMD(CLEAR_POISON, 0x48, 0, 0), + CXL_CMD(GET_SCAN_MEDIA_CAPS, 0x10, 0x4, 0), + CXL_CMD(SCAN_MEDIA, 0x11, 0, 0), + CXL_CMD(GET_SCAN_MEDIA, 0, ~0, 0), +}; + +/* + * Commands that RAW doesn't permit. The rationale for each: + * + * CXL_MBOX_OP_ACTIVATE_FW: Firmware activation requires adjustment / + * coordination of transaction timeout values at the root bridge level. + * + * CXL_MBOX_OP_SET_PARTITION_INFO: The device memory map may change live + * and needs to be coordinated with HDM updates. + * + * CXL_MBOX_OP_SET_LSA: The label storage area may be cached by the + * driver and any writes from userspace invalidates those contents. + * + * CXL_MBOX_OP_SET_SHUTDOWN_STATE: Set shutdown state assumes no writes + * to the device after it is marked clean, userspace can not make that + * assertion. + * + * CXL_MBOX_OP_[GET_]SCAN_MEDIA: The kernel provides a native error list that + * is kept up to date with patrol notifications and error management. + */ +static u16 cxl_disabled_raw_commands[] = { + CXL_MBOX_OP_ACTIVATE_FW, + CXL_MBOX_OP_SET_PARTITION_INFO, + CXL_MBOX_OP_SET_LSA, + CXL_MBOX_OP_SET_SHUTDOWN_STATE, + CXL_MBOX_OP_SCAN_MEDIA, + CXL_MBOX_OP_GET_SCAN_MEDIA, +}; + +/* + * Command sets that RAW doesn't permit. All opcodes in this set are + * disabled because they pass plain text security payloads over the + * user/kernel boundary. This functionality is intended to be wrapped + * behind the keys ABI which allows for encrypted payloads in the UAPI + */ +static u8 security_command_sets[] = { + 0x44, /* Sanitize */ + 0x45, /* Persistent Memory Data-at-rest Security */ + 0x46, /* Security Passthrough */ +}; + +static bool cxl_is_security_command(u16 opcode) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(security_command_sets); i++) + if (security_command_sets[i] == (opcode >> 8)) + return true; + return false; +} + +static struct cxl_mem_command *cxl_mem_find_command(u16 opcode) +{ + struct cxl_mem_command *c; + + cxl_for_each_cmd(c) + if (c->opcode == opcode) + return c; + + return NULL; +} + +/** + * cxl_mem_mbox_send_cmd() - Send a mailbox command to a memory device. + * @cxlm: The CXL memory device to communicate with. + * @opcode: Opcode for the mailbox command. + * @in: The input payload for the mailbox command. + * @in_size: The length of the input payload + * @out: Caller allocated buffer for the output. + * @out_size: Expected size of output. + * + * Context: Any context. Will acquire and release mbox_mutex. + * Return: + * * %>=0 - Number of bytes returned in @out. + * * %-E2BIG - Payload is too large for hardware. + * * %-EBUSY - Couldn't acquire exclusive mailbox access. + * * %-EFAULT - Hardware error occurred. + * * %-ENXIO - Command completed, but device reported an error. + * * %-EIO - Unexpected output size. + * + * Mailbox commands may execute successfully yet the device itself reported an + * error. While this distinction can be useful for commands from userspace, the + * kernel will only be able to use results when both are successful. + * + * See __cxl_mem_mbox_send_cmd() + */ +int cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm, u16 opcode, void *in, + size_t in_size, void *out, size_t out_size) +{ + const struct cxl_mem_command *cmd = cxl_mem_find_command(opcode); + struct cxl_mbox_cmd mbox_cmd = { + .opcode = opcode, + .payload_in = in, + .size_in = in_size, + .size_out = out_size, + .payload_out = out, + }; + int rc; + + if (out_size > cxlm->payload_size) + return -E2BIG; + + rc = cxlm->mbox_send(cxlm, &mbox_cmd); + if (rc) + return rc; + + /* TODO: Map return code to proper kernel style errno */ + if (mbox_cmd.return_code != CXL_MBOX_SUCCESS) + return -ENXIO; + + /* + * Variable sized commands can't be validated and so it's up to the + * caller to do that if they wish. + */ + if (cmd->info.size_out >= 0 && mbox_cmd.size_out != out_size) + return -EIO; + + return 0; +} +EXPORT_SYMBOL_GPL(cxl_mem_mbox_send_cmd); + +static bool cxl_mem_raw_command_allowed(u16 opcode) +{ + int i; + + if (!IS_ENABLED(CONFIG_CXL_MEM_RAW_COMMANDS)) + return false; + + if (security_locked_down(LOCKDOWN_PCI_ACCESS)) + return false; + + if (cxl_raw_allow_all) + return true; + + if (cxl_is_security_command(opcode)) + return false; + + for (i = 0; i < ARRAY_SIZE(cxl_disabled_raw_commands); i++) + if (cxl_disabled_raw_commands[i] == opcode) + return false; + + return true; +} + +/** + * cxl_validate_cmd_from_user() - Check fields for CXL_MEM_SEND_COMMAND. + * @cxlm: &struct cxl_mem device whose mailbox will be used. + * @send_cmd: &struct cxl_send_command copied in from userspace. + * @out_cmd: Sanitized and populated &struct cxl_mem_command. + * + * Return: + * * %0 - @out_cmd is ready to send. + * * %-ENOTTY - Invalid command specified. + * * %-EINVAL - Reserved fields or invalid values were used. + * * %-ENOMEM - Input or output buffer wasn't sized properly. + * * %-EPERM - Attempted to use a protected command. + * + * The result of this command is a fully validated command in @out_cmd that is + * safe to send to the hardware. + * + * See handle_mailbox_cmd_from_user() + */ +static int cxl_validate_cmd_from_user(struct cxl_mem *cxlm, + const struct cxl_send_command *send_cmd, + struct cxl_mem_command *out_cmd) +{ + const struct cxl_command_info *info; + struct cxl_mem_command *c; + + if (send_cmd->id == 0 || send_cmd->id >= CXL_MEM_COMMAND_ID_MAX) + return -ENOTTY; + + /* + * The user can never specify an input payload larger than what hardware + * supports, but output can be arbitrarily large (simply write out as + * much data as the hardware provides). + */ + if (send_cmd->in.size > cxlm->payload_size) + return -EINVAL; + + /* + * Checks are bypassed for raw commands but a WARN/taint will occur + * later in the callchain + */ + if (send_cmd->id == CXL_MEM_COMMAND_ID_RAW) { + const struct cxl_mem_command temp = { + .info = { + .id = CXL_MEM_COMMAND_ID_RAW, + .flags = 0, + .size_in = send_cmd->in.size, + .size_out = send_cmd->out.size, + }, + .opcode = send_cmd->raw.opcode + }; + + if (send_cmd->raw.rsvd) + return -EINVAL; + + /* + * Unlike supported commands, the output size of RAW commands + * gets passed along without further checking, so it must be + * validated here. + */ + if (send_cmd->out.size > cxlm->payload_size) + return -EINVAL; + + if (!cxl_mem_raw_command_allowed(send_cmd->raw.opcode)) + return -EPERM; + + memcpy(out_cmd, &temp, sizeof(temp)); + + return 0; + } + + if (send_cmd->flags & ~CXL_MEM_COMMAND_FLAG_MASK) + return -EINVAL; + + if (send_cmd->rsvd) + return -EINVAL; + + if (send_cmd->in.rsvd || send_cmd->out.rsvd) + return -EINVAL; + + /* Convert user's command into the internal representation */ + c = &cxl_mem_commands[send_cmd->id]; + info = &c->info; + + /* Check that the command is enabled for hardware */ + if (!test_bit(info->id, cxlm->enabled_cmds)) + return -ENOTTY; + + /* Check the input buffer is the expected size */ + if (info->size_in >= 0 && info->size_in != send_cmd->in.size) + return -ENOMEM; + + /* Check the output buffer is at least large enough */ + if (info->size_out >= 0 && send_cmd->out.size < info->size_out) + return -ENOMEM; + + memcpy(out_cmd, c, sizeof(*c)); + out_cmd->info.size_in = send_cmd->in.size; + /* + * XXX: out_cmd->info.size_out will be controlled by the driver, and the + * specified number of bytes @send_cmd->out.size will be copied back out + * to userspace. + */ + + return 0; +} + +#define cxl_cmd_count ARRAY_SIZE(cxl_mem_commands) + +int cxl_query_cmd(struct cxl_memdev *cxlmd, + struct cxl_mem_query_commands __user *q) +{ + struct device *dev = &cxlmd->dev; + struct cxl_mem_command *cmd; + u32 n_commands; + int j = 0; + + dev_dbg(dev, "Query IOCTL\n"); + + if (get_user(n_commands, &q->n_commands)) + return -EFAULT; + + /* returns the total number if 0 elements are requested. */ + if (n_commands == 0) + return put_user(cxl_cmd_count, &q->n_commands); + + /* + * otherwise, return max(n_commands, total commands) cxl_command_info + * structures. + */ + cxl_for_each_cmd(cmd) { + const struct cxl_command_info *info = &cmd->info; + + if (copy_to_user(&q->commands[j++], info, sizeof(*info))) + return -EFAULT; + + if (j == n_commands) + break; + } + + return 0; +} + +/** + * handle_mailbox_cmd_from_user() - Dispatch a mailbox command for userspace. + * @cxlm: The CXL memory device to communicate with. + * @cmd: The validated command. + * @in_payload: Pointer to userspace's input payload. + * @out_payload: Pointer to userspace's output payload. + * @size_out: (Input) Max payload size to copy out. + * (Output) Payload size hardware generated. + * @retval: Hardware generated return code from the operation. + * + * Return: + * * %0 - Mailbox transaction succeeded. This implies the mailbox + * protocol completed successfully not that the operation itself + * was successful. + * * %-ENOMEM - Couldn't allocate a bounce buffer. + * * %-EFAULT - Something happened with copy_to/from_user. + * * %-EINTR - Mailbox acquisition interrupted. + * * %-EXXX - Transaction level failures. + * + * Creates the appropriate mailbox command and dispatches it on behalf of a + * userspace request. The input and output payloads are copied between + * userspace. + * + * See cxl_send_cmd(). + */ +static int handle_mailbox_cmd_from_user(struct cxl_mem *cxlm, + const struct cxl_mem_command *cmd, + u64 in_payload, u64 out_payload, + s32 *size_out, u32 *retval) +{ + struct device *dev = cxlm->dev; + struct cxl_mbox_cmd mbox_cmd = { + .opcode = cmd->opcode, + .size_in = cmd->info.size_in, + .size_out = cmd->info.size_out, + }; + int rc; + + if (cmd->info.size_out) { + mbox_cmd.payload_out = kvzalloc(cmd->info.size_out, GFP_KERNEL); + if (!mbox_cmd.payload_out) + return -ENOMEM; + } + + if (cmd->info.size_in) { + mbox_cmd.payload_in = vmemdup_user(u64_to_user_ptr(in_payload), + cmd->info.size_in); + if (IS_ERR(mbox_cmd.payload_in)) { + kvfree(mbox_cmd.payload_out); + return PTR_ERR(mbox_cmd.payload_in); + } + } + + dev_dbg(dev, + "Submitting %s command for user\n" + "\topcode: %x\n" + "\tsize: %ub\n", + cxl_command_names[cmd->info.id].name, mbox_cmd.opcode, + cmd->info.size_in); + + dev_WARN_ONCE(dev, cmd->info.id == CXL_MEM_COMMAND_ID_RAW, + "raw command path used\n"); + + rc = cxlm->mbox_send(cxlm, &mbox_cmd); + if (rc) + goto out; + + /* + * @size_out contains the max size that's allowed to be written back out + * to userspace. While the payload may have written more output than + * this it will have to be ignored. + */ + if (mbox_cmd.size_out) { + dev_WARN_ONCE(dev, mbox_cmd.size_out > *size_out, + "Invalid return size\n"); + if (copy_to_user(u64_to_user_ptr(out_payload), + mbox_cmd.payload_out, mbox_cmd.size_out)) { + rc = -EFAULT; + goto out; + } + } + + *size_out = mbox_cmd.size_out; + *retval = mbox_cmd.return_code; + +out: + kvfree(mbox_cmd.payload_in); + kvfree(mbox_cmd.payload_out); + return rc; +} + +int cxl_send_cmd(struct cxl_memdev *cxlmd, struct cxl_send_command __user *s) +{ + struct cxl_mem *cxlm = cxlmd->cxlm; + struct device *dev = &cxlmd->dev; + struct cxl_send_command send; + struct cxl_mem_command c; + int rc; + + dev_dbg(dev, "Send IOCTL\n"); + + if (copy_from_user(&send, s, sizeof(send))) + return -EFAULT; + + rc = cxl_validate_cmd_from_user(cxlmd->cxlm, &send, &c); + if (rc) + return rc; + + /* Prepare to handle a full payload for variable sized output */ + if (c.info.size_out < 0) + c.info.size_out = cxlm->payload_size; + + rc = handle_mailbox_cmd_from_user(cxlm, &c, send.in.payload, + send.out.payload, &send.out.size, + &send.retval); + if (rc) + return rc; + + if (copy_to_user(s, &send, sizeof(send))) + return -EFAULT; + + return 0; +} + +static int cxl_xfer_log(struct cxl_mem *cxlm, uuid_t *uuid, u32 size, u8 *out) +{ + u32 remaining = size; + u32 offset = 0; + + while (remaining) { + u32 xfer_size = min_t(u32, remaining, cxlm->payload_size); + struct cxl_mbox_get_log { + uuid_t uuid; + __le32 offset; + __le32 length; + } __packed log = { + .uuid = *uuid, + .offset = cpu_to_le32(offset), + .length = cpu_to_le32(xfer_size) + }; + int rc; + + rc = cxl_mem_mbox_send_cmd(cxlm, CXL_MBOX_OP_GET_LOG, &log, + sizeof(log), out, xfer_size); + if (rc < 0) + return rc; + + out += xfer_size; + remaining -= xfer_size; + offset += xfer_size; + } + + return 0; +} + +/** + * cxl_walk_cel() - Walk through the Command Effects Log. + * @cxlm: Device. + * @size: Length of the Command Effects Log. + * @cel: CEL + * + * Iterate over each entry in the CEL and determine if the driver supports the + * command. If so, the command is enabled for the device and can be used later. + */ +static void cxl_walk_cel(struct cxl_mem *cxlm, size_t size, u8 *cel) +{ + struct cel_entry { + __le16 opcode; + __le16 effect; + } __packed * cel_entry; + const int cel_entries = size / sizeof(*cel_entry); + int i; + + cel_entry = (struct cel_entry *)cel; + + for (i = 0; i < cel_entries; i++) { + u16 opcode = le16_to_cpu(cel_entry[i].opcode); + struct cxl_mem_command *cmd = cxl_mem_find_command(opcode); + + if (!cmd) { + dev_dbg(cxlm->dev, + "Opcode 0x%04x unsupported by driver", opcode); + continue; + } + + set_bit(cmd->info.id, cxlm->enabled_cmds); + } +} + +struct cxl_mbox_get_supported_logs { + __le16 entries; + u8 rsvd[6]; + struct gsl_entry { + uuid_t uuid; + __le32 size; + } __packed entry[]; +} __packed; + +static struct cxl_mbox_get_supported_logs *cxl_get_gsl(struct cxl_mem *cxlm) +{ + struct cxl_mbox_get_supported_logs *ret; + int rc; + + ret = kvmalloc(cxlm->payload_size, GFP_KERNEL); + if (!ret) + return ERR_PTR(-ENOMEM); + + rc = cxl_mem_mbox_send_cmd(cxlm, CXL_MBOX_OP_GET_SUPPORTED_LOGS, NULL, + 0, ret, cxlm->payload_size); + if (rc < 0) { + kvfree(ret); + return ERR_PTR(rc); + } + + return ret; +} + +enum { + CEL_UUID, + VENDOR_DEBUG_UUID, +}; + +/* See CXL 2.0 Table 170. Get Log Input Payload */ +static const uuid_t log_uuid[] = { + [CEL_UUID] = UUID_INIT(0xda9c0b5, 0xbf41, 0x4b78, 0x8f, 0x79, 0x96, + 0xb1, 0x62, 0x3b, 0x3f, 0x17), + [VENDOR_DEBUG_UUID] = UUID_INIT(0xe1819d9, 0x11a9, 0x400c, 0x81, 0x1f, + 0xd6, 0x07, 0x19, 0x40, 0x3d, 0x86), +}; + +/** + * cxl_mem_enumerate_cmds() - Enumerate commands for a device. + * @cxlm: The device. + * + * Returns 0 if enumerate completed successfully. + * + * CXL devices have optional support for certain commands. This function will + * determine the set of supported commands for the hardware and update the + * enabled_cmds bitmap in the @cxlm. + */ +int cxl_mem_enumerate_cmds(struct cxl_mem *cxlm) +{ + struct cxl_mbox_get_supported_logs *gsl; + struct device *dev = cxlm->dev; + struct cxl_mem_command *cmd; + int i, rc; + + gsl = cxl_get_gsl(cxlm); + if (IS_ERR(gsl)) + return PTR_ERR(gsl); + + rc = -ENOENT; + for (i = 0; i < le16_to_cpu(gsl->entries); i++) { + u32 size = le32_to_cpu(gsl->entry[i].size); + uuid_t uuid = gsl->entry[i].uuid; + u8 *log; + + dev_dbg(dev, "Found LOG type %pU of size %d", &uuid, size); + + if (!uuid_equal(&uuid, &log_uuid[CEL_UUID])) + continue; + + log = kvmalloc(size, GFP_KERNEL); + if (!log) { + rc = -ENOMEM; + goto out; + } + + rc = cxl_xfer_log(cxlm, &uuid, size, log); + if (rc) { + kvfree(log); + goto out; + } + + cxl_walk_cel(cxlm, size, log); + kvfree(log); + + /* In case CEL was bogus, enable some default commands. */ + cxl_for_each_cmd(cmd) + if (cmd->flags & CXL_CMD_FLAG_FORCE_ENABLE) + set_bit(cmd->info.id, cxlm->enabled_cmds); + + /* Found the required CEL */ + rc = 0; + } + +out: + kvfree(gsl); + return rc; +} +EXPORT_SYMBOL_GPL(cxl_mem_enumerate_cmds); + +/** + * cxl_mem_get_partition_info - Get partition info + * @cxlm: cxl_mem instance to update partition info + * + * Retrieve the current partition info for the device specified. The active + * values are the current capacity in bytes. If not 0, the 'next' values are + * the pending values, in bytes, which take affect on next cold reset. + * + * Return: 0 if no error: or the result of the mailbox command. + * + * See CXL @8.2.9.5.2.1 Get Partition Info + */ +static int cxl_mem_get_partition_info(struct cxl_mem *cxlm) +{ + struct cxl_mbox_get_partition_info { + __le64 active_volatile_cap; + __le64 active_persistent_cap; + __le64 next_volatile_cap; + __le64 next_persistent_cap; + } __packed pi; + int rc; + + rc = cxl_mem_mbox_send_cmd(cxlm, CXL_MBOX_OP_GET_PARTITION_INFO, + NULL, 0, &pi, sizeof(pi)); + + if (rc) + return rc; + + cxlm->active_volatile_bytes = + le64_to_cpu(pi.active_volatile_cap) * CXL_CAPACITY_MULTIPLIER; + cxlm->active_persistent_bytes = + le64_to_cpu(pi.active_persistent_cap) * CXL_CAPACITY_MULTIPLIER; + cxlm->next_volatile_bytes = + le64_to_cpu(pi.next_volatile_cap) * CXL_CAPACITY_MULTIPLIER; + cxlm->next_persistent_bytes = + le64_to_cpu(pi.next_volatile_cap) * CXL_CAPACITY_MULTIPLIER; + + return 0; +} + +/** + * cxl_mem_identify() - Send the IDENTIFY command to the device. + * @cxlm: The device to identify. + * + * Return: 0 if identify was executed successfully. + * + * This will dispatch the identify command to the device and on success populate + * structures to be exported to sysfs. + */ +int cxl_mem_identify(struct cxl_mem *cxlm) +{ + /* See CXL 2.0 Table 175 Identify Memory Device Output Payload */ + struct cxl_mbox_identify { + char fw_revision[0x10]; + __le64 total_capacity; + __le64 volatile_capacity; + __le64 persistent_capacity; + __le64 partition_align; + __le16 info_event_log_size; + __le16 warning_event_log_size; + __le16 failure_event_log_size; + __le16 fatal_event_log_size; + __le32 lsa_size; + u8 poison_list_max_mer[3]; + __le16 inject_poison_limit; + u8 poison_caps; + u8 qos_telemetry_caps; + } __packed id; + int rc; + + rc = cxl_mem_mbox_send_cmd(cxlm, CXL_MBOX_OP_IDENTIFY, NULL, 0, &id, + sizeof(id)); + if (rc < 0) + return rc; + + cxlm->total_bytes = + le64_to_cpu(id.total_capacity) * CXL_CAPACITY_MULTIPLIER; + cxlm->volatile_only_bytes = + le64_to_cpu(id.volatile_capacity) * CXL_CAPACITY_MULTIPLIER; + cxlm->persistent_only_bytes = + le64_to_cpu(id.persistent_capacity) * CXL_CAPACITY_MULTIPLIER; + cxlm->partition_align_bytes = + le64_to_cpu(id.partition_align) * CXL_CAPACITY_MULTIPLIER; + + dev_dbg(cxlm->dev, + "Identify Memory Device\n" + " total_bytes = %#llx\n" + " volatile_only_bytes = %#llx\n" + " persistent_only_bytes = %#llx\n" + " partition_align_bytes = %#llx\n", + cxlm->total_bytes, cxlm->volatile_only_bytes, + cxlm->persistent_only_bytes, cxlm->partition_align_bytes); + + cxlm->lsa_size = le32_to_cpu(id.lsa_size); + memcpy(cxlm->firmware_version, id.fw_revision, sizeof(id.fw_revision)); + + return 0; +} +EXPORT_SYMBOL_GPL(cxl_mem_identify); + +int cxl_mem_create_range_info(struct cxl_mem *cxlm) +{ + int rc; + + if (cxlm->partition_align_bytes == 0) { + cxlm->ram_range.start = 0; + cxlm->ram_range.end = cxlm->volatile_only_bytes - 1; + cxlm->pmem_range.start = cxlm->volatile_only_bytes; + cxlm->pmem_range.end = cxlm->volatile_only_bytes + + cxlm->persistent_only_bytes - 1; + return 0; + } + + rc = cxl_mem_get_partition_info(cxlm); + if (rc) { + dev_err(cxlm->dev, "Failed to query partition information\n"); + return rc; + } + + dev_dbg(cxlm->dev, + "Get Partition Info\n" + " active_volatile_bytes = %#llx\n" + " active_persistent_bytes = %#llx\n" + " next_volatile_bytes = %#llx\n" + " next_persistent_bytes = %#llx\n", + cxlm->active_volatile_bytes, cxlm->active_persistent_bytes, + cxlm->next_volatile_bytes, cxlm->next_persistent_bytes); + + cxlm->ram_range.start = 0; + cxlm->ram_range.end = cxlm->active_volatile_bytes - 1; + + cxlm->pmem_range.start = cxlm->active_volatile_bytes; + cxlm->pmem_range.end = + cxlm->active_volatile_bytes + cxlm->active_persistent_bytes - 1; + + return 0; +} +EXPORT_SYMBOL_GPL(cxl_mem_create_range_info); + +struct cxl_mem *cxl_mem_create(struct device *dev) +{ + struct cxl_mem *cxlm; + + cxlm = devm_kzalloc(dev, sizeof(*cxlm), GFP_KERNEL); + if (!cxlm) { + dev_err(dev, "No memory available\n"); + return ERR_PTR(-ENOMEM); + } + + mutex_init(&cxlm->mbox_mutex); + cxlm->dev = dev; + cxlm->enabled_cmds = + devm_kmalloc_array(dev, BITS_TO_LONGS(cxl_cmd_count), + sizeof(unsigned long), + GFP_KERNEL | __GFP_ZERO); + if (!cxlm->enabled_cmds) { + dev_err(dev, "No memory available for bitmap\n"); + return ERR_PTR(-ENOMEM); + } + + return cxlm; +} +EXPORT_SYMBOL_GPL(cxl_mem_create); + +static struct dentry *cxl_debugfs; + +void __init cxl_mbox_init(void) +{ + struct dentry *mbox_debugfs; + + cxl_debugfs = debugfs_create_dir("cxl", NULL); + mbox_debugfs = debugfs_create_dir("mbox", cxl_debugfs); + debugfs_create_bool("raw_allow_all", 0600, mbox_debugfs, + &cxl_raw_allow_all); +} + +void cxl_mbox_exit(void) +{ + debugfs_remove_recursive(cxl_debugfs); +} diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c index 331ef7d6c598..df2ba87238c2 100644 --- a/drivers/cxl/core/memdev.c +++ b/drivers/cxl/core/memdev.c @@ -8,6 +8,8 @@ #include #include "core.h" +static DECLARE_RWSEM(cxl_memdev_rwsem); + /* * An entire PCI topology full of devices should be enough for any * config @@ -132,16 +134,21 @@ static const struct device_type cxl_memdev_type = { .groups = cxl_memdev_attribute_groups, }; +static void cxl_memdev_shutdown(struct device *dev) +{ + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); + + down_write(&cxl_memdev_rwsem); + cxlmd->cxlm = NULL; + up_write(&cxl_memdev_rwsem); +} + static void cxl_memdev_unregister(void *_cxlmd) { struct cxl_memdev *cxlmd = _cxlmd; struct device *dev = &cxlmd->dev; - struct cdev *cdev = &cxlmd->cdev; - const struct cdevm_file_operations *cdevm_fops; - - cdevm_fops = container_of(cdev->ops, typeof(*cdevm_fops), fops); - cdevm_fops->shutdown(dev); + cxl_memdev_shutdown(dev); cdev_device_del(&cxlmd->cdev, dev); put_device(dev); } @@ -180,16 +187,72 @@ err: return ERR_PTR(rc); } +static long __cxl_memdev_ioctl(struct cxl_memdev *cxlmd, unsigned int cmd, + unsigned long arg) +{ + switch (cmd) { + case CXL_MEM_QUERY_COMMANDS: + return cxl_query_cmd(cxlmd, (void __user *)arg); + case CXL_MEM_SEND_COMMAND: + return cxl_send_cmd(cxlmd, (void __user *)arg); + default: + return -ENOTTY; + } +} + +static long cxl_memdev_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct cxl_memdev *cxlmd = file->private_data; + int rc = -ENXIO; + + down_read(&cxl_memdev_rwsem); + if (cxlmd->cxlm) + rc = __cxl_memdev_ioctl(cxlmd, cmd, arg); + up_read(&cxl_memdev_rwsem); + + return rc; +} + +static int cxl_memdev_open(struct inode *inode, struct file *file) +{ + struct cxl_memdev *cxlmd = + container_of(inode->i_cdev, typeof(*cxlmd), cdev); + + get_device(&cxlmd->dev); + file->private_data = cxlmd; + + return 0; +} + +static int cxl_memdev_release_file(struct inode *inode, struct file *file) +{ + struct cxl_memdev *cxlmd = + container_of(inode->i_cdev, typeof(*cxlmd), cdev); + + put_device(&cxlmd->dev); + + return 0; +} + +static const struct file_operations cxl_memdev_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = cxl_memdev_ioctl, + .open = cxl_memdev_open, + .release = cxl_memdev_release_file, + .compat_ioctl = compat_ptr_ioctl, + .llseek = noop_llseek, +}; + struct cxl_memdev * -devm_cxl_add_memdev(struct cxl_mem *cxlm, - const struct cdevm_file_operations *cdevm_fops) +devm_cxl_add_memdev(struct cxl_mem *cxlm) { struct cxl_memdev *cxlmd; struct device *dev; struct cdev *cdev; int rc; - cxlmd = cxl_memdev_alloc(cxlm, &cdevm_fops->fops); + cxlmd = cxl_memdev_alloc(cxlm, &cxl_memdev_fops); if (IS_ERR(cxlmd)) return cxlmd; @@ -219,7 +282,7 @@ err: * The cdev was briefly live, shutdown any ioctl operations that * saw that state. */ - cdevm_fops->shutdown(dev); + cxl_memdev_shutdown(dev); put_device(dev); return ERR_PTR(rc); } diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index c142532db8cb..f5d3326a1d0b 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -2,6 +2,7 @@ /* Copyright(c) 2020-2021 Intel Corporation. */ #ifndef __CXL_MEM_H__ #define __CXL_MEM_H__ +#include #include #include "cxl.h" @@ -28,21 +29,6 @@ (FIELD_GET(CXLMDEV_RESET_NEEDED_MASK, status) != \ CXLMDEV_RESET_NEEDED_NOT) -/** - * struct cdevm_file_operations - devm coordinated cdev file operations - * @fops: file operations that are synchronized against @shutdown - * @shutdown: disconnect driver data - * - * @shutdown is invoked in the devres release path to disconnect any - * driver instance data from @dev. It assumes synchronization with any - * fops operation that requires driver data. After @shutdown an - * operation may only reference @device data. - */ -struct cdevm_file_operations { - struct file_operations fops; - void (*shutdown)(struct device *dev); -}; - /** * struct cxl_memdev - CXL bus object representing a Type-3 Memory Device * @dev: driver core device object @@ -62,9 +48,7 @@ static inline struct cxl_memdev *to_cxl_memdev(struct device *dev) return container_of(dev, struct cxl_memdev, dev); } -struct cxl_memdev * -devm_cxl_add_memdev(struct cxl_mem *cxlm, - const struct cdevm_file_operations *cdevm_fops); +struct cxl_memdev *devm_cxl_add_memdev(struct cxl_mem *cxlm); /** * struct cxl_mbox_cmd - A command to be submitted to hardware. @@ -158,4 +142,62 @@ struct cxl_mem { int (*mbox_send)(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd); }; + +enum cxl_opcode { + CXL_MBOX_OP_INVALID = 0x0000, + CXL_MBOX_OP_RAW = CXL_MBOX_OP_INVALID, + CXL_MBOX_OP_GET_FW_INFO = 0x0200, + CXL_MBOX_OP_ACTIVATE_FW = 0x0202, + CXL_MBOX_OP_GET_SUPPORTED_LOGS = 0x0400, + CXL_MBOX_OP_GET_LOG = 0x0401, + CXL_MBOX_OP_IDENTIFY = 0x4000, + CXL_MBOX_OP_GET_PARTITION_INFO = 0x4100, + CXL_MBOX_OP_SET_PARTITION_INFO = 0x4101, + CXL_MBOX_OP_GET_LSA = 0x4102, + CXL_MBOX_OP_SET_LSA = 0x4103, + CXL_MBOX_OP_GET_HEALTH_INFO = 0x4200, + CXL_MBOX_OP_GET_ALERT_CONFIG = 0x4201, + CXL_MBOX_OP_SET_ALERT_CONFIG = 0x4202, + CXL_MBOX_OP_GET_SHUTDOWN_STATE = 0x4203, + CXL_MBOX_OP_SET_SHUTDOWN_STATE = 0x4204, + CXL_MBOX_OP_GET_POISON = 0x4300, + CXL_MBOX_OP_INJECT_POISON = 0x4301, + CXL_MBOX_OP_CLEAR_POISON = 0x4302, + CXL_MBOX_OP_GET_SCAN_MEDIA_CAPS = 0x4303, + CXL_MBOX_OP_SCAN_MEDIA = 0x4304, + CXL_MBOX_OP_GET_SCAN_MEDIA = 0x4305, + CXL_MBOX_OP_MAX = 0x10000 +}; + +/** + * struct cxl_mem_command - Driver representation of a memory device command + * @info: Command information as it exists for the UAPI + * @opcode: The actual bits used for the mailbox protocol + * @flags: Set of flags effecting driver behavior. + * + * * %CXL_CMD_FLAG_FORCE_ENABLE: In cases of error, commands with this flag + * will be enabled by the driver regardless of what hardware may have + * advertised. + * + * The cxl_mem_command is the driver's internal representation of commands that + * are supported by the driver. Some of these commands may not be supported by + * the hardware. The driver will use @info to validate the fields passed in by + * the user then submit the @opcode to the hardware. + * + * See struct cxl_command_info. + */ +struct cxl_mem_command { + struct cxl_command_info info; + enum cxl_opcode opcode; + u32 flags; +#define CXL_CMD_FLAG_NONE 0 +#define CXL_CMD_FLAG_FORCE_ENABLE BIT(0) +}; + +int cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm, u16 opcode, void *in, + size_t in_size, void *out, size_t out_size); +int cxl_mem_identify(struct cxl_mem *cxlm); +int cxl_mem_enumerate_cmds(struct cxl_mem *cxlm); +int cxl_mem_create_range_info(struct cxl_mem *cxlm); +struct cxl_mem *cxl_mem_create(struct device *dev); #endif /* __CXL_MEM_H__ */ diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index 9d8050fdd69c..c9f2ac134f4d 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -1,16 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright(c) 2020 Intel Corporation. All rights reserved. */ -#include -#include -#include +#include #include #include #include #include -#include #include #include -#include #include "cxlmem.h" #include "pci.h" #include "cxl.h" @@ -37,162 +33,6 @@ /* CXL 2.0 - 8.2.8.4 */ #define CXL_MAILBOX_TIMEOUT_MS (2 * HZ) -enum opcode { - CXL_MBOX_OP_INVALID = 0x0000, - CXL_MBOX_OP_RAW = CXL_MBOX_OP_INVALID, - CXL_MBOX_OP_GET_FW_INFO = 0x0200, - CXL_MBOX_OP_ACTIVATE_FW = 0x0202, - CXL_MBOX_OP_GET_SUPPORTED_LOGS = 0x0400, - CXL_MBOX_OP_GET_LOG = 0x0401, - CXL_MBOX_OP_IDENTIFY = 0x4000, - CXL_MBOX_OP_GET_PARTITION_INFO = 0x4100, - CXL_MBOX_OP_SET_PARTITION_INFO = 0x4101, - CXL_MBOX_OP_GET_LSA = 0x4102, - CXL_MBOX_OP_SET_LSA = 0x4103, - CXL_MBOX_OP_GET_HEALTH_INFO = 0x4200, - CXL_MBOX_OP_GET_ALERT_CONFIG = 0x4201, - CXL_MBOX_OP_SET_ALERT_CONFIG = 0x4202, - CXL_MBOX_OP_GET_SHUTDOWN_STATE = 0x4203, - CXL_MBOX_OP_SET_SHUTDOWN_STATE = 0x4204, - CXL_MBOX_OP_GET_POISON = 0x4300, - CXL_MBOX_OP_INJECT_POISON = 0x4301, - CXL_MBOX_OP_CLEAR_POISON = 0x4302, - CXL_MBOX_OP_GET_SCAN_MEDIA_CAPS = 0x4303, - CXL_MBOX_OP_SCAN_MEDIA = 0x4304, - CXL_MBOX_OP_GET_SCAN_MEDIA = 0x4305, - CXL_MBOX_OP_MAX = 0x10000 -}; - -static DECLARE_RWSEM(cxl_memdev_rwsem); -static struct dentry *cxl_debugfs; -static bool cxl_raw_allow_all; - -enum { - CEL_UUID, - VENDOR_DEBUG_UUID, -}; - -/* See CXL 2.0 Table 170. Get Log Input Payload */ -static const uuid_t log_uuid[] = { - [CEL_UUID] = UUID_INIT(0xda9c0b5, 0xbf41, 0x4b78, 0x8f, 0x79, 0x96, - 0xb1, 0x62, 0x3b, 0x3f, 0x17), - [VENDOR_DEBUG_UUID] = UUID_INIT(0xe1819d9, 0x11a9, 0x400c, 0x81, 0x1f, - 0xd6, 0x07, 0x19, 0x40, 0x3d, 0x86), -}; - -/** - * struct cxl_mem_command - Driver representation of a memory device command - * @info: Command information as it exists for the UAPI - * @opcode: The actual bits used for the mailbox protocol - * @flags: Set of flags effecting driver behavior. - * - * * %CXL_CMD_FLAG_FORCE_ENABLE: In cases of error, commands with this flag - * will be enabled by the driver regardless of what hardware may have - * advertised. - * - * The cxl_mem_command is the driver's internal representation of commands that - * are supported by the driver. Some of these commands may not be supported by - * the hardware. The driver will use @info to validate the fields passed in by - * the user then submit the @opcode to the hardware. - * - * See struct cxl_command_info. - */ -struct cxl_mem_command { - struct cxl_command_info info; - enum opcode opcode; - u32 flags; -#define CXL_CMD_FLAG_NONE 0 -#define CXL_CMD_FLAG_FORCE_ENABLE BIT(0) -}; - -#define CXL_CMD(_id, sin, sout, _flags) \ - [CXL_MEM_COMMAND_ID_##_id] = { \ - .info = { \ - .id = CXL_MEM_COMMAND_ID_##_id, \ - .size_in = sin, \ - .size_out = sout, \ - }, \ - .opcode = CXL_MBOX_OP_##_id, \ - .flags = _flags, \ - } - -/* - * This table defines the supported mailbox commands for the driver. This table - * is made up of a UAPI structure. Non-negative values as parameters in the - * table will be validated against the user's input. For example, if size_in is - * 0, and the user passed in 1, it is an error. - */ -static struct cxl_mem_command mem_commands[CXL_MEM_COMMAND_ID_MAX] = { - CXL_CMD(IDENTIFY, 0, 0x43, CXL_CMD_FLAG_FORCE_ENABLE), -#ifdef CONFIG_CXL_MEM_RAW_COMMANDS - CXL_CMD(RAW, ~0, ~0, 0), -#endif - CXL_CMD(GET_SUPPORTED_LOGS, 0, ~0, CXL_CMD_FLAG_FORCE_ENABLE), - CXL_CMD(GET_FW_INFO, 0, 0x50, 0), - CXL_CMD(GET_PARTITION_INFO, 0, 0x20, 0), - CXL_CMD(GET_LSA, 0x8, ~0, 0), - CXL_CMD(GET_HEALTH_INFO, 0, 0x12, 0), - CXL_CMD(GET_LOG, 0x18, ~0, CXL_CMD_FLAG_FORCE_ENABLE), - CXL_CMD(SET_PARTITION_INFO, 0x0a, 0, 0), - CXL_CMD(SET_LSA, ~0, 0, 0), - CXL_CMD(GET_ALERT_CONFIG, 0, 0x10, 0), - CXL_CMD(SET_ALERT_CONFIG, 0xc, 0, 0), - CXL_CMD(GET_SHUTDOWN_STATE, 0, 0x1, 0), - CXL_CMD(SET_SHUTDOWN_STATE, 0x1, 0, 0), - CXL_CMD(GET_POISON, 0x10, ~0, 0), - CXL_CMD(INJECT_POISON, 0x8, 0, 0), - CXL_CMD(CLEAR_POISON, 0x48, 0, 0), - CXL_CMD(GET_SCAN_MEDIA_CAPS, 0x10, 0x4, 0), - CXL_CMD(SCAN_MEDIA, 0x11, 0, 0), - CXL_CMD(GET_SCAN_MEDIA, 0, ~0, 0), -}; - -/* - * Commands that RAW doesn't permit. The rationale for each: - * - * CXL_MBOX_OP_ACTIVATE_FW: Firmware activation requires adjustment / - * coordination of transaction timeout values at the root bridge level. - * - * CXL_MBOX_OP_SET_PARTITION_INFO: The device memory map may change live - * and needs to be coordinated with HDM updates. - * - * CXL_MBOX_OP_SET_LSA: The label storage area may be cached by the - * driver and any writes from userspace invalidates those contents. - * - * CXL_MBOX_OP_SET_SHUTDOWN_STATE: Set shutdown state assumes no writes - * to the device after it is marked clean, userspace can not make that - * assertion. - * - * CXL_MBOX_OP_[GET_]SCAN_MEDIA: The kernel provides a native error list that - * is kept up to date with patrol notifications and error management. - */ -static u16 cxl_disabled_raw_commands[] = { - CXL_MBOX_OP_ACTIVATE_FW, - CXL_MBOX_OP_SET_PARTITION_INFO, - CXL_MBOX_OP_SET_LSA, - CXL_MBOX_OP_SET_SHUTDOWN_STATE, - CXL_MBOX_OP_SCAN_MEDIA, - CXL_MBOX_OP_GET_SCAN_MEDIA, -}; - -/* - * Command sets that RAW doesn't permit. All opcodes in this set are - * disabled because they pass plain text security payloads over the - * user/kernel boundary. This functionality is intended to be wrapped - * behind the keys ABI which allows for encrypted payloads in the UAPI - */ -static u8 security_command_sets[] = { - 0x44, /* Sanitize */ - 0x45, /* Persistent Memory Data-at-rest Security */ - 0x46, /* Security Passthrough */ -}; - -#define cxl_for_each_cmd(cmd) \ - for ((cmd) = &mem_commands[0]; \ - ((cmd) - mem_commands) < ARRAY_SIZE(mem_commands); (cmd)++) - -#define cxl_cmd_count ARRAY_SIZE(mem_commands) - static int cxl_mem_wait_for_doorbell(struct cxl_mem *cxlm) { const unsigned long start = jiffies; @@ -215,16 +55,6 @@ static int cxl_mem_wait_for_doorbell(struct cxl_mem *cxlm) return 0; } -static bool cxl_is_security_command(u16 opcode) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(security_command_sets); i++) - if (security_command_sets[i] == (opcode >> 8)) - return true; - return false; -} - static void cxl_mem_mbox_timeout(struct cxl_mem *cxlm, struct cxl_mbox_cmd *mbox_cmd) { @@ -446,433 +276,6 @@ static int cxl_pci_mbox_send(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) return rc; } -/** - * handle_mailbox_cmd_from_user() - Dispatch a mailbox command for userspace. - * @cxlm: The CXL memory device to communicate with. - * @cmd: The validated command. - * @in_payload: Pointer to userspace's input payload. - * @out_payload: Pointer to userspace's output payload. - * @size_out: (Input) Max payload size to copy out. - * (Output) Payload size hardware generated. - * @retval: Hardware generated return code from the operation. - * - * Return: - * * %0 - Mailbox transaction succeeded. This implies the mailbox - * protocol completed successfully not that the operation itself - * was successful. - * * %-ENOMEM - Couldn't allocate a bounce buffer. - * * %-EFAULT - Something happened with copy_to/from_user. - * * %-EINTR - Mailbox acquisition interrupted. - * * %-EXXX - Transaction level failures. - * - * Creates the appropriate mailbox command and dispatches it on behalf of a - * userspace request. The input and output payloads are copied between - * userspace. - * - * See cxl_send_cmd(). - */ -static int handle_mailbox_cmd_from_user(struct cxl_mem *cxlm, - const struct cxl_mem_command *cmd, - u64 in_payload, u64 out_payload, - s32 *size_out, u32 *retval) -{ - struct device *dev = cxlm->dev; - struct cxl_mbox_cmd mbox_cmd = { - .opcode = cmd->opcode, - .size_in = cmd->info.size_in, - .size_out = cmd->info.size_out, - }; - int rc; - - if (cmd->info.size_out) { - mbox_cmd.payload_out = kvzalloc(cmd->info.size_out, GFP_KERNEL); - if (!mbox_cmd.payload_out) - return -ENOMEM; - } - - if (cmd->info.size_in) { - mbox_cmd.payload_in = vmemdup_user(u64_to_user_ptr(in_payload), - cmd->info.size_in); - if (IS_ERR(mbox_cmd.payload_in)) { - kvfree(mbox_cmd.payload_out); - return PTR_ERR(mbox_cmd.payload_in); - } - } - - dev_dbg(dev, - "Submitting %s command for user\n" - "\topcode: %x\n" - "\tsize: %ub\n", - cxl_command_names[cmd->info.id].name, mbox_cmd.opcode, - cmd->info.size_in); - - dev_WARN_ONCE(dev, cmd->info.id == CXL_MEM_COMMAND_ID_RAW, - "raw command path used\n"); - - rc = cxlm->mbox_send(cxlm, &mbox_cmd); - if (rc) - goto out; - - /* - * @size_out contains the max size that's allowed to be written back out - * to userspace. While the payload may have written more output than - * this it will have to be ignored. - */ - if (mbox_cmd.size_out) { - dev_WARN_ONCE(dev, mbox_cmd.size_out > *size_out, - "Invalid return size\n"); - if (copy_to_user(u64_to_user_ptr(out_payload), - mbox_cmd.payload_out, mbox_cmd.size_out)) { - rc = -EFAULT; - goto out; - } - } - - *size_out = mbox_cmd.size_out; - *retval = mbox_cmd.return_code; - -out: - kvfree(mbox_cmd.payload_in); - kvfree(mbox_cmd.payload_out); - return rc; -} - -static bool cxl_mem_raw_command_allowed(u16 opcode) -{ - int i; - - if (!IS_ENABLED(CONFIG_CXL_MEM_RAW_COMMANDS)) - return false; - - if (security_locked_down(LOCKDOWN_PCI_ACCESS)) - return false; - - if (cxl_raw_allow_all) - return true; - - if (cxl_is_security_command(opcode)) - return false; - - for (i = 0; i < ARRAY_SIZE(cxl_disabled_raw_commands); i++) - if (cxl_disabled_raw_commands[i] == opcode) - return false; - - return true; -} - -/** - * cxl_validate_cmd_from_user() - Check fields for CXL_MEM_SEND_COMMAND. - * @cxlm: &struct cxl_mem device whose mailbox will be used. - * @send_cmd: &struct cxl_send_command copied in from userspace. - * @out_cmd: Sanitized and populated &struct cxl_mem_command. - * - * Return: - * * %0 - @out_cmd is ready to send. - * * %-ENOTTY - Invalid command specified. - * * %-EINVAL - Reserved fields or invalid values were used. - * * %-ENOMEM - Input or output buffer wasn't sized properly. - * * %-EPERM - Attempted to use a protected command. - * - * The result of this command is a fully validated command in @out_cmd that is - * safe to send to the hardware. - * - * See handle_mailbox_cmd_from_user() - */ -static int cxl_validate_cmd_from_user(struct cxl_mem *cxlm, - const struct cxl_send_command *send_cmd, - struct cxl_mem_command *out_cmd) -{ - const struct cxl_command_info *info; - struct cxl_mem_command *c; - - if (send_cmd->id == 0 || send_cmd->id >= CXL_MEM_COMMAND_ID_MAX) - return -ENOTTY; - - /* - * The user can never specify an input payload larger than what hardware - * supports, but output can be arbitrarily large (simply write out as - * much data as the hardware provides). - */ - if (send_cmd->in.size > cxlm->payload_size) - return -EINVAL; - - /* - * Checks are bypassed for raw commands but a WARN/taint will occur - * later in the callchain - */ - if (send_cmd->id == CXL_MEM_COMMAND_ID_RAW) { - const struct cxl_mem_command temp = { - .info = { - .id = CXL_MEM_COMMAND_ID_RAW, - .flags = 0, - .size_in = send_cmd->in.size, - .size_out = send_cmd->out.size, - }, - .opcode = send_cmd->raw.opcode - }; - - if (send_cmd->raw.rsvd) - return -EINVAL; - - /* - * Unlike supported commands, the output size of RAW commands - * gets passed along without further checking, so it must be - * validated here. - */ - if (send_cmd->out.size > cxlm->payload_size) - return -EINVAL; - - if (!cxl_mem_raw_command_allowed(send_cmd->raw.opcode)) - return -EPERM; - - memcpy(out_cmd, &temp, sizeof(temp)); - - return 0; - } - - if (send_cmd->flags & ~CXL_MEM_COMMAND_FLAG_MASK) - return -EINVAL; - - if (send_cmd->rsvd) - return -EINVAL; - - if (send_cmd->in.rsvd || send_cmd->out.rsvd) - return -EINVAL; - - /* Convert user's command into the internal representation */ - c = &mem_commands[send_cmd->id]; - info = &c->info; - - /* Check that the command is enabled for hardware */ - if (!test_bit(info->id, cxlm->enabled_cmds)) - return -ENOTTY; - - /* Check the input buffer is the expected size */ - if (info->size_in >= 0 && info->size_in != send_cmd->in.size) - return -ENOMEM; - - /* Check the output buffer is at least large enough */ - if (info->size_out >= 0 && send_cmd->out.size < info->size_out) - return -ENOMEM; - - memcpy(out_cmd, c, sizeof(*c)); - out_cmd->info.size_in = send_cmd->in.size; - /* - * XXX: out_cmd->info.size_out will be controlled by the driver, and the - * specified number of bytes @send_cmd->out.size will be copied back out - * to userspace. - */ - - return 0; -} - -static int cxl_query_cmd(struct cxl_memdev *cxlmd, - struct cxl_mem_query_commands __user *q) -{ - struct device *dev = &cxlmd->dev; - struct cxl_mem_command *cmd; - u32 n_commands; - int j = 0; - - dev_dbg(dev, "Query IOCTL\n"); - - if (get_user(n_commands, &q->n_commands)) - return -EFAULT; - - /* returns the total number if 0 elements are requested. */ - if (n_commands == 0) - return put_user(cxl_cmd_count, &q->n_commands); - - /* - * otherwise, return max(n_commands, total commands) cxl_command_info - * structures. - */ - cxl_for_each_cmd(cmd) { - const struct cxl_command_info *info = &cmd->info; - - if (copy_to_user(&q->commands[j++], info, sizeof(*info))) - return -EFAULT; - - if (j == n_commands) - break; - } - - return 0; -} - -static int cxl_send_cmd(struct cxl_memdev *cxlmd, - struct cxl_send_command __user *s) -{ - struct cxl_mem *cxlm = cxlmd->cxlm; - struct device *dev = &cxlmd->dev; - struct cxl_send_command send; - struct cxl_mem_command c; - int rc; - - dev_dbg(dev, "Send IOCTL\n"); - - if (copy_from_user(&send, s, sizeof(send))) - return -EFAULT; - - rc = cxl_validate_cmd_from_user(cxlmd->cxlm, &send, &c); - if (rc) - return rc; - - /* Prepare to handle a full payload for variable sized output */ - if (c.info.size_out < 0) - c.info.size_out = cxlm->payload_size; - - rc = handle_mailbox_cmd_from_user(cxlm, &c, send.in.payload, - send.out.payload, &send.out.size, - &send.retval); - if (rc) - return rc; - - if (copy_to_user(s, &send, sizeof(send))) - return -EFAULT; - - return 0; -} - -static long __cxl_memdev_ioctl(struct cxl_memdev *cxlmd, unsigned int cmd, - unsigned long arg) -{ - switch (cmd) { - case CXL_MEM_QUERY_COMMANDS: - return cxl_query_cmd(cxlmd, (void __user *)arg); - case CXL_MEM_SEND_COMMAND: - return cxl_send_cmd(cxlmd, (void __user *)arg); - default: - return -ENOTTY; - } -} - -static long cxl_memdev_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct cxl_memdev *cxlmd = file->private_data; - int rc = -ENXIO; - - down_read(&cxl_memdev_rwsem); - if (cxlmd->cxlm) - rc = __cxl_memdev_ioctl(cxlmd, cmd, arg); - up_read(&cxl_memdev_rwsem); - - return rc; -} - -static int cxl_memdev_open(struct inode *inode, struct file *file) -{ - struct cxl_memdev *cxlmd = - container_of(inode->i_cdev, typeof(*cxlmd), cdev); - - get_device(&cxlmd->dev); - file->private_data = cxlmd; - - return 0; -} - -static int cxl_memdev_release_file(struct inode *inode, struct file *file) -{ - struct cxl_memdev *cxlmd = - container_of(inode->i_cdev, typeof(*cxlmd), cdev); - - put_device(&cxlmd->dev); - - return 0; -} - -static void cxl_memdev_shutdown(struct device *dev) -{ - struct cxl_memdev *cxlmd = to_cxl_memdev(dev); - - down_write(&cxl_memdev_rwsem); - cxlmd->cxlm = NULL; - up_write(&cxl_memdev_rwsem); -} - -static const struct cdevm_file_operations cxl_memdev_fops = { - .fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = cxl_memdev_ioctl, - .open = cxl_memdev_open, - .release = cxl_memdev_release_file, - .compat_ioctl = compat_ptr_ioctl, - .llseek = noop_llseek, - }, - .shutdown = cxl_memdev_shutdown, -}; - -static inline struct cxl_mem_command *cxl_mem_find_command(u16 opcode) -{ - struct cxl_mem_command *c; - - cxl_for_each_cmd(c) - if (c->opcode == opcode) - return c; - - return NULL; -} - -/** - * cxl_mem_mbox_send_cmd() - Send a mailbox command to a memory device. - * @cxlm: The CXL memory device to communicate with. - * @opcode: Opcode for the mailbox command. - * @in: The input payload for the mailbox command. - * @in_size: The length of the input payload - * @out: Caller allocated buffer for the output. - * @out_size: Expected size of output. - * - * Context: Any context. Will acquire and release mbox_mutex. - * Return: - * * %>=0 - Number of bytes returned in @out. - * * %-E2BIG - Payload is too large for hardware. - * * %-EBUSY - Couldn't acquire exclusive mailbox access. - * * %-EFAULT - Hardware error occurred. - * * %-ENXIO - Command completed, but device reported an error. - * * %-EIO - Unexpected output size. - * - * Mailbox commands may execute successfully yet the device itself reported an - * error. While this distinction can be useful for commands from userspace, the - * kernel will only be able to use results when both are successful. - * - * See __cxl_mem_mbox_send_cmd() - */ -static int cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm, u16 opcode, - void *in, size_t in_size, - void *out, size_t out_size) -{ - const struct cxl_mem_command *cmd = cxl_mem_find_command(opcode); - struct cxl_mbox_cmd mbox_cmd = { - .opcode = opcode, - .payload_in = in, - .size_in = in_size, - .size_out = out_size, - .payload_out = out, - }; - int rc; - - if (out_size > cxlm->payload_size) - return -E2BIG; - - rc = cxlm->mbox_send(cxlm, &mbox_cmd); - if (rc) - return rc; - - /* TODO: Map return code to proper kernel style errno */ - if (mbox_cmd.return_code != CXL_MBOX_SUCCESS) - return -ENXIO; - - /* - * Variable sized commands can't be validated and so it's up to the - * caller to do that if they wish. - */ - if (cmd->info.size_out >= 0 && mbox_cmd.size_out != out_size) - return -EIO; - - return 0; -} - static int cxl_mem_setup_mailbox(struct cxl_mem *cxlm) { const int cap = readl(cxlm->regs.mbox + CXLDEV_MBOX_CAPS_OFFSET); @@ -901,30 +304,6 @@ static int cxl_mem_setup_mailbox(struct cxl_mem *cxlm) return 0; } -static struct cxl_mem *cxl_mem_create(struct device *dev) -{ - struct cxl_mem *cxlm; - - cxlm = devm_kzalloc(dev, sizeof(*cxlm), GFP_KERNEL); - if (!cxlm) { - dev_err(dev, "No memory available\n"); - return ERR_PTR(-ENOMEM); - } - - mutex_init(&cxlm->mbox_mutex); - cxlm->dev = dev; - cxlm->enabled_cmds = - devm_kmalloc_array(dev, BITS_TO_LONGS(cxl_cmd_count), - sizeof(unsigned long), - GFP_KERNEL | __GFP_ZERO); - if (!cxlm->enabled_cmds) { - dev_err(dev, "No memory available for bitmap\n"); - return ERR_PTR(-ENOMEM); - } - - return cxlm; -} - static void __iomem *cxl_mem_map_regblock(struct cxl_mem *cxlm, u8 bar, u64 offset) { @@ -1132,298 +511,6 @@ static int cxl_mem_setup_regs(struct cxl_mem *cxlm) return ret; } -static int cxl_xfer_log(struct cxl_mem *cxlm, uuid_t *uuid, u32 size, u8 *out) -{ - u32 remaining = size; - u32 offset = 0; - - while (remaining) { - u32 xfer_size = min_t(u32, remaining, cxlm->payload_size); - struct cxl_mbox_get_log { - uuid_t uuid; - __le32 offset; - __le32 length; - } __packed log = { - .uuid = *uuid, - .offset = cpu_to_le32(offset), - .length = cpu_to_le32(xfer_size) - }; - int rc; - - rc = cxl_mem_mbox_send_cmd(cxlm, CXL_MBOX_OP_GET_LOG, &log, - sizeof(log), out, xfer_size); - if (rc < 0) - return rc; - - out += xfer_size; - remaining -= xfer_size; - offset += xfer_size; - } - - return 0; -} - -/** - * cxl_walk_cel() - Walk through the Command Effects Log. - * @cxlm: Device. - * @size: Length of the Command Effects Log. - * @cel: CEL - * - * Iterate over each entry in the CEL and determine if the driver supports the - * command. If so, the command is enabled for the device and can be used later. - */ -static void cxl_walk_cel(struct cxl_mem *cxlm, size_t size, u8 *cel) -{ - struct cel_entry { - __le16 opcode; - __le16 effect; - } __packed * cel_entry; - const int cel_entries = size / sizeof(*cel_entry); - int i; - - cel_entry = (struct cel_entry *)cel; - - for (i = 0; i < cel_entries; i++) { - u16 opcode = le16_to_cpu(cel_entry[i].opcode); - struct cxl_mem_command *cmd = cxl_mem_find_command(opcode); - - if (!cmd) { - dev_dbg(cxlm->dev, - "Opcode 0x%04x unsupported by driver", opcode); - continue; - } - - set_bit(cmd->info.id, cxlm->enabled_cmds); - } -} - -struct cxl_mbox_get_supported_logs { - __le16 entries; - u8 rsvd[6]; - struct gsl_entry { - uuid_t uuid; - __le32 size; - } __packed entry[]; -} __packed; - -static struct cxl_mbox_get_supported_logs *cxl_get_gsl(struct cxl_mem *cxlm) -{ - struct cxl_mbox_get_supported_logs *ret; - int rc; - - ret = kvmalloc(cxlm->payload_size, GFP_KERNEL); - if (!ret) - return ERR_PTR(-ENOMEM); - - rc = cxl_mem_mbox_send_cmd(cxlm, CXL_MBOX_OP_GET_SUPPORTED_LOGS, NULL, - 0, ret, cxlm->payload_size); - if (rc < 0) { - kvfree(ret); - return ERR_PTR(rc); - } - - return ret; -} - -/** - * cxl_mem_get_partition_info - Get partition info - * @cxlm: cxl_mem instance to update partition info - * - * Retrieve the current partition info for the device specified. If not 0, the - * 'next' values are pending and take affect on next cold reset. - * - * Return: 0 if no error: or the result of the mailbox command. - * - * See CXL @8.2.9.5.2.1 Get Partition Info - */ -static int cxl_mem_get_partition_info(struct cxl_mem *cxlm) -{ - struct cxl_mbox_get_partition_info { - __le64 active_volatile_cap; - __le64 active_persistent_cap; - __le64 next_volatile_cap; - __le64 next_persistent_cap; - } __packed pi; - int rc; - - rc = cxl_mem_mbox_send_cmd(cxlm, CXL_MBOX_OP_GET_PARTITION_INFO, - NULL, 0, &pi, sizeof(pi)); - if (rc) - return rc; - - cxlm->active_volatile_bytes = - le64_to_cpu(pi.active_volatile_cap) * CXL_CAPACITY_MULTIPLIER; - cxlm->active_persistent_bytes = - le64_to_cpu(pi.active_persistent_cap) * CXL_CAPACITY_MULTIPLIER; - cxlm->next_volatile_bytes = - le64_to_cpu(pi.next_volatile_cap) * CXL_CAPACITY_MULTIPLIER; - cxlm->next_persistent_bytes = - le64_to_cpu(pi.next_volatile_cap) * CXL_CAPACITY_MULTIPLIER; - - return 0; -} - -/** - * cxl_mem_enumerate_cmds() - Enumerate commands for a device. - * @cxlm: The device. - * - * Returns 0 if enumerate completed successfully. - * - * CXL devices have optional support for certain commands. This function will - * determine the set of supported commands for the hardware and update the - * enabled_cmds bitmap in the @cxlm. - */ -static int cxl_mem_enumerate_cmds(struct cxl_mem *cxlm) -{ - struct cxl_mbox_get_supported_logs *gsl; - struct device *dev = cxlm->dev; - struct cxl_mem_command *cmd; - int i, rc; - - gsl = cxl_get_gsl(cxlm); - if (IS_ERR(gsl)) - return PTR_ERR(gsl); - - rc = -ENOENT; - for (i = 0; i < le16_to_cpu(gsl->entries); i++) { - u32 size = le32_to_cpu(gsl->entry[i].size); - uuid_t uuid = gsl->entry[i].uuid; - u8 *log; - - dev_dbg(dev, "Found LOG type %pU of size %d", &uuid, size); - - if (!uuid_equal(&uuid, &log_uuid[CEL_UUID])) - continue; - - log = kvmalloc(size, GFP_KERNEL); - if (!log) { - rc = -ENOMEM; - goto out; - } - - rc = cxl_xfer_log(cxlm, &uuid, size, log); - if (rc) { - kvfree(log); - goto out; - } - - cxl_walk_cel(cxlm, size, log); - kvfree(log); - - /* In case CEL was bogus, enable some default commands. */ - cxl_for_each_cmd(cmd) - if (cmd->flags & CXL_CMD_FLAG_FORCE_ENABLE) - set_bit(cmd->info.id, cxlm->enabled_cmds); - - /* Found the required CEL */ - rc = 0; - } - -out: - kvfree(gsl); - return rc; -} - -/** - * cxl_mem_identify() - Send the IDENTIFY command to the device. - * @cxlm: The device to identify. - * - * Return: 0 if identify was executed successfully. - * - * This will dispatch the identify command to the device and on success populate - * structures to be exported to sysfs. - */ -static int cxl_mem_identify(struct cxl_mem *cxlm) -{ - /* See CXL 2.0 Table 175 Identify Memory Device Output Payload */ - struct cxl_mbox_identify { - char fw_revision[0x10]; - __le64 total_capacity; - __le64 volatile_capacity; - __le64 persistent_capacity; - __le64 partition_align; - __le16 info_event_log_size; - __le16 warning_event_log_size; - __le16 failure_event_log_size; - __le16 fatal_event_log_size; - __le32 lsa_size; - u8 poison_list_max_mer[3]; - __le16 inject_poison_limit; - u8 poison_caps; - u8 qos_telemetry_caps; - } __packed id; - int rc; - - rc = cxl_mem_mbox_send_cmd(cxlm, CXL_MBOX_OP_IDENTIFY, NULL, 0, &id, - sizeof(id)); - if (rc < 0) - return rc; - - cxlm->total_bytes = le64_to_cpu(id.total_capacity); - cxlm->total_bytes *= CXL_CAPACITY_MULTIPLIER; - - cxlm->volatile_only_bytes = le64_to_cpu(id.volatile_capacity); - cxlm->volatile_only_bytes *= CXL_CAPACITY_MULTIPLIER; - - cxlm->persistent_only_bytes = le64_to_cpu(id.persistent_capacity); - cxlm->persistent_only_bytes *= CXL_CAPACITY_MULTIPLIER; - - cxlm->partition_align_bytes = le64_to_cpu(id.partition_align); - cxlm->partition_align_bytes *= CXL_CAPACITY_MULTIPLIER; - - dev_dbg(cxlm->dev, - "Identify Memory Device\n" - " total_bytes = %#llx\n" - " volatile_only_bytes = %#llx\n" - " persistent_only_bytes = %#llx\n" - " partition_align_bytes = %#llx\n", - cxlm->total_bytes, cxlm->volatile_only_bytes, - cxlm->persistent_only_bytes, cxlm->partition_align_bytes); - - cxlm->lsa_size = le32_to_cpu(id.lsa_size); - memcpy(cxlm->firmware_version, id.fw_revision, sizeof(id.fw_revision)); - - return 0; -} - -static int cxl_mem_create_range_info(struct cxl_mem *cxlm) -{ - int rc; - - if (cxlm->partition_align_bytes == 0) { - cxlm->ram_range.start = 0; - cxlm->ram_range.end = cxlm->volatile_only_bytes - 1; - cxlm->pmem_range.start = cxlm->volatile_only_bytes; - cxlm->pmem_range.end = cxlm->volatile_only_bytes + - cxlm->persistent_only_bytes - 1; - return 0; - } - - rc = cxl_mem_get_partition_info(cxlm); - if (rc < 0) { - dev_err(cxlm->dev, "Failed to query partition information\n"); - return rc; - } - - dev_dbg(cxlm->dev, - "Get Partition Info\n" - " active_volatile_bytes = %#llx\n" - " active_persistent_bytes = %#llx\n" - " next_volatile_bytes = %#llx\n" - " next_persistent_bytes = %#llx\n", - cxlm->active_volatile_bytes, cxlm->active_persistent_bytes, - cxlm->next_volatile_bytes, cxlm->next_persistent_bytes); - - cxlm->ram_range.start = 0; - cxlm->ram_range.end = cxlm->active_volatile_bytes - 1; - - cxlm->pmem_range.start = cxlm->active_volatile_bytes; - cxlm->pmem_range.end = cxlm->active_volatile_bytes + - cxlm->active_persistent_bytes - 1; - - return 0; -} - static int cxl_mem_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct cxl_memdev *cxlmd; @@ -1458,7 +545,7 @@ static int cxl_mem_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (rc) return rc; - cxlmd = devm_cxl_add_memdev(cxlm, &cxl_memdev_fops); + cxlmd = devm_cxl_add_memdev(cxlm); if (IS_ERR(cxlmd)) return PTR_ERR(cxlmd); @@ -1486,7 +573,6 @@ static struct pci_driver cxl_mem_driver = { static __init int cxl_mem_init(void) { - struct dentry *mbox_debugfs; int rc; /* Double check the anonymous union trickery in struct cxl_regs */ @@ -1497,17 +583,11 @@ static __init int cxl_mem_init(void) if (rc) return rc; - cxl_debugfs = debugfs_create_dir("cxl", NULL); - mbox_debugfs = debugfs_create_dir("mbox", cxl_debugfs); - debugfs_create_bool("raw_allow_all", 0600, mbox_debugfs, - &cxl_raw_allow_all); - return 0; } static __exit void cxl_mem_exit(void) { - debugfs_remove_recursive(cxl_debugfs); pci_unregister_driver(&cxl_mem_driver); } -- cgit From 5a2328f4e872a5bcbb2ff790497f000e8f79b152 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 8 Sep 2021 22:12:38 -0700 Subject: cxl/pci: Use module_pci_driver Now that cxl_mem_{init,exit} no longer need to manage debugfs, switch back to the smaller form of the boiler plate. Acked-by: Ben Widawsky Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/163116435825.2460985.7201322215431441130.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/cxl/pci.c | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index c9f2ac134f4d..27f75b5a2ee2 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -517,6 +517,13 @@ static int cxl_mem_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct cxl_mem *cxlm; int rc; + /* + * Double check the anonymous union trickery in struct cxl_regs + * FIXME switch to struct_group() + */ + BUILD_BUG_ON(offsetof(struct cxl_regs, memdev) != + offsetof(struct cxl_regs, device_regs.memdev)); + rc = pcim_enable_device(pdev); if (rc) return rc; @@ -571,27 +578,6 @@ static struct pci_driver cxl_mem_driver = { }, }; -static __init int cxl_mem_init(void) -{ - int rc; - - /* Double check the anonymous union trickery in struct cxl_regs */ - BUILD_BUG_ON(offsetof(struct cxl_regs, memdev) != - offsetof(struct cxl_regs, device_regs.memdev)); - - rc = pci_register_driver(&cxl_mem_driver); - if (rc) - return rc; - - return 0; -} - -static __exit void cxl_mem_exit(void) -{ - pci_unregister_driver(&cxl_mem_driver); -} - MODULE_LICENSE("GPL v2"); -module_init(cxl_mem_init); -module_exit(cxl_mem_exit); +module_pci_driver(cxl_mem_driver); MODULE_IMPORT_NS(CXL); -- cgit From ff56ab9e164d71c4a6ae33fc61ae856faec265a1 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 8 Sep 2021 22:12:44 -0700 Subject: cxl/mbox: Convert 'enabled_cmds' to DECLARE_BITMAP Define enabled_cmds as an embedded member of 'struct cxl_mem' rather than a pointer to another dynamic allocation. As this leaves only one user of cxl_cmd_count, just open code it and delete the helper. Acked-by: Ben Widawsky Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/163116436415.2460985.10101824045493194813.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/cxl/core/mbox.c | 12 +----------- drivers/cxl/cxlmem.h | 2 +- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index 31e183991726..422999740649 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -315,8 +315,6 @@ static int cxl_validate_cmd_from_user(struct cxl_mem *cxlm, return 0; } -#define cxl_cmd_count ARRAY_SIZE(cxl_mem_commands) - int cxl_query_cmd(struct cxl_memdev *cxlmd, struct cxl_mem_query_commands __user *q) { @@ -332,7 +330,7 @@ int cxl_query_cmd(struct cxl_memdev *cxlmd, /* returns the total number if 0 elements are requested. */ if (n_commands == 0) - return put_user(cxl_cmd_count, &q->n_commands); + return put_user(ARRAY_SIZE(cxl_mem_commands), &q->n_commands); /* * otherwise, return max(n_commands, total commands) cxl_command_info @@ -794,14 +792,6 @@ struct cxl_mem *cxl_mem_create(struct device *dev) mutex_init(&cxlm->mbox_mutex); cxlm->dev = dev; - cxlm->enabled_cmds = - devm_kmalloc_array(dev, BITS_TO_LONGS(cxl_cmd_count), - sizeof(unsigned long), - GFP_KERNEL | __GFP_ZERO); - if (!cxlm->enabled_cmds) { - dev_err(dev, "No memory available for bitmap\n"); - return ERR_PTR(-ENOMEM); - } return cxlm; } diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index f5d3326a1d0b..8f59a89a0aab 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -126,7 +126,7 @@ struct cxl_mem { size_t lsa_size; struct mutex mbox_mutex; /* Protects device mailbox and firmware */ char firmware_version[0x10]; - unsigned long *enabled_cmds; + DECLARE_BITMAP(enabled_cmds, CXL_MEM_COMMAND_ID_MAX); struct range pmem_range; struct range ram_range; -- cgit From 12f3856ad42d6ce0dbd4266e105c04ae999f908c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 14 Sep 2021 12:03:04 -0700 Subject: cxl/mbox: Add exclusive kernel command support The CXL_PMEM driver expects exclusive control of the label storage area space. Similar to the LIBNVDIMM expectation that the label storage area is only writable from userspace when the corresponding memory device is not active in any region, the expectation is the native CXL_PCI UAPI path is disabled while the cxl_nvdimm for a given cxl_memdev device is active in LIBNVDIMM. Add the ability to toggle the availability of a given command for the UAPI path. Use that new capability to shutdown changes to partitions and the label storage area while the cxl_nvdimm device is actively proxying commands for LIBNVDIMM. Reviewed-by: Ben Widawsky Link: https://lore.kernel.org/r/163164579468.2830966.6980053377428474263.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/cxl/core/mbox.c | 5 +++++ drivers/cxl/core/memdev.c | 32 ++++++++++++++++++++++++++++++++ drivers/cxl/cxlmem.h | 4 ++++ drivers/cxl/pmem.c | 29 ++++++++++++++++++++++++++--- 4 files changed, 67 insertions(+), 3 deletions(-) diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index 422999740649..82e79da195fa 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -221,6 +221,7 @@ static bool cxl_mem_raw_command_allowed(u16 opcode) * * %-EINVAL - Reserved fields or invalid values were used. * * %-ENOMEM - Input or output buffer wasn't sized properly. * * %-EPERM - Attempted to use a protected command. + * * %-EBUSY - Kernel has claimed exclusive access to this opcode * * The result of this command is a fully validated command in @out_cmd that is * safe to send to the hardware. @@ -296,6 +297,10 @@ static int cxl_validate_cmd_from_user(struct cxl_mem *cxlm, if (!test_bit(info->id, cxlm->enabled_cmds)) return -ENOTTY; + /* Check that the command is not claimed for exclusive kernel use */ + if (test_bit(info->id, cxlm->exclusive_cmds)) + return -EBUSY; + /* Check the input buffer is the expected size */ if (info->size_in >= 0 && info->size_in != send_cmd->in.size) return -ENOMEM; diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c index df2ba87238c2..bf1b04d00ff4 100644 --- a/drivers/cxl/core/memdev.c +++ b/drivers/cxl/core/memdev.c @@ -134,6 +134,38 @@ static const struct device_type cxl_memdev_type = { .groups = cxl_memdev_attribute_groups, }; +/** + * set_exclusive_cxl_commands() - atomically disable user cxl commands + * @cxlm: cxl_mem instance to modify + * @cmds: bitmap of commands to mark exclusive + * + * Grab the cxl_memdev_rwsem in write mode to flush in-flight + * invocations of the ioctl path and then disable future execution of + * commands with the command ids set in @cmds. + */ +void set_exclusive_cxl_commands(struct cxl_mem *cxlm, unsigned long *cmds) +{ + down_write(&cxl_memdev_rwsem); + bitmap_or(cxlm->exclusive_cmds, cxlm->exclusive_cmds, cmds, + CXL_MEM_COMMAND_ID_MAX); + up_write(&cxl_memdev_rwsem); +} +EXPORT_SYMBOL_GPL(set_exclusive_cxl_commands); + +/** + * clear_exclusive_cxl_commands() - atomically enable user cxl commands + * @cxlm: cxl_mem instance to modify + * @cmds: bitmap of commands to mark available for userspace + */ +void clear_exclusive_cxl_commands(struct cxl_mem *cxlm, unsigned long *cmds) +{ + down_write(&cxl_memdev_rwsem); + bitmap_andnot(cxlm->exclusive_cmds, cxlm->exclusive_cmds, cmds, + CXL_MEM_COMMAND_ID_MAX); + up_write(&cxl_memdev_rwsem); +} +EXPORT_SYMBOL_GPL(clear_exclusive_cxl_commands); + static void cxl_memdev_shutdown(struct device *dev) { struct cxl_memdev *cxlmd = to_cxl_memdev(dev); diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index 8f59a89a0aab..373add570ef6 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -101,6 +101,7 @@ struct cxl_mbox_cmd { * @mbox_mutex: Mutex to synchronize mailbox access. * @firmware_version: Firmware version for the memory device. * @enabled_cmds: Hardware commands found enabled in CEL. + * @exclusive_cmds: Commands that are kernel-internal only * @pmem_range: Active Persistent memory capacity configuration * @ram_range: Active Volatile memory capacity configuration * @total_bytes: sum of all possible capacities @@ -127,6 +128,7 @@ struct cxl_mem { struct mutex mbox_mutex; /* Protects device mailbox and firmware */ char firmware_version[0x10]; DECLARE_BITMAP(enabled_cmds, CXL_MEM_COMMAND_ID_MAX); + DECLARE_BITMAP(exclusive_cmds, CXL_MEM_COMMAND_ID_MAX); struct range pmem_range; struct range ram_range; @@ -200,4 +202,6 @@ int cxl_mem_identify(struct cxl_mem *cxlm); int cxl_mem_enumerate_cmds(struct cxl_mem *cxlm); int cxl_mem_create_range_info(struct cxl_mem *cxlm); struct cxl_mem *cxl_mem_create(struct device *dev); +void set_exclusive_cxl_commands(struct cxl_mem *cxlm, unsigned long *cmds); +void clear_exclusive_cxl_commands(struct cxl_mem *cxlm, unsigned long *cmds); #endif /* __CXL_MEM_H__ */ diff --git a/drivers/cxl/pmem.c b/drivers/cxl/pmem.c index 9652c3ee41e7..5629289939af 100644 --- a/drivers/cxl/pmem.c +++ b/drivers/cxl/pmem.c @@ -16,6 +16,13 @@ */ static struct workqueue_struct *cxl_pmem_wq; +static __read_mostly DECLARE_BITMAP(exclusive_cmds, CXL_MEM_COMMAND_ID_MAX); + +static void clear_exclusive(void *cxlm) +{ + clear_exclusive_cxl_commands(cxlm, exclusive_cmds); +} + static void unregister_nvdimm(void *nvdimm) { nvdimm_delete(nvdimm); @@ -39,25 +46,37 @@ static struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(void) static int cxl_nvdimm_probe(struct device *dev) { struct cxl_nvdimm *cxl_nvd = to_cxl_nvdimm(dev); + struct cxl_memdev *cxlmd = cxl_nvd->cxlmd; + struct cxl_mem *cxlm = cxlmd->cxlm; struct cxl_nvdimm_bridge *cxl_nvb; unsigned long flags = 0; struct nvdimm *nvdimm; - int rc = -ENXIO; + int rc; cxl_nvb = cxl_find_nvdimm_bridge(); if (!cxl_nvb) return -ENXIO; device_lock(&cxl_nvb->dev); - if (!cxl_nvb->nvdimm_bus) + if (!cxl_nvb->nvdimm_bus) { + rc = -ENXIO; + goto out; + } + + set_exclusive_cxl_commands(cxlm, exclusive_cmds); + rc = devm_add_action_or_reset(dev, clear_exclusive, cxlm); + if (rc) goto out; set_bit(NDD_LABELING, &flags); nvdimm = nvdimm_create(cxl_nvb->nvdimm_bus, cxl_nvd, NULL, flags, 0, 0, NULL); - if (!nvdimm) + if (!nvdimm) { + rc = -ENOMEM; goto out; + } + dev_set_drvdata(dev, nvdimm); rc = devm_add_action_or_reset(dev, unregister_nvdimm, nvdimm); out: device_unlock(&cxl_nvb->dev); @@ -194,6 +213,10 @@ static __init int cxl_pmem_init(void) { int rc; + set_bit(CXL_MEM_COMMAND_ID_SET_PARTITION_INFO, exclusive_cmds); + set_bit(CXL_MEM_COMMAND_ID_SET_SHUTDOWN_STATE, exclusive_cmds); + set_bit(CXL_MEM_COMMAND_ID_SET_LSA, exclusive_cmds); + cxl_pmem_wq = alloc_ordered_workqueue("cxl_pmem", 0); if (!cxl_pmem_wq) return -ENXIO; -- cgit From 60b8f17215de1e6551fec4e942494c3832c3e98b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 9 Sep 2021 15:08:15 -0700 Subject: cxl/pmem: Translate NVDIMM label commands to CXL label commands The LIBNVDIMM IOCTL UAPI calls back to the nvdimm-bus-provider to translate the Linux command payload to the device native command format. The LIBNVDIMM commands get-config-size, get-config-data, and set-config-data, map to the CXL memory device commands device-identify, get-lsa, and set-lsa. Recall that the label-storage-area (LSA) on an NVDIMM device arranges for the provisioning of namespaces. Additionally for CXL the LSA is used for provisioning regions as well. The data from device-identify is already cached in the 'struct cxl_mem' instance associated with @cxl_nvd, so that payload return is simply crafted and no CXL command is issued. The conversion for get-lsa is straightforward, but the conversion for set-lsa requires an allocation to append the set-lsa header in front of the payload. Reviewed-by: Ben Widawsky Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/163122524923.2534512.9431316965424264864.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/cxl/pmem.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 124 insertions(+), 4 deletions(-) diff --git a/drivers/cxl/pmem.c b/drivers/cxl/pmem.c index 5629289939af..bc1466b0e999 100644 --- a/drivers/cxl/pmem.c +++ b/drivers/cxl/pmem.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright(c) 2021 Intel Corporation. All rights reserved. */ #include +#include #include #include #include @@ -47,9 +48,9 @@ static int cxl_nvdimm_probe(struct device *dev) { struct cxl_nvdimm *cxl_nvd = to_cxl_nvdimm(dev); struct cxl_memdev *cxlmd = cxl_nvd->cxlmd; + unsigned long flags = 0, cmd_mask = 0; struct cxl_mem *cxlm = cxlmd->cxlm; struct cxl_nvdimm_bridge *cxl_nvb; - unsigned long flags = 0; struct nvdimm *nvdimm; int rc; @@ -69,8 +70,11 @@ static int cxl_nvdimm_probe(struct device *dev) goto out; set_bit(NDD_LABELING, &flags); - nvdimm = nvdimm_create(cxl_nvb->nvdimm_bus, cxl_nvd, NULL, flags, 0, 0, - NULL); + set_bit(ND_CMD_GET_CONFIG_SIZE, &cmd_mask); + set_bit(ND_CMD_GET_CONFIG_DATA, &cmd_mask); + set_bit(ND_CMD_SET_CONFIG_DATA, &cmd_mask); + nvdimm = nvdimm_create(cxl_nvb->nvdimm_bus, cxl_nvd, NULL, flags, + cmd_mask, 0, NULL); if (!nvdimm) { rc = -ENOMEM; goto out; @@ -91,11 +95,127 @@ static struct cxl_driver cxl_nvdimm_driver = { .id = CXL_DEVICE_NVDIMM, }; +static int cxl_pmem_get_config_size(struct cxl_mem *cxlm, + struct nd_cmd_get_config_size *cmd, + unsigned int buf_len) +{ + if (sizeof(*cmd) > buf_len) + return -EINVAL; + + *cmd = (struct nd_cmd_get_config_size) { + .config_size = cxlm->lsa_size, + .max_xfer = cxlm->payload_size, + }; + + return 0; +} + +static int cxl_pmem_get_config_data(struct cxl_mem *cxlm, + struct nd_cmd_get_config_data_hdr *cmd, + unsigned int buf_len) +{ + struct cxl_mbox_get_lsa { + u32 offset; + u32 length; + } get_lsa; + int rc; + + if (sizeof(*cmd) > buf_len) + return -EINVAL; + if (struct_size(cmd, out_buf, cmd->in_length) > buf_len) + return -EINVAL; + + get_lsa = (struct cxl_mbox_get_lsa) { + .offset = cmd->in_offset, + .length = cmd->in_length, + }; + + rc = cxl_mem_mbox_send_cmd(cxlm, CXL_MBOX_OP_GET_LSA, &get_lsa, + sizeof(get_lsa), cmd->out_buf, + cmd->in_length); + cmd->status = 0; + + return rc; +} + +static int cxl_pmem_set_config_data(struct cxl_mem *cxlm, + struct nd_cmd_set_config_hdr *cmd, + unsigned int buf_len) +{ + struct cxl_mbox_set_lsa { + u32 offset; + u32 reserved; + u8 data[]; + } *set_lsa; + int rc; + + if (sizeof(*cmd) > buf_len) + return -EINVAL; + + /* 4-byte status follows the input data in the payload */ + if (struct_size(cmd, in_buf, cmd->in_length) + 4 > buf_len) + return -EINVAL; + + set_lsa = + kvzalloc(struct_size(set_lsa, data, cmd->in_length), GFP_KERNEL); + if (!set_lsa) + return -ENOMEM; + + *set_lsa = (struct cxl_mbox_set_lsa) { + .offset = cmd->in_offset, + }; + memcpy(set_lsa->data, cmd->in_buf, cmd->in_length); + + rc = cxl_mem_mbox_send_cmd(cxlm, CXL_MBOX_OP_SET_LSA, set_lsa, + struct_size(set_lsa, data, cmd->in_length), + NULL, 0); + + /* + * Set "firmware" status (4-packed bytes at the end of the input + * payload. + */ + put_unaligned(0, (u32 *) &cmd->in_buf[cmd->in_length]); + kvfree(set_lsa); + + return rc; +} + +static int cxl_pmem_nvdimm_ctl(struct nvdimm *nvdimm, unsigned int cmd, + void *buf, unsigned int buf_len) +{ + struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm); + unsigned long cmd_mask = nvdimm_cmd_mask(nvdimm); + struct cxl_memdev *cxlmd = cxl_nvd->cxlmd; + struct cxl_mem *cxlm = cxlmd->cxlm; + + if (!test_bit(cmd, &cmd_mask)) + return -ENOTTY; + + switch (cmd) { + case ND_CMD_GET_CONFIG_SIZE: + return cxl_pmem_get_config_size(cxlm, buf, buf_len); + case ND_CMD_GET_CONFIG_DATA: + return cxl_pmem_get_config_data(cxlm, buf, buf_len); + case ND_CMD_SET_CONFIG_DATA: + return cxl_pmem_set_config_data(cxlm, buf, buf_len); + default: + return -ENOTTY; + } +} + static int cxl_pmem_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, unsigned int cmd, void *buf, unsigned int buf_len, int *cmd_rc) { - return -ENOTTY; + /* + * No firmware response to translate, let the transport error + * code take precedence. + */ + *cmd_rc = 0; + + if (!nvdimm) + return -ENOTTY; + return cxl_pmem_nvdimm_ctl(nvdimm, cmd, buf, buf_len); } static bool online_nvdimm_bus(struct cxl_nvdimm_bridge *cxl_nvb) -- cgit From 2e52b6256b9af23c5a881f56b5b5e7f5cb9b8b4b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 14 Sep 2021 12:08:40 -0700 Subject: cxl/pmem: Add support for multiple nvdimm-bridge objects In preparation for a mocked unit test environment for CXL objects, allow for multiple unique nvdimm-bridge objects. For now, just allow multiple bridges to be registered. Later, when there are multiple present, further updates are needed to cxl_find_nvdimm_bridge() to identify which bridge is associated with which CXL hierarchy for nvdimm registration. Note that this does change the kernel device-name for the bridge object. User space should not have any attachment to the device name at this point as it is still early days in the CXL driver development. Acked-by: Ben Widawsky Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/163164647007.2831228.2150246954620721526.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/cxl/core/pmem.c | 32 +++++++++++++++++++++++++++++++- drivers/cxl/cxl.h | 2 ++ drivers/cxl/pmem.c | 15 --------------- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/drivers/cxl/core/pmem.c b/drivers/cxl/core/pmem.c index d24570f5b8ba..9e56be3994f1 100644 --- a/drivers/cxl/core/pmem.c +++ b/drivers/cxl/core/pmem.c @@ -2,6 +2,7 @@ /* Copyright(c) 2020 Intel Corporation. */ #include #include +#include #include #include #include "core.h" @@ -20,10 +21,13 @@ * operations, for example, namespace label access commands. */ +static DEFINE_IDA(cxl_nvdimm_bridge_ida); + static void cxl_nvdimm_bridge_release(struct device *dev) { struct cxl_nvdimm_bridge *cxl_nvb = to_cxl_nvdimm_bridge(dev); + ida_free(&cxl_nvdimm_bridge_ida, cxl_nvb->id); kfree(cxl_nvb); } @@ -47,16 +51,38 @@ struct cxl_nvdimm_bridge *to_cxl_nvdimm_bridge(struct device *dev) } EXPORT_SYMBOL_GPL(to_cxl_nvdimm_bridge); +static int match_nvdimm_bridge(struct device *dev, const void *data) +{ + return dev->type == &cxl_nvdimm_bridge_type; +} + +struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(void) +{ + struct device *dev; + + dev = bus_find_device(&cxl_bus_type, NULL, NULL, match_nvdimm_bridge); + if (!dev) + return NULL; + return to_cxl_nvdimm_bridge(dev); +} +EXPORT_SYMBOL_GPL(cxl_find_nvdimm_bridge); + static struct cxl_nvdimm_bridge * cxl_nvdimm_bridge_alloc(struct cxl_port *port) { struct cxl_nvdimm_bridge *cxl_nvb; struct device *dev; + int rc; cxl_nvb = kzalloc(sizeof(*cxl_nvb), GFP_KERNEL); if (!cxl_nvb) return ERR_PTR(-ENOMEM); + rc = ida_alloc(&cxl_nvdimm_bridge_ida, GFP_KERNEL); + if (rc < 0) + goto err; + cxl_nvb->id = rc; + dev = &cxl_nvb->dev; cxl_nvb->port = port; cxl_nvb->state = CXL_NVB_NEW; @@ -67,6 +93,10 @@ cxl_nvdimm_bridge_alloc(struct cxl_port *port) dev->type = &cxl_nvdimm_bridge_type; return cxl_nvb; + +err: + kfree(cxl_nvb); + return ERR_PTR(rc); } static void unregister_nvb(void *_cxl_nvb) @@ -119,7 +149,7 @@ struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host, return cxl_nvb; dev = &cxl_nvb->dev; - rc = dev_set_name(dev, "nvdimm-bridge"); + rc = dev_set_name(dev, "nvdimm-bridge%d", cxl_nvb->id); if (rc) goto err; diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 53927f9fa77e..1b2e816e061e 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -211,6 +211,7 @@ enum cxl_nvdimm_brige_state { }; struct cxl_nvdimm_bridge { + int id; struct device dev; struct cxl_port *port; struct nvdimm_bus *nvdimm_bus; @@ -323,4 +324,5 @@ struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host, struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev); bool is_cxl_nvdimm(struct device *dev); int devm_cxl_add_nvdimm(struct device *host, struct cxl_memdev *cxlmd); +struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(void); #endif /* __CXL_H__ */ diff --git a/drivers/cxl/pmem.c b/drivers/cxl/pmem.c index bc1466b0e999..5ccf9aa6b3ae 100644 --- a/drivers/cxl/pmem.c +++ b/drivers/cxl/pmem.c @@ -29,21 +29,6 @@ static void unregister_nvdimm(void *nvdimm) nvdimm_delete(nvdimm); } -static int match_nvdimm_bridge(struct device *dev, const void *data) -{ - return strcmp(dev_name(dev), "nvdimm-bridge") == 0; -} - -static struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(void) -{ - struct device *dev; - - dev = bus_find_device(&cxl_bus_type, NULL, NULL, match_nvdimm_bridge); - if (!dev) - return NULL; - return to_cxl_nvdimm_bridge(dev); -} - static int cxl_nvdimm_probe(struct device *dev) { struct cxl_nvdimm *cxl_nvd = to_cxl_nvdimm(dev); -- cgit From 67dcdd4d3b832ace448f454c47426f657d648fc5 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 14 Sep 2021 12:14:22 -0700 Subject: tools/testing/cxl: Introduce a mocked-up CXL port hierarchy Create an environment for CXL plumbing unit tests. Especially when it comes to an algorithm for HDM Decoder (Host-managed Device Memory Decoder) programming, the availability of an in-kernel-tree emulation environment for CXL configuration complexity and corner cases speeds development and deters regressions. The approach taken mirrors what was done for tools/testing/nvdimm/. I.e. an external module, cxl_test.ko built out of the tools/testing/cxl/ directory, provides mock implementations of kernel APIs and kernel objects to simulate a real world device hierarchy. One feedback for the tools/testing/nvdimm/ proposal was "why not do this in QEMU?". In fact, the CXL development community has developed a QEMU model for CXL [1]. However, there are a few blocking issues that keep QEMU from being a tight fit for topology + provisioning unit tests: 1/ The QEMU community has yet to show interest in merging any of this support that has had patches on the list since November 2020. So, testing CXL to date involves building custom QEMU with out-of-tree patches. 2/ CXL mechanisms like cross-host-bridge interleave do not have a clear path to be emulated by QEMU without major infrastructure work. This is easier to achieve with the alloc_mock_res() approach taken in this patch to shortcut-define emulated system physical address ranges with interleave behavior. The QEMU enabling has been critical to get the driver off the ground, and may still move forward, but it does not address the ongoing needs of a regression testing environment and test driven development. This patch adds an ACPI CXL Platform definition with emulated CXL multi-ported host-bridges. A follow on patch adds emulated memory expander devices. Acked-by: Ben Widawsky Reported-by: Vishal Verma Link: https://lore.kernel.org/r/20210202005948.241655-1-ben.widawsky@intel.com [1] Link: https://lore.kernel.org/r/163164680798.2831381.838684634806668012.stgit@dwillia2-desk3.amr.corp.intel.com Reviewed-by: Jonathan Cameron Signed-off-by: Dan Williams --- drivers/cxl/acpi.c | 36 +-- drivers/cxl/cxl.h | 16 ++ tools/testing/cxl/Kbuild | 36 +++ tools/testing/cxl/config_check.c | 13 + tools/testing/cxl/mock_acpi.c | 109 +++++++++ tools/testing/cxl/test/Kbuild | 6 + tools/testing/cxl/test/cxl.c | 509 +++++++++++++++++++++++++++++++++++++++ tools/testing/cxl/test/mock.c | 171 +++++++++++++ tools/testing/cxl/test/mock.h | 27 +++ 9 files changed, 908 insertions(+), 15 deletions(-) create mode 100644 tools/testing/cxl/Kbuild create mode 100644 tools/testing/cxl/config_check.c create mode 100644 tools/testing/cxl/mock_acpi.c create mode 100644 tools/testing/cxl/test/Kbuild create mode 100644 tools/testing/cxl/test/cxl.c create mode 100644 tools/testing/cxl/test/mock.c create mode 100644 tools/testing/cxl/test/mock.h diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c index 54e9d4d2cf5f..32775d1ac4b3 100644 --- a/drivers/cxl/acpi.c +++ b/drivers/cxl/acpi.c @@ -182,15 +182,7 @@ static resource_size_t get_chbcr(struct acpi_cedt_chbs *chbs) return IS_ERR(chbs) ? CXL_RESOURCE_NONE : chbs->base; } -struct cxl_walk_context { - struct device *dev; - struct pci_bus *root; - struct cxl_port *port; - int error; - int count; -}; - -static int match_add_root_ports(struct pci_dev *pdev, void *data) +__mock int match_add_root_ports(struct pci_dev *pdev, void *data) { struct cxl_walk_context *ctx = data; struct pci_bus *root_bus = ctx->root; @@ -239,7 +231,8 @@ static struct cxl_dport *find_dport_by_dev(struct cxl_port *port, struct device return NULL; } -static struct acpi_device *to_cxl_host_bridge(struct device *dev) +__mock struct acpi_device *to_cxl_host_bridge(struct device *host, + struct device *dev) { struct acpi_device *adev = to_acpi_device(dev); @@ -257,9 +250,9 @@ static struct acpi_device *to_cxl_host_bridge(struct device *dev) */ static int add_host_bridge_uport(struct device *match, void *arg) { - struct acpi_device *bridge = to_cxl_host_bridge(match); struct cxl_port *root_port = arg; struct device *host = root_port->dev.parent; + struct acpi_device *bridge = to_cxl_host_bridge(host, match); struct acpi_pci_root *pci_root; struct cxl_walk_context ctx; struct cxl_decoder *cxld; @@ -323,7 +316,7 @@ static int add_host_bridge_dport(struct device *match, void *arg) struct acpi_cedt_chbs *chbs; struct cxl_port *root_port = arg; struct device *host = root_port->dev.parent; - struct acpi_device *bridge = to_cxl_host_bridge(match); + struct acpi_device *bridge = to_cxl_host_bridge(host, match); if (!bridge) return 0; @@ -375,6 +368,17 @@ static int add_root_nvdimm_bridge(struct device *match, void *data) return 1; } +static u32 cedt_instance(struct platform_device *pdev) +{ + const bool *native_acpi0017 = acpi_device_get_match_data(&pdev->dev); + + if (native_acpi0017 && *native_acpi0017) + return 0; + + /* for cxl_test request a non-canonical instance */ + return U32_MAX; +} + static int cxl_acpi_probe(struct platform_device *pdev) { int rc; @@ -388,7 +392,7 @@ static int cxl_acpi_probe(struct platform_device *pdev) return PTR_ERR(root_port); dev_dbg(host, "add: %s\n", dev_name(&root_port->dev)); - status = acpi_get_table(ACPI_SIG_CEDT, 0, &acpi_cedt); + status = acpi_get_table(ACPI_SIG_CEDT, cedt_instance(pdev), &acpi_cedt); if (ACPI_FAILURE(status)) return -ENXIO; @@ -419,9 +423,11 @@ out: return 0; } +static bool native_acpi0017 = true; + static const struct acpi_device_id cxl_acpi_ids[] = { - { "ACPI0017", 0 }, - { "", 0 }, + { "ACPI0017", (unsigned long) &native_acpi0017 }, + { }, }; MODULE_DEVICE_TABLE(acpi, cxl_acpi_ids); diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 1b2e816e061e..c5152718267e 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -226,6 +226,14 @@ struct cxl_nvdimm { struct nvdimm *nvdimm; }; +struct cxl_walk_context { + struct device *dev; + struct pci_bus *root; + struct cxl_port *port; + int error; + int count; +}; + /** * struct cxl_port - logical collection of upstream port devices and * downstream port devices to construct a CXL memory @@ -325,4 +333,12 @@ struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev); bool is_cxl_nvdimm(struct device *dev); int devm_cxl_add_nvdimm(struct device *host, struct cxl_memdev *cxlmd); struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(void); + +/* + * Unit test builds overrides this to __weak, find the 'strong' version + * of these symbols in tools/testing/cxl/. + */ +#ifndef __mock +#define __mock static +#endif #endif /* __CXL_H__ */ diff --git a/tools/testing/cxl/Kbuild b/tools/testing/cxl/Kbuild new file mode 100644 index 000000000000..63a4a07e71c4 --- /dev/null +++ b/tools/testing/cxl/Kbuild @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: GPL-2.0 +ldflags-y += --wrap=is_acpi_device_node +ldflags-y += --wrap=acpi_get_table +ldflags-y += --wrap=acpi_put_table +ldflags-y += --wrap=acpi_evaluate_integer +ldflags-y += --wrap=acpi_pci_find_root +ldflags-y += --wrap=pci_walk_bus +ldflags-y += --wrap=nvdimm_bus_register + +DRIVERS := ../../../drivers +CXL_SRC := $(DRIVERS)/cxl +CXL_CORE_SRC := $(DRIVERS)/cxl/core +ccflags-y := -I$(srctree)/drivers/cxl/ +ccflags-y += -D__mock=__weak + +obj-m += cxl_acpi.o + +cxl_acpi-y := $(CXL_SRC)/acpi.o +cxl_acpi-y += mock_acpi.o +cxl_acpi-y += config_check.o + +obj-m += cxl_pmem.o + +cxl_pmem-y := $(CXL_SRC)/pmem.o +cxl_pmem-y += config_check.o + +obj-m += cxl_core.o + +cxl_core-y := $(CXL_CORE_SRC)/bus.o +cxl_core-y += $(CXL_CORE_SRC)/pmem.o +cxl_core-y += $(CXL_CORE_SRC)/regs.o +cxl_core-y += $(CXL_CORE_SRC)/memdev.o +cxl_core-y += $(CXL_CORE_SRC)/mbox.o +cxl_core-y += config_check.o + +obj-m += test/ diff --git a/tools/testing/cxl/config_check.c b/tools/testing/cxl/config_check.c new file mode 100644 index 000000000000..de5e5b3652fd --- /dev/null +++ b/tools/testing/cxl/config_check.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 +#include + +void check(void) +{ + /* + * These kconfig symbols must be set to "m" for cxl_test to load + * and operate. + */ + BUILD_BUG_ON(!IS_MODULE(CONFIG_CXL_BUS)); + BUILD_BUG_ON(!IS_MODULE(CONFIG_CXL_ACPI)); + BUILD_BUG_ON(!IS_MODULE(CONFIG_CXL_PMEM)); +} diff --git a/tools/testing/cxl/mock_acpi.c b/tools/testing/cxl/mock_acpi.c new file mode 100644 index 000000000000..4c8a493ace56 --- /dev/null +++ b/tools/testing/cxl/mock_acpi.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2021 Intel Corporation. All rights reserved. */ + +#include +#include +#include +#include +#include +#include "test/mock.h" + +struct acpi_device *to_cxl_host_bridge(struct device *host, struct device *dev) +{ + int index; + struct acpi_device *adev, *found = NULL; + struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); + + if (ops && ops->is_mock_bridge(dev)) { + found = ACPI_COMPANION(dev); + goto out; + } + + if (dev->bus == &platform_bus_type) + goto out; + + adev = to_acpi_device(dev); + if (!acpi_pci_find_root(adev->handle)) + goto out; + + if (strcmp(acpi_device_hid(adev), "ACPI0016") == 0) { + found = adev; + dev_dbg(host, "found host bridge %s\n", dev_name(&adev->dev)); + } +out: + put_cxl_mock_ops(index); + return found; +} + +static int match_add_root_port(struct pci_dev *pdev, void *data) +{ + struct cxl_walk_context *ctx = data; + struct pci_bus *root_bus = ctx->root; + struct cxl_port *port = ctx->port; + int type = pci_pcie_type(pdev); + struct device *dev = ctx->dev; + u32 lnkcap, port_num; + int rc; + + if (pdev->bus != root_bus) + return 0; + if (!pci_is_pcie(pdev)) + return 0; + if (type != PCI_EXP_TYPE_ROOT_PORT) + return 0; + if (pci_read_config_dword(pdev, pci_pcie_cap(pdev) + PCI_EXP_LNKCAP, + &lnkcap) != PCIBIOS_SUCCESSFUL) + return 0; + + /* TODO walk DVSEC to find component register base */ + port_num = FIELD_GET(PCI_EXP_LNKCAP_PN, lnkcap); + rc = cxl_add_dport(port, &pdev->dev, port_num, CXL_RESOURCE_NONE); + if (rc) { + dev_err(dev, "failed to add dport: %s (%d)\n", + dev_name(&pdev->dev), rc); + ctx->error = rc; + return rc; + } + ctx->count++; + + dev_dbg(dev, "add dport%d: %s\n", port_num, dev_name(&pdev->dev)); + + return 0; +} + +static int mock_add_root_port(struct platform_device *pdev, void *data) +{ + struct cxl_walk_context *ctx = data; + struct cxl_port *port = ctx->port; + struct device *dev = ctx->dev; + int rc; + + rc = cxl_add_dport(port, &pdev->dev, pdev->id, CXL_RESOURCE_NONE); + if (rc) { + dev_err(dev, "failed to add dport: %s (%d)\n", + dev_name(&pdev->dev), rc); + ctx->error = rc; + return rc; + } + ctx->count++; + + dev_dbg(dev, "add dport%d: %s\n", pdev->id, dev_name(&pdev->dev)); + + return 0; +} + +int match_add_root_ports(struct pci_dev *dev, void *data) +{ + int index, rc; + struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); + struct platform_device *pdev = (struct platform_device *) dev; + + if (ops && ops->is_mock_port(pdev)) + rc = mock_add_root_port(pdev, data); + else + rc = match_add_root_port(dev, data); + + put_cxl_mock_ops(index); + + return rc; +} diff --git a/tools/testing/cxl/test/Kbuild b/tools/testing/cxl/test/Kbuild new file mode 100644 index 000000000000..7de4ddecfd21 --- /dev/null +++ b/tools/testing/cxl/test/Kbuild @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-m += cxl_test.o +obj-m += cxl_mock.o + +cxl_test-y := cxl.o +cxl_mock-y := mock.o diff --git a/tools/testing/cxl/test/cxl.c b/tools/testing/cxl/test/cxl.c new file mode 100644 index 000000000000..1c47b34244a4 --- /dev/null +++ b/tools/testing/cxl/test/cxl.c @@ -0,0 +1,509 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright(c) 2021 Intel Corporation. All rights reserved. + +#include +#include +#include +#include +#include +#include +#include +#include "mock.h" + +#define NR_CXL_HOST_BRIDGES 4 +#define NR_CXL_ROOT_PORTS 2 + +static struct platform_device *cxl_acpi; +static struct platform_device *cxl_host_bridge[NR_CXL_HOST_BRIDGES]; +static struct platform_device + *cxl_root_port[NR_CXL_HOST_BRIDGES * NR_CXL_ROOT_PORTS]; + +static struct acpi_device acpi0017_mock; +static struct acpi_device host_bridge[NR_CXL_HOST_BRIDGES] = { + [0] = { + .handle = &host_bridge[0], + }, + [1] = { + .handle = &host_bridge[1], + }, + [2] = { + .handle = &host_bridge[2], + }, + [3] = { + .handle = &host_bridge[3], + }, +}; + +static bool is_mock_dev(struct device *dev) +{ + if (dev == &cxl_acpi->dev) + return true; + return false; +} + +static bool is_mock_adev(struct acpi_device *adev) +{ + int i; + + if (adev == &acpi0017_mock) + return true; + + for (i = 0; i < ARRAY_SIZE(host_bridge); i++) + if (adev == &host_bridge[i]) + return true; + + return false; +} + +static struct { + struct acpi_table_cedt cedt; + struct acpi_cedt_chbs chbs[NR_CXL_HOST_BRIDGES]; + struct { + struct acpi_cedt_cfmws cfmws; + u32 target[1]; + } cfmws0; + struct { + struct acpi_cedt_cfmws cfmws; + u32 target[4]; + } cfmws1; + struct { + struct acpi_cedt_cfmws cfmws; + u32 target[1]; + } cfmws2; + struct { + struct acpi_cedt_cfmws cfmws; + u32 target[4]; + } cfmws3; +} __packed mock_cedt = { + .cedt = { + .header = { + .signature = "CEDT", + .length = sizeof(mock_cedt), + .revision = 1, + }, + }, + .chbs[0] = { + .header = { + .type = ACPI_CEDT_TYPE_CHBS, + .length = sizeof(mock_cedt.chbs[0]), + }, + .uid = 0, + .cxl_version = ACPI_CEDT_CHBS_VERSION_CXL20, + }, + .chbs[1] = { + .header = { + .type = ACPI_CEDT_TYPE_CHBS, + .length = sizeof(mock_cedt.chbs[0]), + }, + .uid = 1, + .cxl_version = ACPI_CEDT_CHBS_VERSION_CXL20, + }, + .chbs[2] = { + .header = { + .type = ACPI_CEDT_TYPE_CHBS, + .length = sizeof(mock_cedt.chbs[0]), + }, + .uid = 2, + .cxl_version = ACPI_CEDT_CHBS_VERSION_CXL20, + }, + .chbs[3] = { + .header = { + .type = ACPI_CEDT_TYPE_CHBS, + .length = sizeof(mock_cedt.chbs[0]), + }, + .uid = 3, + .cxl_version = ACPI_CEDT_CHBS_VERSION_CXL20, + }, + .cfmws0 = { + .cfmws = { + .header = { + .type = ACPI_CEDT_TYPE_CFMWS, + .length = sizeof(mock_cedt.cfmws0), + }, + .interleave_ways = 0, + .granularity = 4, + .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 | + ACPI_CEDT_CFMWS_RESTRICT_VOLATILE, + .qtg_id = 0, + .window_size = SZ_256M, + }, + .target = { 0 }, + }, + .cfmws1 = { + .cfmws = { + .header = { + .type = ACPI_CEDT_TYPE_CFMWS, + .length = sizeof(mock_cedt.cfmws1), + }, + .interleave_ways = 2, + .granularity = 4, + .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 | + ACPI_CEDT_CFMWS_RESTRICT_VOLATILE, + .qtg_id = 1, + .window_size = SZ_256M * 4, + }, + .target = { 0, 1, 2, 3 }, + }, + .cfmws2 = { + .cfmws = { + .header = { + .type = ACPI_CEDT_TYPE_CFMWS, + .length = sizeof(mock_cedt.cfmws2), + }, + .interleave_ways = 0, + .granularity = 4, + .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 | + ACPI_CEDT_CFMWS_RESTRICT_PMEM, + .qtg_id = 2, + .window_size = SZ_256M, + }, + .target = { 0 }, + }, + .cfmws3 = { + .cfmws = { + .header = { + .type = ACPI_CEDT_TYPE_CFMWS, + .length = sizeof(mock_cedt.cfmws3), + }, + .interleave_ways = 2, + .granularity = 4, + .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 | + ACPI_CEDT_CFMWS_RESTRICT_PMEM, + .qtg_id = 3, + .window_size = SZ_256M * 4, + }, + .target = { 0, 1, 2, 3 }, + }, +}; + +struct cxl_mock_res { + struct list_head list; + struct range range; +}; + +static LIST_HEAD(mock_res); +static DEFINE_MUTEX(mock_res_lock); +static struct gen_pool *cxl_mock_pool; + +static void depopulate_all_mock_resources(void) +{ + struct cxl_mock_res *res, *_res; + + mutex_lock(&mock_res_lock); + list_for_each_entry_safe(res, _res, &mock_res, list) { + gen_pool_free(cxl_mock_pool, res->range.start, + range_len(&res->range)); + list_del(&res->list); + kfree(res); + } + mutex_unlock(&mock_res_lock); +} + +static struct cxl_mock_res *alloc_mock_res(resource_size_t size) +{ + struct cxl_mock_res *res = kzalloc(sizeof(*res), GFP_KERNEL); + struct genpool_data_align data = { + .align = SZ_256M, + }; + unsigned long phys; + + INIT_LIST_HEAD(&res->list); + phys = gen_pool_alloc_algo(cxl_mock_pool, size, + gen_pool_first_fit_align, &data); + if (!phys) + return NULL; + + res->range = (struct range) { + .start = phys, + .end = phys + size - 1, + }; + mutex_lock(&mock_res_lock); + list_add(&res->list, &mock_res); + mutex_unlock(&mock_res_lock); + + return res; +} + +static int populate_cedt(void) +{ + struct acpi_cedt_cfmws *cfmws[4] = { + [0] = &mock_cedt.cfmws0.cfmws, + [1] = &mock_cedt.cfmws1.cfmws, + [2] = &mock_cedt.cfmws2.cfmws, + [3] = &mock_cedt.cfmws3.cfmws, + }; + struct cxl_mock_res *res; + int i; + + for (i = 0; i < ARRAY_SIZE(mock_cedt.chbs); i++) { + struct acpi_cedt_chbs *chbs = &mock_cedt.chbs[i]; + resource_size_t size; + + if (chbs->cxl_version == ACPI_CEDT_CHBS_VERSION_CXL20) + size = ACPI_CEDT_CHBS_LENGTH_CXL20; + else + size = ACPI_CEDT_CHBS_LENGTH_CXL11; + + res = alloc_mock_res(size); + if (!res) + return -ENOMEM; + chbs->base = res->range.start; + chbs->length = size; + } + + for (i = 0; i < ARRAY_SIZE(cfmws); i++) { + struct acpi_cedt_cfmws *window = cfmws[i]; + + res = alloc_mock_res(window->window_size); + if (!res) + return -ENOMEM; + window->base_hpa = res->range.start; + } + + return 0; +} + +static acpi_status mock_acpi_get_table(char *signature, u32 instance, + struct acpi_table_header **out_table) +{ + if (instance < U32_MAX || strcmp(signature, ACPI_SIG_CEDT) != 0) + return acpi_get_table(signature, instance, out_table); + + *out_table = (struct acpi_table_header *) &mock_cedt; + return AE_OK; +} + +static void mock_acpi_put_table(struct acpi_table_header *table) +{ + if (table == (struct acpi_table_header *) &mock_cedt) + return; + acpi_put_table(table); +} + +static bool is_mock_bridge(struct device *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cxl_host_bridge); i++) + if (dev == &cxl_host_bridge[i]->dev) + return true; + + return false; +} + +static int host_bridge_index(struct acpi_device *adev) +{ + return adev - host_bridge; +} + +static struct acpi_device *find_host_bridge(acpi_handle handle) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(host_bridge); i++) + if (handle == host_bridge[i].handle) + return &host_bridge[i]; + return NULL; +} + +static acpi_status +mock_acpi_evaluate_integer(acpi_handle handle, acpi_string pathname, + struct acpi_object_list *arguments, + unsigned long long *data) +{ + struct acpi_device *adev = find_host_bridge(handle); + + if (!adev || strcmp(pathname, METHOD_NAME__UID) != 0) + return acpi_evaluate_integer(handle, pathname, arguments, data); + + *data = host_bridge_index(adev); + return AE_OK; +} + +static struct pci_bus mock_pci_bus[NR_CXL_HOST_BRIDGES]; +static struct acpi_pci_root mock_pci_root[NR_CXL_HOST_BRIDGES] = { + [0] = { + .bus = &mock_pci_bus[0], + }, + [1] = { + .bus = &mock_pci_bus[1], + }, + [2] = { + .bus = &mock_pci_bus[2], + }, + [3] = { + .bus = &mock_pci_bus[3], + }, +}; + +static struct platform_device *mock_cxl_root_port(struct pci_bus *bus, int index) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mock_pci_bus); i++) + if (bus == &mock_pci_bus[i]) + return cxl_root_port[index + i * NR_CXL_ROOT_PORTS]; + return NULL; +} + +static bool is_mock_port(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cxl_root_port); i++) + if (pdev == cxl_root_port[i]) + return true; + return false; +} + +static bool is_mock_bus(struct pci_bus *bus) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mock_pci_bus); i++) + if (bus == &mock_pci_bus[i]) + return true; + return false; +} + +static struct acpi_pci_root *mock_acpi_pci_find_root(acpi_handle handle) +{ + struct acpi_device *adev = find_host_bridge(handle); + + if (!adev) + return acpi_pci_find_root(handle); + return &mock_pci_root[host_bridge_index(adev)]; +} + +static struct cxl_mock_ops cxl_mock_ops = { + .is_mock_adev = is_mock_adev, + .is_mock_bridge = is_mock_bridge, + .is_mock_bus = is_mock_bus, + .is_mock_port = is_mock_port, + .is_mock_dev = is_mock_dev, + .mock_port = mock_cxl_root_port, + .acpi_get_table = mock_acpi_get_table, + .acpi_put_table = mock_acpi_put_table, + .acpi_evaluate_integer = mock_acpi_evaluate_integer, + .acpi_pci_find_root = mock_acpi_pci_find_root, + .list = LIST_HEAD_INIT(cxl_mock_ops.list), +}; + +static void mock_companion(struct acpi_device *adev, struct device *dev) +{ + device_initialize(&adev->dev); + fwnode_init(&adev->fwnode, NULL); + dev->fwnode = &adev->fwnode; + adev->fwnode.dev = dev; +} + +#ifndef SZ_64G +#define SZ_64G (SZ_32G * 2) +#endif + +#ifndef SZ_512G +#define SZ_512G (SZ_64G * 8) +#endif + +static __init int cxl_test_init(void) +{ + int rc, i; + + register_cxl_mock_ops(&cxl_mock_ops); + + cxl_mock_pool = gen_pool_create(ilog2(SZ_2M), NUMA_NO_NODE); + if (!cxl_mock_pool) { + rc = -ENOMEM; + goto err_gen_pool_create; + } + + rc = gen_pool_add(cxl_mock_pool, SZ_512G, SZ_64G, NUMA_NO_NODE); + if (rc) + goto err_gen_pool_add; + + rc = populate_cedt(); + if (rc) + goto err_populate; + + for (i = 0; i < ARRAY_SIZE(cxl_host_bridge); i++) { + struct acpi_device *adev = &host_bridge[i]; + struct platform_device *pdev; + + pdev = platform_device_alloc("cxl_host_bridge", i); + if (!pdev) + goto err_bridge; + + mock_companion(adev, &pdev->dev); + rc = platform_device_add(pdev); + if (rc) { + platform_device_put(pdev); + goto err_bridge; + } + cxl_host_bridge[i] = pdev; + } + + for (i = 0; i < ARRAY_SIZE(cxl_root_port); i++) { + struct platform_device *bridge = + cxl_host_bridge[i / NR_CXL_ROOT_PORTS]; + struct platform_device *pdev; + + pdev = platform_device_alloc("cxl_root_port", i); + if (!pdev) + goto err_port; + pdev->dev.parent = &bridge->dev; + + rc = platform_device_add(pdev); + if (rc) { + platform_device_put(pdev); + goto err_port; + } + cxl_root_port[i] = pdev; + } + + cxl_acpi = platform_device_alloc("cxl_acpi", 0); + if (!cxl_acpi) + goto err_port; + + mock_companion(&acpi0017_mock, &cxl_acpi->dev); + acpi0017_mock.dev.bus = &platform_bus_type; + + rc = platform_device_add(cxl_acpi); + if (rc) + goto err_add; + + return 0; + +err_add: + platform_device_put(cxl_acpi); +err_port: + for (i = ARRAY_SIZE(cxl_root_port) - 1; i >= 0; i--) + platform_device_unregister(cxl_root_port[i]); +err_bridge: + for (i = ARRAY_SIZE(cxl_host_bridge) - 1; i >= 0; i--) + platform_device_unregister(cxl_host_bridge[i]); +err_populate: + depopulate_all_mock_resources(); +err_gen_pool_add: + gen_pool_destroy(cxl_mock_pool); +err_gen_pool_create: + unregister_cxl_mock_ops(&cxl_mock_ops); + return rc; +} + +static __exit void cxl_test_exit(void) +{ + int i; + + platform_device_unregister(cxl_acpi); + for (i = ARRAY_SIZE(cxl_root_port) - 1; i >= 0; i--) + platform_device_unregister(cxl_root_port[i]); + for (i = ARRAY_SIZE(cxl_host_bridge) - 1; i >= 0; i--) + platform_device_unregister(cxl_host_bridge[i]); + depopulate_all_mock_resources(); + gen_pool_destroy(cxl_mock_pool); + unregister_cxl_mock_ops(&cxl_mock_ops); +} + +module_init(cxl_test_init); +module_exit(cxl_test_exit); +MODULE_LICENSE("GPL v2"); diff --git a/tools/testing/cxl/test/mock.c b/tools/testing/cxl/test/mock.c new file mode 100644 index 000000000000..b8c108abcf07 --- /dev/null +++ b/tools/testing/cxl/test/mock.c @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: GPL-2.0-only +//Copyright(c) 2021 Intel Corporation. All rights reserved. + +#include +#include +#include +#include +#include +#include +#include "mock.h" + +static LIST_HEAD(mock); + +void register_cxl_mock_ops(struct cxl_mock_ops *ops) +{ + list_add_rcu(&ops->list, &mock); +} +EXPORT_SYMBOL_GPL(register_cxl_mock_ops); + +static DEFINE_SRCU(cxl_mock_srcu); + +void unregister_cxl_mock_ops(struct cxl_mock_ops *ops) +{ + list_del_rcu(&ops->list); + synchronize_srcu(&cxl_mock_srcu); +} +EXPORT_SYMBOL_GPL(unregister_cxl_mock_ops); + +struct cxl_mock_ops *get_cxl_mock_ops(int *index) +{ + *index = srcu_read_lock(&cxl_mock_srcu); + return list_first_or_null_rcu(&mock, struct cxl_mock_ops, list); +} +EXPORT_SYMBOL_GPL(get_cxl_mock_ops); + +void put_cxl_mock_ops(int index) +{ + srcu_read_unlock(&cxl_mock_srcu, index); +} +EXPORT_SYMBOL_GPL(put_cxl_mock_ops); + +bool __wrap_is_acpi_device_node(const struct fwnode_handle *fwnode) +{ + struct acpi_device *adev = + container_of(fwnode, struct acpi_device, fwnode); + int index; + struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); + bool retval = false; + + if (ops) + retval = ops->is_mock_adev(adev); + + if (!retval) + retval = is_acpi_device_node(fwnode); + + put_cxl_mock_ops(index); + return retval; +} +EXPORT_SYMBOL(__wrap_is_acpi_device_node); + +acpi_status __wrap_acpi_get_table(char *signature, u32 instance, + struct acpi_table_header **out_table) +{ + int index; + struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); + acpi_status status; + + if (ops) + status = ops->acpi_get_table(signature, instance, out_table); + else + status = acpi_get_table(signature, instance, out_table); + + put_cxl_mock_ops(index); + + return status; +} +EXPORT_SYMBOL(__wrap_acpi_get_table); + +void __wrap_acpi_put_table(struct acpi_table_header *table) +{ + int index; + struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); + + if (ops) + ops->acpi_put_table(table); + else + acpi_put_table(table); + put_cxl_mock_ops(index); +} +EXPORT_SYMBOL(__wrap_acpi_put_table); + +acpi_status __wrap_acpi_evaluate_integer(acpi_handle handle, + acpi_string pathname, + struct acpi_object_list *arguments, + unsigned long long *data) +{ + int index; + struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); + acpi_status status; + + if (ops) + status = ops->acpi_evaluate_integer(handle, pathname, arguments, + data); + else + status = acpi_evaluate_integer(handle, pathname, arguments, + data); + put_cxl_mock_ops(index); + + return status; +} +EXPORT_SYMBOL(__wrap_acpi_evaluate_integer); + +struct acpi_pci_root *__wrap_acpi_pci_find_root(acpi_handle handle) +{ + int index; + struct acpi_pci_root *root; + struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); + + if (ops) + root = ops->acpi_pci_find_root(handle); + else + root = acpi_pci_find_root(handle); + + put_cxl_mock_ops(index); + + return root; +} +EXPORT_SYMBOL_GPL(__wrap_acpi_pci_find_root); + +void __wrap_pci_walk_bus(struct pci_bus *bus, + int (*cb)(struct pci_dev *, void *), void *userdata) +{ + int index; + struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); + + if (ops && ops->is_mock_bus(bus)) { + int rc, i; + + /* + * Simulate 2 root ports per host-bridge and no + * depth recursion. + */ + for (i = 0; i < 2; i++) { + rc = cb((struct pci_dev *) ops->mock_port(bus, i), + userdata); + if (rc) + break; + } + } else + pci_walk_bus(bus, cb, userdata); + + put_cxl_mock_ops(index); +} +EXPORT_SYMBOL_GPL(__wrap_pci_walk_bus); + +struct nvdimm_bus * +__wrap_nvdimm_bus_register(struct device *dev, + struct nvdimm_bus_descriptor *nd_desc) +{ + int index; + struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); + + if (ops && ops->is_mock_dev(dev->parent->parent)) + nd_desc->provider_name = "cxl_test"; + put_cxl_mock_ops(index); + + return nvdimm_bus_register(dev, nd_desc); +} +EXPORT_SYMBOL_GPL(__wrap_nvdimm_bus_register); + +MODULE_LICENSE("GPL v2"); diff --git a/tools/testing/cxl/test/mock.h b/tools/testing/cxl/test/mock.h new file mode 100644 index 000000000000..805a94cb3fbe --- /dev/null +++ b/tools/testing/cxl/test/mock.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#include +#include + +struct cxl_mock_ops { + struct list_head list; + bool (*is_mock_adev)(struct acpi_device *dev); + acpi_status (*acpi_get_table)(char *signature, u32 instance, + struct acpi_table_header **out_table); + void (*acpi_put_table)(struct acpi_table_header *table); + bool (*is_mock_bridge)(struct device *dev); + acpi_status (*acpi_evaluate_integer)(acpi_handle handle, + acpi_string pathname, + struct acpi_object_list *arguments, + unsigned long long *data); + struct acpi_pci_root *(*acpi_pci_find_root)(acpi_handle handle); + struct platform_device *(*mock_port)(struct pci_bus *bus, int index); + bool (*is_mock_bus)(struct pci_bus *bus); + bool (*is_mock_port)(struct platform_device *pdev); + bool (*is_mock_dev)(struct device *dev); +}; + +void register_cxl_mock_ops(struct cxl_mock_ops *ops); +void unregister_cxl_mock_ops(struct cxl_mock_ops *ops); +struct cxl_mock_ops *get_cxl_mock_ops(int *index); +void put_cxl_mock_ops(int index); -- cgit From a5c25802168993c67a03a6e04142761dfb4a3bf5 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 8 Sep 2021 22:13:10 -0700 Subject: cxl/bus: Populate the target list at decoder create As found by cxl_test, the implementation populated the target_list for the single dport exceptional case, it missed populating the target_list for the typical multi-dport case. Root decoders always know their target list at the beginning of time, and even switch-level decoders should have a target list of one or more zeros by default, depending on the interleave-ways setting. Walk the hosting port's dport list and populate based on the passed in map. Move devm_cxl_add_passthrough_decoder() out of line now that it does the work of generating a target_map. Before: $ cat /sys/bus/cxl/devices/root2/decoder*/target_list 0 0 After: $ cat /sys/bus/cxl/devices/root2/decoder*/target_list 0 0,1,2,3 0 0,1,2,3 Where root2 is a CXL topology root object generated by 'cxl_test'. Acked-by: Ben Widawsky Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/163116439000.2460985.11713777051267946018.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/cxl/acpi.c | 13 +++++++- drivers/cxl/core/bus.c | 80 +++++++++++++++++++++++++++++++++++++++++++------- drivers/cxl/cxl.h | 25 +++++++--------- 3 files changed, 91 insertions(+), 27 deletions(-) diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c index 32775d1ac4b3..d39cc797a64e 100644 --- a/drivers/cxl/acpi.c +++ b/drivers/cxl/acpi.c @@ -52,6 +52,12 @@ static int cxl_acpi_cfmws_verify(struct device *dev, return -EINVAL; } + if (CFMWS_INTERLEAVE_WAYS(cfmws) > CXL_DECODER_MAX_INTERLEAVE) { + dev_err(dev, "CFMWS Interleave Ways (%d) too large\n", + CFMWS_INTERLEAVE_WAYS(cfmws)); + return -EINVAL; + } + expected_len = struct_size((cfmws), interleave_targets, CFMWS_INTERLEAVE_WAYS(cfmws)); @@ -71,6 +77,7 @@ static int cxl_acpi_cfmws_verify(struct device *dev, static void cxl_add_cfmws_decoders(struct device *dev, struct cxl_port *root_port) { + int target_map[CXL_DECODER_MAX_INTERLEAVE]; struct acpi_cedt_cfmws *cfmws; struct cxl_decoder *cxld; acpi_size len, cur = 0; @@ -83,6 +90,7 @@ static void cxl_add_cfmws_decoders(struct device *dev, while (cur < len) { struct acpi_cedt_header *c = cedt_subtable + cur; + int i; if (c->type != ACPI_CEDT_TYPE_CFMWS) { cur += c->length; @@ -108,6 +116,9 @@ static void cxl_add_cfmws_decoders(struct device *dev, continue; } + for (i = 0; i < CFMWS_INTERLEAVE_WAYS(cfmws); i++) + target_map[i] = cfmws->interleave_targets[i]; + flags = cfmws_to_decoder_flags(cfmws->restrictions); cxld = devm_cxl_add_decoder(dev, root_port, CFMWS_INTERLEAVE_WAYS(cfmws), @@ -115,7 +126,7 @@ static void cxl_add_cfmws_decoders(struct device *dev, CFMWS_INTERLEAVE_WAYS(cfmws), CFMWS_INTERLEAVE_GRANULARITY(cfmws), CXL_DECODER_EXPANDER, - flags); + flags, target_map); if (IS_ERR(cxld)) { dev_err(dev, "Failed to add decoder for %#llx-%#llx\n", diff --git a/drivers/cxl/core/bus.c b/drivers/cxl/core/bus.c index 9a8fa88b634c..6dfdeaf999f0 100644 --- a/drivers/cxl/core/bus.c +++ b/drivers/cxl/core/bus.c @@ -453,11 +453,38 @@ err: } EXPORT_SYMBOL_GPL(cxl_add_dport); +static int decoder_populate_targets(struct device *host, + struct cxl_decoder *cxld, + struct cxl_port *port, int *target_map, + int nr_targets) +{ + int rc = 0, i; + + if (!target_map) + return 0; + + device_lock(&port->dev); + for (i = 0; i < nr_targets; i++) { + struct cxl_dport *dport = find_dport(port, target_map[i]); + + if (!dport) { + rc = -ENXIO; + break; + } + dev_dbg(host, "%s: target: %d\n", dev_name(dport->dport), i); + cxld->target[i] = dport; + } + device_unlock(&port->dev); + + return rc; +} + static struct cxl_decoder * -cxl_decoder_alloc(struct cxl_port *port, int nr_targets, resource_size_t base, - resource_size_t len, int interleave_ways, - int interleave_granularity, enum cxl_decoder_type type, - unsigned long flags) +cxl_decoder_alloc(struct device *host, struct cxl_port *port, int nr_targets, + resource_size_t base, resource_size_t len, + int interleave_ways, int interleave_granularity, + enum cxl_decoder_type type, unsigned long flags, + int *target_map) { struct cxl_decoder *cxld; struct device *dev; @@ -493,10 +520,10 @@ cxl_decoder_alloc(struct cxl_port *port, int nr_targets, resource_size_t base, .target_type = type, }; - /* handle implied target_list */ - if (interleave_ways == 1) - cxld->target[0] = - list_first_entry(&port->dports, struct cxl_dport, list); + rc = decoder_populate_targets(host, cxld, port, target_map, nr_targets); + if (rc) + goto err; + dev = &cxld->dev; device_initialize(dev); device_set_pm_not_required(dev); @@ -519,14 +546,19 @@ struct cxl_decoder * devm_cxl_add_decoder(struct device *host, struct cxl_port *port, int nr_targets, resource_size_t base, resource_size_t len, int interleave_ways, int interleave_granularity, - enum cxl_decoder_type type, unsigned long flags) + enum cxl_decoder_type type, unsigned long flags, + int *target_map) { struct cxl_decoder *cxld; struct device *dev; int rc; - cxld = cxl_decoder_alloc(port, nr_targets, base, len, interleave_ways, - interleave_granularity, type, flags); + if (nr_targets > CXL_DECODER_MAX_INTERLEAVE) + return ERR_PTR(-EINVAL); + + cxld = cxl_decoder_alloc(host, port, nr_targets, base, len, + interleave_ways, interleave_granularity, type, + flags, target_map); if (IS_ERR(cxld)) return cxld; @@ -550,6 +582,32 @@ err: } EXPORT_SYMBOL_GPL(devm_cxl_add_decoder); +/* + * Per the CXL specification (8.2.5.12 CXL HDM Decoder Capability Structure) + * single ported host-bridges need not publish a decoder capability when a + * passthrough decode can be assumed, i.e. all transactions that the uport sees + * are claimed and passed to the single dport. Default the range a 0-base + * 0-length until the first CXL region is activated. + */ +struct cxl_decoder *devm_cxl_add_passthrough_decoder(struct device *host, + struct cxl_port *port) +{ + struct cxl_dport *dport; + int target_map[1]; + + device_lock(&port->dev); + dport = list_first_entry_or_null(&port->dports, typeof(*dport), list); + device_unlock(&port->dev); + + if (!dport) + return ERR_PTR(-ENXIO); + + target_map[0] = dport->port_id; + return devm_cxl_add_decoder(host, port, 1, 0, 0, 1, PAGE_SIZE, + CXL_DECODER_EXPANDER, 0, target_map); +} +EXPORT_SYMBOL_GPL(devm_cxl_add_passthrough_decoder); + /** * __cxl_driver_register - register a driver for the cxl bus * @cxl_drv: cxl driver structure to attach diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index c5152718267e..84b8836c1f91 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -180,6 +180,12 @@ enum cxl_decoder_type { CXL_DECODER_EXPANDER = 3, }; +/* + * Current specification goes up to 8, double that seems a reasonable + * software max for the foreseeable future + */ +#define CXL_DECODER_MAX_INTERLEAVE 16 + /** * struct cxl_decoder - CXL address range decode configuration * @dev: this decoder's device @@ -284,22 +290,11 @@ struct cxl_decoder * devm_cxl_add_decoder(struct device *host, struct cxl_port *port, int nr_targets, resource_size_t base, resource_size_t len, int interleave_ways, int interleave_granularity, - enum cxl_decoder_type type, unsigned long flags); - -/* - * Per the CXL specification (8.2.5.12 CXL HDM Decoder Capability Structure) - * single ported host-bridges need not publish a decoder capability when a - * passthrough decode can be assumed, i.e. all transactions that the uport sees - * are claimed and passed to the single dport. Default the range a 0-base - * 0-length until the first CXL region is activated. - */ -static inline struct cxl_decoder * -devm_cxl_add_passthrough_decoder(struct device *host, struct cxl_port *port) -{ - return devm_cxl_add_decoder(host, port, 1, 0, 0, 1, PAGE_SIZE, - CXL_DECODER_EXPANDER, 0); -} + enum cxl_decoder_type type, unsigned long flags, + int *target_map); +struct cxl_decoder *devm_cxl_add_passthrough_decoder(struct device *host, + struct cxl_port *port); extern struct bus_type cxl_bus_type; struct cxl_driver { -- cgit From 49be6dd807511db31809000a7b9d430b18d5e780 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 8 Sep 2021 22:13:15 -0700 Subject: cxl/mbox: Move command definitions to common location In preparation for cxl_test to mock responses to mailbox command requests, move some definitions from core/mbox.c to cxlmem.h. No functional changes intended. Acked-by: Ben Widawsky Acked-by: Jonathan Cameron Link: https://lore.kernel.org/r/163116439547.2460985.10457111177103589574.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/cxl/core/mbox.c | 45 ++++++-------------------------------- drivers/cxl/cxlmem.h | 57 +++++++++++++++++++++++++++++++++++++++++++++++++ drivers/cxl/pmem.c | 11 ++-------- 3 files changed, 65 insertions(+), 48 deletions(-) diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index 82e79da195fa..576796a5d9f3 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -485,11 +485,7 @@ static int cxl_xfer_log(struct cxl_mem *cxlm, uuid_t *uuid, u32 size, u8 *out) while (remaining) { u32 xfer_size = min_t(u32, remaining, cxlm->payload_size); - struct cxl_mbox_get_log { - uuid_t uuid; - __le32 offset; - __le32 length; - } __packed log = { + struct cxl_mbox_get_log log = { .uuid = *uuid, .offset = cpu_to_le32(offset), .length = cpu_to_le32(xfer_size) @@ -520,14 +516,11 @@ static int cxl_xfer_log(struct cxl_mem *cxlm, uuid_t *uuid, u32 size, u8 *out) */ static void cxl_walk_cel(struct cxl_mem *cxlm, size_t size, u8 *cel) { - struct cel_entry { - __le16 opcode; - __le16 effect; - } __packed * cel_entry; + struct cxl_cel_entry *cel_entry; const int cel_entries = size / sizeof(*cel_entry); int i; - cel_entry = (struct cel_entry *)cel; + cel_entry = (struct cxl_cel_entry *) cel; for (i = 0; i < cel_entries; i++) { u16 opcode = le16_to_cpu(cel_entry[i].opcode); @@ -543,15 +536,6 @@ static void cxl_walk_cel(struct cxl_mem *cxlm, size_t size, u8 *cel) } } -struct cxl_mbox_get_supported_logs { - __le16 entries; - u8 rsvd[6]; - struct gsl_entry { - uuid_t uuid; - __le32 size; - } __packed entry[]; -} __packed; - static struct cxl_mbox_get_supported_logs *cxl_get_gsl(struct cxl_mem *cxlm) { struct cxl_mbox_get_supported_logs *ret; @@ -578,10 +562,8 @@ enum { /* See CXL 2.0 Table 170. Get Log Input Payload */ static const uuid_t log_uuid[] = { - [CEL_UUID] = UUID_INIT(0xda9c0b5, 0xbf41, 0x4b78, 0x8f, 0x79, 0x96, - 0xb1, 0x62, 0x3b, 0x3f, 0x17), - [VENDOR_DEBUG_UUID] = UUID_INIT(0xe1819d9, 0x11a9, 0x400c, 0x81, 0x1f, - 0xd6, 0x07, 0x19, 0x40, 0x3d, 0x86), + [CEL_UUID] = DEFINE_CXL_CEL_UUID, + [VENDOR_DEBUG_UUID] = DEFINE_CXL_VENDOR_DEBUG_UUID, }; /** @@ -698,22 +680,7 @@ static int cxl_mem_get_partition_info(struct cxl_mem *cxlm) int cxl_mem_identify(struct cxl_mem *cxlm) { /* See CXL 2.0 Table 175 Identify Memory Device Output Payload */ - struct cxl_mbox_identify { - char fw_revision[0x10]; - __le64 total_capacity; - __le64 volatile_capacity; - __le64 persistent_capacity; - __le64 partition_align; - __le16 info_event_log_size; - __le16 warning_event_log_size; - __le16 failure_event_log_size; - __le16 fatal_event_log_size; - __le32 lsa_size; - u8 poison_list_max_mer[3]; - __le16 inject_poison_limit; - u8 poison_caps; - u8 qos_telemetry_caps; - } __packed id; + struct cxl_mbox_identify id; int rc; rc = cxl_mem_mbox_send_cmd(cxlm, CXL_MBOX_OP_IDENTIFY, NULL, 0, &id, diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index 373add570ef6..c4f450ad434d 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -171,6 +171,63 @@ enum cxl_opcode { CXL_MBOX_OP_MAX = 0x10000 }; +#define DEFINE_CXL_CEL_UUID \ + UUID_INIT(0xda9c0b5, 0xbf41, 0x4b78, 0x8f, 0x79, 0x96, 0xb1, 0x62, \ + 0x3b, 0x3f, 0x17) + +#define DEFINE_CXL_VENDOR_DEBUG_UUID \ + UUID_INIT(0xe1819d9, 0x11a9, 0x400c, 0x81, 0x1f, 0xd6, 0x07, 0x19, \ + 0x40, 0x3d, 0x86) + +struct cxl_mbox_get_supported_logs { + __le16 entries; + u8 rsvd[6]; + struct cxl_gsl_entry { + uuid_t uuid; + __le32 size; + } __packed entry[]; +} __packed; + +struct cxl_cel_entry { + __le16 opcode; + __le16 effect; +} __packed; + +struct cxl_mbox_get_log { + uuid_t uuid; + __le32 offset; + __le32 length; +} __packed; + +/* See CXL 2.0 Table 175 Identify Memory Device Output Payload */ +struct cxl_mbox_identify { + char fw_revision[0x10]; + __le64 total_capacity; + __le64 volatile_capacity; + __le64 persistent_capacity; + __le64 partition_align; + __le16 info_event_log_size; + __le16 warning_event_log_size; + __le16 failure_event_log_size; + __le16 fatal_event_log_size; + __le32 lsa_size; + u8 poison_list_max_mer[3]; + __le16 inject_poison_limit; + u8 poison_caps; + u8 qos_telemetry_caps; +} __packed; + +struct cxl_mbox_get_lsa { + u32 offset; + u32 length; +} __packed; + +struct cxl_mbox_set_lsa { + u32 offset; + u32 reserved; + u8 data[]; +} __packed; + /** * struct cxl_mem_command - Driver representation of a memory device command * @info: Command information as it exists for the UAPI diff --git a/drivers/cxl/pmem.c b/drivers/cxl/pmem.c index 5ccf9aa6b3ae..d7b5548551e9 100644 --- a/drivers/cxl/pmem.c +++ b/drivers/cxl/pmem.c @@ -99,10 +99,7 @@ static int cxl_pmem_get_config_data(struct cxl_mem *cxlm, struct nd_cmd_get_config_data_hdr *cmd, unsigned int buf_len) { - struct cxl_mbox_get_lsa { - u32 offset; - u32 length; - } get_lsa; + struct cxl_mbox_get_lsa get_lsa; int rc; if (sizeof(*cmd) > buf_len) @@ -127,11 +124,7 @@ static int cxl_pmem_set_config_data(struct cxl_mem *cxlm, struct nd_cmd_set_config_hdr *cmd, unsigned int buf_len) { - struct cxl_mbox_set_lsa { - u32 offset; - u32 reserved; - u8 data[]; - } *set_lsa; + struct cxl_mbox_set_lsa *set_lsa; int rc; if (sizeof(*cmd) > buf_len) -- cgit From 7d3eb23c4ccf457b52cafdca1a7b20cddf29e021 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 8 Sep 2021 22:13:21 -0700 Subject: tools/testing/cxl: Introduce a mock memory device + driver Introduce an emulated device-set plus driver to register CXL memory devices, 'struct cxl_memdev' instances, in the mock cxl_test topology. This enables the development of HDM Decoder (Host-managed Device Memory Decoder) programming flow (region provisioning) in an environment that can be updated alongside the kernel as it gains more functionality. Whereas the cxl_pci module looks for CXL memory expanders on the 'pci' bus, the cxl_mock_mem module attaches to CXL expanders on the platform bus emitted by cxl_test. Acked-by: Ben Widawsky Reported-by: kernel test robot Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/163116440099.2460985.10692549614409346604.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/cxl/core/pmem.c | 6 +- drivers/cxl/cxl.h | 2 +- drivers/cxl/pmem.c | 2 +- tools/testing/cxl/Kbuild | 2 + tools/testing/cxl/mock_pmem.c | 24 ++++ tools/testing/cxl/test/Kbuild | 4 + tools/testing/cxl/test/cxl.c | 69 +++++++++++- tools/testing/cxl/test/mem.c | 256 ++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 359 insertions(+), 6 deletions(-) create mode 100644 tools/testing/cxl/mock_pmem.c create mode 100644 tools/testing/cxl/test/mem.c diff --git a/drivers/cxl/core/pmem.c b/drivers/cxl/core/pmem.c index 9e56be3994f1..74be5132df1c 100644 --- a/drivers/cxl/core/pmem.c +++ b/drivers/cxl/core/pmem.c @@ -51,16 +51,16 @@ struct cxl_nvdimm_bridge *to_cxl_nvdimm_bridge(struct device *dev) } EXPORT_SYMBOL_GPL(to_cxl_nvdimm_bridge); -static int match_nvdimm_bridge(struct device *dev, const void *data) +__mock int match_nvdimm_bridge(struct device *dev, const void *data) { return dev->type == &cxl_nvdimm_bridge_type; } -struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(void) +struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_nvdimm *cxl_nvd) { struct device *dev; - dev = bus_find_device(&cxl_bus_type, NULL, NULL, match_nvdimm_bridge); + dev = bus_find_device(&cxl_bus_type, NULL, cxl_nvd, match_nvdimm_bridge); if (!dev) return NULL; return to_cxl_nvdimm_bridge(dev); diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 84b8836c1f91..9af5745ba2c0 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -327,7 +327,7 @@ struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host, struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev); bool is_cxl_nvdimm(struct device *dev); int devm_cxl_add_nvdimm(struct device *host, struct cxl_memdev *cxlmd); -struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(void); +struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_nvdimm *cxl_nvd); /* * Unit test builds overrides this to __weak, find the 'strong' version diff --git a/drivers/cxl/pmem.c b/drivers/cxl/pmem.c index d7b5548551e9..ceb2115981e5 100644 --- a/drivers/cxl/pmem.c +++ b/drivers/cxl/pmem.c @@ -39,7 +39,7 @@ static int cxl_nvdimm_probe(struct device *dev) struct nvdimm *nvdimm; int rc; - cxl_nvb = cxl_find_nvdimm_bridge(); + cxl_nvb = cxl_find_nvdimm_bridge(cxl_nvd); if (!cxl_nvb) return -ENXIO; diff --git a/tools/testing/cxl/Kbuild b/tools/testing/cxl/Kbuild index 63a4a07e71c4..86deba8308a1 100644 --- a/tools/testing/cxl/Kbuild +++ b/tools/testing/cxl/Kbuild @@ -33,4 +33,6 @@ cxl_core-y += $(CXL_CORE_SRC)/memdev.o cxl_core-y += $(CXL_CORE_SRC)/mbox.o cxl_core-y += config_check.o +cxl_core-y += mock_pmem.o + obj-m += test/ diff --git a/tools/testing/cxl/mock_pmem.c b/tools/testing/cxl/mock_pmem.c new file mode 100644 index 000000000000..f7315e6f52c0 --- /dev/null +++ b/tools/testing/cxl/mock_pmem.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2021 Intel Corporation. All rights reserved. */ +#include +#include "test/mock.h" +#include + +int match_nvdimm_bridge(struct device *dev, const void *data) +{ + int index, rc = 0; + struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); + const struct cxl_nvdimm *cxl_nvd = data; + + if (ops) { + if (dev->type == &cxl_nvdimm_bridge_type && + (ops->is_mock_dev(dev->parent->parent) == + ops->is_mock_dev(cxl_nvd->dev.parent->parent))) + rc = 1; + } else + rc = dev->type == &cxl_nvdimm_bridge_type; + + put_cxl_mock_ops(index); + + return rc; +} diff --git a/tools/testing/cxl/test/Kbuild b/tools/testing/cxl/test/Kbuild index 7de4ddecfd21..4e59e2c911f6 100644 --- a/tools/testing/cxl/test/Kbuild +++ b/tools/testing/cxl/test/Kbuild @@ -1,6 +1,10 @@ # SPDX-License-Identifier: GPL-2.0 +ccflags-y := -I$(srctree)/drivers/cxl/ + obj-m += cxl_test.o obj-m += cxl_mock.o +obj-m += cxl_mock_mem.o cxl_test-y := cxl.o cxl_mock-y := mock.o +cxl_mock_mem-y := mem.o diff --git a/tools/testing/cxl/test/cxl.c b/tools/testing/cxl/test/cxl.c index 1c47b34244a4..cb32f9e27d5d 100644 --- a/tools/testing/cxl/test/cxl.c +++ b/tools/testing/cxl/test/cxl.c @@ -17,6 +17,7 @@ static struct platform_device *cxl_acpi; static struct platform_device *cxl_host_bridge[NR_CXL_HOST_BRIDGES]; static struct platform_device *cxl_root_port[NR_CXL_HOST_BRIDGES * NR_CXL_ROOT_PORTS]; +struct platform_device *cxl_mem[NR_CXL_HOST_BRIDGES * NR_CXL_ROOT_PORTS]; static struct acpi_device acpi0017_mock; static struct acpi_device host_bridge[NR_CXL_HOST_BRIDGES] = { @@ -36,6 +37,11 @@ static struct acpi_device host_bridge[NR_CXL_HOST_BRIDGES] = { static bool is_mock_dev(struct device *dev) { + int i; + + for (i = 0; i < ARRAY_SIZE(cxl_mem); i++) + if (dev == &cxl_mem[i]->dev) + return true; if (dev == &cxl_acpi->dev) return true; return false; @@ -405,6 +411,44 @@ static void mock_companion(struct acpi_device *adev, struct device *dev) #define SZ_512G (SZ_64G * 8) #endif +static struct platform_device *alloc_memdev(int id) +{ + struct resource res[] = { + [0] = { + .flags = IORESOURCE_MEM, + }, + [1] = { + .flags = IORESOURCE_MEM, + .desc = IORES_DESC_PERSISTENT_MEMORY, + }, + }; + struct platform_device *pdev; + int i, rc; + + for (i = 0; i < ARRAY_SIZE(res); i++) { + struct cxl_mock_res *r = alloc_mock_res(SZ_256M); + + if (!r) + return NULL; + res[i].start = r->range.start; + res[i].end = r->range.end; + } + + pdev = platform_device_alloc("cxl_mem", id); + if (!pdev) + return NULL; + + rc = platform_device_add_resources(pdev, res, ARRAY_SIZE(res)); + if (rc) + goto err; + + return pdev; + +err: + platform_device_put(pdev); + return NULL; +} + static __init int cxl_test_init(void) { int rc, i; @@ -460,9 +504,27 @@ static __init int cxl_test_init(void) cxl_root_port[i] = pdev; } + BUILD_BUG_ON(ARRAY_SIZE(cxl_mem) != ARRAY_SIZE(cxl_root_port)); + for (i = 0; i < ARRAY_SIZE(cxl_mem); i++) { + struct platform_device *port = cxl_root_port[i]; + struct platform_device *pdev; + + pdev = alloc_memdev(i); + if (!pdev) + goto err_mem; + pdev->dev.parent = &port->dev; + + rc = platform_device_add(pdev); + if (rc) { + platform_device_put(pdev); + goto err_mem; + } + cxl_mem[i] = pdev; + } + cxl_acpi = platform_device_alloc("cxl_acpi", 0); if (!cxl_acpi) - goto err_port; + goto err_mem; mock_companion(&acpi0017_mock, &cxl_acpi->dev); acpi0017_mock.dev.bus = &platform_bus_type; @@ -475,6 +537,9 @@ static __init int cxl_test_init(void) err_add: platform_device_put(cxl_acpi); +err_mem: + for (i = ARRAY_SIZE(cxl_mem) - 1; i >= 0; i--) + platform_device_unregister(cxl_mem[i]); err_port: for (i = ARRAY_SIZE(cxl_root_port) - 1; i >= 0; i--) platform_device_unregister(cxl_root_port[i]); @@ -495,6 +560,8 @@ static __exit void cxl_test_exit(void) int i; platform_device_unregister(cxl_acpi); + for (i = ARRAY_SIZE(cxl_mem) - 1; i >= 0; i--) + platform_device_unregister(cxl_mem[i]); for (i = ARRAY_SIZE(cxl_root_port) - 1; i >= 0; i--) platform_device_unregister(cxl_root_port[i]); for (i = ARRAY_SIZE(cxl_host_bridge) - 1; i >= 0; i--) diff --git a/tools/testing/cxl/test/mem.c b/tools/testing/cxl/test/mem.c new file mode 100644 index 000000000000..12a8437a9ca0 --- /dev/null +++ b/tools/testing/cxl/test/mem.c @@ -0,0 +1,256 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright(c) 2021 Intel Corporation. All rights reserved. + +#include +#include +#include +#include +#include +#include + +#define LSA_SIZE SZ_128K +#define EFFECT(x) (1U << x) + +static struct cxl_cel_entry mock_cel[] = { + { + .opcode = cpu_to_le16(CXL_MBOX_OP_GET_SUPPORTED_LOGS), + .effect = cpu_to_le16(0), + }, + { + .opcode = cpu_to_le16(CXL_MBOX_OP_IDENTIFY), + .effect = cpu_to_le16(0), + }, + { + .opcode = cpu_to_le16(CXL_MBOX_OP_GET_LSA), + .effect = cpu_to_le16(0), + }, + { + .opcode = cpu_to_le16(CXL_MBOX_OP_SET_LSA), + .effect = cpu_to_le16(EFFECT(1) | EFFECT(2)), + }, +}; + +static struct { + struct cxl_mbox_get_supported_logs gsl; + struct cxl_gsl_entry entry; +} mock_gsl_payload = { + .gsl = { + .entries = cpu_to_le16(1), + }, + .entry = { + .uuid = DEFINE_CXL_CEL_UUID, + .size = cpu_to_le32(sizeof(mock_cel)), + }, +}; + +static int mock_gsl(struct cxl_mbox_cmd *cmd) +{ + if (cmd->size_out < sizeof(mock_gsl_payload)) + return -EINVAL; + + memcpy(cmd->payload_out, &mock_gsl_payload, sizeof(mock_gsl_payload)); + cmd->size_out = sizeof(mock_gsl_payload); + + return 0; +} + +static int mock_get_log(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) +{ + struct cxl_mbox_get_log *gl = cmd->payload_in; + u32 offset = le32_to_cpu(gl->offset); + u32 length = le32_to_cpu(gl->length); + uuid_t uuid = DEFINE_CXL_CEL_UUID; + void *data = &mock_cel; + + if (cmd->size_in < sizeof(*gl)) + return -EINVAL; + if (length > cxlm->payload_size) + return -EINVAL; + if (offset + length > sizeof(mock_cel)) + return -EINVAL; + if (!uuid_equal(&gl->uuid, &uuid)) + return -EINVAL; + if (length > cmd->size_out) + return -EINVAL; + + memcpy(cmd->payload_out, data + offset, length); + + return 0; +} + +static int mock_id(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) +{ + struct platform_device *pdev = to_platform_device(cxlm->dev); + struct cxl_mbox_identify id = { + .fw_revision = { "mock fw v1 " }, + .lsa_size = cpu_to_le32(LSA_SIZE), + /* FIXME: Add partition support */ + .partition_align = cpu_to_le64(0), + }; + u64 capacity = 0; + int i; + + if (cmd->size_out < sizeof(id)) + return -EINVAL; + + for (i = 0; i < 2; i++) { + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, i); + if (!res) + break; + + capacity += resource_size(res) / CXL_CAPACITY_MULTIPLIER; + + if (le64_to_cpu(id.partition_align)) + continue; + + if (res->desc == IORES_DESC_PERSISTENT_MEMORY) + id.persistent_capacity = cpu_to_le64( + resource_size(res) / CXL_CAPACITY_MULTIPLIER); + else + id.volatile_capacity = cpu_to_le64( + resource_size(res) / CXL_CAPACITY_MULTIPLIER); + } + + id.total_capacity = cpu_to_le64(capacity); + + memcpy(cmd->payload_out, &id, sizeof(id)); + + return 0; +} + +static int mock_get_lsa(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) +{ + struct cxl_mbox_get_lsa *get_lsa = cmd->payload_in; + void *lsa = dev_get_drvdata(cxlm->dev); + u32 offset, length; + + if (sizeof(*get_lsa) > cmd->size_in) + return -EINVAL; + offset = le32_to_cpu(get_lsa->offset); + length = le32_to_cpu(get_lsa->length); + if (offset + length > LSA_SIZE) + return -EINVAL; + if (length > cmd->size_out) + return -EINVAL; + + memcpy(cmd->payload_out, lsa + offset, length); + return 0; +} + +static int mock_set_lsa(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) +{ + struct cxl_mbox_set_lsa *set_lsa = cmd->payload_in; + void *lsa = dev_get_drvdata(cxlm->dev); + u32 offset, length; + + if (sizeof(*set_lsa) > cmd->size_in) + return -EINVAL; + offset = le32_to_cpu(set_lsa->offset); + length = cmd->size_in - sizeof(*set_lsa); + if (offset + length > LSA_SIZE) + return -EINVAL; + + memcpy(lsa + offset, &set_lsa->data[0], length); + return 0; +} + +static int cxl_mock_mbox_send(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) +{ + struct device *dev = cxlm->dev; + int rc = -EIO; + + switch (cmd->opcode) { + case CXL_MBOX_OP_GET_SUPPORTED_LOGS: + rc = mock_gsl(cmd); + break; + case CXL_MBOX_OP_GET_LOG: + rc = mock_get_log(cxlm, cmd); + break; + case CXL_MBOX_OP_IDENTIFY: + rc = mock_id(cxlm, cmd); + break; + case CXL_MBOX_OP_GET_LSA: + rc = mock_get_lsa(cxlm, cmd); + break; + case CXL_MBOX_OP_SET_LSA: + rc = mock_set_lsa(cxlm, cmd); + break; + default: + break; + } + + dev_dbg(dev, "opcode: %#x sz_in: %zd sz_out: %zd rc: %d\n", cmd->opcode, + cmd->size_in, cmd->size_out, rc); + + return rc; +} + +static void label_area_release(void *lsa) +{ + vfree(lsa); +} + +static int cxl_mock_mem_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct cxl_memdev *cxlmd; + struct cxl_mem *cxlm; + void *lsa; + int rc; + + lsa = vmalloc(LSA_SIZE); + if (!lsa) + return -ENOMEM; + rc = devm_add_action_or_reset(dev, label_area_release, lsa); + if (rc) + return rc; + dev_set_drvdata(dev, lsa); + + cxlm = cxl_mem_create(dev); + if (IS_ERR(cxlm)) + return PTR_ERR(cxlm); + + cxlm->mbox_send = cxl_mock_mbox_send; + cxlm->payload_size = SZ_4K; + + rc = cxl_mem_enumerate_cmds(cxlm); + if (rc) + return rc; + + rc = cxl_mem_identify(cxlm); + if (rc) + return rc; + + rc = cxl_mem_create_range_info(cxlm); + if (rc) + return rc; + + cxlmd = devm_cxl_add_memdev(cxlm); + if (IS_ERR(cxlmd)) + return PTR_ERR(cxlmd); + + if (range_len(&cxlm->pmem_range) && IS_ENABLED(CONFIG_CXL_PMEM)) + rc = devm_cxl_add_nvdimm(dev, cxlmd); + + return 0; +} + +static const struct platform_device_id cxl_mock_mem_ids[] = { + { .name = "cxl_mem", }, + { }, +}; +MODULE_DEVICE_TABLE(platform, cxl_mock_mem_ids); + +static struct platform_driver cxl_mock_mem_driver = { + .probe = cxl_mock_mem_probe, + .id_table = cxl_mock_mem_ids, + .driver = { + .name = KBUILD_MODNAME, + }, +}; + +module_platform_driver(cxl_mock_mem_driver); +MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(CXL); -- cgit From 48667f676189eccfe9b7ac3a31772d55d6da40e5 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 21 Sep 2021 12:22:16 -0700 Subject: cxl/core: Split decoder setup into alloc + add The kbuild robot reports: drivers/cxl/core/bus.c:516:1: warning: stack frame size (1032) exceeds limit (1024) in function 'devm_cxl_add_decoder' It is also the case the devm_cxl_add_decoder() is unwieldy to use for all the different decoder types. Fix the stack usage by splitting the creation into alloc and add steps. This also allows for context specific construction before adding. With the split the caller is responsible for registering a devm callback to trigger device_unregister() for the decoder rather than it being implicit in the decoder registration. I.e. the routine that calls alloc is responsible for calling put_device() if the "add" operation fails. Reported-by: kernel test robot Reported-by: Nathan Chancellor Reported-by: Dan Carpenter Reviewed-by: Ben Widawsky Link: https://lore.kernel.org/r/163225205828.3038145.6831131648369404859.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/cxl/acpi.c | 84 ++++++++++++++++++++++--------- drivers/cxl/core/bus.c | 129 ++++++++++++++++-------------------------------- drivers/cxl/core/core.h | 5 -- drivers/cxl/core/pmem.c | 7 ++- drivers/cxl/cxl.h | 15 +++--- 5 files changed, 114 insertions(+), 126 deletions(-) diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c index d39cc797a64e..af1c6c1875ac 100644 --- a/drivers/cxl/acpi.c +++ b/drivers/cxl/acpi.c @@ -82,7 +82,6 @@ static void cxl_add_cfmws_decoders(struct device *dev, struct cxl_decoder *cxld; acpi_size len, cur = 0; void *cedt_subtable; - unsigned long flags; int rc; len = acpi_cedt->length - sizeof(*acpi_cedt); @@ -119,24 +118,36 @@ static void cxl_add_cfmws_decoders(struct device *dev, for (i = 0; i < CFMWS_INTERLEAVE_WAYS(cfmws); i++) target_map[i] = cfmws->interleave_targets[i]; - flags = cfmws_to_decoder_flags(cfmws->restrictions); - cxld = devm_cxl_add_decoder(dev, root_port, - CFMWS_INTERLEAVE_WAYS(cfmws), - cfmws->base_hpa, cfmws->window_size, - CFMWS_INTERLEAVE_WAYS(cfmws), - CFMWS_INTERLEAVE_GRANULARITY(cfmws), - CXL_DECODER_EXPANDER, - flags, target_map); - - if (IS_ERR(cxld)) { + cxld = cxl_decoder_alloc(root_port, + CFMWS_INTERLEAVE_WAYS(cfmws)); + if (IS_ERR(cxld)) + goto next; + + cxld->flags = cfmws_to_decoder_flags(cfmws->restrictions); + cxld->target_type = CXL_DECODER_EXPANDER; + cxld->range = (struct range) { + .start = cfmws->base_hpa, + .end = cfmws->base_hpa + cfmws->window_size - 1, + }; + cxld->interleave_ways = CFMWS_INTERLEAVE_WAYS(cfmws); + cxld->interleave_granularity = + CFMWS_INTERLEAVE_GRANULARITY(cfmws); + + rc = cxl_decoder_add(cxld, target_map); + if (rc) + put_device(&cxld->dev); + else + rc = cxl_decoder_autoremove(dev, cxld); + if (rc) { dev_err(dev, "Failed to add decoder for %#llx-%#llx\n", cfmws->base_hpa, cfmws->base_hpa + cfmws->window_size - 1); - } else { - dev_dbg(dev, "add: %s range %#llx-%#llx\n", - dev_name(&cxld->dev), cfmws->base_hpa, - cfmws->base_hpa + cfmws->window_size - 1); + goto next; } + dev_dbg(dev, "add: %s range %#llx-%#llx\n", + dev_name(&cxld->dev), cfmws->base_hpa, + cfmws->base_hpa + cfmws->window_size - 1); +next: cur += c->length; } } @@ -266,6 +277,7 @@ static int add_host_bridge_uport(struct device *match, void *arg) struct acpi_device *bridge = to_cxl_host_bridge(host, match); struct acpi_pci_root *pci_root; struct cxl_walk_context ctx; + int single_port_map[1], rc; struct cxl_decoder *cxld; struct cxl_dport *dport; struct cxl_port *port; @@ -301,22 +313,46 @@ static int add_host_bridge_uport(struct device *match, void *arg) return -ENODEV; if (ctx.error) return ctx.error; + if (ctx.count > 1) + return 0; /* TODO: Scan CHBCR for HDM Decoder resources */ /* - * In the single-port host-bridge case there are no HDM decoders - * in the CHBCR and a 1:1 passthrough decode is implied. + * Per the CXL specification (8.2.5.12 CXL HDM Decoder Capability + * Structure) single ported host-bridges need not publish a decoder + * capability when a passthrough decode can be assumed, i.e. all + * transactions that the uport sees are claimed and passed to the single + * dport. Disable the range until the first CXL region is enumerated / + * activated. */ - if (ctx.count == 1) { - cxld = devm_cxl_add_passthrough_decoder(host, port); - if (IS_ERR(cxld)) - return PTR_ERR(cxld); + cxld = cxl_decoder_alloc(port, 1); + if (IS_ERR(cxld)) + return PTR_ERR(cxld); + + cxld->interleave_ways = 1; + cxld->interleave_granularity = PAGE_SIZE; + cxld->target_type = CXL_DECODER_EXPANDER; + cxld->range = (struct range) { + .start = 0, + .end = -1, + }; - dev_dbg(host, "add: %s\n", dev_name(&cxld->dev)); - } + device_lock(&port->dev); + dport = list_first_entry(&port->dports, typeof(*dport), list); + device_unlock(&port->dev); - return 0; + single_port_map[0] = dport->port_id; + + rc = cxl_decoder_add(cxld, single_port_map); + if (rc) + put_device(&cxld->dev); + else + rc = cxl_decoder_autoremove(host, cxld); + + if (rc == 0) + dev_dbg(host, "add: %s\n", dev_name(&cxld->dev)); + return rc; } static int add_host_bridge_dport(struct device *match, void *arg) diff --git a/drivers/cxl/core/bus.c b/drivers/cxl/core/bus.c index 6dfdeaf999f0..ebd061d03950 100644 --- a/drivers/cxl/core/bus.c +++ b/drivers/cxl/core/bus.c @@ -453,10 +453,8 @@ err: } EXPORT_SYMBOL_GPL(cxl_add_dport); -static int decoder_populate_targets(struct device *host, - struct cxl_decoder *cxld, - struct cxl_port *port, int *target_map, - int nr_targets) +static int decoder_populate_targets(struct cxl_decoder *cxld, + struct cxl_port *port, int *target_map) { int rc = 0, i; @@ -464,66 +462,48 @@ static int decoder_populate_targets(struct device *host, return 0; device_lock(&port->dev); - for (i = 0; i < nr_targets; i++) { + if (list_empty(&port->dports)) { + rc = -EINVAL; + goto out_unlock; + } + + for (i = 0; i < cxld->nr_targets; i++) { struct cxl_dport *dport = find_dport(port, target_map[i]); if (!dport) { rc = -ENXIO; - break; + goto out_unlock; } - dev_dbg(host, "%s: target: %d\n", dev_name(dport->dport), i); cxld->target[i] = dport; } + +out_unlock: device_unlock(&port->dev); return rc; } -static struct cxl_decoder * -cxl_decoder_alloc(struct device *host, struct cxl_port *port, int nr_targets, - resource_size_t base, resource_size_t len, - int interleave_ways, int interleave_granularity, - enum cxl_decoder_type type, unsigned long flags, - int *target_map) +struct cxl_decoder *cxl_decoder_alloc(struct cxl_port *port, int nr_targets) { - struct cxl_decoder *cxld; + struct cxl_decoder *cxld, cxld_const_init = { + .nr_targets = nr_targets, + }; struct device *dev; int rc = 0; - if (interleave_ways < 1) + if (nr_targets > CXL_DECODER_MAX_INTERLEAVE || nr_targets < 1) return ERR_PTR(-EINVAL); - device_lock(&port->dev); - if (list_empty(&port->dports)) - rc = -EINVAL; - device_unlock(&port->dev); - if (rc) - return ERR_PTR(rc); - cxld = kzalloc(struct_size(cxld, target, nr_targets), GFP_KERNEL); if (!cxld) return ERR_PTR(-ENOMEM); + memcpy(cxld, &cxld_const_init, sizeof(cxld_const_init)); rc = ida_alloc(&port->decoder_ida, GFP_KERNEL); if (rc < 0) goto err; - *cxld = (struct cxl_decoder) { - .id = rc, - .range = { - .start = base, - .end = base + len - 1, - }, - .flags = flags, - .interleave_ways = interleave_ways, - .interleave_granularity = interleave_granularity, - .target_type = type, - }; - - rc = decoder_populate_targets(host, cxld, port, target_map, nr_targets); - if (rc) - goto err; - + cxld->id = rc; dev = &cxld->dev; device_initialize(dev); device_set_pm_not_required(dev); @@ -541,72 +521,47 @@ err: kfree(cxld); return ERR_PTR(rc); } +EXPORT_SYMBOL_GPL(cxl_decoder_alloc); -struct cxl_decoder * -devm_cxl_add_decoder(struct device *host, struct cxl_port *port, int nr_targets, - resource_size_t base, resource_size_t len, - int interleave_ways, int interleave_granularity, - enum cxl_decoder_type type, unsigned long flags, - int *target_map) +int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map) { - struct cxl_decoder *cxld; + struct cxl_port *port; struct device *dev; int rc; - if (nr_targets > CXL_DECODER_MAX_INTERLEAVE) - return ERR_PTR(-EINVAL); + if (WARN_ON_ONCE(!cxld)) + return -EINVAL; - cxld = cxl_decoder_alloc(host, port, nr_targets, base, len, - interleave_ways, interleave_granularity, type, - flags, target_map); - if (IS_ERR(cxld)) - return cxld; + if (WARN_ON_ONCE(IS_ERR(cxld))) + return PTR_ERR(cxld); - dev = &cxld->dev; - rc = dev_set_name(dev, "decoder%d.%d", port->id, cxld->id); - if (rc) - goto err; + if (cxld->interleave_ways < 1) + return -EINVAL; - rc = device_add(dev); + port = to_cxl_port(cxld->dev.parent); + rc = decoder_populate_targets(cxld, port, target_map); if (rc) - goto err; + return rc; - rc = devm_add_action_or_reset(host, unregister_cxl_dev, dev); + dev = &cxld->dev; + rc = dev_set_name(dev, "decoder%d.%d", port->id, cxld->id); if (rc) - return ERR_PTR(rc); - return cxld; + return rc; -err: - put_device(dev); - return ERR_PTR(rc); + return device_add(dev); } -EXPORT_SYMBOL_GPL(devm_cxl_add_decoder); +EXPORT_SYMBOL_GPL(cxl_decoder_add); -/* - * Per the CXL specification (8.2.5.12 CXL HDM Decoder Capability Structure) - * single ported host-bridges need not publish a decoder capability when a - * passthrough decode can be assumed, i.e. all transactions that the uport sees - * are claimed and passed to the single dport. Default the range a 0-base - * 0-length until the first CXL region is activated. - */ -struct cxl_decoder *devm_cxl_add_passthrough_decoder(struct device *host, - struct cxl_port *port) +static void cxld_unregister(void *dev) { - struct cxl_dport *dport; - int target_map[1]; - - device_lock(&port->dev); - dport = list_first_entry_or_null(&port->dports, typeof(*dport), list); - device_unlock(&port->dev); - - if (!dport) - return ERR_PTR(-ENXIO); + device_unregister(dev); +} - target_map[0] = dport->port_id; - return devm_cxl_add_decoder(host, port, 1, 0, 0, 1, PAGE_SIZE, - CXL_DECODER_EXPANDER, 0, target_map); +int cxl_decoder_autoremove(struct device *host, struct cxl_decoder *cxld) +{ + return devm_add_action_or_reset(host, cxld_unregister, &cxld->dev); } -EXPORT_SYMBOL_GPL(devm_cxl_add_passthrough_decoder); +EXPORT_SYMBOL_GPL(cxl_decoder_autoremove); /** * __cxl_driver_register - register a driver for the cxl bus diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h index c85b7fbad02d..e0c9aacc4e9c 100644 --- a/drivers/cxl/core/core.h +++ b/drivers/cxl/core/core.h @@ -9,11 +9,6 @@ extern const struct device_type cxl_nvdimm_type; extern struct attribute_group cxl_base_attribute_group; -static inline void unregister_cxl_dev(void *dev) -{ - device_unregister(dev); -} - struct cxl_send_command; struct cxl_mem_query_commands; int cxl_query_cmd(struct cxl_memdev *cxlmd, diff --git a/drivers/cxl/core/pmem.c b/drivers/cxl/core/pmem.c index 74be5132df1c..5032f4c1c69d 100644 --- a/drivers/cxl/core/pmem.c +++ b/drivers/cxl/core/pmem.c @@ -222,6 +222,11 @@ static struct cxl_nvdimm *cxl_nvdimm_alloc(struct cxl_memdev *cxlmd) return cxl_nvd; } +static void cxl_nvd_unregister(void *dev) +{ + device_unregister(dev); +} + /** * devm_cxl_add_nvdimm() - add a bridge between a cxl_memdev and an nvdimm * @host: same host as @cxlmd @@ -251,7 +256,7 @@ int devm_cxl_add_nvdimm(struct device *host, struct cxl_memdev *cxlmd) dev_dbg(host, "%s: register %s\n", dev_name(dev->parent), dev_name(dev)); - return devm_add_action_or_reset(host, unregister_cxl_dev, dev); + return devm_add_action_or_reset(host, cxl_nvd_unregister, dev); err: put_device(dev); diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 9af5745ba2c0..a6687e7fd598 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -195,6 +195,7 @@ enum cxl_decoder_type { * @interleave_granularity: data stride per dport * @target_type: accelerator vs expander (type2 vs type3) selector * @flags: memory type capabilities and locking + * @nr_targets: number of elements in @target * @target: active ordered target list in current decoder configuration */ struct cxl_decoder { @@ -205,6 +206,7 @@ struct cxl_decoder { int interleave_granularity; enum cxl_decoder_type target_type; unsigned long flags; + const int nr_targets; struct cxl_dport *target[]; }; @@ -286,15 +288,10 @@ int cxl_add_dport(struct cxl_port *port, struct device *dport, int port_id, struct cxl_decoder *to_cxl_decoder(struct device *dev); bool is_root_decoder(struct device *dev); -struct cxl_decoder * -devm_cxl_add_decoder(struct device *host, struct cxl_port *port, int nr_targets, - resource_size_t base, resource_size_t len, - int interleave_ways, int interleave_granularity, - enum cxl_decoder_type type, unsigned long flags, - int *target_map); - -struct cxl_decoder *devm_cxl_add_passthrough_decoder(struct device *host, - struct cxl_port *port); +struct cxl_decoder *cxl_decoder_alloc(struct cxl_port *port, int nr_targets); +int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map); +int cxl_decoder_autoremove(struct device *host, struct cxl_decoder *cxld); + extern struct bus_type cxl_bus_type; struct cxl_driver { -- cgit From fa9a7d2db6134c737e7d6da3b0902766d92f06be Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 13 Sep 2021 09:33:22 -0700 Subject: Documentation/cxl: Add bus internal docs Kernel docs are already present in this file, but nothing is instructed to generate them. Address that. Acked-by: Jonathan Cameron Signed-off-by: Ben Widawsky Link: https://lore.kernel.org/r/20210913163324.1008564-2-ben.widawsky@intel.com Signed-off-by: Dan Williams --- Documentation/driver-api/cxl/memory-devices.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/driver-api/cxl/memory-devices.rst b/Documentation/driver-api/cxl/memory-devices.rst index 4624951b5c38..3b8f41395f6b 100644 --- a/Documentation/driver-api/cxl/memory-devices.rst +++ b/Documentation/driver-api/cxl/memory-devices.rst @@ -39,6 +39,9 @@ CXL Core .. kernel-doc:: drivers/cxl/core/bus.c :doc: cxl core +.. kernel-doc:: drivers/cxl/core/bus.c + :identifiers: + .. kernel-doc:: drivers/cxl/core/pmem.c :doc: cxl pmem -- cgit From ed97afb53365cd03dde266c9644334a558fe5a16 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 13 Sep 2021 09:33:24 -0700 Subject: cxl/pci: Disambiguate cxl_pci further from cxl_mem Commit 21e9f76733a8 ("cxl: Rename mem to pci") introduced the cxl_pci driver which had formerly been named cxl_mem. At the time, the goal was to be as light touch as possible because there were other patches in flight. Since things have settled now, and a new cxl_mem driver will be introduced shortly, spend the LOC now to clean up the existing names. While here, fix the kernel docs to explain the situation better after the core rework that has already landed. Reviewed-by: Jonathan Cameron Signed-off-by: Ben Widawsky Link: https://lore.kernel.org/r/20210913163324.1008564-4-ben.widawsky@intel.com Signed-off-by: Dan Williams --- drivers/cxl/pci.c | 68 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index 27f75b5a2ee2..64180f46c895 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -16,14 +16,16 @@ * * This implements the PCI exclusive functionality for a CXL device as it is * defined by the Compute Express Link specification. CXL devices may surface - * certain functionality even if it isn't CXL enabled. + * certain functionality even if it isn't CXL enabled. While this driver is + * focused around the PCI specific aspects of a CXL device, it binds to the + * specific CXL memory device class code, and therefore the implementation of + * cxl_pci is focused around CXL memory devices. * * The driver has several responsibilities, mainly: * - Create the memX device and register on the CXL bus. * - Enumerate device's register interface and map them. - * - Probe the device attributes to establish sysfs interface. - * - Provide an IOCTL interface to userspace to communicate with the device for - * things like firmware update. + * - Registers nvdimm bridge device with cxl_core. + * - Registers a CXL mailbox with cxl_core. */ #define cxl_doorbell_busy(cxlm) \ @@ -33,7 +35,7 @@ /* CXL 2.0 - 8.2.8.4 */ #define CXL_MAILBOX_TIMEOUT_MS (2 * HZ) -static int cxl_mem_wait_for_doorbell(struct cxl_mem *cxlm) +static int cxl_pci_mbox_wait_for_doorbell(struct cxl_mem *cxlm) { const unsigned long start = jiffies; unsigned long end = start; @@ -55,7 +57,7 @@ static int cxl_mem_wait_for_doorbell(struct cxl_mem *cxlm) return 0; } -static void cxl_mem_mbox_timeout(struct cxl_mem *cxlm, +static void cxl_pci_mbox_timeout(struct cxl_mem *cxlm, struct cxl_mbox_cmd *mbox_cmd) { struct device *dev = cxlm->dev; @@ -65,7 +67,7 @@ static void cxl_mem_mbox_timeout(struct cxl_mem *cxlm, } /** - * __cxl_mem_mbox_send_cmd() - Execute a mailbox command + * __cxl_pci_mbox_send_cmd() - Execute a mailbox command * @cxlm: The CXL memory device to communicate with. * @mbox_cmd: Command to send to the memory device. * @@ -86,7 +88,7 @@ static void cxl_mem_mbox_timeout(struct cxl_mem *cxlm, * not need to coordinate with each other. The driver only uses the primary * mailbox. */ -static int __cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm, +static int __cxl_pci_mbox_send_cmd(struct cxl_mem *cxlm, struct cxl_mbox_cmd *mbox_cmd) { void __iomem *payload = cxlm->regs.mbox + CXLDEV_MBOX_PAYLOAD_OFFSET; @@ -140,9 +142,9 @@ static int __cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm, cxlm->regs.mbox + CXLDEV_MBOX_CTRL_OFFSET); /* #5 */ - rc = cxl_mem_wait_for_doorbell(cxlm); + rc = cxl_pci_mbox_wait_for_doorbell(cxlm); if (rc == -ETIMEDOUT) { - cxl_mem_mbox_timeout(cxlm, mbox_cmd); + cxl_pci_mbox_timeout(cxlm, mbox_cmd); return rc; } @@ -181,13 +183,13 @@ static int __cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm, } /** - * cxl_mem_mbox_get() - Acquire exclusive access to the mailbox. + * cxl_pci_mbox_get() - Acquire exclusive access to the mailbox. * @cxlm: The memory device to gain access to. * * Context: Any context. Takes the mbox_mutex. * Return: 0 if exclusive access was acquired. */ -static int cxl_mem_mbox_get(struct cxl_mem *cxlm) +static int cxl_pci_mbox_get(struct cxl_mem *cxlm) { struct device *dev = cxlm->dev; u64 md_status; @@ -212,7 +214,7 @@ static int cxl_mem_mbox_get(struct cxl_mem *cxlm) * Mailbox Interface Ready bit. Therefore, waiting for the doorbell * to be ready is sufficient. */ - rc = cxl_mem_wait_for_doorbell(cxlm); + rc = cxl_pci_mbox_wait_for_doorbell(cxlm); if (rc) { dev_warn(dev, "Mailbox interface not ready\n"); goto out; @@ -252,12 +254,12 @@ out: } /** - * cxl_mem_mbox_put() - Release exclusive access to the mailbox. + * cxl_pci_mbox_put() - Release exclusive access to the mailbox. * @cxlm: The CXL memory device to communicate with. * * Context: Any context. Expects mbox_mutex to be held. */ -static void cxl_mem_mbox_put(struct cxl_mem *cxlm) +static void cxl_pci_mbox_put(struct cxl_mem *cxlm) { mutex_unlock(&cxlm->mbox_mutex); } @@ -266,17 +268,17 @@ static int cxl_pci_mbox_send(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) { int rc; - rc = cxl_mem_mbox_get(cxlm); + rc = cxl_pci_mbox_get(cxlm); if (rc) return rc; - rc = __cxl_mem_mbox_send_cmd(cxlm, cmd); - cxl_mem_mbox_put(cxlm); + rc = __cxl_pci_mbox_send_cmd(cxlm, cmd); + cxl_pci_mbox_put(cxlm); return rc; } -static int cxl_mem_setup_mailbox(struct cxl_mem *cxlm) +static int cxl_pci_setup_mailbox(struct cxl_mem *cxlm) { const int cap = readl(cxlm->regs.mbox + CXLDEV_MBOX_CAPS_OFFSET); @@ -304,7 +306,7 @@ static int cxl_mem_setup_mailbox(struct cxl_mem *cxlm) return 0; } -static void __iomem *cxl_mem_map_regblock(struct cxl_mem *cxlm, +static void __iomem *cxl_pci_map_regblock(struct cxl_mem *cxlm, u8 bar, u64 offset) { void __iomem *addr; @@ -330,12 +332,12 @@ static void __iomem *cxl_mem_map_regblock(struct cxl_mem *cxlm, return addr; } -static void cxl_mem_unmap_regblock(struct cxl_mem *cxlm, void __iomem *base) +static void cxl_pci_unmap_regblock(struct cxl_mem *cxlm, void __iomem *base) { pci_iounmap(to_pci_dev(cxlm->dev), base); } -static int cxl_mem_dvsec(struct pci_dev *pdev, int dvsec) +static int cxl_pci_dvsec(struct pci_dev *pdev, int dvsec) { int pos; @@ -427,7 +429,7 @@ static void cxl_decode_register_block(u32 reg_lo, u32 reg_hi, } /** - * cxl_mem_setup_regs() - Setup necessary MMIO. + * cxl_pci_setup_regs() - Setup necessary MMIO. * @cxlm: The CXL memory device to communicate with. * * Return: 0 if all necessary registers mapped. @@ -436,7 +438,7 @@ static void cxl_decode_register_block(u32 reg_lo, u32 reg_hi, * regions. The purpose of this function is to enumerate and map those * registers. */ -static int cxl_mem_setup_regs(struct cxl_mem *cxlm) +static int cxl_pci_setup_regs(struct cxl_mem *cxlm) { void __iomem *base; u32 regloc_size, regblocks; @@ -445,7 +447,7 @@ static int cxl_mem_setup_regs(struct cxl_mem *cxlm) struct pci_dev *pdev = to_pci_dev(dev); struct cxl_register_map *map, maps[CXL_REGLOC_RBI_TYPES]; - regloc = cxl_mem_dvsec(pdev, PCI_DVSEC_ID_CXL_REGLOC_DVSEC_ID); + regloc = cxl_pci_dvsec(pdev, PCI_DVSEC_ID_CXL_REGLOC_DVSEC_ID); if (!regloc) { dev_err(dev, "register location dvsec not found\n"); return -ENXIO; @@ -480,7 +482,7 @@ static int cxl_mem_setup_regs(struct cxl_mem *cxlm) if (reg_type > CXL_REGLOC_RBI_MEMDEV) continue; - base = cxl_mem_map_regblock(cxlm, bar, offset); + base = cxl_pci_map_regblock(cxlm, bar, offset); if (!base) return -ENOMEM; @@ -492,7 +494,7 @@ static int cxl_mem_setup_regs(struct cxl_mem *cxlm) ret = cxl_probe_regs(cxlm, base + offset, map); /* Always unmap the regblock regardless of probe success */ - cxl_mem_unmap_regblock(cxlm, base); + cxl_pci_unmap_regblock(cxlm, base); if (ret) return ret; @@ -511,7 +513,7 @@ static int cxl_mem_setup_regs(struct cxl_mem *cxlm) return ret; } -static int cxl_mem_probe(struct pci_dev *pdev, const struct pci_device_id *id) +static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct cxl_memdev *cxlmd; struct cxl_mem *cxlm; @@ -532,11 +534,11 @@ static int cxl_mem_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (IS_ERR(cxlm)) return PTR_ERR(cxlm); - rc = cxl_mem_setup_regs(cxlm); + rc = cxl_pci_setup_regs(cxlm); if (rc) return rc; - rc = cxl_mem_setup_mailbox(cxlm); + rc = cxl_pci_setup_mailbox(cxlm); if (rc) return rc; @@ -569,15 +571,15 @@ static const struct pci_device_id cxl_mem_pci_tbl[] = { }; MODULE_DEVICE_TABLE(pci, cxl_mem_pci_tbl); -static struct pci_driver cxl_mem_driver = { +static struct pci_driver cxl_pci_driver = { .name = KBUILD_MODNAME, .id_table = cxl_mem_pci_tbl, - .probe = cxl_mem_probe, + .probe = cxl_pci_probe, .driver = { .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; MODULE_LICENSE("GPL v2"); -module_pci_driver(cxl_mem_driver); +module_pci_driver(cxl_pci_driver); MODULE_IMPORT_NS(CXL); -- cgit From 9b6e27d01adcec58e046c624874f8a124e8b07ec Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 14 Sep 2021 12:30:32 -0400 Subject: nfsd: don't alloc under spinlock in rpc_parse_scope_id Dan Carpenter says: The patch d20c11d86d8f: "nfsd: Protect session creation and client confirm using client_lock" from Jul 30, 2014, leads to the following Smatch static checker warning: net/sunrpc/addr.c:178 rpc_parse_scope_id() warn: sleeping in atomic context Reported-by: Dan Carpenter Fixes: d20c11d86d8f ("nfsd: Protect session creation and client...") Signed-off-by: J. Bruce Fields --- net/sunrpc/addr.c | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/net/sunrpc/addr.c b/net/sunrpc/addr.c index 6e4dbd577a39..d435bffc6199 100644 --- a/net/sunrpc/addr.c +++ b/net/sunrpc/addr.c @@ -162,8 +162,10 @@ static int rpc_parse_scope_id(struct net *net, const char *buf, const size_t buflen, const char *delim, struct sockaddr_in6 *sin6) { - char *p; + char p[IPV6_SCOPE_ID_LEN + 1]; size_t len; + u32 scope_id = 0; + struct net_device *dev; if ((buf + buflen) == delim) return 1; @@ -175,29 +177,23 @@ static int rpc_parse_scope_id(struct net *net, const char *buf, return 0; len = (buf + buflen) - delim - 1; - p = kmemdup_nul(delim + 1, len, GFP_KERNEL); - if (p) { - u32 scope_id = 0; - struct net_device *dev; - - dev = dev_get_by_name(net, p); - if (dev != NULL) { - scope_id = dev->ifindex; - dev_put(dev); - } else { - if (kstrtou32(p, 10, &scope_id) != 0) { - kfree(p); - return 0; - } - } - - kfree(p); - - sin6->sin6_scope_id = scope_id; - return 1; + if (len > IPV6_SCOPE_ID_LEN) + return 0; + + memcpy(p, delim + 1, len); + p[len] = 0; + + dev = dev_get_by_name(net, p); + if (dev != NULL) { + scope_id = dev->ifindex; + dev_put(dev); + } else { + if (kstrtou32(p, 10, &scope_id) != 0) + return 0; } - return 0; + sin6->sin6_scope_id = scope_id; + return 1; } static size_t rpc_pton6(struct net *net, const char *buf, const size_t buflen, -- cgit From dc451bbc6f54a2c7bacef7ec445718709071b61c Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 10 Sep 2021 14:42:54 -0400 Subject: nfs: reexport documentation We've supported reexport for a while but documentation is limited. This is mainly a simplified version of the text I wrote for the linux-nfs wiki at https://wiki.linux-nfs.org/wiki/index.php/NFS_re-export. Signed-off-by: J. Bruce Fields --- Documentation/filesystems/nfs/index.rst | 1 + Documentation/filesystems/nfs/reexport.rst | 113 +++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 Documentation/filesystems/nfs/reexport.rst diff --git a/Documentation/filesystems/nfs/index.rst b/Documentation/filesystems/nfs/index.rst index 65805624e39b..288d8ddb2bc6 100644 --- a/Documentation/filesystems/nfs/index.rst +++ b/Documentation/filesystems/nfs/index.rst @@ -11,3 +11,4 @@ NFS rpc-server-gss nfs41-server knfsd-stats + reexport diff --git a/Documentation/filesystems/nfs/reexport.rst b/Documentation/filesystems/nfs/reexport.rst new file mode 100644 index 000000000000..ff9ae4a46530 --- /dev/null +++ b/Documentation/filesystems/nfs/reexport.rst @@ -0,0 +1,113 @@ +Reexporting NFS filesystems +=========================== + +Overview +-------- + +It is possible to reexport an NFS filesystem over NFS. However, this +feature comes with a number of limitations. Before trying it, we +recommend some careful research to determine whether it will work for +your purposes. + +A discussion of current known limitations follows. + +"fsid=" required, crossmnt broken +--------------------------------- + +We require the "fsid=" export option on any reexport of an NFS +filesystem. You can use "uuidgen -r" to generate a unique argument. + +The "crossmnt" export does not propagate "fsid=", so it will not allow +traversing into further nfs filesystems; if you wish to export nfs +filesystems mounted under the exported filesystem, you'll need to export +them explicitly, assigning each its own unique "fsid= option. + +Reboot recovery +--------------- + +The NFS protocol's normal reboot recovery mechanisms don't work for the +case when the reexport server reboots. Clients will lose any locks +they held before the reboot, and further IO will result in errors. +Closing and reopening files should clear the errors. + +Filehandle limits +----------------- + +If the original server uses an X byte filehandle for a given object, the +reexport server's filehandle for the reexported object will be X+22 +bytes, rounded up to the nearest multiple of four bytes. + +The result must fit into the RFC-mandated filehandle size limits: + ++-------+-----------+ +| NFSv2 | 32 bytes | ++-------+-----------+ +| NFSv3 | 64 bytes | ++-------+-----------+ +| NFSv4 | 128 bytes | ++-------+-----------+ + +So, for example, you will only be able to reexport a filesystem over +NFSv2 if the original server gives you filehandles that fit in 10 +bytes--which is unlikely. + +In general there's no way to know the maximum filehandle size given out +by an NFS server without asking the server vendor. + +But the following table gives a few examples. The first column is the +typical length of the filehandle from a Linux server exporting the given +filesystem, the second is the length after that nfs export is reexported +by another Linux host: + ++--------+-------------------+----------------+ +| | filehandle length | after reexport | ++========+===================+================+ +| ext4: | 28 bytes | 52 bytes | ++--------+-------------------+----------------+ +| xfs: | 32 bytes | 56 bytes | ++--------+-------------------+----------------+ +| btrfs: | 40 bytes | 64 bytes | ++--------+-------------------+----------------+ + +All will therefore fit in an NFSv3 or NFSv4 filehandle after reexport, +but none are reexportable over NFSv2. + +Linux server filehandles are a bit more complicated than this, though; +for example: + + - The (non-default) "subtreecheck" export option generally + requires another 4 to 8 bytes in the filehandle. + - If you export a subdirectory of a filesystem (instead of + exporting the filesystem root), that also usually adds 4 to 8 + bytes. + - If you export over NFSv2, knfsd usually uses a shorter + filesystem identifier that saves 8 bytes. + - The root directory of an export uses a filehandle that is + shorter. + +As you can see, the 128-byte NFSv4 filehandle is large enough that +you're unlikely to have trouble using NFSv4 to reexport any filesystem +exported from a Linux server. In general, if the original server is +something that also supports NFSv3, you're *probably* OK. Re-exporting +over NFSv3 may be dicier, and reexporting over NFSv2 will probably +never work. + +For more details of Linux filehandle structure, the best reference is +the source code and comments; see in particular: + + - include/linux/exportfs.h:enum fid_type + - include/uapi/linux/nfsd/nfsfh.h:struct nfs_fhbase_new + - fs/nfsd/nfsfh.c:set_version_and_fsid_type + - fs/nfs/export.c:nfs_encode_fh + +Open DENY bits ignored +---------------------- + +NFS since NFSv4 supports ALLOW and DENY bits taken from Windows, which +allow you, for example, to open a file in a mode which forbids other +read opens or write opens. The Linux client doesn't use them, and the +server's support has always been incomplete: they are enforced only +against other NFS users, not against processes accessing the exported +filesystem locally. A reexport server will also not pass them along to +the original server, so they will not be enforced between clients of +different reexport servers. -- cgit From 8847ecc9274a14114385d1cb4030326baa0766eb Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 20 Sep 2021 15:25:21 -0400 Subject: NFSD: Optimize DRC bucket pruning DRC bucket pruning is done by nfsd_cache_lookup(), which is part of every NFSv2 and NFSv3 dispatch (ie, it's done while the client is waiting). I added a trace_printk() in prune_bucket() to see just how long it takes to prune. Here are two ends of the spectrum: prune_bucket: Scanned 1 and freed 0 in 90 ns, 62 entries remaining prune_bucket: Scanned 2 and freed 1 in 716 ns, 63 entries remaining ... prune_bucket: Scanned 75 and freed 74 in 34149 ns, 1 entries remaining Pruning latency is noticeable on fast transports with fast storage. By noticeable, I mean that the latency measured here in the worst case is the same order of magnitude as the round trip time for cached server operations. We could do something like moving expired entries to an expired list and then free them later instead of freeing them right in prune_bucket(). But simply limiting the number of entries that can be pruned by a lookup is simple and retains more entries in the cache, making the DRC somewhat more effective. Comparison with a 70/30 fio 8KB 12 thread direct I/O test: Before: write: IOPS=61.6k, BW=481MiB/s (505MB/s)(14.1GiB/30001msec); 0 zone resets WRITE: 1848726 ops (30%) avg bytes sent per op: 8340 avg bytes received per op: 136 backlog wait: 0.635158 RTT: 0.128525 total execute time: 0.827242 (milliseconds) After: write: IOPS=63.0k, BW=492MiB/s (516MB/s)(14.4GiB/30001msec); 0 zone resets WRITE: 1891144 ops (30%) avg bytes sent per op: 8340 avg bytes received per op: 136 backlog wait: 0.616114 RTT: 0.126842 total execute time: 0.805348 (milliseconds) Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfscache.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c index 96cdf77925f3..6e0b6f3148dc 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c @@ -241,8 +241,8 @@ lru_put_end(struct nfsd_drc_bucket *b, struct svc_cacherep *rp) list_move_tail(&rp->c_lru, &b->lru_head); } -static long -prune_bucket(struct nfsd_drc_bucket *b, struct nfsd_net *nn) +static long prune_bucket(struct nfsd_drc_bucket *b, struct nfsd_net *nn, + unsigned int max) { struct svc_cacherep *rp, *tmp; long freed = 0; @@ -258,11 +258,17 @@ prune_bucket(struct nfsd_drc_bucket *b, struct nfsd_net *nn) time_before(jiffies, rp->c_timestamp + RC_EXPIRE)) break; nfsd_reply_cache_free_locked(b, rp, nn); - freed++; + if (max && freed++ > max) + break; } return freed; } +static long nfsd_prune_bucket(struct nfsd_drc_bucket *b, struct nfsd_net *nn) +{ + return prune_bucket(b, nn, 3); +} + /* * Walk the LRU list and prune off entries that are older than RC_EXPIRE. * Also prune the oldest ones when the total exceeds the max number of entries. @@ -279,7 +285,7 @@ prune_cache_entries(struct nfsd_net *nn) if (list_empty(&b->lru_head)) continue; spin_lock(&b->cache_lock); - freed += prune_bucket(b, nn); + freed += prune_bucket(b, nn, 0); spin_unlock(&b->cache_lock); } return freed; @@ -453,8 +459,7 @@ int nfsd_cache_lookup(struct svc_rqst *rqstp) atomic_inc(&nn->num_drc_entries); nfsd_stats_drc_mem_usage_add(nn, sizeof(*rp)); - /* go ahead and prune the cache */ - prune_bucket(b, nn); + nfsd_prune_bucket(b, nn); out_unlock: spin_unlock(&b->cache_lock); -- cgit From cb7bfb1da6f609bf954d5f164733ff35b1cb4d4e Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 27 Jan 2021 10:46:29 -0800 Subject: perf parse-events: Remove unnecessary #includes Minor cleanup motivated by trying to separately fuzz test parse-events. Signed-off-by: Ian Rogers Acked-by: Namhyung Kim Cc: Alexander Shishkin Cc: Andi Kleen Cc: Jin Yao Cc: Jiri Olsa Cc: Leo Yan Cc: Mark Rutland Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lore.kernel.org/lkml/20210127184629.516169-1-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 2 -- tools/perf/util/parse-events.l | 1 - 2 files changed, 3 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 5d1346aa0627..85d3d77d3c6a 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -19,8 +19,6 @@ #include #include "string2.h" #include "strlist.h" -#include "symbol.h" -#include "header.h" #include "bpf-loader.h" #include "debug.h" #include diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 923849024b15..47da7a0c5df4 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -12,7 +12,6 @@ #include #include #include -#include "../perf.h" #include "parse-events.h" #include "parse-events-bison.h" #include "evsel.h" -- cgit From 89b4db61c76197b899f9dc3dc06ea7c3a60729b8 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 29 Jul 2021 23:07:06 +0900 Subject: nios2: move the install rule to arch/nios2/Makefile Currently, the install target in arch/nios2/Makefile descends into arch/nios2/boot/Makefile to invoke the shell script, but it is no good reason to do so. arch/nios2/Makefile can run the shell script directly. Signed-off-by: Masahiro Yamada --- arch/nios2/Makefile | 3 ++- arch/nios2/boot/Makefile | 3 --- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/nios2/Makefile b/arch/nios2/Makefile index 52c03e60b114..72e8ff065cf7 100644 --- a/arch/nios2/Makefile +++ b/arch/nios2/Makefile @@ -60,7 +60,8 @@ $(BOOT_TARGETS): vmlinux $(Q)$(MAKE) $(build)=$(nios2-boot) $(nios2-boot)/$@ install: - $(Q)$(MAKE) $(build)=$(nios2-boot) BOOTIMAGE=$(KBUILD_IMAGE) install + sh $(srctree)/$(nios2-boot)/install.sh $(KERNELRELEASE) \ + $(KBUILD_IMAGE) System.map "$(INSTALL_PATH)" define archhelp echo '* vmImage - Kernel-only image for U-Boot ($(KBUILD_IMAGE))' diff --git a/arch/nios2/boot/Makefile b/arch/nios2/boot/Makefile index 37dfc7e584bc..8c3ad76602f3 100644 --- a/arch/nios2/boot/Makefile +++ b/arch/nios2/boot/Makefile @@ -30,6 +30,3 @@ $(obj)/zImage: $(obj)/compressed/vmlinux FORCE $(obj)/compressed/vmlinux: $(obj)/vmlinux.gz FORCE $(Q)$(MAKE) $(build)=$(obj)/compressed $@ - -install: - sh $(srctree)/$(src)/install.sh $(KERNELRELEASE) $(BOOTIMAGE) System.map "$(INSTALL_PATH)" -- cgit From 04e85bbf71c9072dcf0ad9a7150495d72461105c Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 2 Aug 2021 23:43:15 +0300 Subject: isystem: delete global -isystem compile option Further isolate kernel from userspace, prevent accidental inclusion of undesireable headers, mainly float.h and stdatomic.h. nds32 keeps -isystem globally due to intrinsics used in entrenched header. -isystem is selectively reenabled for some files, again, for intrinsics. Compile tested on: hexagon-defconfig hexagon-allmodconfig alpha-allmodconfig alpha-allnoconfig alpha-defconfig arm64-allmodconfig arm64-allnoconfig arm64-defconfig arm-am200epdkit arm-aspeed_g4 arm-aspeed_g5 arm-assabet arm-at91_dt arm-axm55xx arm-badge4 arm-bcm2835 arm-cerfcube arm-clps711x arm-cm_x300 arm-cns3420vb arm-colibri_pxa270 arm-colibri_pxa300 arm-collie arm-corgi arm-davinci_all arm-dove arm-ep93xx arm-eseries_pxa arm-exynos arm-ezx arm-footbridge arm-gemini arm-h3600 arm-h5000 arm-hackkit arm-hisi arm-imote2 arm-imx_v4_v5 arm-imx_v6_v7 arm-integrator arm-iop32x arm-ixp4xx arm-jornada720 arm-keystone arm-lart arm-lpc18xx arm-lpc32xx arm-lpd270 arm-lubbock arm-magician arm-mainstone arm-milbeaut_m10v arm-mini2440 arm-mmp2 arm-moxart arm-mps2 arm-multi_v4t arm-multi_v5 arm-multi_v7 arm-mv78xx0 arm-mvebu_v5 arm-mvebu_v7 arm-mxs arm-neponset arm-netwinder arm-nhk8815 arm-omap1 arm-omap2plus arm-orion5x arm-oxnas_v6 arm-palmz72 arm-pcm027 arm-pleb arm-pxa arm-pxa168 arm-pxa255-idp arm-pxa3xx arm-pxa910 arm-qcom arm-realview arm-rpc arm-s3c2410 arm-s3c6400 arm-s5pv210 arm-sama5 arm-shannon arm-shmobile arm-simpad arm-socfpga arm-spear13xx arm-spear3xx arm-spear6xx arm-spitz arm-stm32 arm-sunxi arm-tct_hammer arm-tegra arm-trizeps4 arm-u8500 arm-versatile arm-vexpress arm-vf610m4 arm-viper arm-vt8500_v6_v7 arm-xcep arm-zeus csky-allmodconfig csky-allnoconfig csky-defconfig h8300-edosk2674 h8300-h8300h-sim h8300-h8s-sim i386-allmodconfig i386-allnoconfig i386-defconfig ia64-allmodconfig ia64-allnoconfig ia64-bigsur ia64-generic ia64-gensparse ia64-tiger ia64-zx1 m68k-amcore m68k-amiga m68k-apollo m68k-atari m68k-bvme6000 m68k-hp300 m68k-m5208evb m68k-m5249evb m68k-m5272c3 m68k-m5275evb m68k-m5307c3 m68k-m5407c3 m68k-m5475evb m68k-mac m68k-multi m68k-mvme147 m68k-mvme16x m68k-q40 m68k-stmark2 m68k-sun3 m68k-sun3x microblaze-allmodconfig microblaze-allnoconfig microblaze-mmu mips-ar7 mips-ath25 mips-ath79 mips-bcm47xx mips-bcm63xx mips-bigsur mips-bmips_be mips-bmips_stb mips-capcella mips-cavium_octeon mips-ci20 mips-cobalt mips-cu1000-neo mips-cu1830-neo mips-db1xxx mips-decstation mips-decstation_64 mips-decstation_r4k mips-e55 mips-fuloong2e mips-gcw0 mips-generic mips-gpr mips-ip22 mips-ip27 mips-ip28 mips-ip32 mips-jazz mips-jmr3927 mips-lemote2f mips-loongson1b mips-loongson1c mips-loongson2k mips-loongson3 mips-malta mips-maltaaprp mips-malta_kvm mips-malta_qemu_32r6 mips-maltasmvp mips-maltasmvp_eva mips-maltaup mips-maltaup_xpa mips-mpc30x mips-mtx1 mips-nlm_xlp mips-nlm_xlr mips-omega2p mips-pic32mzda mips-pistachio mips-qi_lb60 mips-rb532 mips-rbtx49xx mips-rm200 mips-rs90 mips-rt305x mips-sb1250_swarm mips-tb0219 mips-tb0226 mips-tb0287 mips-vocore2 mips-workpad mips-xway nds32-allmodconfig nds32-allnoconfig nds32-defconfig nios2-10m50 nios2-3c120 nios2-allmodconfig nios2-allnoconfig openrisc-allmodconfig openrisc-allnoconfig openrisc-or1klitex openrisc-or1ksim openrisc-simple_smp parisc-allnoconfig parisc-generic-32bit parisc-generic-64bit powerpc-acadia powerpc-adder875 powerpc-akebono powerpc-amigaone powerpc-arches powerpc-asp8347 powerpc-bamboo powerpc-bluestone powerpc-canyonlands powerpc-cell powerpc-chrp32 powerpc-cm5200 powerpc-currituck powerpc-ebony powerpc-eiger powerpc-ep8248e powerpc-ep88xc powerpc-fsp2 powerpc-g5 powerpc-gamecube powerpc-ge_imp3a powerpc-holly powerpc-icon powerpc-iss476-smp powerpc-katmai powerpc-kilauea powerpc-klondike powerpc-kmeter1 powerpc-ksi8560 powerpc-linkstation powerpc-lite5200b powerpc-makalu powerpc-maple powerpc-mgcoge powerpc-microwatt powerpc-motionpro powerpc-mpc512x powerpc-mpc5200 powerpc-mpc7448_hpc2 powerpc-mpc8272_ads powerpc-mpc8313_rdb powerpc-mpc8315_rdb powerpc-mpc832x_mds powerpc-mpc832x_rdb powerpc-mpc834x_itx powerpc-mpc834x_itxgp powerpc-mpc834x_mds powerpc-mpc836x_mds powerpc-mpc836x_rdk powerpc-mpc837x_mds powerpc-mpc837x_rdb powerpc-mpc83xx powerpc-mpc8540_ads powerpc-mpc8560_ads powerpc-mpc85xx_cds powerpc-mpc866_ads powerpc-mpc885_ads powerpc-mvme5100 powerpc-obs600 powerpc-pasemi powerpc-pcm030 powerpc-pmac32 powerpc-powernv powerpc-ppa8548 powerpc-ppc40x powerpc-ppc44x powerpc-ppc64 powerpc-ppc64e powerpc-ppc6xx powerpc-pq2fads powerpc-ps3 powerpc-pseries powerpc-rainier powerpc-redwood powerpc-sam440ep powerpc-sbc8548 powerpc-sequoia powerpc-skiroot powerpc-socrates powerpc-storcenter powerpc-stx_gp3 powerpc-taishan powerpc-tqm5200 powerpc-tqm8540 powerpc-tqm8541 powerpc-tqm8548 powerpc-tqm8555 powerpc-tqm8560 powerpc-tqm8xx powerpc-walnut powerpc-warp powerpc-wii powerpc-xes_mpc85xx riscv-allmodconfig riscv-allnoconfig riscv-nommu_k210 riscv-nommu_k210_sdcard riscv-nommu_virt riscv-rv32 s390-allmodconfig s390-allnoconfig s390-debug s390-zfcpdump sh-ap325rxa sh-apsh4a3a sh-apsh4ad0a sh-dreamcast sh-ecovec24 sh-ecovec24-romimage sh-edosk7705 sh-edosk7760 sh-espt sh-hp6xx sh-j2 sh-kfr2r09 sh-kfr2r09-romimage sh-landisk sh-lboxre2 sh-magicpanelr2 sh-microdev sh-migor sh-polaris sh-r7780mp sh-r7785rp sh-rsk7201 sh-rsk7203 sh-rsk7264 sh-rsk7269 sh-rts7751r2d1 sh-rts7751r2dplus sh-sdk7780 sh-sdk7786 sh-se7206 sh-se7343 sh-se7619 sh-se7705 sh-se7712 sh-se7721 sh-se7722 sh-se7724 sh-se7750 sh-se7751 sh-se7780 sh-secureedge5410 sh-sh03 sh-sh2007 sh-sh7710voipgw sh-sh7724_generic sh-sh7757lcr sh-sh7763rdp sh-sh7770_generic sh-sh7785lcr sh-sh7785lcr_32bit sh-shmin sh-shx3 sh-titan sh-ul2 sh-urquell sparc-allmodconfig sparc-allnoconfig sparc-sparc32 sparc-sparc64 um-i386-allmodconfig um-i386-allnoconfig um-i386-defconfig um-x86_64-allmodconfig um-x86_64-allnoconfig x86_64-allmodconfig x86_64-allnoconfig x86_64-defconfig xtensa-allmodconfig xtensa-allnoconfig xtensa-audio_kc705 xtensa-cadence_csp xtensa-common xtensa-generic_kc705 xtensa-iss xtensa-nommu_kc705 xtensa-smp_lx200 xtensa-virt xtensa-xip_kc705 Tested-by: Nathan Chancellor # build (hexagon) Signed-off-by: Alexey Dobriyan Acked-by: Ard Biesheuvel Signed-off-by: Masahiro Yamada --- Makefile | 2 +- arch/arm64/lib/Makefile | 2 ++ arch/nds32/Makefile | 2 ++ arch/powerpc/lib/Makefile | 2 ++ crypto/Makefile | 2 ++ lib/raid6/Makefile | 4 ++++ 6 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5e7c1d854441..ee5896261d2f 100644 --- a/Makefile +++ b/Makefile @@ -981,7 +981,7 @@ KBUILD_CFLAGS += -falign-functions=64 endif # arch Makefile may override CC so keep this after arch Makefile is included -NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include) +NOSTDINC_FLAGS += -nostdinc # warn about C99 declaration after statement KBUILD_CFLAGS += -Wdeclaration-after-statement diff --git a/arch/arm64/lib/Makefile b/arch/arm64/lib/Makefile index 0941180a86d3..29490be2546b 100644 --- a/arch/arm64/lib/Makefile +++ b/arch/arm64/lib/Makefile @@ -9,6 +9,8 @@ ifeq ($(CONFIG_KERNEL_MODE_NEON), y) obj-$(CONFIG_XOR_BLOCKS) += xor-neon.o CFLAGS_REMOVE_xor-neon.o += -mgeneral-regs-only CFLAGS_xor-neon.o += -ffreestanding +# Enable +CFLAGS_xor-neon.o += -isystem $(shell $(CC) -print-file-name=include) endif lib-$(CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE) += uaccess_flushcache.o diff --git a/arch/nds32/Makefile b/arch/nds32/Makefile index ccdca7142020..c17fc3a755c3 100644 --- a/arch/nds32/Makefile +++ b/arch/nds32/Makefile @@ -9,6 +9,8 @@ endif # Avoid generating FPU instructions arch-y += -mno-ext-fpu-sp -mno-ext-fpu-dp -mfloat-abi=soft +# Enable +KBUILD_CFLAGS += -isystem $(shell $(CC) -print-file-name=include) KBUILD_CFLAGS += $(call cc-option, -mno-sched-prolog-epilog) KBUILD_CFLAGS += -mcmodel=large diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 99a7c9132422..9e5d0f413b71 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -65,5 +65,7 @@ obj-$(CONFIG_FTR_FIXUP_SELFTEST) += feature-fixups-test.o obj-$(CONFIG_ALTIVEC) += xor_vmx.o xor_vmx_glue.o CFLAGS_xor_vmx.o += -maltivec $(call cc-option,-mabi=altivec) +# Enable +CFLAGS_xor_vmx.o += -isystem $(shell $(CC) -print-file-name=include) obj-$(CONFIG_PPC64) += $(obj64-y) diff --git a/crypto/Makefile b/crypto/Makefile index c633f15a0481..429c4d57458c 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -119,6 +119,8 @@ CFLAGS_aegis128-neon-inner.o += $(aegis128-cflags-y) CFLAGS_REMOVE_aegis128-neon-inner.o += -mgeneral-regs-only aegis128-$(CONFIG_CRYPTO_AEGIS128_SIMD) += aegis128-neon.o aegis128-neon-inner.o endif +# Enable +CFLAGS_aegis128-neon-inner.o += -isystem $(shell $(CC) -print-file-name=include) obj-$(CONFIG_CRYPTO_PCRYPT) += pcrypt.o obj-$(CONFIG_CRYPTO_CRYPTD) += cryptd.o diff --git a/lib/raid6/Makefile b/lib/raid6/Makefile index c770570bfe4f..45e17619422b 100644 --- a/lib/raid6/Makefile +++ b/lib/raid6/Makefile @@ -14,6 +14,8 @@ hostprogs += mktables ifeq ($(CONFIG_ALTIVEC),y) altivec_flags := -maltivec $(call cc-option,-mabi=altivec) +# Enable +altivec_flags += -isystem $(shell $(CC) -print-file-name=include) ifdef CONFIG_CC_IS_CLANG # clang ppc port does not yet support -maltivec when -msoft-float is @@ -34,6 +36,8 @@ endif # ARM/NEON intrinsics in a non C99-compliant environment (such as the kernel) ifeq ($(CONFIG_KERNEL_MODE_NEON),y) NEON_FLAGS := -ffreestanding +# Enable +NEON_FLAGS += -isystem $(shell $(CC) -print-file-name=include) ifeq ($(ARCH),arm) NEON_FLAGS += -march=armv7-a -mfloat-abi=softfp -mfpu=neon endif -- cgit From 8f0c32c788fffa8e88f995372415864039347c8a Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 31 Aug 2021 16:39:52 +0900 Subject: kbuild: move objtool_args back to scripts/Makefile.build Commit b1a1a1a09b46 ("kbuild: lto: postpone objtool") moved objtool_args to Makefile.lib, so the arguments can be used in Makefile.modfinal as well as Makefile.build. With commit 850ded46c642 ("kbuild: Fix TRIM_UNUSED_KSYMS with LTO_CLANG"), module LTO linking came back to scripts/Makefile.build again. So, there is no more reason to keep objtool_args in a separate file. Get it back to the original place, close to the objtool command. Remove the stale comment too. Signed-off-by: Masahiro Yamada Reviewed-by: Kees Cook Acked-by: Josh Poimboeuf --- scripts/Makefile.build | 10 ++++++++++ scripts/Makefile.lib | 11 ----------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 3efc984d4c69..17508c0e4358 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -224,6 +224,16 @@ cmd_record_mcount = $(if $(findstring $(strip $(CC_FLAGS_FTRACE)),$(_c_flags)), endif # CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT ifdef CONFIG_STACK_VALIDATION + +objtool_args = \ + $(if $(CONFIG_UNWINDER_ORC),orc generate,check) \ + $(if $(part-of-module), --module) \ + $(if $(CONFIG_FRAME_POINTER),, --no-fp) \ + $(if $(CONFIG_GCOV_KERNEL)$(CONFIG_LTO_CLANG), --no-unreachable)\ + $(if $(CONFIG_RETPOLINE), --retpoline) \ + $(if $(CONFIG_X86_SMAP), --uaccess) \ + $(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount) + ifndef CONFIG_LTO_CLANG __objtool_obj := $(objtree)/tools/objtool/objtool diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 54582673fc1a..0a8a4689c3eb 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -232,17 +232,6 @@ ifeq ($(CONFIG_LTO_CLANG),y) mod-prelink-ext := .lto endif -# Objtool arguments are also needed for modfinal with LTO, so we define -# then here to avoid duplication. -objtool_args = \ - $(if $(CONFIG_UNWINDER_ORC),orc generate,check) \ - $(if $(part-of-module), --module) \ - $(if $(CONFIG_FRAME_POINTER),, --no-fp) \ - $(if $(CONFIG_GCOV_KERNEL)$(CONFIG_LTO_CLANG), --no-unreachable)\ - $(if $(CONFIG_RETPOLINE), --retpoline) \ - $(if $(CONFIG_X86_SMAP), --uaccess) \ - $(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount) - # Useful for describing the dependency of composite objects # Usage: # $(call multi_depend, multi_used_targets, suffix_to_remove, suffix_to_add) -- cgit From 5c4859e77aa11f9a8d9533962389893d199df70e Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 31 Aug 2021 16:39:53 +0900 Subject: kbuild: rename __objtool_obj and reuse it for cmd_cc_lto_link_modules Rename __objtool_obj to objtool, and move it out of the 'ifndef CONFIG_LTO_CLANG' conditional, so it can be used for cmd_cc_lto_link_modules as well. Signed-off-by: Masahiro Yamada Reviewed-by: Nick Desaulniers Reviewed-by: Kees Cook Acked-by: Josh Poimboeuf --- scripts/Makefile.build | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 17508c0e4358..e78096cd396b 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -225,6 +225,8 @@ endif # CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT ifdef CONFIG_STACK_VALIDATION +objtool := $(objtree)/tools/objtool/objtool + objtool_args = \ $(if $(CONFIG_UNWINDER_ORC),orc generate,check) \ $(if $(part-of-module), --module) \ @@ -236,17 +238,15 @@ objtool_args = \ ifndef CONFIG_LTO_CLANG -__objtool_obj := $(objtree)/tools/objtool/objtool - # 'OBJECT_FILES_NON_STANDARD := y': skip objtool checking for a directory # 'OBJECT_FILES_NON_STANDARD_foo.o := 'y': skip objtool checking for a file # 'OBJECT_FILES_NON_STANDARD_foo.o := 'n': override directory skip for a file cmd_objtool = $(if $(patsubst y%,, \ $(OBJECT_FILES_NON_STANDARD_$(basetarget).o)$(OBJECT_FILES_NON_STANDARD)n), \ - $(__objtool_obj) $(objtool_args) $@) + $(objtool) $(objtool_args) $@) objtool_obj = $(if $(patsubst y%,, \ $(OBJECT_FILES_NON_STANDARD_$(basetarget).o)$(OBJECT_FILES_NON_STANDARD)n), \ - $(__objtool_obj)) + $(objtool)) endif # CONFIG_LTO_CLANG endif # CONFIG_STACK_VALIDATION @@ -300,8 +300,7 @@ cmd_cc_lto_link_modules = \ ifdef CONFIG_STACK_VALIDATION # objtool was skipped for LLVM bitcode, run it now that we have compiled # modules into native code -cmd_cc_lto_link_modules += ; \ - $(objtree)/tools/objtool/objtool $(objtool_args) --module $@ +cmd_cc_lto_link_modules += ; $(objtool) $(objtool_args) --module $@ endif $(obj)/%.lto.o: $(obj)/%.o FORCE -- cgit From 92594d569b6d377168fa74c6bb27c5696af02a9d Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 31 Aug 2021 16:39:54 +0900 Subject: kbuild: store the objtool command in *.cmd files objtool_dep includes include/config/{ORC_UNWINDER,STACK_VALIDATION} so that all the objects are rebuilt when CONFIG_ORC_UNWINDER or CONFIG_STACK_VALIDATION is toggled. BTW, the correct option name is not CONFIG_ORC_UNWINDER, but CONFIG_UNWINDER_ORC. Commit 11af847446ed ("x86/unwind: Rename unwinder config options to 'CONFIG_UNWINDER_*'") missed to adjust this part. So, this dependency has been broken for a long time. As you can see in 'objtool_args', there are more CONFIG options that affect the objtool command line. Adding more and more include/config/* is ugly and unmaintainable. Another issue is that non-standard objects are needlessly rebuilt. Objects specified as OBJECT_FILES_NON_STANDARD is not processed by objtool, but they are rebuilt anyway when CONFIG_STACK_VALIDATION is toggled. This is not a big deal, but better to fix. A cleaner and more precise fix is to include the objtool command in *.cmd files so any command change is naturally detected by if_change. Signed-off-by: Masahiro Yamada Reviewed-by: Nick Desaulniers Reviewed-by: Kees Cook Acked-by: Josh Poimboeuf --- scripts/Makefile.build | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/scripts/Makefile.build b/scripts/Makefile.build index e78096cd396b..021ae0146913 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -155,7 +155,7 @@ $(obj)/%.ll: $(src)/%.c FORCE # (See cmd_cc_o_c + relevant part of rule_cc_o_c) quiet_cmd_cc_o_c = CC $(quiet_modtag) $@ - cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< + cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< $(cmd_objtool) ifdef CONFIG_MODVERSIONS # When module versioning is enabled the following steps are executed: @@ -243,7 +243,7 @@ ifndef CONFIG_LTO_CLANG # 'OBJECT_FILES_NON_STANDARD_foo.o := 'n': override directory skip for a file cmd_objtool = $(if $(patsubst y%,, \ $(OBJECT_FILES_NON_STANDARD_$(basetarget).o)$(OBJECT_FILES_NON_STANDARD)n), \ - $(objtool) $(objtool_args) $@) + ; $(objtool) $(objtool_args) $@) objtool_obj = $(if $(patsubst y%,, \ $(OBJECT_FILES_NON_STANDARD_$(basetarget).o)$(OBJECT_FILES_NON_STANDARD)n), \ $(objtool)) @@ -251,10 +251,8 @@ objtool_obj = $(if $(patsubst y%,, \ endif # CONFIG_LTO_CLANG endif # CONFIG_STACK_VALIDATION -# Rebuild all objects when objtool changes, or is enabled/disabled. -objtool_dep = $(objtool_obj) \ - $(wildcard include/config/ORC_UNWINDER \ - include/config/STACK_VALIDATION) +# Rebuild all objects when objtool changes +objtool_dep = $(objtool_obj) ifdef CONFIG_TRIM_UNUSED_KSYMS cmd_gen_ksymdeps = \ @@ -269,7 +267,6 @@ define rule_cc_o_c $(call cmd,gen_ksymdeps) $(call cmd,checksrc) $(call cmd,checkdoc) - $(call cmd,objtool) $(call cmd,modversions_c) $(call cmd,record_mcount) endef @@ -277,7 +274,6 @@ endef define rule_as_o_S $(call cmd_and_fixdep,as_o_S) $(call cmd,gen_ksymdeps) - $(call cmd,objtool) $(call cmd,modversions_S) endef @@ -365,7 +361,7 @@ $(obj)/%.s: $(src)/%.S FORCE $(call if_changed_dep,cpp_s_S) quiet_cmd_as_o_S = AS $(quiet_modtag) $@ - cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $< + cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $< $(cmd_objtool) ifdef CONFIG_ASM_MODVERSIONS -- cgit From 918a6b7f68468ab80ec5e7ab7f3d2ef88905c20b Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 31 Aug 2021 16:39:55 +0900 Subject: kbuild: factor out OBJECT_FILES_NON_STANDARD check into a macro The OBJECT_FILES_NON_STANDARD check is quite long. Factor it out into a new macro, objtool-enabled, to not repeat it. Signed-off-by: Masahiro Yamada Reviewed-by: Nick Desaulniers Reviewed-by: Kees Cook Acked-by: Josh Poimboeuf --- scripts/Makefile.build | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 021ae0146913..720a86642f48 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -241,12 +241,12 @@ ifndef CONFIG_LTO_CLANG # 'OBJECT_FILES_NON_STANDARD := y': skip objtool checking for a directory # 'OBJECT_FILES_NON_STANDARD_foo.o := 'y': skip objtool checking for a file # 'OBJECT_FILES_NON_STANDARD_foo.o := 'n': override directory skip for a file -cmd_objtool = $(if $(patsubst y%,, \ - $(OBJECT_FILES_NON_STANDARD_$(basetarget).o)$(OBJECT_FILES_NON_STANDARD)n), \ - ; $(objtool) $(objtool_args) $@) -objtool_obj = $(if $(patsubst y%,, \ - $(OBJECT_FILES_NON_STANDARD_$(basetarget).o)$(OBJECT_FILES_NON_STANDARD)n), \ - $(objtool)) + +objtool-enabled = $(if $(filter-out y%, \ + $(OBJECT_FILES_NON_STANDARD_$(basetarget).o)$(OBJECT_FILES_NON_STANDARD)n),y) + +cmd_objtool = $(if $(objtool-enabled), ; $(objtool) $(objtool_args) $@) +objtool_obj = $(if $(objtool-enabled), $(objtool)) endif # CONFIG_LTO_CLANG endif # CONFIG_STACK_VALIDATION -- cgit From ef62588c2c8611c196b780561610921b7b864bb2 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 31 Aug 2021 16:39:56 +0900 Subject: kbuild: detect objtool update without using .SECONDEXPANSION Redo commit 8852c5524029 ("kbuild: Fix objtool dependency for 'OBJECT_FILES_NON_STANDARD_ := n'") to add the objtool dependency in a cleaner way. Using .SECONDEXPANSION ends up with unreadable code due to escaped dollars. Also, it is not efficient because the second half of Makefile.build is parsed twice every time. Append the objtool dependency to the *.cmd files at the build time. This is what fixdep and gen_ksymdeps.sh already do. So, following the same pattern seems a natural solution. This allows us to drop $$(objtool_dep) entirely. Signed-off-by: Masahiro Yamada Reviewed-by: Kees Cook Reviewed-by: Nick Desaulniers Acked-by: Josh Poimboeuf --- scripts/Makefile.build | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 720a86642f48..21b55f37a23f 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -246,14 +246,11 @@ objtool-enabled = $(if $(filter-out y%, \ $(OBJECT_FILES_NON_STANDARD_$(basetarget).o)$(OBJECT_FILES_NON_STANDARD)n),y) cmd_objtool = $(if $(objtool-enabled), ; $(objtool) $(objtool_args) $@) -objtool_obj = $(if $(objtool-enabled), $(objtool)) +cmd_gen_objtooldep = $(if $(objtool-enabled), { echo ; echo '$@: $$(wildcard $(objtool))' ; } >> $(dot-target).cmd) endif # CONFIG_LTO_CLANG endif # CONFIG_STACK_VALIDATION -# Rebuild all objects when objtool changes -objtool_dep = $(objtool_obj) - ifdef CONFIG_TRIM_UNUSED_KSYMS cmd_gen_ksymdeps = \ $(CONFIG_SHELL) $(srctree)/scripts/gen_ksymdeps.sh $@ >> $(dot-target).cmd @@ -267,6 +264,7 @@ define rule_cc_o_c $(call cmd,gen_ksymdeps) $(call cmd,checksrc) $(call cmd,checkdoc) + $(call cmd,gen_objtooldep) $(call cmd,modversions_c) $(call cmd,record_mcount) endef @@ -274,12 +272,12 @@ endef define rule_as_o_S $(call cmd_and_fixdep,as_o_S) $(call cmd,gen_ksymdeps) + $(call cmd,gen_objtooldep) $(call cmd,modversions_S) endef # Built-in and composite module parts -.SECONDEXPANSION: -$(obj)/%.o: $(src)/%.c $(recordmcount_source) $$(objtool_dep) FORCE +$(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE $(call if_changed_rule,cc_o_c) $(call cmd,force_checksrc) @@ -380,7 +378,7 @@ cmd_modversions_S = \ fi endif -$(obj)/%.o: $(src)/%.S $$(objtool_dep) FORCE +$(obj)/%.o: $(src)/%.S FORCE $(call if_changed_rule,as_o_S) targets += $(filter-out $(subdir-builtin), $(real-obj-y)) -- cgit From 90a353491e9f95516fcfd33ae7331d638557416c Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 31 Aug 2021 16:39:57 +0900 Subject: kbuild: reuse $(cmd_objtool) for cmd_cc_lto_link_modules For CONFIG_LTO_CLANG=y, the objtool processing is not possible at the compilation, hence postponed by the link time. Reuse $(cmd_objtool) for CONFIG_LTO_CLANG=y by defining objtool-enabled properly. For CONFIG_LTO_CLANG=y: objtool-enabled is off for %.o compilation objtool-enabled is on for %.lto link For CONFIG_LTO_CLANG=n: objtool-enabled is on for %.o compilation (but, it depends on OBJECT_FILE_NON_STANDARD) Set part-of-module := y for %.lto.o to avoid repeating --module. Signed-off-by: Masahiro Yamada Reviewed-by: Kees Cook Acked-by: Josh Poimboeuf --- scripts/Makefile.build | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 21b55f37a23f..78656b527fe5 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -236,20 +236,26 @@ objtool_args = \ $(if $(CONFIG_X86_SMAP), --uaccess) \ $(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount) -ifndef CONFIG_LTO_CLANG +cmd_objtool = $(if $(objtool-enabled), ; $(objtool) $(objtool_args) $@) +cmd_gen_objtooldep = $(if $(objtool-enabled), { echo ; echo '$@: $$(wildcard $(objtool))' ; } >> $(dot-target).cmd) + +endif # CONFIG_STACK_VALIDATION + +ifdef CONFIG_LTO_CLANG + +# Skip objtool for LLVM bitcode +$(obj)/%.o: objtool-enabled := + +else # 'OBJECT_FILES_NON_STANDARD := y': skip objtool checking for a directory # 'OBJECT_FILES_NON_STANDARD_foo.o := 'y': skip objtool checking for a file # 'OBJECT_FILES_NON_STANDARD_foo.o := 'n': override directory skip for a file -objtool-enabled = $(if $(filter-out y%, \ +$(obj)/%.o: objtool-enabled = $(if $(filter-out y%, \ $(OBJECT_FILES_NON_STANDARD_$(basetarget).o)$(OBJECT_FILES_NON_STANDARD)n),y) -cmd_objtool = $(if $(objtool-enabled), ; $(objtool) $(objtool_args) $@) -cmd_gen_objtooldep = $(if $(objtool-enabled), { echo ; echo '$@: $$(wildcard $(objtool))' ; } >> $(dot-target).cmd) - -endif # CONFIG_LTO_CLANG -endif # CONFIG_STACK_VALIDATION +endif ifdef CONFIG_TRIM_UNUSED_KSYMS cmd_gen_ksymdeps = \ @@ -289,13 +295,13 @@ cmd_cc_lto_link_modules = \ $(LD) $(ld_flags) -r -o $@ \ $(shell [ -s $(@:.lto.o=.o.symversions) ] && \ echo -T $(@:.lto.o=.o.symversions)) \ - --whole-archive $(filter-out FORCE,$^) + --whole-archive $(filter-out FORCE,$^) \ + $(cmd_objtool) -ifdef CONFIG_STACK_VALIDATION # objtool was skipped for LLVM bitcode, run it now that we have compiled # modules into native code -cmd_cc_lto_link_modules += ; $(objtool) $(objtool_args) --module $@ -endif +$(obj)/%.lto.o: objtool-enabled = y +$(obj)/%.lto.o: part-of-module := y $(obj)/%.lto.o: $(obj)/%.o FORCE $(call if_changed,cc_lto_link_modules) -- cgit From a7c0520669869c088dc207735c2e85888a10b0eb Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 17 Sep 2021 14:27:51 -0700 Subject: scsi: core: Remove include from scsi_cmnd.h There are no dependencies in on the header file. Hence remove the scsi_host.h include directive from scsi_cmnd.h. This include directive was introduced in February 2021 by commit af1830956dc3 ("scsi: core: Add mq_poll support to SCSI layer"). Link: https://lore.kernel.org/r/20210917212751.2676054-1-bvanassche@acm.org Cc: Kashyap Desai Reviewed-by: Himanshu Madhani Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- include/scsi/scsi_cmnd.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index eaf04c9a1dfc..a2315aac93c7 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -10,7 +10,6 @@ #include #include #include -#include #include struct Scsi_Host; -- cgit From 8d4efd0040e52bad2907a6a7b1cd686bee31fbcd Mon Sep 17 00:00:00 2001 From: Dmitry Bogdanov Date: Tue, 14 Sep 2021 13:55:37 +0300 Subject: scsi: efct: Add state in nport sm trace printout Similar to other state machine traces and to make debug easier, add the state name to nport sm trace printout. Link: https://lore.kernel.org/r/20210914105539.6942-2-d.bogdanov@yadro.com Reviewed-by: Ram Vegesna Signed-off-by: Dmitry Bogdanov Signed-off-by: Martin K. Petersen --- drivers/scsi/elx/libefc/efc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/elx/libefc/efc.h b/drivers/scsi/elx/libefc/efc.h index 927016283f41..468ff3cc9c00 100644 --- a/drivers/scsi/elx/libefc/efc.h +++ b/drivers/scsi/elx/libefc/efc.h @@ -47,6 +47,6 @@ enum efc_scsi_del_target_reason { #define nport_sm_trace(nport) \ efc_log_debug(nport->efc, \ - "[%s] %-20s\n", nport->display_name, efc_sm_event_name(evt)) \ + "[%s] %-20s %-20s\n", nport->display_name, __func__, efc_sm_event_name(evt)) \ #endif /* __EFC_H__ */ -- cgit From ee3dce9f38426776b48406441d0dc39c74940818 Mon Sep 17 00:00:00 2001 From: Dmitry Bogdanov Date: Tue, 14 Sep 2021 13:55:38 +0300 Subject: scsi: efct: Fix nport free nport_free for an empty nport hangs the state machine waiting for mbox completion if nport is not yet attached thinking that it is attaching right now. Add a check for nport attaching state and complete nport free. Link: https://lore.kernel.org/r/20210914105539.6942-3-d.bogdanov@yadro.com Reviewed-by: Ram Vegesna Signed-off-by: Dmitry Bogdanov Signed-off-by: Martin K. Petersen --- drivers/scsi/elx/libefc/efc_cmds.c | 7 ++++++- drivers/scsi/elx/libefc/efclib.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/elx/libefc/efc_cmds.c b/drivers/scsi/elx/libefc/efc_cmds.c index 37e6697d86b8..f8665d48904a 100644 --- a/drivers/scsi/elx/libefc/efc_cmds.c +++ b/drivers/scsi/elx/libefc/efc_cmds.c @@ -249,6 +249,7 @@ efc_nport_attach_reg_vpi_cb(struct efc *efc, int status, u8 *mqe, { struct efc_nport *nport = arg; + nport->attaching = false; if (efc_nport_get_mbox_status(nport, mqe, status)) { efc_nport_free_resources(nport, EFC_EVT_NPORT_ATTACH_FAIL, mqe); return -EIO; @@ -286,6 +287,8 @@ efc_cmd_nport_attach(struct efc *efc, struct efc_nport *nport, u32 fc_id) if (rc) { efc_log_err(efc, "REG_VPI command failure\n"); efc_nport_free_resources(nport, EFC_EVT_NPORT_ATTACH_FAIL, buf); + } else { + nport->attaching = true; } return rc; @@ -302,8 +305,10 @@ efc_cmd_nport_free(struct efc *efc, struct efc_nport *nport) /* Issue the UNREG_VPI command to free the assigned VPI context */ if (nport->attached) efc_nport_free_unreg_vpi(nport); - else + else if (nport->attaching) nport->free_req_pending = true; + else + efc_sm_post_event(&nport->sm, EFC_EVT_NPORT_FREE_OK, NULL); return 0; } diff --git a/drivers/scsi/elx/libefc/efclib.h b/drivers/scsi/elx/libefc/efclib.h index ee291cabf7e0..dde20891c2dd 100644 --- a/drivers/scsi/elx/libefc/efclib.h +++ b/drivers/scsi/elx/libefc/efclib.h @@ -142,6 +142,7 @@ struct efc_nport { bool is_vport; bool free_req_pending; bool attached; + bool attaching; bool p2p_winner; struct efc_domain *domain; u64 wwpn; -- cgit From e76b7c5e25a1fa818bb3e727873a899cc89f5196 Mon Sep 17 00:00:00 2001 From: Dmitry Bogdanov Date: Tue, 14 Sep 2021 13:55:39 +0300 Subject: scsi: efct: Decrease area under spinlock Under the session level spinlock node->active_ios_lock in efct_scsi_io_alloc() we are taking another spinlock for the port. This leads to contention between sessions and even between I/Os in the same session. Reduce the locked region to active_ios list for which active_ios_lock is intended. Spinlock CPU usage decreases from 18% down to 13%. IOPS are increased from 220 kIOPS to 264 kIOPS for one LUN. Link: https://lore.kernel.org/r/20210914105539.6942-4-d.bogdanov@yadro.com Reviewed-by: Roman Bolshakov Reviewed-by: Ram Vegesna Signed-off-by: Dmitry Bogdanov Signed-off-by: Martin K. Petersen --- drivers/scsi/elx/efct/efct_scsi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/elx/efct/efct_scsi.c b/drivers/scsi/elx/efct/efct_scsi.c index 40fb3a724c76..8535bb7eabd8 100644 --- a/drivers/scsi/elx/efct/efct_scsi.c +++ b/drivers/scsi/elx/efct/efct_scsi.c @@ -38,8 +38,6 @@ efct_scsi_io_alloc(struct efct_node *node) xport = efct->xport; - spin_lock_irqsave(&node->active_ios_lock, flags); - io = efct_io_pool_io_alloc(efct->xport->io_pool); if (!io) { efc_log_err(efct, "IO alloc Failed\n"); @@ -66,6 +64,7 @@ efct_scsi_io_alloc(struct efct_node *node) /* Add to node's active_ios list */ INIT_LIST_HEAD(&io->list_entry); + spin_lock_irqsave(&node->active_ios_lock, flags); list_add(&io->list_entry, &node->active_ios); spin_unlock_irqrestore(&node->active_ios_lock, flags); -- cgit From e88e2d32200a1734cb4a2ca292c5c7b338257bb6 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Wed, 15 Sep 2021 09:04:06 +0300 Subject: scsi: ufs: core: Probe for temperature notification support Probe the dExtendedUFSFeaturesSupport register for the device's temperature notification support and, if supported, add a hardware monitor device. Link: https://lore.kernel.org/r/20210915060407.40-2-avri.altman@wdc.com Reviewed-by: Guenter Roeck Reviewed-by: Bean Huo Reviewed-by: Daejun Park Signed-off-by: Avri Altman Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/Kconfig | 9 ++ drivers/scsi/ufs/Makefile | 1 + drivers/scsi/ufs/ufs-hwmon.c | 198 +++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/ufs/ufs.h | 7 ++ drivers/scsi/ufs/ufshcd.c | 26 ++++++ drivers/scsi/ufs/ufshcd.h | 18 ++++ 6 files changed, 259 insertions(+) create mode 100644 drivers/scsi/ufs/ufs-hwmon.c diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index 432df76e6318..565e8aa6319d 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -199,3 +199,12 @@ config SCSI_UFS_FAULT_INJECTION help Enable fault injection support in the UFS driver. This makes it easier to test the UFS error handler and abort handler. + +config SCSI_UFS_HWMON + bool "UFS Temperature Notification" + depends on SCSI_UFSHCD && HWMON + help + This provides support for UFS hardware monitoring. If enabled, + a hardware monitoring device will be created for the UFS device. + + If unsure, say N. diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile index c407da9b5171..966048875b50 100644 --- a/drivers/scsi/ufs/Makefile +++ b/drivers/scsi/ufs/Makefile @@ -10,6 +10,7 @@ ufshcd-core-$(CONFIG_SCSI_UFS_BSG) += ufs_bsg.o ufshcd-core-$(CONFIG_SCSI_UFS_CRYPTO) += ufshcd-crypto.o ufshcd-core-$(CONFIG_SCSI_UFS_HPB) += ufshpb.o ufshcd-core-$(CONFIG_SCSI_UFS_FAULT_INJECTION) += ufs-fault-injection.o +ufshcd-core-$(CONFIG_SCSI_UFS_HWMON) += ufs-hwmon.o obj-$(CONFIG_SCSI_UFS_DWC_TC_PCI) += tc-dwc-g210-pci.o ufshcd-dwc.o tc-dwc-g210.o obj-$(CONFIG_SCSI_UFS_DWC_TC_PLATFORM) += tc-dwc-g210-pltfrm.o ufshcd-dwc.o tc-dwc-g210.o diff --git a/drivers/scsi/ufs/ufs-hwmon.c b/drivers/scsi/ufs/ufs-hwmon.c new file mode 100644 index 000000000000..33b66736aaa4 --- /dev/null +++ b/drivers/scsi/ufs/ufs-hwmon.c @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * UFS hardware monitoring support + * Copyright (c) 2021, Western Digital Corporation + */ + +#include +#include + +#include "ufshcd.h" + +struct ufs_hwmon_data { + struct ufs_hba *hba; + u8 mask; +}; + +static int ufs_read_temp_enable(struct ufs_hba *hba, u8 mask, long *val) +{ + u32 ee_mask; + int err; + + err = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR, QUERY_ATTR_IDN_EE_CONTROL, 0, 0, + &ee_mask); + if (err) + return err; + + *val = (mask & ee_mask & MASK_EE_TOO_HIGH_TEMP) || (mask & ee_mask & MASK_EE_TOO_LOW_TEMP); + + return 0; +} + +static int ufs_get_temp(struct ufs_hba *hba, enum attr_idn idn, long *val) +{ + u32 value; + int err; + + err = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR, idn, 0, 0, &value); + if (err) + return err; + + if (value == 0) + return -ENODATA; + + *val = ((long)value - 80) * MILLIDEGREE_PER_DEGREE; + + return 0; +} + +static int ufs_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, + long *val) +{ + struct ufs_hwmon_data *data = dev_get_drvdata(dev); + struct ufs_hba *hba = data->hba; + int err; + + down(&hba->host_sem); + + if (!ufshcd_is_user_access_allowed(hba)) { + up(&hba->host_sem); + return -EBUSY; + } + + ufshcd_rpm_get_sync(hba); + + switch (attr) { + case hwmon_temp_enable: + err = ufs_read_temp_enable(hba, data->mask, val); + + break; + case hwmon_temp_crit: + err = ufs_get_temp(hba, QUERY_ATTR_IDN_HIGH_TEMP_BOUND, val); + + break; + case hwmon_temp_lcrit: + err = ufs_get_temp(hba, QUERY_ATTR_IDN_LOW_TEMP_BOUND, val); + + break; + case hwmon_temp_input: + err = ufs_get_temp(hba, QUERY_ATTR_IDN_CASE_ROUGH_TEMP, val); + + break; + default: + err = -EOPNOTSUPP; + + break; + } + + ufshcd_rpm_put_sync(hba); + + up(&hba->host_sem); + + return err; +} + +static int ufs_hwmon_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, + long val) +{ + struct ufs_hwmon_data *data = dev_get_drvdata(dev); + struct ufs_hba *hba = data->hba; + int err; + + if (attr != hwmon_temp_enable) + return -EINVAL; + + if (val != 0 && val != 1) + return -EINVAL; + + down(&hba->host_sem); + + if (!ufshcd_is_user_access_allowed(hba)) { + up(&hba->host_sem); + return -EBUSY; + } + + ufshcd_rpm_get_sync(hba); + + if (val == 1) + err = ufshcd_update_ee_usr_mask(hba, MASK_EE_URGENT_TEMP, 0); + else + err = ufshcd_update_ee_usr_mask(hba, 0, MASK_EE_URGENT_TEMP); + + ufshcd_rpm_put_sync(hba); + + up(&hba->host_sem); + + return err; +} + +static umode_t ufs_hwmon_is_visible(const void *_data, enum hwmon_sensor_types type, u32 attr, + int channel) +{ + if (type != hwmon_temp) + return 0; + + switch (attr) { + case hwmon_temp_enable: + return 0644; + case hwmon_temp_crit: + case hwmon_temp_lcrit: + case hwmon_temp_input: + return 0444; + default: + break; + } + return 0; +} + +static const struct hwmon_channel_info *ufs_hwmon_info[] = { + HWMON_CHANNEL_INFO(temp, HWMON_T_ENABLE | HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_LCRIT), + NULL +}; + +static const struct hwmon_ops ufs_hwmon_ops = { + .is_visible = ufs_hwmon_is_visible, + .read = ufs_hwmon_read, + .write = ufs_hwmon_write, +}; + +static const struct hwmon_chip_info ufs_hwmon_hba_info = { + .ops = &ufs_hwmon_ops, + .info = ufs_hwmon_info, +}; + +void ufs_hwmon_probe(struct ufs_hba *hba, u8 mask) +{ + struct device *dev = hba->dev; + struct ufs_hwmon_data *data; + struct device *hwmon; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return; + + data->hba = hba; + data->mask = mask; + + hwmon = hwmon_device_register_with_info(dev, "ufs", data, &ufs_hwmon_hba_info, NULL); + if (IS_ERR(hwmon)) { + dev_warn(dev, "Failed to instantiate hwmon device\n"); + kfree(data); + return; + } + + hba->hwmon_device = hwmon; +} + +void ufs_hwmon_remove(struct ufs_hba *hba) +{ + struct ufs_hwmon_data *data; + + if (!hba->hwmon_device) + return; + + data = dev_get_drvdata(hba->hwmon_device); + hwmon_device_unregister(hba->hwmon_device); + hba->hwmon_device = NULL; + kfree(data); +} diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index 8c6b38b1b142..0bfdca3e648e 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -152,6 +152,9 @@ enum attr_idn { QUERY_ATTR_IDN_PSA_STATE = 0x15, QUERY_ATTR_IDN_PSA_DATA_SIZE = 0x16, QUERY_ATTR_IDN_REF_CLK_GATING_WAIT_TIME = 0x17, + QUERY_ATTR_IDN_CASE_ROUGH_TEMP = 0x18, + QUERY_ATTR_IDN_HIGH_TEMP_BOUND = 0x19, + QUERY_ATTR_IDN_LOW_TEMP_BOUND = 0x1A, QUERY_ATTR_IDN_WB_FLUSH_STATUS = 0x1C, QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE = 0x1D, QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST = 0x1E, @@ -338,6 +341,9 @@ enum { /* Possible values for dExtendedUFSFeaturesSupport */ enum { + UFS_DEV_LOW_TEMP_NOTIF = BIT(4), + UFS_DEV_HIGH_TEMP_NOTIF = BIT(5), + UFS_DEV_EXT_TEMP_NOTIF = BIT(6), UFS_DEV_HPB_SUPPORT = BIT(7), UFS_DEV_WRITE_BOOSTER_SUP = BIT(8), }; @@ -370,6 +376,7 @@ enum { MASK_EE_WRITEBOOSTER_EVENT = BIT(5), MASK_EE_PERFORMANCE_THROTTLING = BIT(6), }; +#define MASK_EE_URGENT_TEMP (MASK_EE_TOO_HIGH_TEMP | MASK_EE_TOO_LOW_TEMP) /* Background operation status */ enum bkops_status { diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 3841ab49f556..ce22340024ce 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -7469,6 +7469,29 @@ wb_disabled: hba->caps &= ~UFSHCD_CAP_WB_EN; } +static void ufshcd_temp_notif_probe(struct ufs_hba *hba, u8 *desc_buf) +{ + struct ufs_dev_info *dev_info = &hba->dev_info; + u32 ext_ufs_feature; + u8 mask = 0; + + if (!(hba->caps & UFSHCD_CAP_TEMP_NOTIF) || dev_info->wspecversion < 0x300) + return; + + ext_ufs_feature = get_unaligned_be32(desc_buf + DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP); + + if (ext_ufs_feature & UFS_DEV_LOW_TEMP_NOTIF) + mask |= MASK_EE_TOO_LOW_TEMP; + + if (ext_ufs_feature & UFS_DEV_HIGH_TEMP_NOTIF) + mask |= MASK_EE_TOO_HIGH_TEMP; + + if (mask) { + ufshcd_enable_ee(hba, mask); + ufs_hwmon_probe(hba, mask); + } +} + void ufshcd_fixup_dev_quirks(struct ufs_hba *hba, struct ufs_dev_fix *fixups) { struct ufs_dev_fix *f; @@ -7564,6 +7587,8 @@ static int ufs_get_device_desc(struct ufs_hba *hba) ufshcd_wb_probe(hba, desc_buf); + ufshcd_temp_notif_probe(hba, desc_buf); + /* * ufshcd_read_string_desc returns size of the string * reset the error value @@ -9408,6 +9433,7 @@ void ufshcd_remove(struct ufs_hba *hba) { if (hba->sdev_ufs_device) ufshcd_rpm_get_sync(hba); + ufs_hwmon_remove(hba); ufs_bsg_remove(hba); ufshpb_remove(hba); ufs_sysfs_remove_nodes(hba->dev); diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 52ea6f350b18..021c858955af 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -653,6 +653,12 @@ enum ufshcd_caps { * in order to exit DeepSleep state. */ UFSHCD_CAP_DEEPSLEEP = 1 << 10, + + /* + * This capability allows the host controller driver to use temperature + * notification if it is supported by the UFS device. + */ + UFSHCD_CAP_TEMP_NOTIF = 1 << 11, }; struct ufs_hba_variant_params { @@ -789,6 +795,10 @@ struct ufs_hba { struct scsi_device *sdev_ufs_device; struct scsi_device *sdev_rpmb; +#ifdef CONFIG_SCSI_UFS_HWMON + struct device *hwmon_device; +#endif + enum ufs_dev_pwr_mode curr_dev_pwr_mode; enum uic_link_state uic_link_state; /* Desired UFS power management level during runtime PM */ @@ -1049,6 +1059,14 @@ static inline u8 ufshcd_wb_get_query_index(struct ufs_hba *hba) return 0; } +#ifdef CONFIG_SCSI_UFS_HWMON +void ufs_hwmon_probe(struct ufs_hba *hba, u8 mask); +void ufs_hwmon_remove(struct ufs_hba *hba); +#else +static inline void ufs_hwmon_probe(struct ufs_hba *hba, u8 mask) {} +static inline void ufs_hwmon_remove(struct ufs_hba *hba) {} +#endif + #ifdef CONFIG_PM extern int ufshcd_runtime_suspend(struct device *dev); extern int ufshcd_runtime_resume(struct device *dev); -- cgit From 322c4b29ee1f19ce153f027bfb21d272b029f2d7 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Wed, 15 Sep 2021 09:04:07 +0300 Subject: scsi: ufs: core: Add temperature notification exception handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The device may notify the host of an extreme temperature by using the exception event mechanism. The exception can be raised when the device’s Tcase temperature is either too high or too low. It is essentially up to the platform to decide what further actions need to be taken. leave a placeholder for a designated vop for that. Link: https://lore.kernel.org/r/20210915060407.40-3-avri.altman@wdc.com Reviewed-by: Guenter Roeck Reviewed-by: Bean Huo Reviewed-by: Daejun Park Signed-off-by: Avri Altman Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs-hwmon.c | 12 ++++++++++++ drivers/scsi/ufs/ufshcd.c | 21 +++++++++++++++++++++ drivers/scsi/ufs/ufshcd.h | 2 ++ 3 files changed, 35 insertions(+) diff --git a/drivers/scsi/ufs/ufs-hwmon.c b/drivers/scsi/ufs/ufs-hwmon.c index 33b66736aaa4..74855491dc8f 100644 --- a/drivers/scsi/ufs/ufs-hwmon.c +++ b/drivers/scsi/ufs/ufs-hwmon.c @@ -196,3 +196,15 @@ void ufs_hwmon_remove(struct ufs_hba *hba) hba->hwmon_device = NULL; kfree(data); } + +void ufs_hwmon_notify_event(struct ufs_hba *hba, u8 ee_mask) +{ + if (!hba->hwmon_device) + return; + + if (ee_mask & MASK_EE_TOO_HIGH_TEMP) + hwmon_notify_event(hba->hwmon_device, hwmon_temp, hwmon_temp_max_alarm, 0); + + if (ee_mask & MASK_EE_TOO_LOW_TEMP) + hwmon_notify_event(hba->hwmon_device, hwmon_temp, hwmon_temp_min_alarm, 0); +} diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index ce22340024ce..debef631c89a 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -5642,6 +5642,24 @@ out: __func__, err); } +static void ufshcd_temp_exception_event_handler(struct ufs_hba *hba, u16 status) +{ + u32 value; + + if (ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR, + QUERY_ATTR_IDN_CASE_ROUGH_TEMP, 0, 0, &value)) + return; + + dev_info(hba->dev, "exception Tcase %d\n", value - 80); + + ufs_hwmon_notify_event(hba, status & MASK_EE_URGENT_TEMP); + + /* + * A placeholder for the platform vendors to add whatever additional + * steps required + */ +} + static int __ufshcd_wb_toggle(struct ufs_hba *hba, bool set, enum flag_idn idn) { u8 index; @@ -5821,6 +5839,9 @@ static void ufshcd_exception_event_handler(struct work_struct *work) if (status & hba->ee_drv_mask & MASK_EE_URGENT_BKOPS) ufshcd_bkops_exception_event_handler(hba); + if (status & hba->ee_drv_mask & MASK_EE_URGENT_TEMP) + ufshcd_temp_exception_event_handler(hba, status); + ufs_debugfs_exception_event(hba, status); out: ufshcd_scsi_unblock_requests(hba); diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 021c858955af..92d05329de68 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -1062,9 +1062,11 @@ static inline u8 ufshcd_wb_get_query_index(struct ufs_hba *hba) #ifdef CONFIG_SCSI_UFS_HWMON void ufs_hwmon_probe(struct ufs_hba *hba, u8 mask); void ufs_hwmon_remove(struct ufs_hba *hba); +void ufs_hwmon_notify_event(struct ufs_hba *hba, u8 ee_mask); #else static inline void ufs_hwmon_probe(struct ufs_hba *hba, u8 mask) {} static inline void ufs_hwmon_remove(struct ufs_hba *hba) {} +static inline void ufs_hwmon_notify_event(struct ufs_hba *hba, u8 ee_mask) {} #endif #ifdef CONFIG_PM -- cgit From cbd9a3347c757383f3d2b50cf7cfd03eb479c481 Mon Sep 17 00:00:00 2001 From: Tong Zhang Date: Mon, 6 Sep 2021 21:07:02 -0700 Subject: scsi: dc395: Fix error case unwinding dc395x_init_one()->adapter_init() might fail. In this case, the acb is already cleaned up by adapter_init(), no need to do that in adapter_uninit(acb) again. [ 1.252251] dc395x: adapter init failed [ 1.254900] RIP: 0010:adapter_uninit+0x94/0x170 [dc395x] [ 1.260307] Call Trace: [ 1.260442] dc395x_init_one.cold+0x72a/0x9bb [dc395x] Link: https://lore.kernel.org/r/20210907040702.1846409-1-ztong0001@gmail.com Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reviewed-by: Finn Thain Signed-off-by: Tong Zhang Signed-off-by: Martin K. Petersen --- drivers/scsi/dc395x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index 24c7cefb0b78..1c79e6c27163 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -4618,6 +4618,7 @@ static int dc395x_init_one(struct pci_dev *dev, const struct pci_device_id *id) /* initialise the adapter and everything we need */ if (adapter_init(acb, io_port_base, io_port_len, irq)) { dprintkl(KERN_INFO, "adapter init failed\n"); + acb = NULL; goto fail; } -- cgit From efe1dc571a5b808baa26682eef16561be2e356fd Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 21 Sep 2021 07:30:08 -0700 Subject: scsi: lpfc: Fix mailbox command failure during driver initialization Contention for the mailbox interface may occur during driver initialization (immediately after a function reset), between mailbox commands initiated via ioctl (bsg) and those driver requested by the driver. After setting SLI_ACTIVE flag for a port, there is a window in which the driver will allow an ioctl to be initiated while the adapter is initializing and issuing mailbox commands via polling. The polling logic then gets confused. Correct by having thread setting SLI_ACTIVE spot an active mailbox command and allow it complete before proceeding. Link: https://lore.kernel.org/r/20210921143008.64212-1-jsmart2021@gmail.com Co-developed-by: Nigel Kirkland Signed-off-by: Nigel Kirkland Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 34cf2bfcce07..3f911cb48cf2 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -8158,6 +8158,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) struct lpfc_vport *vport = phba->pport; struct lpfc_dmabuf *mp; struct lpfc_rqb *rqbp; + u32 flg; /* Perform a PCI function reset to start from clean */ rc = lpfc_pci_function_reset(phba); @@ -8171,7 +8172,17 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) else { spin_lock_irq(&phba->hbalock); phba->sli.sli_flag |= LPFC_SLI_ACTIVE; + flg = phba->sli.sli_flag; spin_unlock_irq(&phba->hbalock); + /* Allow a little time after setting SLI_ACTIVE for any polled + * MBX commands to complete via BSG. + */ + for (i = 0; i < 50 && (flg & LPFC_SLI_MBOX_ACTIVE); i++) { + msleep(20); + spin_lock_irq(&phba->hbalock); + flg = phba->sli.sli_flag; + spin_unlock_irq(&phba->hbalock); + } } lpfc_sli4_dip(phba); @@ -9755,7 +9766,7 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, "(%d):2541 Mailbox command x%x " "(x%x/x%x) failure: " "mqe_sta: x%x mcqe_sta: x%x/x%x " - "Data: x%x x%x\n,", + "Data: x%x x%x\n", mboxq->vport ? mboxq->vport->vpi : 0, mboxq->u.mb.mbxCommand, lpfc_sli_config_mbox_subsys_get(phba, @@ -9789,7 +9800,7 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, "(%d):2597 Sync Mailbox command " "x%x (x%x/x%x) failure: " "mqe_sta: x%x mcqe_sta: x%x/x%x " - "Data: x%x x%x\n,", + "Data: x%x x%x\n", mboxq->vport ? mboxq->vport->vpi : 0, mboxq->u.mb.mbxCommand, lpfc_sli_config_mbox_subsys_get(phba, -- cgit From 33a5471f8da976bf271a1ebbd6b9d163cb0cb6aa Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 21 Sep 2021 19:35:06 +0200 Subject: video: backlight: Drop maximum brightness override for brightness zero MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The note in c2adda27d202f ("video: backlight: Add of_find_backlight helper in backlight.c") says that gpio-backlight uses brightness as power state. This has been fixed since in ec665b756e6f7 ("backlight: gpio-backlight: Correct initial power state handling") and other backlight drivers do not require this workaround. Drop the workaround. This fixes the case where e.g. pwm-backlight can perfectly well be set to brightness 0 on boot in DT, which without this patch leads to the display brightness to be max instead of off. Fixes: c2adda27d202f ("video: backlight: Add of_find_backlight helper in backlight.c") Cc: # 5.4+ Cc: # 4.19.x: ec665b756e6f7: backlight: gpio-backlight: Correct initial power state handling Signed-off-by: Marek Vasut Acked-by: Noralf Trønnes Reviewed-by: Daniel Thompson Signed-off-by: Lee Jones --- drivers/video/backlight/backlight.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index 537fe1b376ad..fc990e576340 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -688,12 +688,6 @@ static struct backlight_device *of_find_backlight(struct device *dev) of_node_put(np); if (!bd) return ERR_PTR(-EPROBE_DEFER); - /* - * Note: gpio_backlight uses brightness as - * power state during probe - */ - if (!bd->props.brightness) - bd->props.brightness = bd->props.max_brightness; } } -- cgit From e1db0f55976f796d1e75aa48c06658488d407709 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Thu, 16 Sep 2021 20:19:36 +0900 Subject: gpio: uniphier: Use helper function to get IRQ hardware number Use helper function to get IRQ hardware number instead of direct access. No functional changes intended. Signed-off-by: Kunihiko Hayashi Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-uniphier.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio-uniphier.c b/drivers/gpio/gpio-uniphier.c index f99f3c10bed0..954f2b537a75 100644 --- a/drivers/gpio/gpio-uniphier.c +++ b/drivers/gpio/gpio-uniphier.c @@ -180,7 +180,7 @@ static int uniphier_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) static void uniphier_gpio_irq_mask(struct irq_data *data) { struct uniphier_gpio_priv *priv = data->chip_data; - u32 mask = BIT(data->hwirq); + u32 mask = BIT(irqd_to_hwirq(data)); uniphier_gpio_reg_update(priv, UNIPHIER_GPIO_IRQ_EN, mask, 0); @@ -190,7 +190,7 @@ static void uniphier_gpio_irq_mask(struct irq_data *data) static void uniphier_gpio_irq_unmask(struct irq_data *data) { struct uniphier_gpio_priv *priv = data->chip_data; - u32 mask = BIT(data->hwirq); + u32 mask = BIT(irqd_to_hwirq(data)); uniphier_gpio_reg_update(priv, UNIPHIER_GPIO_IRQ_EN, mask, mask); @@ -200,7 +200,7 @@ static void uniphier_gpio_irq_unmask(struct irq_data *data) static int uniphier_gpio_irq_set_type(struct irq_data *data, unsigned int type) { struct uniphier_gpio_priv *priv = data->chip_data; - u32 mask = BIT(data->hwirq); + u32 mask = BIT(irqd_to_hwirq(data)); u32 val = 0; if (type == IRQ_TYPE_EDGE_BOTH) { @@ -297,7 +297,8 @@ static int uniphier_gpio_irq_domain_activate(struct irq_domain *domain, struct uniphier_gpio_priv *priv = domain->host_data; struct gpio_chip *chip = &priv->chip; - return gpiochip_lock_as_irq(chip, data->hwirq + UNIPHIER_GPIO_IRQ_OFFSET); + return gpiochip_lock_as_irq(chip, + irqd_to_hwirq(data) + UNIPHIER_GPIO_IRQ_OFFSET); } static void uniphier_gpio_irq_domain_deactivate(struct irq_domain *domain, @@ -306,7 +307,8 @@ static void uniphier_gpio_irq_domain_deactivate(struct irq_domain *domain, struct uniphier_gpio_priv *priv = domain->host_data; struct gpio_chip *chip = &priv->chip; - gpiochip_unlock_as_irq(chip, data->hwirq + UNIPHIER_GPIO_IRQ_OFFSET); + gpiochip_unlock_as_irq(chip, + irqd_to_hwirq(data) + UNIPHIER_GPIO_IRQ_OFFSET); } static const struct irq_domain_ops uniphier_gpio_irq_domain_ops = { -- cgit From dcfd2a2975f3eaa29c5a96d150a9364f51a5302c Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Thu, 16 Sep 2021 20:19:37 +0900 Subject: gpio: uniphier: Use helper functions to get private data from IRQ data Use helper functions to get private data from IRQ data instead of direct access. No functional changes intended. Signed-off-by: Kunihiko Hayashi Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-uniphier.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-uniphier.c b/drivers/gpio/gpio-uniphier.c index 954f2b537a75..9c677a0e7025 100644 --- a/drivers/gpio/gpio-uniphier.c +++ b/drivers/gpio/gpio-uniphier.c @@ -179,7 +179,7 @@ static int uniphier_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) static void uniphier_gpio_irq_mask(struct irq_data *data) { - struct uniphier_gpio_priv *priv = data->chip_data; + struct uniphier_gpio_priv *priv = irq_data_get_irq_chip_data(data); u32 mask = BIT(irqd_to_hwirq(data)); uniphier_gpio_reg_update(priv, UNIPHIER_GPIO_IRQ_EN, mask, 0); @@ -189,7 +189,7 @@ static void uniphier_gpio_irq_mask(struct irq_data *data) static void uniphier_gpio_irq_unmask(struct irq_data *data) { - struct uniphier_gpio_priv *priv = data->chip_data; + struct uniphier_gpio_priv *priv = irq_data_get_irq_chip_data(data); u32 mask = BIT(irqd_to_hwirq(data)); uniphier_gpio_reg_update(priv, UNIPHIER_GPIO_IRQ_EN, mask, mask); @@ -199,7 +199,7 @@ static void uniphier_gpio_irq_unmask(struct irq_data *data) static int uniphier_gpio_irq_set_type(struct irq_data *data, unsigned int type) { - struct uniphier_gpio_priv *priv = data->chip_data; + struct uniphier_gpio_priv *priv = irq_data_get_irq_chip_data(data); u32 mask = BIT(irqd_to_hwirq(data)); u32 val = 0; -- cgit From ca038748068f454d20ad1bb120cbe36599f81db6 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 17 Sep 2021 12:54:11 +0200 Subject: gpio: tegra186: Force one interrupt per bank Newer chips support up to 8 interrupts per bank, which can be useful to balance the load and decrease latency. However, it also required a very complicated interrupt routing to be set up. To keep things simple for now, ensure that a single interrupt per bank is enforced, even if all possible interrupts are described in device tree. Signed-off-by: Thierry Reding Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-tegra186.c | 68 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index c99858f40a27..1bc4152e0275 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -81,6 +81,8 @@ struct tegra_gpio { unsigned int *irq; const struct tegra_gpio_soc *soc; + unsigned int num_irqs_per_bank; + unsigned int num_banks; void __iomem *secure; void __iomem *base; @@ -594,6 +596,28 @@ static void tegra186_gpio_init_route_mapping(struct tegra_gpio *gpio) } } +static unsigned int tegra186_gpio_irqs_per_bank(struct tegra_gpio *gpio) +{ + struct device *dev = gpio->gpio.parent; + + if (gpio->num_irq > gpio->num_banks) { + if (gpio->num_irq % gpio->num_banks != 0) + goto error; + } + + if (gpio->num_irq < gpio->num_banks) + goto error; + + gpio->num_irqs_per_bank = gpio->num_irq / gpio->num_banks; + + return 0; + +error: + dev_err(dev, "invalid number of interrupts (%u) for %u banks\n", + gpio->num_irq, gpio->num_banks); + return -EINVAL; +} + static int tegra186_gpio_probe(struct platform_device *pdev) { unsigned int i, j, offset; @@ -608,7 +632,17 @@ static int tegra186_gpio_probe(struct platform_device *pdev) return -ENOMEM; gpio->soc = device_get_match_data(&pdev->dev); + gpio->gpio.label = gpio->soc->name; + gpio->gpio.parent = &pdev->dev; + + /* count the number of banks in the controller */ + for (i = 0; i < gpio->soc->num_ports; i++) + if (gpio->soc->ports[i].bank > gpio->num_banks) + gpio->num_banks = gpio->soc->ports[i].bank; + + gpio->num_banks++; + /* get register apertures */ gpio->secure = devm_platform_ioremap_resource_byname(pdev, "security"); if (IS_ERR(gpio->secure)) { gpio->secure = devm_platform_ioremap_resource(pdev, 0); @@ -629,6 +663,10 @@ static int tegra186_gpio_probe(struct platform_device *pdev) gpio->num_irq = err; + err = tegra186_gpio_irqs_per_bank(gpio); + if (err < 0) + return err; + gpio->irq = devm_kcalloc(&pdev->dev, gpio->num_irq, sizeof(*gpio->irq), GFP_KERNEL); if (!gpio->irq) @@ -642,9 +680,6 @@ static int tegra186_gpio_probe(struct platform_device *pdev) gpio->irq[i] = err; } - gpio->gpio.label = gpio->soc->name; - gpio->gpio.parent = &pdev->dev; - gpio->gpio.request = gpiochip_generic_request; gpio->gpio.free = gpiochip_generic_free; gpio->gpio.get_direction = tegra186_gpio_get_direction; @@ -708,7 +743,30 @@ static int tegra186_gpio_probe(struct platform_device *pdev) irq->parent_handler = tegra186_gpio_irq; irq->parent_handler_data = gpio; irq->num_parents = gpio->num_irq; - irq->parents = gpio->irq; + + /* + * To simplify things, use a single interrupt per bank for now. Some + * chips support up to 8 interrupts per bank, which can be useful to + * distribute the load and decrease the processing latency for GPIOs + * but it also requires a more complicated interrupt routing than we + * currently program. + */ + if (gpio->num_irqs_per_bank > 1) { + irq->parents = devm_kcalloc(&pdev->dev, gpio->num_banks, + sizeof(*irq->parents), GFP_KERNEL); + if (!irq->parents) + return -ENOMEM; + + for (i = 0; i < gpio->num_banks; i++) + irq->parents[i] = gpio->irq[i * gpio->num_irqs_per_bank]; + + irq->num_parents = gpio->num_banks; + } else { + irq->num_parents = gpio->num_irq; + irq->parents = gpio->irq; + } + + tegra186_gpio_init_route_mapping(gpio); np = of_find_matching_node(NULL, tegra186_pmc_of_match); if (np) { @@ -719,8 +777,6 @@ static int tegra186_gpio_probe(struct platform_device *pdev) return -EPROBE_DEFER; } - tegra186_gpio_init_route_mapping(gpio); - irq->map = devm_kcalloc(&pdev->dev, gpio->gpio.ngpio, sizeof(*irq->map), GFP_KERNEL); if (!irq->map) -- cgit From 2103868047456e5f3e431ebb253d87e1fb806c76 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 17 Sep 2021 12:54:12 +0200 Subject: gpio: tegra186: Support multiple interrupts per bank Tegra194 and later support more than a single interrupt per bank. This is primarily useful for virtualization but can also be helpful for more fine-grained CPU affinity control. To keep things simple for now, route all pins to the first interrupt. For backwards-compatibility, support old device trees that specify only one interrupt per bank by counting the interrupts at probe time. Signed-off-by: Thierry Reding Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-tegra186.c | 48 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index 1bc4152e0275..c026e7141e4e 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -69,6 +69,8 @@ struct tegra_gpio_soc { const char *name; unsigned int instance; + unsigned int num_irqs_per_bank; + const struct tegra186_pin_range *pin_ranges; unsigned int num_pin_ranges; const char *pinmux; @@ -452,7 +454,7 @@ static void tegra186_gpio_irq(struct irq_desc *desc) struct irq_domain *domain = gpio->gpio.irq.domain; struct irq_chip *chip = irq_desc_get_chip(desc); unsigned int parent = irq_desc_get_irq(desc); - unsigned int i, offset = 0; + unsigned int i, j, offset = 0; chained_irq_enter(chip, desc); @@ -465,7 +467,12 @@ static void tegra186_gpio_irq(struct irq_desc *desc) base = gpio->base + port->bank * 0x1000 + port->port * 0x200; /* skip ports that are not associated with this bank */ - if (parent != gpio->irq[port->bank]) + for (j = 0; j < gpio->num_irqs_per_bank; j++) { + if (parent == gpio->irq[port->bank * gpio->num_irqs_per_bank + j]) + break; + } + + if (j == gpio->num_irqs_per_bank) goto skip; value = readl(base + TEGRA186_GPIO_INTERRUPT_STATUS(1)); @@ -567,6 +574,7 @@ static const struct of_device_id tegra186_pmc_of_match[] = { static void tegra186_gpio_init_route_mapping(struct tegra_gpio *gpio) { + struct device *dev = gpio->gpio.parent; unsigned int i, j; u32 value; @@ -585,12 +593,30 @@ static void tegra186_gpio_init_route_mapping(struct tegra_gpio *gpio) */ if ((value & TEGRA186_GPIO_CTL_SCR_SEC_REN) == 0 && (value & TEGRA186_GPIO_CTL_SCR_SEC_WEN) == 0) { - for (j = 0; j < 8; j++) { + /* + * On Tegra194 and later, each pin can be routed to one or more + * interrupts. + */ + for (j = 0; j < gpio->num_irqs_per_bank; j++) { + dev_dbg(dev, "programming default interrupt routing for port %s\n", + port->name); + offset = TEGRA186_GPIO_INT_ROUTE_MAPPING(p, j); - value = readl(base + offset); - value = BIT(port->pins) - 1; - writel(value, base + offset); + /* + * By default we only want to route GPIO pins to IRQ 0. This works + * only under the assumption that we're running as the host kernel + * and hence all GPIO pins are owned by Linux. + * + * For cases where Linux is the guest OS, the hypervisor will have + * to configure the interrupt routing and pass only the valid + * interrupts via device tree. + */ + if (j == 0) { + value = readl(base + offset); + value = BIT(port->pins) - 1; + writel(value, base + offset); + } } } } @@ -610,6 +636,9 @@ static unsigned int tegra186_gpio_irqs_per_bank(struct tegra_gpio *gpio) gpio->num_irqs_per_bank = gpio->num_irq / gpio->num_banks; + if (gpio->num_irqs_per_bank > gpio->soc->num_irqs_per_bank) + goto error; + return 0; error: @@ -766,7 +795,8 @@ static int tegra186_gpio_probe(struct platform_device *pdev) irq->parents = gpio->irq; } - tegra186_gpio_init_route_mapping(gpio); + if (gpio->soc->num_irqs_per_bank > 1) + tegra186_gpio_init_route_mapping(gpio); np = of_find_matching_node(NULL, tegra186_pmc_of_match); if (np) { @@ -833,6 +863,7 @@ static const struct tegra_gpio_soc tegra186_main_soc = { .ports = tegra186_main_ports, .name = "tegra186-gpio", .instance = 0, + .num_irqs_per_bank = 1, }; #define TEGRA186_AON_GPIO_PORT(_name, _bank, _port, _pins) \ @@ -859,6 +890,7 @@ static const struct tegra_gpio_soc tegra186_aon_soc = { .ports = tegra186_aon_ports, .name = "tegra186-gpio-aon", .instance = 1, + .num_irqs_per_bank = 1, }; #define TEGRA194_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ @@ -910,6 +942,7 @@ static const struct tegra_gpio_soc tegra194_main_soc = { .ports = tegra194_main_ports, .name = "tegra194-gpio", .instance = 0, + .num_irqs_per_bank = 8, .num_pin_ranges = ARRAY_SIZE(tegra194_main_pin_ranges), .pin_ranges = tegra194_main_pin_ranges, .pinmux = "nvidia,tegra194-pinmux", @@ -936,6 +969,7 @@ static const struct tegra_gpio_soc tegra194_aon_soc = { .ports = tegra194_aon_ports, .name = "tegra194-gpio-aon", .instance = 1, + .num_irqs_per_bank = 8, }; static const struct of_device_id tegra186_gpio_of_match[] = { -- cgit From e24b9fc109280a2420aabe352d38fad722f4ea37 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 20 Sep 2021 11:05:15 +0200 Subject: gpio: xilinx: simplify getting .driver_data We should get 'driver_data' from 'struct device' directly. Going via platform_device is an unneeded step back and forth. Signed-off-by: Wolfram Sang Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-xilinx.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index a1b66338d077..b6d3a57e27ed 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -371,8 +371,7 @@ static int __maybe_unused xgpio_resume(struct device *dev) static int __maybe_unused xgpio_runtime_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct xgpio_instance *gpio = platform_get_drvdata(pdev); + struct xgpio_instance *gpio = dev_get_drvdata(dev); clk_disable(gpio->clk); @@ -381,8 +380,7 @@ static int __maybe_unused xgpio_runtime_suspend(struct device *dev) static int __maybe_unused xgpio_runtime_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct xgpio_instance *gpio = platform_get_drvdata(pdev); + struct xgpio_instance *gpio = dev_get_drvdata(dev); return clk_enable(gpio->clk); } -- cgit From 3846a3607738ccbc763afe7af75b5bd25009b037 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 16 Sep 2021 18:46:40 +0200 Subject: gpio: max77620: drop unneeded MODULE_ALIAS The MODULE_DEVICE_TABLE already creates proper alias for platform driver. Having another MODULE_ALIAS causes the alias to be duplicated. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-max77620.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpio/gpio-max77620.c b/drivers/gpio/gpio-max77620.c index 82b3a913005d..ebf9dea6546b 100644 --- a/drivers/gpio/gpio-max77620.c +++ b/drivers/gpio/gpio-max77620.c @@ -365,5 +365,4 @@ module_platform_driver(max77620_gpio_driver); MODULE_DESCRIPTION("GPIO interface for MAX77620 and MAX20024 PMIC"); MODULE_AUTHOR("Laxman Dewangan "); MODULE_AUTHOR("Chaitanya Bandi "); -MODULE_ALIAS("platform:max77620-gpio"); MODULE_LICENSE("GPL v2"); -- cgit From 03e2080defd2494bd2790d2ac1df9d7432671e85 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 16 Sep 2021 18:46:41 +0200 Subject: gpio: tps65218: drop unneeded MODULE_ALIAS The MODULE_DEVICE_TABLE already creates proper alias for platform driver. Having another MODULE_ALIAS causes the alias to be duplicated. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-tps65218.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpio/gpio-tps65218.c b/drivers/gpio/gpio-tps65218.c index 3517debe2b0b..912382be48e1 100644 --- a/drivers/gpio/gpio-tps65218.c +++ b/drivers/gpio/gpio-tps65218.c @@ -230,4 +230,3 @@ module_platform_driver(tps65218_gpio_driver); MODULE_AUTHOR("Nicolas Saenz Julienne "); MODULE_DESCRIPTION("GPO interface for TPS65218 PMICs"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:tps65218-gpio"); -- cgit From b083704fbf6cea21a187a99f6dae20fbca86b44e Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 22 Sep 2021 21:39:42 -0700 Subject: Input: elants_i2c - make use of devm_add_action_or_reset() The helper function devm_add_action_or_reset() will internally call devm_add_action(), and if devm_add_action() fails then it will execute the action mentioned and return the error code. So use devm_add_action_or_reset() instead of devm_add_action() to simplify the error handling, reduce the code. Signed-off-by: Cai Huoqing Link: https://lore.kernel.org/r/20210922125212.95-2-caihuoqing@baidu.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/elants_i2c.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index 17540bdb1eaf..98ba5cab685b 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -1440,11 +1440,11 @@ static int elants_i2c_probe(struct i2c_client *client, if (error) return error; - error = devm_add_action(&client->dev, elants_i2c_power_off, ts); + error = devm_add_action_or_reset(&client->dev, + elants_i2c_power_off, ts); if (error) { dev_err(&client->dev, "failed to install power off action: %d\n", error); - elants_i2c_power_off(ts); return error; } -- cgit From 4b3ed1ae2817d78e72a4281be2a9751a41f20508 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 22 Sep 2021 21:49:14 -0700 Subject: Input: raydium_i2c_ts - make use of the helper function devm_add_action_or_reset() The helper function devm_add_action_or_reset() will internally call devm_add_action(), and if devm_add_action() fails then it will execute the action mentioned and return the error code. So use devm_add_action_or_reset() instead of devm_add_action() to simplify the error handling, reduce the code. Signed-off-by: Cai Huoqing Link: https://lore.kernel.org/r/20210922125212.95-3-caihuoqing@baidu.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/raydium_i2c_ts.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/raydium_i2c_ts.c b/drivers/input/touchscreen/raydium_i2c_ts.c index 92c48d8e35a4..3a4952935366 100644 --- a/drivers/input/touchscreen/raydium_i2c_ts.c +++ b/drivers/input/touchscreen/raydium_i2c_ts.c @@ -1118,11 +1118,11 @@ static int raydium_i2c_probe(struct i2c_client *client, if (error) return error; - error = devm_add_action(&client->dev, raydium_i2c_power_off, ts); + error = devm_add_action_or_reset(&client->dev, + raydium_i2c_power_off, ts); if (error) { dev_err(&client->dev, "failed to install power off action: %d\n", error); - raydium_i2c_power_off(ts); return error; } -- cgit From d5af8a8f7c4c54758e89fa3b077b62270de3910c Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 22 Sep 2021 21:50:49 -0700 Subject: Input: mpr121 - make use of the helper function devm_add_action_or_reset() The helper function devm_add_action_or_reset() will internally call devm_add_action(), and if devm_add_action() fails then it will execute the action mentioned and return the error code. So use devm_add_action_or_reset() instead of devm_add_action() to simplify the error handling, reduce the code. Signed-off-by: Cai Huoqing Link: https://lore.kernel.org/r/20210922125954.533-1-caihuoqing@baidu.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/mpr121_touchkey.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c index 40d6e5087cde..230ab3d50b9e 100644 --- a/drivers/input/keyboard/mpr121_touchkey.c +++ b/drivers/input/keyboard/mpr121_touchkey.c @@ -107,9 +107,9 @@ static struct regulator *mpr121_vdd_supply_init(struct device *dev) return ERR_PTR(err); } - err = devm_add_action(dev, mpr121_vdd_supply_disable, vdd_supply); + err = devm_add_action_or_reset(dev, mpr121_vdd_supply_disable, + vdd_supply); if (err) { - regulator_disable(vdd_supply); dev_err(dev, "failed to add disable regulator action: %d\n", err); return ERR_PTR(err); -- cgit From 23c64d7618a7e76e46db99444d184ef75498fb71 Mon Sep 17 00:00:00 2001 From: Piyush Mehta Date: Wed, 22 Sep 2021 19:23:17 +0530 Subject: firmware: zynqmp: Add MMIO read and write support for PS_MODE pin Add Xilinx ZynqMP firmware MMIO APIs support to set and get PS_MODE pins value and status. These APIs create an interface path between mode pin controller driver and low-level API to access GPIO pins. Signed-off-by: Piyush Mehta Acked-by: Michal Simek Acked-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/firmware/xilinx/zynqmp.c | 46 ++++++++++++++++++++++++++++++++++++ include/linux/firmware/xlnx-zynqmp.h | 14 +++++++++++ 2 files changed, 60 insertions(+) diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c index a3cadbaf3cba..7feba125b883 100644 --- a/drivers/firmware/xilinx/zynqmp.c +++ b/drivers/firmware/xilinx/zynqmp.c @@ -28,6 +28,13 @@ /* Max HashMap Order for PM API feature check (1<<7 = 128) */ #define PM_API_FEATURE_CHECK_MAX_ORDER 7 +/* CRL registers and bitfields */ +#define CRL_APB_BASE 0xFF5E0000U +/* BOOT_PIN_CTRL- Used to control the mode pins after boot */ +#define CRL_APB_BOOT_PIN_CTRL (CRL_APB_BASE + (0x250U)) +/* BOOT_PIN_CTRL_MASK- out_val[11:8], out_en[3:0] */ +#define CRL_APB_BOOTPIN_CTRL_MASK 0xF0FU + static bool feature_check_enabled; static DEFINE_HASHTABLE(pm_api_features_map, PM_API_FEATURE_CHECK_MAX_ORDER); @@ -925,6 +932,45 @@ int zynqmp_pm_pinctrl_set_config(const u32 pin, const u32 param, } EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_set_config); +/** + * zynqmp_pm_bootmode_read() - PM Config API for read bootpin status + * @ps_mode: Returned output value of ps_mode + * + * This API function is to be used for notify the power management controller + * to read bootpin status. + * + * Return: status, either success or error+reason + */ +unsigned int zynqmp_pm_bootmode_read(u32 *ps_mode) +{ + unsigned int ret; + u32 ret_payload[PAYLOAD_ARG_CNT]; + + ret = zynqmp_pm_invoke_fn(PM_MMIO_READ, CRL_APB_BOOT_PIN_CTRL, 0, + 0, 0, ret_payload); + + *ps_mode = ret_payload[1]; + + return ret; +} +EXPORT_SYMBOL_GPL(zynqmp_pm_bootmode_read); + +/** + * zynqmp_pm_bootmode_write() - PM Config API for Configure bootpin + * @ps_mode: Value to be written to the bootpin ctrl register + * + * This API function is to be used for notify the power management controller + * to configure bootpin. + * + * Return: Returns status, either success or error+reason + */ +int zynqmp_pm_bootmode_write(u32 ps_mode) +{ + return zynqmp_pm_invoke_fn(PM_MMIO_WRITE, CRL_APB_BOOT_PIN_CTRL, + CRL_APB_BOOTPIN_CTRL_MASK, ps_mode, 0, NULL); +} +EXPORT_SYMBOL_GPL(zynqmp_pm_bootmode_write); + /** * zynqmp_pm_init_finalize() - PM call to inform firmware that the caller * master has initialized its own power management diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h index 56b426fe020c..3917f89b2b3c 100644 --- a/include/linux/firmware/xlnx-zynqmp.h +++ b/include/linux/firmware/xlnx-zynqmp.h @@ -72,6 +72,8 @@ enum pm_api_id { PM_SET_REQUIREMENT = 15, PM_RESET_ASSERT = 17, PM_RESET_GET_STATUS = 18, + PM_MMIO_WRITE = 19, + PM_MMIO_READ = 20, PM_PM_INIT_FINALIZE = 21, PM_FPGA_LOAD = 22, PM_FPGA_GET_STATUS = 23, @@ -390,6 +392,8 @@ int zynqmp_pm_sd_dll_reset(u32 node_id, u32 type); int zynqmp_pm_reset_assert(const enum zynqmp_pm_reset reset, const enum zynqmp_pm_reset_action assert_flag); int zynqmp_pm_reset_get_status(const enum zynqmp_pm_reset reset, u32 *status); +unsigned int zynqmp_pm_bootmode_read(u32 *ps_mode); +int zynqmp_pm_bootmode_write(u32 ps_mode); int zynqmp_pm_init_finalize(void); int zynqmp_pm_set_suspend_mode(u32 mode); int zynqmp_pm_request_node(const u32 node, const u32 capabilities, @@ -520,6 +524,16 @@ static inline int zynqmp_pm_reset_get_status(const enum zynqmp_pm_reset reset, return -ENODEV; } +static inline unsigned int zynqmp_pm_bootmode_read(u32 *ps_mode) +{ + return -ENODEV; +} + +static inline int zynqmp_pm_bootmode_write(u32 ps_mode) +{ + return -ENODEV; +} + static inline int zynqmp_pm_init_finalize(void) { return -ENODEV; -- cgit From d7f4a65cdf4f671296fab1e5b331fd3f5ab776e5 Mon Sep 17 00:00:00 2001 From: Piyush Mehta Date: Wed, 22 Sep 2021 19:23:18 +0530 Subject: dt-bindings: gpio: zynqmp: Add binding documentation for modepin This patch adds DT binding document for zynqmp modepin GPIO controller. Modepin GPIO controller has four GPIO pins which can be configurable as input or output. Modepin driver is a bridge between the peripheral driver and GPIO pins. It has set and get APIs for accessing GPIO pins, based on the device-tree entry of reset-gpio property in the peripheral driver, every pin can be configured as input/output and trigger GPIO pin. For more information please refer zynqMp TRM link: Link: https://www.xilinx.com/support/documentation/user_guides/ug1085-zynq-ultrascale-trm.pdf Chapter 2: Signals, Interfaces, and Pins Table 2-2: Clock, Reset, and Configuration Pins - PS_MODE Signed-off-by: Piyush Mehta Acked-by: Michal Simek Reviewed-by: Rob Herring Signed-off-by: Bartosz Golaszewski --- .../bindings/gpio/xlnx,zynqmp-gpio-modepin.yaml | 43 ++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/xlnx,zynqmp-gpio-modepin.yaml diff --git a/Documentation/devicetree/bindings/gpio/xlnx,zynqmp-gpio-modepin.yaml b/Documentation/devicetree/bindings/gpio/xlnx,zynqmp-gpio-modepin.yaml new file mode 100644 index 000000000000..31c0fc345903 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/xlnx,zynqmp-gpio-modepin.yaml @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/gpio/xlnx,zynqmp-gpio-modepin.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: ZynqMP Mode Pin GPIO controller + +description: + PS_MODE is 4-bits boot mode pins sampled on POR deassertion. Mode Pin + GPIO controller with configurable from numbers of pins (from 0 to 3 per + PS_MODE). Every pin can be configured as input/output. + +maintainers: + - Piyush Mehta + +properties: + compatible: + const: xlnx,zynqmp-gpio-modepin + + gpio-controller: true + + "#gpio-cells": + const: 2 + +required: + - compatible + - gpio-controller + - "#gpio-cells" + +additionalProperties: false + +examples: + - | + zynqmp-firmware { + gpio { + compatible = "xlnx,zynqmp-gpio-modepin"; + gpio-controller; + #gpio-cells = <2>; + }; + }; + +... -- cgit From 7687a5b0ee9358c96d85db58bad2a3aebee562b7 Mon Sep 17 00:00:00 2001 From: Piyush Mehta Date: Wed, 22 Sep 2021 19:23:19 +0530 Subject: gpio: modepin: Add driver support for modepin GPIO controller This patch adds driver support for the zynqmp modepin GPIO controller. GPIO modepin driver set and get the value and status of the PS_MODE pin, based on device-tree pin configuration. These four mode pins are configurable as input/output. The mode pin has a control register, which have lower four-bits [0:3] are configurable as input/output, next four-bits can be used for reading the data as input[4:7], and next setting the output pin state output[8:11]. By default value of mode pin register is 0. Signed-off-by: Piyush Mehta Acked-by: Michal Simek Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 12 +++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-zynqmp-modepin.c | 162 +++++++++++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+) create mode 100644 drivers/gpio/gpio-zynqmp-modepin.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index fae5141251e5..37a6f77c86fe 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -763,6 +763,18 @@ config GPIO_ZYNQ help Say yes here to support Xilinx Zynq GPIO controller. +config GPIO_ZYNQMP_MODEPIN + tristate "ZynqMP ps-mode pin gpio configuration driver" + depends on ZYNQMP_FIRMWARE + default ZYNQMP_FIRMWARE + help + Say yes here to support the ZynqMP ps-mode pin gpio configuration + driver. + + This ps-mode pin gpio driver is based on GPIO framework, PS_MODE + is 4-bits boot mode pins. It sets and gets the status of + the ps-mode pin. Every pin can be configured as input/output. + config GPIO_LOONGSON1 tristate "Loongson1 GPIO support" depends on MACH_LOONGSON32 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index fbcda637d5e1..71ee9fc2ff83 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -184,3 +184,4 @@ obj-$(CONFIG_GPIO_XRA1403) += gpio-xra1403.o obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o +obj-$(CONFIG_GPIO_ZYNQMP_MODEPIN) += gpio-zynqmp-modepin.o diff --git a/drivers/gpio/gpio-zynqmp-modepin.c b/drivers/gpio/gpio-zynqmp-modepin.c new file mode 100644 index 000000000000..a0d69387c153 --- /dev/null +++ b/drivers/gpio/gpio-zynqmp-modepin.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for the ps-mode pin configuration. + * + * Copyright (c) 2021 Xilinx, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 4-bit boot mode pins */ +#define MODE_PINS 4 + +/** + * modepin_gpio_get_value - Get the state of the specified pin of GPIO device + * @chip: gpio_chip instance to be worked on + * @pin: gpio pin number within the device + * + * This function reads the state of the specified pin of the GPIO device. + * + * Return: 0 if the pin is low, 1 if pin is high, -EINVAL wrong pin configured + * or error value. + */ +static int modepin_gpio_get_value(struct gpio_chip *chip, unsigned int pin) +{ + u32 regval = 0; + int ret; + + ret = zynqmp_pm_bootmode_read(®val); + if (ret) + return ret; + + /* When [0:3] corresponding bit is set, then read output bit [8:11], + * if the bit is clear then read input bit [4:7] for status or value. + */ + if (regval & BIT(pin)) + return !!(regval & BIT(pin + 8)); + else + return !!(regval & BIT(pin + 4)); +} + +/** + * modepin_gpio_set_value - Modify the state of the pin with specified value + * @chip: gpio_chip instance to be worked on + * @pin: gpio pin number within the device + * @state: value used to modify the state of the specified pin + * + * This function reads the state of the specified pin of the GPIO device, mask + * with the capture state of GPIO pin, and update pin of GPIO device. + * + * Return: None. + */ +static void modepin_gpio_set_value(struct gpio_chip *chip, unsigned int pin, + int state) +{ + u32 bootpin_val = 0; + int ret; + + zynqmp_pm_bootmode_read(&bootpin_val); + + /* Configure pin as an output by set bit [0:3] */ + bootpin_val |= BIT(pin); + + if (state) + bootpin_val |= BIT(pin + 8); + else + bootpin_val &= ~BIT(pin + 8); + + /* Configure bootpin value */ + ret = zynqmp_pm_bootmode_write(bootpin_val); + if (ret) + pr_err("modepin: set value error %d for pin %d\n", ret, pin); +} + +/** + * modepin_gpio_dir_in - Set the direction of the specified GPIO pin as input + * @chip: gpio_chip instance to be worked on + * @pin: gpio pin number within the device + * + * Return: 0 always + */ +static int modepin_gpio_dir_in(struct gpio_chip *chip, unsigned int pin) +{ + return 0; +} + +/** + * modepin_gpio_dir_out - Set the direction of the specified GPIO pin as output + * @chip: gpio_chip instance to be worked on + * @pin: gpio pin number within the device + * @state: value to be written to specified pin + * + * Return: 0 always + */ +static int modepin_gpio_dir_out(struct gpio_chip *chip, unsigned int pin, + int state) +{ + return 0; +} + +/** + * modepin_gpio_probe - Initialization method for modepin_gpio + * @pdev: platform device instance + * + * Return: 0 on success, negative error otherwise. + */ +static int modepin_gpio_probe(struct platform_device *pdev) +{ + struct gpio_chip *chip; + int status; + + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + platform_set_drvdata(pdev, chip); + + /* configure the gpio chip */ + chip->base = -1; + chip->ngpio = MODE_PINS; + chip->owner = THIS_MODULE; + chip->parent = &pdev->dev; + chip->get = modepin_gpio_get_value; + chip->set = modepin_gpio_set_value; + chip->direction_input = modepin_gpio_dir_in; + chip->direction_output = modepin_gpio_dir_out; + chip->label = dev_name(&pdev->dev); + + /* modepin gpio registration */ + status = devm_gpiochip_add_data(&pdev->dev, chip, chip); + if (status) + return dev_err_probe(&pdev->dev, status, + "Failed to add GPIO chip\n"); + + return status; +} + +static const struct of_device_id modepin_platform_id[] = { + { .compatible = "xlnx,zynqmp-gpio-modepin", }, + { } +}; + +static struct platform_driver modepin_platform_driver = { + .driver = { + .name = "modepin-gpio", + .of_match_table = modepin_platform_id, + }, + .probe = modepin_gpio_probe, +}; + +module_platform_driver(modepin_platform_driver); + +MODULE_AUTHOR("Piyush Mehta "); +MODULE_DESCRIPTION("ZynqMP Boot PS_MODE Configuration"); +MODULE_LICENSE("GPL v2"); -- cgit From 563edf85ce18a90dd0a7b39e279a691d937205f6 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Tue, 7 Sep 2021 14:47:51 +0200 Subject: backlight: Propagate errors from get_brightness() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit backlight.h documents "struct backlight_ops->get_brightness()" to return a negative errno on failure. So far these errors have not been handled in the backlight core. This leads to negative values being exposed through sysfs although only positive values are documented to be reported. Signed-off-by: Thomas Weißschuh Reviewed-by: Daniel Thompson Signed-off-by: Lee Jones --- drivers/video/backlight/backlight.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index fc990e576340..4ae6fae94ac2 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -292,10 +292,13 @@ static ssize_t actual_brightness_show(struct device *dev, struct backlight_device *bd = to_backlight_device(dev); mutex_lock(&bd->ops_lock); - if (bd->ops && bd->ops->get_brightness) - rc = sprintf(buf, "%d\n", bd->ops->get_brightness(bd)); - else + if (bd->ops && bd->ops->get_brightness) { + rc = bd->ops->get_brightness(bd); + if (rc >= 0) + rc = sprintf(buf, "%d\n", rc); + } else { rc = sprintf(buf, "%d\n", bd->props.brightness); + } mutex_unlock(&bd->ops_lock); return rc; @@ -381,9 +384,18 @@ ATTRIBUTE_GROUPS(bl_device); void backlight_force_update(struct backlight_device *bd, enum backlight_update_reason reason) { + int brightness; + mutex_lock(&bd->ops_lock); - if (bd->ops && bd->ops->get_brightness) - bd->props.brightness = bd->ops->get_brightness(bd); + if (bd->ops && bd->ops->get_brightness) { + brightness = bd->ops->get_brightness(bd); + if (brightness >= 0) + bd->props.brightness = brightness; + else + dev_err(&bd->dev, + "Could not update brightness from device: %pe\n", + ERR_PTR(brightness)); + } mutex_unlock(&bd->ops_lock); backlight_generate_event(bd, reason); } -- cgit From d50497c4a05e73e76874fd0d4942036375a7ec0f Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Wed, 15 Sep 2021 18:46:27 -0700 Subject: platform/chrome: cros_ec_proto: Fix check_features ret val The kerneldoc for cros_ec_check_features() states that it returns 1 or 0 depedending on whether a feature is supported or not, but it instead returns a negative error number in one case, and a non-1 bitmask in other cases. Since all call-sites only check for a 1 or 0 return value, update the function to return boolean values. Signed-off-by: Prashant Malani Reviewed-by: Guenter Roeck Signed-off-by: Enric Balletbo i Serra Link: https://lore.kernel.org/r/20210916014632.2662612-1-pmalani@chromium.org --- drivers/platform/chrome/cros_ec_proto.c | 12 +++++++----- include/linux/platform_data/cros_ec_proto.h | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index a7404d69b2d3..a34cf58c5ef7 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -808,9 +808,9 @@ EXPORT_SYMBOL(cros_ec_get_host_event); * * Call this function to test whether the ChromeOS EC supports a feature. * - * Return: 1 if supported, 0 if not + * Return: true if supported, false if not (or if an error was encountered). */ -int cros_ec_check_features(struct cros_ec_dev *ec, int feature) +bool cros_ec_check_features(struct cros_ec_dev *ec, int feature) { struct cros_ec_command *msg; int ret; @@ -818,8 +818,10 @@ int cros_ec_check_features(struct cros_ec_dev *ec, int feature) if (ec->features[0] == -1U && ec->features[1] == -1U) { /* features bitmap not read yet */ msg = kzalloc(sizeof(*msg) + sizeof(ec->features), GFP_KERNEL); - if (!msg) - return -ENOMEM; + if (!msg) { + dev_err(ec->dev, "failed to allocate memory to get EC features\n"); + return false; + } msg->command = EC_CMD_GET_FEATURES + ec->cmd_offset; msg->insize = sizeof(ec->features); @@ -839,7 +841,7 @@ int cros_ec_check_features(struct cros_ec_dev *ec, int feature) kfree(msg); } - return ec->features[feature / 32] & EC_FEATURE_MASK_0(feature); + return !!(ec->features[feature / 32] & EC_FEATURE_MASK_0(feature)); } EXPORT_SYMBOL_GPL(cros_ec_check_features); diff --git a/include/linux/platform_data/cros_ec_proto.h b/include/linux/platform_data/cros_ec_proto.h index 02599687770c..55844ece0b32 100644 --- a/include/linux/platform_data/cros_ec_proto.h +++ b/include/linux/platform_data/cros_ec_proto.h @@ -227,7 +227,7 @@ int cros_ec_get_next_event(struct cros_ec_device *ec_dev, u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev); -int cros_ec_check_features(struct cros_ec_dev *ec, int feature); +bool cros_ec_check_features(struct cros_ec_dev *ec, int feature); int cros_ec_get_sensor_count(struct cros_ec_dev *ec); -- cgit From 458032fcfa91c8714859b1f01b9ac7dccea5d6cd Mon Sep 17 00:00:00 2001 From: Yang Li Date: Fri, 10 Sep 2021 17:33:24 +0800 Subject: UNRPC: Return specific error code on kmalloc failure Although the callers of this function only care about whether the return value is null or not, we should still give a rigorous error code. Smatch tool warning: net/sunrpc/auth_gss/svcauth_gss.c:784 gss_write_verf() warn: returning -1 instead of -ENOMEM is sloppy No functional change, just more standardized. Reported-by: Abaci Robot Signed-off-by: Yang Li Signed-off-by: J. Bruce Fields --- net/sunrpc/auth_gss/svcauth_gss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 3e776e3dff91..7dba6a9c213a 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -781,7 +781,7 @@ gss_write_verf(struct svc_rqst *rqstp, struct gss_ctx *ctx_id, u32 seq) svc_putnl(rqstp->rq_res.head, RPC_AUTH_GSS); xdr_seq = kmalloc(4, GFP_KERNEL); if (!xdr_seq) - return -1; + return -ENOMEM; *xdr_seq = htonl(seq); iov.iov_base = xdr_seq; -- cgit From 73eff8602ad10cb55cdb614241b18f3d842abbe1 Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Thu, 23 Sep 2021 13:03:21 -0700 Subject: platform/chrome: cros-ec-typec: Cleanup use of check_features cros_ec_check_features() now returns a boolean. Remove the double NOT operator since it's not required anymore. No functional changes are expected with this patch. Signed-off-by: Prashant Malani Reviewed-by: Guenter Roeck Signed-off-by: Enric Balletbo i Serra Link: https://lore.kernel.org/r/20210923200321.3623222-1-pmalani@chromium.org --- drivers/platform/chrome/cros_ec_typec.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c index 262a891eded3..7b3afb6cda5d 100644 --- a/drivers/platform/chrome/cros_ec_typec.c +++ b/drivers/platform/chrome/cros_ec_typec.c @@ -1116,9 +1116,8 @@ static int cros_typec_probe(struct platform_device *pdev) } ec_dev = dev_get_drvdata(&typec->ec->ec->dev); - typec->typec_cmd_supported = !!cros_ec_check_features(ec_dev, EC_FEATURE_TYPEC_CMD); - typec->needs_mux_ack = !!cros_ec_check_features(ec_dev, - EC_FEATURE_TYPEC_MUX_REQUIRE_AP_ACK); + typec->typec_cmd_supported = cros_ec_check_features(ec_dev, EC_FEATURE_TYPEC_CMD); + typec->needs_mux_ack = cros_ec_check_features(ec_dev, EC_FEATURE_TYPEC_MUX_REQUIRE_AP_ACK); ret = cros_typec_ec_command(typec, 0, EC_CMD_USB_PD_PORTS, NULL, 0, &resp, sizeof(resp)); -- cgit From 6c93f39f2f435d822c2f765650f405acebdc49fc Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Thu, 9 Sep 2021 14:18:44 +0800 Subject: perf list: Display pmu prefix for partially supported hybrid cache events Part of hardware cache events are only available on one CPU PMU. For example, 'L1-dcache-load-misses' is only available on cpu_core. perf list should clearly report this info. root@otcpl-adl-s-2:~# ./perf list Before: L1-dcache-load-misses [Hardware cache event] L1-dcache-loads [Hardware cache event] L1-dcache-stores [Hardware cache event] L1-icache-load-misses [Hardware cache event] L1-icache-loads [Hardware cache event] LLC-load-misses [Hardware cache event] LLC-loads [Hardware cache event] LLC-store-misses [Hardware cache event] LLC-stores [Hardware cache event] branch-load-misses [Hardware cache event] branch-loads [Hardware cache event] dTLB-load-misses [Hardware cache event] dTLB-loads [Hardware cache event] dTLB-store-misses [Hardware cache event] dTLB-stores [Hardware cache event] iTLB-load-misses [Hardware cache event] node-load-misses [Hardware cache event] node-loads [Hardware cache event] node-store-misses [Hardware cache event] node-stores [Hardware cache event] After: L1-dcache-loads [Hardware cache event] L1-dcache-stores [Hardware cache event] L1-icache-load-misses [Hardware cache event] LLC-load-misses [Hardware cache event] LLC-loads [Hardware cache event] LLC-store-misses [Hardware cache event] LLC-stores [Hardware cache event] branch-load-misses [Hardware cache event] branch-loads [Hardware cache event] cpu_atom/L1-icache-loads/ [Hardware cache event] cpu_core/L1-dcache-load-misses/ [Hardware cache event] cpu_core/node-load-misses/ [Hardware cache event] cpu_core/node-loads/ [Hardware cache event] dTLB-load-misses [Hardware cache event] dTLB-loads [Hardware cache event] dTLB-store-misses [Hardware cache event] dTLB-stores [Hardware cache event] iTLB-load-misses [Hardware cache event] Now we can clearly see 'L1-dcache-load-misses' is only available on cpu_core. If without pmu prefix, it indicates the event is available on both cpu_core and cpu_atom. Signed-off-by: Jin Yao Cc: Alexander Shishkin Cc: Andi Kleen Cc: Jin Yao Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/20210909061844.10221-1-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 76 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 68 insertions(+), 8 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 85d3d77d3c6a..067f830dea4b 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -2701,7 +2701,7 @@ next: return 0; } -static bool is_event_supported(u8 type, unsigned config) +static bool is_event_supported(u8 type, u64 config) { bool ret = true; int open_return; @@ -2821,10 +2821,18 @@ void print_sdt_events(const char *subsys_glob, const char *event_glob, int print_hwcache_events(const char *event_glob, bool name_only) { - unsigned int type, op, i, evt_i = 0, evt_num = 0; - char name[64]; - char **evt_list = NULL; + unsigned int type, op, i, evt_i = 0, evt_num = 0, npmus = 0; + char name[64], new_name[128]; + char **evt_list = NULL, **evt_pmus = NULL; bool evt_num_known = false; + struct perf_pmu *pmu = NULL; + + if (perf_pmu__has_hybrid()) { + npmus = perf_pmu__hybrid_pmu_num(); + evt_pmus = zalloc(sizeof(char *) * npmus); + if (!evt_pmus) + goto out_enomem; + } restart: if (evt_num_known) { @@ -2840,20 +2848,61 @@ restart: continue; for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { + unsigned int hybrid_supported = 0, j; + bool supported; + __evsel__hw_cache_type_op_res_name(type, op, i, name, sizeof(name)); if (event_glob != NULL && !strglobmatch(name, event_glob)) continue; - if (!is_event_supported(PERF_TYPE_HW_CACHE, - type | (op << 8) | (i << 16))) - continue; + if (!perf_pmu__has_hybrid()) { + if (!is_event_supported(PERF_TYPE_HW_CACHE, + type | (op << 8) | (i << 16))) { + continue; + } + } else { + perf_pmu__for_each_hybrid_pmu(pmu) { + if (!evt_num_known) { + evt_num++; + continue; + } + + supported = is_event_supported( + PERF_TYPE_HW_CACHE, + type | (op << 8) | (i << 16) | + ((__u64)pmu->type << PERF_PMU_TYPE_SHIFT)); + if (supported) { + snprintf(new_name, sizeof(new_name), "%s/%s/", + pmu->name, name); + evt_pmus[hybrid_supported] = strdup(new_name); + hybrid_supported++; + } + } + + if (hybrid_supported == 0) + continue; + } if (!evt_num_known) { evt_num++; continue; } - evt_list[evt_i] = strdup(name); + if ((hybrid_supported == 0) || + (hybrid_supported == npmus)) { + evt_list[evt_i] = strdup(name); + if (npmus > 0) { + for (j = 0; j < npmus; j++) + zfree(&evt_pmus[j]); + } + } else { + for (j = 0; j < hybrid_supported; j++) { + evt_list[evt_i++] = evt_pmus[j]; + evt_pmus[j] = NULL; + } + continue; + } + if (evt_list[evt_i] == NULL) goto out_enomem; evt_i++; @@ -2865,6 +2914,13 @@ restart: evt_num_known = true; goto restart; } + + for (evt_i = 0; evt_i < evt_num; evt_i++) { + if (!evt_list[evt_i]) + break; + } + + evt_num = evt_i; qsort(evt_list, evt_num, sizeof(char *), cmp_string); evt_i = 0; while (evt_i < evt_num) { @@ -2883,6 +2939,10 @@ out_free: for (evt_i = 0; evt_i < evt_num; evt_i++) zfree(&evt_list[evt_i]); zfree(&evt_list); + + for (evt_i = 0; evt_i < npmus; evt_i++) + zfree(&evt_pmus[evt_i]); + zfree(&evt_pmus); return evt_num; out_enomem: -- cgit From d05377e184fc88e965e20606da93387b8fadf493 Mon Sep 17 00:00:00 2001 From: Ariel Marcovitch Date: Mon, 13 Sep 2021 19:45:14 +0300 Subject: kconfig: Create links to main menu items in search When one searches for a main menu item, links aren't created for it like with the rest of the symbols. This happens because we trace the item until we get to the rootmenu, but we don't include it in the path of the item. The rationale was probably that we don't want to show the main menu in the path of all items, because it is redundant. However, when an item has only the rootmenu in its path it should be included, because this way the user can jump to its location. Add a 'Main menu' entry in the 'Location:' section for the kconfig items. This makes the 'if (i > 0)' superfluous because each item with prompt will have at least one menu in its path. Signed-off-by: Ariel Marcovitch Signed-off-by: Masahiro Yamada --- scripts/kconfig/menu.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 606ba8a63c24..3d6f7cba8846 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -728,7 +728,7 @@ static void get_prompt_str(struct gstr *r, struct property *prop, get_dep_str(r, prop->visible.expr, " Visible if: "); menu = prop->menu->parent; - for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) { + for (i = 0; menu && i < 8; menu = menu->parent) { bool accessible = menu_is_visible(menu); submenu[i++] = menu; @@ -758,21 +758,24 @@ static void get_prompt_str(struct gstr *r, struct property *prop, list_add_tail(&jump->entries, head); } - if (i > 0) { - str_printf(r, " Location:\n"); - for (j = 4; --i >= 0; j += 2) { - menu = submenu[i]; - if (jump && menu == location) - jump->offset = strlen(r->s); - str_printf(r, "%*c-> %s", j, ' ', - menu_get_prompt(menu)); - if (menu->sym) { - str_printf(r, " (%s [=%s])", menu->sym->name ? - menu->sym->name : "", - sym_get_string_value(menu->sym)); - } - str_append(r, "\n"); + str_printf(r, " Location:\n"); + for (j = 4; --i >= 0; j += 2) { + menu = submenu[i]; + if (jump && menu == location) + jump->offset = strlen(r->s); + + if (menu == &rootmenu) + /* The real rootmenu prompt is ugly */ + str_printf(r, "%*cMain menu", j, ' '); + else + str_printf(r, "%*c-> %s", j, ' ', menu_get_prompt(menu)); + + if (menu->sym) { + str_printf(r, " (%s [=%s])", menu->sym->name ? + menu->sym->name : "", + sym_get_string_value(menu->sym)); } + str_append(r, "\n"); } } -- cgit From 8719a17613e0233d707eb22e1645d217594631ef Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 23 Sep 2021 20:49:20 +0100 Subject: rtc: ds1302: Add SPI ID table Currently autoloading for SPI devices does not use the DT ID table, it uses SPI modalises. Supporting OF modalises is going to be difficult if not impractical, an attempt was made but has been reverted, so ensure that module autoloading works for this driver by adding an id_table listing the SPI IDs for everything. Fixes: 96c8395e2166 ("spi: Revert modalias changes") Signed-off-by: Mark Brown Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210923194922.53386-2-broonie@kernel.org --- drivers/rtc/rtc-ds1302.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c index b3de6d2e680a..2f83adef966e 100644 --- a/drivers/rtc/rtc-ds1302.c +++ b/drivers/rtc/rtc-ds1302.c @@ -199,11 +199,18 @@ static const struct of_device_id ds1302_dt_ids[] = { MODULE_DEVICE_TABLE(of, ds1302_dt_ids); #endif +static const struct spi_device_id ds1302_spi_ids[] = { + { .name = "ds1302", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(spi, ds1302_spi_ids); + static struct spi_driver ds1302_driver = { .driver.name = "rtc-ds1302", .driver.of_match_table = of_match_ptr(ds1302_dt_ids), .probe = ds1302_probe, .remove = ds1302_remove, + .id_table = ds1302_spi_ids, }; module_spi_driver(ds1302_driver); -- cgit From da87639d6312afb8855717c791768bf2d4ca8ac8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 23 Sep 2021 20:49:21 +0100 Subject: rtc: ds1390: Add SPI ID table Currently autoloading for SPI devices does not use the DT ID table, it uses SPI modalises. Supporting OF modalises is going to be difficult if not impractical, an attempt was made but has been reverted, so ensure that module autoloading works for this driver by adding an id_table listing the SPI IDs for everything. Fixes: 96c8395e2166 ("spi: Revert modalias changes") Signed-off-by: Mark Brown Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210923194922.53386-3-broonie@kernel.org --- drivers/rtc/rtc-ds1390.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/rtc/rtc-ds1390.c b/drivers/rtc/rtc-ds1390.c index 66fc8617d07e..93ce72b9ae59 100644 --- a/drivers/rtc/rtc-ds1390.c +++ b/drivers/rtc/rtc-ds1390.c @@ -219,12 +219,19 @@ static const struct of_device_id ds1390_of_match[] = { }; MODULE_DEVICE_TABLE(of, ds1390_of_match); +static const struct spi_device_id ds1390_spi_ids[] = { + { .name = "ds1390" }, + {} +}; +MODULE_DEVICE_TABLE(spi, ds1390_spi_ids); + static struct spi_driver ds1390_driver = { .driver = { .name = "rtc-ds1390", .of_match_table = of_match_ptr(ds1390_of_match), }, .probe = ds1390_probe, + .id_table = ds1390_spi_ids, }; module_spi_driver(ds1390_driver); -- cgit From 5f84478e14aa8b43a4ea85d2e091931741947749 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 23 Sep 2021 20:49:22 +0100 Subject: rtc: pcf2123: Add SPI ID table Currently autoloading for SPI devices does not use the DT ID table, it uses SPI modalises. Supporting OF modalises is going to be difficult if not impractical, an attempt was made but has been reverted, so ensure that module autoloading works for this driver by adding an id_table listing the SPI IDs for everything. Fixes: 96c8395e2166 ("spi: Revert modalias changes") Signed-off-by: Mark Brown Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210923194922.53386-4-broonie@kernel.org --- drivers/rtc/rtc-pcf2123.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c index 0f58cac81d8c..7473e6c8a183 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c @@ -451,12 +451,21 @@ static const struct of_device_id pcf2123_dt_ids[] = { MODULE_DEVICE_TABLE(of, pcf2123_dt_ids); #endif +static const struct spi_device_id pcf2123_spi_ids[] = { + { .name = "pcf2123", }, + { .name = "rv2123", }, + { .name = "rtc-pcf2123", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(spi, pcf2123_spi_ids); + static struct spi_driver pcf2123_driver = { .driver = { .name = "rtc-pcf2123", .of_match_table = of_match_ptr(pcf2123_dt_ids), }, .probe = pcf2123_probe, + .id_table = pcf2123_spi_ids, }; module_spi_driver(pcf2123_driver); -- cgit From 5e295f9402039aaa38d0949f598745b98850fd13 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 16 Sep 2021 18:45:12 +0200 Subject: rtc: omap: drop unneeded MODULE_ALIAS The MODULE_DEVICE_TABLE already creates proper alias for platform driver. Having another MODULE_ALIAS causes the alias to be duplicated. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210916164513.134725-1-krzysztof.kozlowski@canonical.com --- drivers/rtc/rtc-omap.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index d46e0f0cc502..4d4f3b1a7309 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -1029,6 +1029,5 @@ static struct platform_driver omap_rtc_driver = { module_platform_driver(omap_rtc_driver); -MODULE_ALIAS("platform:omap_rtc"); MODULE_AUTHOR("George G. Davis (and others)"); MODULE_LICENSE("GPL"); -- cgit From 6eee1c48be7cb0b9b14408521a9151c1021901d3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 16 Sep 2021 18:46:04 +0200 Subject: rtc: s5m: drop unneeded MODULE_ALIAS The MODULE_DEVICE_TABLE already creates proper alias for platform driver. Having another MODULE_ALIAS causes the alias to be duplicated. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210916164604.134924-1-krzysztof.kozlowski@canonical.com --- drivers/rtc/rtc-s5m.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index fb9c6b709e13..4243fe6d3842 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -861,4 +861,3 @@ module_platform_driver(s5m_rtc_driver); MODULE_AUTHOR("Sangbeom Kim "); MODULE_DESCRIPTION("Samsung S5M/S2MPS14 RTC driver"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:s5m-rtc"); -- cgit From 38b17bc9c40e8f3138b02c624d9063b6781c8150 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 18 Sep 2021 23:35:51 +0200 Subject: rtc: rx6110: simplify getting the adapter of a client We have a dedicated pointer for that, so use it. Much easier to read and less computation involved. Signed-off-by: Wolfram Sang Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210918213553.14514-1-wsa+renesas@sang-engineering.com --- drivers/rtc/rtc-rx6110.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-rx6110.c b/drivers/rtc/rtc-rx6110.c index f4d425002f7f..758fd6e11a15 100644 --- a/drivers/rtc/rtc-rx6110.c +++ b/drivers/rtc/rtc-rx6110.c @@ -422,7 +422,7 @@ static struct regmap_config regmap_i2c_config = { static int rx6110_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct i2c_adapter *adapter = client->adapter; struct rx6110_data *rx6110; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA -- cgit From dd49cbedde8a0f1e0d09698f9cad791d37a8e03e Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Mon, 23 Aug 2021 19:16:11 +0200 Subject: dt-bindings: rtc: Add Mstar MSC313e RTC devicetree bindings documentation This adds the documentation for the devicetree bindings of the Mstar MSC313e RTC driver, found from MSC313e SoCs and newer. Signed-off-by: Romain Perier Reviewed-by: Rob Herring Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210823171613.18941-2-romain.perier@gmail.com --- .../devicetree/bindings/rtc/mstar,msc313-rtc.yaml | 49 ++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 Documentation/devicetree/bindings/rtc/mstar,msc313-rtc.yaml diff --git a/Documentation/devicetree/bindings/rtc/mstar,msc313-rtc.yaml b/Documentation/devicetree/bindings/rtc/mstar,msc313-rtc.yaml new file mode 100644 index 000000000000..114199cf4d28 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/mstar,msc313-rtc.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/mstar,msc313-rtc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mstar MSC313e RTC Device Tree Bindings + +allOf: + - $ref: "rtc.yaml#" + +maintainers: + - Daniel Palmer + - Romain Perier + +properties: + compatible: + enum: + - mstar,msc313-rtc + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + start-year: true + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + +additionalProperties: false + +examples: + - | + #include + rtc@2400 { + compatible = "mstar,msc313-rtc"; + reg = <0x2400 0x40>; + clocks = <&xtal_div2>; + interrupts-extended = <&intc_irq GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>; + }; +... -- cgit From be7d9c9161b9c76edeff15e79edc2f256568fe05 Mon Sep 17 00:00:00 2001 From: Daniel Palmer Date: Mon, 23 Aug 2021 19:16:12 +0200 Subject: rtc: Add support for the MSTAR MSC313 RTC This adds support for the RTC block on the Mstar MSC313e SoCs and newer. Signed-off-by: Daniel Palmer Co-developed-by: Romain Perier Signed-off-by: Romain Perier Reviewed-by: Nobuhiro Iwamatsu Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210823171613.18941-3-romain.perier@gmail.com --- MAINTAINERS | 1 + drivers/rtc/Kconfig | 10 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-msc313.c | 258 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 270 insertions(+) create mode 100644 drivers/rtc/rtc-msc313.c diff --git a/MAINTAINERS b/MAINTAINERS index eeb4c70b3d5b..caedf3c29286 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2247,6 +2247,7 @@ F: arch/arm/boot/dts/mstar-* F: arch/arm/mach-mstar/ F: drivers/clk/mstar/ F: drivers/gpio/gpio-msc313.c +F: drivers/rtc/rtc-msc313.c F: drivers/watchdog/msc313e_wdt.c F: include/dt-bindings/clock/mstar-* F: include/dt-bindings/gpio/msc313-gpio.h diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index e1bc5214494e..59dc1410a160 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1935,4 +1935,14 @@ config RTC_DRV_WILCO_EC This can also be built as a module. If so, the module will be named "rtc_wilco_ec". +config RTC_DRV_MSC313 + tristate "MStar MSC313 RTC" + depends on ARCH_MSTARV7 || COMPILE_TEST + help + If you say yes here you get support for the Mstar MSC313e On-Chip + Real Time Clock. + + This driver can also be built as a module, if so, the module + will be called "rtc-msc313". + endif # RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 5ceeafe4d5b2..e76308053b0f 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -103,6 +103,7 @@ obj-$(CONFIG_RTC_DRV_MCP795) += rtc-mcp795.o obj-$(CONFIG_RTC_DRV_MESON) += rtc-meson.o obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o +obj-$(CONFIG_RTC_DRV_MSC313) += rtc-msc313.o obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o obj-$(CONFIG_RTC_DRV_MT2712) += rtc-mt2712.o obj-$(CONFIG_RTC_DRV_MT6397) += rtc-mt6397.o diff --git a/drivers/rtc/rtc-msc313.c b/drivers/rtc/rtc-msc313.c new file mode 100644 index 000000000000..f493ca5f181b --- /dev/null +++ b/drivers/rtc/rtc-msc313.c @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Real time clocks driver for MStar/SigmaStar ARMv7 SoCs. + * Based on "Real Time Clock driver for msb252x." that was contained + * in various MStar kernels. + * + * (C) 2019 Daniel Palmer + * (C) 2021 Romain Perier + */ + +#include +#include +#include +#include +#include +#include + +/* Registers */ +#define REG_RTC_CTRL 0x00 +#define REG_RTC_FREQ_CW_L 0x04 +#define REG_RTC_FREQ_CW_H 0x08 +#define REG_RTC_LOAD_VAL_L 0x0C +#define REG_RTC_LOAD_VAL_H 0x10 +#define REG_RTC_MATCH_VAL_L 0x14 +#define REG_RTC_MATCH_VAL_H 0x18 +#define REG_RTC_STATUS_INT 0x1C +#define REG_RTC_CNT_VAL_L 0x20 +#define REG_RTC_CNT_VAL_H 0x24 + +/* Control bits for REG_RTC_CTRL */ +#define SOFT_RSTZ_BIT BIT(0) +#define CNT_EN_BIT BIT(1) +#define WRAP_EN_BIT BIT(2) +#define LOAD_EN_BIT BIT(3) +#define READ_EN_BIT BIT(4) +#define INT_MASK_BIT BIT(5) +#define INT_FORCE_BIT BIT(6) +#define INT_CLEAR_BIT BIT(7) + +/* Control bits for REG_RTC_STATUS_INT */ +#define RAW_INT_BIT BIT(0) +#define ALM_INT_BIT BIT(1) + +struct msc313_rtc { + struct rtc_device *rtc_dev; + void __iomem *rtc_base; +}; + +static int msc313_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct msc313_rtc *priv = dev_get_drvdata(dev); + unsigned long seconds; + + seconds = readw(priv->rtc_base + REG_RTC_MATCH_VAL_L) + | (readw(priv->rtc_base + REG_RTC_MATCH_VAL_H) << 16); + + rtc_time64_to_tm(seconds, &alarm->time); + + if (!(readw(priv->rtc_base + REG_RTC_CTRL) & INT_MASK_BIT)) + alarm->enabled = 1; + + return 0; +} + +static int msc313_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct msc313_rtc *priv = dev_get_drvdata(dev); + u16 reg; + + reg = readw(priv->rtc_base + REG_RTC_CTRL); + if (enabled) + reg &= ~INT_MASK_BIT; + else + reg |= INT_MASK_BIT; + writew(reg, priv->rtc_base + REG_RTC_CTRL); + return 0; +} + +static int msc313_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct msc313_rtc *priv = dev_get_drvdata(dev); + unsigned long seconds; + + seconds = rtc_tm_to_time64(&alarm->time); + writew((seconds & 0xFFFF), priv->rtc_base + REG_RTC_MATCH_VAL_L); + writew((seconds >> 16) & 0xFFFF, priv->rtc_base + REG_RTC_MATCH_VAL_H); + + msc313_rtc_alarm_irq_enable(dev, alarm->enabled); + + return 0; +} + +static bool msc313_rtc_get_enabled(struct msc313_rtc *priv) +{ + return readw(priv->rtc_base + REG_RTC_CTRL) & CNT_EN_BIT; +} + +static void msc313_rtc_set_enabled(struct msc313_rtc *priv) +{ + u16 reg; + + reg = readw(priv->rtc_base + REG_RTC_CTRL); + reg |= CNT_EN_BIT; + writew(reg, priv->rtc_base + REG_RTC_CTRL); +} + +static int msc313_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct msc313_rtc *priv = dev_get_drvdata(dev); + u32 seconds; + u16 reg; + + if (!msc313_rtc_get_enabled(priv)) + return -EINVAL; + + reg = readw(priv->rtc_base + REG_RTC_CTRL); + writew(reg | READ_EN_BIT, priv->rtc_base + REG_RTC_CTRL); + + /* Wait for HW latch done */ + while (readw(priv->rtc_base + REG_RTC_CTRL) & READ_EN_BIT) + udelay(1); + + seconds = readw(priv->rtc_base + REG_RTC_CNT_VAL_L) + | (readw(priv->rtc_base + REG_RTC_CNT_VAL_H) << 16); + + rtc_time64_to_tm(seconds, tm); + + return 0; +} + +static int msc313_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct msc313_rtc *priv = dev_get_drvdata(dev); + unsigned long seconds; + u16 reg; + + seconds = rtc_tm_to_time64(tm); + writew(seconds & 0xFFFF, priv->rtc_base + REG_RTC_LOAD_VAL_L); + writew((seconds >> 16) & 0xFFFF, priv->rtc_base + REG_RTC_LOAD_VAL_H); + + /* Enable load for loading value into internal RTC counter */ + reg = readw(priv->rtc_base + REG_RTC_CTRL); + writew(reg | LOAD_EN_BIT, priv->rtc_base + REG_RTC_CTRL); + + /* Wait for HW latch done */ + while (readw(priv->rtc_base + REG_RTC_CTRL) & LOAD_EN_BIT) + udelay(1); + msc313_rtc_set_enabled(priv); + return 0; +} + +static const struct rtc_class_ops msc313_rtc_ops = { + .read_time = msc313_rtc_read_time, + .set_time = msc313_rtc_set_time, + .read_alarm = msc313_rtc_read_alarm, + .set_alarm = msc313_rtc_set_alarm, + .alarm_irq_enable = msc313_rtc_alarm_irq_enable, +}; + +static irqreturn_t msc313_rtc_interrupt(s32 irq, void *dev_id) +{ + struct msc313_rtc *priv = dev_get_drvdata(dev_id); + u16 reg; + + reg = readw(priv->rtc_base + REG_RTC_STATUS_INT); + if (!(reg & ALM_INT_BIT)) + return IRQ_NONE; + + reg = readw(priv->rtc_base + REG_RTC_CTRL); + reg |= INT_CLEAR_BIT; + reg &= ~INT_FORCE_BIT; + writew(reg, priv->rtc_base + REG_RTC_CTRL); + + rtc_update_irq(priv->rtc_dev, 1, RTC_IRQF | RTC_AF); + + return IRQ_HANDLED; +} + +static int msc313_rtc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct msc313_rtc *priv; + unsigned long rate; + struct clk *clk; + int ret; + int irq; + + priv = devm_kzalloc(&pdev->dev, sizeof(struct msc313_rtc), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->rtc_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->rtc_base)) + return PTR_ERR(priv->rtc_base); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return -EINVAL; + + priv->rtc_dev = devm_rtc_allocate_device(dev); + if (IS_ERR(priv->rtc_dev)) + return PTR_ERR(priv->rtc_dev); + + priv->rtc_dev->ops = &msc313_rtc_ops; + priv->rtc_dev->range_max = U32_MAX; + + ret = devm_request_irq(dev, irq, msc313_rtc_interrupt, IRQF_SHARED, + dev_name(&pdev->dev), &pdev->dev); + if (ret) { + dev_err(dev, "Could not request IRQ\n"); + return ret; + } + + clk = devm_clk_get(dev, NULL); + if (IS_ERR(clk)) { + dev_err(dev, "No input reference clock\n"); + return PTR_ERR(clk); + } + + ret = clk_prepare_enable(clk); + if (ret) { + dev_err(dev, "Failed to enable the reference clock, %d\n", ret); + return ret; + } + + ret = devm_add_action_or_reset(dev, (void (*) (void *))clk_disable_unprepare, clk); + if (ret) + return ret; + + rate = clk_get_rate(clk); + writew(rate & 0xFFFF, priv->rtc_base + REG_RTC_FREQ_CW_L); + writew((rate >> 16) & 0xFFFF, priv->rtc_base + REG_RTC_FREQ_CW_H); + + platform_set_drvdata(pdev, priv); + + return devm_rtc_register_device(priv->rtc_dev); +} + +static const struct of_device_id msc313_rtc_of_match_table[] = { + { .compatible = "mstar,msc313-rtc" }, + { } +}; +MODULE_DEVICE_TABLE(of, msc313_rtc_of_match_table); + +static struct platform_driver msc313_rtc_driver = { + .probe = msc313_rtc_probe, + .driver = { + .name = "msc313-rtc", + .of_match_table = msc313_rtc_of_match_table, + }, +}; + +module_platform_driver(msc313_rtc_driver); + +MODULE_AUTHOR("Daniel Palmer "); +MODULE_AUTHOR("Romain Perier "); +MODULE_DESCRIPTION("MStar RTC Driver"); +MODULE_LICENSE("GPL v2"); -- cgit From 27ff63eb076c31086e0a72d41b5c635193a58516 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 27 Sep 2021 08:37:23 +0200 Subject: rtc: msc313: fix missing include The driver needs io.h Reported-by: Stephen Rothwell Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210927063724.312687-1-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-msc313.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rtc/rtc-msc313.c b/drivers/rtc/rtc-msc313.c index f493ca5f181b..5f178d29cfd8 100644 --- a/drivers/rtc/rtc-msc313.c +++ b/drivers/rtc/rtc-msc313.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include -- cgit From f636fb044ad6a4bea1032cf65e2fe0dd04332265 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 20 Sep 2021 11:05:18 +0200 Subject: iio: common: cros_ec_sensors: simplify getting .driver_data We should get 'driver_data' from 'struct device' directly. Going via platform_device is an unneeded step back and forth. Signed-off-by: Wolfram Sang Acked-by: Jonathan Cameron Signed-off-by: Enric Balletbo i Serra Link: https://lore.kernel.org/r/20210920090522.23784-7-wsa+renesas@sang-engineering.com --- drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c index 28bde13003b7..b2725c6adc7f 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c @@ -831,8 +831,7 @@ EXPORT_SYMBOL_GPL(cros_ec_sensors_core_write); static int __maybe_unused cros_ec_sensors_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); int ret = 0; -- cgit From f11c35e18150a347f6251a9fecd14290c25b743a Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 20 Sep 2021 11:05:20 +0200 Subject: platform/chrome: cros_ec_sensorhub: simplify getting .driver_data We should get 'driver_data' from 'struct device' directly. Going via platform_device is an unneeded step back and forth. Signed-off-by: Wolfram Sang Signed-off-by: Enric Balletbo i Serra Link: https://lore.kernel.org/r/20210920090522.23784-9-wsa+renesas@sang-engineering.com --- drivers/platform/chrome/cros_ec_sensorhub.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_sensorhub.c b/drivers/platform/chrome/cros_ec_sensorhub.c index 9c4af76a9956..31fb8bdaad5a 100644 --- a/drivers/platform/chrome/cros_ec_sensorhub.c +++ b/drivers/platform/chrome/cros_ec_sensorhub.c @@ -224,8 +224,7 @@ static int cros_ec_sensorhub_probe(struct platform_device *pdev) */ static int cros_ec_sensorhub_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct cros_ec_sensorhub *sensorhub = platform_get_drvdata(pdev); + struct cros_ec_sensorhub *sensorhub = dev_get_drvdata(dev); struct cros_ec_dev *ec = sensorhub->ec; if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO)) @@ -235,8 +234,7 @@ static int cros_ec_sensorhub_suspend(struct device *dev) static int cros_ec_sensorhub_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct cros_ec_sensorhub *sensorhub = platform_get_drvdata(pdev); + struct cros_ec_sensorhub *sensorhub = dev_get_drvdata(dev); struct cros_ec_dev *ec = sensorhub->ec; if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO)) -- cgit From 0ba37e05c240c7b38e5a327a96f404798a8698ff Mon Sep 17 00:00:00 2001 From: William Cohen Date: Sun, 26 Sep 2021 20:51:15 -0400 Subject: perf annotate: Add riscv64 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds basic arch initialization and instruction associate support for the riscv64 CPU architecture. Example output: $ perf annotate --stdio2 Samples: 122K of event 'task-clock:u', 4000 Hz, Event count (approx.): 30637250000, [percent: local period] strcmp() /usr/lib64/libc-2.32.so Percent Disassembly of section .text: 0000000000069a30 : __GI_strcmp(): const unsigned char *s2 = (const unsigned char *) p2; unsigned char c1, c2; do { c1 = (unsigned char) *s1++; 37.30 lbu a5,0(a0) c2 = (unsigned char) *s2++; 1.23 addi a1,a1,1 c1 = (unsigned char) *s1++; 18.68 addi a0,a0,1 c2 = (unsigned char) *s2++; 1.37 lbu a4,-1(a1) if (c1 == '\0') 18.71 ↓ beqz a5,18 return c1 - c2; } Signed-off-by: William Cohen Cc: Albert Ou Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Palmer Dabbelt Cc: Paul Walmsley Cc: Peter Zijlstra Cc: linux-riscv@lists.infradead.org Link: http://lore.kernel.org/lkml/20210927005115.610264-1-wcohen@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/riscv64/annotate/instructions.c | 34 +++++++++++++++++++++++++ tools/perf/util/annotate.c | 5 ++++ 2 files changed, 39 insertions(+) create mode 100644 tools/perf/arch/riscv64/annotate/instructions.c diff --git a/tools/perf/arch/riscv64/annotate/instructions.c b/tools/perf/arch/riscv64/annotate/instructions.c new file mode 100644 index 000000000000..869a0eb28953 --- /dev/null +++ b/tools/perf/arch/riscv64/annotate/instructions.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0 + +static +struct ins_ops *riscv64__associate_ins_ops(struct arch *arch, const char *name) +{ + struct ins_ops *ops = NULL; + + if (!strncmp(name, "jal", 3) || + !strncmp(name, "jr", 2) || + !strncmp(name, "call", 4)) + ops = &call_ops; + else if (!strncmp(name, "ret", 3)) + ops = &ret_ops; + else if (name[0] == 'j' || name[0] == 'b') + ops = &jump_ops; + else + return NULL; + + arch__associate_ins_ops(arch, name, ops); + + return ops; +} + +static +int riscv64__annotate_init(struct arch *arch, char *cpuid __maybe_unused) +{ + if (!arch->initialized) { + arch->associate_instruction_ops = riscv64__associate_ins_ops; + arch->initialized = true; + arch->objdump.comment_char = '#'; + } + + return 0; +} diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index b55f35485e43..4bab2273303a 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -151,6 +151,7 @@ static int arch__associate_ins_ops(struct arch* arch, const char *name, struct i #include "arch/mips/annotate/instructions.c" #include "arch/x86/annotate/instructions.c" #include "arch/powerpc/annotate/instructions.c" +#include "arch/riscv64/annotate/instructions.c" #include "arch/s390/annotate/instructions.c" #include "arch/sparc/annotate/instructions.c" @@ -191,6 +192,10 @@ static struct arch architectures[] = { .name = "powerpc", .init = powerpc__annotate_init, }, + { + .name = "riscv64", + .init = riscv64__annotate_init, + }, { .name = "s390", .init = s390__annotate_init, -- cgit From e765f13ed126fe7e41d1a6e3c60d754cd6c2af93 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 22 Sep 2021 19:34:30 +0200 Subject: nvdimm/pmem: move dax_attribute_group from dax to pmem dax_attribute_group is only used by the pmem driver, and can avoid the completely pointless lookup by the disk name if moved there. This leaves just a single caller of dax_get_by_host, so move dax_get_by_host into the same ifdef block as that caller. Signed-off-by: Christoph Hellwig Reviewed-by: Dan Williams Link: https://lore.kernel.org/r/20210922173431.2454024-3-hch@lst.de Signed-off-by: Dan Williams --- drivers/dax/super.c | 100 +++++++++----------------------------------------- drivers/nvdimm/pmem.c | 43 ++++++++++++++++++++++ include/linux/dax.h | 2 - 3 files changed, 61 insertions(+), 84 deletions(-) diff --git a/drivers/dax/super.c b/drivers/dax/super.c index fc89e91beea7..b882cf8106ea 100644 --- a/drivers/dax/super.c +++ b/drivers/dax/super.c @@ -63,6 +63,24 @@ static int dax_host_hash(const char *host) return hashlen_hash(hashlen_string("DAX", host)) % DAX_HASH_SIZE; } +#ifdef CONFIG_BLOCK +#include + +int bdev_dax_pgoff(struct block_device *bdev, sector_t sector, size_t size, + pgoff_t *pgoff) +{ + sector_t start_sect = bdev ? get_start_sect(bdev) : 0; + phys_addr_t phys_off = (start_sect + sector) * 512; + + if (pgoff) + *pgoff = PHYS_PFN(phys_off); + if (phys_off % PAGE_SIZE || size % PAGE_SIZE) + return -EINVAL; + return 0; +} +EXPORT_SYMBOL(bdev_dax_pgoff); + +#if IS_ENABLED(CONFIG_FS_DAX) /** * dax_get_by_host() - temporary lookup mechanism for filesystem-dax * @host: alternate name for the device registered by a dax driver @@ -94,24 +112,6 @@ static struct dax_device *dax_get_by_host(const char *host) return found; } -#ifdef CONFIG_BLOCK -#include - -int bdev_dax_pgoff(struct block_device *bdev, sector_t sector, size_t size, - pgoff_t *pgoff) -{ - sector_t start_sect = bdev ? get_start_sect(bdev) : 0; - phys_addr_t phys_off = (start_sect + sector) * 512; - - if (pgoff) - *pgoff = PHYS_PFN(phys_off); - if (phys_off % PAGE_SIZE || size % PAGE_SIZE) - return -EINVAL; - return 0; -} -EXPORT_SYMBOL(bdev_dax_pgoff); - -#if IS_ENABLED(CONFIG_FS_DAX) struct dax_device *fs_dax_get_by_bdev(struct block_device *bdev) { if (!blk_queue_dax(bdev->bd_disk->queue)) @@ -231,70 +231,6 @@ enum dax_device_flags { DAXDEV_SYNC, }; -static ssize_t write_cache_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct dax_device *dax_dev = dax_get_by_host(dev_name(dev)); - ssize_t rc; - - WARN_ON_ONCE(!dax_dev); - if (!dax_dev) - return -ENXIO; - - rc = sprintf(buf, "%d\n", !!dax_write_cache_enabled(dax_dev)); - put_dax(dax_dev); - return rc; -} - -static ssize_t write_cache_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t len) -{ - bool write_cache; - int rc = strtobool(buf, &write_cache); - struct dax_device *dax_dev = dax_get_by_host(dev_name(dev)); - - WARN_ON_ONCE(!dax_dev); - if (!dax_dev) - return -ENXIO; - - if (rc) - len = rc; - else - dax_write_cache(dax_dev, write_cache); - - put_dax(dax_dev); - return len; -} -static DEVICE_ATTR_RW(write_cache); - -static umode_t dax_visible(struct kobject *kobj, struct attribute *a, int n) -{ - struct device *dev = container_of(kobj, typeof(*dev), kobj); - struct dax_device *dax_dev = dax_get_by_host(dev_name(dev)); - - WARN_ON_ONCE(!dax_dev); - if (!dax_dev) - return 0; - -#ifndef CONFIG_ARCH_HAS_PMEM_API - if (a == &dev_attr_write_cache.attr) - return 0; -#endif - return a->mode; -} - -static struct attribute *dax_attributes[] = { - &dev_attr_write_cache.attr, - NULL, -}; - -struct attribute_group dax_attribute_group = { - .name = "dax", - .attrs = dax_attributes, - .is_visible = dax_visible, -}; -EXPORT_SYMBOL_GPL(dax_attribute_group); - /** * dax_direct_access() - translate a device pgoff to an absolute pfn * @dax_dev: a dax_device instance representing the logical memory range diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index 72de88ff0d30..bccbc95f6d70 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -328,6 +328,49 @@ static const struct dax_operations pmem_dax_ops = { .zero_page_range = pmem_dax_zero_page_range, }; +static ssize_t write_cache_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pmem_device *pmem = dev_to_disk(dev)->private_data; + + return sprintf(buf, "%d\n", !!dax_write_cache_enabled(pmem->dax_dev)); +} + +static ssize_t write_cache_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct pmem_device *pmem = dev_to_disk(dev)->private_data; + bool write_cache; + int rc; + + rc = strtobool(buf, &write_cache); + if (rc) + return rc; + dax_write_cache(pmem->dax_dev, write_cache); + return len; +} +static DEVICE_ATTR_RW(write_cache); + +static umode_t dax_visible(struct kobject *kobj, struct attribute *a, int n) +{ +#ifndef CONFIG_ARCH_HAS_PMEM_API + if (a == &dev_attr_write_cache.attr) + return 0; +#endif + return a->mode; +} + +static struct attribute *dax_attributes[] = { + &dev_attr_write_cache.attr, + NULL, +}; + +static const struct attribute_group dax_attribute_group = { + .name = "dax", + .attrs = dax_attributes, + .is_visible = dax_visible, +}; + static const struct attribute_group *pmem_attribute_groups[] = { &dax_attribute_group, NULL, diff --git a/include/linux/dax.h b/include/linux/dax.h index 2619d94c308d..8623caa67388 100644 --- a/include/linux/dax.h +++ b/include/linux/dax.h @@ -38,8 +38,6 @@ struct dax_operations { int (*zero_page_range)(struct dax_device *, pgoff_t, size_t); }; -extern struct attribute_group dax_attribute_group; - #if IS_ENABLED(CONFIG_DAX) struct dax_device *alloc_dax(void *private, const char *host, const struct dax_operations *ops, unsigned long flags); -- cgit From 7b4d7894c65bd1e83b2f021d7944a46bdd64836a Mon Sep 17 00:00:00 2001 From: Deepak Kumar Singh Date: Tue, 31 Aug 2021 20:00:27 +0530 Subject: soc: qcom: aoss: Expose send for generic usecase Not all upcoming usecases will have an interface to allow the aoss driver to hook onto. Expose the send api and create a get function to enable drivers to send their own messages to aoss. Signed-off-by: Chris Lew Signed-off-by: Deepak Kumar Singh Reviewed-by: Stephen Boyd Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/1630420228-31075-2-git-send-email-deesin@codeaurora.org --- drivers/soc/qcom/qcom_aoss.c | 54 +++++++++++++++++++++++++++++++++++++- include/linux/soc/qcom/qcom_aoss.h | 38 +++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 include/linux/soc/qcom/qcom_aoss.h diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c index 536c3e4114fb..bb336cc8df6f 100644 --- a/drivers/soc/qcom/qcom_aoss.c +++ b/drivers/soc/qcom/qcom_aoss.c @@ -8,10 +8,12 @@ #include #include #include +#include #include #include #include #include +#include #define QMP_DESC_MAGIC 0x0 #define QMP_DESC_VERSION 0x4 @@ -223,11 +225,14 @@ static bool qmp_message_empty(struct qmp *qmp) * * Return: 0 on success, negative errno on failure */ -static int qmp_send(struct qmp *qmp, const void *data, size_t len) +int qmp_send(struct qmp *qmp, const void *data, size_t len) { long time_left; int ret; + if (WARN_ON(IS_ERR_OR_NULL(qmp) || !data)) + return -EINVAL; + if (WARN_ON(len + sizeof(u32) > qmp->size)) return -EINVAL; @@ -261,6 +266,7 @@ static int qmp_send(struct qmp *qmp, const void *data, size_t len) return ret; } +EXPORT_SYMBOL(qmp_send); static int qmp_qdss_clk_prepare(struct clk_hw *hw) { @@ -519,6 +525,51 @@ static void qmp_cooling_devices_remove(struct qmp *qmp) thermal_cooling_device_unregister(qmp->cooling_devs[i].cdev); } +/** + * qmp_get() - get a qmp handle from a device + * @dev: client device pointer + * + * Return: handle to qmp device on success, ERR_PTR() on failure + */ +struct qmp *qmp_get(struct device *dev) +{ + struct platform_device *pdev; + struct device_node *np; + struct qmp *qmp; + + if (!dev || !dev->of_node) + return ERR_PTR(-EINVAL); + + np = of_parse_phandle(dev->of_node, "qcom,qmp", 0); + if (!np) + return ERR_PTR(-ENODEV); + + pdev = of_find_device_by_node(np); + of_node_put(np); + if (!pdev) + return ERR_PTR(-EINVAL); + + qmp = platform_get_drvdata(pdev); + + return qmp ? qmp : ERR_PTR(-EPROBE_DEFER); +} +EXPORT_SYMBOL(qmp_get); + +/** + * qmp_put() - release a qmp handle + * @qmp: qmp handle obtained from qmp_get() + */ +void qmp_put(struct qmp *qmp) +{ + /* + * Match get_device() inside of_find_device_by_node() in + * qmp_get() + */ + if (!IS_ERR_OR_NULL(qmp)) + put_device(qmp->dev); +} +EXPORT_SYMBOL(qmp_put); + static int qmp_probe(struct platform_device *pdev) { struct resource *res; @@ -615,6 +666,7 @@ static struct platform_driver qmp_driver = { .driver = { .name = "qcom_aoss_qmp", .of_match_table = qmp_dt_match, + .suppress_bind_attrs = true, }, .probe = qmp_probe, .remove = qmp_remove, diff --git a/include/linux/soc/qcom/qcom_aoss.h b/include/linux/soc/qcom/qcom_aoss.h new file mode 100644 index 000000000000..3c2a82e606f8 --- /dev/null +++ b/include/linux/soc/qcom/qcom_aoss.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + */ + +#ifndef __QCOM_AOSS_H__ +#define __QCOM_AOSS_H__ + +#include +#include + +struct qmp; + +#if IS_ENABLED(CONFIG_QCOM_AOSS_QMP) + +int qmp_send(struct qmp *qmp, const void *data, size_t len); +struct qmp *qmp_get(struct device *dev); +void qmp_put(struct qmp *qmp); + +#else + +static inline int qmp_send(struct qmp *qmp, const void *data, size_t len) +{ + return -ENODEV; +} + +static inline struct qmp *qmp_get(struct device *dev) +{ + return ERR_PTR(-ENODEV); +} + +static inline void qmp_put(struct qmp *qmp) +{ +} + +#endif + +#endif -- cgit From e73c632b18a936b5489068d2418a58ea95b49469 Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Thu, 16 Sep 2021 19:29:19 +0530 Subject: dt-bindings: remoteproc: qcom: pas: Add QMP property The load state power-domain, used by the co-processors to notify the Always on Subsystem (AOSS) that a particular co-processor is up/down, suffers from the side-effect of changing states during suspend/resume. However the co-processors enter low-power modes independent to that of the application processor and their states are expected to remain unaltered across system suspend/resume cycles. To achieve this behavior let's drop the load state power-domain and replace them with the qmp property for all SoCs supporting low power mode signalling. Due to the current broken load state implementation, we can afford the binding breakage that ensues and the remoteproc functionality will remain the same when using newer kernels with older dtbs. Signed-off-by: Sibi Sankar Reviewed-by: Stephen Boyd Reviewed-by: Rob Herring Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/1631800770-371-3-git-send-email-sibis@codeaurora.org --- .../devicetree/bindings/remoteproc/qcom,adsp.yaml | 54 ++++++++++------------ 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml index 0c112f3264a9..ff265aa365de 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml @@ -93,6 +93,10 @@ properties: maxItems: 1 description: Reference to the reserved-memory for the Hexagon core + qcom,qmp: + $ref: /schemas/types.yaml#/definitions/phandle + description: Reference to the AOSS side-channel message RAM. + qcom,smem-states: $ref: /schemas/types.yaml#/definitions/phandle-array description: States used by the AP to signal the Hexagon core @@ -369,13 +373,11 @@ allOf: properties: power-domains: items: - - description: Load State power domain - description: CX power domain - description: MX power domain - description: MSS power domain power-domain-names: items: - - const: load_state - const: cx - const: mx - const: mss @@ -391,39 +393,16 @@ allOf: properties: power-domains: items: - - description: Load State power domain - description: CX power domain - power-domain-names: - items: - - const: load_state - - const: cx - if: properties: compatible: contains: enum: + - qcom,sdx55-mpss-pas - qcom,sm8150-mpss-pas - qcom,sm8350-mpss-pas - then: - properties: - power-domains: - items: - - description: Load State power domain - - description: CX power domain - - description: MSS power domain - power-domain-names: - items: - - const: load_state - - const: cx - - const: mss - - - if: - properties: - compatible: - contains: - enum: - - qcom,sdx55-mpss-pas then: properties: power-domains: @@ -451,12 +430,10 @@ allOf: properties: power-domains: items: - - description: Load State power domain - description: LCX power domain - description: LMX power domain power-domain-names: items: - - const: load_state - const: lcx - const: lmx @@ -470,12 +447,10 @@ allOf: properties: power-domains: items: - - description: Load State power domain - description: CX power domain - description: MXC power domain power-domain-names: items: - - const: load_state - const: cx - const: mxc @@ -511,6 +486,25 @@ allOf: - const: mss_restart - const: pdc_reset + - if: + properties: + compatible: + contains: + enum: + - qcom,msm8974-adsp-pil + - qcom,msm8996-adsp-pil + - qcom,msm8996-slpi-pil + - qcom,msm8998-adsp-pas + - qcom,msm8998-slpi-pas + - qcom,qcs404-adsp-pas + - qcom,qcs404-cdsp-pas + - qcom,qcs404-wcss-pas + - qcom,sdm660-adsp-pas + - qcom,sdx55-mpss-pas + then: + properties: + qcom,qmp: false + examples: - | #include -- cgit From 8443ef7b5771830bc86c9e2c1622b55ddf33f0f5 Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Thu, 16 Sep 2021 19:29:20 +0530 Subject: dt-bindings: remoteproc: qcom: Add QMP property Add Qualcomm Mailbox Protocol (QMP) property to replace the power domain exposed by the AOSS QMP node. Signed-off-by: Sibi Sankar Reviewed-by: Stephen Boyd Acked-by: Rob Herring Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/1631800770-371-4-git-send-email-sibis@codeaurora.org --- Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt b/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt index 69c49c7b2cff..494257010629 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt +++ b/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt @@ -174,7 +174,12 @@ For the compatible string below the following supplies are required: must be "cx", "mx" qcom,sc7180-mss-pil: qcom,sdm845-mss-pil: - must be "cx", "mx", "mss", "load_state" + must be "cx", "mx", "mss" + +- qcom,qmp: + Usage: optional + Value type: + Definition: reference to the AOSS side-channel message RAM. - qcom,smem-states: Usage: required -- cgit From c1fe10d238c0256a77dbc4bf6493b9782b2a218d Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Thu, 16 Sep 2021 19:29:21 +0530 Subject: remoteproc: qcom: q6v5: Use qmp_send to update co-processor load state The power domains exposed by the AOSS QMP driver control the load state resources linked to modem, adsp, cdsp remoteprocs. These are used to notify the Always on Subsystem (AOSS) that a particular co-processor is up/down. AOSS uses this information to wait for the co-processors to suspend before starting its sleep sequence. These co-processors enter low-power modes independent to that of the application processor and the load state resources linked to them are expected to remain unaltered across system suspend/resume cycles. To achieve this behavior lets stop using the power-domains exposed by the AOSS QMP node and replace them with generic qmp_send interface instead. Signed-off-by: Sibi Sankar Reviewed-by: Stephen Boyd [bjorn: Fixed up build error in q6v5_wcss_remove()] Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/1631800770-371-5-git-send-email-sibis@codeaurora.org --- drivers/remoteproc/qcom_q6v5.c | 57 +++++++++++++++++- drivers/remoteproc/qcom_q6v5.h | 7 ++- drivers/remoteproc/qcom_q6v5_adsp.c | 7 ++- drivers/remoteproc/qcom_q6v5_mss.c | 44 +++----------- drivers/remoteproc/qcom_q6v5_pas.c | 113 ++++++++++++++---------------------- drivers/remoteproc/qcom_q6v5_wcss.c | 5 +- 6 files changed, 123 insertions(+), 110 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c index 7e9244c748da..eada7e34f3af 100644 --- a/drivers/remoteproc/qcom_q6v5.c +++ b/drivers/remoteproc/qcom_q6v5.c @@ -16,8 +16,30 @@ #include "qcom_common.h" #include "qcom_q6v5.h" +#define Q6V5_LOAD_STATE_MSG_LEN 64 #define Q6V5_PANIC_DELAY_MS 200 +static int q6v5_load_state_toggle(struct qcom_q6v5 *q6v5, bool enable) +{ + char buf[Q6V5_LOAD_STATE_MSG_LEN]; + int ret; + + if (!q6v5->qmp) + return 0; + + ret = snprintf(buf, sizeof(buf), + "{class: image, res: load_state, name: %s, val: %s}", + q6v5->load_state, enable ? "on" : "off"); + + WARN_ON(ret >= Q6V5_LOAD_STATE_MSG_LEN); + + ret = qmp_send(q6v5->qmp, buf, sizeof(buf)); + if (ret) + dev_err(q6v5->dev, "failed to toggle load state\n"); + + return ret; +} + /** * qcom_q6v5_prepare() - reinitialize the qcom_q6v5 context before start * @q6v5: reference to qcom_q6v5 context to be reinitialized @@ -26,6 +48,12 @@ */ int qcom_q6v5_prepare(struct qcom_q6v5 *q6v5) { + int ret; + + ret = q6v5_load_state_toggle(q6v5, true); + if (ret) + return ret; + reinit_completion(&q6v5->start_done); reinit_completion(&q6v5->stop_done); @@ -47,6 +75,7 @@ EXPORT_SYMBOL_GPL(qcom_q6v5_prepare); int qcom_q6v5_unprepare(struct qcom_q6v5 *q6v5) { disable_irq(q6v5->handover_irq); + q6v5_load_state_toggle(q6v5, false); return !q6v5->handover_issued; } @@ -196,12 +225,13 @@ EXPORT_SYMBOL_GPL(qcom_q6v5_panic); * @pdev: platform_device reference for acquiring resources * @rproc: associated remoteproc instance * @crash_reason: SMEM id for crash reason string, or 0 if none + * @load_state: load state resource string * @handover: function to be called when proxy resources should be released * * Return: 0 on success, negative errno on failure */ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev, - struct rproc *rproc, int crash_reason, + struct rproc *rproc, int crash_reason, const char *load_state, void (*handover)(struct qcom_q6v5 *q6v5)) { int ret; @@ -286,9 +316,34 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev, return PTR_ERR(q6v5->state); } + q6v5->load_state = devm_kstrdup_const(&pdev->dev, load_state, GFP_KERNEL); + q6v5->qmp = qmp_get(&pdev->dev); + if (IS_ERR(q6v5->qmp)) { + if (PTR_ERR(q6v5->qmp) != -ENODEV) + return dev_err_probe(&pdev->dev, PTR_ERR(q6v5->qmp), + "failed to acquire load state\n"); + q6v5->qmp = NULL; + } else if (!q6v5->load_state) { + if (!load_state) + dev_err(&pdev->dev, "load state resource string empty\n"); + + qmp_put(q6v5->qmp); + return load_state ? -ENOMEM : -EINVAL; + } + return 0; } EXPORT_SYMBOL_GPL(qcom_q6v5_init); +/** + * qcom_q6v5_deinit() - deinitialize the q6v5 common struct + * @q6v5: reference to qcom_q6v5 context to be deinitialized + */ +void qcom_q6v5_deinit(struct qcom_q6v5 *q6v5) +{ + qmp_put(q6v5->qmp); +} +EXPORT_SYMBOL_GPL(qcom_q6v5_deinit); + MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Qualcomm Peripheral Image Loader for Q6V5"); diff --git a/drivers/remoteproc/qcom_q6v5.h b/drivers/remoteproc/qcom_q6v5.h index 1c212f670cbc..f35e04471ed7 100644 --- a/drivers/remoteproc/qcom_q6v5.h +++ b/drivers/remoteproc/qcom_q6v5.h @@ -5,6 +5,7 @@ #include #include +#include struct rproc; struct qcom_smem_state; @@ -15,6 +16,8 @@ struct qcom_q6v5 { struct rproc *rproc; struct qcom_smem_state *state; + struct qmp *qmp; + unsigned stop_bit; int wdog_irq; @@ -32,12 +35,14 @@ struct qcom_q6v5 { bool running; + const char *load_state; void (*handover)(struct qcom_q6v5 *q6v5); }; int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev, - struct rproc *rproc, int crash_reason, + struct rproc *rproc, int crash_reason, const char *load_state, void (*handover)(struct qcom_q6v5 *q6v5)); +void qcom_q6v5_deinit(struct qcom_q6v5 *q6v5); int qcom_q6v5_prepare(struct qcom_q6v5 *q6v5); int qcom_q6v5_unprepare(struct qcom_q6v5 *q6v5); diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c index 8b0d8bbacd2e..098362e6e233 100644 --- a/drivers/remoteproc/qcom_q6v5_adsp.c +++ b/drivers/remoteproc/qcom_q6v5_adsp.c @@ -185,7 +185,9 @@ static int adsp_start(struct rproc *rproc) int ret; unsigned int val; - qcom_q6v5_prepare(&adsp->q6v5); + ret = qcom_q6v5_prepare(&adsp->q6v5); + if (ret) + return ret; ret = clk_prepare_enable(adsp->xo); if (ret) @@ -465,7 +467,7 @@ static int adsp_probe(struct platform_device *pdev) if (ret) goto disable_pm; - ret = qcom_q6v5_init(&adsp->q6v5, pdev, rproc, desc->crash_reason_smem, + ret = qcom_q6v5_init(&adsp->q6v5, pdev, rproc, desc->crash_reason_smem, NULL, qcom_adsp_pil_handover); if (ret) goto disable_pm; @@ -500,6 +502,7 @@ static int adsp_remove(struct platform_device *pdev) rproc_del(adsp->rproc); + qcom_q6v5_deinit(&adsp->q6v5); qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev); qcom_remove_sysmon_subdev(adsp->sysmon); qcom_remove_ssr_subdev(adsp->rproc, &adsp->ssr_subdev); diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 423b31dfa574..7a1422bd7925 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -137,7 +137,6 @@ struct rproc_hexagon_res { char **proxy_clk_names; char **reset_clk_names; char **active_clk_names; - char **active_pd_names; char **proxy_pd_names; int version; bool need_mem_protection; @@ -169,12 +168,10 @@ struct q6v5 { struct clk *active_clks[8]; struct clk *reset_clks[4]; struct clk *proxy_clks[4]; - struct device *active_pds[1]; struct device *proxy_pds[3]; int active_clk_count; int reset_clk_count; int proxy_clk_count; - int active_pd_count; int proxy_pd_count; struct reg_info active_regs[1]; @@ -895,18 +892,14 @@ static int q6v5_mba_load(struct q6v5 *qproc) int xfermemop_ret; bool mba_load_err = false; - qcom_q6v5_prepare(&qproc->q6v5); - - ret = q6v5_pds_enable(qproc, qproc->active_pds, qproc->active_pd_count); - if (ret < 0) { - dev_err(qproc->dev, "failed to enable active power domains\n"); - goto disable_irqs; - } + ret = qcom_q6v5_prepare(&qproc->q6v5); + if (ret) + return ret; ret = q6v5_pds_enable(qproc, qproc->proxy_pds, qproc->proxy_pd_count); if (ret < 0) { dev_err(qproc->dev, "failed to enable proxy power domains\n"); - goto disable_active_pds; + goto disable_irqs; } ret = q6v5_regulator_enable(qproc, qproc->fallback_proxy_regs, @@ -1039,8 +1032,6 @@ disable_fallback_proxy_reg: qproc->fallback_proxy_reg_count); disable_proxy_pds: q6v5_pds_disable(qproc, qproc->proxy_pds, qproc->proxy_pd_count); -disable_active_pds: - q6v5_pds_disable(qproc, qproc->active_pds, qproc->active_pd_count); disable_irqs: qcom_q6v5_unprepare(&qproc->q6v5); @@ -1076,7 +1067,6 @@ static void q6v5_mba_reclaim(struct q6v5 *qproc) qproc->active_clk_count); q6v5_regulator_disable(qproc, qproc->active_regs, qproc->active_reg_count); - q6v5_pds_disable(qproc, qproc->active_pds, qproc->active_pd_count); /* In case of failure or coredump scenario where reclaiming MBA memory * could not happen reclaim it here. @@ -1756,14 +1746,6 @@ static int q6v5_probe(struct platform_device *pdev) } qproc->active_reg_count = ret; - ret = q6v5_pds_attach(&pdev->dev, qproc->active_pds, - desc->active_pd_names); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to attach active power domains\n"); - goto free_rproc; - } - qproc->active_pd_count = ret; - ret = q6v5_pds_attach(&pdev->dev, qproc->proxy_pds, desc->proxy_pd_names); /* Fallback to regulators for old device trees */ @@ -1773,12 +1755,12 @@ static int q6v5_probe(struct platform_device *pdev) desc->fallback_proxy_supply); if (ret < 0) { dev_err(&pdev->dev, "Failed to get fallback proxy regulators.\n"); - goto detach_active_pds; + goto free_rproc; } qproc->fallback_proxy_reg_count = ret; } else if (ret < 0) { dev_err(&pdev->dev, "Failed to init power domains\n"); - goto detach_active_pds; + goto free_rproc; } else { qproc->proxy_pd_count = ret; } @@ -1792,7 +1774,7 @@ static int q6v5_probe(struct platform_device *pdev) qproc->need_mem_protection = desc->need_mem_protection; qproc->has_mba_logs = desc->has_mba_logs; - ret = qcom_q6v5_init(&qproc->q6v5, pdev, rproc, MPSS_CRASH_REASON_SMEM, + ret = qcom_q6v5_init(&qproc->q6v5, pdev, rproc, MPSS_CRASH_REASON_SMEM, "modem", qcom_msa_handover); if (ret) goto detach_proxy_pds; @@ -1822,8 +1804,6 @@ remove_subdevs: qcom_remove_glink_subdev(rproc, &qproc->glink_subdev); detach_proxy_pds: q6v5_pds_detach(qproc, qproc->proxy_pds, qproc->proxy_pd_count); -detach_active_pds: - q6v5_pds_detach(qproc, qproc->active_pds, qproc->active_pd_count); free_rproc: rproc_free(rproc); @@ -1837,13 +1817,13 @@ static int q6v5_remove(struct platform_device *pdev) rproc_del(rproc); + qcom_q6v5_deinit(&qproc->q6v5); qcom_remove_sysmon_subdev(qproc->sysmon); qcom_remove_ssr_subdev(rproc, &qproc->ssr_subdev); qcom_remove_smd_subdev(rproc, &qproc->smd_subdev); qcom_remove_glink_subdev(rproc, &qproc->glink_subdev); q6v5_pds_detach(qproc, qproc->proxy_pds, qproc->proxy_pd_count); - q6v5_pds_detach(qproc, qproc->active_pds, qproc->active_pd_count); rproc_free(rproc); @@ -1867,10 +1847,6 @@ static const struct rproc_hexagon_res sc7180_mss = { "nav", NULL }, - .active_pd_names = (char*[]){ - "load_state", - NULL - }, .proxy_pd_names = (char*[]){ "cx", "mx", @@ -1903,10 +1879,6 @@ static const struct rproc_hexagon_res sdm845_mss = { "mnoc_axi", NULL }, - .active_pd_names = (char*[]){ - "load_state", - NULL - }, .proxy_pd_names = (char*[]){ "cx", "mx", diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 401b1ec90785..8da0362d3d85 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -37,9 +37,9 @@ struct adsp_data { bool has_aggre2_clk; bool auto_boot; - char **active_pd_names; char **proxy_pd_names; + const char *load_state; const char *ssr_name; const char *sysmon_name; int ssctl_id; @@ -57,10 +57,8 @@ struct qcom_adsp { struct regulator *cx_supply; struct regulator *px_supply; - struct device *active_pds[1]; struct device *proxy_pds[3]; - int active_pd_count; int proxy_pd_count; int pas_id; @@ -149,15 +147,13 @@ static int adsp_start(struct rproc *rproc) struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv; int ret; - qcom_q6v5_prepare(&adsp->q6v5); - - ret = adsp_pds_enable(adsp, adsp->active_pds, adsp->active_pd_count); - if (ret < 0) - goto disable_irqs; + ret = qcom_q6v5_prepare(&adsp->q6v5); + if (ret) + return ret; ret = adsp_pds_enable(adsp, adsp->proxy_pds, adsp->proxy_pd_count); if (ret < 0) - goto disable_active_pds; + goto disable_irqs; ret = clk_prepare_enable(adsp->xo); if (ret) @@ -201,8 +197,6 @@ disable_xo_clk: clk_disable_unprepare(adsp->xo); disable_proxy_pds: adsp_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count); -disable_active_pds: - adsp_pds_disable(adsp, adsp->active_pds, adsp->active_pd_count); disable_irqs: qcom_q6v5_unprepare(&adsp->q6v5); @@ -234,7 +228,6 @@ static int adsp_stop(struct rproc *rproc) if (ret) dev_err(adsp->dev, "failed to shutdown: %d\n", ret); - adsp_pds_disable(adsp, adsp->active_pds, adsp->active_pd_count); handover = qcom_q6v5_unprepare(&adsp->q6v5); if (handover) qcom_pas_handover(&adsp->q6v5); @@ -456,19 +449,13 @@ static int adsp_probe(struct platform_device *pdev) if (ret) goto free_rproc; - ret = adsp_pds_attach(&pdev->dev, adsp->active_pds, - desc->active_pd_names); - if (ret < 0) - goto free_rproc; - adsp->active_pd_count = ret; - ret = adsp_pds_attach(&pdev->dev, adsp->proxy_pds, desc->proxy_pd_names); if (ret < 0) - goto detach_active_pds; + goto free_rproc; adsp->proxy_pd_count = ret; - ret = qcom_q6v5_init(&adsp->q6v5, pdev, rproc, desc->crash_reason_smem, + ret = qcom_q6v5_init(&adsp->q6v5, pdev, rproc, desc->crash_reason_smem, desc->load_state, qcom_pas_handover); if (ret) goto detach_proxy_pds; @@ -492,8 +479,6 @@ static int adsp_probe(struct platform_device *pdev) detach_proxy_pds: adsp_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count); -detach_active_pds: - adsp_pds_detach(adsp, adsp->active_pds, adsp->active_pd_count); free_rproc: rproc_free(rproc); @@ -506,6 +491,7 @@ static int adsp_remove(struct platform_device *pdev) rproc_del(adsp->rproc); + qcom_q6v5_deinit(&adsp->q6v5); qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev); qcom_remove_sysmon_subdev(adsp->sysmon); qcom_remove_smd_subdev(adsp->rproc, &adsp->smd_subdev); @@ -526,20 +512,29 @@ static const struct adsp_data adsp_resource_init = { .ssctl_id = 0x14, }; +static const struct adsp_data sdm845_adsp_resource_init = { + .crash_reason_smem = 423, + .firmware_name = "adsp.mdt", + .pas_id = 1, + .has_aggre2_clk = false, + .auto_boot = true, + .load_state = "adsp", + .ssr_name = "lpass", + .sysmon_name = "adsp", + .ssctl_id = 0x14, +}; + static const struct adsp_data sm8150_adsp_resource = { .crash_reason_smem = 423, .firmware_name = "adsp.mdt", .pas_id = 1, .has_aggre2_clk = false, .auto_boot = true, - .active_pd_names = (char*[]){ - "load_state", - NULL - }, .proxy_pd_names = (char*[]){ "cx", NULL }, + .load_state = "adsp", .ssr_name = "lpass", .sysmon_name = "adsp", .ssctl_id = 0x14, @@ -551,15 +546,12 @@ static const struct adsp_data sm8250_adsp_resource = { .pas_id = 1, .has_aggre2_clk = false, .auto_boot = true, - .active_pd_names = (char*[]){ - "load_state", - NULL - }, .proxy_pd_names = (char*[]){ "lcx", "lmx", NULL }, + .load_state = "adsp", .ssr_name = "lpass", .sysmon_name = "adsp", .ssctl_id = 0x14, @@ -571,15 +563,12 @@ static const struct adsp_data sm8350_adsp_resource = { .pas_id = 1, .has_aggre2_clk = false, .auto_boot = true, - .active_pd_names = (char*[]){ - "load_state", - NULL - }, .proxy_pd_names = (char*[]){ "lcx", "lmx", NULL }, + .load_state = "adsp", .ssr_name = "lpass", .sysmon_name = "adsp", .ssctl_id = 0x14, @@ -611,20 +600,29 @@ static const struct adsp_data cdsp_resource_init = { .ssctl_id = 0x17, }; +static const struct adsp_data sdm845_cdsp_resource_init = { + .crash_reason_smem = 601, + .firmware_name = "cdsp.mdt", + .pas_id = 18, + .has_aggre2_clk = false, + .auto_boot = true, + .load_state = "cdsp", + .ssr_name = "cdsp", + .sysmon_name = "cdsp", + .ssctl_id = 0x17, +}; + static const struct adsp_data sm8150_cdsp_resource = { .crash_reason_smem = 601, .firmware_name = "cdsp.mdt", .pas_id = 18, .has_aggre2_clk = false, .auto_boot = true, - .active_pd_names = (char*[]){ - "load_state", - NULL - }, .proxy_pd_names = (char*[]){ "cx", NULL }, + .load_state = "cdsp", .ssr_name = "cdsp", .sysmon_name = "cdsp", .ssctl_id = 0x17, @@ -636,14 +634,11 @@ static const struct adsp_data sm8250_cdsp_resource = { .pas_id = 18, .has_aggre2_clk = false, .auto_boot = true, - .active_pd_names = (char*[]){ - "load_state", - NULL - }, .proxy_pd_names = (char*[]){ "cx", NULL }, + .load_state = "cdsp", .ssr_name = "cdsp", .sysmon_name = "cdsp", .ssctl_id = 0x17, @@ -655,14 +650,11 @@ static const struct adsp_data sm8350_cdsp_resource = { .pas_id = 18, .has_aggre2_clk = false, .auto_boot = true, - .active_pd_names = (char*[]){ - "load_state", - NULL - }, .proxy_pd_names = (char*[]){ "cx", NULL }, + .load_state = "cdsp", .ssr_name = "cdsp", .sysmon_name = "cdsp", .ssctl_id = 0x17, @@ -675,15 +667,12 @@ static const struct adsp_data mpss_resource_init = { .minidump_id = 3, .has_aggre2_clk = false, .auto_boot = false, - .active_pd_names = (char*[]){ - "load_state", - NULL - }, .proxy_pd_names = (char*[]){ "cx", "mss", NULL }, + .load_state = "modem", .ssr_name = "mpss", .sysmon_name = "modem", .ssctl_id = 0x12, @@ -695,14 +684,11 @@ static const struct adsp_data sc8180x_mpss_resource = { .pas_id = 4, .has_aggre2_clk = false, .auto_boot = false, - .active_pd_names = (char*[]){ - "load_state", - NULL - }, .proxy_pd_names = (char*[]){ "cx", NULL }, + .load_state = "modem", .ssr_name = "mpss", .sysmon_name = "modem", .ssctl_id = 0x12, @@ -725,15 +711,12 @@ static const struct adsp_data sm8150_slpi_resource = { .pas_id = 12, .has_aggre2_clk = false, .auto_boot = true, - .active_pd_names = (char*[]){ - "load_state", - NULL - }, .proxy_pd_names = (char*[]){ "lcx", "lmx", NULL }, + .load_state = "slpi", .ssr_name = "dsps", .sysmon_name = "slpi", .ssctl_id = 0x16, @@ -745,15 +728,12 @@ static const struct adsp_data sm8250_slpi_resource = { .pas_id = 12, .has_aggre2_clk = false, .auto_boot = true, - .active_pd_names = (char*[]){ - "load_state", - NULL - }, .proxy_pd_names = (char*[]){ "lcx", "lmx", NULL }, + .load_state = "slpi", .ssr_name = "dsps", .sysmon_name = "slpi", .ssctl_id = 0x16, @@ -765,15 +745,12 @@ static const struct adsp_data sm8350_slpi_resource = { .pas_id = 12, .has_aggre2_clk = false, .auto_boot = true, - .active_pd_names = (char*[]){ - "load_state", - NULL - }, .proxy_pd_names = (char*[]){ "lcx", "lmx", NULL }, + .load_state = "slpi", .ssr_name = "dsps", .sysmon_name = "slpi", .ssctl_id = 0x16, @@ -834,8 +811,8 @@ static const struct of_device_id adsp_of_match[] = { { .compatible = "qcom,sc8180x-cdsp-pas", .data = &sm8150_cdsp_resource}, { .compatible = "qcom,sc8180x-mpss-pas", .data = &sc8180x_mpss_resource}, { .compatible = "qcom,sdm660-adsp-pas", .data = &adsp_resource_init}, - { .compatible = "qcom,sdm845-adsp-pas", .data = &adsp_resource_init}, - { .compatible = "qcom,sdm845-cdsp-pas", .data = &cdsp_resource_init}, + { .compatible = "qcom,sdm845-adsp-pas", .data = &sdm845_adsp_resource_init}, + { .compatible = "qcom,sdm845-cdsp-pas", .data = &sdm845_cdsp_resource_init}, { .compatible = "qcom,sdx55-mpss-pas", .data = &sdx55_mpss_resource}, { .compatible = "qcom,sm8150-adsp-pas", .data = &sm8150_adsp_resource}, { .compatible = "qcom,sm8150-cdsp-pas", .data = &sm8150_cdsp_resource}, diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c index 20d50ec7eff1..bb0947f7770e 100644 --- a/drivers/remoteproc/qcom_q6v5_wcss.c +++ b/drivers/remoteproc/qcom_q6v5_wcss.c @@ -1044,8 +1044,7 @@ static int q6v5_wcss_probe(struct platform_device *pdev) if (ret) goto free_rproc; - ret = qcom_q6v5_init(&wcss->q6v5, pdev, rproc, desc->crash_reason_smem, - NULL); + ret = qcom_q6v5_init(&wcss->q6v5, pdev, rproc, desc->crash_reason_smem, NULL, NULL); if (ret) goto free_rproc; @@ -1074,7 +1073,9 @@ free_rproc: static int q6v5_wcss_remove(struct platform_device *pdev) { struct rproc *rproc = platform_get_drvdata(pdev); + struct q6v5_wcss *wcss = rproc->priv; + qcom_q6v5_deinit(&wcss->q6v5); rproc_del(rproc); rproc_free(rproc); -- cgit From 54c9237a97e00e506ed18e89b12690a9ddfe4a56 Mon Sep 17 00:00:00 2001 From: Tinghan Shen Date: Fri, 24 Sep 2021 11:39:34 +0800 Subject: rpmsg: Change naming of mediatek rpmsg property Change from "mtk,rpmsg-name" to "mediatek,rpmsg-name" to sync with the vendor name defined in vendor-prefixes.yaml. Signed-off-by: Tinghan Shen Link: https://lore.kernel.org/r/20210924033935.2127-6-tinghan.shen@mediatek.com [Fixed capital letter in title] Signed-off-by: Mathieu Poirier Signed-off-by: Bjorn Andersson --- drivers/rpmsg/mtk_rpmsg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rpmsg/mtk_rpmsg.c b/drivers/rpmsg/mtk_rpmsg.c index 96a17ec29140..5b4404b8be4c 100644 --- a/drivers/rpmsg/mtk_rpmsg.c +++ b/drivers/rpmsg/mtk_rpmsg.c @@ -183,7 +183,7 @@ mtk_rpmsg_match_device_subnode(struct device_node *node, const char *channel) int ret; for_each_available_child_of_node(node, child) { - ret = of_property_read_string(child, "mtk,rpmsg-name", &name); + ret = of_property_read_string(child, "mediatek,rpmsg-name", &name); if (ret) continue; -- cgit From 24acbd9dc934f5d9418a736c532d3970a272063e Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 10 Sep 2021 17:06:16 +0800 Subject: remoteproc: elf_loader: Fix loading segment when is_iomem true It seems luckliy work on i.MX platform, but it is wrong. Need use memcpy_toio, not memcpy_fromio. Fixes: 40df0a91b2a5 ("remoteproc: add is_iomem to da_to_va") Tested-by: Dong Aisheng (i.MX8MQ) Reported-by: kernel test robot Reported-by: Dong Aisheng Signed-off-by: Peng Fan Cc: stable Link: https://lore.kernel.org/r/20210910090621.3073540-2-peng.fan@oss.nxp.com Signed-off-by: Mathieu Poirier Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_elf_loader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c index 469c52e62faf..44e7f9308f4b 100644 --- a/drivers/remoteproc/remoteproc_elf_loader.c +++ b/drivers/remoteproc/remoteproc_elf_loader.c @@ -220,7 +220,7 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw) /* put the segment where the remote processor expects it */ if (filesz) { if (is_iomem) - memcpy_fromio(ptr, (void __iomem *)(elf_data + offset), filesz); + memcpy_toio((void __iomem *)ptr, elf_data + offset, filesz); else memcpy(ptr, elf_data + offset, filesz); } -- cgit From 970675f61bf5761d7e5326f6e4df995ecdba5e11 Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Fri, 10 Sep 2021 17:06:17 +0800 Subject: remoteproc: Fix the wrong default value of is_iomem Currently the is_iomem is a random value in the stack which may be default to true even on those platforms that not use iomem to store firmware. Cc: Bjorn Andersson Cc: Mathieu Poirier Fixes: 40df0a91b2a5 ("remoteproc: add is_iomem to da_to_va") Reviewed-and-tested-by: Peng Fan Signed-off-by: Dong Aisheng Signed-off-by: Peng Fan Cc: stable Link: https://lore.kernel.org/r/20210910090621.3073540-3-peng.fan@oss.nxp.com Signed-off-by: Mathieu Poirier Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_coredump.c | 2 +- drivers/remoteproc/remoteproc_elf_loader.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/remoteproc/remoteproc_coredump.c b/drivers/remoteproc/remoteproc_coredump.c index aee657cc08c6..c892f433a323 100644 --- a/drivers/remoteproc/remoteproc_coredump.c +++ b/drivers/remoteproc/remoteproc_coredump.c @@ -152,8 +152,8 @@ static void rproc_copy_segment(struct rproc *rproc, void *dest, struct rproc_dump_segment *segment, size_t offset, size_t size) { + bool is_iomem = false; void *ptr; - bool is_iomem; if (segment->dump) { segment->dump(rproc, segment, dest, offset, size); diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c index 44e7f9308f4b..d635d19a5aa8 100644 --- a/drivers/remoteproc/remoteproc_elf_loader.c +++ b/drivers/remoteproc/remoteproc_elf_loader.c @@ -178,8 +178,8 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw) u64 filesz = elf_phdr_get_p_filesz(class, phdr); u64 offset = elf_phdr_get_p_offset(class, phdr); u32 type = elf_phdr_get_p_type(class, phdr); + bool is_iomem = false; void *ptr; - bool is_iomem; if (type != PT_LOAD) continue; -- cgit From 91bb26637353f35241f5472eedf3202ebe13e2e5 Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Fri, 10 Sep 2021 17:06:18 +0800 Subject: remoteproc: imx_rproc: Fix TCM io memory type is_iomem was introduced in the commit 40df0a91b2a5 ("remoteproc: add is_iomem to da_to_va"), but the driver seemed missed to provide the io type correctly. This patch updates remoteproc driver to indicate the TCM on IMX are io memories. Without the change, remoteproc kick will fail. Cc: Bjorn Andersson Cc: Mathieu Poirier Cc: Peng Fan Reviewed-and-tested-by: Peng Fan Fixes: 79806d32d5aa ("remoteproc: imx_rproc: support i.MX8MN/P") Signed-off-by: Dong Aisheng Signed-off-by: Peng Fan stable Link: https://lore.kernel.org/r/20210910090621.3073540-4-peng.fan@oss.nxp.com Signed-off-by: Mathieu Poirier Signed-off-by: Bjorn Andersson --- drivers/remoteproc/imx_rproc.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index d88f76f5305e..71dcc6dd32e4 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -71,6 +71,7 @@ struct imx_rproc_mem { /* att flags */ /* M4 own area. Can be mapped at probe */ #define ATT_OWN BIT(1) +#define ATT_IOMEM BIT(2) /* address translation table */ struct imx_rproc_att { @@ -117,7 +118,7 @@ struct imx_rproc { static const struct imx_rproc_att imx_rproc_att_imx8mn[] = { /* dev addr , sys addr , size , flags */ /* ITCM */ - { 0x00000000, 0x007E0000, 0x00020000, ATT_OWN }, + { 0x00000000, 0x007E0000, 0x00020000, ATT_OWN | ATT_IOMEM }, /* OCRAM_S */ { 0x00180000, 0x00180000, 0x00009000, 0 }, /* OCRAM */ @@ -131,7 +132,7 @@ static const struct imx_rproc_att imx_rproc_att_imx8mn[] = { /* DDR (Code) - alias */ { 0x10000000, 0x40000000, 0x0FFE0000, 0 }, /* DTCM */ - { 0x20000000, 0x00800000, 0x00020000, ATT_OWN }, + { 0x20000000, 0x00800000, 0x00020000, ATT_OWN | ATT_IOMEM }, /* OCRAM_S - alias */ { 0x20180000, 0x00180000, 0x00008000, ATT_OWN }, /* OCRAM */ @@ -147,7 +148,7 @@ static const struct imx_rproc_att imx_rproc_att_imx8mn[] = { static const struct imx_rproc_att imx_rproc_att_imx8mq[] = { /* dev addr , sys addr , size , flags */ /* TCML - alias */ - { 0x00000000, 0x007e0000, 0x00020000, 0 }, + { 0x00000000, 0x007e0000, 0x00020000, ATT_IOMEM}, /* OCRAM_S */ { 0x00180000, 0x00180000, 0x00008000, 0 }, /* OCRAM */ @@ -159,9 +160,9 @@ static const struct imx_rproc_att imx_rproc_att_imx8mq[] = { /* DDR (Code) - alias */ { 0x10000000, 0x80000000, 0x0FFE0000, 0 }, /* TCML */ - { 0x1FFE0000, 0x007E0000, 0x00020000, ATT_OWN }, + { 0x1FFE0000, 0x007E0000, 0x00020000, ATT_OWN | ATT_IOMEM}, /* TCMU */ - { 0x20000000, 0x00800000, 0x00020000, ATT_OWN }, + { 0x20000000, 0x00800000, 0x00020000, ATT_OWN | ATT_IOMEM}, /* OCRAM_S */ { 0x20180000, 0x00180000, 0x00008000, ATT_OWN }, /* OCRAM */ @@ -199,12 +200,12 @@ static const struct imx_rproc_att imx_rproc_att_imx7d[] = { /* OCRAM_PXP (Code) - alias */ { 0x00940000, 0x00940000, 0x00008000, 0 }, /* TCML (Code) */ - { 0x1FFF8000, 0x007F8000, 0x00008000, ATT_OWN }, + { 0x1FFF8000, 0x007F8000, 0x00008000, ATT_OWN | ATT_IOMEM }, /* DDR (Code) - alias, first part of DDR (Data) */ { 0x10000000, 0x80000000, 0x0FFF0000, 0 }, /* TCMU (Data) */ - { 0x20000000, 0x00800000, 0x00008000, ATT_OWN }, + { 0x20000000, 0x00800000, 0x00008000, ATT_OWN | ATT_IOMEM }, /* OCRAM (Data) */ { 0x20200000, 0x00900000, 0x00020000, 0 }, /* OCRAM_EPDC (Data) */ @@ -218,18 +219,18 @@ static const struct imx_rproc_att imx_rproc_att_imx7d[] = { static const struct imx_rproc_att imx_rproc_att_imx6sx[] = { /* dev addr , sys addr , size , flags */ /* TCML (M4 Boot Code) - alias */ - { 0x00000000, 0x007F8000, 0x00008000, 0 }, + { 0x00000000, 0x007F8000, 0x00008000, ATT_IOMEM }, /* OCRAM_S (Code) */ { 0x00180000, 0x008F8000, 0x00004000, 0 }, /* OCRAM_S (Code) - alias */ { 0x00180000, 0x008FC000, 0x00004000, 0 }, /* TCML (Code) */ - { 0x1FFF8000, 0x007F8000, 0x00008000, ATT_OWN }, + { 0x1FFF8000, 0x007F8000, 0x00008000, ATT_OWN | ATT_IOMEM }, /* DDR (Code) - alias, first part of DDR (Data) */ { 0x10000000, 0x80000000, 0x0FFF8000, 0 }, /* TCMU (Data) */ - { 0x20000000, 0x00800000, 0x00008000, ATT_OWN }, + { 0x20000000, 0x00800000, 0x00008000, ATT_OWN | ATT_IOMEM }, /* OCRAM_S (Data) - alias? */ { 0x208F8000, 0x008F8000, 0x00004000, 0 }, /* DDR (Data) */ @@ -341,7 +342,7 @@ static int imx_rproc_stop(struct rproc *rproc) } static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da, - size_t len, u64 *sys) + size_t len, u64 *sys, bool *is_iomem) { const struct imx_rproc_dcfg *dcfg = priv->dcfg; int i; @@ -354,6 +355,8 @@ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da, unsigned int offset = da - att->da; *sys = att->sa + offset; + if (is_iomem) + *is_iomem = att->flags & ATT_IOMEM; return 0; } } @@ -377,7 +380,7 @@ static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *i * On device side we have many aliases, so we need to convert device * address (M4) to system bus address first. */ - if (imx_rproc_da_to_sys(priv, da, len, &sys)) + if (imx_rproc_da_to_sys(priv, da, len, &sys, is_iomem)) return NULL; for (i = 0; i < IMX_RPROC_MEM_MAX; i++) { @@ -553,8 +556,12 @@ static int imx_rproc_addr_init(struct imx_rproc *priv, if (b >= IMX_RPROC_MEM_MAX) break; - priv->mem[b].cpu_addr = devm_ioremap(&pdev->dev, - att->sa, att->size); + if (att->flags & ATT_IOMEM) + priv->mem[b].cpu_addr = devm_ioremap(&pdev->dev, + att->sa, att->size); + else + priv->mem[b].cpu_addr = devm_ioremap_wc(&pdev->dev, + att->sa, att->size); if (!priv->mem[b].cpu_addr) { dev_err(dev, "failed to remap %#x bytes from %#x\n", att->size, att->sa); return -ENOMEM; -- cgit From afe670e23af91d8a74a8d7049f6e0984bbf6ea11 Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Fri, 10 Sep 2021 17:06:19 +0800 Subject: remoteproc: imx_rproc: Fix ignoring mapping vdev regions vdev regions are typically named vdev0buffer, vdev0ring0, vdev0ring1 and etc. Change to strncmp to cover them all. Fixes: 8f2d8961640f ("remoteproc: imx_rproc: ignore mapping vdev regions") Reviewed-and-tested-by: Peng Fan Signed-off-by: Dong Aisheng Signed-off-by: Peng Fan Cc: stable Link: https://lore.kernel.org/r/20210910090621.3073540-5-peng.fan@oss.nxp.com Signed-off-by: Mathieu Poirier Signed-off-by: Bjorn Andersson --- drivers/remoteproc/imx_rproc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 71dcc6dd32e4..abfeac0b1738 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -582,8 +582,8 @@ static int imx_rproc_addr_init(struct imx_rproc *priv, struct resource res; node = of_parse_phandle(np, "memory-region", a); - /* Not map vdev region */ - if (!strcmp(node->name, "vdev")) + /* Not map vdevbuffer, vdevring region */ + if (!strncmp(node->name, "vdev", strlen("vdev"))) continue; err = of_address_to_resource(node, 0, &res); if (err) { -- cgit From e90547d59d4e29e269e22aa6ce590ed0b41207d2 Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Fri, 10 Sep 2021 17:06:20 +0800 Subject: remoteproc: imx_rproc: Fix rsc-table name Usually the dash '-' is preferred in node name. So far, not dts in upstream kernel, so we just update node name in driver. Cc: Bjorn Andersson Cc: Mathieu Poirier Fixes: 5e4c1243071d ("remoteproc: imx_rproc: support remote cores booted before Linux Kernel") Reviewed-and-tested-by: Peng Fan Signed-off-by: Dong Aisheng Signed-off-by: Peng Fan Cc: stable Link: https://lore.kernel.org/r/20210910090621.3073540-6-peng.fan@oss.nxp.com Signed-off-by: Mathieu Poirier Signed-off-by: Bjorn Andersson --- drivers/remoteproc/imx_rproc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index abfeac0b1738..ff620688fad9 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -604,7 +604,7 @@ static int imx_rproc_addr_init(struct imx_rproc *priv, } priv->mem[b].sys_addr = res.start; priv->mem[b].size = resource_size(&res); - if (!strcmp(node->name, "rsc_table")) + if (!strcmp(node->name, "rsc-table")) priv->rsc_table = priv->mem[b].cpu_addr; b++; } -- cgit From 28d5554b4630dca4b7dda723ba94d705dd3da3f3 Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Fri, 10 Sep 2021 17:06:21 +0800 Subject: remoteproc: imx_rproc: Change to ioremap_wc for dram DRAM is not io memory, so changed to ioremap_wc. This is also aligned with core io accessories. e.g. memcpy/memset and cpu direct access. Cc: Bjorn Andersson Cc: Mathieu Poirier Cc: Peng Fan Reviewed-and-tested-by: Peng Fan Signed-off-by: Dong Aisheng Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20210910090621.3073540-7-peng.fan@oss.nxp.com Signed-off-by: Mathieu Poirier Signed-off-by: Bjorn Andersson --- drivers/remoteproc/imx_rproc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index ff620688fad9..4ae416ba5080 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -597,7 +597,7 @@ static int imx_rproc_addr_init(struct imx_rproc *priv, break; /* Not use resource version, because we might share region */ - priv->mem[b].cpu_addr = devm_ioremap(&pdev->dev, res.start, resource_size(&res)); + priv->mem[b].cpu_addr = devm_ioremap_wc(&pdev->dev, res.start, resource_size(&res)); if (!priv->mem[b].cpu_addr) { dev_err(dev, "failed to remap %pr\n", &res); return -ENOMEM; -- cgit From eeaf9700b9c6976c0360b10caf55f7e4374f7c3b Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Tue, 21 Sep 2021 21:25:56 +0200 Subject: dt-bindings: remoteproc: Add the documentation for Meson AO ARC rproc Amlogic Meson6, Meson8, Meson8b and Meson8m2 SoCs embed an ARC EM4 controller for always-on operations, typically used for managing system suspend. Reviewed-by: Rob Herring Signed-off-by: Martin Blumenstingl Link: https://lore.kernel.org/r/20210921192557.1610709-2-martin.blumenstingl@googlemail.com Signed-off-by: Mathieu Poirier Signed-off-by: Bjorn Andersson --- .../remoteproc/amlogic,meson-mx-ao-arc.yaml | 87 ++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 Documentation/devicetree/bindings/remoteproc/amlogic,meson-mx-ao-arc.yaml diff --git a/Documentation/devicetree/bindings/remoteproc/amlogic,meson-mx-ao-arc.yaml b/Documentation/devicetree/bindings/remoteproc/amlogic,meson-mx-ao-arc.yaml new file mode 100644 index 000000000000..d892d29a656b --- /dev/null +++ b/Documentation/devicetree/bindings/remoteproc/amlogic,meson-mx-ao-arc.yaml @@ -0,0 +1,87 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/remoteproc/amlogic,meson-mx-ao-arc.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Amlogic Meson AO ARC Remote Processor bindings + +description: + Amlogic Meson6, Meson8, Meson8b and Meson8m2 SoCs embed an ARC core + controller for always-on operations, typically used for managing + system suspend. Meson6 and older use a ARC core based on the ARCv1 + ISA, while Meson8, Meson8b and Meson8m2 use an ARC EM4 (ARCv2 ISA) + core. + +maintainers: + - Martin Blumenstingl + +properties: + compatible: + items: + - enum: + - amlogic,meson8-ao-arc + - amlogic,meson8b-ao-arc + - const: amlogic,meson-mx-ao-arc + + firmware-name: + $ref: /schemas/types.yaml#/definitions/string + description: + The name of the firmware which should be loaded for this remote + processor. + + reg: + description: + Address ranges of the remap and CPU control addresses for the + remote processor. + minItems: 2 + + reg-names: + items: + - const: remap + - const: cpu + + resets: + minItems: 1 + + clocks: + minItems: 1 + + sram: + $ref: /schemas/types.yaml#/definitions/phandle + description: + phandles to a reserved SRAM region which is used as the memory of + the ARC core. The region should be defined as child nodes of the + AHB SRAM node as per the generic bindings in + Documentation/devicetree/bindings/sram/sram.yaml + + amlogic,secbus2: + $ref: /schemas/types.yaml#/definitions/phandle + description: + A phandle to the SECBUS2 region which contains some configuration + bits of this remote processor + +required: + - compatible + - reg + - reg-names + - resets + - clocks + - sram + - amlogic,secbus2 + +additionalProperties: false + +examples: + - | + remoteproc@1c { + compatible= "amlogic,meson8-ao-arc", "amlogic,meson-mx-ao-arc"; + reg = <0x1c 0x8>, <0x38 0x8>; + reg-names = "remap", "cpu"; + resets = <&media_cpu_reset>; + clocks = <&media_cpu_clock>; + sram = <&ahb_sram_ao_arc>; + amlogic,secbus2 = <&secbus2>; + }; + +... -- cgit From 6cb58ea897dd1d10b1a52c16b344f112102cf7d3 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Tue, 21 Sep 2021 21:25:57 +0200 Subject: remoteproc: meson-mx-ao-arc: Add a driver for the AO ARC remote procesor Amlogic Meson6, Meson8, Meson8b and Meson8m2 embed an ARC core in the Always-On (AO) power-domain. This is typically used for waking up the ARM cores after system suspend. The configuration is spread across three different registers: - AO_REMAP_REG0 which must be programmed to zero, it's actual purpose is unknown. There is a second remap register which is not used in the vendor kernel (which served as reference for this driver). - AO_CPU_CNTL is used to start and stop the ARC core. - AO_SECURE_REG0 in the SECBUS2 register area with unknown purpose. To boot the ARC core we also need to enable it's gate clock and trigger a reset. The actual code for this ARC core can come from an ELF binary, for example by building the Zephyr RTOS for an ARC EM4 core and then taking "zephyr.elf" as firmware. This executable does not have any "rsc table" so we are skipping rproc_elf_load_rsc_table (rproc_ops.parse_fw) and rproc_elf_find_loaded_rsc_table (rproc_ops.find_loaded_rsc_table). Signed-off-by: Martin Blumenstingl Link: https://lore.kernel.org/r/20210921192557.1610709-3-martin.blumenstingl@googlemail.com [Fixed header file order] Signed-off-by: Mathieu Poirier Signed-off-by: Bjorn Andersson --- drivers/remoteproc/Kconfig | 11 ++ drivers/remoteproc/Makefile | 1 + drivers/remoteproc/meson_mx_ao_arc.c | 261 +++++++++++++++++++++++++++++++++++ 3 files changed, 273 insertions(+) create mode 100644 drivers/remoteproc/meson_mx_ao_arc.c diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index f30d00a3aabe..dcb87a366ec7 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -127,6 +127,17 @@ config KEYSTONE_REMOTEPROC It's safe to say N here if you're not interested in the Keystone DSPs or just want to use a bare minimum kernel. +config MESON_MX_AO_ARC_REMOTEPROC + tristate "Amlogic Meson6/8/8b/8m2 AO ARC remote processor support" + depends on HAS_IOMEM + depends on (ARM && ARCH_MESON) || COMPILE_TEST + select GENERIC_ALLOCATOR + help + Say m or y here to have support for the AO ARC remote processor + on Amlogic Meson6/Meson8/Meson8b/Meson8m2 SoCs. This is + typically used for system suspend. + If unsure say N. + config PRU_REMOTEPROC tristate "TI PRU remoteproc support" depends on TI_PRUSS diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index bb26c9e4ef9c..ce1abeb30907 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o obj-$(CONFIG_WKUP_M3_RPROC) += wkup_m3_rproc.o obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o obj-$(CONFIG_KEYSTONE_REMOTEPROC) += keystone_remoteproc.o +obj-$(CONFIG_MESON_MX_AO_ARC_REMOTEPROC)+= meson_mx_ao_arc.o obj-$(CONFIG_PRU_REMOTEPROC) += pru_rproc.o obj-$(CONFIG_QCOM_PIL_INFO) += qcom_pil_info.o obj-$(CONFIG_QCOM_RPROC_COMMON) += qcom_common.o diff --git a/drivers/remoteproc/meson_mx_ao_arc.c b/drivers/remoteproc/meson_mx_ao_arc.c new file mode 100644 index 000000000000..3d8f927ae448 --- /dev/null +++ b/drivers/remoteproc/meson_mx_ao_arc.c @@ -0,0 +1,261 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 Martin Blumenstingl + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "remoteproc_internal.h" + +#define AO_REMAP_REG0 0x0 +#define AO_REMAP_REG0_REMAP_AHB_SRAM_BITS_17_14_FOR_ARM_CPU GENMASK(3, 0) + +#define AO_REMAP_REG1 0x4 +#define AO_REMAP_REG1_MOVE_AHB_SRAM_TO_0X0_INSTEAD_OF_DDR BIT(4) +#define AO_REMAP_REG1_REMAP_AHB_SRAM_BITS_17_14_FOR_MEDIA_CPU GENMASK(3, 0) + +#define AO_CPU_CNTL 0x0 +#define AO_CPU_CNTL_AHB_SRAM_BITS_31_20 GENMASK(28, 16) +#define AO_CPU_CNTL_HALT BIT(9) +#define AO_CPU_CNTL_UNKNONWN BIT(8) +#define AO_CPU_CNTL_RUN BIT(0) + +#define AO_CPU_STAT 0x4 + +#define AO_SECURE_REG0 0x0 +#define AO_SECURE_REG0_AHB_SRAM_BITS_19_12 GENMASK(15, 8) + +/* Only bits [31:20] and [17:14] are usable, all other bits must be zero */ +#define MESON_AO_RPROC_SRAM_USABLE_BITS 0xfff3c000 + +#define MESON_AO_RPROC_MEMORY_OFFSET 0x10000000 + +struct meson_mx_ao_arc_rproc_priv { + void __iomem *remap_base; + void __iomem *cpu_base; + unsigned long sram_va; + phys_addr_t sram_pa; + size_t sram_size; + struct gen_pool *sram_pool; + struct reset_control *arc_reset; + struct clk *arc_pclk; + struct regmap *secbus2_regmap; +}; + +static int meson_mx_ao_arc_rproc_start(struct rproc *rproc) +{ + struct meson_mx_ao_arc_rproc_priv *priv = rproc->priv; + phys_addr_t translated_sram_addr; + u32 tmp; + int ret; + + ret = clk_prepare_enable(priv->arc_pclk); + if (ret) + return ret; + + tmp = FIELD_PREP(AO_REMAP_REG0_REMAP_AHB_SRAM_BITS_17_14_FOR_ARM_CPU, + priv->sram_pa >> 14); + writel(tmp, priv->remap_base + AO_REMAP_REG0); + + /* + * The SRAM content as seen by the ARC core always starts at 0x0 + * regardless of the value given here (this was discovered by trial and + * error). For SoCs older than Meson6 we probably have to set + * AO_REMAP_REG1_MOVE_AHB_SRAM_TO_0X0_INSTEAD_OF_DDR to achieve the + * same. (At least) For Meson8 and newer that bit must not be set. + */ + writel(0x0, priv->remap_base + AO_REMAP_REG1); + + regmap_update_bits(priv->secbus2_regmap, AO_SECURE_REG0, + AO_SECURE_REG0_AHB_SRAM_BITS_19_12, + FIELD_PREP(AO_SECURE_REG0_AHB_SRAM_BITS_19_12, + priv->sram_pa >> 12)); + + ret = reset_control_reset(priv->arc_reset); + if (ret) { + clk_disable_unprepare(priv->arc_pclk); + return ret; + } + + usleep_range(10, 100); + + /* + * Convert from 0xd9000000 to 0xc9000000 as the vendor driver does. + * This only seems to be relevant for the AO_CPU_CNTL register. It is + * unknown why this is needed. + */ + translated_sram_addr = priv->sram_pa - MESON_AO_RPROC_MEMORY_OFFSET; + + tmp = FIELD_PREP(AO_CPU_CNTL_AHB_SRAM_BITS_31_20, + translated_sram_addr >> 20); + tmp |= AO_CPU_CNTL_UNKNONWN | AO_CPU_CNTL_RUN; + writel(tmp, priv->cpu_base + AO_CPU_CNTL); + + usleep_range(20, 200); + + return 0; +} + +static int meson_mx_ao_arc_rproc_stop(struct rproc *rproc) +{ + struct meson_mx_ao_arc_rproc_priv *priv = rproc->priv; + + writel(AO_CPU_CNTL_HALT, priv->cpu_base + AO_CPU_CNTL); + + clk_disable_unprepare(priv->arc_pclk); + + return 0; +} + +static void *meson_mx_ao_arc_rproc_da_to_va(struct rproc *rproc, u64 da, + size_t len, bool *is_iomem) +{ + struct meson_mx_ao_arc_rproc_priv *priv = rproc->priv; + + /* The memory from the ARC core's perspective always starts at 0x0. */ + if ((da + len) > priv->sram_size) + return NULL; + + return (void *)priv->sram_va + da; +} + +static struct rproc_ops meson_mx_ao_arc_rproc_ops = { + .start = meson_mx_ao_arc_rproc_start, + .stop = meson_mx_ao_arc_rproc_stop, + .da_to_va = meson_mx_ao_arc_rproc_da_to_va, + .get_boot_addr = rproc_elf_get_boot_addr, + .load = rproc_elf_load_segments, + .sanity_check = rproc_elf_sanity_check, +}; + +static int meson_mx_ao_arc_rproc_probe(struct platform_device *pdev) +{ + struct meson_mx_ao_arc_rproc_priv *priv; + struct device *dev = &pdev->dev; + const char *fw_name = NULL; + struct rproc *rproc; + int ret; + + device_property_read_string(dev, "firmware-name", &fw_name); + + rproc = devm_rproc_alloc(dev, "meson-mx-ao-arc", + &meson_mx_ao_arc_rproc_ops, fw_name, + sizeof(*priv)); + if (!rproc) + return -ENOMEM; + + rproc->has_iommu = false; + priv = rproc->priv; + + priv->sram_pool = of_gen_pool_get(dev->of_node, "sram", 0); + if (!priv->sram_pool) { + dev_err(dev, "Could not get SRAM pool\n"); + return -ENODEV; + } + + priv->sram_size = gen_pool_avail(priv->sram_pool); + + priv->sram_va = gen_pool_alloc(priv->sram_pool, priv->sram_size); + if (!priv->sram_va) { + dev_err(dev, "Could not alloc memory in SRAM pool\n"); + return -ENOMEM; + } + + priv->sram_pa = gen_pool_virt_to_phys(priv->sram_pool, priv->sram_va); + if (priv->sram_pa & ~MESON_AO_RPROC_SRAM_USABLE_BITS) { + dev_err(dev, "SRAM address contains unusable bits\n"); + ret = -EINVAL; + goto err_free_genpool; + } + + priv->secbus2_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, + "amlogic,secbus2"); + if (IS_ERR(priv->secbus2_regmap)) { + dev_err(dev, "Failed to find SECBUS2 regmap\n"); + ret = PTR_ERR(priv->secbus2_regmap); + goto err_free_genpool; + } + + priv->remap_base = devm_platform_ioremap_resource_byname(pdev, "remap"); + if (IS_ERR(priv->remap_base)) { + ret = PTR_ERR(priv->remap_base); + goto err_free_genpool; + } + + priv->cpu_base = devm_platform_ioremap_resource_byname(pdev, "cpu"); + if (IS_ERR(priv->cpu_base)) { + ret = PTR_ERR(priv->cpu_base); + goto err_free_genpool; + } + + priv->arc_reset = devm_reset_control_get_exclusive(dev, NULL); + if (IS_ERR(priv->arc_reset)) { + dev_err(dev, "Failed to get ARC reset\n"); + ret = PTR_ERR(priv->arc_reset); + goto err_free_genpool; + } + + priv->arc_pclk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->arc_pclk)) { + dev_err(dev, "Failed to get the ARC PCLK\n"); + ret = PTR_ERR(priv->arc_pclk); + goto err_free_genpool; + } + + platform_set_drvdata(pdev, rproc); + + ret = rproc_add(rproc); + if (ret) + goto err_free_genpool; + + return 0; + +err_free_genpool: + gen_pool_free(priv->sram_pool, priv->sram_va, priv->sram_size); + return ret; +} + +static int meson_mx_ao_arc_rproc_remove(struct platform_device *pdev) +{ + struct rproc *rproc = platform_get_drvdata(pdev); + struct meson_mx_ao_arc_rproc_priv *priv = rproc->priv; + + rproc_del(rproc); + gen_pool_free(priv->sram_pool, priv->sram_va, priv->sram_size); + + return 0; +} + +static const struct of_device_id meson_mx_ao_arc_rproc_match[] = { + { .compatible = "amlogic,meson8-ao-arc" }, + { .compatible = "amlogic,meson8b-ao-arc" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, meson_mx_ao_arc_rproc_match); + +static struct platform_driver meson_mx_ao_arc_rproc_driver = { + .probe = meson_mx_ao_arc_rproc_probe, + .remove = meson_mx_ao_arc_rproc_remove, + .driver = { + .name = "meson-mx-ao-arc-rproc", + .of_match_table = meson_mx_ao_arc_rproc_match, + }, +}; +module_platform_driver(meson_mx_ao_arc_rproc_driver); + +MODULE_DESCRIPTION("Amlogic Meson6/8/8b/8m2 AO ARC remote processor driver"); +MODULE_AUTHOR("Martin Blumenstingl "); +MODULE_LICENSE("GPL v2"); -- cgit From ca7380a41d37f811dba911bdf446e649a8a8f18b Mon Sep 17 00:00:00 2001 From: Tinghan Shen Date: Fri, 24 Sep 2021 11:39:30 +0800 Subject: dt-bindings: remoteproc: mediatek: Add binding for mt8195 scp Add mt8195 compatible to binding document. The description of required properties are also modified to reflect the hardware change between mt8183 and mt8195. The mt8195 doesn't have to control the scp clock on kernel side. Signed-off-by: Tinghan Shen Acked-by: Rob Herring Link: https://lore.kernel.org/r/20210924033935.2127-2-tinghan.shen@mediatek.com Signed-off-by: Mathieu Poirier Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/remoteproc/mtk,scp.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/remoteproc/mtk,scp.txt b/Documentation/devicetree/bindings/remoteproc/mtk,scp.txt index 3f5f78764b60..d64466eefbe3 100644 --- a/Documentation/devicetree/bindings/remoteproc/mtk,scp.txt +++ b/Documentation/devicetree/bindings/remoteproc/mtk,scp.txt @@ -5,13 +5,15 @@ This binding provides support for ARM Cortex M4 Co-processor found on some Mediatek SoCs. Required properties: -- compatible Should be "mediatek,mt8183-scp" +- compatible Should be one of: + "mediatek,mt8183-scp" + "mediatek,mt8195-scp" - reg Should contain the address ranges for memory regions: SRAM, CFG, and L1TCM. - reg-names Contains the corresponding names for the memory regions: "sram", "cfg", and "l1tcm". -- clocks Clock for co-processor (See: ../clock/clock-bindings.txt) -- clock-names Contains the corresponding name for the clock. This +- clocks Required by mt8183. Clock for co-processor (See: ../clock/clock-bindings.txt) +- clock-names Required by mt8183. Contains the corresponding name for the clock. This should be named "main". Subnodes -- cgit From 63e6a34068a331854fa087aad7baf5bf80a3c7ab Mon Sep 17 00:00:00 2001 From: Tinghan Shen Date: Fri, 24 Sep 2021 11:39:31 +0800 Subject: dt-bindings: remoteproc: mediatek: Add binding for mt8192 scp Add mt8192 compatible to binding document. Signed-off-by: Tinghan Shen Acked-by: Rob Herring Link: https://lore.kernel.org/r/20210924033935.2127-3-tinghan.shen@mediatek.com Signed-off-by: Mathieu Poirier Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/remoteproc/mtk,scp.txt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/remoteproc/mtk,scp.txt b/Documentation/devicetree/bindings/remoteproc/mtk,scp.txt index d64466eefbe3..88f37dee7bca 100644 --- a/Documentation/devicetree/bindings/remoteproc/mtk,scp.txt +++ b/Documentation/devicetree/bindings/remoteproc/mtk,scp.txt @@ -7,14 +7,17 @@ Mediatek SoCs. Required properties: - compatible Should be one of: "mediatek,mt8183-scp" + "mediatek,mt8192-scp" "mediatek,mt8195-scp" - reg Should contain the address ranges for memory regions: SRAM, CFG, and L1TCM. - reg-names Contains the corresponding names for the memory regions: "sram", "cfg", and "l1tcm". -- clocks Required by mt8183. Clock for co-processor (See: ../clock/clock-bindings.txt) -- clock-names Required by mt8183. Contains the corresponding name for the clock. This - should be named "main". +- clocks Required by mt8183 and mt8192. Clock for co-processor + (See: ../clock/clock-bindings.txt) +- clock-names Required by mt8183 and mt8192. Contains the + corresponding name for the clock. This should be + named "main". Subnodes -------- -- cgit From f4d7e6f6eb3c115f574008964a763b1e33eec6b9 Mon Sep 17 00:00:00 2001 From: Tinghan Shen Date: Fri, 24 Sep 2021 11:39:32 +0800 Subject: dt-bindings: remoteproc: mediatek: Convert mtk,scp to json-schema Convert the mtk,scp binding to DT schema format using json-schema. Signed-off-by: Tinghan Shen Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210924033935.2127-4-tinghan.shen@mediatek.com Signed-off-by: Mathieu Poirier Signed-off-by: Bjorn Andersson --- .../devicetree/bindings/remoteproc/mtk,scp.txt | 41 ---------- .../devicetree/bindings/remoteproc/mtk,scp.yaml | 92 ++++++++++++++++++++++ 2 files changed, 92 insertions(+), 41 deletions(-) delete mode 100644 Documentation/devicetree/bindings/remoteproc/mtk,scp.txt create mode 100644 Documentation/devicetree/bindings/remoteproc/mtk,scp.yaml diff --git a/Documentation/devicetree/bindings/remoteproc/mtk,scp.txt b/Documentation/devicetree/bindings/remoteproc/mtk,scp.txt deleted file mode 100644 index 88f37dee7bca..000000000000 --- a/Documentation/devicetree/bindings/remoteproc/mtk,scp.txt +++ /dev/null @@ -1,41 +0,0 @@ -Mediatek SCP Bindings ----------------------------------------- - -This binding provides support for ARM Cortex M4 Co-processor found on some -Mediatek SoCs. - -Required properties: -- compatible Should be one of: - "mediatek,mt8183-scp" - "mediatek,mt8192-scp" - "mediatek,mt8195-scp" -- reg Should contain the address ranges for memory regions: - SRAM, CFG, and L1TCM. -- reg-names Contains the corresponding names for the memory regions: - "sram", "cfg", and "l1tcm". -- clocks Required by mt8183 and mt8192. Clock for co-processor - (See: ../clock/clock-bindings.txt) -- clock-names Required by mt8183 and mt8192. Contains the - corresponding name for the clock. This should be - named "main". - -Subnodes --------- - -Subnodes of the SCP represent rpmsg devices. The names of the devices are not -important. The properties of these nodes are defined by the individual bindings -for the rpmsg devices - but must contain the following property: - -- mtk,rpmsg-name Contains the name for the rpmsg device. Used to match - the subnode to rpmsg device announced by SCP. - -Example: - - scp: scp@10500000 { - compatible = "mediatek,mt8183-scp"; - reg = <0 0x10500000 0 0x80000>, - <0 0x105c0000 0 0x5000>; - reg-names = "sram", "cfg"; - clocks = <&infracfg CLK_INFRA_SCPSYS>; - clock-names = "main"; - }; diff --git a/Documentation/devicetree/bindings/remoteproc/mtk,scp.yaml b/Documentation/devicetree/bindings/remoteproc/mtk,scp.yaml new file mode 100644 index 000000000000..d21a25ee96e6 --- /dev/null +++ b/Documentation/devicetree/bindings/remoteproc/mtk,scp.yaml @@ -0,0 +1,92 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/remoteproc/mtk,scp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mediatek SCP Bindings + +maintainers: + - Tinghan Shen + +description: + This binding provides support for ARM Cortex M4 Co-processor found on some + Mediatek SoCs. + +properties: + compatible: + enum: + - mediatek,mt8183-scp + - mediatek,mt8192-scp + - mediatek,mt8195-scp + + reg: + description: + Should contain the address ranges for memory regions SRAM, CFG, and + L1TCM. + maxItems: 3 + + reg-names: + items: + - const: sram + - const: cfg + - const: l1tcm + + clocks: + description: + Clock for co-processor (see ../clock/clock-bindings.txt). + Required by mt8183 and mt8192. + maxItems: 1 + + clock-names: + const: main + +required: + - compatible + - reg + - reg-names + +if: + properties: + compatible: + enum: + - mediatek,mt8183-scp + - mediatek,mt8192-scp +then: + required: + - clocks + - clock-names + +additionalProperties: + type: object + description: + Subnodes of the SCP represent rpmsg devices. The names of the devices + are not important. The properties of these nodes are defined by the + individual bindings for the rpmsg devices. + properties: + mediatek,rpmsg-name: + $ref: /schemas/types.yaml#/definitions/string-array + description: + Contains the name for the rpmsg device. Used to match + the subnode to rpmsg device announced by SCP. + + required: + - mediatek,rpmsg-name + +examples: + - | + #include + + scp@10500000 { + compatible = "mediatek,mt8183-scp"; + reg = <0x10500000 0x80000>, + <0x10700000 0x8000>, + <0x10720000 0xe0000>; + reg-names = "sram", "cfg", "l1tcm"; + clocks = <&infracfg CLK_INFRA_SCPSYS>; + clock-names = "main"; + + cros_ec { + mediatek,rpmsg-name = "cros-ec-rpmsg"; + }; + }; -- cgit From 79111df414fc2971e419825132113d906b1611b3 Mon Sep 17 00:00:00 2001 From: Tinghan Shen Date: Fri, 24 Sep 2021 11:39:33 +0800 Subject: remoteproc: mediatek: Support mt8195 scp The SCP clock design is changed on mt8195 that doesn't need to control SCP clock on kernel side. Signed-off-by: Tinghan Shen Reviewed-by: Mathieu Poirier Link: https://lore.kernel.org/r/20210924033935.2127-5-tinghan.shen@mediatek.com Signed-off-by: Mathieu Poirier Signed-off-by: Bjorn Andersson --- drivers/remoteproc/mtk_common.h | 1 + drivers/remoteproc/mtk_scp.c | 48 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/drivers/remoteproc/mtk_common.h b/drivers/remoteproc/mtk_common.h index 61901f5efa05..5ff3867c72f3 100644 --- a/drivers/remoteproc/mtk_common.h +++ b/drivers/remoteproc/mtk_common.h @@ -72,6 +72,7 @@ struct scp_ipi_desc { struct mtk_scp; struct mtk_scp_of_data { + int (*scp_clk_get)(struct mtk_scp *scp); int (*scp_before_load)(struct mtk_scp *scp); void (*scp_irq_handler)(struct mtk_scp *scp); void (*scp_reset_assert)(struct mtk_scp *scp); diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index 9679cc26895e..36e48cf58ed6 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -312,6 +312,32 @@ static int scp_elf_read_ipi_buf_addr(struct mtk_scp *scp, return -ENOENT; } +static int mt8183_scp_clk_get(struct mtk_scp *scp) +{ + struct device *dev = scp->dev; + int ret = 0; + + scp->clk = devm_clk_get(dev, "main"); + if (IS_ERR(scp->clk)) { + dev_err(dev, "Failed to get clock\n"); + ret = PTR_ERR(scp->clk); + } + + return ret; +} + +static int mt8192_scp_clk_get(struct mtk_scp *scp) +{ + return mt8183_scp_clk_get(scp); +} + +static int mt8195_scp_clk_get(struct mtk_scp *scp) +{ + scp->clk = NULL; + + return 0; +} + static int mt8183_scp_before_load(struct mtk_scp *scp) { /* Clear SCP to host interrupt */ @@ -785,12 +811,9 @@ static int scp_probe(struct platform_device *pdev) if (ret) goto destroy_mutex; - scp->clk = devm_clk_get(dev, "main"); - if (IS_ERR(scp->clk)) { - dev_err(dev, "Failed to get clock\n"); - ret = PTR_ERR(scp->clk); + ret = scp->data->scp_clk_get(scp); + if (ret) goto release_dev_mem; - } /* register SCP initialization IPI */ ret = scp_ipi_register(scp, SCP_IPI_INIT, scp_init_ipi_handler, scp); @@ -852,6 +875,7 @@ static int scp_remove(struct platform_device *pdev) } static const struct mtk_scp_of_data mt8183_of_data = { + .scp_clk_get = mt8183_scp_clk_get, .scp_before_load = mt8183_scp_before_load, .scp_irq_handler = mt8183_scp_irq_handler, .scp_reset_assert = mt8183_scp_reset_assert, @@ -864,6 +888,19 @@ static const struct mtk_scp_of_data mt8183_of_data = { }; static const struct mtk_scp_of_data mt8192_of_data = { + .scp_clk_get = mt8192_scp_clk_get, + .scp_before_load = mt8192_scp_before_load, + .scp_irq_handler = mt8192_scp_irq_handler, + .scp_reset_assert = mt8192_scp_reset_assert, + .scp_reset_deassert = mt8192_scp_reset_deassert, + .scp_stop = mt8192_scp_stop, + .scp_da_to_va = mt8192_scp_da_to_va, + .host_to_scp_reg = MT8192_GIPC_IN_SET, + .host_to_scp_int_bit = MT8192_HOST_IPC_INT_BIT, +}; + +static const struct mtk_scp_of_data mt8195_of_data = { + .scp_clk_get = mt8195_scp_clk_get, .scp_before_load = mt8192_scp_before_load, .scp_irq_handler = mt8192_scp_irq_handler, .scp_reset_assert = mt8192_scp_reset_assert, @@ -877,6 +914,7 @@ static const struct mtk_scp_of_data mt8192_of_data = { static const struct of_device_id mtk_scp_of_match[] = { { .compatible = "mediatek,mt8183-scp", .data = &mt8183_of_data }, { .compatible = "mediatek,mt8192-scp", .data = &mt8192_of_data }, + { .compatible = "mediatek,mt8195-scp", .data = &mt8195_of_data }, {}, }; MODULE_DEVICE_TABLE(of, mtk_scp_of_match); -- cgit From 81231af135cac867170f06ceda35d7197863a2e2 Mon Sep 17 00:00:00 2001 From: Sinthu Raja Date: Mon, 27 Sep 2021 16:08:10 +0530 Subject: dt-bindings: remoteproc: k3-r5f: Cleanup SoC compatible from DT example The K3 R5F binding example used the root-node with a SoC compatible property originally to address the dt_binding_check warnings resulting from using a value of 2 for #address-cells and #size-cells as per most common usage on K3 SoCs. Clean this up and replace it with a generic soc node to keep it agnostic of the SoC or board compatibles that are outside the scope of this binding. Signed-off-by: Sinthu Raja Acked-by: Rob Herring Acked-by: Suman Anna Reviewed-by: Nishanth Menon Link: https://lore.kernel.org/r/20210927103811.11222-2-sinthu.raja@ti.com Signed-off-by: Mathieu Poirier Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/remoteproc/ti,k3-r5f-rproc.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/remoteproc/ti,k3-r5f-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/ti,k3-r5f-rproc.yaml index 130fbaacc4b1..eeef255c4045 100644 --- a/Documentation/devicetree/bindings/remoteproc/ti,k3-r5f-rproc.yaml +++ b/Documentation/devicetree/bindings/remoteproc/ti,k3-r5f-rproc.yaml @@ -230,9 +230,7 @@ additionalProperties: false examples: - | - / { - model = "Texas Instruments K3 AM654 SoC"; - compatible = "ti,am654-evm", "ti,am654"; + soc { #address-cells = <2>; #size-cells = <2>; -- cgit From f13f5d729a8d4dd25e266ad04169718b41f1f933 Mon Sep 17 00:00:00 2001 From: Sinthu Raja Date: Mon, 27 Sep 2021 16:08:11 +0530 Subject: dt-bindings: remoteproc: k3-dsp: Cleanup SoC compatible from DT example The K3 DSP binding example used the root-node with a SoC compatible property originally to address the dt_binding_check warnings resulting from using a value of 2 for #address-cells and #size-cells as per most common usage on K3 SoCs. Clean this up and replace it with a generic soc node to keep it agnostic of the SoC or board compatibles that are outside the scope of this binding. Signed-off-by: Sinthu Raja Acked-by: Rob Herring Acked-by: Suman Anna Reviewed-by: Nishanth Menon Link: https://lore.kernel.org/r/20210927103811.11222-3-sinthu.raja@ti.com Signed-off-by: Mathieu Poirier Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/remoteproc/ti,k3-dsp-rproc.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/remoteproc/ti,k3-dsp-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/ti,k3-dsp-rproc.yaml index 6070456a7b67..5ec6505ac408 100644 --- a/Documentation/devicetree/bindings/remoteproc/ti,k3-dsp-rproc.yaml +++ b/Documentation/devicetree/bindings/remoteproc/ti,k3-dsp-rproc.yaml @@ -133,9 +133,7 @@ unevaluatedProperties: false examples: - | - / { - model = "Texas Instruments K3 J721E SoC"; - compatible = "ti,j721e"; + soc { #address-cells = <2>; #size-cells = <2>; -- cgit From cc73f503f7ecde168e6874a1375900906ec16ad8 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 27 Sep 2021 14:09:46 -0700 Subject: MAINTAINERS: Update remoteproc repo url The remoteproc and rpmsg repos are moving from my personal namespace to allow Mathieu to push to the projects as well. Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210927210946.3746116-1-bjorn.andersson@linaro.org Signed-off-by: Mathieu Poirier Signed-off-by: Bjorn Andersson --- MAINTAINERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index eeb4c70b3d5b..18b5a8f88d17 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15904,7 +15904,7 @@ M: Bjorn Andersson M: Mathieu Poirier L: linux-remoteproc@vger.kernel.org S: Maintained -T: git git://git.kernel.org/pub/scm/linux/kernel/git/andersson/remoteproc.git rproc-next +T: git https://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux.git rproc-next F: Documentation/ABI/testing/sysfs-class-remoteproc F: Documentation/devicetree/bindings/remoteproc/ F: Documentation/staging/remoteproc.rst @@ -15918,7 +15918,7 @@ M: Bjorn Andersson M: Mathieu Poirier L: linux-remoteproc@vger.kernel.org S: Maintained -T: git git://git.kernel.org/pub/scm/linux/kernel/git/andersson/remoteproc.git rpmsg-next +T: git https://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux.git rpmsg-next F: Documentation/ABI/testing/sysfs-bus-rpmsg F: Documentation/staging/rpmsg.rst F: drivers/rpmsg/ -- cgit From 9ae45035ba2be4117edb8fd3952c3c5b84a0b820 Mon Sep 17 00:00:00 2001 From: Yassine Oudjana Date: Sun, 26 Sep 2021 19:06:22 +0000 Subject: remoteproc: qcom: pas: Use the same init resources for MSM8996 and MSM8998 The resources for MSM8996 are missing power domains, and adding them makes the resources identical to the MSM8998 ones. Rename msm8998_adsp_resource to msm8996_adsp_resource then use it for both chips. Also add power domains to slpi_resource_init and use it for both chips. Signed-off-by: Yassine Oudjana Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210926190555.278589-3-y.oudjana@protonmail.com --- drivers/remoteproc/qcom_q6v5_pas.c | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 8da0362d3d85..f0d4ec1d2b60 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -574,7 +574,7 @@ static const struct adsp_data sm8350_adsp_resource = { .ssctl_id = 0x14, }; -static const struct adsp_data msm8998_adsp_resource = { +static const struct adsp_data msm8996_adsp_resource = { .crash_reason_smem = 423, .firmware_name = "adsp.mdt", .pas_id = 1, @@ -700,6 +700,10 @@ static const struct adsp_data slpi_resource_init = { .pas_id = 12, .has_aggre2_clk = true, .auto_boot = true, + .proxy_pd_names = (char*[]){ + "ssc_cx", + NULL + }, .ssr_name = "dsps", .sysmon_name = "slpi", .ssctl_id = 0x16, @@ -756,21 +760,6 @@ static const struct adsp_data sm8350_slpi_resource = { .ssctl_id = 0x16, }; -static const struct adsp_data msm8998_slpi_resource = { - .crash_reason_smem = 424, - .firmware_name = "slpi.mdt", - .pas_id = 12, - .has_aggre2_clk = true, - .auto_boot = true, - .proxy_pd_names = (char*[]){ - "ssc_cx", - NULL - }, - .ssr_name = "dsps", - .sysmon_name = "slpi", - .ssctl_id = 0x16, -}; - static const struct adsp_data wcss_resource_init = { .crash_reason_smem = 421, .firmware_name = "wcnss.mdt", @@ -799,10 +788,10 @@ static const struct adsp_data sdx55_mpss_resource = { static const struct of_device_id adsp_of_match[] = { { .compatible = "qcom,msm8974-adsp-pil", .data = &adsp_resource_init}, - { .compatible = "qcom,msm8996-adsp-pil", .data = &adsp_resource_init}, + { .compatible = "qcom,msm8996-adsp-pil", .data = &msm8996_adsp_resource}, { .compatible = "qcom,msm8996-slpi-pil", .data = &slpi_resource_init}, - { .compatible = "qcom,msm8998-adsp-pas", .data = &msm8998_adsp_resource}, - { .compatible = "qcom,msm8998-slpi-pas", .data = &msm8998_slpi_resource}, + { .compatible = "qcom,msm8998-adsp-pas", .data = &msm8996_adsp_resource}, + { .compatible = "qcom,msm8998-slpi-pas", .data = &slpi_resource_init}, { .compatible = "qcom,qcs404-adsp-pas", .data = &adsp_resource_init }, { .compatible = "qcom,qcs404-cdsp-pas", .data = &cdsp_resource_init }, { .compatible = "qcom,qcs404-wcss-pas", .data = &wcss_resource_init }, -- cgit From 04a1261951bcb7aa2b5f13ffe6a73c14b26b2c5d Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Fri, 17 Sep 2021 19:25:26 +0530 Subject: dt-bindings: remoteproc: qcom: pas: Add SC7280 MPSS support Add MPSS PAS support for SC7280 SoCs. Signed-off-by: Sibi Sankar Reviewed-by: Matthias Kaehlcke Acked-by: Rob Herring Reviewed-by: Stephen Boyd Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/1631886935-14691-2-git-send-email-sibis@codeaurora.org --- Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml index ff265aa365de..63e06d93bca3 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml @@ -25,6 +25,7 @@ properties: - qcom,qcs404-cdsp-pas - qcom,qcs404-wcss-pas - qcom,sc7180-mpss-pas + - qcom,sc7280-mpss-pas - qcom,sc8180x-adsp-pas - qcom,sc8180x-cdsp-pas - qcom,sc8180x-mpss-pas @@ -151,6 +152,7 @@ allOf: - qcom,msm8998-adsp-pas - qcom,qcs404-adsp-pas - qcom,qcs404-wcss-pas + - qcom,sc7280-mpss-pas - qcom,sc8180x-adsp-pas - qcom,sc8180x-cdsp-pas - qcom,sc8180x-mpss-pas @@ -296,6 +298,7 @@ allOf: contains: enum: - qcom,sc7180-mpss-pas + - qcom,sc7280-mpss-pas - qcom,sc8180x-mpss-pas - qcom,sdx55-mpss-pas - qcom,sm8150-mpss-pas @@ -400,6 +403,7 @@ allOf: compatible: contains: enum: + - qcom,sc7280-mpss-pas - qcom,sdx55-mpss-pas - qcom,sm8150-mpss-pas - qcom,sm8350-mpss-pas @@ -475,6 +479,7 @@ allOf: contains: enum: - qcom,sc7180-mpss-pas + - qcom,sc7280-mpss-pas then: properties: resets: -- cgit From 58c8db93f7210975d48fa156837365ad3ac01d6c Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Fri, 17 Sep 2021 19:25:27 +0530 Subject: remoteproc: qcom: pas: Add SC7280 Modem support Add support for booting the Modem DSP found on QTI SC7280 SoCs. Signed-off-by: Sibi Sankar Reviewed-by: Matthias Kaehlcke Reviewed-by: Stephen Boyd Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/1631886935-14691-3-git-send-email-sibis@codeaurora.org --- drivers/remoteproc/qcom_q6v5_pas.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index f0d4ec1d2b60..03857dc9cdc1 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -796,6 +796,7 @@ static const struct of_device_id adsp_of_match[] = { { .compatible = "qcom,qcs404-cdsp-pas", .data = &cdsp_resource_init }, { .compatible = "qcom,qcs404-wcss-pas", .data = &wcss_resource_init }, { .compatible = "qcom,sc7180-mpss-pas", .data = &mpss_resource_init}, + { .compatible = "qcom,sc7280-mpss-pas", .data = &mpss_resource_init}, { .compatible = "qcom,sc8180x-adsp-pas", .data = &sm8150_adsp_resource}, { .compatible = "qcom,sc8180x-cdsp-pas", .data = &sm8150_cdsp_resource}, { .compatible = "qcom,sc8180x-mpss-pas", .data = &sc8180x_mpss_resource}, -- cgit From c42c0a5e97d154a05b8a40055f21a37bd1cade46 Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Fri, 17 Sep 2021 19:25:28 +0530 Subject: dt-bindings: remoteproc: qcom: Update Q6V5 Modem PIL binding Add a new modem compatible string for QTI SC7280 SoCs and introduce the "qcom,ext-regs" and "qcom,qaccept-regs" properties needed by the modem sub-system running on SC7280 SoCs. Signed-off-by: Sibi Sankar Acked-by: Rob Herring Reviewed-by: Stephen Boyd Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/1631886935-14691-4-git-send-email-sibis@codeaurora.org --- .../devicetree/bindings/remoteproc/qcom,q6v5.txt | 32 ++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt b/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt index 494257010629..8f1507052afd 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt +++ b/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt @@ -15,6 +15,7 @@ on the Qualcomm Hexagon core. "qcom,msm8996-mss-pil" "qcom,msm8998-mss-pil" "qcom,sc7180-mss-pil" + "qcom,sc7280-mss-pil" "qcom,sdm845-mss-pil" - reg: @@ -47,6 +48,7 @@ on the Qualcomm Hexagon core. qcom,msm8996-mss-pil: qcom,msm8998-mss-pil: qcom,sc7180-mss-pil: + qcom,sc7280-mss-pil: qcom,sdm845-mss-pil: must be "wdog", "fatal", "ready", "handover", "stop-ack", "shutdown-ack" @@ -87,6 +89,8 @@ on the Qualcomm Hexagon core. qcom,sc7180-mss-pil: must be "iface", "bus", "xo", "snoc_axi", "mnoc_axi", "nav" + qcom,sc7280-mss-pil: + must be "iface", "xo", "snoc_axi", "offline", "pka" qcom,sdm845-mss-pil: must be "iface", "bus", "mem", "xo", "gpll0_mss", "snoc_axi", "mnoc_axi", "prng" @@ -98,7 +102,7 @@ on the Qualcomm Hexagon core. reference to the list of 3 reset-controllers for the wcss sub-system reference to the list of 2 reset-controllers for the modem - sub-system on SC7180, SDM845 SoCs + sub-system on SC7180, SC7280, SDM845 SoCs - reset-names: Usage: required @@ -107,7 +111,7 @@ on the Qualcomm Hexagon core. must be "wcss_aon_reset", "wcss_reset", "wcss_q6_reset" for the wcss sub-system must be "mss_restart", "pdc_reset" for the modem - sub-system on SC7180, SDM845 SoCs + sub-system on SC7180, SC7280, SDM845 SoCs For devices where the mba and mpss sub-nodes are not specified, mba/mpss region should be referenced as follows: @@ -173,6 +177,9 @@ For the compatible string below the following supplies are required: qcom,msm8998-mss-pil: must be "cx", "mx" qcom,sc7180-mss-pil: + must be "cx", "mx", "mss" + qcom,sc7280-mss-pil: + must be "cx", "mss" qcom,sdm845-mss-pil: must be "cx", "mx", "mss" @@ -198,6 +205,9 @@ For the compatible string below the following supplies are required: Definition: a phandle reference to a syscon representing TCSR followed by the three offsets within syscon for q6, modem and nc halt registers. + a phandle reference to a syscon representing TCSR followed + by the four offsets within syscon for q6, modem, nc and vq6 + halt registers on SC7280 SoCs. For the compatible strings below the following phandle references are required: "qcom,sc7180-mss-pil" @@ -208,6 +218,24 @@ For the compatible strings below the following phandle references are required: by the offset within syscon for conn_box_spare0 register used by the modem sub-system running on SC7180 SoC. +For the compatible strings below the following phandle references are required: + "qcom,sc7280-mss-pil" +- qcom,ext-regs: + Usage: required + Value type: + Definition: two phandle references to syscons representing TCSR_REG and + TCSR register space followed by the two offsets within the syscon + to force_clk_en/rscc_disable and axim1_clk_off/crypto_clk_off + registers respectively. + +- qcom,qaccept-regs: + Usage: required + Value type: + Definition: a phandle reference to a syscon representing TCSR followed + by the three offsets within syscon for mdm, cx and axi + qaccept registers used by the modem sub-system running on + SC7280 SoC. + The Hexagon node must contain iommus property as described in ../iommu/iommu.txt on platforms which do not have TrustZone. -- cgit From c842379d00f1595bb5a025f24de016f7b937cd59 Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Fri, 17 Sep 2021 19:25:30 +0530 Subject: remoteproc: mss: q6v5-mss: Add modem support on SC7280 Add out of reset sequence support for modem sub-system on SC7280 SoCs. It requires access to an additional set of qaccept registers, external power/clk control registers and halt vq6 register to put the modem back into reset. Signed-off-by: Sibi Sankar Reviewed-by: Stephen Boyd Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/1631886935-14691-6-git-send-email-sibis@codeaurora.org --- drivers/remoteproc/qcom_q6v5_mss.c | 253 ++++++++++++++++++++++++++++++++++++- 1 file changed, 249 insertions(+), 4 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 7a1422bd7925..ec0701126ab3 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -77,6 +77,14 @@ #define HALT_ACK_TIMEOUT_US 100000 +/* QACCEPT Register Offsets */ +#define QACCEPT_ACCEPT_REG 0x0 +#define QACCEPT_ACTIVE_REG 0x4 +#define QACCEPT_DENY_REG 0x8 +#define QACCEPT_REQ_REG 0xC + +#define QACCEPT_TIMEOUT_US 50 + /* QDSP6SS_RESET */ #define Q6SS_STOP_CORE BIT(0) #define Q6SS_CORE_ARES BIT(1) @@ -143,6 +151,9 @@ struct rproc_hexagon_res { bool has_alt_reset; bool has_mba_logs; bool has_spare_reg; + bool has_qaccept_regs; + bool has_ext_cntl_regs; + bool has_vq6; }; struct q6v5 { @@ -158,8 +169,18 @@ struct q6v5 { u32 halt_q6; u32 halt_modem; u32 halt_nc; + u32 halt_vq6; u32 conn_box; + u32 qaccept_mdm; + u32 qaccept_cx; + u32 qaccept_axi; + + u32 axim1_clk_off; + u32 crypto_clk_off; + u32 force_clk_on; + u32 rscc_disable; + struct reset_control *mss_restart; struct reset_control *pdc_reset; @@ -201,6 +222,9 @@ struct q6v5 { bool has_alt_reset; bool has_mba_logs; bool has_spare_reg; + bool has_qaccept_regs; + bool has_ext_cntl_regs; + bool has_vq6; int mpss_perm; int mba_perm; const char *hexagon_mdt_image; @@ -213,6 +237,7 @@ enum { MSS_MSM8996, MSS_MSM8998, MSS_SC7180, + MSS_SC7280, MSS_SDM845, }; @@ -473,6 +498,12 @@ static int q6v5_reset_assert(struct q6v5 *qproc) regmap_update_bits(qproc->conn_map, qproc->conn_box, AXI_GATING_VALID_OVERRIDE, 0); ret = reset_control_deassert(qproc->mss_restart); + } else if (qproc->has_ext_cntl_regs) { + regmap_write(qproc->conn_map, qproc->rscc_disable, 0); + reset_control_assert(qproc->pdc_reset); + reset_control_assert(qproc->mss_restart); + reset_control_deassert(qproc->pdc_reset); + ret = reset_control_deassert(qproc->mss_restart); } else { ret = reset_control_assert(qproc->mss_restart); } @@ -490,7 +521,7 @@ static int q6v5_reset_deassert(struct q6v5 *qproc) ret = reset_control_reset(qproc->mss_restart); writel(0, qproc->rmb_base + RMB_MBA_ALT_RESET); reset_control_deassert(qproc->pdc_reset); - } else if (qproc->has_spare_reg) { + } else if (qproc->has_spare_reg || qproc->has_ext_cntl_regs) { ret = reset_control_reset(qproc->mss_restart); } else { ret = reset_control_deassert(qproc->mss_restart); @@ -604,7 +635,7 @@ static int q6v5proc_reset(struct q6v5 *qproc) } goto pbl_wait; - } else if (qproc->version == MSS_SC7180) { + } else if (qproc->version == MSS_SC7180 || qproc->version == MSS_SC7280) { val = readl(qproc->reg_base + QDSP6SS_SLEEP); val |= Q6SS_CBCR_CLKEN; writel(val, qproc->reg_base + QDSP6SS_SLEEP); @@ -787,6 +818,89 @@ pbl_wait: return ret; } +static int q6v5proc_enable_qchannel(struct q6v5 *qproc, struct regmap *map, u32 offset) +{ + unsigned int val; + int ret; + + if (!qproc->has_qaccept_regs) + return 0; + + if (qproc->has_ext_cntl_regs) { + regmap_write(qproc->conn_map, qproc->rscc_disable, 0); + regmap_write(qproc->conn_map, qproc->force_clk_on, 1); + + ret = regmap_read_poll_timeout(qproc->halt_map, qproc->axim1_clk_off, val, + !val, 1, Q6SS_CBCR_TIMEOUT_US); + if (ret) { + dev_err(qproc->dev, "failed to enable axim1 clock\n"); + return -ETIMEDOUT; + } + } + + regmap_write(map, offset + QACCEPT_REQ_REG, 1); + + /* Wait for accept */ + ret = regmap_read_poll_timeout(map, offset + QACCEPT_ACCEPT_REG, val, val, 5, + QACCEPT_TIMEOUT_US); + if (ret) { + dev_err(qproc->dev, "qchannel enable failed\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static void q6v5proc_disable_qchannel(struct q6v5 *qproc, struct regmap *map, u32 offset) +{ + int ret; + unsigned int val, retry; + unsigned int nretry = 10; + bool takedown_complete = false; + + if (!qproc->has_qaccept_regs) + return; + + while (!takedown_complete && nretry) { + nretry--; + + /* Wait for active transactions to complete */ + regmap_read_poll_timeout(map, offset + QACCEPT_ACTIVE_REG, val, !val, 5, + QACCEPT_TIMEOUT_US); + + /* Request Q-channel transaction takedown */ + regmap_write(map, offset + QACCEPT_REQ_REG, 0); + + /* + * If the request is denied, reset the Q-channel takedown request, + * wait for active transactions to complete and retry takedown. + */ + retry = 10; + while (retry) { + usleep_range(5, 10); + retry--; + ret = regmap_read(map, offset + QACCEPT_DENY_REG, &val); + if (!ret && val) { + regmap_write(map, offset + QACCEPT_REQ_REG, 1); + break; + } + + ret = regmap_read(map, offset + QACCEPT_ACCEPT_REG, &val); + if (!ret && !val) { + takedown_complete = true; + break; + } + } + + if (!retry) + break; + } + + /* Rely on mss_restart to clear out pending transactions on takedown failure */ + if (!takedown_complete) + dev_err(qproc->dev, "qchannel takedown failed\n"); +} + static void q6v5proc_halt_axi_port(struct q6v5 *qproc, struct regmap *halt_map, u32 offset) @@ -950,6 +1064,12 @@ static int q6v5_mba_load(struct q6v5 *qproc) goto assert_reset; } + ret = q6v5proc_enable_qchannel(qproc, qproc->halt_map, qproc->qaccept_axi); + if (ret) { + dev_err(qproc->dev, "failed to enable axi bridge\n"); + goto disable_active_clks; + } + /* * Some versions of the MBA firmware will upon boot wipe the MPSS region as well, so provide * the Q6 access to this region. @@ -996,8 +1116,13 @@ static int q6v5_mba_load(struct q6v5 *qproc) halt_axi_ports: q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6); + if (qproc->has_vq6) + q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_vq6); q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem); q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc); + q6v5proc_disable_qchannel(qproc, qproc->halt_map, qproc->qaccept_mdm); + q6v5proc_disable_qchannel(qproc, qproc->halt_map, qproc->qaccept_cx); + q6v5proc_disable_qchannel(qproc, qproc->halt_map, qproc->qaccept_axi); mba_load_err = true; reclaim_mba: xfermemop_ret = q6v5_xfer_mem_ownership(qproc, &qproc->mba_perm, true, @@ -1047,6 +1172,8 @@ static void q6v5_mba_reclaim(struct q6v5 *qproc) qproc->dp_size = 0; q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6); + if (qproc->has_vq6) + q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_vq6); q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem); q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc); if (qproc->version == MSS_MSM8996) { @@ -1059,6 +1186,24 @@ static void q6v5_mba_reclaim(struct q6v5 *qproc) writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); } + if (qproc->has_ext_cntl_regs) { + regmap_write(qproc->conn_map, qproc->rscc_disable, 1); + + ret = regmap_read_poll_timeout(qproc->halt_map, qproc->axim1_clk_off, val, + !val, 1, Q6SS_CBCR_TIMEOUT_US); + if (ret) + dev_err(qproc->dev, "failed to enable axim1 clock\n"); + + ret = regmap_read_poll_timeout(qproc->halt_map, qproc->crypto_clk_off, val, + !val, 1, Q6SS_CBCR_TIMEOUT_US); + if (ret) + dev_err(qproc->dev, "failed to enable crypto clock\n"); + } + + q6v5proc_disable_qchannel(qproc, qproc->halt_map, qproc->qaccept_mdm); + q6v5proc_disable_qchannel(qproc, qproc->halt_map, qproc->qaccept_cx); + q6v5proc_disable_qchannel(qproc, qproc->halt_map, qproc->qaccept_axi); + q6v5_reset_assert(qproc); q6v5_clk_disable(qproc->dev, qproc->reset_clks, @@ -1471,6 +1616,7 @@ static int q6v5_init_mem(struct q6v5 *qproc, struct platform_device *pdev) { struct of_phandle_args args; struct resource *res; + int halt_cell_cnt = 3; int ret; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6"); @@ -1483,8 +1629,11 @@ static int q6v5_init_mem(struct q6v5 *qproc, struct platform_device *pdev) if (IS_ERR(qproc->rmb_base)) return PTR_ERR(qproc->rmb_base); + if (qproc->has_vq6) + halt_cell_cnt++; + ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, - "qcom,halt-regs", 3, 0, &args); + "qcom,halt-regs", halt_cell_cnt, 0, &args); if (ret < 0) { dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n"); return -EINVAL; @@ -1499,6 +1648,52 @@ static int q6v5_init_mem(struct q6v5 *qproc, struct platform_device *pdev) qproc->halt_modem = args.args[1]; qproc->halt_nc = args.args[2]; + if (qproc->has_vq6) + qproc->halt_vq6 = args.args[3]; + + if (qproc->has_qaccept_regs) { + ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, + "qcom,qaccept-regs", + 3, 0, &args); + if (ret < 0) { + dev_err(&pdev->dev, "failed to parse qaccept-regs\n"); + return -EINVAL; + } + + qproc->qaccept_mdm = args.args[0]; + qproc->qaccept_cx = args.args[1]; + qproc->qaccept_axi = args.args[2]; + } + + if (qproc->has_ext_cntl_regs) { + ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, + "qcom,ext-regs", + 2, 0, &args); + if (ret < 0) { + dev_err(&pdev->dev, "failed to parse ext-regs index 0\n"); + return -EINVAL; + } + + qproc->conn_map = syscon_node_to_regmap(args.np); + of_node_put(args.np); + if (IS_ERR(qproc->conn_map)) + return PTR_ERR(qproc->conn_map); + + qproc->force_clk_on = args.args[0]; + qproc->rscc_disable = args.args[1]; + + ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, + "qcom,ext-regs", + 2, 1, &args); + if (ret < 0) { + dev_err(&pdev->dev, "failed to parse ext-regs index 1\n"); + return -EINVAL; + } + + qproc->axim1_clk_off = args.args[0]; + qproc->crypto_clk_off = args.args[1]; + } + if (qproc->has_spare_reg) { ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, "qcom,spare-regs", @@ -1590,7 +1785,7 @@ static int q6v5_init_reset(struct q6v5 *qproc) return PTR_ERR(qproc->mss_restart); } - if (qproc->has_alt_reset || qproc->has_spare_reg) { + if (qproc->has_alt_reset || qproc->has_spare_reg || qproc->has_ext_cntl_regs) { qproc->pdc_reset = devm_reset_control_get_exclusive(qproc->dev, "pdc_reset"); if (IS_ERR(qproc->pdc_reset)) { @@ -1697,6 +1892,9 @@ static int q6v5_probe(struct platform_device *pdev) platform_set_drvdata(pdev, qproc); + qproc->has_qaccept_regs = desc->has_qaccept_regs; + qproc->has_ext_cntl_regs = desc->has_ext_cntl_regs; + qproc->has_vq6 = desc->has_vq6; qproc->has_spare_reg = desc->has_spare_reg; ret = q6v5_init_mem(qproc, pdev); if (ret) @@ -1857,9 +2055,40 @@ static const struct rproc_hexagon_res sc7180_mss = { .has_alt_reset = false, .has_mba_logs = true, .has_spare_reg = true, + .has_qaccept_regs = false, + .has_ext_cntl_regs = false, + .has_vq6 = false, .version = MSS_SC7180, }; +static const struct rproc_hexagon_res sc7280_mss = { + .hexagon_mba_image = "mba.mbn", + .proxy_clk_names = (char*[]){ + "xo", + "pka", + NULL + }, + .active_clk_names = (char*[]){ + "iface", + "offline", + "snoc_axi", + NULL + }, + .proxy_pd_names = (char*[]){ + "cx", + "mss", + NULL + }, + .need_mem_protection = true, + .has_alt_reset = false, + .has_mba_logs = true, + .has_spare_reg = false, + .has_qaccept_regs = true, + .has_ext_cntl_regs = true, + .has_vq6 = true, + .version = MSS_SC7280, +}; + static const struct rproc_hexagon_res sdm845_mss = { .hexagon_mba_image = "mba.mbn", .proxy_clk_names = (char*[]){ @@ -1889,6 +2118,9 @@ static const struct rproc_hexagon_res sdm845_mss = { .has_alt_reset = true, .has_mba_logs = false, .has_spare_reg = false, + .has_qaccept_regs = false, + .has_ext_cntl_regs = false, + .has_vq6 = false, .version = MSS_SDM845, }; @@ -1917,6 +2149,9 @@ static const struct rproc_hexagon_res msm8998_mss = { .has_alt_reset = false, .has_mba_logs = false, .has_spare_reg = false, + .has_qaccept_regs = false, + .has_ext_cntl_regs = false, + .has_vq6 = false, .version = MSS_MSM8998, }; @@ -1948,6 +2183,9 @@ static const struct rproc_hexagon_res msm8996_mss = { .has_alt_reset = false, .has_mba_logs = false, .has_spare_reg = false, + .has_qaccept_regs = false, + .has_ext_cntl_regs = false, + .has_vq6 = false, .version = MSS_MSM8996, }; @@ -1990,6 +2228,9 @@ static const struct rproc_hexagon_res msm8916_mss = { .has_alt_reset = false, .has_mba_logs = false, .has_spare_reg = false, + .has_qaccept_regs = false, + .has_ext_cntl_regs = false, + .has_vq6 = false, .version = MSS_MSM8916, }; @@ -2040,6 +2281,9 @@ static const struct rproc_hexagon_res msm8974_mss = { .has_alt_reset = false, .has_mba_logs = false, .has_spare_reg = false, + .has_qaccept_regs = false, + .has_ext_cntl_regs = false, + .has_vq6 = false, .version = MSS_MSM8974, }; @@ -2050,6 +2294,7 @@ static const struct of_device_id q6v5_of_match[] = { { .compatible = "qcom,msm8996-mss-pil", .data = &msm8996_mss}, { .compatible = "qcom,msm8998-mss-pil", .data = &msm8998_mss}, { .compatible = "qcom,sc7180-mss-pil", .data = &sc7180_mss}, + { .compatible = "qcom,sc7280-mss-pil", .data = &sc7280_mss}, { .compatible = "qcom,sdm845-mss-pil", .data = &sdm845_mss}, { }, }; -- cgit From 0e46c8307574a8e2dac8d7ba97e0f6f4bbee67a5 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 28 Sep 2021 14:15:01 -0300 Subject: perf jevents: Add __maybe_unused attribute to unused function arg The tools/perf/pmu-events/jevents.c file isn't being compiled with -Werror and -Wextra, which will be the case soon, so before we turn those compiler flags on, fix what it would flag. Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Jiri Olsa Cc: Like Xu Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Signed-off-by: Arnaldo Carvalho de Melo To: John Garry --- tools/perf/pmu-events/jevents.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/perf/pmu-events/jevents.c b/tools/perf/pmu-events/jevents.c index 6731b3cf0c2f..323e1dfe2436 100644 --- a/tools/perf/pmu-events/jevents.c +++ b/tools/perf/pmu-events/jevents.c @@ -45,6 +45,7 @@ #include /* getrlimit */ #include #include +#include #include #include "jsmn.h" #include "json.h" @@ -470,7 +471,7 @@ static void free_arch_std_events(void) } } -static int save_arch_std_events(void *data, struct json_event *je) +static int save_arch_std_events(void *data __maybe_unused, struct json_event *je) { struct event_struct *es; -- cgit From 9a0a1417d3bb91dba9f95fef9771954ff72ede19 Mon Sep 17 00:00:00 2001 From: Pranay Sanghai Date: Sat, 18 Sep 2021 13:18:02 -0700 Subject: PCI: Tidy comments Make comments follow multi-line comment conventions. No functional change intended. Link: https://lore.kernel.org/r/YUZJenW2UCA4Qu0O@pranay-desktop Signed-off-by: Pranay Sanghai Signed-off-by: Bjorn Helgaas --- drivers/pci/setup-irq.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c index 7129494754dd..cc7d26b015f3 100644 --- a/drivers/pci/setup-irq.c +++ b/drivers/pci/setup-irq.c @@ -8,7 +8,6 @@ * David Miller (davem@redhat.com) */ - #include #include #include @@ -28,25 +27,26 @@ void pci_assign_irq(struct pci_dev *dev) return; } - /* If this device is not on the primary bus, we need to figure out - which interrupt pin it will come in on. We know which slot it - will come in on 'cos that slot is where the bridge is. Each - time the interrupt line passes through a PCI-PCI bridge we must - apply the swizzle function. */ - + /* + * If this device is not on the primary bus, we need to figure out + * which interrupt pin it will come in on. We know which slot it + * will come in on because that slot is where the bridge is. Each + * time the interrupt line passes through a PCI-PCI bridge we must + * apply the swizzle function. + */ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); /* Cope with illegal. */ if (pin > 4) pin = 1; if (pin) { - /* Follow the chain of bridges, swizzling as we go. */ + /* Follow the chain of bridges, swizzling as we go. */ if (hbrg->swizzle_irq) slot = (*(hbrg->swizzle_irq))(dev, &pin); /* - * If a swizzling function is not used map_irq must - * ignore slot + * If a swizzling function is not used, map_irq() must + * ignore slot. */ irq = (*(hbrg->map_irq))(dev, slot, pin); if (irq == -1) @@ -56,7 +56,9 @@ void pci_assign_irq(struct pci_dev *dev) pci_dbg(dev, "assign IRQ: got %d\n", dev->irq); - /* Always tell the device, so the driver knows what is - the real IRQ to use; the device does not use it. */ + /* + * Always tell the device, so the driver knows what is the real IRQ + * to use; the device does not use it. + */ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); } -- cgit From 4a87dea9e60fe10079f01e06a58c4f9dfb667940 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 17 Sep 2021 11:42:39 -0700 Subject: perf test: Workload test of metric and metricgroups Test every metric and metricgroup with 'true' as a workload. For metrics, check that we see the metric printed or get unsupported. If the 'true' workload executes too quickly retry with 'perf bench internals synthesize'. v3. Fix test condition (thanks to Paul A. Clarke ). Add a fallback case of a larger workload so that we don't ignore "". v2. Switched the workload to something faster. Signed-off-by: Ian Rogers Reviewed-by: John Garry Cc: Alexander Shishkin Cc: Jin Yao Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Paul Clarke Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lore.kernel.org/lkml/20210917184240.2181186-1-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/stat_all_metricgroups.sh | 12 ++++++++++++ tools/perf/tests/shell/stat_all_metrics.sh | 22 ++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100755 tools/perf/tests/shell/stat_all_metricgroups.sh create mode 100755 tools/perf/tests/shell/stat_all_metrics.sh diff --git a/tools/perf/tests/shell/stat_all_metricgroups.sh b/tools/perf/tests/shell/stat_all_metricgroups.sh new file mode 100755 index 000000000000..de24d374ce24 --- /dev/null +++ b/tools/perf/tests/shell/stat_all_metricgroups.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# perf all metricgroups test +# SPDX-License-Identifier: GPL-2.0 + +set -e + +for m in $(perf list --raw-dump metricgroups); do + echo "Testing $m" + perf stat -M "$m" true +done + +exit 0 diff --git a/tools/perf/tests/shell/stat_all_metrics.sh b/tools/perf/tests/shell/stat_all_metrics.sh new file mode 100755 index 000000000000..7f4ba3cad632 --- /dev/null +++ b/tools/perf/tests/shell/stat_all_metrics.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# perf all metrics test +# SPDX-License-Identifier: GPL-2.0 + +set -e + +for m in $(perf list --raw-dump metrics); do + echo "Testing $m" + result=$(perf stat -M "$m" true 2>&1) + if [[ ! "$result" =~ "$m" ]] && [[ ! "$result" =~ "" ]]; then + # We failed to see the metric and the events are support. Possibly the + # workload was too small so retry with something longer. + result=$(perf stat -M "$m" perf bench internals synthesize 2>&1) + if [[ ! "$result" =~ "$m" ]]; then + echo "Metric '$m' not printed in:" + echo "$result" + exit 1 + fi + fi +done + +exit 0 -- cgit From 3d5ac9effcc640d5d66bc6d833e1dcc9faa279aa Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 17 Sep 2021 11:42:40 -0700 Subject: perf test: Workload test of all PMUs Iterate over the list of PMUs and run the 'true' workload on them. If the event isn't printed then run the large 'perf bench internals synthesize' workload and check the event is counted. On a Skylake this test takes 1m15s mainly running the 'true' workload. Suggested-by: John Garry Signed-off-by: Ian Rogers Reviewed-by: John Garry Cc: Alexander Shishkin Cc: Jin Yao Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Paul Clarke Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lore.kernel.org/lkml/20210917184240.2181186-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/stat_all_pmu.sh | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100755 tools/perf/tests/shell/stat_all_pmu.sh diff --git a/tools/perf/tests/shell/stat_all_pmu.sh b/tools/perf/tests/shell/stat_all_pmu.sh new file mode 100755 index 000000000000..2de7fd0394fd --- /dev/null +++ b/tools/perf/tests/shell/stat_all_pmu.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# perf all PMU test +# SPDX-License-Identifier: GPL-2.0 + +set -e + +for p in $(perf list --raw-dump pmu); do + echo "Testing $p" + result=$(perf stat -e "$p" true 2>&1) + if [[ ! "$result" =~ "$p" ]] && [[ ! "$result" =~ "" ]]; then + # We failed to see the event and it is supported. Possibly the workload was + # too small so retry with something longer. + result=$(perf stat -e "$p" perf bench internals synthesize 2>&1) + if [[ ! "$result" =~ "$p" ]]; then + echo "Event '$p' not printed in:" + echo "$result" + exit 1 + fi + fi +done + +exit 0 -- cgit From 70a9ac36ffd807ac506ed0b849f3e8ce3c6623f2 Mon Sep 17 00:00:00 2001 From: Gao Xiang Date: Tue, 21 Sep 2021 22:37:30 +0800 Subject: f2fs: fix up f2fs_lookup tracepoints Fix up a misuse that the filename pointer isn't always valid in the ring buffer, and we should copy the content instead. Fixes: 0c5e36db17f5 ("f2fs: trace f2fs_lookup") Signed-off-by: Gao Xiang Signed-off-by: Jaegeuk Kim --- include/trace/events/f2fs.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h index 4e881d91c874..4cb055af1ec0 100644 --- a/include/trace/events/f2fs.h +++ b/include/trace/events/f2fs.h @@ -807,20 +807,20 @@ TRACE_EVENT(f2fs_lookup_start, TP_STRUCT__entry( __field(dev_t, dev) __field(ino_t, ino) - __field(const char *, name) + __string(name, dentry->d_name.name) __field(unsigned int, flags) ), TP_fast_assign( __entry->dev = dir->i_sb->s_dev; __entry->ino = dir->i_ino; - __entry->name = dentry->d_name.name; + __assign_str(name, dentry->d_name.name); __entry->flags = flags; ), TP_printk("dev = (%d,%d), pino = %lu, name:%s, flags:%u", show_dev_ino(__entry), - __entry->name, + __get_str(name), __entry->flags) ); @@ -834,7 +834,7 @@ TRACE_EVENT(f2fs_lookup_end, TP_STRUCT__entry( __field(dev_t, dev) __field(ino_t, ino) - __field(const char *, name) + __string(name, dentry->d_name.name) __field(nid_t, cino) __field(int, err) ), @@ -842,14 +842,14 @@ TRACE_EVENT(f2fs_lookup_end, TP_fast_assign( __entry->dev = dir->i_sb->s_dev; __entry->ino = dir->i_ino; - __entry->name = dentry->d_name.name; + __assign_str(name, dentry->d_name.name); __entry->cino = ino; __entry->err = err; ), TP_printk("dev = (%d,%d), pino = %lu, name:%s, ino:%u, err:%d", show_dev_ino(__entry), - __entry->name, + __get_str(name), __entry->cino, __entry->err) ); -- cgit From b758a61b391fb5ed749f4848f444d8223ae0a324 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 22 Sep 2021 17:10:21 -0700 Subject: perf tools: Enable libtracefs dynamic linking Currently libtracefs isn't used by perf, but there are potential improvements by using it as identified Steven Rostedt's e-mail: https://lore.kernel.org/lkml/20210610154759.1ef958f0@oasis.local.home/ This change is modelled on the dynamic libtraceevent patch by Michael Petlan: https://lore.kernel.org/linux-perf-users/20210428092023.4009-1-mpetlan@redhat.com/ v3. Adds file missed in v1 and v2 spotted by Jiri Olsa. Signed-off-by: Ian Rogers Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Steven Rostedt (VMware) Cc: Tzvetomir Stoyanov (VMware) Cc: linux-trace-devel@vger.kernel.org Link: http://lore.kernel.org/lkml/20210923001024.550263-1-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/build/Makefile.feature | 1 + tools/build/feature/Makefile | 4 ++++ tools/build/feature/test-libtracefs.c | 10 ++++++++++ tools/perf/Makefile.config | 9 +++++++++ tools/perf/Makefile.perf | 2 ++ 5 files changed, 26 insertions(+) create mode 100644 tools/build/feature/test-libtracefs.c diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature index 3dd2f68366f9..45a9a59828c3 100644 --- a/tools/build/Makefile.feature +++ b/tools/build/Makefile.feature @@ -52,6 +52,7 @@ FEATURE_TESTS_BASIC := \ libslang \ libslang-include-subdir \ libtraceevent \ + libtracefs \ libcrypto \ libunwind \ pthread-attr-setaffinity-np \ diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile index eff55d287db1..d024b5204ba0 100644 --- a/tools/build/feature/Makefile +++ b/tools/build/feature/Makefile @@ -36,6 +36,7 @@ FILES= \ test-libslang.bin \ test-libslang-include-subdir.bin \ test-libtraceevent.bin \ + test-libtracefs.bin \ test-libcrypto.bin \ test-libunwind.bin \ test-libunwind-debug-frame.bin \ @@ -199,6 +200,9 @@ $(OUTPUT)test-libslang-include-subdir.bin: $(OUTPUT)test-libtraceevent.bin: $(BUILD) -ltraceevent +$(OUTPUT)test-libtracefs.bin: + $(BUILD) -ltracefs + $(OUTPUT)test-libcrypto.bin: $(BUILD) -lcrypto diff --git a/tools/build/feature/test-libtracefs.c b/tools/build/feature/test-libtracefs.c new file mode 100644 index 000000000000..8eff16c0c10b --- /dev/null +++ b/tools/build/feature/test-libtracefs.c @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 +#include + +int main(void) +{ + struct tracefs_instance *inst = tracefs_instance_create("dummy"); + + tracefs_instance_destroy(inst); + return 0; +} diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 446180401e26..00ec900ddbca 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -1098,6 +1098,15 @@ ifdef LIBTRACEEVENT_DYNAMIC endif endif +ifdef LIBTRACEFS_DYNAMIC + $(call feature_check,libtracefs) + ifeq ($(feature-libtracefs), 1) + EXTLIBS += -ltracefs + else + dummy := $(error Error: No libtracefs devel library found, please install libtracefs-dev); + endif +endif + # Among the variables below, these: # perfexecdir # perf_include_dir diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index e04313c4d840..7df13e74450c 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -130,6 +130,8 @@ include ../scripts/utilities.mak # # Define LIBTRACEEVENT_DYNAMIC to enable libtraceevent dynamic linking # +# Define LIBTRACEFS_DYNAMIC to enable libtracefs dynamic linking +# # As per kernel Makefile, avoid funny character set dependencies unexport LC_ALL -- cgit From 569715164ba2125cf5014aa6de7154ebdb95fef4 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 22 Sep 2021 17:10:22 -0700 Subject: perf tools: Add define for libtraceevent version The definition is derived from pkg-config as discussed in: https://lore.kernel.org/lkml/20210610155915.20a252d3@oasis.local.home/ The definition is computed using expr rather than passed to be computed in C code, this avoids complications with quote in the variable expansions. For example see the target python/perf.so in Makefile.perf. Signed-off-by: Ian Rogers Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Steven Rostedt (VMware) Cc: Tzvetomir Stoyanov (VMware) Cc: linux-trace-devel@vger.kernel.org Link: http://lore.kernel.org/lkml/20210923001024.550263-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.config | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 00ec900ddbca..2001c315f0db 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -1093,6 +1093,12 @@ ifdef LIBTRACEEVENT_DYNAMIC $(call feature_check,libtraceevent) ifeq ($(feature-libtraceevent), 1) EXTLIBS += -ltraceevent + LIBTRACEEVENT_VERSION := $(shell $(PKG_CONFIG) --modversion libtraceevent) + LIBTRACEEVENT_VERSION_1 := $(word 1, $(subst ., ,$(LIBTRACEEVENT_VERSION))) + LIBTRACEEVENT_VERSION_2 := $(word 2, $(subst ., ,$(LIBTRACEEVENT_VERSION))) + LIBTRACEEVENT_VERSION_3 := $(word 3, $(subst ., ,$(LIBTRACEEVENT_VERSION))) + LIBTRACEEVENT_VERSION_CPP := $(shell expr $(LIBTRACEEVENT_VERSION_1) \* 255 \* 255 + $(LIBTRACEEVENT_VERSION_2) \* 255 + $(LIBTRACEEVENT_VERSION_3)) + CFLAGS += -DLIBTRACEEVENT_VERSION=$(LIBTRACEEVENT_VERSION_CPP) else dummy := $(error Error: No libtraceevent devel library found, please install libtraceevent-devel); endif -- cgit From 359cad09e40bedf927ea6046d27ccf977c83b71a Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 22 Sep 2021 17:10:23 -0700 Subject: perf tools: Add define for libtracefs version This will allow version specific support of libtracefs. Signed-off-by: Ian Rogers Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Steven Rostedt (VMware) Cc: Tzvetomir Stoyanov (VMware) Cc: linux-trace-devel@vger.kernel.org Link: http://lore.kernel.org/lkml/20210923001024.550263-3-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.config | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 2001c315f0db..0ae2e3d8b832 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -1108,6 +1108,12 @@ ifdef LIBTRACEFS_DYNAMIC $(call feature_check,libtracefs) ifeq ($(feature-libtracefs), 1) EXTLIBS += -ltracefs + LIBTRACEFS_VERSION := $(shell $(PKG_CONFIG) --modversion libtracefs) + LIBTRACEFS_VERSION_1 := $(word 1, $(subst ., ,$(LIBTRACEFS_VERSION))) + LIBTRACEFS_VERSION_2 := $(word 2, $(subst ., ,$(LIBTRACEFS_VERSION))) + LIBTRACEFS_VERSION_3 := $(word 3, $(subst ., ,$(LIBTRACEFS_VERSION))) + LIBTRACEFS_VERSION_CPP := $(shell expr $(LIBTRACEFS_VERSION_1) \* 255 \* 255 + $(LIBTRACEFS_VERSION_2) \* 255 + $(LIBTRACEFS_VERSION_3)) + CFLAGS += -DLIBTRACEFS_VERSION=$(LIBTRACEFS_VERSION_CPP) else dummy := $(error Error: No libtracefs devel library found, please install libtracefs-dev); endif -- cgit From 08efcb4a638d260ef7fcbae64ecf7ceceb3f1841 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 22 Sep 2021 17:10:24 -0700 Subject: libtraceevent: Increase libtraceevent logging when verbose libtraceevent has added more levels of debug printout and with changes like: https://lore.kernel.org/linux-trace-devel/20210507095022.1079364-3-tz.stoyanov@gmail.com previously generated output like "registering plugin" is no longer displayed. This change makes it so that if perf's verbose debug output is enabled then the debug and info libtraceevent messages can be displayed. The code is conditionally enabled based on the libtraceevent version as discussed in the RFC: https://lore.kernel.org/lkml/20210610060643.595673-1-irogers@google.com/ v2. Is a rebase and handles the case of building without LIBTRACEEVENT_DYNAMIC. Signed-off-by: Ian Rogers Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Steven Rostedt (VMware) Cc: Tzvetomir Stoyanov (VMware) Cc: linux-trace-devel@vger.kernel.org Link: http://lore.kernel.org/lkml/20210923001024.550263-4-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/debug.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 2c06abf6dcd2..c7a9fa0ffae9 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -24,6 +24,16 @@ #include "util/parse-sublevel-options.h" #include +#include + +#define MAKE_LIBTRACEEVENT_VERSION(a, b, c) ((a)*255*255+(b)*255+(c)) +#ifndef LIBTRACEEVENT_VERSION +/* + * If LIBTRACEEVENT_VERSION wasn't computed then set to version 1.1.0 that ships + * with the Linux kernel tools. + */ +#define LIBTRACEEVENT_VERSION MAKE_LIBTRACEEVENT_VERSION(1, 1, 0) +#endif int verbose; int debug_peo_args; @@ -228,6 +238,15 @@ int perf_debug_option(const char *str) /* Allow only verbose value in range (0, 10), otherwise set 0. */ verbose = (verbose < 0) || (verbose > 10) ? 0 : verbose; +#if MAKE_LIBTRACEEVENT_VERSION(1, 3, 0) <= LIBTRACEEVENT_VERSION + if (verbose == 1) + tep_set_loglevel(TEP_LOG_INFO); + else if (verbose == 2) + tep_set_loglevel(TEP_LOG_DEBUG); + else if (verbose >= 3) + tep_set_loglevel(TEP_LOG_ALL); +#endif + return 0; } -- cgit From 4f9d4f8aa7328068a2f25cfb3d1d04c1b6fa54ac Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 16 Sep 2021 20:34:21 +0800 Subject: perf parse-events: Set numeric term config For numeric terms, the config field may be NULL as it is not set from the l+y parsing. Fix by setting the term config from the term type name. Also fix up the pmu-events test to set the alias strings to set the period term properly, and fix up parse-events test to check the term config string. Signed-off-by: John Garry Acked-by: Ian Rogers Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Jiri Olsa Cc: Leo Yan Cc: Mark Rutland Cc: Mathieu Poirier Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Shaokun Zhang Cc: Will Deacon Cc: linux-arm-kernel@lists.infradead.org Cc: linuxarm@huawei.com Cc: liuqi115@huawei.com Link: https://lore.kernel.org/r/1631795665-240946-2-git-send-email-john.garry@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/parse-events.c | 8 ++++---- tools/perf/tests/pmu-events.c | 6 +++--- tools/perf/util/parse-events.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index fd3556cc9ad4..8875e388563e 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -605,7 +605,7 @@ static int test__checkterms_simple(struct list_head *terms) TEST_ASSERT_VAL("wrong type val", term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); TEST_ASSERT_VAL("wrong val", term->val.num == 10); - TEST_ASSERT_VAL("wrong config", !term->config); + TEST_ASSERT_VAL("wrong config", !strcmp(term->config, "config")); /* config1 */ term = list_entry(term->list.next, struct parse_events_term, list); @@ -614,7 +614,7 @@ static int test__checkterms_simple(struct list_head *terms) TEST_ASSERT_VAL("wrong type val", term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); TEST_ASSERT_VAL("wrong val", term->val.num == 1); - TEST_ASSERT_VAL("wrong config", !term->config); + TEST_ASSERT_VAL("wrong config", !strcmp(term->config, "config1")); /* config2=3 */ term = list_entry(term->list.next, struct parse_events_term, list); @@ -623,7 +623,7 @@ static int test__checkterms_simple(struct list_head *terms) TEST_ASSERT_VAL("wrong type val", term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); TEST_ASSERT_VAL("wrong val", term->val.num == 3); - TEST_ASSERT_VAL("wrong config", !term->config); + TEST_ASSERT_VAL("wrong config", !strcmp(term->config, "config2")); /* umask=1*/ term = list_entry(term->list.next, struct parse_events_term, list); @@ -661,7 +661,7 @@ static int test__checkterms_simple(struct list_head *terms) TEST_ASSERT_VAL("wrong type val", term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); TEST_ASSERT_VAL("wrong val", term->val.num == 0xead); - TEST_ASSERT_VAL("wrong config", !term->config); + TEST_ASSERT_VAL("wrong config", !strcmp(term->config, "config")); return 0; } diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c index 43743cf719ef..8c5a6ba1cb14 100644 --- a/tools/perf/tests/pmu-events.c +++ b/tools/perf/tests/pmu-events.c @@ -67,7 +67,7 @@ static const struct perf_pmu_test_event segment_reg_loads_any = { .desc = "Number of segment register loads", .topic = "other", }, - .alias_str = "umask=0x80,(null)=0x30d40,event=0x6", + .alias_str = "umask=0x80,period=0x30d40,event=0x6", .alias_long_desc = "Number of segment register loads", }; @@ -78,7 +78,7 @@ static const struct perf_pmu_test_event dispatch_blocked_any = { .desc = "Memory cluster signals to block micro-op dispatch for any reason", .topic = "other", }, - .alias_str = "umask=0x20,(null)=0x30d40,event=0x9", + .alias_str = "umask=0x20,period=0x30d40,event=0x9", .alias_long_desc = "Memory cluster signals to block micro-op dispatch for any reason", }; @@ -89,7 +89,7 @@ static const struct perf_pmu_test_event eist_trans = { .desc = "Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions", .topic = "other", }, - .alias_str = "umask=0,(null)=0x30d40,event=0x3a", + .alias_str = "umask=0,period=0x30d40,event=0x3a", .alias_long_desc = "Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions", }; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 067f830dea4b..1acac3e13b32 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -3141,7 +3141,7 @@ int parse_events_term__num(struct parse_events_term **term, struct parse_events_term temp = { .type_val = PARSE_EVENTS__TERM_TYPE_NUM, .type_term = type_term, - .config = config, + .config = config ? : strdup(config_term_names[type_term]), .no_value = no_value, .err_term = loc_term ? loc_term->first_column : 0, .err_val = loc_val ? loc_val->first_column : 0, -- cgit From d60bad10c4ae42ef96b5b7dfd5924c54f3f257a6 Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 16 Sep 2021 20:34:22 +0800 Subject: perf jevents: Support ConfigCode Some PMUs use "config=XXX" for eventcodes, like: more /sys/bus/event_source/devices/hisi_sccl1_ddrc3/events/act_cmd config=0x5 However jevents would give an alias with .event field "event=0x5" for this event. This is handled without issue by the parse events code, but the pmu alias code gets a bit confused, as it warns about assigning "event=0x5" over "config=0x5" in perf_pmu_assign_str() when merging aliases: ./perf stat -v -e act_cmd ... alias act_cmd differs in field 'value' ... To make things a bit more straightforward, allow jevents to support "config=XXX" as well, by supporting a "ConfigCode" field. Signed-off-by: John Garry Acked-by: Ian Rogers Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Jiri Olsa Cc: Leo Yan Cc: Mark Rutland Cc: Mathieu Poirier Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Shaokun Zhang Cc: Will Deacon Cc: linux-arm-kernel@lists.infradead.org Cc: linuxarm@huawei.com Cc: liuqi115@huawei.com Link: https://lore.kernel.org/r/1631795665-240946-3-git-send-email-john.garry@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/pmu-events/jevents.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tools/perf/pmu-events/jevents.c b/tools/perf/pmu-events/jevents.c index 323e1dfe2436..19497e4f8a86 100644 --- a/tools/perf/pmu-events/jevents.c +++ b/tools/perf/pmu-events/jevents.c @@ -576,10 +576,12 @@ static int json_events(const char *fn, struct json_event je = {}; char *arch_std = NULL; unsigned long long eventcode = 0; + unsigned long long configcode = 0; struct msrmap *msr = NULL; jsmntok_t *msrval = NULL; jsmntok_t *precise = NULL; jsmntok_t *obj = tok++; + bool configcode_present = false; EXPECT(obj->type == JSMN_OBJECT, obj, "expected object"); for (j = 0; j < obj->size; j += 2) { @@ -602,6 +604,12 @@ static int json_events(const char *fn, addfield(map, &code, "", "", val); eventcode |= strtoul(code, NULL, 0); free(code); + } else if (json_streq(map, field, "ConfigCode")) { + char *code = NULL; + addfield(map, &code, "", "", val); + configcode |= strtoul(code, NULL, 0); + free(code); + configcode_present = true; } else if (json_streq(map, field, "ExtSel")) { char *code = NULL; addfield(map, &code, "", "", val); @@ -683,7 +691,10 @@ static int json_events(const char *fn, addfield(map, &extra_desc, " ", "(Precise event)", NULL); } - snprintf(buf, sizeof buf, "event=%#llx", eventcode); + if (configcode_present) + snprintf(buf, sizeof buf, "config=%#llx", configcode); + else + snprintf(buf, sizeof buf, "event=%#llx", eventcode); addfield(map, &event, ",", buf, NULL); if (je.desc && extra_desc) addfield(map, &je.desc, " ", extra_desc, NULL); -- cgit From 56be05103a408b7f56c5e75717b2b23a5adf1ddb Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 16 Sep 2021 20:34:23 +0800 Subject: perf test: Verify more event members in pmu-events test Function compare_pmu_events() does not compare all struct pmu-events members, so add tests for missing members "name", "event", "aggr_mod", "event", "metric_constraint", and "metric_group", and re-order the tests to match current struct pmu-events member ordering. Also fix uncore_hisi_l3c_rd_hit_cpipe.event member, now that we're actually testing it. Signed-off-by: John Garry Acked-by: Ian Rogers Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Jiri Olsa Cc: Leo Yan Cc: Mark Rutland Cc: Mathieu Poirier Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Shaokun Zhang Cc: Will Deacon Cc: linux-arm-kernel@lists.infradead.org Cc: linuxarm@huawei.com Cc: liuqi115@huawei.com Link: https://lore.kernel.org/r/1631795665-240946-4-git-send-email-john.garry@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/pmu-events.c | 50 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c index 8c5a6ba1cb14..adfc17f51c7b 100644 --- a/tools/perf/tests/pmu-events.c +++ b/tools/perf/tests/pmu-events.c @@ -146,7 +146,7 @@ static const struct perf_pmu_test_event unc_cbo_xsnp_response_miss_eviction = { static const struct perf_pmu_test_event uncore_hisi_l3c_rd_hit_cpipe = { .event = { .name = "uncore_hisi_l3c.rd_hit_cpipe", - .event = "event=0x2", + .event = "event=0x7", .desc = "Total read hits. Unit: hisi_sccl,l3c ", .topic = "uncore", .long_desc = "Total read hits", @@ -255,6 +255,24 @@ static struct pmu_event *__test_pmu_get_sys_events_table(void) static int compare_pmu_events(struct pmu_event *e1, const struct pmu_event *e2) { + if (!is_same(e1->name, e2->name)) { + pr_debug2("testing event e1 %s: mismatched name string, %s vs %s\n", + e1->name, e1->name, e2->name); + return -1; + } + + if (!is_same(e1->compat, e2->compat)) { + pr_debug2("testing event e1 %s: mismatched compat string, %s vs %s\n", + e1->name, e1->compat, e2->compat); + return -1; + } + + if (!is_same(e1->event, e2->event)) { + pr_debug2("testing event e1 %s: mismatched event, %s vs %s\n", + e1->name, e1->event, e2->event); + return -1; + } + if (!is_same(e1->desc, e2->desc)) { pr_debug2("testing event e1 %s: mismatched desc, %s vs %s\n", e1->name, e1->desc, e2->desc); @@ -273,6 +291,12 @@ static int compare_pmu_events(struct pmu_event *e1, const struct pmu_event *e2) return -1; } + if (!is_same(e1->pmu, e2->pmu)) { + pr_debug2("testing event e1 %s: mismatched pmu string, %s vs %s\n", + e1->name, e1->pmu, e2->pmu); + return -1; + } + if (!is_same(e1->unit, e2->unit)) { pr_debug2("testing event e1 %s: mismatched unit, %s vs %s\n", e1->name, e1->unit, e2->unit); @@ -285,6 +309,12 @@ static int compare_pmu_events(struct pmu_event *e1, const struct pmu_event *e2) return -1; } + if (!is_same(e1->aggr_mode, e2->aggr_mode)) { + pr_debug2("testing event e1 %s: mismatched aggr_mode, %s vs %s\n", + e1->name, e1->aggr_mode, e2->aggr_mode); + return -1; + } + if (!is_same(e1->metric_expr, e2->metric_expr)) { pr_debug2("testing event e1 %s: mismatched metric_expr, %s vs %s\n", e1->name, e1->metric_expr, e2->metric_expr); @@ -297,21 +327,21 @@ static int compare_pmu_events(struct pmu_event *e1, const struct pmu_event *e2) return -1; } - if (!is_same(e1->deprecated, e2->deprecated)) { - pr_debug2("testing event e1 %s: mismatched deprecated, %s vs %s\n", - e1->name, e1->deprecated, e2->deprecated); + if (!is_same(e1->metric_group, e2->metric_group)) { + pr_debug2("testing event e1 %s: mismatched metric_group, %s vs %s\n", + e1->name, e1->metric_group, e2->metric_group); return -1; } - if (!is_same(e1->pmu, e2->pmu)) { - pr_debug2("testing event e1 %s: mismatched pmu string, %s vs %s\n", - e1->name, e1->pmu, e2->pmu); + if (!is_same(e1->deprecated, e2->deprecated)) { + pr_debug2("testing event e1 %s: mismatched deprecated, %s vs %s\n", + e1->name, e1->deprecated, e2->deprecated); return -1; } - if (!is_same(e1->compat, e2->compat)) { - pr_debug2("testing event e1 %s: mismatched compat string, %s vs %s\n", - e1->name, e1->compat, e2->compat); + if (!is_same(e1->metric_constraint, e2->metric_constraint)) { + pr_debug2("testing event e1 %s: mismatched metric_constant, %s vs %s\n", + e1->name, e1->metric_constraint, e2->metric_constraint); return -1; } -- cgit From b8b350afaa4bd007261c1ce367123444f6953a42 Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 16 Sep 2021 20:34:24 +0800 Subject: perf test: Add pmu-event test for event described as "config=" Add a new test event for a system event whose event member is in form "config=". Signed-off-by: John Garry Acked-by: Ian Rogers Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Jiri Olsa Cc: Leo Yan Cc: Mark Rutland Cc: Mathieu Poirier Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Shaokun Zhang Cc: Will Deacon Cc: linux-arm-kernel@lists.infradead.org Cc: linuxarm@huawei.com Cc: liuqi115@huawei.com Link: https://lore.kernel.org/r/1631795665-240946-5-git-send-email-john.garry@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- .../pmu-events/arch/test/test_soc/sys/uncore.json | 7 ++++++ tools/perf/tests/pmu-events.c | 25 ++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/tools/perf/pmu-events/arch/test/test_soc/sys/uncore.json b/tools/perf/pmu-events/arch/test/test_soc/sys/uncore.json index 0f681a6e10ea..c7e7528db315 100644 --- a/tools/perf/pmu-events/arch/test/test_soc/sys/uncore.json +++ b/tools/perf/pmu-events/arch/test/test_soc/sys/uncore.json @@ -6,4 +6,11 @@ "Unit": "sys_ddr_pmu", "Compat": "v8" }, + { + "BriefDescription": "ccn read-cycles event", + "ConfigCode": "0x2c", + "EventName": "sys_ccn_pmu.read_cycles", + "Unit": "sys_ccn_pmu", + "Compat": "0x01" + } ] diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c index adfc17f51c7b..f14266a4c513 100644 --- a/tools/perf/tests/pmu-events.c +++ b/tools/perf/tests/pmu-events.c @@ -208,8 +208,23 @@ static const struct perf_pmu_test_event sys_ddr_pmu_write_cycles = { .matching_pmu = "uncore_sys_ddr_pmu", }; +static const struct perf_pmu_test_event sys_ccn_pmu_read_cycles = { + .event = { + .name = "sys_ccn_pmu.read_cycles", + .event = "config=0x2c", + .desc = "ccn read-cycles event. Unit: uncore_sys_ccn_pmu ", + .topic = "uncore", + .pmu = "uncore_sys_ccn_pmu", + .compat = "0x01", + }, + .alias_str = "config=0x2c", + .alias_long_desc = "ccn read-cycles event. Unit: uncore_sys_ccn_pmu ", + .matching_pmu = "uncore_sys_ccn_pmu", +}; + static const struct perf_pmu_test_event *sys_events[] = { &sys_ddr_pmu_write_cycles, + &sys_ccn_pmu_read_cycles, NULL }; @@ -677,6 +692,16 @@ static struct perf_pmu_test_pmu test_pmus[] = { &sys_ddr_pmu_write_cycles, }, }, + { + .pmu = { + .name = (char *)"uncore_sys_ccn_pmu4", + .is_uncore = 1, + .id = (char *)"0x01", + }, + .aliases = { + &sys_ccn_pmu_read_cycles, + }, + }, }; /* Test that aliases generated are as expected */ -- cgit From c801612875909cbce823dfc276c58c7155f95b01 Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 16 Sep 2021 20:34:25 +0800 Subject: perf vendor events arm64: Revise hip08 uncore events To improve alias matching, remove the PMU name prefix from the EventName. This will mean that the pmu code will merge aliases, such that we no longer get a huge list of per-PMU events - see perf_pmu_merge_alias(). Also make the following associated changes: - Use "ConfigCode" rather than "EventCode", so the pmu code is not so disagreeable about inconsistent event codes - Add undocumented HHA event codes to allow alias merging (for those events) Signed-off-by: John Garry Acked-by: Ian Rogers Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Jiri Olsa Cc: Leo Yan Cc: Mark Rutland Cc: Mathieu Poirier Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Shaokun Zhang Cc: Will Deacon Cc: linux-arm-kernel@lists.infradead.org Cc: linuxarm@huawei.com Cc: liuqi115@huawei.com Link: https://lore.kernel.org/r/1631795665-240946-6-git-send-email-john.garry@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- .../arch/arm64/hisilicon/hip08/uncore-ddrc.json | 32 +++--- .../arch/arm64/hisilicon/hip08/uncore-hha.json | 120 +++++++++++++++++---- .../arch/arm64/hisilicon/hip08/uncore-l3c.json | 52 ++++----- 3 files changed, 142 insertions(+), 62 deletions(-) diff --git a/tools/perf/pmu-events/arch/arm64/hisilicon/hip08/uncore-ddrc.json b/tools/perf/pmu-events/arch/arm64/hisilicon/hip08/uncore-ddrc.json index 61514d38601b..2b3cb55df288 100644 --- a/tools/perf/pmu-events/arch/arm64/hisilicon/hip08/uncore-ddrc.json +++ b/tools/perf/pmu-events/arch/arm64/hisilicon/hip08/uncore-ddrc.json @@ -1,56 +1,56 @@ [ { - "EventCode": "0x00", - "EventName": "uncore_hisi_ddrc.flux_wr", + "ConfigCode": "0x00", + "EventName": "flux_wr", "BriefDescription": "DDRC total write operations", "PublicDescription": "DDRC total write operations", "Unit": "hisi_sccl,ddrc" }, { - "EventCode": "0x01", - "EventName": "uncore_hisi_ddrc.flux_rd", + "ConfigCode": "0x01", + "EventName": "flux_rd", "BriefDescription": "DDRC total read operations", "PublicDescription": "DDRC total read operations", "Unit": "hisi_sccl,ddrc" }, { - "EventCode": "0x02", - "EventName": "uncore_hisi_ddrc.flux_wcmd", + "ConfigCode": "0x02", + "EventName": "flux_wcmd", "BriefDescription": "DDRC write commands", "PublicDescription": "DDRC write commands", "Unit": "hisi_sccl,ddrc" }, { - "EventCode": "0x03", - "EventName": "uncore_hisi_ddrc.flux_rcmd", + "ConfigCode": "0x03", + "EventName": "flux_rcmd", "BriefDescription": "DDRC read commands", "PublicDescription": "DDRC read commands", "Unit": "hisi_sccl,ddrc" }, { - "EventCode": "0x04", - "EventName": "uncore_hisi_ddrc.pre_cmd", + "ConfigCode": "0x04", + "EventName": "pre_cmd", "BriefDescription": "DDRC precharge commands", "PublicDescription": "DDRC precharge commands", "Unit": "hisi_sccl,ddrc" }, { - "EventCode": "0x05", - "EventName": "uncore_hisi_ddrc.act_cmd", + "ConfigCode": "0x05", + "EventName": "act_cmd", "BriefDescription": "DDRC active commands", "PublicDescription": "DDRC active commands", "Unit": "hisi_sccl,ddrc" }, { - "EventCode": "0x06", - "EventName": "uncore_hisi_ddrc.rnk_chg", + "ConfigCode": "0x06", + "EventName": "rnk_chg", "BriefDescription": "DDRC rank commands", "PublicDescription": "DDRC rank commands", "Unit": "hisi_sccl,ddrc" }, { - "EventCode": "0x07", - "EventName": "uncore_hisi_ddrc.rw_chg", + "ConfigCode": "0x07", + "EventName": "rw_chg", "BriefDescription": "DDRC read and write changes", "PublicDescription": "DDRC read and write changes", "Unit": "hisi_sccl,ddrc" diff --git a/tools/perf/pmu-events/arch/arm64/hisilicon/hip08/uncore-hha.json b/tools/perf/pmu-events/arch/arm64/hisilicon/hip08/uncore-hha.json index ada86782933f..9a7ec7af2060 100644 --- a/tools/perf/pmu-events/arch/arm64/hisilicon/hip08/uncore-hha.json +++ b/tools/perf/pmu-events/arch/arm64/hisilicon/hip08/uncore-hha.json @@ -1,72 +1,152 @@ [ { - "EventCode": "0x00", - "EventName": "uncore_hisi_hha.rx_ops_num", + "ConfigCode": "0x00", + "EventName": "rx_ops_num", "BriefDescription": "The number of all operations received by the HHA", "PublicDescription": "The number of all operations received by the HHA", "Unit": "hisi_sccl,hha" }, { - "EventCode": "0x01", - "EventName": "uncore_hisi_hha.rx_outer", + "ConfigCode": "0x01", + "EventName": "rx_outer", "BriefDescription": "The number of all operations received by the HHA from another socket", "PublicDescription": "The number of all operations received by the HHA from another socket", "Unit": "hisi_sccl,hha" }, { - "EventCode": "0x02", - "EventName": "uncore_hisi_hha.rx_sccl", + "ConfigCode": "0x02", + "EventName": "rx_sccl", "BriefDescription": "The number of all operations received by the HHA from another SCCL in this socket", "PublicDescription": "The number of all operations received by the HHA from another SCCL in this socket", "Unit": "hisi_sccl,hha" }, { - "EventCode": "0x03", - "EventName": "uncore_hisi_hha.rx_ccix", + "ConfigCode": "0x03", + "EventName": "rx_ccix", "BriefDescription": "Count of the number of operations that HHA has received from CCIX", "PublicDescription": "Count of the number of operations that HHA has received from CCIX", "Unit": "hisi_sccl,hha" }, { - "EventCode": "0x1c", - "EventName": "uncore_hisi_hha.rd_ddr_64b", + "ConfigCode": "0x4", + "EventName": "rx_wbi", + "Unit": "hisi_sccl,hha" + }, + { + "ConfigCode": "0x5", + "EventName": "rx_wbip", + "Unit": "hisi_sccl,hha" + }, + { + "ConfigCode": "0x11", + "EventName": "rx_wtistash", + "Unit": "hisi_sccl,hha" + }, + { + "ConfigCode": "0x1c", + "EventName": "rd_ddr_64b", "BriefDescription": "The number of read operations sent by HHA to DDRC which size is 64 bytes", "PublicDescription": "The number of read operations sent by HHA to DDRC which size is 64bytes", "Unit": "hisi_sccl,hha" }, { - "EventCode": "0x1d", - "EventName": "uncore_hisi_hha.wr_ddr_64b", + "ConfigCode": "0x1d", + "EventName": "wr_ddr_64b", "BriefDescription": "The number of write operations sent by HHA to DDRC which size is 64 bytes", "PublicDescription": "The number of write operations sent by HHA to DDRC which size is 64 bytes", "Unit": "hisi_sccl,hha" }, { - "EventCode": "0x1e", - "EventName": "uncore_hisi_hha.rd_ddr_128b", + "ConfigCode": "0x1e", + "EventName": "rd_ddr_128b", "BriefDescription": "The number of read operations sent by HHA to DDRC which size is 128 bytes", "PublicDescription": "The number of read operations sent by HHA to DDRC which size is 128 bytes", "Unit": "hisi_sccl,hha" }, { - "EventCode": "0x1f", - "EventName": "uncore_hisi_hha.wr_ddr_128b", + "ConfigCode": "0x1f", + "EventName": "wr_ddr_128b", "BriefDescription": "The number of write operations sent by HHA to DDRC which size is 128 bytes", "PublicDescription": "The number of write operations sent by HHA to DDRC which size is 128 bytes", "Unit": "hisi_sccl,hha" }, { - "EventCode": "0x20", - "EventName": "uncore_hisi_hha.spill_num", + "ConfigCode": "0x20", + "EventName": "spill_num", "BriefDescription": "Count of the number of spill operations that the HHA has sent", "PublicDescription": "Count of the number of spill operations that the HHA has sent", "Unit": "hisi_sccl,hha" }, { - "EventCode": "0x21", - "EventName": "uncore_hisi_hha.spill_success", + "ConfigCode": "0x21", + "EventName": "spill_success", "BriefDescription": "Count of the number of successful spill operations that the HHA has sent", "PublicDescription": "Count of the number of successful spill operations that the HHA has sent", "Unit": "hisi_sccl,hha" + }, + { + "ConfigCode": "0x23", + "EventName": "bi_num", + "Unit": "hisi_sccl,hha" + }, + { + "ConfigCode": "0x32", + "EventName": "mediated_num", + "Unit": "hisi_sccl,hha" + }, + { + "ConfigCode": "0x33", + "EventName": "tx_snp_num", + "Unit": "hisi_sccl,hha" + }, + { + "ConfigCode": "0x34", + "EventName": "tx_snp_outer", + "Unit": "hisi_sccl,hha" + }, + { + "ConfigCode": "0x35", + "EventName": "tx_snp_ccix", + "Unit": "hisi_sccl,hha" + }, + { + "ConfigCode": "0x38", + "EventName": "rx_snprspdata", + "Unit": "hisi_sccl,hha" + }, + { + "ConfigCode": "0x3c", + "EventName": "rx_snprsp_outer", + "Unit": "hisi_sccl,hha" + }, + { + "ConfigCode": "0x40", + "EventName": "sdir-lookup", + "Unit": "hisi_sccl,hha" + }, + { + "ConfigCode": "0x41", + "EventName": "edir-lookup", + "Unit": "hisi_sccl,hha" + }, + { + "ConfigCode": "0x42", + "EventName": "sdir-hit", + "Unit": "hisi_sccl,hha" + }, + { + "ConfigCode": "0x43", + "EventName": "edir-hit", + "Unit": "hisi_sccl,hha" + }, + { + "ConfigCode": "0x4c", + "EventName": "sdir-home-migrate", + "Unit": "hisi_sccl,hha" + }, + { + "ConfigCode": "0x4d", + "EventName": "edir-home-migrate", + "Unit": "hisi_sccl,hha" } ] diff --git a/tools/perf/pmu-events/arch/arm64/hisilicon/hip08/uncore-l3c.json b/tools/perf/pmu-events/arch/arm64/hisilicon/hip08/uncore-l3c.json index 67ab19e8cf3a..e3479b65be9a 100644 --- a/tools/perf/pmu-events/arch/arm64/hisilicon/hip08/uncore-l3c.json +++ b/tools/perf/pmu-events/arch/arm64/hisilicon/hip08/uncore-l3c.json @@ -1,91 +1,91 @@ [ { - "EventCode": "0x00", - "EventName": "uncore_hisi_l3c.rd_cpipe", + "ConfigCode": "0x00", + "EventName": "rd_cpipe", "BriefDescription": "Total read accesses", "PublicDescription": "Total read accesses", "Unit": "hisi_sccl,l3c" }, { - "EventCode": "0x01", - "EventName": "uncore_hisi_l3c.wr_cpipe", + "ConfigCode": "0x01", + "EventName": "wr_cpipe", "BriefDescription": "Total write accesses", "PublicDescription": "Total write accesses", "Unit": "hisi_sccl,l3c" }, { - "EventCode": "0x02", - "EventName": "uncore_hisi_l3c.rd_hit_cpipe", + "ConfigCode": "0x02", + "EventName": "rd_hit_cpipe", "BriefDescription": "Total read hits", "PublicDescription": "Total read hits", "Unit": "hisi_sccl,l3c" }, { - "EventCode": "0x03", - "EventName": "uncore_hisi_l3c.wr_hit_cpipe", + "ConfigCode": "0x03", + "EventName": "wr_hit_cpipe", "BriefDescription": "Total write hits", "PublicDescription": "Total write hits", "Unit": "hisi_sccl,l3c" }, { - "EventCode": "0x04", - "EventName": "uncore_hisi_l3c.victim_num", + "ConfigCode": "0x04", + "EventName": "victim_num", "BriefDescription": "l3c precharge commands", "PublicDescription": "l3c precharge commands", "Unit": "hisi_sccl,l3c" }, { - "EventCode": "0x20", - "EventName": "uncore_hisi_l3c.rd_spipe", + "ConfigCode": "0x20", + "EventName": "rd_spipe", "BriefDescription": "Count of the number of read lines that come from this cluster of CPU core in spipe", "PublicDescription": "Count of the number of read lines that come from this cluster of CPU core in spipe", "Unit": "hisi_sccl,l3c" }, { - "EventCode": "0x21", - "EventName": "uncore_hisi_l3c.wr_spipe", + "ConfigCode": "0x21", + "EventName": "wr_spipe", "BriefDescription": "Count of the number of write lines that come from this cluster of CPU core in spipe", "PublicDescription": "Count of the number of write lines that come from this cluster of CPU core in spipe", "Unit": "hisi_sccl,l3c" }, { - "EventCode": "0x22", - "EventName": "uncore_hisi_l3c.rd_hit_spipe", + "ConfigCode": "0x22", + "EventName": "rd_hit_spipe", "BriefDescription": "Count of the number of read lines that hits in spipe of this L3C", "PublicDescription": "Count of the number of read lines that hits in spipe of this L3C", "Unit": "hisi_sccl,l3c" }, { - "EventCode": "0x23", - "EventName": "uncore_hisi_l3c.wr_hit_spipe", + "ConfigCode": "0x23", + "EventName": "wr_hit_spipe", "BriefDescription": "Count of the number of write lines that hits in spipe of this L3C", "PublicDescription": "Count of the number of write lines that hits in spipe of this L3C", "Unit": "hisi_sccl,l3c" }, { - "EventCode": "0x29", - "EventName": "uncore_hisi_l3c.back_invalid", + "ConfigCode": "0x29", + "EventName": "back_invalid", "BriefDescription": "Count of the number of L3C back invalid operations", "PublicDescription": "Count of the number of L3C back invalid operations", "Unit": "hisi_sccl,l3c" }, { - "EventCode": "0x40", - "EventName": "uncore_hisi_l3c.retry_cpu", + "ConfigCode": "0x40", + "EventName": "retry_cpu", "BriefDescription": "Count of the number of retry that L3C suppresses the CPU operations", "PublicDescription": "Count of the number of retry that L3C suppresses the CPU operations", "Unit": "hisi_sccl,l3c" }, { - "EventCode": "0x41", - "EventName": "uncore_hisi_l3c.retry_ring", + "ConfigCode": "0x41", + "EventName": "retry_ring", "BriefDescription": "Count of the number of retry that L3C suppresses the ring operations", "PublicDescription": "Count of the number of retry that L3C suppresses the ring operations", "Unit": "hisi_sccl,l3c" }, { - "EventCode": "0x42", - "EventName": "uncore_hisi_l3c.prefetch_drop", + "ConfigCode": "0x42", + "EventName": "prefetch_drop", "BriefDescription": "Count of the number of prefetch drops from this L3C", "PublicDescription": "Count of the number of prefetch drops from this L3C", "Unit": "hisi_sccl,l3c" -- cgit From af9d82626c8f8547910e3e22c76ced3f5d5f5286 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 24 Aug 2021 14:20:51 +0200 Subject: PCI/ACPI: Remove OSC_PCI_SUPPORT_MASKS and OSC_PCI_CONTROL_MASKS These masks are only used internally in the PCI Host Bridge _OSC negotiation code, which already makes sure nothing outside of these masks is set. Remove the masks and simplify the code. Suggested-by: Bjorn Helgaas Link: https://lore.kernel.org/r/20210824122054.29481-2-joro@8bytes.org Signed-off-by: Joerg Roedel Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki --- drivers/acpi/pci_root.c | 9 +++------ include/linux/acpi.h | 2 -- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index d7deedf3548e..0c3030a58219 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -199,18 +199,15 @@ static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, acpi_status status; u32 result, capbuf[3]; - support &= OSC_PCI_SUPPORT_MASKS; support |= root->osc_support_set; capbuf[OSC_QUERY_DWORD] = OSC_QUERY_ENABLE; capbuf[OSC_SUPPORT_DWORD] = support; - if (control) { - *control &= OSC_PCI_CONTROL_MASKS; + if (control) capbuf[OSC_CONTROL_DWORD] = *control | root->osc_control_set; - } else { + else /* Run _OSC query only with existing controls. */ capbuf[OSC_CONTROL_DWORD] = root->osc_control_set; - } status = acpi_pci_run_osc(root->device->handle, capbuf, &result); if (ACPI_SUCCESS(status)) { @@ -357,7 +354,7 @@ static acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 r if (!mask) return AE_BAD_PARAMETER; - ctrl = *mask & OSC_PCI_CONTROL_MASKS; + ctrl = *mask; if ((ctrl & req) != req) return AE_TYPE; diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 974d497a897d..eb59fd3052c0 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -577,7 +577,6 @@ extern u32 osc_sb_native_usb4_control; #define OSC_PCI_MSI_SUPPORT 0x00000010 #define OSC_PCI_EDR_SUPPORT 0x00000080 #define OSC_PCI_HPX_TYPE_3_SUPPORT 0x00000100 -#define OSC_PCI_SUPPORT_MASKS 0x0000019f /* PCI Host Bridge _OSC: Capabilities DWORD 3: Control Field */ #define OSC_PCI_EXPRESS_NATIVE_HP_CONTROL 0x00000001 @@ -587,7 +586,6 @@ extern u32 osc_sb_native_usb4_control; #define OSC_PCI_EXPRESS_CAPABILITY_CONTROL 0x00000010 #define OSC_PCI_EXPRESS_LTR_CONTROL 0x00000020 #define OSC_PCI_EXPRESS_DPC_CONTROL 0x00000080 -#define OSC_PCI_CONTROL_MASKS 0x000000bf #define ACPI_GSB_ACCESS_ATTRIB_QUICK 0x00000002 #define ACPI_GSB_ACCESS_ATTRIB_SEND_RCV 0x00000004 -- cgit From 4c6f6060b7c4fe058981d17784684429c5491243 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 24 Aug 2021 14:20:52 +0200 Subject: PCI/ACPI: Move supported and control calculations to separate functions Move the calculations of supported and controlled _OSC features out of negotiate_os_control() into separate functions. Link: https://lore.kernel.org/r/20210824122054.29481-3-joro@8bytes.org Signed-off-by: Joerg Roedel Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki --- drivers/acpi/pci_root.c | 93 +++++++++++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 38 deletions(-) diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 0c3030a58219..ed4e6b55e9bc 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -396,6 +396,59 @@ static acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 r return AE_OK; } +static u32 calculate_support(void) +{ + u32 support; + + /* + * All supported architectures that use ACPI have support for + * PCI domains, so we indicate this in _OSC support capabilities. + */ + support = OSC_PCI_SEGMENT_GROUPS_SUPPORT; + support |= OSC_PCI_HPX_TYPE_3_SUPPORT; + if (pci_ext_cfg_avail()) + support |= OSC_PCI_EXT_CONFIG_SUPPORT; + if (pcie_aspm_support_enabled()) + support |= OSC_PCI_ASPM_SUPPORT | OSC_PCI_CLOCK_PM_SUPPORT; + if (pci_msi_enabled()) + support |= OSC_PCI_MSI_SUPPORT; + if (IS_ENABLED(CONFIG_PCIE_EDR)) + support |= OSC_PCI_EDR_SUPPORT; + + return support; +} + +static u32 calculate_control(void) +{ + u32 control; + + control = OSC_PCI_EXPRESS_CAPABILITY_CONTROL + | OSC_PCI_EXPRESS_PME_CONTROL; + + if (IS_ENABLED(CONFIG_PCIEASPM)) + control |= OSC_PCI_EXPRESS_LTR_CONTROL; + + if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)) + control |= OSC_PCI_EXPRESS_NATIVE_HP_CONTROL; + + if (IS_ENABLED(CONFIG_HOTPLUG_PCI_SHPC)) + control |= OSC_PCI_SHPC_NATIVE_HP_CONTROL; + + if (pci_aer_available()) + control |= OSC_PCI_EXPRESS_AER_CONTROL; + + /* + * Per the Downstream Port Containment Related Enhancements ECN to + * the PCI Firmware Spec, r3.2, sec 4.5.1, table 4-5, + * OSC_PCI_EXPRESS_DPC_CONTROL indicates the OS supports both DPC + * and EDR. + */ + if (IS_ENABLED(CONFIG_PCIE_DPC) && IS_ENABLED(CONFIG_PCIE_EDR)) + control |= OSC_PCI_EXPRESS_DPC_CONTROL; + + return control; +} + static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm, bool is_pcie) { @@ -416,20 +469,7 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm, return; } - /* - * All supported architectures that use ACPI have support for - * PCI domains, so we indicate this in _OSC support capabilities. - */ - support = OSC_PCI_SEGMENT_GROUPS_SUPPORT; - support |= OSC_PCI_HPX_TYPE_3_SUPPORT; - if (pci_ext_cfg_avail()) - support |= OSC_PCI_EXT_CONFIG_SUPPORT; - if (pcie_aspm_support_enabled()) - support |= OSC_PCI_ASPM_SUPPORT | OSC_PCI_CLOCK_PM_SUPPORT; - if (pci_msi_enabled()) - support |= OSC_PCI_MSI_SUPPORT; - if (IS_ENABLED(CONFIG_PCIE_EDR)) - support |= OSC_PCI_EDR_SUPPORT; + support = calculate_support(); decode_osc_support(root, "OS supports", support); status = acpi_pci_osc_support(root, support); @@ -456,31 +496,8 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm, return; } - control = OSC_PCI_EXPRESS_CAPABILITY_CONTROL - | OSC_PCI_EXPRESS_PME_CONTROL; - - if (IS_ENABLED(CONFIG_PCIEASPM)) - control |= OSC_PCI_EXPRESS_LTR_CONTROL; - - if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)) - control |= OSC_PCI_EXPRESS_NATIVE_HP_CONTROL; - - if (IS_ENABLED(CONFIG_HOTPLUG_PCI_SHPC)) - control |= OSC_PCI_SHPC_NATIVE_HP_CONTROL; - - if (pci_aer_available()) - control |= OSC_PCI_EXPRESS_AER_CONTROL; - - /* - * Per the Downstream Port Containment Related Enhancements ECN to - * the PCI Firmware Spec, r3.2, sec 4.5.1, table 4-5, - * OSC_PCI_EXPRESS_DPC_CONTROL indicates the OS supports both DPC - * and EDR. - */ - if (IS_ENABLED(CONFIG_PCIE_DPC) && IS_ENABLED(CONFIG_PCIE_EDR)) - control |= OSC_PCI_EXPRESS_DPC_CONTROL; + requested = control = calculate_control(); - requested = control; status = acpi_pci_osc_control_set(handle, &control, OSC_PCI_EXPRESS_CAPABILITY_CONTROL); if (ACPI_SUCCESS(status)) { -- cgit From 87f1f87a16818c36431391ea8c30ea926cab917f Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 24 Aug 2021 14:20:53 +0200 Subject: PCI/ACPI: Move _OSC query checks to separate function Move the checks about whether the _OSC controls are requested from the firmware to a separate function. Link: https://lore.kernel.org/r/20210824122054.29481-4-joro@8bytes.org Signed-off-by: Joerg Roedel Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki --- drivers/acpi/pci_root.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index ed4e6b55e9bc..f12e512bcddc 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -449,6 +449,24 @@ static u32 calculate_control(void) return control; } +static bool os_control_query_checks(struct acpi_pci_root *root, u32 support) +{ + struct acpi_device *device = root->device; + + if (pcie_ports_disabled) { + dev_info(&device->dev, "PCIe port services disabled; not requesting _OSC control\n"); + return false; + } + + if ((support & ACPI_PCIE_REQ_SUPPORT) != ACPI_PCIE_REQ_SUPPORT) { + decode_osc_support(root, "not requesting OS control; OS requires", + ACPI_PCIE_REQ_SUPPORT); + return false; + } + + return true; +} + static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm, bool is_pcie) { @@ -485,16 +503,8 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm, return; } - if (pcie_ports_disabled) { - dev_info(&device->dev, "PCIe port services disabled; not requesting _OSC control\n"); + if (!os_control_query_checks(root, support)) return; - } - - if ((support & ACPI_PCIE_REQ_SUPPORT) != ACPI_PCIE_REQ_SUPPORT) { - decode_osc_support(root, "not requesting OS control; OS requires", - ACPI_PCIE_REQ_SUPPORT); - return; - } requested = control = calculate_control(); -- cgit From 6bc779ee05d4fa66c99096dbf88ff61acbb8a887 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 24 Aug 2021 14:20:54 +0200 Subject: PCI/ACPI: Check for _OSC support in acpi_pci_osc_control_set() Get rid of acpi_pci_osc_support() and check for _OSC supported features directly in acpi_pci_osc_control_set(). There is no point in doing an unconditional _OSC query with control=0 even when the kernel later wants to take control over more features. This saves one _OSC query and simplifies the code by getting rid of the acpi_pci_osc_support() function. As a side effect, the !control checks in acpi_pci_query_osc() can also be removed. Link: https://lore.kernel.org/r/20210824122054.29481-5-joro@8bytes.org Signed-off-by: Joerg Roedel Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki --- drivers/acpi/pci_root.c | 81 +++++++++++++++++++------------------------------ 1 file changed, 32 insertions(+), 49 deletions(-) diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index f12e512bcddc..ab2f7dfb0c44 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -203,26 +203,16 @@ static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, capbuf[OSC_QUERY_DWORD] = OSC_QUERY_ENABLE; capbuf[OSC_SUPPORT_DWORD] = support; - if (control) - capbuf[OSC_CONTROL_DWORD] = *control | root->osc_control_set; - else - /* Run _OSC query only with existing controls. */ - capbuf[OSC_CONTROL_DWORD] = root->osc_control_set; + capbuf[OSC_CONTROL_DWORD] = *control | root->osc_control_set; status = acpi_pci_run_osc(root->device->handle, capbuf, &result); if (ACPI_SUCCESS(status)) { root->osc_support_set = support; - if (control) - *control = result; + *control = result; } return status; } -static acpi_status acpi_pci_osc_support(struct acpi_pci_root *root, u32 flags) -{ - return acpi_pci_query_osc(root, flags, NULL); -} - struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle) { struct acpi_pci_root *root; @@ -345,8 +335,9 @@ EXPORT_SYMBOL_GPL(acpi_get_pci_dev); * _OSC bits the BIOS has granted control of, but its contents are meaningless * on failure. **/ -static acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 req) +static acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 support) { + u32 req = OSC_PCI_EXPRESS_CAPABILITY_CONTROL; struct acpi_pci_root *root; acpi_status status; u32 ctrl, capbuf[3]; @@ -354,22 +345,16 @@ static acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 r if (!mask) return AE_BAD_PARAMETER; - ctrl = *mask; - if ((ctrl & req) != req) - return AE_TYPE; - root = acpi_pci_find_root(handle); if (!root) return AE_NOT_EXIST; - *mask = ctrl | root->osc_control_set; - /* No need to evaluate _OSC if the control was already granted. */ - if ((root->osc_control_set & ctrl) == ctrl) - return AE_OK; + ctrl = *mask; + *mask |= root->osc_control_set; /* Need to check the available controls bits before requesting them. */ - while (*mask) { - status = acpi_pci_query_osc(root, root->osc_support_set, mask); + do { + status = acpi_pci_query_osc(root, support, mask); if (ACPI_FAILURE(status)) return status; if (ctrl == *mask) @@ -377,7 +362,11 @@ static acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 r decode_osc_control(root, "platform does not support", ctrl & ~(*mask)); ctrl = *mask; - } + } while (*mask); + + /* No need to request _OSC if the control was already granted. */ + if ((root->osc_control_set & ctrl) == ctrl) + return AE_OK; if ((ctrl & req) != req) { decode_osc_control(root, "not requesting control; platform does not support", @@ -470,7 +459,7 @@ static bool os_control_query_checks(struct acpi_pci_root *root, u32 support) static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm, bool is_pcie) { - u32 support, control, requested; + u32 support, control = 0, requested = 0; acpi_status status; struct acpi_device *device = root->device; acpi_handle handle = device->handle; @@ -490,28 +479,15 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm, support = calculate_support(); decode_osc_support(root, "OS supports", support); - status = acpi_pci_osc_support(root, support); - if (ACPI_FAILURE(status)) { - *no_aspm = 1; - - /* _OSC is optional for PCI host bridges */ - if ((status == AE_NOT_FOUND) && !is_pcie) - return; - - dev_info(&device->dev, "_OSC: platform retains control of PCIe features (%s)\n", - acpi_format_exception(status)); - return; - } - - if (!os_control_query_checks(root, support)) - return; - requested = control = calculate_control(); + if (os_control_query_checks(root, support)) + requested = control = calculate_control(); - status = acpi_pci_osc_control_set(handle, &control, - OSC_PCI_EXPRESS_CAPABILITY_CONTROL); + status = acpi_pci_osc_control_set(handle, &control, support); if (ACPI_SUCCESS(status)) { - decode_osc_control(root, "OS now controls", control); + if (control) + decode_osc_control(root, "OS now controls", control); + if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) { /* * We have ASPM control, but the FADT indicates that @@ -522,11 +498,6 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm, *no_aspm = 1; } } else { - decode_osc_control(root, "OS requested", requested); - decode_osc_control(root, "platform willing to grant", control); - dev_info(&device->dev, "_OSC: platform retains control of PCIe features (%s)\n", - acpi_format_exception(status)); - /* * We want to disable ASPM here, but aspm_disabled * needs to remain in its state from boot so that we @@ -535,6 +506,18 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm, * root scan. */ *no_aspm = 1; + + /* _OSC is optional for PCI host bridges */ + if ((status == AE_NOT_FOUND) && !is_pcie) + return; + + if (control) { + decode_osc_control(root, "OS requested", requested); + decode_osc_control(root, "platform willing to grant", control); + } + + dev_info(&device->dev, "_OSC: platform retains control of PCIe features (%s)\n", + acpi_format_exception(status)); } } -- cgit From c2606ddcf5ad1969ceffe3c98d427b272243e150 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 24 Sep 2021 15:32:23 +0200 Subject: mtd: onenand: samsung: drop Exynos4 and describe driver in KConfig None of supported Samsung Exynos4 SoCs (Exynos4210, Exynos4412) seem to use OneNAND driver so drop it. Describe better which driver applies to which SoC, to make configuring kernel for Samsung SoC easier. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20210924133223.111930-1-krzysztof.kozlowski@canonical.com --- drivers/mtd/nand/onenand/Kconfig | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/onenand/Kconfig b/drivers/mtd/nand/onenand/Kconfig index 1a0e65bc246e..34d9a7a82ad4 100644 --- a/drivers/mtd/nand/onenand/Kconfig +++ b/drivers/mtd/nand/onenand/Kconfig @@ -33,11 +33,12 @@ config MTD_ONENAND_OMAP2 config MTD_ONENAND_SAMSUNG tristate "OneNAND on Samsung SOC controller support" - depends on ARCH_S3C64XX || ARCH_S5PV210 || ARCH_EXYNOS4 || COMPILE_TEST + depends on ARCH_S3C64XX || ARCH_S5PV210 || COMPILE_TEST help - Support for a OneNAND flash device connected to an Samsung SOC. - S3C64XX uses command mapping method. - S5PC110/S5PC210 use generic OneNAND method. + Support for a OneNAND flash device connected to Samsung S3C64XX + (using command mapping method) and S5PC110/S5PC210 (using generic + OneNAND method) SoCs. + Choose Y here only if you build for such Samsung SoC. config MTD_ONENAND_OTP bool "OneNAND OTP Support" -- cgit From 95e83e219d68956ba4fed9326683e4d2bd3e39a9 Mon Sep 17 00:00:00 2001 From: Krzysztof Wilczyński Date: Wed, 15 Sep 2021 23:01:25 +0000 Subject: PCI/sysfs: Check CAP_SYS_ADMIN before parsing user input MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check if the "CAP_SYS_ADMIN" capability flag is set before parsing user input as it makes more sense to first check whether the current user actually has the right permissions before accepting any input from such user. This will also make order in which enable_store() and msi_bus_store() perform the "CAP_SYS_ADMIN" capability check consistent with other PCI-related sysfs objects that first verify whether user has this capability set. Link: https://lore.kernel.org/r/20210915230127.2495723-1-kw@linux.com Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-sysfs.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 7fb5cd17cc98..6832e161be1c 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -273,15 +273,16 @@ static ssize_t enable_store(struct device *dev, struct device_attribute *attr, { struct pci_dev *pdev = to_pci_dev(dev); unsigned long val; - ssize_t result = kstrtoul(buf, 0, &val); - - if (result < 0) - return result; + ssize_t result; /* this can crash the machine when done on the "wrong" device */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; + result = kstrtoul(buf, 0, &val); + if (result < 0) + return result; + device_lock(dev); if (dev->driver) result = -EBUSY; @@ -378,12 +379,12 @@ static ssize_t msi_bus_store(struct device *dev, struct device_attribute *attr, struct pci_bus *subordinate = pdev->subordinate; unsigned long val; - if (kstrtoul(buf, 0, &val) < 0) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) return -EPERM; + if (kstrtoul(buf, 0, &val) < 0) + return -EINVAL; + /* * "no_msi" and "bus_flags" only affect what happens when a driver * requests MSI or MSI-X. They don't affect any drivers that have -- cgit From 36f354ec7bf92f8aaf09eaf3b261ea06c25ec337 Mon Sep 17 00:00:00 2001 From: Krzysztof Wilczyński Date: Wed, 15 Sep 2021 23:01:26 +0000 Subject: PCI/sysfs: Return -EINVAL consistently from "store" functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most of the "store" functions that handle userspace input via sysfs return -EINVAL should the value fail validation and/or type conversion. This error code is a clear message to userspace that the value is not a valid input. However, some of the "show" functions return input parsing error codes as-is, which may be either -EINVAL or -ERANGE. The former would often be from kstrtobool(), and the latter typically from other kstr*() functions such as kstrtou8(), kstrtou32(), kstrtoint(), etc. -EINVAL is commonly returned as the error code to indicate that the value provided is invalid, but -ERANGE is not very useful in userspace. Therefore, normalize the return error code to be -EINVAL for when the validation and/or type conversion fails. Link: https://lore.kernel.org/r/20210915230127.2495723-2-kw@linux.com Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas --- drivers/pci/endpoint/functions/pci-epf-ntb.c | 18 +++++--------- drivers/pci/endpoint/pci-ep-cfs.c | 35 ++++++++++------------------ drivers/pci/iov.c | 14 +++++------ drivers/pci/pci-sysfs.c | 20 +++++++--------- 4 files changed, 33 insertions(+), 54 deletions(-) diff --git a/drivers/pci/endpoint/functions/pci-epf-ntb.c b/drivers/pci/endpoint/functions/pci-epf-ntb.c index 8b4756159f15..e67489144349 100644 --- a/drivers/pci/endpoint/functions/pci-epf-ntb.c +++ b/drivers/pci/endpoint/functions/pci-epf-ntb.c @@ -1947,11 +1947,9 @@ static ssize_t epf_ntb_##_name##_store(struct config_item *item, \ struct config_group *group = to_config_group(item); \ struct epf_ntb *ntb = to_epf_ntb(group); \ u32 val; \ - int ret; \ \ - ret = kstrtou32(page, 0, &val); \ - if (ret) \ - return ret; \ + if (kstrtou32(page, 0, &val) < 0) \ + return -EINVAL; \ \ ntb->_name = val; \ \ @@ -1980,11 +1978,9 @@ static ssize_t epf_ntb_##_name##_store(struct config_item *item, \ struct device *dev = &ntb->epf->dev; \ int win_no; \ u64 val; \ - int ret; \ \ - ret = kstrtou64(page, 0, &val); \ - if (ret) \ - return ret; \ + if (kstrtou64(page, 0, &val) < 0) \ + return -EINVAL; \ \ if (sscanf(#_name, "mw%d", &win_no) != 1) \ return -EINVAL; \ @@ -2005,11 +2001,9 @@ static ssize_t epf_ntb_num_mws_store(struct config_item *item, struct config_group *group = to_config_group(item); struct epf_ntb *ntb = to_epf_ntb(group); u32 val; - int ret; - ret = kstrtou32(page, 0, &val); - if (ret) - return ret; + if (kstrtou32(page, 0, &val) < 0) + return -EINVAL; if (val > MAX_MW) return -EINVAL; diff --git a/drivers/pci/endpoint/pci-ep-cfs.c b/drivers/pci/endpoint/pci-ep-cfs.c index 999911801877..19bc0e828c0c 100644 --- a/drivers/pci/endpoint/pci-ep-cfs.c +++ b/drivers/pci/endpoint/pci-ep-cfs.c @@ -175,9 +175,8 @@ static ssize_t pci_epc_start_store(struct config_item *item, const char *page, epc = epc_group->epc; - ret = kstrtobool(page, &start); - if (ret) - return ret; + if (kstrtobool(page, &start) < 0) + return -EINVAL; if (!start) { pci_epc_stop(epc); @@ -329,13 +328,11 @@ static ssize_t pci_epf_##_name##_store(struct config_item *item, \ const char *page, size_t len) \ { \ u32 val; \ - int ret; \ struct pci_epf *epf = to_pci_epf_group(item)->epf; \ if (WARN_ON_ONCE(!epf->header)) \ return -EINVAL; \ - ret = kstrtou32(page, 0, &val); \ - if (ret) \ - return ret; \ + if (kstrtou32(page, 0, &val) < 0) \ + return -EINVAL; \ epf->header->_name = val; \ return len; \ } @@ -345,13 +342,11 @@ static ssize_t pci_epf_##_name##_store(struct config_item *item, \ const char *page, size_t len) \ { \ u16 val; \ - int ret; \ struct pci_epf *epf = to_pci_epf_group(item)->epf; \ if (WARN_ON_ONCE(!epf->header)) \ return -EINVAL; \ - ret = kstrtou16(page, 0, &val); \ - if (ret) \ - return ret; \ + if (kstrtou16(page, 0, &val) < 0) \ + return -EINVAL; \ epf->header->_name = val; \ return len; \ } @@ -361,13 +356,11 @@ static ssize_t pci_epf_##_name##_store(struct config_item *item, \ const char *page, size_t len) \ { \ u8 val; \ - int ret; \ struct pci_epf *epf = to_pci_epf_group(item)->epf; \ if (WARN_ON_ONCE(!epf->header)) \ return -EINVAL; \ - ret = kstrtou8(page, 0, &val); \ - if (ret) \ - return ret; \ + if (kstrtou8(page, 0, &val) < 0) \ + return -EINVAL; \ epf->header->_name = val; \ return len; \ } @@ -376,11 +369,9 @@ static ssize_t pci_epf_msi_interrupts_store(struct config_item *item, const char *page, size_t len) { u8 val; - int ret; - ret = kstrtou8(page, 0, &val); - if (ret) - return ret; + if (kstrtou8(page, 0, &val) < 0) + return -EINVAL; to_pci_epf_group(item)->epf->msi_interrupts = val; @@ -398,11 +389,9 @@ static ssize_t pci_epf_msix_interrupts_store(struct config_item *item, const char *page, size_t len) { u16 val; - int ret; - ret = kstrtou16(page, 0, &val); - if (ret) - return ret; + if (kstrtou16(page, 0, &val) < 0) + return -EINVAL; to_pci_epf_group(item)->epf->msix_interrupts = val; diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index dafdc652fcd0..0267977c9f17 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -183,11 +183,10 @@ static ssize_t sriov_vf_msix_count_store(struct device *dev, { struct pci_dev *vf_dev = to_pci_dev(dev); struct pci_dev *pdev = pci_physfn(vf_dev); - int val, ret; + int val, ret = 0; - ret = kstrtoint(buf, 0, &val); - if (ret) - return ret; + if (kstrtoint(buf, 0, &val) < 0) + return -EINVAL; if (val < 0) return -EINVAL; @@ -376,12 +375,11 @@ static ssize_t sriov_numvfs_store(struct device *dev, const char *buf, size_t count) { struct pci_dev *pdev = to_pci_dev(dev); - int ret; + int ret = 0; u16 num_vfs; - ret = kstrtou16(buf, 0, &num_vfs); - if (ret < 0) - return ret; + if (kstrtou16(buf, 0, &num_vfs) < 0) + return -EINVAL; if (num_vfs > pci_sriov_get_totalvfs(pdev)) return -ERANGE; diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 6832e161be1c..a092fc0c665d 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -273,15 +273,14 @@ static ssize_t enable_store(struct device *dev, struct device_attribute *attr, { struct pci_dev *pdev = to_pci_dev(dev); unsigned long val; - ssize_t result; + ssize_t result = 0; /* this can crash the machine when done on the "wrong" device */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; - result = kstrtoul(buf, 0, &val); - if (result < 0) - return result; + if (kstrtoul(buf, 0, &val) < 0) + return -EINVAL; device_lock(dev); if (dev->driver) @@ -313,14 +312,13 @@ static ssize_t numa_node_store(struct device *dev, size_t count) { struct pci_dev *pdev = to_pci_dev(dev); - int node, ret; + int node; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - ret = kstrtoint(buf, 0, &node); - if (ret) - return ret; + if (kstrtoint(buf, 0, &node) < 0) + return -EINVAL; if ((node < 0 && node != NUMA_NO_NODE) || node >= MAX_NUMNODES) return -EINVAL; @@ -1340,10 +1338,10 @@ static ssize_t reset_store(struct device *dev, struct device_attribute *attr, { struct pci_dev *pdev = to_pci_dev(dev); unsigned long val; - ssize_t result = kstrtoul(buf, 0, &val); + ssize_t result; - if (result < 0) - return result; + if (kstrtoul(buf, 0, &val) < 0) + return -EINVAL; if (val != 1) return -EINVAL; -- cgit From e0f7b19223582c302f5736e93927aafde9458d48 Mon Sep 17 00:00:00 2001 From: Krzysztof Wilczyński Date: Wed, 15 Sep 2021 23:01:27 +0000 Subject: PCI: Use kstrtobool() directly, sans strtobool() wrapper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit strtobool() is a wrapper around kstrtobool() that has been added for backward compatibility. There is no reason to use the old API, so use kstrtobool() directly. Related: ef951599074b ("lib: move strtobool() to kstrtobool()") Link: https://lore.kernel.org/r/20210915230127.2495723-3-kw@linux.com Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas --- drivers/pci/p2pdma.c | 6 +++--- drivers/pci/pcie/aspm.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c index 50cdde3e9a8b..4fccdcf9186f 100644 --- a/drivers/pci/p2pdma.c +++ b/drivers/pci/p2pdma.c @@ -943,7 +943,7 @@ EXPORT_SYMBOL_GPL(pci_p2pdma_unmap_sg_attrs); * * Parses an attribute value to decide whether to enable p2pdma. * The value can select a PCI device (using its full BDF device - * name) or a boolean (in any format strtobool() accepts). A false + * name) or a boolean (in any format kstrtobool() accepts). A false * value disables p2pdma, a true value expects the caller * to automatically find a compatible device and specifying a PCI device * expects the caller to use the specific provider. @@ -975,11 +975,11 @@ int pci_p2pdma_enable_store(const char *page, struct pci_dev **p2p_dev, } else if ((page[0] == '0' || page[0] == '1') && !iscntrl(page[1])) { /* * If the user enters a PCI device that doesn't exist - * like "0000:01:00.1", we don't want strtobool to think + * like "0000:01:00.1", we don't want kstrtobool to think * it's a '0' when it's clearly not what the user wanted. * So we require 0's and 1's to be exactly one character. */ - } else if (!strtobool(page, use_p2pdma)) { + } else if (!kstrtobool(page, use_p2pdma)) { return 0; } diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 013a47f587ce..52c74682601a 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -1219,7 +1219,7 @@ static ssize_t aspm_attr_store_common(struct device *dev, struct pcie_link_state *link = pcie_aspm_get_link(pdev); bool state_enable; - if (strtobool(buf, &state_enable) < 0) + if (kstrtobool(buf, &state_enable) < 0) return -EINVAL; down_read(&pci_bus_sem); @@ -1276,7 +1276,7 @@ static ssize_t clkpm_store(struct device *dev, struct pcie_link_state *link = pcie_aspm_get_link(pdev); bool state_enable; - if (strtobool(buf, &state_enable) < 0) + if (kstrtobool(buf, &state_enable) < 0) return -EINVAL; down_read(&pci_bus_sem); -- cgit From ce580e47e8481047faf296757d747e95464ff71c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 24 Sep 2021 15:26:58 +0200 Subject: scsi: ufs: exynos: Unify naming Use "Samsung" and "Exynos", not the uppercase versions. Link: https://lore.kernel.org/r/20210924132658.109814-2-krzysztof.kozlowski@canonical.com Reviewed-by: Alim Akhtar Signed-off-by: Krzysztof Kozlowski Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/Kconfig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index 565e8aa6319d..af66cb3634a8 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -165,14 +165,14 @@ config SCSI_UFS_BSG If unsure, say N. config SCSI_UFS_EXYNOS - tristate "EXYNOS specific hooks to UFS controller platform driver" + tristate "Exynos specific hooks to UFS controller platform driver" depends on SCSI_UFSHCD_PLATFORM && (ARCH_EXYNOS || COMPILE_TEST) help - This selects the EXYNOS specific additions to UFSHCD platform driver. - UFS host on EXYNOS includes HCI and UNIPRO layer, and associates with - UFS-PHY driver. + This selects the Samsung Exynos SoC specific additions to UFSHCD + platform driver. UFS host on Samsung Exynos SoC includes HCI and + UNIPRO layer, and associates with UFS-PHY driver. - Select this if you have UFS host controller on EXYNOS chipset. + Select this if you have UFS host controller on Samsung Exynos SoC. If unsure, say N. config SCSI_UFS_CRYPTO -- cgit From 568778f5572afd5b30984edd2a4a2c96df8b2b16 Mon Sep 17 00:00:00 2001 From: Len Baker Date: Sat, 25 Sep 2021 13:42:05 +0200 Subject: scsi: advansys: Prefer struct_size() over open-coded arithmetic As noted in the "Deprecated Interfaces, Language Features, Attributes, and Conventions" documentation [1], size calculations (especially multiplication) should not be performed in memory allocator (or similar) function arguments due to the risk of them overflowing. This could lead to values wrapping around and a smaller allocation being made than the caller was expecting. Using those allocations could lead to linear overflows of heap memory and other misbehaviors. Use the struct_size() helper to do the arithmetic instead of the argument "size + count * size" in the kzalloc() function. This code was detected with the help of Coccinelle and audited and fixed manually. [1] https://www.kernel.org/doc/html/latest/process/deprecated.html#open-coded-arithmetic-in-allocator-arguments Link: https://lore.kernel.org/r/20210925114205.11377-1-len.baker@gmx.com Reviewed-by: Gustavo A. R. Silva Signed-off-by: Len Baker Signed-off-by: Martin K. Petersen --- drivers/scsi/advansys.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index ffb391967573..e341b3372482 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -7477,8 +7477,8 @@ static int asc_build_req(struct asc_board *boardp, struct scsi_cmnd *scp, return ASC_ERROR; } - asc_sg_head = kzalloc(sizeof(asc_scsi_q->sg_head) + - use_sg * sizeof(struct asc_sg_list), GFP_ATOMIC); + asc_sg_head = kzalloc(struct_size(asc_sg_head, sg_list, use_sg), + GFP_ATOMIC); if (!asc_sg_head) { scsi_dma_unmap(scp); set_host_byte(scp, DID_SOFT_ERROR); -- cgit From 8d807a068090ef15480d9e812f60d3356aa66b0e Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Sat, 25 Sep 2021 20:53:23 +0800 Subject: scsi: lpfc: Fix a function name in comments Use dma_map_sg() instead of pci_map_sg() in comments. Link: https://lore.kernel.org/r/20210925125324.1760-3-caihuoqing@baidu.com Signed-off-by: Cai Huoqing Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_scsi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 078fbea3f436..f25a9bad995f 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -894,7 +894,7 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) bpl += 2; if (scsi_sg_count(scsi_cmnd)) { /* - * The driver stores the segment count returned from pci_map_sg + * The driver stores the segment count returned from dma_map_sg * because this a count of dma-mappings used to map the use_sg * pages. They are not guaranteed to be the same for those * architectures that implement an IOMMU. @@ -2590,7 +2590,7 @@ lpfc_bg_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, bpl += 2; if (scsi_sg_count(scsi_cmnd)) { /* - * The driver stores the segment count returned from pci_map_sg + * The driver stores the segment count returned from dma_map_sg * because this a count of dma-mappings used to map the use_sg * pages. They are not guaranteed to be the same for those * architectures that implement an IOMMU. @@ -3250,7 +3250,7 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) */ if (scsi_sg_count(scsi_cmnd)) { /* - * The driver stores the segment count returned from pci_map_sg + * The driver stores the segment count returned from dma_map_sg * because this a count of dma-mappings used to map the use_sg * pages. They are not guaranteed to be the same for those * architectures that implement an IOMMU. @@ -3489,7 +3489,7 @@ lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, */ if (scsi_sg_count(scsi_cmnd)) { /* - * The driver stores the segment count returned from pci_map_sg + * The driver stores the segment count returned from dma_map_sg * because this a count of dma-mappings used to map the use_sg * pages. They are not guaranteed to be the same for those * architectures that implement an IOMMU. -- cgit From 9f80eca441a9e1c4682862e44ad3e7a618a0486f Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Sat, 25 Sep 2021 21:29:30 +0800 Subject: scsi: aic7xxx: Fix a function name in comments Use dma_alloc_coherent() instead of pci_alloc_consistent(). Link: https://lore.kernel.org/r/20210925132931.95-1-caihuoqing@baidu.com Signed-off-by: Cai Huoqing Signed-off-by: Martin K. Petersen --- drivers/scsi/aic7xxx/aic79xx_osm.h | 2 +- drivers/scsi/aic7xxx/aic7xxx_osm.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h index 35ec24f28d2c..679a4fd13874 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.h +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h @@ -196,7 +196,7 @@ int ahd_dmamap_unload(struct ahd_softc *, bus_dma_tag_t, bus_dmamap_t); /* * XXX * ahd_dmamap_sync is only used on buffers allocated with - * the pci_alloc_consistent() API. Although I'm not sure how + * the dma_alloc_coherent() API. Although I'm not sure how * this works on architectures with a write buffer, Linux does * not have an API to sync "coherent" memory. Perhaps we need * to do an mb()? diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h index 53240f53b654..4782a304e93c 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h @@ -209,7 +209,7 @@ int ahc_dmamap_unload(struct ahc_softc *, bus_dma_tag_t, bus_dmamap_t); /* * XXX * ahc_dmamap_sync is only used on buffers allocated with - * the pci_alloc_consistent() API. Although I'm not sure how + * the dma_alloc_coherent() API. Although I'm not sure how * this works on architectures with a write buffer, Linux does * not have an API to sync "coherent" memory. Perhaps we need * to do an mb()? -- cgit From 5860d9fb5622ecd79913ac981403c612f6c8a2d8 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 25 Sep 2021 23:41:13 +0100 Subject: scsi: lpfc: Return NULL rather than a plain 0 integer Function lpfc_sli4_perform_vport_cvl() returns a pointer to struct lpfc_nodelist so returning a plain 0 integer isn't good practice. Fix this by returning a NULL instead. Link: https://lore.kernel.org/r/20210925224113.183040-1-colin.king@canonical.com Signed-off-by: Colin Ian King Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index ff2a4e387523..0be8c8ab3d94 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -6564,7 +6564,7 @@ lpfc_sli4_perform_vport_cvl(struct lpfc_vport *vport) /* Cannot find existing Fabric ndlp, so allocate a new one */ ndlp = lpfc_nlp_init(vport, Fabric_DID); if (!ndlp) - return 0; + return NULL; /* Set the node type */ ndlp->nlp_type |= NLP_FABRIC; /* Put ndlp onto node list */ -- cgit From 60c98a87fcaad9e71b835d2096e6665543cfe2e1 Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Mon, 27 Sep 2021 10:46:15 +0200 Subject: scsi: ufs: core: SCSI_UFS_HWMON depends on HWMON=y When building an allmodconfig kernel, the following build error shows up: aarch64-linux-gnu-ld: drivers/scsi/ufs/ufs-hwmon.o: in function `ufs_hwmon_probe': /kernel/next/drivers/scsi/ufs/ufs-hwmon.c:177: undefined reference to `hwmon_device_register_with_info' /kernel/next/drivers/scsi/ufs/ufs-hwmon.c:177:(.text+0x510): relocation truncated to fit: R_AARCH64_CALL26 against undefined symbol `hwmon_device_register_with_info' aarch64-linux-gnu-ld: drivers/scsi/ufs/ufs-hwmon.o: in function `ufs_hwmon_remove': /kernel/next/drivers/scsi/ufs/ufs-hwmon.c:195: undefined reference to `hwmon_device_unregister' /kernel/next/drivers/scsi/ufs/ufs-hwmon.c:195:(.text+0x5c8): relocation truncated to fit: R_AARCH64_CALL26 against undefined symbol `hwmon_device_unregister' aarch64-linux-gnu-ld: drivers/scsi/ufs/ufs-hwmon.o: in function `ufs_hwmon_notify_event': /kernel/next/drivers/scsi/ufs/ufs-hwmon.c:206: undefined reference to `hwmon_notify_event' /kernel/next/drivers/scsi/ufs/ufs-hwmon.c:206:(.text+0x64c): relocation truncated to fit: R_AARCH64_CALL26 against undefined symbol `hwmon_notify_event' aarch64-linux-gnu-ld: /home/anders/src/kernel/next/drivers/scsi/ufs/ufs-hwmon.c:209: undefined reference to `hwmon_notify_event' /kernel/next/drivers/scsi/ufs/ufs-hwmon.c:209:(.text+0x66c): relocation truncated to fit: R_AARCH64_CALL26 against undefined symbol `hwmon_notify_event' Since SCSI_UFS_HWMON can't be built as a module, SCSI_UFS_HWMON has to depend on HWMON=y. Link: https://lore.kernel.org/r/20210927084615.1938432-1-anders.roxell@linaro.org Fixes: e88e2d32200a ("scsi: ufs: core: Probe for temperature notification support") Also-reported-by: Randy Dunlap Acked-by: Randy Dunlap # build-tested Acked-by: Avri Altman Signed-off-by: Anders Roxell Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index af66cb3634a8..b2521b830be7 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -202,7 +202,7 @@ config SCSI_UFS_FAULT_INJECTION config SCSI_UFS_HWMON bool "UFS Temperature Notification" - depends on SCSI_UFSHCD && HWMON + depends on SCSI_UFSHCD=HWMON || HWMON=y help This provides support for UFS hardware monitoring. If enabled, a hardware monitoring device will be created for the UFS device. -- cgit From a5b141a895b592b401d739949d347ca473921c92 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 27 Sep 2021 11:35:18 -0700 Subject: scsi: lpfc: Add support for optional PLDV handling At adapter attachment or SLI port initialization, read the SLIPORT_STATUS register to check for pldv_enable. If found, the driver will perform a PCIe configuration space write when attaching to an SLI port instance that is an LPe32000 series adapter. Link: https://lore.kernel.org/r/20210927183518.22130-1-jsmart2021@gmail.com Co-developed-by: Nigel Kirkland Signed-off-by: Nigel Kirkland Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_hw4.h | 4 ++++ drivers/scsi/lpfc/lpfc_init.c | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 79a4872c2edb..143b73f71333 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -673,6 +673,10 @@ struct lpfc_register { #define lpfc_sliport_status_rdy_SHIFT 23 #define lpfc_sliport_status_rdy_MASK 0x1 #define lpfc_sliport_status_rdy_WORD word0 +#define lpfc_sliport_status_pldv_SHIFT 0 +#define lpfc_sliport_status_pldv_MASK 0x1 +#define lpfc_sliport_status_pldv_WORD word0 +#define CFG_PLD 0x3C #define MAX_IF_TYPE_2_RESETS 6 #define LPFC_CTL_PORT_CTL_OFFSET 0x408 diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 0be8c8ab3d94..b9d3c848ac88 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -68,6 +68,7 @@ static enum cpuhp_state lpfc_cpuhp_state; /* Used when mapping IRQ vectors in a driver centric manner */ static uint32_t lpfc_present_cpu; +static bool lpfc_pldv_detect; static void __lpfc_cpuhp_remove(struct lpfc_hba *phba); static void lpfc_cpuhp_remove(struct lpfc_hba *phba); @@ -9359,7 +9360,15 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba) phba->work_status[0], phba->work_status[1]); port_error = -ENODEV; + break; } + + if (lpfc_pldv_detect && + bf_get(lpfc_sli_intf_sli_family, + &phba->sli4_hba.sli_intf) == + LPFC_SLI_INTF_FAMILY_G6) + pci_write_config_byte(phba->pcidev, + LPFC_SLI_INTF, CFG_PLD); break; case LPFC_SLI_INTF_IF_TYPE_1: default: @@ -11567,6 +11576,9 @@ wait: goto out; } + if (bf_get(lpfc_sliport_status_pldv, ®_data)) + lpfc_pldv_detect = true; + if (!port_reset) { /* * Reset the port now @@ -15560,6 +15572,8 @@ lpfc_init(void) /* Initialize in case vector mapping is needed */ lpfc_present_cpu = num_present_cpus(); + lpfc_pldv_detect = false; + error = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "lpfc/sli4:online", lpfc_cpu_online, lpfc_cpu_offline); -- cgit From 525943a586ef43ed365974deef2ebd9e921f2f83 Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Tue, 28 Sep 2021 02:06:12 -0700 Subject: scsi: ufs: core: Export hibern8 entry and exit functions Qualcomm controllers need to be in hibern8 before scaling up or down the clocks. Hence, export the hibern8 entry and exit functions. Link: https://lore.kernel.org/r/a29bfdd0c8f1d1a3e5fb69e43ea277c97a7f0cb6.1632818942.git.nguyenb@codeaurora.org Reviewed-by: Bart Van Assche Reviewed-by: Alim Akhtar Signed-off-by: Asutosh Das Signed-off-by: Bao D. Nguyen Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 4 ++-- drivers/scsi/ufs/ufshcd.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index debef631c89a..9faf02cbb9ad 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -227,7 +227,6 @@ static void ufshcd_hba_exit(struct ufs_hba *hba); static int ufshcd_clear_ua_wluns(struct ufs_hba *hba); static int ufshcd_probe_hba(struct ufs_hba *hba, bool async); static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on); -static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba); static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba); static int ufshcd_host_reset_and_restore(struct ufs_hba *hba); static void ufshcd_resume_clkscaling(struct ufs_hba *hba); @@ -4116,7 +4115,7 @@ int ufshcd_link_recovery(struct ufs_hba *hba) } EXPORT_SYMBOL_GPL(ufshcd_link_recovery); -static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba) +int ufshcd_uic_hibern8_enter(struct ufs_hba *hba) { int ret; struct uic_command uic_cmd = {0}; @@ -4138,6 +4137,7 @@ static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba) return ret; } +EXPORT_SYMBOL_GPL(ufshcd_uic_hibern8_enter); int ufshcd_uic_hibern8_exit(struct ufs_hba *hba) { diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 92d05329de68..ed960d206260 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -1011,6 +1011,7 @@ int ufshcd_init(struct ufs_hba *, void __iomem *, unsigned int); int ufshcd_link_recovery(struct ufs_hba *hba); int ufshcd_make_hba_operational(struct ufs_hba *hba); void ufshcd_remove(struct ufs_hba *); +int ufshcd_uic_hibern8_enter(struct ufs_hba *hba); int ufshcd_uic_hibern8_exit(struct ufs_hba *hba); void ufshcd_delay_us(unsigned long us, unsigned long tolerance); int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask, -- cgit From a0cea83332ae2ba4b740a89fc094aba3298825db Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Tue, 28 Sep 2021 02:06:13 -0700 Subject: scsi: ufs: ufs-qcom: Enter and exit hibern8 during clock scaling Qualcomm controller needs to be in hibern8 before scaling clocks. This change puts the controller in hibern8 state before scaling and brings it out after scaling of clocks. Link: https://lore.kernel.org/r/212b7aaf6d834c4a8c682fdac4a59b84013ed573.1632818942.git.nguyenb@codeaurora.org Reviewed-by: Alim Akhtar Signed-off-by: Asutosh Das Signed-off-by: Bao D. Nguyen Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs-qcom.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 92d4c61fc9d0..92f5bb4965fa 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -1212,24 +1212,34 @@ static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba, int err = 0; if (status == PRE_CHANGE) { + err = ufshcd_uic_hibern8_enter(hba); + if (err) + return err; if (scale_up) err = ufs_qcom_clk_scale_up_pre_change(hba); else err = ufs_qcom_clk_scale_down_pre_change(hba); + if (err) + ufshcd_uic_hibern8_exit(hba); + } else { if (scale_up) err = ufs_qcom_clk_scale_up_post_change(hba); else err = ufs_qcom_clk_scale_down_post_change(hba); - if (err || !dev_req_params) + + if (err || !dev_req_params) { + ufshcd_uic_hibern8_exit(hba); goto out; + } ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx, dev_req_params->pwr_rx, dev_req_params->hs_rate, false); + ufshcd_uic_hibern8_exit(hba); } out: -- cgit From ca4ff9e751eb9c6371813ca9cc00c45444048088 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 22 Aug 2021 13:55:33 +0200 Subject: scsi: elx: efct: Switch from 'pci_' to 'dma_' API The wrappers in include/linux/pci-dma-compat.h should go away. The patch has been generated with the coccinelle script below. It has been hand modified to use 'dma_set_mask_and_coherent()' instead of 'pci_set_dma_mask()/pci_set_consistent_dma_mask()' when applicable. This is less verbose. It has been compile tested. @@ @@ - PCI_DMA_BIDIRECTIONAL + DMA_BIDIRECTIONAL @@ @@ - PCI_DMA_TODEVICE + DMA_TO_DEVICE @@ @@ - PCI_DMA_FROMDEVICE + DMA_FROM_DEVICE @@ @@ - PCI_DMA_NONE + DMA_NONE @@ expression e1, e2, e3; @@ - pci_alloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3; @@ - pci_zalloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3, e4; @@ - pci_free_consistent(e1, e2, e3, e4) + dma_free_coherent(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_single(e1, e2, e3, e4) + dma_map_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_single(e1, e2, e3, e4) + dma_unmap_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4, e5; @@ - pci_map_page(e1, e2, e3, e4, e5) + dma_map_page(&e1->dev, e2, e3, e4, e5) @@ expression e1, e2, e3, e4; @@ - pci_unmap_page(e1, e2, e3, e4) + dma_unmap_page(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_sg(e1, e2, e3, e4) + dma_map_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_sg(e1, e2, e3, e4) + dma_unmap_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_cpu(e1, e2, e3, e4) + dma_sync_single_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_device(e1, e2, e3, e4) + dma_sync_single_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_cpu(e1, e2, e3, e4) + dma_sync_sg_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_device(e1, e2, e3, e4) + dma_sync_sg_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2; @@ - pci_dma_mapping_error(e1, e2) + dma_mapping_error(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_dma_mask(e1, e2) + dma_set_mask(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_consistent_dma_mask(e1, e2) + dma_set_coherent_mask(&e1->dev, e2) Link: https://lore.kernel.org/r/3899b1ed4abac581c30845d82f33ec6df8b38976.1629633207.git.christophe.jaillet@wanadoo.fr Signed-off-by: Christophe JAILLET Signed-off-by: Martin K. Petersen --- drivers/scsi/elx/efct/efct_driver.c | 6 ++---- drivers/scsi/elx/efct/efct_lio.c | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/elx/efct/efct_driver.c b/drivers/scsi/elx/efct/efct_driver.c index eab68fd9337a..b2b61bc45f12 100644 --- a/drivers/scsi/elx/efct/efct_driver.c +++ b/drivers/scsi/elx/efct/efct_driver.c @@ -541,11 +541,9 @@ efct_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, efct); - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0 || - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) { + if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)) != 0) { dev_warn(&pdev->dev, "trying DMA_BIT_MASK(32)\n"); - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0 || - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) { + if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)) != 0) { dev_err(&pdev->dev, "setting DMA_BIT_MASK failed\n"); rc = -1; goto dma_mask_out; diff --git a/drivers/scsi/elx/efct/efct_lio.c b/drivers/scsi/elx/efct/efct_lio.c index bb3b460dc0bc..5f61d761258a 100644 --- a/drivers/scsi/elx/efct/efct_lio.c +++ b/drivers/scsi/elx/efct/efct_lio.c @@ -382,7 +382,7 @@ efct_lio_sg_map(struct efct_io *io) struct efct_scsi_tgt_io *ocp = &io->tgt_io; struct se_cmd *cmd = &ocp->cmd; - ocp->seg_map_cnt = pci_map_sg(io->efct->pci, cmd->t_data_sg, + ocp->seg_map_cnt = dma_map_sg(&io->efct->pci->dev, cmd->t_data_sg, cmd->t_data_nents, cmd->data_direction); if (ocp->seg_map_cnt == 0) return -EFAULT; @@ -398,7 +398,7 @@ efct_lio_sg_unmap(struct efct_io *io) if (WARN_ON(!ocp->seg_map_cnt || !cmd->t_data_sg)) return; - pci_unmap_sg(io->efct->pci, cmd->t_data_sg, + dma_unmap_sg(&io->efct->pci->dev, cmd->t_data_sg, ocp->seg_map_cnt, cmd->data_direction); ocp->seg_map_cnt = 0; } -- cgit From 6bd49b1a8d43ec118c55f3aaa7577729b52bde15 Mon Sep 17 00:00:00 2001 From: John Garry Date: Mon, 13 Sep 2021 18:14:07 +0800 Subject: scsi: core: Delete scsi_{get,free}_host_dev() Since commit 0653c358d2dc ("scsi: Drop gdth driver"), functions scsi_{get,free}_host_dev() no longer have any in-tree users, so delete them. Link: https://lore.kernel.org/r/1631528047-30150-1-git-send-email-john.garry@huawei.com Reviewed-by: Bart Van Assche Reviewed-by: Christoph Hellwig Signed-off-by: John Garry Signed-off-by: Martin K. Petersen Nacked-by: Hannes Reinecke --- drivers/scsi/scsi_scan.c | 57 ------------------------------------------------ include/scsi/scsi_host.h | 10 --------- 2 files changed, 67 deletions(-) diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index fe22191522a3..0d0381df25f7 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -1902,60 +1902,3 @@ void scsi_forget_host(struct Scsi_Host *shost) spin_unlock_irqrestore(shost->host_lock, flags); } -/** - * scsi_get_host_dev - Create a scsi_device that points to the host adapter itself - * @shost: Host that needs a scsi_device - * - * Lock status: None assumed. - * - * Returns: The scsi_device or NULL - * - * Notes: - * Attach a single scsi_device to the Scsi_Host - this should - * be made to look like a "pseudo-device" that points to the - * HA itself. - * - * Note - this device is not accessible from any high-level - * drivers (including generics), which is probably not - * optimal. We can add hooks later to attach. - */ -struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost) -{ - struct scsi_device *sdev = NULL; - struct scsi_target *starget; - - mutex_lock(&shost->scan_mutex); - if (!scsi_host_scan_allowed(shost)) - goto out; - starget = scsi_alloc_target(&shost->shost_gendev, 0, shost->this_id); - if (!starget) - goto out; - - sdev = scsi_alloc_sdev(starget, 0, NULL); - if (sdev) - sdev->borken = 0; - else - scsi_target_reap(starget); - put_device(&starget->dev); - out: - mutex_unlock(&shost->scan_mutex); - return sdev; -} -EXPORT_SYMBOL(scsi_get_host_dev); - -/** - * scsi_free_host_dev - Free a scsi_device that points to the host adapter itself - * @sdev: Host device to be freed - * - * Lock status: None assumed. - * - * Returns: Nothing - */ -void scsi_free_host_dev(struct scsi_device *sdev) -{ - BUG_ON(sdev->id != sdev->host->this_id); - - __scsi_remove_device(sdev); -} -EXPORT_SYMBOL(scsi_free_host_dev); - diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 75363707b73f..bc9c45ced145 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -797,16 +797,6 @@ void scsi_host_busy_iter(struct Scsi_Host *, struct class_container; -/* - * These two functions are used to allocate and free a pseudo device - * which will connect to the host adapter itself rather than any - * physical device. You must deallocate when you are done with the - * thing. This physical pseudo-device isn't real and won't be available - * from any high-level drivers. - */ -extern void scsi_free_host_dev(struct scsi_device *); -extern struct scsi_device *scsi_get_host_dev(struct Scsi_Host *); - /* * DIF defines the exchange of protection information between * initiator and SBC block device. -- cgit From 17b49bcbf8351d3dbe57204468ac34f033ed60bc Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Fri, 20 Aug 2021 16:02:53 +0900 Subject: scsi: core: Fix scsi_mode_sense() buffer length handling Several problems exist with scsi_mode_sense() buffer length handling: 1) The allocation length field of the MODE SENSE(10) command is 16-bits, occupying bytes 7 and 8 of the CDB. With this command, access to mode pages larger than 255 bytes is thus possible. However, the CDB allocation length field is set by assigning len to byte 8 only, thus truncating buffer length larger than 255. 2) If scsi_mode_sense() is called with len smaller than 8 with sdev->use_10_for_ms set, or smaller than 4 otherwise, the buffer length is increased to 8 and 4 respectively, and the buffer is zero filled with these increased values, thus corrupting the memory following the buffer. Fix these 2 problems by using put_unaligned_be16() to set the allocation length field of MODE SENSE(10) CDB and by returning an error when len is too small. Furthermore, if len is larger than 255B, always try MODE SENSE(10) first, even if the device driver did not set sdev->use_10_for_ms. In case of invalid opcode error for MODE SENSE(10), access to mode pages larger than 255 bytes are not retried using MODE SENSE(6). To avoid buffer length overflows for the MODE_SENSE(10) case, check that len is smaller than 65535 bytes. While at it, also fix the folowing: * Use get_unaligned_be16() to retrieve the mode data length and block descriptor length fields of the mode sense reply header instead of using an open coded calculation. * Fix the kdoc dbd argument explanation: the DBD bit stands for Disable Block Descriptor, which is the opposite of what the dbd argument description was. Link: https://lore.kernel.org/r/20210820070255.682775-2-damien.lemoal@wdc.com Signed-off-by: Damien Le Moal Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_lib.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 572673873ddf..701d8e8480f2 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2075,7 +2075,7 @@ EXPORT_SYMBOL_GPL(scsi_mode_select); /** * scsi_mode_sense - issue a mode sense, falling back from 10 to six bytes if necessary. * @sdev: SCSI device to be queried - * @dbd: set if mode sense will allow block descriptors to be returned + * @dbd: set to prevent mode sense from returning block descriptors * @modepage: mode page being requested * @buffer: request buffer (may not be smaller than eight bytes) * @len: length of request buffer. @@ -2110,18 +2110,18 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, sshdr = &my_sshdr; retry: - use_10_for_ms = sdev->use_10_for_ms; + use_10_for_ms = sdev->use_10_for_ms || len > 255; if (use_10_for_ms) { - if (len < 8) - len = 8; + if (len < 8 || len > 65535) + return -EINVAL; cmd[0] = MODE_SENSE_10; - cmd[8] = len; + put_unaligned_be16(len, &cmd[7]); header_length = 8; } else { if (len < 4) - len = 4; + return -EINVAL; cmd[0] = MODE_SENSE; cmd[4] = len; @@ -2145,9 +2145,15 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, if ((sshdr->sense_key == ILLEGAL_REQUEST) && (sshdr->asc == 0x20) && (sshdr->ascq == 0)) { /* - * Invalid command operation code + * Invalid command operation code: retry using + * MODE SENSE(6) if this was a MODE SENSE(10) + * request, except if the request mode page is + * too large for MODE SENSE single byte + * allocation length field. */ if (use_10_for_ms) { + if (len > 255) + return -EIO; sdev->use_10_for_ms = 0; goto retry; } @@ -2171,12 +2177,11 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, data->longlba = 0; data->block_descriptor_length = 0; } else if (use_10_for_ms) { - data->length = buffer[0]*256 + buffer[1] + 2; + data->length = get_unaligned_be16(&buffer[0]) + 2; data->medium_type = buffer[2]; data->device_specific = buffer[3]; data->longlba = buffer[4] & 0x01; - data->block_descriptor_length = buffer[6]*256 - + buffer[7]; + data->block_descriptor_length = get_unaligned_be16(&buffer[6]); } else { data->length = buffer[0] + 1; data->medium_type = buffer[1]; -- cgit From a7d6840bed0c2b16ac3071b74b5fcf08fc488241 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Fri, 20 Aug 2021 16:02:54 +0900 Subject: scsi: core: Fix scsi_mode_select() buffer length handling The MODE SELECT(6) command allows handling mode page buffers that are up to 255 bytes, including the 4 byte header needed in front of the page buffer. For requests larger than this limit, automatically use the MODE SELECT(10) command. In both cases, since scsi_mode_select() adds the mode select page header, checks on the buffer length value must include this header size to avoid overflows of the command CDB allocation length field. While at it, use put_unaligned_be16() for setting the header block descriptor length and CDB allocation length when using MODE SELECT(10). [mkp: fix MODE SENSE vs. MODE SELECT confusion] Link: https://lore.kernel.org/r/20210820070255.682775-3-damien.lemoal@wdc.com Signed-off-by: Damien Le Moal Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_lib.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 701d8e8480f2..dcf105287a76 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2026,8 +2026,15 @@ scsi_mode_select(struct scsi_device *sdev, int pf, int sp, int modepage, memset(cmd, 0, sizeof(cmd)); cmd[1] = (pf ? 0x10 : 0) | (sp ? 0x01 : 0); - if (sdev->use_10_for_ms) { - if (len > 65535) + /* + * Use MODE SELECT(10) if the device asked for it or if the mode page + * and the mode select header cannot fit within the maximumm 255 bytes + * of the MODE SELECT(6) command. + */ + if (sdev->use_10_for_ms || + len + 4 > 255 || + data->block_descriptor_length > 255) { + if (len > 65535 - 8) return -EINVAL; real_buffer = kmalloc(8 + len, GFP_KERNEL); if (!real_buffer) @@ -2040,15 +2047,13 @@ scsi_mode_select(struct scsi_device *sdev, int pf, int sp, int modepage, real_buffer[3] = data->device_specific; real_buffer[4] = data->longlba ? 0x01 : 0; real_buffer[5] = 0; - real_buffer[6] = data->block_descriptor_length >> 8; - real_buffer[7] = data->block_descriptor_length; + put_unaligned_be16(data->block_descriptor_length, + &real_buffer[6]); cmd[0] = MODE_SELECT_10; - cmd[7] = len >> 8; - cmd[8] = len; + put_unaligned_be16(len, &cmd[7]); } else { - if (len > 255 || data->block_descriptor_length > 255 || - data->longlba) + if (data->longlba) return -EINVAL; real_buffer = kmalloc(4 + len, GFP_KERNEL); -- cgit From c749301ebee82eb5e97dec14b6ab31a4aabe37a6 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Fri, 20 Aug 2021 16:02:55 +0900 Subject: scsi: sd: Fix sd_do_mode_sense() buffer length handling For devices that explicitly asked for MODE SENSE(10) use, make sure that scsi_mode_sense() is called with a buffer of at least 8 bytes so that the sense header fits. Link: https://lore.kernel.org/r/20210820070255.682775-4-damien.lemoal@wdc.com Signed-off-by: Damien Le Moal Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index cbd9999f93a6..71fa70b42c2b 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2604,6 +2604,13 @@ sd_do_mode_sense(struct scsi_disk *sdkp, int dbd, int modepage, unsigned char *buffer, int len, struct scsi_mode_data *data, struct scsi_sense_hdr *sshdr) { + /* + * If we must use MODE SENSE(10), make sure that the buffer length + * is at least 8 bytes so that the mode sense header fits. + */ + if (sdkp->device->use_10_for_ms && len < 8) + len = 8; + return scsi_mode_sense(sdkp->device, dbd, modepage, buffer, len, SD_TIMEOUT, sdkp->max_retries, data, sshdr); -- cgit From 61bc346ce64a3864ac55f5d18bdc1572cda4fb18 Mon Sep 17 00:00:00 2001 From: Eugene Syromiatnikov Date: Wed, 25 Aug 2021 19:06:13 +0200 Subject: uapi/linux/prctl: provide macro definitions for the PR_SCHED_CORE type argument Commit 7ac592aa35a684ff ("sched: prctl() core-scheduling interface") made use of enum pid_type in prctl's arg4; this type and the associated enumeration definitions are not exposed to userspace. Christian has suggested to provide additional macro definitions that convey the meaning of the type argument more in alignment with its actual usage, and this patch does exactly that. Link: https://lore.kernel.org/r/20210825170613.GA3884@asgard.redhat.com Suggested-by: Christian Brauner Acked-by: Christian Brauner Signed-off-by: Eugene Syromiatnikov Complements: 7ac592aa35a684ff ("sched: prctl() core-scheduling interface") Signed-off-by: Christian Brauner --- Documentation/admin-guide/hw-vuln/core-scheduling.rst | 5 +++-- include/uapi/linux/prctl.h | 3 +++ kernel/sched/core_sched.c | 4 ++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Documentation/admin-guide/hw-vuln/core-scheduling.rst b/Documentation/admin-guide/hw-vuln/core-scheduling.rst index 0febe458597c..cf1eeefdfc32 100644 --- a/Documentation/admin-guide/hw-vuln/core-scheduling.rst +++ b/Documentation/admin-guide/hw-vuln/core-scheduling.rst @@ -61,8 +61,9 @@ arg3: ``pid`` of the task for which the operation applies. arg4: - ``pid_type`` for which the operation applies. It is of type ``enum pid_type``. - For example, if arg4 is ``PIDTYPE_TGID``, then the operation of this command + ``pid_type`` for which the operation applies. It is one of + ``PR_SCHED_CORE_SCOPE_``-prefixed macro constants. For example, if arg4 + is ``PR_SCHED_CORE_SCOPE_THREAD_GROUP``, then the operation of this command will be performed for all tasks in the task group of ``pid``. arg5: diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h index 43bd7f713c39..b2e4dc1449b9 100644 --- a/include/uapi/linux/prctl.h +++ b/include/uapi/linux/prctl.h @@ -268,5 +268,8 @@ struct prctl_mm_map { # define PR_SCHED_CORE_SHARE_TO 2 /* push core_sched cookie to pid */ # define PR_SCHED_CORE_SHARE_FROM 3 /* pull core_sched cookie to pid */ # define PR_SCHED_CORE_MAX 4 +# define PR_SCHED_CORE_SCOPE_THREAD 0 +# define PR_SCHED_CORE_SCOPE_THREAD_GROUP 1 +# define PR_SCHED_CORE_SCOPE_PROCESS_GROUP 2 #endif /* _LINUX_PRCTL_H */ diff --git a/kernel/sched/core_sched.c b/kernel/sched/core_sched.c index 9a80e9a474c0..20f640949450 100644 --- a/kernel/sched/core_sched.c +++ b/kernel/sched/core_sched.c @@ -134,6 +134,10 @@ int sched_core_share_pid(unsigned int cmd, pid_t pid, enum pid_type type, if (!static_branch_likely(&sched_smt_present)) return -ENODEV; + BUILD_BUG_ON(PR_SCHED_CORE_SCOPE_THREAD != PIDTYPE_PID); + BUILD_BUG_ON(PR_SCHED_CORE_SCOPE_THREAD_GROUP != PIDTYPE_TGID); + BUILD_BUG_ON(PR_SCHED_CORE_SCOPE_PROCESS_GROUP != PIDTYPE_PGID); + if (type > PIDTYPE_PGID || cmd >= PR_SCHED_CORE_MAX || pid < 0 || (cmd != PR_SCHED_CORE_GET && uaddr)) return -EINVAL; -- cgit From cb94a02e7494c001fa8b5a4c5e16693fafd98530 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 23 Sep 2021 00:46:04 -0700 Subject: perf metric: Restructure struct expr_parse_ctx. A later change to parsing the ids out (in expr__find_other) will potentially drop hashmaps and so it is more convenient to move expr_parse_ctx to have a hashmap pointer rather than a struct value. As this pointer must be freed, rather than just going out of scope, add expr__ctx_new and expr__ctx_free to manage expr_parse_ctx memory. Adjust use of struct expr_parse_ctx accordingly. Reviewed-by: Andi Kleen Signed-off-by: Ian Rogers Tested-by: John Garry Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Jin Yao Cc: Kajol Jain Cc: Mark Rutland Cc: Namhyung Kim Cc: Paul Clarke Cc: Peter Zijlstra Cc: Sandeep Dasgupta Cc: Stephane Eranian Link: https://lore.kernel.org/r/20210923074616.674826-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/expr.c | 81 ++++++++++++++++++++++--------------------- tools/perf/tests/pmu-events.c | 47 +++++++++++++++---------- tools/perf/util/expr.c | 39 ++++++++++++++++----- tools/perf/util/expr.h | 5 +-- tools/perf/util/metricgroup.c | 44 ++++++++++++----------- tools/perf/util/stat-shadow.c | 50 ++++++++++++++++---------- 6 files changed, 159 insertions(+), 107 deletions(-) diff --git a/tools/perf/tests/expr.c b/tools/perf/tests/expr.c index 4d01051951cd..b0a3b5fd0c00 100644 --- a/tools/perf/tests/expr.c +++ b/tools/perf/tests/expr.c @@ -22,67 +22,70 @@ int test__expr(struct test *t __maybe_unused, int subtest __maybe_unused) const char *p; double val; int ret; - struct expr_parse_ctx ctx; + struct expr_parse_ctx *ctx; - expr__ctx_init(&ctx); - expr__add_id_val(&ctx, strdup("FOO"), 1); - expr__add_id_val(&ctx, strdup("BAR"), 2); + ctx = expr__ctx_new(); + TEST_ASSERT_VAL("expr__ctx_new", ctx); + expr__add_id_val(ctx, strdup("FOO"), 1); + expr__add_id_val(ctx, strdup("BAR"), 2); - ret = test(&ctx, "1+1", 2); - ret |= test(&ctx, "FOO+BAR", 3); - ret |= test(&ctx, "(BAR/2)%2", 1); - ret |= test(&ctx, "1 - -4", 5); - ret |= test(&ctx, "(FOO-1)*2 + (BAR/2)%2 - -4", 5); - ret |= test(&ctx, "1-1 | 1", 1); - ret |= test(&ctx, "1-1 & 1", 0); - ret |= test(&ctx, "min(1,2) + 1", 2); - ret |= test(&ctx, "max(1,2) + 1", 3); - ret |= test(&ctx, "1+1 if 3*4 else 0", 2); - ret |= test(&ctx, "1.1 + 2.1", 3.2); - ret |= test(&ctx, ".1 + 2.", 2.1); - ret |= test(&ctx, "d_ratio(1, 2)", 0.5); - ret |= test(&ctx, "d_ratio(2.5, 0)", 0); - ret |= test(&ctx, "1.1 < 2.2", 1); - ret |= test(&ctx, "2.2 > 1.1", 1); - ret |= test(&ctx, "1.1 < 1.1", 0); - ret |= test(&ctx, "2.2 > 2.2", 0); - ret |= test(&ctx, "2.2 < 1.1", 0); - ret |= test(&ctx, "1.1 > 2.2", 0); + ret = test(ctx, "1+1", 2); + ret |= test(ctx, "FOO+BAR", 3); + ret |= test(ctx, "(BAR/2)%2", 1); + ret |= test(ctx, "1 - -4", 5); + ret |= test(ctx, "(FOO-1)*2 + (BAR/2)%2 - -4", 5); + ret |= test(ctx, "1-1 | 1", 1); + ret |= test(ctx, "1-1 & 1", 0); + ret |= test(ctx, "min(1,2) + 1", 2); + ret |= test(ctx, "max(1,2) + 1", 3); + ret |= test(ctx, "1+1 if 3*4 else 0", 2); + ret |= test(ctx, "1.1 + 2.1", 3.2); + ret |= test(ctx, ".1 + 2.", 2.1); + ret |= test(ctx, "d_ratio(1, 2)", 0.5); + ret |= test(ctx, "d_ratio(2.5, 0)", 0); + ret |= test(ctx, "1.1 < 2.2", 1); + ret |= test(ctx, "2.2 > 1.1", 1); + ret |= test(ctx, "1.1 < 1.1", 0); + ret |= test(ctx, "2.2 > 2.2", 0); + ret |= test(ctx, "2.2 < 1.1", 0); + ret |= test(ctx, "1.1 > 2.2", 0); - if (ret) + if (ret) { + expr__ctx_free(ctx); return ret; + } p = "FOO/0"; - ret = expr__parse(&val, &ctx, p, 1); + ret = expr__parse(&val, ctx, p, 1); TEST_ASSERT_VAL("division by zero", ret == -1); p = "BAR/"; - ret = expr__parse(&val, &ctx, p, 1); + ret = expr__parse(&val, ctx, p, 1); TEST_ASSERT_VAL("missing operand", ret == -1); - expr__ctx_clear(&ctx); + expr__ctx_clear(ctx); TEST_ASSERT_VAL("find other", expr__find_other("FOO + BAR + BAZ + BOZO", "FOO", - &ctx, 1) == 0); - TEST_ASSERT_VAL("find other", hashmap__size(&ctx.ids) == 3); - TEST_ASSERT_VAL("find other", hashmap__find(&ctx.ids, "BAR", + ctx, 1) == 0); + TEST_ASSERT_VAL("find other", hashmap__size(ctx->ids) == 3); + TEST_ASSERT_VAL("find other", hashmap__find(ctx->ids, "BAR", (void **)&val_ptr)); - TEST_ASSERT_VAL("find other", hashmap__find(&ctx.ids, "BAZ", + TEST_ASSERT_VAL("find other", hashmap__find(ctx->ids, "BAZ", (void **)&val_ptr)); - TEST_ASSERT_VAL("find other", hashmap__find(&ctx.ids, "BOZO", + TEST_ASSERT_VAL("find other", hashmap__find(ctx->ids, "BOZO", (void **)&val_ptr)); - expr__ctx_clear(&ctx); + expr__ctx_clear(ctx); TEST_ASSERT_VAL("find other", expr__find_other("EVENT1\\,param\\=?@ + EVENT2\\,param\\=?@", - NULL, &ctx, 3) == 0); - TEST_ASSERT_VAL("find other", hashmap__size(&ctx.ids) == 2); - TEST_ASSERT_VAL("find other", hashmap__find(&ctx.ids, "EVENT1,param=3/", + NULL, ctx, 3) == 0); + TEST_ASSERT_VAL("find other", hashmap__size(ctx->ids) == 2); + TEST_ASSERT_VAL("find other", hashmap__find(ctx->ids, "EVENT1,param=3/", (void **)&val_ptr)); - TEST_ASSERT_VAL("find other", hashmap__find(&ctx.ids, "EVENT2,param=3/", + TEST_ASSERT_VAL("find other", hashmap__find(ctx->ids, "EVENT2,param=3/", (void **)&val_ptr)); - expr__ctx_clear(&ctx); + expr__ctx_free(ctx); return 0; } diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c index f14266a4c513..91076ab0514b 100644 --- a/tools/perf/tests/pmu-events.c +++ b/tools/perf/tests/pmu-events.c @@ -836,7 +836,7 @@ static int resolve_metric_simple(struct expr_parse_ctx *pctx, do { all = true; - hashmap__for_each_entry_safe((&pctx->ids), cur, cur_tmp, bkt) { + hashmap__for_each_entry_safe(pctx->ids, cur, cur_tmp, bkt) { struct metric_ref *ref; struct pmu_event *pe; @@ -890,9 +890,14 @@ static int test_parsing(void) struct pmu_event *pe; int i, j, k; int ret = 0; - struct expr_parse_ctx ctx; + struct expr_parse_ctx *ctx; double result; + ctx = expr__ctx_new(); + if (!ctx) { + pr_debug("expr__ctx_new failed"); + return TEST_FAIL; + } i = 0; for (;;) { map = &pmu_events_map[i++]; @@ -910,15 +915,15 @@ static int test_parsing(void) break; if (!pe->metric_expr) continue; - expr__ctx_init(&ctx); - if (expr__find_other(pe->metric_expr, NULL, &ctx, 0) + expr__ctx_clear(ctx); + if (expr__find_other(pe->metric_expr, NULL, ctx, 0) < 0) { expr_failure("Parse other failed", map, pe); ret++; continue; } - if (resolve_metric_simple(&ctx, &compound_list, map, + if (resolve_metric_simple(ctx, &compound_list, map, pe->metric_name)) { expr_failure("Could not resolve metrics", map, pe); ret++; @@ -931,27 +936,27 @@ static int test_parsing(void) * make them unique. */ k = 1; - hashmap__for_each_entry((&ctx.ids), cur, bkt) - expr__add_id_val(&ctx, strdup(cur->key), k++); + hashmap__for_each_entry(ctx->ids, cur, bkt) + expr__add_id_val(ctx, strdup(cur->key), k++); - hashmap__for_each_entry((&ctx.ids), cur, bkt) { + hashmap__for_each_entry(ctx->ids, cur, bkt) { if (check_parse_cpu(cur->key, map == cpus_map, pe)) ret++; } list_for_each_entry_safe(metric, tmp, &compound_list, list) { - expr__add_ref(&ctx, &metric->metric_ref); + expr__add_ref(ctx, &metric->metric_ref); free(metric); } - if (expr__parse(&result, &ctx, pe->metric_expr, 0)) { + if (expr__parse(&result, ctx, pe->metric_expr, 0)) { expr_failure("Parse failed", map, pe); ret++; } - expr__ctx_clear(&ctx); } } + expr__ctx_free(ctx); /* TODO: fail when not ok */ exit: return ret == 0 ? TEST_OK : TEST_SKIP; @@ -971,7 +976,7 @@ static struct test_metric metrics[] = { static int metric_parse_fake(const char *str) { - struct expr_parse_ctx ctx; + struct expr_parse_ctx *ctx; struct hashmap_entry *cur; double result; int ret = -1; @@ -980,8 +985,12 @@ static int metric_parse_fake(const char *str) pr_debug("parsing '%s'\n", str); - expr__ctx_init(&ctx); - if (expr__find_other(str, NULL, &ctx, 0) < 0) { + ctx = expr__ctx_new(); + if (!ctx) { + pr_debug("expr__ctx_new failed"); + return TEST_FAIL; + } + if (expr__find_other(str, NULL, ctx, 0) < 0) { pr_err("expr__find_other failed\n"); return -1; } @@ -992,23 +1001,23 @@ static int metric_parse_fake(const char *str) * make them unique. */ i = 1; - hashmap__for_each_entry((&ctx.ids), cur, bkt) - expr__add_id_val(&ctx, strdup(cur->key), i++); + hashmap__for_each_entry(ctx->ids, cur, bkt) + expr__add_id_val(ctx, strdup(cur->key), i++); - hashmap__for_each_entry((&ctx.ids), cur, bkt) { + hashmap__for_each_entry(ctx->ids, cur, bkt) { if (check_parse_fake(cur->key)) { pr_err("check_parse_fake failed\n"); goto out; } } - if (expr__parse(&result, &ctx, str, 0)) + if (expr__parse(&result, ctx, str, 0)) pr_err("expr__parse failed\n"); else ret = 0; out: - expr__ctx_clear(&ctx); + expr__ctx_free(ctx); return ret; } diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c index a850fd0be3ee..7b1c06772a49 100644 --- a/tools/perf/util/expr.c +++ b/tools/perf/util/expr.c @@ -73,7 +73,7 @@ int expr__add_id(struct expr_parse_ctx *ctx, const char *id) data_ptr->parent = ctx->parent; data_ptr->kind = EXPR_ID_DATA__PARENT; - ret = hashmap__set(&ctx->ids, id, data_ptr, + ret = hashmap__set(ctx->ids, id, data_ptr, (const void **)&old_key, (void **)&old_data); if (ret) free(data_ptr); @@ -95,7 +95,7 @@ int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val) data_ptr->val = val; data_ptr->kind = EXPR_ID_DATA__VALUE; - ret = hashmap__set(&ctx->ids, id, data_ptr, + ret = hashmap__set(ctx->ids, id, data_ptr, (const void **)&old_key, (void **)&old_data); if (ret) free(data_ptr); @@ -140,7 +140,7 @@ int expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref) data_ptr->ref.metric_expr = ref->metric_expr; data_ptr->kind = EXPR_ID_DATA__REF; - ret = hashmap__set(&ctx->ids, name, data_ptr, + ret = hashmap__set(ctx->ids, name, data_ptr, (const void **)&old_key, (void **)&old_data); if (ret) free(data_ptr); @@ -156,7 +156,7 @@ int expr__add_ref(struct expr_parse_ctx *ctx, struct metric_ref *ref) int expr__get_id(struct expr_parse_ctx *ctx, const char *id, struct expr_id_data **data) { - return hashmap__find(&ctx->ids, id, (void **)data) ? 0 : -1; + return hashmap__find(ctx->ids, id, (void **)data) ? 0 : -1; } int expr__resolve_id(struct expr_parse_ctx *ctx, const char *id, @@ -205,15 +205,23 @@ void expr__del_id(struct expr_parse_ctx *ctx, const char *id) struct expr_id_data *old_val = NULL; char *old_key = NULL; - hashmap__delete(&ctx->ids, id, + hashmap__delete(ctx->ids, id, (const void **)&old_key, (void **)&old_val); free(old_key); free(old_val); } -void expr__ctx_init(struct expr_parse_ctx *ctx) +struct expr_parse_ctx *expr__ctx_new(void) { - hashmap__init(&ctx->ids, key_hash, key_equal, NULL); + struct expr_parse_ctx *ctx; + + ctx = malloc(sizeof(struct expr_parse_ctx)); + if (!ctx) + return NULL; + + ctx->ids = hashmap__new(key_hash, key_equal, NULL); + ctx->parent = NULL; + return ctx; } void expr__ctx_clear(struct expr_parse_ctx *ctx) @@ -221,11 +229,24 @@ void expr__ctx_clear(struct expr_parse_ctx *ctx) struct hashmap_entry *cur; size_t bkt; - hashmap__for_each_entry((&ctx->ids), cur, bkt) { + hashmap__for_each_entry(ctx->ids, cur, bkt) { + free((char *)cur->key); + free(cur->value); + } + hashmap__clear(ctx->ids); +} + +void expr__ctx_free(struct expr_parse_ctx *ctx) +{ + struct hashmap_entry *cur; + size_t bkt; + + hashmap__for_each_entry(ctx->ids, cur, bkt) { free((char *)cur->key); free(cur->value); } - hashmap__clear(&ctx->ids); + hashmap__free(ctx->ids); + free(ctx); } static int diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h index 85df3e4771e4..5fa394f10418 100644 --- a/tools/perf/util/expr.h +++ b/tools/perf/util/expr.h @@ -19,7 +19,7 @@ struct expr_id { }; struct expr_parse_ctx { - struct hashmap ids; + struct hashmap *ids; struct expr_id *parent; }; @@ -30,8 +30,9 @@ struct expr_scanner_ctx { int runtime; }; -void expr__ctx_init(struct expr_parse_ctx *ctx); +struct expr_parse_ctx *expr__ctx_new(void); void expr__ctx_clear(struct expr_parse_ctx *ctx); +void expr__ctx_free(struct expr_parse_ctx *ctx); void expr__del_id(struct expr_parse_ctx *ctx, const char *id); int expr__add_id(struct expr_parse_ctx *ctx, const char *id); int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val); diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index 29b747ac31c1..b7924a2f1f45 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -118,7 +118,7 @@ struct metric_ref_node { struct metric { struct list_head nd; - struct expr_parse_ctx pctx; + struct expr_parse_ctx *pctx; const char *metric_name; const char *metric_expr; const char *metric_unit; @@ -198,7 +198,7 @@ static struct evsel *find_evsel_group(struct evlist *perf_evlist, struct evsel *ev, *current_leader = NULL; struct expr_id_data *val_ptr; int i = 0, matched_events = 0, events_to_match; - const int idnum = (int)hashmap__size(&pctx->ids); + const int idnum = (int)hashmap__size(pctx->ids); /* * duration_time is always grouped separately, when events are grouped @@ -206,7 +206,7 @@ static struct evsel *find_evsel_group(struct evlist *perf_evlist, * add it to metric_events at the end. */ if (!has_constraint && - hashmap__find(&pctx->ids, "duration_time", (void **)&val_ptr)) + hashmap__find(pctx->ids, "duration_time", (void **)&val_ptr)) events_to_match = idnum - 1; else events_to_match = idnum; @@ -242,7 +242,7 @@ static struct evsel *find_evsel_group(struct evlist *perf_evlist, if (contains_event(metric_events, matched_events, ev->name)) continue; /* Does this event belong to the parse context? */ - if (hashmap__find(&pctx->ids, ev->name, (void **)&val_ptr)) + if (hashmap__find(pctx->ids, ev->name, (void **)&val_ptr)) metric_events[matched_events++] = ev; if (matched_events == events_to_match) @@ -322,12 +322,12 @@ static int metricgroup__setup_events(struct list_head *groups, struct metric_ref *metric_refs = NULL; metric_events = calloc(sizeof(void *), - hashmap__size(&m->pctx.ids) + 1); + hashmap__size(m->pctx->ids) + 1); if (!metric_events) { ret = -ENOMEM; break; } - evsel = find_evsel_group(perf_evlist, &m->pctx, + evsel = find_evsel_group(perf_evlist, m->pctx, metric_no_merge, m->has_constraint, metric_events, evlist_used); @@ -693,7 +693,7 @@ static void metricgroup__add_metric_weak_group(struct strbuf *events, size_t bkt; bool no_group = true, has_duration = false; - hashmap__for_each_entry((&ctx->ids), cur, bkt) { + hashmap__for_each_entry(ctx->ids, cur, bkt) { pr_debug("found event %s\n", (const char *)cur->key); /* * Duration time maps to a software event and can make @@ -724,7 +724,7 @@ static void metricgroup__add_metric_non_group(struct strbuf *events, size_t bkt; bool first = true; - hashmap__for_each_entry((&ctx->ids), cur, bkt) { + hashmap__for_each_entry(ctx->ids, cur, bkt) { if (!first) strbuf_addf(events, ","); strbuf_addf(events, "%s", (const char *)cur->key); @@ -799,7 +799,11 @@ static int __add_metric(struct list_head *metric_list, if (!m) return -ENOMEM; - expr__ctx_init(&m->pctx); + m->pctx = expr__ctx_new(); + if (!m->pctx) { + free(m); + return -ENOMEM; + } m->metric_name = pe->metric_name; m->metric_expr = pe->metric_expr; m->metric_unit = pe->unit; @@ -847,15 +851,15 @@ static int __add_metric(struct list_head *metric_list, /* Force all found IDs in metric to have us as parent ID. */ WARN_ON_ONCE(!parent); - m->pctx.parent = parent; + m->pctx->parent = parent; /* * For both the parent and referenced metrics, we parse * all the metric's IDs and add it to the parent context. */ - if (expr__find_other(pe->metric_expr, NULL, &m->pctx, runtime) < 0) { + if (expr__find_other(pe->metric_expr, NULL, m->pctx, runtime) < 0) { if (m->metric_refs_cnt == 0) { - expr__ctx_clear(&m->pctx); + expr__ctx_free(m->pctx); free(m); *mp = NULL; } @@ -878,8 +882,8 @@ static int __add_metric(struct list_head *metric_list, list_for_each_prev(pos, metric_list) { struct metric *old = list_entry(pos, struct metric, nd); - if (hashmap__size(&m->pctx.ids) <= - hashmap__size(&old->pctx.ids)) + if (hashmap__size(m->pctx->ids) <= + hashmap__size(old->pctx->ids)) break; } list_add(&m->nd, pos); @@ -927,7 +931,7 @@ static int recursion_check(struct metric *m, const char *id, struct expr_id **pa * if we already processed 'id', if we did, it's recursion * and we fail. */ - ret = expr__get_id(&m->pctx, id, &data); + ret = expr__get_id(m->pctx, id, &data); if (ret) return ret; @@ -982,7 +986,7 @@ static int __resolve_metric(struct metric *m, */ do { all = true; - hashmap__for_each_entry((&m->pctx.ids), cur, bkt) { + hashmap__for_each_entry(m->pctx->ids, cur, bkt) { struct expr_id *parent; struct pmu_event *pe; @@ -996,7 +1000,7 @@ static int __resolve_metric(struct metric *m, all = false; /* The metric key itself needs to go out.. */ - expr__del_id(&m->pctx, cur->key); + expr__del_id(m->pctx, cur->key); /* ... and it gets resolved to the parent context. */ ret = add_metric(metric_list, pe, metric_no_group, &m, parent, ids); @@ -1144,10 +1148,10 @@ static int metricgroup__add_metric(const char *metric, bool metric_no_group, if (m->has_constraint) { metricgroup__add_metric_non_group(events, - &m->pctx); + m->pctx); } else { metricgroup__add_metric_weak_group(events, - &m->pctx); + m->pctx); } } @@ -1210,7 +1214,7 @@ static void metricgroup__free_metrics(struct list_head *metric_list) list_for_each_entry_safe (m, tmp, metric_list, nd) { metric__free_refs(m); - expr__ctx_clear(&m->pctx); + expr__ctx_free(m->pctx); list_del_init(&m->nd); free(m); } diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c index 34a7f5c1fff7..c9fa07e49e72 100644 --- a/tools/perf/util/stat-shadow.c +++ b/tools/perf/util/stat-shadow.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 +#include #include #include "evsel.h" #include "stat.h" #include "color.h" +#include "debug.h" #include "pmu.h" #include "rblist.h" #include "evlist.h" @@ -370,12 +372,16 @@ void perf_stat__collect_metric_expr(struct evlist *evsel_list) { struct evsel *counter, *leader, **metric_events, *oc; bool found; - struct expr_parse_ctx ctx; + struct expr_parse_ctx *ctx; struct hashmap_entry *cur; size_t bkt; int i; - expr__ctx_init(&ctx); + ctx = expr__ctx_new(); + if (!ctx) { + pr_debug("expr__ctx_new failed"); + return; + } evlist__for_each_entry(evsel_list, counter) { bool invalid = false; @@ -383,25 +389,25 @@ void perf_stat__collect_metric_expr(struct evlist *evsel_list) if (!counter->metric_expr) continue; - expr__ctx_clear(&ctx); + expr__ctx_clear(ctx); metric_events = counter->metric_events; if (!metric_events) { if (expr__find_other(counter->metric_expr, counter->name, - &ctx, 1) < 0) + ctx, 1) < 0) continue; metric_events = calloc(sizeof(struct evsel *), - hashmap__size(&ctx.ids) + 1); + hashmap__size(ctx->ids) + 1); if (!metric_events) { - expr__ctx_clear(&ctx); + expr__ctx_free(ctx); return; } counter->metric_events = metric_events; } i = 0; - hashmap__for_each_entry((&ctx.ids), cur, bkt) { + hashmap__for_each_entry(ctx->ids, cur, bkt) { const char *metric_name = (const char *)cur->key; found = false; @@ -453,7 +459,7 @@ void perf_stat__collect_metric_expr(struct evlist *evsel_list) counter->metric_expr = NULL; } } - expr__ctx_clear(&ctx); + expr__ctx_free(ctx); } static double runtime_stat_avg(struct runtime_stat *st, @@ -818,7 +824,6 @@ static int prepare_metric(struct evsel **metric_events, char *n, *pn; int i, j, ret; - expr__ctx_init(pctx); for (i = 0; metric_events[i]; i++) { struct saved_value *v; struct stats *stats; @@ -880,17 +885,22 @@ static void generic_metric(struct perf_stat_config *config, struct runtime_stat *st) { print_metric_t print_metric = out->print_metric; - struct expr_parse_ctx pctx; + struct expr_parse_ctx *pctx; double ratio, scale; int i; void *ctxp = out->ctx; - i = prepare_metric(metric_events, metric_refs, &pctx, cpu, st); - if (i < 0) + pctx = expr__ctx_new(); + if (!pctx) return; + i = prepare_metric(metric_events, metric_refs, pctx, cpu, st); + if (i < 0) { + expr__ctx_free(pctx); + return; + } if (!metric_events[i]) { - if (expr__parse(&ratio, &pctx, metric_expr, runtime) == 0) { + if (expr__parse(&ratio, pctx, metric_expr, runtime) == 0) { char *unit; char metric_bf[64]; @@ -926,22 +936,26 @@ static void generic_metric(struct perf_stat_config *config, (metric_name ? metric_name : name) : "", 0); } - expr__ctx_clear(&pctx); + expr__ctx_free(pctx); } double test_generic_metric(struct metric_expr *mexp, int cpu, struct runtime_stat *st) { - struct expr_parse_ctx pctx; + struct expr_parse_ctx *pctx; double ratio = 0.0; - if (prepare_metric(mexp->metric_events, mexp->metric_refs, &pctx, cpu, st) < 0) + pctx = expr__ctx_new(); + if (!pctx) + return NAN; + + if (prepare_metric(mexp->metric_events, mexp->metric_refs, pctx, cpu, st) < 0) goto out; - if (expr__parse(&ratio, &pctx, mexp->metric_expr, 1)) + if (expr__parse(&ratio, pctx, mexp->metric_expr, 1)) ratio = 0.0; out: - expr__ctx_clear(&pctx); + expr__ctx_free(pctx); return ratio; } -- cgit From edfe7f554ab8f083556c718ecbcefda509c46851 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 23 Sep 2021 00:46:05 -0700 Subject: perf metric: Use NAN for missing event IDs. If during computing a metric an event (id) is missing the parsing aborts. A later patch will make it so that events that aren't used in the output are deliberately omitted, in which case we don't want the abort. Modify the missing ID case to report NAN for these cases. Reviewed-by: Andi Kleen Signed-off-by: Ian Rogers Tested-by: John Garry Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Jin Yao Cc: Kajol Jain Cc: Mark Rutland Cc: Namhyung Kim Cc: Paul Clarke Cc: Peter Zijlstra Cc: Sandeep Dasgupta Cc: Stephane Eranian Link: https://lore.kernel.org/r/20210923074616.674826-3-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/expr.y | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y index b2ada8f8309a..41c9cd4efadd 100644 --- a/tools/perf/util/expr.y +++ b/tools/perf/util/expr.y @@ -1,6 +1,7 @@ /* Simple expression parser */ %{ #define YYDEBUG 1 +#include #include #include "util.h" #include "util/debug.h" @@ -88,12 +89,10 @@ expr: NUMBER | ID { struct expr_id_data *data; - if (expr__resolve_id(ctx, $1, &data)) { - free($1); - YYABORT; - } + $$ = NAN; + if (expr__resolve_id(ctx, $1, &data) == 0) + $$ = expr_id_data__value(data); - $$ = expr_id_data__value(data); free($1); } | expr '|' expr { $$ = (long)$1 | (long)$3; } -- cgit From 7f8fdcbbbefb2d95259aa76a362689affafa4e4b Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 23 Sep 2021 00:46:06 -0700 Subject: perf expr: Remove unused headers and inline d_ratio No functional change. Inlining d_ratio makes it easier to special case for constants in a later patch. Signed-off-by: Ian Rogers Tested-by: John Garry Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Ingo Molnar Cc: Kajol Jain Cc: Jin Yao Cc: Mark Rutland Cc: Namhyung Kim Cc: Paul Clarke Cc: Peter Zijlstra Cc: Sandeep Dasgupta Cc: Stephane Eranian Link: https://lore.kernel.org/r/20210923074616.674826-4-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/expr.y | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y index 41c9cd4efadd..e6005450feae 100644 --- a/tools/perf/util/expr.y +++ b/tools/perf/util/expr.y @@ -2,23 +2,10 @@ %{ #define YYDEBUG 1 #include -#include -#include "util.h" #include "util/debug.h" -#include // strtod() +#include "smt.h" #define IN_EXPR_Y 1 #include "expr.h" -#include "smt.h" -#include - -static double d_ratio(double val0, double val1) -{ - if (val1 == 0) { - return 0; - } - return val0 / val1; -} - %} %define api.pure full @@ -120,7 +107,12 @@ expr: NUMBER | MIN '(' expr ',' expr ')' { $$ = $3 < $5 ? $3 : $5; } | MAX '(' expr ',' expr ')' { $$ = $3 > $5 ? $3 : $5; } | SMT_ON { $$ = smt_on() > 0; } - | D_RATIO '(' expr ',' expr ')' { $$ = d_ratio($3,$5); } + | D_RATIO '(' expr ',' expr ')' { if ($5 == 0) { + $$ = 0; + } else { + $$ = $3 / $5; + } + } ; %% -- cgit From aed0d6f8c6edab48be649a071e18d28efb1a203a Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 23 Sep 2021 00:46:07 -0700 Subject: perf expr: Separate token declataion from type No functional change, so the type of expr remains . A later patch will change the computation to be an aggregate type and making this change makes that later change smaller. Signed-off-by: Ian Rogers Tested-by: John Garry Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Ingo Molnar Cc: Jin Yao Cc: Kajol Jain Cc: Mark Rutland Cc: Namhyung Kim Cc: Paul Clarke Cc: Peter Zijlstra Cc: Sandeep Dasgupta Cc: Stephane Eranian Link: https://lore.kernel.org/r/20210923074616.674826-5-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/expr.y | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y index e6005450feae..68b122e59b3f 100644 --- a/tools/perf/util/expr.y +++ b/tools/perf/util/expr.y @@ -20,11 +20,7 @@ char *str; } -%token EXPR_PARSE EXPR_OTHER EXPR_ERROR -%token NUMBER -%token ID -%destructor { free ($$); } -%token MIN MAX IF ELSE SMT_ON D_RATIO +%token ID NUMBER MIN MAX IF ELSE SMT_ON D_RATIO EXPR_ERROR EXPR_PARSE EXPR_OTHER %left MIN MAX IF %left '|' %left '^' @@ -33,6 +29,9 @@ %left '-' '+' %left '*' '/' '%' %left NEG NOT +%type NUMBER +%type ID +%destructor { free ($$); } %type expr if_expr %{ -- cgit From e87576c5ac14e038ac96145d289bf0134eb08506 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 23 Sep 2021 00:46:08 -0700 Subject: perf expr: Use macros for operators No functional change, switch the operators to use macros so that additional complexity for constants can be added in a later change. Signed-off-by: Ian Rogers Tested-by: John Garry Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Ingo Molnar Cc: Jin Yao Cc: Kajol Jain Cc: Mark Rutland Cc: Namhyung Kim Cc: Paul Clarke Cc: Peter Zijlstra Cc: Sandeep Dasgupta Cc: Stephane Eranian Link: https://lore.kernel.org/r/20210923074616.674826-6-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/expr.y | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y index 68b122e59b3f..5535badeef0a 100644 --- a/tools/perf/util/expr.y +++ b/tools/perf/util/expr.y @@ -43,6 +43,12 @@ static void expr_error(double *final_val __maybe_unused, pr_debug("%s\n", s); } +#define BINARY_LONG_OP(RESULT, OP, LHS, RHS) \ + RESULT = (long)LHS OP (long)RHS; + +#define BINARY_OP(RESULT, OP, LHS, RHS) \ + RESULT = LHS OP RHS; + %} %% @@ -81,14 +87,14 @@ expr: NUMBER free($1); } - | expr '|' expr { $$ = (long)$1 | (long)$3; } - | expr '&' expr { $$ = (long)$1 & (long)$3; } - | expr '^' expr { $$ = (long)$1 ^ (long)$3; } - | expr '<' expr { $$ = $1 < $3; } - | expr '>' expr { $$ = $1 > $3; } - | expr '+' expr { $$ = $1 + $3; } - | expr '-' expr { $$ = $1 - $3; } - | expr '*' expr { $$ = $1 * $3; } + | expr '|' expr { BINARY_LONG_OP($$, |, $1, $3); } + | expr '&' expr { BINARY_LONG_OP($$, &, $1, $3); } + | expr '^' expr { BINARY_LONG_OP($$, ^, $1, $3); } + | expr '<' expr { BINARY_OP($$, <, $1, $3); } + | expr '>' expr { BINARY_OP($$, >, $1, $3); } + | expr '+' expr { BINARY_OP($$, +, $1, $3); } + | expr '-' expr { BINARY_OP($$, -, $1, $3); } + | expr '*' expr { BINARY_OP($$, *, $1, $3); } | expr '/' expr { if ($3 == 0) { pr_debug("division by zero\n"); YYABORT; -- cgit From c924e0cc0576b4e45b9c495174cd785aa41d51ad Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 23 Sep 2021 00:46:09 -0700 Subject: perf expr: Move actions to the left. No functional change, just modifying whitespace. This creates additional space for adding logic to actions in later changes. Signed-off-by: Ian Rogers Tested-by: John Garry Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Ingo Molnar Cc: Jin Yao Cc: Kajol Jain Cc: Mark Rutland Cc: Namhyung Kim Cc: Paul Clarke Cc: Peter Zijlstra Cc: Sandeep Dasgupta Cc: Stephane Eranian Link: https://lore.kernel.org/r/20210923074616.674826-7-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/expr.y | 124 ++++++++++++++++++++++++++++++------------------- 1 file changed, 75 insertions(+), 49 deletions(-) diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y index 5535badeef0a..78cbe377eb0e 100644 --- a/tools/perf/util/expr.y +++ b/tools/perf/util/expr.y @@ -70,54 +70,80 @@ MIN | MAX | IF | ELSE | SMT_ON | NUMBER | '|' | '^' | '&' | '-' | '+' | '*' | '/ '<' | '>' | D_RATIO all_expr: if_expr { *final_val = $1; } - ; - -if_expr: - expr IF expr ELSE expr { $$ = $3 ? $1 : $5; } - | expr - ; - -expr: NUMBER - | ID { - struct expr_id_data *data; - - $$ = NAN; - if (expr__resolve_id(ctx, $1, &data) == 0) - $$ = expr_id_data__value(data); - - free($1); - } - | expr '|' expr { BINARY_LONG_OP($$, |, $1, $3); } - | expr '&' expr { BINARY_LONG_OP($$, &, $1, $3); } - | expr '^' expr { BINARY_LONG_OP($$, ^, $1, $3); } - | expr '<' expr { BINARY_OP($$, <, $1, $3); } - | expr '>' expr { BINARY_OP($$, >, $1, $3); } - | expr '+' expr { BINARY_OP($$, +, $1, $3); } - | expr '-' expr { BINARY_OP($$, -, $1, $3); } - | expr '*' expr { BINARY_OP($$, *, $1, $3); } - | expr '/' expr { if ($3 == 0) { - pr_debug("division by zero\n"); - YYABORT; - } - $$ = $1 / $3; - } - | expr '%' expr { if ((long)$3 == 0) { - pr_debug("division by zero\n"); - YYABORT; - } - $$ = (long)$1 % (long)$3; - } - | '-' expr %prec NEG { $$ = -$2; } - | '(' if_expr ')' { $$ = $2; } - | MIN '(' expr ',' expr ')' { $$ = $3 < $5 ? $3 : $5; } - | MAX '(' expr ',' expr ')' { $$ = $3 > $5 ? $3 : $5; } - | SMT_ON { $$ = smt_on() > 0; } - | D_RATIO '(' expr ',' expr ')' { if ($5 == 0) { - $$ = 0; - } else { - $$ = $3 / $5; - } - } - ; + +if_expr: expr IF expr ELSE expr +{ + $$ = $3 ? $1 : $5; +} +| expr +; + +expr: NUMBER +{ + $$ = $1; +} +| ID +{ + struct expr_id_data *data; + + $$ = NAN; + if (expr__resolve_id(ctx, $1, &data) == 0) + $$ = expr_id_data__value(data); + + free($1); +} +| expr '|' expr { BINARY_LONG_OP($$, |, $1, $3); } +| expr '&' expr { BINARY_LONG_OP($$, &, $1, $3); } +| expr '^' expr { BINARY_LONG_OP($$, ^, $1, $3); } +| expr '<' expr { BINARY_OP($$, <, $1, $3); } +| expr '>' expr { BINARY_OP($$, >, $1, $3); } +| expr '+' expr { BINARY_OP($$, +, $1, $3); } +| expr '-' expr { BINARY_OP($$, -, $1, $3); } +| expr '*' expr { BINARY_OP($$, *, $1, $3); } +| expr '/' expr +{ + if ($3 == 0) { + pr_debug("division by zero\n"); + YYABORT; + } + $$ = $1 / $3; +} +| expr '%' expr +{ + if ((long)$3 == 0) { + pr_debug("division by zero\n"); + YYABORT; + } + $$ = (long)$1 % (long)$3; +} +| D_RATIO '(' expr ',' expr ')' +{ + if ($5 == 0) { + $$ = 0; + } else { + $$ = $3 / $5; + } +} +| '-' expr %prec NEG +{ + $$ = -$2; +} +| '(' if_expr ')' +{ + $$ = $2; +} +| MIN '(' expr ',' expr ')' +{ + $$ = $3 < $5 ? $3 : $5; +} +| MAX '(' expr ',' expr ')' +{ + $$ = $3 > $5 ? $3 : $5; +} +| SMT_ON +{ + $$ = smt_on() > 0 ? 1.0 : 0.0; +} +; %% -- cgit From 7e06a5e30a0c5155291efab8cf866ffea052f829 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 23 Sep 2021 00:46:10 -0700 Subject: perf metric: Rename expr__find_other. A later change will remove the notion of other, rename the function to expr__find_ids as this is what it populates. Signed-off-by: Ian Rogers Tested-by: John Garry Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Ingo Molnar Cc: Jin Yao Cc: Kajol Jain Cc: Mark Rutland Cc: Namhyung Kim Cc: Paul Clarke Cc: Peter Zijlstra Cc: Sandeep Dasgupta Cc: Stephane Eranian Link: https://lore.kernel.org/r/20210923074616.674826-8-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/expr.c | 26 +++++++++++++------------- tools/perf/tests/pmu-events.c | 11 +++++------ tools/perf/util/expr.c | 4 ++-- tools/perf/util/expr.h | 2 +- tools/perf/util/metricgroup.c | 2 +- tools/perf/util/stat-shadow.c | 6 +++--- 6 files changed, 25 insertions(+), 26 deletions(-) diff --git a/tools/perf/tests/expr.c b/tools/perf/tests/expr.c index b0a3b5fd0c00..7ccb97c73347 100644 --- a/tools/perf/tests/expr.c +++ b/tools/perf/tests/expr.c @@ -64,25 +64,25 @@ int test__expr(struct test *t __maybe_unused, int subtest __maybe_unused) TEST_ASSERT_VAL("missing operand", ret == -1); expr__ctx_clear(ctx); - TEST_ASSERT_VAL("find other", - expr__find_other("FOO + BAR + BAZ + BOZO", "FOO", - ctx, 1) == 0); - TEST_ASSERT_VAL("find other", hashmap__size(ctx->ids) == 3); - TEST_ASSERT_VAL("find other", hashmap__find(ctx->ids, "BAR", + TEST_ASSERT_VAL("find ids", + expr__find_ids("FOO + BAR + BAZ + BOZO", "FOO", + ctx, 1) == 0); + TEST_ASSERT_VAL("find ids", hashmap__size(ctx->ids) == 3); + TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids, "BAR", (void **)&val_ptr)); - TEST_ASSERT_VAL("find other", hashmap__find(ctx->ids, "BAZ", + TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids, "BAZ", (void **)&val_ptr)); - TEST_ASSERT_VAL("find other", hashmap__find(ctx->ids, "BOZO", + TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids, "BOZO", (void **)&val_ptr)); expr__ctx_clear(ctx); - TEST_ASSERT_VAL("find other", - expr__find_other("EVENT1\\,param\\=?@ + EVENT2\\,param\\=?@", - NULL, ctx, 3) == 0); - TEST_ASSERT_VAL("find other", hashmap__size(ctx->ids) == 2); - TEST_ASSERT_VAL("find other", hashmap__find(ctx->ids, "EVENT1,param=3/", + TEST_ASSERT_VAL("find ids", + expr__find_ids("EVENT1\\,param\\=?@ + EVENT2\\,param\\=?@", + NULL, ctx, 3) == 0); + TEST_ASSERT_VAL("find ids", hashmap__size(ctx->ids) == 2); + TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids, "EVENT1,param=3/", (void **)&val_ptr)); - TEST_ASSERT_VAL("find other", hashmap__find(ctx->ids, "EVENT2,param=3/", + TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids, "EVENT2,param=3/", (void **)&val_ptr)); expr__ctx_free(ctx); diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c index 91076ab0514b..d3534960ed25 100644 --- a/tools/perf/tests/pmu-events.c +++ b/tools/perf/tests/pmu-events.c @@ -866,7 +866,7 @@ static int resolve_metric_simple(struct expr_parse_ctx *pctx, ref->metric_expr = pe->metric_expr; list_add_tail(&metric->list, compound_list); - rc = expr__find_other(pe->metric_expr, NULL, pctx, 0); + rc = expr__find_ids(pe->metric_expr, NULL, pctx, 0); if (rc) goto out_err; break; /* The hashmap has been modified, so restart */ @@ -916,9 +916,8 @@ static int test_parsing(void) if (!pe->metric_expr) continue; expr__ctx_clear(ctx); - if (expr__find_other(pe->metric_expr, NULL, ctx, 0) - < 0) { - expr_failure("Parse other failed", map, pe); + if (expr__find_ids(pe->metric_expr, NULL, ctx, 0) < 0) { + expr_failure("Parse find ids failed", map, pe); ret++; continue; } @@ -990,8 +989,8 @@ static int metric_parse_fake(const char *str) pr_debug("expr__ctx_new failed"); return TEST_FAIL; } - if (expr__find_other(str, NULL, ctx, 0) < 0) { - pr_err("expr__find_other failed\n"); + if (expr__find_ids(str, NULL, ctx, 0) < 0) { + pr_err("expr__find_ids failed\n"); return -1; } diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c index 7b1c06772a49..adf16bb7571a 100644 --- a/tools/perf/util/expr.c +++ b/tools/perf/util/expr.c @@ -288,8 +288,8 @@ int expr__parse(double *final_val, struct expr_parse_ctx *ctx, return __expr__parse(final_val, ctx, expr, EXPR_PARSE, runtime) ? -1 : 0; } -int expr__find_other(const char *expr, const char *one, - struct expr_parse_ctx *ctx, int runtime) +int expr__find_ids(const char *expr, const char *one, + struct expr_parse_ctx *ctx, int runtime) { int ret = __expr__parse(NULL, ctx, expr, EXPR_OTHER, runtime); diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h index 5fa394f10418..de109c2ab917 100644 --- a/tools/perf/util/expr.h +++ b/tools/perf/util/expr.h @@ -43,7 +43,7 @@ int expr__resolve_id(struct expr_parse_ctx *ctx, const char *id, struct expr_id_data **datap); int expr__parse(double *final_val, struct expr_parse_ctx *ctx, const char *expr, int runtime); -int expr__find_other(const char *expr, const char *one, +int expr__find_ids(const char *expr, const char *one, struct expr_parse_ctx *ids, int runtime); double expr_id_data__value(const struct expr_id_data *data); diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index b7924a2f1f45..046fb3fe1700 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -857,7 +857,7 @@ static int __add_metric(struct list_head *metric_list, * For both the parent and referenced metrics, we parse * all the metric's IDs and add it to the parent context. */ - if (expr__find_other(pe->metric_expr, NULL, m->pctx, runtime) < 0) { + if (expr__find_ids(pe->metric_expr, NULL, m->pctx, runtime) < 0) { if (m->metric_refs_cnt == 0) { expr__ctx_free(m->pctx); free(m); diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c index c9fa07e49e72..9bc841e09a0c 100644 --- a/tools/perf/util/stat-shadow.c +++ b/tools/perf/util/stat-shadow.c @@ -392,9 +392,9 @@ void perf_stat__collect_metric_expr(struct evlist *evsel_list) expr__ctx_clear(ctx); metric_events = counter->metric_events; if (!metric_events) { - if (expr__find_other(counter->metric_expr, - counter->name, - ctx, 1) < 0) + if (expr__find_ids(counter->metric_expr, + counter->name, + ctx, 1) < 0) continue; metric_events = calloc(sizeof(struct evsel *), -- cgit From 114a9d6e396eeb061fa532803ff9a6fd3a966ad8 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 23 Sep 2021 00:46:11 -0700 Subject: perf metric: Add utilities to work on ids map. Add utilities to new/free an ids hashmap, as well as to union. Add testing of the union. Unioning hashmaps will be used when parsing the metric, if a value is known then the hashmap is unnecessary, otherwise we need to union together all the event ids to compute their values for reporting. Signed-off-by: Ian Rogers Tested-by: John Garry Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Ingo Molnar Cc: Jin Yao Cc: Kajol Jain Cc: Mark Rutland Cc: Namhyung Kim Cc: Paul Clarke Cc: Peter Zijlstra Cc: Sandeep Dasgupta Cc: Stephane Eranian Link: https://lore.kernel.org/r/20210923074616.674826-9-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/expr.c | 47 ++++++++++++++++++++++++++++++++ tools/perf/util/expr.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++--- tools/perf/util/expr.h | 12 +++++++++ 3 files changed, 126 insertions(+), 4 deletions(-) diff --git a/tools/perf/tests/expr.c b/tools/perf/tests/expr.c index 7ccb97c73347..1c881bea7fca 100644 --- a/tools/perf/tests/expr.c +++ b/tools/perf/tests/expr.c @@ -6,6 +6,51 @@ #include #include +static int test_ids_union(void) +{ + struct hashmap *ids1, *ids2; + + /* Empty union. */ + ids1 = ids__new(); + TEST_ASSERT_VAL("ids__new", ids1); + ids2 = ids__new(); + TEST_ASSERT_VAL("ids__new", ids2); + + ids1 = ids__union(ids1, ids2); + TEST_ASSERT_EQUAL("union", (int)hashmap__size(ids1), 0); + + /* Union {foo, bar} against {}. */ + ids2 = ids__new(); + TEST_ASSERT_VAL("ids__new", ids2); + + TEST_ASSERT_EQUAL("ids__insert", ids__insert(ids1, strdup("foo"), NULL), 0); + TEST_ASSERT_EQUAL("ids__insert", ids__insert(ids1, strdup("bar"), NULL), 0); + + ids1 = ids__union(ids1, ids2); + TEST_ASSERT_EQUAL("union", (int)hashmap__size(ids1), 2); + + /* Union {foo, bar} against {foo}. */ + ids2 = ids__new(); + TEST_ASSERT_VAL("ids__new", ids2); + TEST_ASSERT_EQUAL("ids__insert", ids__insert(ids2, strdup("foo"), NULL), 0); + + ids1 = ids__union(ids1, ids2); + TEST_ASSERT_EQUAL("union", (int)hashmap__size(ids1), 2); + + /* Union {foo, bar} against {bar,baz}. */ + ids2 = ids__new(); + TEST_ASSERT_VAL("ids__new", ids2); + TEST_ASSERT_EQUAL("ids__insert", ids__insert(ids2, strdup("bar"), NULL), 0); + TEST_ASSERT_EQUAL("ids__insert", ids__insert(ids2, strdup("baz"), NULL), 0); + + ids1 = ids__union(ids1, ids2); + TEST_ASSERT_EQUAL("union", (int)hashmap__size(ids1), 3); + + ids__free(ids1); + + return 0; +} + static int test(struct expr_parse_ctx *ctx, const char *e, double val2) { double val; @@ -24,6 +69,8 @@ int test__expr(struct test *t __maybe_unused, int subtest __maybe_unused) int ret; struct expr_parse_ctx *ctx; + TEST_ASSERT_EQUAL("ids_union", test_ids_union(), 0); + ctx = expr__ctx_new(); TEST_ASSERT_VAL("expr__ctx_new", ctx); expr__add_id_val(ctx, strdup("FOO"), 1); diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c index adf16bb7571a..81101be51044 100644 --- a/tools/perf/util/expr.c +++ b/tools/perf/util/expr.c @@ -59,8 +59,29 @@ static bool key_equal(const void *key1, const void *key2, return !strcmp((const char *)key1, (const char *)key2); } -/* Caller must make sure id is allocated */ -int expr__add_id(struct expr_parse_ctx *ctx, const char *id) +struct hashmap *ids__new(void) +{ + return hashmap__new(key_hash, key_equal, NULL); +} + +void ids__free(struct hashmap *ids) +{ + struct hashmap_entry *cur; + size_t bkt; + + if (ids == NULL) + return; + + hashmap__for_each_entry(ids, cur, bkt) { + free((char *)cur->key); + free(cur->value); + } + + hashmap__free(ids); +} + +int ids__insert(struct hashmap *ids, const char *id, + struct expr_id *parent) { struct expr_id_data *data_ptr = NULL, *old_data = NULL; char *old_key = NULL; @@ -70,10 +91,10 @@ int expr__add_id(struct expr_parse_ctx *ctx, const char *id) if (!data_ptr) return -ENOMEM; - data_ptr->parent = ctx->parent; + data_ptr->parent = parent; data_ptr->kind = EXPR_ID_DATA__PARENT; - ret = hashmap__set(ctx->ids, id, data_ptr, + ret = hashmap__set(ids, id, data_ptr, (const void **)&old_key, (void **)&old_data); if (ret) free(data_ptr); @@ -82,6 +103,48 @@ int expr__add_id(struct expr_parse_ctx *ctx, const char *id) return ret; } +struct hashmap *ids__union(struct hashmap *ids1, struct hashmap *ids2) +{ + size_t bkt; + struct hashmap_entry *cur; + int ret; + struct expr_id_data *old_data = NULL; + char *old_key = NULL; + + if (!ids1) + return ids2; + + if (!ids2) + return ids1; + + if (hashmap__size(ids1) < hashmap__size(ids2)) { + struct hashmap *tmp = ids1; + + ids1 = ids2; + ids2 = tmp; + } + hashmap__for_each_entry(ids2, cur, bkt) { + ret = hashmap__set(ids1, cur->key, cur->value, + (const void **)&old_key, (void **)&old_data); + free(old_key); + free(old_data); + + if (ret) { + hashmap__free(ids1); + hashmap__free(ids2); + return NULL; + } + } + hashmap__free(ids2); + return ids1; +} + +/* Caller must make sure id is allocated */ +int expr__add_id(struct expr_parse_ctx *ctx, const char *id) +{ + return ids__insert(ctx->ids, id, ctx->parent); +} + /* Caller must make sure id is allocated */ int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val) { diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h index de109c2ab917..4ed186bd1f13 100644 --- a/tools/perf/util/expr.h +++ b/tools/perf/util/expr.h @@ -30,9 +30,19 @@ struct expr_scanner_ctx { int runtime; }; +struct hashmap *ids__new(void); +void ids__free(struct hashmap *ids); +int ids__insert(struct hashmap *ids, const char *id, struct expr_id *parent); +/* + * Union two sets of ids (hashmaps) and construct a third, freeing ids1 and + * ids2. + */ +struct hashmap *ids__union(struct hashmap *ids1, struct hashmap *ids2); + struct expr_parse_ctx *expr__ctx_new(void); void expr__ctx_clear(struct expr_parse_ctx *ctx); void expr__ctx_free(struct expr_parse_ctx *ctx); + void expr__del_id(struct expr_parse_ctx *ctx, const char *id); int expr__add_id(struct expr_parse_ctx *ctx, const char *id); int expr__add_id_val(struct expr_parse_ctx *ctx, const char *id, double val); @@ -41,8 +51,10 @@ int expr__get_id(struct expr_parse_ctx *ctx, const char *id, struct expr_id_data **data); int expr__resolve_id(struct expr_parse_ctx *ctx, const char *id, struct expr_id_data **datap); + int expr__parse(double *final_val, struct expr_parse_ctx *ctx, const char *expr, int runtime); + int expr__find_ids(const char *expr, const char *one, struct expr_parse_ctx *ids, int runtime); -- cgit From 762a05c561bcc36ccde6a25e268888383e6adb83 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 23 Sep 2021 00:46:12 -0700 Subject: perf metric: Allow metrics with no events A metric may be a constant value, for example, some SMT metrics are constant 0 if #smt_on is 0. If we eliminate all the events then there is no printing. Fix this by forcing metrics like this to have a duration_time tool event, previously the metric would fail when parsing the events with a parse error. Signed-off-by: Ian Rogers Tested-by: John Garry Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Ingo Molnar Cc: Jin Yao Cc: Kajol Jain Cc: Mark Rutland Cc: Namhyung Kim Cc: Paul Clarke Cc: Peter Zijlstra Cc: Sandeep Dasgupta Cc: Stephane Eranian Link: https://lore.kernel.org/r/20210923074616.674826-10-irogers@google.com [ Reflow one __parse_events() call so that a ternary operation gets in a single line ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/metricgroup.c | 106 ++++++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 50 deletions(-) diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index 046fb3fe1700..8ba5370f5f64 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -198,65 +198,69 @@ static struct evsel *find_evsel_group(struct evlist *perf_evlist, struct evsel *ev, *current_leader = NULL; struct expr_id_data *val_ptr; int i = 0, matched_events = 0, events_to_match; - const int idnum = (int)hashmap__size(pctx->ids); + int idnum = (int)hashmap__size(pctx->ids); - /* - * duration_time is always grouped separately, when events are grouped - * (ie has_constraint is false) then ignore it in the matching loop and - * add it to metric_events at the end. - */ - if (!has_constraint && - hashmap__find(pctx->ids, "duration_time", (void **)&val_ptr)) - events_to_match = idnum - 1; - else - events_to_match = idnum; - - evlist__for_each_entry (perf_evlist, ev) { + if (idnum != 0) { /* - * Events with a constraint aren't grouped and match the first - * events available. + * duration_time is always grouped separately, when events are + * grouped (ie has_constraint is false) then ignore it in the + * matching loop and add it to metric_events at the end. */ - if (has_constraint && ev->weak_group) - continue; - /* Ignore event if already used and merging is disabled. */ - if (metric_no_merge && test_bit(ev->core.idx, evlist_used)) - continue; - if (!has_constraint && !evsel__has_leader(ev, current_leader)) { + events_to_match = idnum; + if (!has_constraint && hashmap__find(pctx->ids, "duration_time", (void **)&val_ptr)) + events_to_match--; + + evlist__for_each_entry(perf_evlist, ev) { + /* + * Events with a constraint aren't grouped and match the + * first events available. + */ + if (has_constraint && ev->weak_group) + continue; + /* Ignore event if already used and merging is disabled. */ + if (metric_no_merge && test_bit(ev->core.idx, evlist_used)) + continue; + if (!has_constraint && !evsel__has_leader(ev, current_leader)) { + /* + * Start of a new group, discard the whole match + * and start again. + */ + matched_events = 0; + memset(metric_events, 0, sizeof(struct evsel *) * idnum); + current_leader = evsel__leader(ev); + } /* - * Start of a new group, discard the whole match and - * start again. + * Check for duplicate events with the same name. For + * example, uncore_imc/cas_count_read/ will turn into 6 + * events per socket on skylakex. Only the first such + * event is placed in metric_events. If events aren't + * grouped then this also ensures that the same event in + * different sibling groups aren't both added to + * metric_events. */ - matched_events = 0; - memset(metric_events, 0, - sizeof(struct evsel *) * idnum); - current_leader = evsel__leader(ev); + if (contains_event(metric_events, matched_events, ev->name)) + continue; + /* Does this event belong to the parse context? */ + if (hashmap__find(pctx->ids, ev->name, (void **)&val_ptr)) + metric_events[matched_events++] = ev; + + if (matched_events == events_to_match) + break; } + } else { /* - * Check for duplicate events with the same name. For example, - * uncore_imc/cas_count_read/ will turn into 6 events per socket - * on skylakex. Only the first such event is placed in - * metric_events. If events aren't grouped then this also - * ensures that the same event in different sibling groups - * aren't both added to metric_events. + * There are no events to match, but we need to associate the + * metric with an event for printing. A duration_time event was + * parsed for this. */ - if (contains_event(metric_events, matched_events, ev->name)) - continue; - /* Does this event belong to the parse context? */ - if (hashmap__find(pctx->ids, ev->name, (void **)&val_ptr)) - metric_events[matched_events++] = ev; - - if (matched_events == events_to_match) - break; + idnum = 1; + events_to_match = 0; } - if (events_to_match != idnum) { /* Add the first duration_time. */ - evlist__for_each_entry(perf_evlist, ev) { - if (!strcmp(ev->name, "duration_time")) { - metric_events[matched_events++] = ev; - break; - } - } + ev = evlist__find_evsel_by_str(perf_evlist, "duration_time"); + if (ev) + metric_events[matched_events++] = ev; } if (matched_events != idnum) { @@ -320,9 +324,10 @@ static int metricgroup__setup_events(struct list_head *groups, list_for_each_entry (m, groups, nd) { struct evsel **metric_events; struct metric_ref *metric_refs = NULL; + const size_t ids_size = hashmap__size(m->pctx->ids); metric_events = calloc(sizeof(void *), - hashmap__size(m->pctx->ids) + 1); + ids_size == 0 ? 2 : ids_size + 1); if (!metric_events) { ret = -ENOMEM; break; @@ -1240,7 +1245,8 @@ static int parse_groups(struct evlist *perf_evlist, const char *str, goto out; pr_debug("adding %s\n", extra_events.buf); bzero(&parse_error, sizeof(parse_error)); - ret = __parse_events(perf_evlist, extra_events.buf, &parse_error, fake_pmu); + ret = __parse_events(perf_evlist, extra_events.len > 0 ? extra_events.buf : "duration_time", + &parse_error, fake_pmu); if (ret) { parse_events_print_error(&parse_error, extra_events.buf); goto out; -- cgit From 3f965a7df09d7eebde0020cefe427219afe7df4a Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 23 Sep 2021 00:46:13 -0700 Subject: perf expr: Merge find_ids and regular parsing Add a new option to parsing that the set of IDs being used should be computed, this means every action needs to handle the compute_ids and regular case. This means actions yield a new ids type is a set of ids or the value being computed. Use the compute_ids case to replace find IDs parsing. Signed-off-by: Ian Rogers Tested-by: John Garry Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Ingo Molnar Cc: Jin Yao Cc: Kajol Jain Cc: Mark Rutland Cc: Namhyung Kim Cc: Paul Clarke Cc: Peter Zijlstra Cc: Sandeep Dasgupta Cc: Stephane Eranian Link: https://lore.kernel.org/r/20210923074616.674826-11-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/expr.c | 9 ++- tools/perf/util/expr.h | 1 - tools/perf/util/expr.l | 9 --- tools/perf/util/expr.y | 176 ++++++++++++++++++++++++++++++++++++------------- 4 files changed, 136 insertions(+), 59 deletions(-) diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c index 81101be51044..db2445677c8c 100644 --- a/tools/perf/util/expr.c +++ b/tools/perf/util/expr.c @@ -314,10 +314,9 @@ void expr__ctx_free(struct expr_parse_ctx *ctx) static int __expr__parse(double *val, struct expr_parse_ctx *ctx, const char *expr, - int start, int runtime) + bool compute_ids, int runtime) { struct expr_scanner_ctx scanner_ctx = { - .start_token = start, .runtime = runtime, }; YY_BUFFER_STATE buffer; @@ -337,7 +336,7 @@ __expr__parse(double *val, struct expr_parse_ctx *ctx, const char *expr, expr_set_debug(1, scanner); #endif - ret = expr_parse(val, ctx, scanner); + ret = expr_parse(val, ctx, compute_ids, scanner); expr__flush_buffer(buffer, scanner); expr__delete_buffer(buffer, scanner); @@ -348,13 +347,13 @@ __expr__parse(double *val, struct expr_parse_ctx *ctx, const char *expr, int expr__parse(double *final_val, struct expr_parse_ctx *ctx, const char *expr, int runtime) { - return __expr__parse(final_val, ctx, expr, EXPR_PARSE, runtime) ? -1 : 0; + return __expr__parse(final_val, ctx, expr, /*compute_ids=*/false, runtime) ? -1 : 0; } int expr__find_ids(const char *expr, const char *one, struct expr_parse_ctx *ctx, int runtime) { - int ret = __expr__parse(NULL, ctx, expr, EXPR_OTHER, runtime); + int ret = __expr__parse(NULL, ctx, expr, /*compute_ids=*/true, runtime); if (one) expr__del_id(ctx, one); diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h index 4ed186bd1f13..b20513f0ae59 100644 --- a/tools/perf/util/expr.h +++ b/tools/perf/util/expr.h @@ -26,7 +26,6 @@ struct expr_parse_ctx { struct expr_id_data; struct expr_scanner_ctx { - int start_token; int runtime; }; diff --git a/tools/perf/util/expr.l b/tools/perf/util/expr.l index 13e5e3c75f56..702fdf6456ca 100644 --- a/tools/perf/util/expr.l +++ b/tools/perf/util/expr.l @@ -91,15 +91,6 @@ symbol ({spec}|{sym})+ %% struct expr_scanner_ctx *sctx = expr_get_extra(yyscanner); - { - int start_token = sctx->start_token; - - if (sctx->start_token) { - sctx->start_token = 0; - return start_token; - } - } - d_ratio { return D_RATIO; } max { return MAX; } min { return MIN; } diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y index 78cbe377eb0e..6aeead54760a 100644 --- a/tools/perf/util/expr.y +++ b/tools/perf/util/expr.y @@ -1,6 +1,7 @@ /* Simple expression parser */ %{ #define YYDEBUG 1 +#include #include #include "util/debug.h" #include "smt.h" @@ -12,15 +13,31 @@ %parse-param { double *final_val } %parse-param { struct expr_parse_ctx *ctx } +%parse-param { bool compute_ids } %parse-param {void *scanner} %lex-param {void* scanner} %union { double num; char *str; + struct ids { + /* + * When creating ids, holds the working set of event ids. NULL + * implies the set is empty. + */ + struct hashmap *ids; + /* + * The metric value. When not creating ids this is the value + * read from a counter, a constant or some computed value. When + * creating ids the value is either a constant or BOTTOM. NAN is + * used as the special BOTTOM value, representing a "set of all + * values" case. + */ + double val; + } ids; } -%token ID NUMBER MIN MAX IF ELSE SMT_ON D_RATIO EXPR_ERROR EXPR_PARSE EXPR_OTHER +%token ID NUMBER MIN MAX IF ELSE SMT_ON D_RATIO EXPR_ERROR %left MIN MAX IF %left '|' %left '^' @@ -32,65 +49,109 @@ %type NUMBER %type ID %destructor { free ($$); } -%type expr if_expr +%type expr if_expr +%destructor { ids__free($$.ids); } %{ static void expr_error(double *final_val __maybe_unused, struct expr_parse_ctx *ctx __maybe_unused, + bool compute_ids __maybe_unused, void *scanner, const char *s) { pr_debug("%s\n", s); } +/* + * During compute ids, the special "bottom" value uses NAN to represent the set + * of all values. NAN is selected as it isn't a useful constant value. + */ +#define BOTTOM NAN + +static struct ids union_expr(struct ids ids1, struct ids ids2) +{ + struct ids result = { + .val = BOTTOM, + .ids = ids__union(ids1.ids, ids2.ids), + }; + return result; +} + #define BINARY_LONG_OP(RESULT, OP, LHS, RHS) \ - RESULT = (long)LHS OP (long)RHS; + if (!compute_ids) { \ + RESULT.val = (long)LHS.val OP (long)RHS.val; \ + RESULT.ids = NULL; \ + } else { \ + RESULT = union_expr(LHS, RHS); \ + } #define BINARY_OP(RESULT, OP, LHS, RHS) \ - RESULT = LHS OP RHS; + if (!compute_ids) { \ + RESULT.val = LHS.val OP RHS.val; \ + RESULT.ids = NULL; \ + } else { \ + RESULT = union_expr(LHS, RHS); \ + } %} %% -start: -EXPR_PARSE all_expr -| -EXPR_OTHER all_other - -all_other: all_other other -| - -other: ID +start: if_expr { - expr__add_id(ctx, $1); -} -| -MIN | MAX | IF | ELSE | SMT_ON | NUMBER | '|' | '^' | '&' | '-' | '+' | '*' | '/' | '%' | '(' | ')' | ',' -| -'<' | '>' | D_RATIO + if (compute_ids) + ctx->ids = ids__union($1.ids, ctx->ids); -all_expr: if_expr { *final_val = $1; } + if (final_val) + *final_val = $1.val; +} +; if_expr: expr IF expr ELSE expr { - $$ = $3 ? $1 : $5; + if (!compute_ids) { + $$.ids = NULL; + if (fpclassify($3.val) == FP_ZERO) { + $$.val = $5.val; + } else { + $$.val = $1.val; + } + } else { + $$ = union_expr($1, union_expr($3, $5)); + } } | expr ; expr: NUMBER { - $$ = $1; + $$.val = $1; + $$.ids = NULL; } | ID { - struct expr_id_data *data; - - $$ = NAN; - if (expr__resolve_id(ctx, $1, &data) == 0) - $$ = expr_id_data__value(data); - - free($1); + if (!compute_ids) { + /* + * Compute the event's value from ID. If the ID isn't known then + * it isn't used to compute the formula so set to NAN. + */ + struct expr_id_data *data; + + $$.val = NAN; + if (expr__resolve_id(ctx, $1, &data) == 0) + $$.val = expr_id_data__value(data); + + $$.ids = NULL; + free($1); + } else { + /* + * Set the value to BOTTOM to show that any value is possible + * when the event is computed. Create a set of just the ID. + */ + $$.val = BOTTOM; + $$.ids = ids__new(); + if (!$$.ids || ids__insert($$.ids, $1, ctx->parent)) + YYABORT; + } } | expr '|' expr { BINARY_LONG_OP($$, |, $1, $3); } | expr '&' expr { BINARY_LONG_OP($$, &, $1, $3); } @@ -102,31 +163,47 @@ expr: NUMBER | expr '*' expr { BINARY_OP($$, *, $1, $3); } | expr '/' expr { - if ($3 == 0) { - pr_debug("division by zero\n"); - YYABORT; + if (!compute_ids) { + if (fpclassify($3.val) == FP_ZERO) { + pr_debug("division by zero\n"); + YYABORT; + } + $$.val = $1.val / $3.val; + $$.ids = NULL; + } else { + $$ = union_expr($1, $3); } - $$ = $1 / $3; } | expr '%' expr { - if ((long)$3 == 0) { - pr_debug("division by zero\n"); - YYABORT; + if (!compute_ids) { + if (fpclassify($3.val) == FP_ZERO) { + pr_debug("division by zero\n"); + YYABORT; + } + $$.val = (long)$1.val % (long)$3.val; + $$.ids = NULL; + } else { + $$ = union_expr($1, $3); } - $$ = (long)$1 % (long)$3; } | D_RATIO '(' expr ',' expr ')' { - if ($5 == 0) { - $$ = 0; + if (!compute_ids) { + $$.ids = NULL; + if (fpclassify($5.val) == FP_ZERO) { + $$.val = 0.0; + } else { + $$.val = $3.val / $5.val; + } } else { - $$ = $3 / $5; + $$ = union_expr($3, $5); } } | '-' expr %prec NEG { - $$ = -$2; + $$.val = -$2.val; + $$.ids = $2.ids; } | '(' if_expr ')' { @@ -134,15 +211,26 @@ expr: NUMBER } | MIN '(' expr ',' expr ')' { - $$ = $3 < $5 ? $3 : $5; + if (!compute_ids) { + $$.val = $3.val < $5.val ? $3.val : $5.val; + $$.ids = NULL; + } else { + $$ = union_expr($3, $5); + } } | MAX '(' expr ',' expr ')' { - $$ = $3 > $5 ? $3 : $5; + if (!compute_ids) { + $$.val = $3.val > $5.val ? $3.val : $5.val; + $$.ids = NULL; + } else { + $$ = union_expr($3, $5); + } } | SMT_ON { - $$ = smt_on() > 0 ? 1.0 : 0.0; + $$.val = smt_on() > 0 ? 1.0 : 0.0; + $$.ids = NULL; } ; -- cgit From 970f7afe55ee3e9d6d1c73cd138c5f023bb0beba Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 23 Sep 2021 00:46:14 -0700 Subject: perf expr: Propagate constants for binary operations When we're computing ID values, if we have constant values then compute the constant result. For example: 1 + 2 Previously .val would be set to BOTTOM by union_expr, meaning that all values are possible. With this change .val is set to 3. Later changes will use the constant values to hopefully eliminate ID values that don't need to be computed. Signed-off-by: Ian Rogers Tested-by: John Garry Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Ingo Molnar Cc: Jin Yao Cc: Kajol Jain Cc: Mark Rutland Cc: Namhyung Kim Cc: Paul Clarke Cc: Peter Zijlstra Cc: Sandeep Dasgupta Cc: Stephane Eranian Link: https://lore.kernel.org/r/20210923074616.674826-12-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/expr.y | 63 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 18 deletions(-) diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y index 6aeead54760a..5a295e385914 100644 --- a/tools/perf/util/expr.y +++ b/tools/perf/util/expr.y @@ -68,6 +68,12 @@ static void expr_error(double *final_val __maybe_unused, */ #define BOTTOM NAN +/* During computing ids, does val represent a constant (non-BOTTOM) value? */ +static bool is_const(double val) +{ + return isfinite(val); +} + static struct ids union_expr(struct ids ids1, struct ids ids2) { struct ids result = { @@ -77,8 +83,15 @@ static struct ids union_expr(struct ids ids1, struct ids ids2) return result; } +/* + * If we're not computing ids or $1 and $3 are constants, compute the new + * constant value using OP. Its invariant that there are no ids. If computing + * ids for non-constants union the set of IDs that must be computed. + */ #define BINARY_LONG_OP(RESULT, OP, LHS, RHS) \ - if (!compute_ids) { \ + if (!compute_ids || (is_const(LHS.val) && is_const(RHS.val))) { \ + assert(LHS.ids == NULL); \ + assert(RHS.ids == NULL); \ RESULT.val = (long)LHS.val OP (long)RHS.val; \ RESULT.ids = NULL; \ } else { \ @@ -86,7 +99,9 @@ static struct ids union_expr(struct ids ids1, struct ids ids2) } #define BINARY_OP(RESULT, OP, LHS, RHS) \ - if (!compute_ids) { \ + if (!compute_ids || (is_const(LHS.val) && is_const(RHS.val))) { \ + assert(LHS.ids == NULL); \ + assert(RHS.ids == NULL); \ RESULT.val = LHS.val OP RHS.val; \ RESULT.ids = NULL; \ } else { \ @@ -163,40 +178,52 @@ expr: NUMBER | expr '*' expr { BINARY_OP($$, *, $1, $3); } | expr '/' expr { - if (!compute_ids) { - if (fpclassify($3.val) == FP_ZERO) { - pr_debug("division by zero\n"); - YYABORT; - } + if (fpclassify($3.val) == FP_ZERO) { + pr_debug("division by zero\n"); + YYABORT; + } else if (!compute_ids || (is_const($1.val) && is_const($3.val))) { + assert($1.ids == NULL); + assert($3.ids == NULL); $$.val = $1.val / $3.val; $$.ids = NULL; } else { + /* LHS and/or RHS need computing from event IDs so union. */ $$ = union_expr($1, $3); } } | expr '%' expr { - if (!compute_ids) { - if (fpclassify($3.val) == FP_ZERO) { - pr_debug("division by zero\n"); - YYABORT; - } + if (fpclassify($3.val) == FP_ZERO) { + pr_debug("division by zero\n"); + YYABORT; + } else if (!compute_ids || (is_const($1.val) && is_const($3.val))) { + assert($1.ids == NULL); + assert($3.ids == NULL); $$.val = (long)$1.val % (long)$3.val; $$.ids = NULL; } else { + /* LHS and/or RHS need computing from event IDs so union. */ $$ = union_expr($1, $3); } } | D_RATIO '(' expr ',' expr ')' { - if (!compute_ids) { + if (fpclassify($5.val) == FP_ZERO) { + /* + * Division by constant zero always yields zero and no events + * are necessary. + */ + assert($5.ids == NULL); + $$.val = 0.0; + $$.ids = NULL; + ids__free($3.ids); + } else if (!compute_ids || (is_const($3.val) && is_const($5.val))) { + assert($3.ids == NULL); + assert($5.ids == NULL); + $$.val = $3.val / $5.val; $$.ids = NULL; - if (fpclassify($5.val) == FP_ZERO) { - $$.val = 0.0; - } else { - $$.val = $3.val / $5.val; - } } else { + /* LHS and/or RHS need computing from event IDs so union. */ $$ = union_expr($3, $5); } } -- cgit From a8e4e880834b5dc53ff6b4cfc9f4268e61399976 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 23 Sep 2021 00:46:15 -0700 Subject: perf metric: Don't compute unused events For a metric like: EVENT1 if #smt_on else EVENT2 currently EVENT1 and EVENT2 will be measured and then when the metric is reported EVENT1 or EVENT2 will be printed depending on the value from smt_on() during the expr parsing. Computing both events is unnecessary and can lead to multiplexing as discussed in this thread: https://lore.kernel.org/lkml/20201110100346.2527031-1-irogers@google.com/ If the input is constant to certain operators like: IDS1 if CONST else IDS2 then the result will be either IDS1 or IDS2 depending on CONST (which may be evaluated from an entire expression), and so IDS1 or IDS2 may be discarded avoiding events from being programmed. Signed-off-by: Ian Rogers Tested-by: John Garry Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Ingo Molnar Cc: Jin Yao Cc: Kajol Jain Cc: Mark Rutland Cc: Namhyung Kim Cc: Paul Clarke Cc: Peter Zijlstra Cc: Sandeep Dasgupta Cc: Stephane Eranian Link: https://lore.kernel.org/r/20210923074616.674826-13-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/expr.c | 11 +++++++++++ tools/perf/util/expr.y | 30 +++++++++++++++++++++++------- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/tools/perf/tests/expr.c b/tools/perf/tests/expr.c index 1c881bea7fca..287989321d2a 100644 --- a/tools/perf/tests/expr.c +++ b/tools/perf/tests/expr.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "util/debug.h" #include "util/expr.h" +#include "util/smt.h" #include "tests.h" #include #include @@ -132,6 +133,16 @@ int test__expr(struct test *t __maybe_unused, int subtest __maybe_unused) TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids, "EVENT2,param=3/", (void **)&val_ptr)); + /* Only EVENT1 or EVENT2 need be measured depending on the value of smt_on. */ + expr__ctx_clear(ctx); + TEST_ASSERT_VAL("find ids", + expr__find_ids("EVENT1 if #smt_on else EVENT2", + NULL, ctx, 0) == 0); + TEST_ASSERT_VAL("find ids", hashmap__size(ctx->ids) == 1); + TEST_ASSERT_VAL("find ids", hashmap__find(ctx->ids, + smt_on() ? "EVENT1" : "EVENT2", + (void **)&val_ptr)); + expr__ctx_free(ctx); return 0; diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y index 5a295e385914..5b878f044f22 100644 --- a/tools/perf/util/expr.y +++ b/tools/perf/util/expr.y @@ -123,14 +123,30 @@ start: if_expr if_expr: expr IF expr ELSE expr { - if (!compute_ids) { - $$.ids = NULL; - if (fpclassify($3.val) == FP_ZERO) { - $$.val = $5.val; - } else { - $$.val = $1.val; - } + if (fpclassify($3.val) == FP_ZERO) { + /* + * The IF expression evaluated to 0 so treat as false, take the + * ELSE and discard everything else. + */ + $$.val = $5.val; + $$.ids = $5.ids; + ids__free($1.ids); + ids__free($3.ids); + } else if (!compute_ids || is_const($3.val)) { + /* + * If ids aren't computed then treat the expression as true. If + * ids are being computed and the IF expr is a non-zero + * constant, then also evaluate the true case. + */ + $$.val = $1.val; + $$.ids = $1.ids; + ids__free($3.ids); + ids__free($5.ids); } else { + /* + * Value is either the LHS or RHS and we need the IF expression + * to compute it. + */ $$ = union_expr($1, union_expr($3, $5)); } } -- cgit From 94886961e324d5b6bae8e206b227c6eeb0f22c2c Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 23 Sep 2021 00:46:16 -0700 Subject: perf metric: Avoid events for an 'if' constant result For a metric like: CONST if expr else CONST if the values of CONST are identical then expr doesn't need evaluating, and events, in order to compute a result. Signed-off-by: Ian Rogers Tested-by: John Garry Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Ingo Molnar Cc: Jin Yao Cc: Kajol Jain Cc: Mark Rutland Cc: Namhyung Kim Cc: Paul Clarke Cc: Peter Zijlstra Cc: Sandeep Dasgupta Cc: Stephane Eranian Link: https://lore.kernel.org/r/20210923074616.674826-14-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/expr.c | 7 +++++++ tools/perf/util/expr.y | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/tools/perf/tests/expr.c b/tools/perf/tests/expr.c index 287989321d2a..f1d8411fce12 100644 --- a/tools/perf/tests/expr.c +++ b/tools/perf/tests/expr.c @@ -143,6 +143,13 @@ int test__expr(struct test *t __maybe_unused, int subtest __maybe_unused) smt_on() ? "EVENT1" : "EVENT2", (void **)&val_ptr)); + /* The expression is a constant 1.0 without needing to evaluate EVENT1. */ + expr__ctx_clear(ctx); + TEST_ASSERT_VAL("find ids", + expr__find_ids("1.0 if EVENT1 > 100.0 else 1.0", + NULL, ctx, 0) == 0); + TEST_ASSERT_VAL("find ids", hashmap__size(ctx->ids) == 0); + expr__ctx_free(ctx); return 0; diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y index 5b878f044f22..ba7d3b667fcb 100644 --- a/tools/perf/util/expr.y +++ b/tools/perf/util/expr.y @@ -142,6 +142,16 @@ if_expr: expr IF expr ELSE expr $$.ids = $1.ids; ids__free($3.ids); ids__free($5.ids); + } else if ($1.val == $5.val) { + /* + * LHS == RHS, so both are an identical constant. No need to + * evaluate any events. + */ + $$.val = $1.val; + $$.ids = NULL; + ids__free($1.ids); + ids__free($3.ids); + ids__free($5.ids); } else { /* * Value is either the LHS or RHS and we need the IF expression -- cgit From 65017d8381e2425a1b4cdc4681fadc179635c000 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 27 Sep 2021 21:54:36 +0900 Subject: kconfig: narrow the scope of variables in the lexer The variables, "ts" and "i", are used locally in the action of the [ \t]+ pattern in the start state. Define them where they are used. Signed-off-by: Masahiro Yamada --- scripts/kconfig/lexer.l | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/kconfig/lexer.l b/scripts/kconfig/lexer.l index 312cbad2d34d..efe487859308 100644 --- a/scripts/kconfig/lexer.l +++ b/scripts/kconfig/lexer.l @@ -85,7 +85,6 @@ n [A-Za-z0-9_-] %% int str = 0; - int ts, i; #.* /* ignore comment */ [ \t]* /* whitespaces */ @@ -196,6 +195,8 @@ n [A-Za-z0-9_-] { [ \t]+ { + int ts, i; + ts = 0; for (i = 0; i < yyleng; i++) { if (yytext[i] == '\t') -- cgit From 6988f70cf105e70b4ea424d320521a9ed452fe46 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 27 Sep 2021 21:54:37 +0900 Subject: kconfig: rename a variable in the lexer to a clearer name In Kconfig, like Python, you can enclose a string by double-quotes or single-quotes. So, both "foo" and 'foo' are allowed. The variable, "str", is used to remember whether the string started with a double-quote or a single-quote because open/closing quotation marks must match. The name "str" is too generic to understand the intent. Rename it to "open_quote", which is easier to understand. The type should be 'char'. Signed-off-by: Masahiro Yamada Reviewed-by: Boris Kolpackov --- scripts/kconfig/lexer.l | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/kconfig/lexer.l b/scripts/kconfig/lexer.l index efe487859308..cc386e443683 100644 --- a/scripts/kconfig/lexer.l +++ b/scripts/kconfig/lexer.l @@ -84,7 +84,7 @@ static void warn_ignored_character(char chr) n [A-Za-z0-9_-] %% - int str = 0; + char open_quote = 0; #.* /* ignore comment */ [ \t]* /* whitespaces */ @@ -133,7 +133,7 @@ n [A-Za-z0-9_-] ":=" return T_COLON_EQUAL; "+=" return T_PLUS_EQUAL; \"|\' { - str = yytext[0]; + open_quote = yytext[0]; new_string(); BEGIN(STRING); } @@ -170,7 +170,7 @@ n [A-Za-z0-9_-] append_string(yytext + 1, yyleng - 1); } \'|\" { - if (str == yytext[0]) { + if (open_quote == yytext[0]) { BEGIN(INITIAL); yylval.string = text; return T_WORD_QUOTE; -- cgit From 2b775152bbe838c9de0055eb5bdb530c2c88235b Mon Sep 17 00:00:00 2001 From: Michael Petlan Date: Wed, 22 Sep 2021 17:27:06 +0200 Subject: perf tests vmlinux-kallsyms: Ignore hidden symbols Certain kernel symbols are purposely hidden from kallsyms. The function is_ignored_symbol() from scripts/kallsyms.c decides if a symbol should be hidden or not. The perf test "vmlinux symtab matches kallsyms" fails in case perf finds some of the hidden symbols in its machine image and can't match them to kallsyms. Let's add a filter to check if a symbol not found isn't one of these before failing the test. The function is_ignored_symbol() has been copied from scripts/kallsyms.c and needs to be updated along with the original. Signed-off-by: Michael Petlan Acked-by: Ian Rogers Cc: Jiri Olsa LPU-Reference: 20210922152706.23655-1-mpetlan@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/vmlinux-kallsyms.c | 102 ++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index 193b7c91b4e2..4f884aabc7f4 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "dso.h" #include "map.h" @@ -14,6 +15,102 @@ #define UM(x) kallsyms_map->unmap_ip(kallsyms_map, (x)) +static bool is_ignored_symbol(const char *name, char type) +{ + /* Symbol names that exactly match to the following are ignored.*/ + static const char * const ignored_symbols[] = { + /* + * Symbols which vary between passes. Passes 1 and 2 must have + * identical symbol lists. The kallsyms_* symbols below are + * only added after pass 1, they would be included in pass 2 + * when --all-symbols is specified so exclude them to get a + * stable symbol list. + */ + "kallsyms_addresses", + "kallsyms_offsets", + "kallsyms_relative_base", + "kallsyms_num_syms", + "kallsyms_names", + "kallsyms_markers", + "kallsyms_token_table", + "kallsyms_token_index", + /* Exclude linker generated symbols which vary between passes */ + "_SDA_BASE_", /* ppc */ + "_SDA2_BASE_", /* ppc */ + NULL + }; + + /* Symbol names that begin with the following are ignored.*/ + static const char * const ignored_prefixes[] = { + "$", /* local symbols for ARM, MIPS, etc. */ + ".LASANPC", /* s390 kasan local symbols */ + "__crc_", /* modversions */ + "__efistub_", /* arm64 EFI stub namespace */ + "__kvm_nvhe_", /* arm64 non-VHE KVM namespace */ + "__AArch64ADRPThunk_", /* arm64 lld */ + "__ARMV5PILongThunk_", /* arm lld */ + "__ARMV7PILongThunk_", + "__ThumbV7PILongThunk_", + "__LA25Thunk_", /* mips lld */ + "__microLA25Thunk_", + NULL + }; + + /* Symbol names that end with the following are ignored.*/ + static const char * const ignored_suffixes[] = { + "_from_arm", /* arm */ + "_from_thumb", /* arm */ + "_veneer", /* arm */ + NULL + }; + + /* Symbol names that contain the following are ignored.*/ + static const char * const ignored_matches[] = { + ".long_branch.", /* ppc stub */ + ".plt_branch.", /* ppc stub */ + NULL + }; + + const char * const *p; + + for (p = ignored_symbols; *p; p++) + if (!strcmp(name, *p)) + return true; + + for (p = ignored_prefixes; *p; p++) + if (!strncmp(name, *p, strlen(*p))) + return true; + + for (p = ignored_suffixes; *p; p++) { + int l = strlen(name) - strlen(*p); + + if (l >= 0 && !strcmp(name + l, *p)) + return true; + } + + for (p = ignored_matches; *p; p++) { + if (strstr(name, *p)) + return true; + } + + if (type == 'U' || type == 'u') + return true; + /* exclude debugging symbols */ + if (type == 'N' || type == 'n') + return true; + + if (toupper(type) == 'A') { + /* Keep these useful absolute symbols */ + if (strcmp(name, "__kernel_syscall_via_break") && + strcmp(name, "__kernel_syscall_via_epc") && + strcmp(name, "__kernel_sigtramp") && + strcmp(name, "__gp")) + return true; + } + + return false; +} + int test__vmlinux_matches_kallsyms(struct test *test __maybe_unused, int subtest __maybe_unused) { int err = -1; @@ -169,6 +266,11 @@ next_pair: * such as __indirect_thunk_end. */ continue; + } else if (is_ignored_symbol(sym->name, sym->type)) { + /* + * Ignore hidden symbols, see scripts/kallsyms.c for the details + */ + continue; } else { pr_debug("ERR : %#" PRIx64 ": %s not on kallsyms\n", mem_start, sym->name); -- cgit From 2b3db4db660f9cc04878d81c2517f840763e6733 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 6 Aug 2021 23:15:15 +0200 Subject: i2c: i801: Improve is_dell_system_with_lis3lv02d Replace the ugly cast of the return_value pointer with proper usage. In addition use dmi_match() instead of open-coding it. Signed-off-by: Heiner Kallweit Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 89ae78ef1a1c..f56060fcf5ac 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -1192,7 +1192,7 @@ static acpi_status check_acpi_smo88xx_device(acpi_handle obj_handle, kfree(info); - *((bool *)return_value) = true; + *return_value = NULL; return AE_CTRL_TERMINATE; smo88xx_not_found: @@ -1202,11 +1202,9 @@ smo88xx_not_found: static bool is_dell_system_with_lis3lv02d(void) { - bool found; - const char *vendor; + void *err = ERR_PTR(-ENOENT); - vendor = dmi_get_system_info(DMI_SYS_VENDOR); - if (!vendor || strcmp(vendor, "Dell Inc.")) + if (!dmi_match(DMI_SYS_VENDOR, "Dell Inc.")) return false; /* @@ -1217,11 +1215,9 @@ static bool is_dell_system_with_lis3lv02d(void) * accelerometer but unfortunately ACPI does not provide any other * information (like I2C address). */ - found = false; - acpi_get_devices(NULL, check_acpi_smo88xx_device, NULL, - (void **)&found); + acpi_get_devices(NULL, check_acpi_smo88xx_device, NULL, &err); - return found; + return !IS_ERR(err); } /* -- cgit From e462aa7e39b5b6f70bc993d5ce50f7cc2e71182a Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 6 Aug 2021 23:15:51 +0200 Subject: i2c: i801: Remove not needed check for PCI_COMMAND_INTX_DISABLE do_pci_enable_device() takes care that PCI_COMMAND_INTX_DISABLE is cleared if a legacy interrupt is used. Signed-off-by: Heiner Kallweit Reviewed-by: Andy Shevchenko Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index f56060fcf5ac..7fa06b85fa97 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -1827,19 +1827,12 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) priv->features &= ~FEATURE_IRQ; if (priv->features & FEATURE_IRQ) { - u16 pcictl, pcists; + u16 pcists; /* Complain if an interrupt is already pending */ pci_read_config_word(priv->pci_dev, PCI_STATUS, &pcists); if (pcists & PCI_STATUS_INTERRUPT) dev_warn(&dev->dev, "An interrupt is pending!\n"); - - /* Check if interrupts have been disabled */ - pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pcictl); - if (pcictl & PCI_COMMAND_INTX_DISABLE) { - dev_info(&dev->dev, "Interrupts are disabled\n"); - priv->features &= ~FEATURE_IRQ; - } } if (priv->features & FEATURE_IRQ) { -- cgit From 4811a411a92913e5327e4b32d4bb783823348537 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 6 Aug 2021 23:16:33 +0200 Subject: i2c: i801: Improve i801_acpi_probe/remove functions By using ACPI_HANDLE() the handler argument can be retrieved directly. Both address space handler functions check the handler argument and return an error if it's NULL. This allows to further simplify the code. Reviewed-by: Jean Delvare Tested-by: Jean Delvare Reviewed-by: Mika Westerberg Signed-off-by: Heiner Kallweit Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 7fa06b85fa97..bd1db0f0aa19 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -1635,31 +1635,22 @@ i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits, static int i801_acpi_probe(struct i801_priv *priv) { - struct acpi_device *adev; + acpi_handle ah = ACPI_HANDLE(&priv->pci_dev->dev); acpi_status status; - adev = ACPI_COMPANION(&priv->pci_dev->dev); - if (adev) { - status = acpi_install_address_space_handler(adev->handle, - ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler, - NULL, priv); - if (ACPI_SUCCESS(status)) - return 0; - } + status = acpi_install_address_space_handler(ah, ACPI_ADR_SPACE_SYSTEM_IO, + i801_acpi_io_handler, NULL, priv); + if (ACPI_SUCCESS(status)) + return 0; return acpi_check_resource_conflict(&priv->pci_dev->resource[SMBBAR]); } static void i801_acpi_remove(struct i801_priv *priv) { - struct acpi_device *adev; - - adev = ACPI_COMPANION(&priv->pci_dev->dev); - if (!adev) - return; + acpi_handle ah = ACPI_HANDLE(&priv->pci_dev->dev); - acpi_remove_address_space_handler(adev->handle, - ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler); + acpi_remove_address_space_handler(ah, ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler); } #else static inline int i801_acpi_probe(struct i801_priv *priv) { return 0; } -- cgit From 4c5910631cc1a9c3b8d34ebb0048727eded9148c Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 6 Aug 2021 23:17:10 +0200 Subject: i2c: i801: Improve i801_add_mux The return value of i801_add_mux() isn't used, so let's change it to void. In addition remove the not needed cast to struct gpiod_lookup. GPIO_LOOKUP() uses GPIO_LOOKUP_IDX() that includes this cast. Reviewed-by: Jean Delvare Tested-by: Jean Delvare Signed-off-by: Heiner Kallweit Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index bd1db0f0aa19..6e9aca81b7f0 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -1391,7 +1391,7 @@ static const struct dmi_system_id mux_dmi_table[] = { }; /* Setup multiplexing if needed */ -static int i801_add_mux(struct i801_priv *priv) +static void i801_add_mux(struct i801_priv *priv) { struct device *dev = &priv->adapter.dev; const struct i801_mux_config *mux_config; @@ -1400,7 +1400,7 @@ static int i801_add_mux(struct i801_priv *priv) int i; if (!priv->mux_drvdata) - return 0; + return; mux_config = priv->mux_drvdata; /* Prepare the platform data */ @@ -1416,13 +1416,11 @@ static int i801_add_mux(struct i801_priv *priv) struct_size(lookup, table, mux_config->n_gpios + 1), GFP_KERNEL); if (!lookup) - return -ENOMEM; + return; lookup->dev_id = "i2c-mux-gpio"; - for (i = 0; i < mux_config->n_gpios; i++) { - lookup->table[i] = (struct gpiod_lookup) - GPIO_LOOKUP(mux_config->gpio_chip, - mux_config->gpios[i], "mux", 0); - } + for (i = 0; i < mux_config->n_gpios; i++) + lookup->table[i] = GPIO_LOOKUP(mux_config->gpio_chip, + mux_config->gpios[i], "mux", 0); gpiod_add_lookup_table(lookup); priv->lookup = lookup; @@ -1440,8 +1438,6 @@ static int i801_add_mux(struct i801_priv *priv) gpiod_remove_lookup_table(lookup); dev_err(dev, "Failed to register i2c-mux-gpio device\n"); } - - return PTR_ERR_OR_ZERO(priv->mux_pdev); } static void i801_del_mux(struct i801_priv *priv) @@ -1471,7 +1467,7 @@ static unsigned int i801_get_adapter_class(struct i801_priv *priv) return class; } #else -static inline int i801_add_mux(struct i801_priv *priv) { return 0; } +static inline void i801_add_mux(struct i801_priv *priv) { } static inline void i801_del_mux(struct i801_priv *priv) { } static inline unsigned int i801_get_adapter_class(struct i801_priv *priv) -- cgit From 7d6b61c394a42b8385858bb9e306d48a0112823c Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sun, 5 Sep 2021 17:59:42 +0200 Subject: i2c: i801: Use PCI bus rescan mutex to protect P2SB access As pointed out by Andy in [0] using a local mutex here isn't strictly wrong but not sufficient. We should hold the PCI rescan lock for P2SB operations. [0] https://www.spinics.net/lists/linux-i2c/msg52717.html Fixes: 1a987c69ce2c ("i2c: i801: make p2sb_spinlock a mutex") Reported-by: Andy Shevchenko Signed-off-by: Heiner Kallweit Reviewed-by: Andy Shevchenko Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 6e9aca81b7f0..260fc41b5ca7 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -1485,7 +1485,6 @@ static struct platform_device * i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev, struct resource *tco_res) { - static DEFINE_MUTEX(p2sb_mutex); struct resource *res; unsigned int devfn; u64 base64_addr; @@ -1498,7 +1497,7 @@ i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev, * enumerated by the PCI subsystem, so we need to unhide/hide it * to lookup the P2SB BAR. */ - mutex_lock(&p2sb_mutex); + pci_lock_rescan_remove(); devfn = PCI_DEVFN(PCI_SLOT(pci_dev->devfn), 1); @@ -1516,7 +1515,7 @@ i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev, /* Hide the P2SB device, if it was hidden before */ if (hidden) pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, hidden); - mutex_unlock(&p2sb_mutex); + pci_unlock_rescan_remove(); res = &tco_res[1]; if (pci_dev->device == PCI_DEVICE_ID_INTEL_DNV_SMBUS) -- cgit From c073b25dad0c2668b73ae9e8652bc3b8012e762b Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 7 Sep 2021 22:33:02 +0200 Subject: i2c: i801: Stop using pm_runtime_set_autosuspend_delay(-1) The original change works as intended, but Andy pointed in [0] that now userspace could re-enable RPM via sysfs, even though we explicitly want to disable it. So effectively revert the original patch, just with small improvements: - Calls to pm_runtime_allow()/pm_runtime_forbid() don't have to be balanced, so we can remove the call to pm_runtime_forbid() in i801_remove(). - priv->acpi_reserved is accessed after i801_acpi_remove(), and according to Robert [1] the custom handler can't run any longer. Therefore we don't have to take priv->acpi_lock. [0] https://www.spinics.net/lists/linux-i2c/msg52730.html [1] https://lore.kernel.org/linux-acpi/BYAPR11MB32561D19A0FD9AB93E2B1E5287D39@BYAPR11MB3256.namprd11.prod.outlook.com/T/#t Fixes: 4e60d5dd10cd ("i2c: i801: Improve disabling runtime pm") Reported-by: Andy Shevchenko Signed-off-by: Heiner Kallweit Acked-by: Rafael J. Wysocki Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 260fc41b5ca7..115660dce722 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -1615,7 +1615,7 @@ i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits, * BIOS is accessing the host controller so prevent it from * suspending automatically from now on. */ - pm_runtime_set_autosuspend_delay(&pdev->dev, -1); + pm_runtime_get_sync(&pdev->dev); } if ((function & ACPI_IO_MASK) == ACPI_READ) @@ -1866,9 +1866,6 @@ static void i801_remove(struct pci_dev *dev) { struct i801_priv *priv = pci_get_drvdata(dev); - pm_runtime_forbid(&dev->dev); - pm_runtime_get_noresume(&dev->dev); - i801_disable_host_notify(priv); i801_del_mux(priv); i2c_del_adapter(&priv->adapter); @@ -1877,6 +1874,10 @@ static void i801_remove(struct pci_dev *dev) platform_device_unregister(priv->tco_pdev); + /* if acpi_reserved is set then usage_count is incremented already */ + if (!priv->acpi_reserved) + pm_runtime_get_noresume(&dev->dev); + /* * do not call pci_disable_device(dev) since it can cause hard hangs on * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010) -- cgit From e7f4264821a4ee07775f3775f8530cfa9a6d4b5d Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 15 Sep 2021 15:48:27 +0200 Subject: i2c: rcar: enable interrupts before starting transfer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to enable the interrupts _before_ starting the transfer because it is good programming style and also the proposed order in the R-Car manual. There is no difference in practice because it doesn't matter in which order both conditions appear if we wait for both to happen. Signed-off-by: Ryo Kataoka Signed-off-by: Wolfram Sang Reviewed-by: Niklas Söderlund Reviewed-by: Ulrich Hecht Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rcar.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index bff9913c37b8..fc13511f4562 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -339,6 +339,9 @@ static void rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv) priv->flags |= ID_LAST_MSG; rcar_i2c_write(priv, ICMAR, i2c_8bit_addr_from_msg(priv->msg)); + if (!priv->atomic_xfer) + rcar_i2c_write(priv, ICMIER, read ? RCAR_IRQ_RECV : RCAR_IRQ_SEND); + /* * We don't have a test case but the HW engineers say that the write order * of ICMSR and ICMCR depends on whether we issue START or REP_START. Since @@ -354,9 +357,6 @@ static void rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv) rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START); rcar_i2c_write(priv, ICMSR, 0); } - - if (!priv->atomic_xfer) - rcar_i2c_write(priv, ICMIER, read ? RCAR_IRQ_RECV : RCAR_IRQ_SEND); } static void rcar_i2c_next_msg(struct rcar_i2c_priv *priv) -- cgit From ed2f85115a8e3423b68d8ac39aa7751c0779ce30 Mon Sep 17 00:00:00 2001 From: zhaoxiao Date: Mon, 6 Sep 2021 13:27:30 +0800 Subject: i2c: bcm-kona: Fix return value in probe() When call function devm_platform_ioremap_resource(), we should use IS_ERR() to check the return value and return PTR_ERR() if failed. Signed-off-by: zhaoxiao Acked-by: Florian Fainelli Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bcm-kona.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-bcm-kona.c b/drivers/i2c/busses/i2c-bcm-kona.c index ed5e1275ae46..8e350f20cde0 100644 --- a/drivers/i2c/busses/i2c-bcm-kona.c +++ b/drivers/i2c/busses/i2c-bcm-kona.c @@ -763,7 +763,7 @@ static int bcm_kona_i2c_probe(struct platform_device *pdev) /* Map hardware registers */ dev->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(dev->base)) - return -ENOMEM; + return PTR_ERR(dev->base); /* Get and enable external clock */ dev->external_clk = devm_clk_get(dev->device, NULL); -- cgit From 647d908816a78d604d47ea925c934fd88375b4fd Mon Sep 17 00:00:00 2001 From: Michael Brunner Date: Tue, 31 Aug 2021 10:29:36 +0000 Subject: i2c: kempld: deprecate class based instantiation Warn users that class based instantiation is going away soon in favour of more robust probing and faster bootup times. Class based instantiation has already been removed for other controllers and it makes absolutely sense to do it for this one too. Signed-off-by: Michael Brunner Acked-by: Ingmar Klein Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-kempld.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-kempld.c b/drivers/i2c/busses/i2c-kempld.c index 2d60be086b1a..5bbb7f0d7852 100644 --- a/drivers/i2c/busses/i2c-kempld.c +++ b/drivers/i2c/busses/i2c-kempld.c @@ -283,7 +283,8 @@ static const struct i2c_algorithm kempld_i2c_algorithm = { static const struct i2c_adapter kempld_i2c_adapter = { .owner = THIS_MODULE, .name = "i2c-kempld", - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON | I2C_CLASS_SPD | + I2C_CLASS_DEPRECATED, .algo = &kempld_i2c_algorithm, }; -- cgit From 7c3855c423b17f6ca211858afb0cef20569914c7 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Tue, 13 Jul 2021 20:50:07 +0800 Subject: PCI: Coalesce host bridge contiguous apertures Built-in graphics at 07:00.0 on HP EliteDesk 805 G6 doesn't work because graphics can't get the BAR it needs. The BIOS configuration is correct: BARs 0 and 2 both fit in the 00:08.1 bridge window. But that 00:08.1 window covers two host bridge apertures from _CRS. Previously we assumed this was illegal, so we clipped the window to fit into one aperture (see 0f7e7aee2f37 ("PCI: Add pci_bus_clip_resource() to clip to fit upstream window")). pci_bus 0000:00: root bus resource [mem 0x10020200000-0x100303fffff window] pci_bus 0000:00: root bus resource [mem 0x10030400000-0x100401fffff window] pci 0000:00:08.1: bridge window [mem 0x10030000000-0x100401fffff 64bit pref] pci 0000:07:00.0: reg 0x10: [mem 0x10030000000-0x1003fffffff 64bit pref] pci 0000:07:00.0: reg 0x18: [mem 0x10040000000-0x100401fffff 64bit pref] pci 0000:00:08.1: can't claim BAR 15 [mem 0x10030000000-0x100401fffff 64bit pref]: no compatible bridge window pci 0000:00:08.1: [mem 0x10030000000-0x100401fffff 64bit pref] clipped to [mem 0x10030000000-0x100303fffff 64bit pref] pci 0000:00:08.1: bridge window [mem 0x10030000000-0x100303fffff 64bit pref] pci 0000:07:00.0: can't claim BAR 0 [mem 0x10030000000-0x1003fffffff 64bit pref]: no compatible bridge window pci 0000:07:00.0: can't claim BAR 2 [mem 0x10040000000-0x100401fffff 64bit pref]: no compatible bridge window However, the host bridge apertures are contiguous, so there's no need to clip in this case. Coalesce contiguous apertures so we can allocate from the entire contiguous region. Previous commit 65db04053efe ("PCI: Coalesce host bridge contiguous apertures") was similar but sorted the apertures, and Guenter Roeck reported a regression in ppc:sam460ex qemu emulation from nvme; see https://lore.kernel.org/all/20210709231529.GA3270116@roeck-us.net/ [bhelgaas: commit log] Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=212013 Suggested-by: Bjorn Helgaas Link: https://lore.kernel.org/r/20210713125007.1260304-1-kai.heng.feng@canonical.com Signed-off-by: Kai-Heng Feng Signed-off-by: Bjorn Helgaas Cc: Guenter Roeck --- drivers/pci/probe.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index d9fc02a71baa..3459f460dbd8 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -883,11 +883,11 @@ static void pci_set_bus_msi_domain(struct pci_bus *bus) static int pci_register_host_bridge(struct pci_host_bridge *bridge) { struct device *parent = bridge->dev.parent; - struct resource_entry *window, *n; + struct resource_entry *window, *next, *n; struct pci_bus *bus, *b; - resource_size_t offset; + resource_size_t offset, next_offset; LIST_HEAD(resources); - struct resource *res; + struct resource *res, *next_res; char addr[64], *fmt; const char *name; int err; @@ -970,11 +970,34 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge) if (nr_node_ids > 1 && pcibus_to_node(bus) == NUMA_NO_NODE) dev_warn(&bus->dev, "Unknown NUMA node; performance will be reduced\n"); + /* Coalesce contiguous windows */ + resource_list_for_each_entry_safe(window, n, &resources) { + if (list_is_last(&window->node, &resources)) + break; + + next = list_next_entry(window, node); + offset = window->offset; + res = window->res; + next_offset = next->offset; + next_res = next->res; + + if (res->flags != next_res->flags || offset != next_offset) + continue; + + if (res->end + 1 == next_res->start) { + next_res->start = res->start; + res->flags = res->start = res->end = 0; + } + } + /* Add initial resources to the bus */ resource_list_for_each_entry_safe(window, n, &resources) { - list_move_tail(&window->node, &bridge->windows); offset = window->offset; res = window->res; + if (!res->end) + continue; + + list_move_tail(&window->node, &bridge->windows); if (res->flags & IORESOURCE_BUS) pci_bus_insert_busn_res(bus, bus->number, res->end); -- cgit From eb057514ccca92d44f37be057152c7d2791cdae0 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 25 Sep 2021 18:17:43 +0100 Subject: platform/chrome: cros_ec: Fix spelling mistake "responsed" -> "response" There are spelling mistakes in dev_warn messages. Fix them. Signed-off-by: Colin Ian King Signed-off-by: Enric Balletbo i Serra Link: https://lore.kernel.org/r/20210925171743.173219-1-colin.king@canonical.com --- drivers/platform/chrome/cros_ec_lpc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c index 1f7861944044..d6306d2a096f 100644 --- a/drivers/platform/chrome/cros_ec_lpc.c +++ b/drivers/platform/chrome/cros_ec_lpc.c @@ -156,7 +156,7 @@ static int cros_ec_pkt_xfer_lpc(struct cros_ec_device *ec, cros_ec_lpc_ops.write(EC_LPC_ADDR_HOST_CMD, 1, &sum); if (ec_response_timed_out()) { - dev_warn(ec->dev, "EC responsed timed out\n"); + dev_warn(ec->dev, "EC response timed out\n"); ret = -EIO; goto done; } @@ -238,7 +238,7 @@ static int cros_ec_cmd_xfer_lpc(struct cros_ec_device *ec, cros_ec_lpc_ops.write(EC_LPC_ADDR_HOST_CMD, 1, &sum); if (ec_response_timed_out()) { - dev_warn(ec->dev, "EC responsed timed out\n"); + dev_warn(ec->dev, "EC response timed out\n"); ret = -EIO; goto done; } -- cgit From 67ea0239fb600dd6aa11d97c08b4356696947d18 Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Wed, 29 Sep 2021 19:23:48 -0700 Subject: platform/chrome: cros_usbpd_notify: Rename cros_ec_pd_command() Rename cros_ec_pd_command()_to cros_ec_command() since it can be used for sending any host command, and not just PD related ones. This patch does not introduce any functional changes. Signed-off-by: Prashant Malani Signed-off-by: Enric Balletbo i Serra Link: https://lore.kernel.org/r/20210930022403.3358070-2-pmalani@chromium.org --- drivers/platform/chrome/cros_usbpd_notify.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/platform/chrome/cros_usbpd_notify.c b/drivers/platform/chrome/cros_usbpd_notify.c index 48a6617aa12f..e718055f4313 100644 --- a/drivers/platform/chrome/cros_usbpd_notify.c +++ b/drivers/platform/chrome/cros_usbpd_notify.c @@ -54,7 +54,7 @@ void cros_usbpd_unregister_notify(struct notifier_block *nb) EXPORT_SYMBOL_GPL(cros_usbpd_unregister_notify); /** - * cros_ec_pd_command - Send a command to the EC. + * cros_ec_command - Send a command to the EC. * * @ec_dev: EC device * @command: EC command @@ -65,12 +65,12 @@ EXPORT_SYMBOL_GPL(cros_usbpd_unregister_notify); * * Return: >= 0 on success, negative error number on failure. */ -static int cros_ec_pd_command(struct cros_ec_device *ec_dev, - int command, - uint8_t *outdata, - int outsize, - uint8_t *indata, - int insize) +static int cros_ec_command(struct cros_ec_device *ec_dev, + int command, + uint8_t *outdata, + int outsize, + uint8_t *indata, + int insize) { struct cros_ec_command *msg; int ret; @@ -115,10 +115,8 @@ static void cros_usbpd_get_event_and_notify(struct device *dev, } /* Check for PD host events on EC. */ - ret = cros_ec_pd_command(ec_dev, EC_CMD_PD_HOST_EVENT_STATUS, - NULL, 0, - (uint8_t *)&host_event_status, - sizeof(host_event_status)); + ret = cros_ec_command(ec_dev, EC_CMD_PD_HOST_EVENT_STATUS, + NULL, 0, (uint8_t *)&host_event_status, sizeof(host_event_status)); if (ret < 0) { dev_warn(dev, "Can't get host event status (err: %d)\n", ret); goto send_notify; -- cgit From 7101c83950e629b83f9d827f288063e52074a6ea Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Wed, 29 Sep 2021 19:23:50 -0700 Subject: platform/chrome: cros_usbpd_notify: Move ec_command() cros_ec_command() can be used by other modules too. So, move it to a common location and export it. This patch does not introduce any functional changes. Signed-off-by: Prashant Malani Signed-off-by: Enric Balletbo i Serra Link: https://lore.kernel.org/r/20210930022403.3358070-3-pmalani@chromium.org --- drivers/platform/chrome/cros_ec_proto.c | 45 +++++++++++++++++++++++++++++ drivers/platform/chrome/cros_usbpd_notify.c | 44 ---------------------------- include/linux/platform_data/cros_ec_proto.h | 3 ++ 3 files changed, 48 insertions(+), 44 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index a34cf58c5ef7..67009b604630 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -910,3 +910,48 @@ int cros_ec_get_sensor_count(struct cros_ec_dev *ec) return sensor_count; } EXPORT_SYMBOL_GPL(cros_ec_get_sensor_count); + +/** + * cros_ec_command - Send a command to the EC. + * + * @ec_dev: EC device + * @command: EC command + * @outdata: EC command output data + * @outsize: Size of outdata + * @indata: EC command input data + * @insize: Size of indata + * + * Return: >= 0 on success, negative error number on failure. + */ +int cros_ec_command(struct cros_ec_device *ec_dev, + int command, + uint8_t *outdata, + int outsize, + uint8_t *indata, + int insize) +{ + struct cros_ec_command *msg; + int ret; + + msg = kzalloc(sizeof(*msg) + max(insize, outsize), GFP_KERNEL); + if (!msg) + return -ENOMEM; + + msg->command = command; + msg->outsize = outsize; + msg->insize = insize; + + if (outsize) + memcpy(msg->data, outdata, outsize); + + ret = cros_ec_cmd_xfer_status(ec_dev, msg); + if (ret < 0) + goto error; + + if (insize) + memcpy(indata, msg->data, insize); +error: + kfree(msg); + return ret; +} +EXPORT_SYMBOL_GPL(cros_ec_command); diff --git a/drivers/platform/chrome/cros_usbpd_notify.c b/drivers/platform/chrome/cros_usbpd_notify.c index e718055f4313..39afdad897ce 100644 --- a/drivers/platform/chrome/cros_usbpd_notify.c +++ b/drivers/platform/chrome/cros_usbpd_notify.c @@ -53,50 +53,6 @@ void cros_usbpd_unregister_notify(struct notifier_block *nb) } EXPORT_SYMBOL_GPL(cros_usbpd_unregister_notify); -/** - * cros_ec_command - Send a command to the EC. - * - * @ec_dev: EC device - * @command: EC command - * @outdata: EC command output data - * @outsize: Size of outdata - * @indata: EC command input data - * @insize: Size of indata - * - * Return: >= 0 on success, negative error number on failure. - */ -static int cros_ec_command(struct cros_ec_device *ec_dev, - int command, - uint8_t *outdata, - int outsize, - uint8_t *indata, - int insize) -{ - struct cros_ec_command *msg; - int ret; - - msg = kzalloc(sizeof(*msg) + max(insize, outsize), GFP_KERNEL); - if (!msg) - return -ENOMEM; - - msg->command = command; - msg->outsize = outsize; - msg->insize = insize; - - if (outsize) - memcpy(msg->data, outdata, outsize); - - ret = cros_ec_cmd_xfer_status(ec_dev, msg); - if (ret < 0) - goto error; - - if (insize) - memcpy(indata, msg->data, insize); -error: - kfree(msg); - return ret; -} - static void cros_usbpd_get_event_and_notify(struct device *dev, struct cros_ec_device *ec_dev) { diff --git a/include/linux/platform_data/cros_ec_proto.h b/include/linux/platform_data/cros_ec_proto.h index 55844ece0b32..20b17c43caeb 100644 --- a/include/linux/platform_data/cros_ec_proto.h +++ b/include/linux/platform_data/cros_ec_proto.h @@ -231,6 +231,9 @@ bool cros_ec_check_features(struct cros_ec_dev *ec, int feature); int cros_ec_get_sensor_count(struct cros_ec_dev *ec); +int cros_ec_command(struct cros_ec_device *ec_dev, int command, uint8_t *outdata, int outsize, + uint8_t *indata, int insize); + /** * cros_ec_get_time_ns() - Return time in ns. * -- cgit From 5d122256f4e5900f7f8de5d8787af570314f6701 Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Wed, 29 Sep 2021 19:23:52 -0700 Subject: platform/chrome: cros_ec_proto: Make data pointers void Convert the input and output data pointers for cros_ec_command() to void pointers so that the callers don't have to cast their custom structs to uint8_t *. Signed-off-by: Prashant Malani Signed-off-by: Enric Balletbo i Serra Link: https://lore.kernel.org/r/20210930022403.3358070-4-pmalani@chromium.org --- drivers/platform/chrome/cros_ec_proto.c | 4 ++-- drivers/platform/chrome/cros_usbpd_notify.c | 2 +- include/linux/platform_data/cros_ec_proto.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index 67009b604630..fd114b57bca2 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -925,9 +925,9 @@ EXPORT_SYMBOL_GPL(cros_ec_get_sensor_count); */ int cros_ec_command(struct cros_ec_device *ec_dev, int command, - uint8_t *outdata, + void *outdata, int outsize, - uint8_t *indata, + void *indata, int insize) { struct cros_ec_command *msg; diff --git a/drivers/platform/chrome/cros_usbpd_notify.c b/drivers/platform/chrome/cros_usbpd_notify.c index 39afdad897ce..860509474f05 100644 --- a/drivers/platform/chrome/cros_usbpd_notify.c +++ b/drivers/platform/chrome/cros_usbpd_notify.c @@ -72,7 +72,7 @@ static void cros_usbpd_get_event_and_notify(struct device *dev, /* Check for PD host events on EC. */ ret = cros_ec_command(ec_dev, EC_CMD_PD_HOST_EVENT_STATUS, - NULL, 0, (uint8_t *)&host_event_status, sizeof(host_event_status)); + NULL, 0, &host_event_status, sizeof(host_event_status)); if (ret < 0) { dev_warn(dev, "Can't get host event status (err: %d)\n", ret); goto send_notify; diff --git a/include/linux/platform_data/cros_ec_proto.h b/include/linux/platform_data/cros_ec_proto.h index 20b17c43caeb..f833473c5f44 100644 --- a/include/linux/platform_data/cros_ec_proto.h +++ b/include/linux/platform_data/cros_ec_proto.h @@ -231,8 +231,8 @@ bool cros_ec_check_features(struct cros_ec_dev *ec, int feature); int cros_ec_get_sensor_count(struct cros_ec_dev *ec); -int cros_ec_command(struct cros_ec_device *ec_dev, int command, uint8_t *outdata, int outsize, - uint8_t *indata, int insize); +int cros_ec_command(struct cros_ec_device *ec_dev, int command, void *outdata, int outsize, + void *indata, int insize); /** * cros_ec_get_time_ns() - Return time in ns. -- cgit From 4f1406396ed4d97518b8112327bdaf14fc9d4090 Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Wed, 29 Sep 2021 19:23:54 -0700 Subject: platform/chrome: cros_ec_proto: Add version for ec_command Add a version parameter to cros_ec_command() for callers that may want to specify which version of the host command they would like to use. Signed-off-by: Prashant Malani Signed-off-by: Enric Balletbo i Serra Link: https://lore.kernel.org/r/20210930022403.3358070-5-pmalani@chromium.org --- drivers/platform/chrome/cros_ec_proto.c | 3 +++ drivers/platform/chrome/cros_usbpd_notify.c | 2 +- include/linux/platform_data/cros_ec_proto.h | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index fd114b57bca2..a9f1867e5d8f 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -915,6 +915,7 @@ EXPORT_SYMBOL_GPL(cros_ec_get_sensor_count); * cros_ec_command - Send a command to the EC. * * @ec_dev: EC device + * @version: EC command version * @command: EC command * @outdata: EC command output data * @outsize: Size of outdata @@ -924,6 +925,7 @@ EXPORT_SYMBOL_GPL(cros_ec_get_sensor_count); * Return: >= 0 on success, negative error number on failure. */ int cros_ec_command(struct cros_ec_device *ec_dev, + unsigned int version, int command, void *outdata, int outsize, @@ -937,6 +939,7 @@ int cros_ec_command(struct cros_ec_device *ec_dev, if (!msg) return -ENOMEM; + msg->version = version; msg->command = command; msg->outsize = outsize; msg->insize = insize; diff --git a/drivers/platform/chrome/cros_usbpd_notify.c b/drivers/platform/chrome/cros_usbpd_notify.c index 860509474f05..91ce6be91aac 100644 --- a/drivers/platform/chrome/cros_usbpd_notify.c +++ b/drivers/platform/chrome/cros_usbpd_notify.c @@ -71,7 +71,7 @@ static void cros_usbpd_get_event_and_notify(struct device *dev, } /* Check for PD host events on EC. */ - ret = cros_ec_command(ec_dev, EC_CMD_PD_HOST_EVENT_STATUS, + ret = cros_ec_command(ec_dev, 0, EC_CMD_PD_HOST_EVENT_STATUS, NULL, 0, &host_event_status, sizeof(host_event_status)); if (ret < 0) { dev_warn(dev, "Can't get host event status (err: %d)\n", ret); diff --git a/include/linux/platform_data/cros_ec_proto.h b/include/linux/platform_data/cros_ec_proto.h index f833473c5f44..9d370816a419 100644 --- a/include/linux/platform_data/cros_ec_proto.h +++ b/include/linux/platform_data/cros_ec_proto.h @@ -231,8 +231,8 @@ bool cros_ec_check_features(struct cros_ec_dev *ec, int feature); int cros_ec_get_sensor_count(struct cros_ec_dev *ec); -int cros_ec_command(struct cros_ec_device *ec_dev, int command, void *outdata, int outsize, - void *indata, int insize); +int cros_ec_command(struct cros_ec_device *ec_dev, unsigned int version, int command, void *outdata, + int outsize, void *indata, int insize); /** * cros_ec_get_time_ns() - Return time in ns. -- cgit From fb75686bed1ac0b3d16055456625f4102100b64a Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Wed, 29 Sep 2021 19:23:56 -0700 Subject: platform/chrome: cros_ec_typec: Use cros_ec_command() Re-use the existing cros_ec_command() instead of relying on a duplicate version. Signed-off-by: Prashant Malani Signed-off-by: Enric Balletbo i Serra Link: https://lore.kernel.org/r/20210930022403.3358070-6-pmalani@chromium.org --- drivers/platform/chrome/cros_ec_typec.c | 69 +++++++++------------------------ 1 file changed, 19 insertions(+), 50 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c index 7b3afb6cda5d..5de0bfb0bc4d 100644 --- a/drivers/platform/chrome/cros_ec_typec.c +++ b/drivers/platform/chrome/cros_ec_typec.c @@ -379,37 +379,6 @@ unregister_ports: return ret; } -static int cros_typec_ec_command(struct cros_typec_data *typec, - unsigned int version, - unsigned int command, - void *outdata, - unsigned int outsize, - void *indata, - unsigned int insize) -{ - struct cros_ec_command *msg; - int ret; - - msg = kzalloc(sizeof(*msg) + max(outsize, insize), GFP_KERNEL); - if (!msg) - return -ENOMEM; - - msg->version = version; - msg->command = command; - msg->outsize = outsize; - msg->insize = insize; - - if (outsize) - memcpy(msg->data, outdata, outsize); - - ret = cros_ec_cmd_xfer_status(typec->ec, msg); - if (ret >= 0 && insize) - memcpy(indata, msg->data, insize); - - kfree(msg); - return ret; -} - static int cros_typec_usb_safe_state(struct cros_typec_port *port) { port->state.mode = TYPEC_STATE_SAFE; @@ -596,8 +565,8 @@ mux_ack: /* Sending Acknowledgment to EC */ mux_ack.port = port_num; - if (cros_typec_ec_command(typec, 0, EC_CMD_USB_PD_MUX_ACK, &mux_ack, - sizeof(mux_ack), NULL, 0) < 0) + if (cros_ec_command(typec->ec, 0, EC_CMD_USB_PD_MUX_ACK, &mux_ack, + sizeof(mux_ack), NULL, 0) < 0) dev_warn(typec->dev, "Failed to send Mux ACK to EC for port: %d\n", port_num); @@ -668,8 +637,8 @@ static int cros_typec_get_mux_info(struct cros_typec_data *typec, int port_num, .port = port_num, }; - return cros_typec_ec_command(typec, 0, EC_CMD_USB_PD_MUX_INFO, &req, - sizeof(req), resp, sizeof(*resp)); + return cros_ec_command(typec->ec, 0, EC_CMD_USB_PD_MUX_INFO, &req, + sizeof(req), resp, sizeof(*resp)); } /* @@ -776,8 +745,8 @@ static int cros_typec_handle_sop_prime_disc(struct cros_typec_data *typec, int p int ret = 0; memset(disc, 0, EC_PROTO2_MAX_RESPONSE_SIZE); - ret = cros_typec_ec_command(typec, 0, EC_CMD_TYPEC_DISCOVERY, &req, sizeof(req), - disc, EC_PROTO2_MAX_RESPONSE_SIZE); + ret = cros_ec_command(typec->ec, 0, EC_CMD_TYPEC_DISCOVERY, &req, sizeof(req), + disc, EC_PROTO2_MAX_RESPONSE_SIZE); if (ret < 0) { dev_err(typec->dev, "Failed to get SOP' discovery data for port: %d\n", port_num); goto sop_prime_disc_exit; @@ -859,8 +828,8 @@ static int cros_typec_handle_sop_disc(struct cros_typec_data *typec, int port_nu typec_partner_set_pd_revision(port->partner, pd_revision); memset(sop_disc, 0, EC_PROTO2_MAX_RESPONSE_SIZE); - ret = cros_typec_ec_command(typec, 0, EC_CMD_TYPEC_DISCOVERY, &req, sizeof(req), - sop_disc, EC_PROTO2_MAX_RESPONSE_SIZE); + ret = cros_ec_command(typec->ec, 0, EC_CMD_TYPEC_DISCOVERY, &req, sizeof(req), + sop_disc, EC_PROTO2_MAX_RESPONSE_SIZE); if (ret < 0) { dev_err(typec->dev, "Failed to get SOP discovery data for port: %d\n", port_num); goto disc_exit; @@ -892,8 +861,8 @@ static int cros_typec_send_clear_event(struct cros_typec_data *typec, int port_n .clear_events_mask = events_mask, }; - return cros_typec_ec_command(typec, 0, EC_CMD_TYPEC_CONTROL, &req, - sizeof(req), NULL, 0); + return cros_ec_command(typec->ec, 0, EC_CMD_TYPEC_CONTROL, &req, + sizeof(req), NULL, 0); } static void cros_typec_handle_status(struct cros_typec_data *typec, int port_num) @@ -904,8 +873,8 @@ static void cros_typec_handle_status(struct cros_typec_data *typec, int port_num }; int ret; - ret = cros_typec_ec_command(typec, 0, EC_CMD_TYPEC_STATUS, &req, sizeof(req), - &resp, sizeof(resp)); + ret = cros_ec_command(typec->ec, 0, EC_CMD_TYPEC_STATUS, &req, sizeof(req), + &resp, sizeof(resp)); if (ret < 0) { dev_warn(typec->dev, "EC_CMD_TYPEC_STATUS failed for port: %d\n", port_num); return; @@ -983,9 +952,9 @@ static int cros_typec_port_update(struct cros_typec_data *typec, int port_num) req.mux = USB_PD_CTRL_MUX_NO_CHANGE; req.swap = USB_PD_CTRL_SWAP_NONE; - ret = cros_typec_ec_command(typec, typec->pd_ctrl_ver, - EC_CMD_USB_PD_CONTROL, &req, sizeof(req), - &resp, sizeof(resp)); + ret = cros_ec_command(typec->ec, typec->pd_ctrl_ver, + EC_CMD_USB_PD_CONTROL, &req, sizeof(req), + &resp, sizeof(resp)); if (ret < 0) return ret; @@ -1035,8 +1004,8 @@ static int cros_typec_get_cmd_version(struct cros_typec_data *typec) /* We're interested in the PD control command version. */ req_v1.cmd = EC_CMD_USB_PD_CONTROL; - ret = cros_typec_ec_command(typec, 1, EC_CMD_GET_CMD_VERSIONS, - &req_v1, sizeof(req_v1), &resp, + ret = cros_ec_command(typec->ec, 1, EC_CMD_GET_CMD_VERSIONS, + &req_v1, sizeof(req_v1), &resp, sizeof(resp)); if (ret < 0) return ret; @@ -1119,8 +1088,8 @@ static int cros_typec_probe(struct platform_device *pdev) typec->typec_cmd_supported = cros_ec_check_features(ec_dev, EC_FEATURE_TYPEC_CMD); typec->needs_mux_ack = cros_ec_check_features(ec_dev, EC_FEATURE_TYPEC_MUX_REQUIRE_AP_ACK); - ret = cros_typec_ec_command(typec, 0, EC_CMD_USB_PD_PORTS, NULL, 0, - &resp, sizeof(resp)); + ret = cros_ec_command(typec->ec, 0, EC_CMD_USB_PD_PORTS, NULL, 0, + &resp, sizeof(resp)); if (ret < 0) return ret; -- cgit From 3a7fb86758c96cc255ecc820ac47168047fe3dfa Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Mon, 31 May 2021 10:59:31 +0200 Subject: PCI: dwc: Export more symbols to allow modular drivers These symbols are used by the pci-dra7xx driver. Export them to allow building pci-dra7xx as a module. Link: https://lore.kernel.org/r/20210531085934.2662457-2-luca@lucaceresoli.net Signed-off-by: Luca Ceresoli Signed-off-by: Lorenzo Pieralisi Acked-by: Kishon Vijay Abraham I --- drivers/pci/controller/dwc/pcie-designware-ep.c | 1 + drivers/pci/controller/dwc/pcie-designware.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 998b698f4085..27e4735f577e 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -83,6 +83,7 @@ void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) for (func_no = 0; func_no < funcs; func_no++) __dw_pcie_ep_reset_bar(pci, func_no, bar, 0); } +EXPORT_SYMBOL_GPL(dw_pcie_ep_reset_bar); static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie_ep *ep, u8 func_no, u8 cap_ptr, u8 cap) diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index a945f0c0e73d..850b4533f4ef 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -538,6 +538,7 @@ int dw_pcie_link_up(struct dw_pcie *pci) return ((val & PCIE_PORT_DEBUG1_LINK_UP) && (!(val & PCIE_PORT_DEBUG1_LINK_IN_TRAINING))); } +EXPORT_SYMBOL_GPL(dw_pcie_link_up); void dw_pcie_upconfig_setup(struct dw_pcie *pci) { -- cgit From 3b868d150efd3c586762cee4410cfc75f46d2a07 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Mon, 31 May 2021 10:59:32 +0200 Subject: PCI: dra7xx: Make it a kernel module Enable building the driver as a loadable kernel module. Link: https://lore.kernel.org/r/20210531085934.2662457-3-luca@lucaceresoli.net Signed-off-by: Luca Ceresoli Signed-off-by: Lorenzo Pieralisi Acked-by: Kishon Vijay Abraham I --- drivers/pci/controller/dwc/Kconfig | 6 +++--- drivers/pci/controller/dwc/pci-dra7xx.c | 8 +++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig index 76c0a63a3f64..9892a1135678 100644 --- a/drivers/pci/controller/dwc/Kconfig +++ b/drivers/pci/controller/dwc/Kconfig @@ -17,10 +17,10 @@ config PCIE_DW_EP select PCIE_DW config PCI_DRA7XX - bool + tristate config PCI_DRA7XX_HOST - bool "TI DRA7xx PCIe controller Host Mode" + tristate "TI DRA7xx PCIe controller Host Mode" depends on SOC_DRA7XX || COMPILE_TEST depends on PCI_MSI_IRQ_DOMAIN depends on OF && HAS_IOMEM && TI_PIPE3 @@ -36,7 +36,7 @@ config PCI_DRA7XX_HOST This uses the DesignWare core. config PCI_DRA7XX_EP - bool "TI DRA7xx PCIe controller Endpoint Mode" + tristate "TI DRA7xx PCIe controller Endpoint Mode" depends on SOC_DRA7XX || COMPILE_TEST depends on PCI_ENDPOINT depends on OF && HAS_IOMEM && TI_PIPE3 diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index fbbb78f6885e..e8418446039d 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -607,6 +608,7 @@ static const struct of_device_id of_dra7xx_pcie_match[] = { }, {}, }; +MODULE_DEVICE_TABLE(of, of_dra7xx_pcie_match); /* * dra7xx_pcie_unaligned_memaccess: workaround for AM572x/AM571x Errata i870 @@ -943,4 +945,8 @@ static struct platform_driver dra7xx_pcie_driver = { }, .shutdown = dra7xx_pcie_shutdown, }; -builtin_platform_driver(dra7xx_pcie_driver); +module_platform_driver(dra7xx_pcie_driver); + +MODULE_AUTHOR("Kishon Vijay Abraham I "); +MODULE_DESCRIPTION("PCIe controller driver for TI DRA7xx SoCs"); +MODULE_LICENSE("GPL v2"); -- cgit From b9a6943dc891f7c4aec41f07e6b60ca2b31a3b2e Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Mon, 31 May 2021 10:59:33 +0200 Subject: PCI: dra7xx: Remove unused include Unused since commit e259c2926c01 ("PCI: pci-dra7xx: Prepare for deferred probe with module_platform_driver"). Link: https://lore.kernel.org/r/20210531085934.2662457-4-luca@lucaceresoli.net Signed-off-by: Luca Ceresoli Signed-off-by: Lorenzo Pieralisi Acked-by: Kishon Vijay Abraham I --- drivers/pci/controller/dwc/pci-dra7xx.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index e8418446039d..f8b1221030b4 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include -- cgit From 5af9405397bfb90d6adab61d58f4d94c78166698 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Mon, 31 May 2021 10:59:34 +0200 Subject: PCI: dra7xx: Get an optional clock If the clock is provided externally we need to make sure it is enabled before starting PCI scan. Link: https://lore.kernel.org/r/20210531085934.2662457-5-luca@lucaceresoli.net Signed-off-by: Luca Ceresoli Signed-off-by: Lorenzo Pieralisi Acked-by: Kishon Vijay Abraham I --- drivers/pci/controller/dwc/pci-dra7xx.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index f8b1221030b4..a4221f6f3629 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -7,6 +7,7 @@ * Authors: Kishon Vijay Abraham I */ +#include #include #include #include @@ -90,6 +91,7 @@ struct dra7xx_pcie { int phy_count; /* DT phy-names count */ struct phy **phy; struct irq_domain *irq_domain; + struct clk *clk; enum dw_pcie_device_mode mode; }; @@ -741,6 +743,15 @@ static int dra7xx_pcie_probe(struct platform_device *pdev) if (!link) return -ENOMEM; + dra7xx->clk = devm_clk_get_optional(dev, NULL); + if (IS_ERR(dra7xx->clk)) + return dev_err_probe(dev, PTR_ERR(dra7xx->clk), + "clock request failed"); + + ret = clk_prepare_enable(dra7xx->clk); + if (ret) + return ret; + for (i = 0; i < phy_count; i++) { snprintf(name, sizeof(name), "pcie-phy%d", i); phy[i] = devm_phy_get(dev, name); @@ -926,6 +937,8 @@ static void dra7xx_pcie_shutdown(struct platform_device *pdev) pm_runtime_disable(dev); dra7xx_pcie_disable_phy(dra7xx); + + clk_disable_unprepare(dra7xx->clk); } static const struct dev_pm_ops dra7xx_pcie_pm_ops = { -- cgit From 894682f0a9b34dcb6e8d2ee2d5f6380b24a5b2d9 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Mon, 27 Sep 2021 15:43:56 +0200 Subject: PCI: xgene: Use PCI_VENDOR_ID_AMCC macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Header file linux/pci_ids.h defines AMCC vendor id (0x10e8) macro named PCI_VENDOR_ID_AMCC. So use this macro instead of driver custom macro. Link: https://lore.kernel.org/r/20210927134356.11799-1-pali@kernel.org Signed-off-by: Pali Rohár Signed-off-by: Lorenzo Pieralisi Reviewed-by: Krzysztof Wilczyński --- drivers/pci/controller/pci-xgene.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/pci/controller/pci-xgene.c b/drivers/pci/controller/pci-xgene.c index e64536047b65..56d0d50338c8 100644 --- a/drivers/pci/controller/pci-xgene.c +++ b/drivers/pci/controller/pci-xgene.c @@ -48,7 +48,6 @@ #define EN_COHERENCY 0xF0000000 #define EN_REG 0x00000001 #define OB_LO_IO 0x00000002 -#define XGENE_PCIE_VENDORID 0x10E8 #define XGENE_PCIE_DEVICEID 0xE004 #define SZ_1T (SZ_1G*1024ULL) #define PIPE_PHY_RATE_RD(src) ((0xc000 & (u32)(src)) >> 0xe) @@ -560,7 +559,7 @@ static int xgene_pcie_setup(struct xgene_pcie_port *port) xgene_pcie_clear_config(port); /* setup the vendor and device IDs correctly */ - val = (XGENE_PCIE_DEVICEID << 16) | XGENE_PCIE_VENDORID; + val = (XGENE_PCIE_DEVICEID << 16) | PCI_VENDOR_ID_AMCC; xgene_pcie_writel(port, BRIDGE_CFG_0, val); ret = xgene_pcie_map_ranges(port); -- cgit From a2258831d12d7845946f9c98f08d65aad9aa1121 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Wed, 1 Sep 2021 14:09:17 +0900 Subject: PCI: endpoint: Use sysfs_emit() in "show" functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert sprintf() in sysfs "show" functions to sysfs_emit() in order to check for buffer overruns in sysfs outputs. Link: https://lore.kernel.org/r/1630472957-26857-1-git-send-email-hayashi.kunihiko@socionext.com Signed-off-by: Kunihiko Hayashi Signed-off-by: Lorenzo Pieralisi Reviewed-by: Krzysztof Wilczyński --- drivers/pci/endpoint/functions/pci-epf-ntb.c | 4 ++-- drivers/pci/endpoint/pci-ep-cfs.c | 13 ++++++------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/pci/endpoint/functions/pci-epf-ntb.c b/drivers/pci/endpoint/functions/pci-epf-ntb.c index 8b4756159f15..99266f05739a 100644 --- a/drivers/pci/endpoint/functions/pci-epf-ntb.c +++ b/drivers/pci/endpoint/functions/pci-epf-ntb.c @@ -1937,7 +1937,7 @@ static ssize_t epf_ntb_##_name##_show(struct config_item *item, \ struct config_group *group = to_config_group(item); \ struct epf_ntb *ntb = to_epf_ntb(group); \ \ - return sprintf(page, "%d\n", ntb->_name); \ + return sysfs_emit(page, "%d\n", ntb->_name); \ } #define EPF_NTB_W(_name) \ @@ -1968,7 +1968,7 @@ static ssize_t epf_ntb_##_name##_show(struct config_item *item, \ \ sscanf(#_name, "mw%d", &win_no); \ \ - return sprintf(page, "%lld\n", ntb->mws_size[win_no - 1]); \ + return sysfs_emit(page, "%lld\n", ntb->mws_size[win_no - 1]); \ } #define EPF_NTB_MW_W(_name) \ diff --git a/drivers/pci/endpoint/pci-ep-cfs.c b/drivers/pci/endpoint/pci-ep-cfs.c index 999911801877..5a0394a38675 100644 --- a/drivers/pci/endpoint/pci-ep-cfs.c +++ b/drivers/pci/endpoint/pci-ep-cfs.c @@ -198,8 +198,7 @@ static ssize_t pci_epc_start_store(struct config_item *item, const char *page, static ssize_t pci_epc_start_show(struct config_item *item, char *page) { - return sprintf(page, "%d\n", - to_pci_epc_group(item)->start); + return sysfs_emit(page, "%d\n", to_pci_epc_group(item)->start); } CONFIGFS_ATTR(pci_epc_, start); @@ -321,7 +320,7 @@ static ssize_t pci_epf_##_name##_show(struct config_item *item, char *page) \ struct pci_epf *epf = to_pci_epf_group(item)->epf; \ if (WARN_ON_ONCE(!epf->header)) \ return -EINVAL; \ - return sprintf(page, "0x%04x\n", epf->header->_name); \ + return sysfs_emit(page, "0x%04x\n", epf->header->_name); \ } #define PCI_EPF_HEADER_W_u32(_name) \ @@ -390,8 +389,8 @@ static ssize_t pci_epf_msi_interrupts_store(struct config_item *item, static ssize_t pci_epf_msi_interrupts_show(struct config_item *item, char *page) { - return sprintf(page, "%d\n", - to_pci_epf_group(item)->epf->msi_interrupts); + return sysfs_emit(page, "%d\n", + to_pci_epf_group(item)->epf->msi_interrupts); } static ssize_t pci_epf_msix_interrupts_store(struct config_item *item, @@ -412,8 +411,8 @@ static ssize_t pci_epf_msix_interrupts_store(struct config_item *item, static ssize_t pci_epf_msix_interrupts_show(struct config_item *item, char *page) { - return sprintf(page, "%d\n", - to_pci_epf_group(item)->epf->msix_interrupts); + return sysfs_emit(page, "%d\n", + to_pci_epf_group(item)->epf->msix_interrupts); } PCI_EPF_HEADER_R(vendorid) -- cgit From 229d0cfae5b21bfc42525cf43b0b4279243acc4e Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 1 Oct 2021 14:32:44 +0900 Subject: kconfig: remove 'const' from the return type of sym_escape_string_value() sym_escape_string_value() returns a malloc'ed memory, but as (const char *). So, it must be casted to (void *) when it is free'd. This is odd. The return type of sym_escape_string_value() should be (char *). I exploited that free(NULL) has no effect. Signed-off-by: Masahiro Yamada --- scripts/kconfig/conf.c | 15 +++++++-------- scripts/kconfig/confdata.c | 27 ++++++++++++++------------- scripts/kconfig/lkc_proto.h | 2 +- scripts/kconfig/symbol.c | 3 ++- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c index 5d84b44a2a2a..310fdd408793 100644 --- a/scripts/kconfig/conf.c +++ b/scripts/kconfig/conf.c @@ -647,17 +647,16 @@ static void check_conf(struct menu *menu) switch (input_mode) { case listnewconfig: if (sym->name) { - const char *str; + const char *val = sym_get_string_value(sym); + char *escaped = NULL; if (sym->type == S_STRING) { - str = sym_get_string_value(sym); - str = sym_escape_string_value(str); - printf("%s%s=%s\n", CONFIG_, sym->name, str); - free((void *)str); - } else { - str = sym_get_string_value(sym); - printf("%s%s=%s\n", CONFIG_, sym->name, str); + escaped = sym_escape_string_value(val); + val = escaped; } + + printf("%s%s=%s\n", CONFIG_, sym->name, val); + free(escaped); } break; case helpnewconfig: diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index cf72680cd769..9b2271eb43d6 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -728,21 +728,22 @@ static struct conf_printer header_printer_cb = static void conf_write_symbol(FILE *fp, struct symbol *sym, struct conf_printer *printer, void *printer_arg) { - const char *str; + const char *val; + char *escaped = NULL; - switch (sym->type) { - case S_UNKNOWN: - break; - case S_STRING: - str = sym_get_string_value(sym); - str = sym_escape_string_value(str); - printer->print_symbol(fp, sym, str, printer_arg); - free((void *)str); - break; - default: - str = sym_get_string_value(sym); - printer->print_symbol(fp, sym, str, printer_arg); + if (sym->type == S_UNKNOWN) + return; + + val = sym_get_string_value(sym); + + if (sym->type == S_STRING) { + escaped = sym_escape_string_value(val); + val = escaped; } + + printer->print_symbol(fp, sym, val, printer_arg); + + free(escaped); } static void diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h index a11626bdc421..e6955df49973 100644 --- a/scripts/kconfig/lkc_proto.h +++ b/scripts/kconfig/lkc_proto.h @@ -18,7 +18,7 @@ extern struct symbol * symbol_hash[SYMBOL_HASHSIZE]; struct symbol * sym_lookup(const char *name, int flags); struct symbol * sym_find(const char *name); -const char * sym_escape_string_value(const char *in); +char *sym_escape_string_value(const char *in); struct symbol ** sym_re_search(const char *pattern); const char * sym_type_name(enum symbol_type type); void sym_calc_value(struct symbol *sym); diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index 5844d636d38f..6bf8665a6a0f 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -871,7 +871,8 @@ struct symbol *sym_find(const char *name) return symbol; } -const char *sym_escape_string_value(const char *in) +/* The returned pointer must be freed on the caller side */ +char *sym_escape_string_value(const char *in) { const char *p; size_t reslen; -- cgit From 5637abaab994a933d7f00c95bc1456c7a58c83f4 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Thu, 26 Aug 2021 11:47:36 +0200 Subject: dmaengine: zynqmp_dma: simplify with dev_err_probe The clocks are provided by the ZynqMP firmware driver and are deferred until the firmware driver has probed. This leads to misleading error messages during probe of the zynqmp_dma driver. Use dev_err_probe for printing errors during probe to avoid error messages for -EPROBE_DEFER. Signed-off-by: Michael Tretter Link: https://lore.kernel.org/r/20210826094742.1302009-2-m.tretter@pengutronix.de Signed-off-by: Vinod Koul --- drivers/dma/xilinx/zynqmp_dma.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c index 97f02f8eb03a..1d077a85f32b 100644 --- a/drivers/dma/xilinx/zynqmp_dma.c +++ b/drivers/dma/xilinx/zynqmp_dma.c @@ -1061,16 +1061,14 @@ static int zynqmp_dma_probe(struct platform_device *pdev) p->dev = &pdev->dev; zdev->clk_main = devm_clk_get(&pdev->dev, "clk_main"); - if (IS_ERR(zdev->clk_main)) { - dev_err(&pdev->dev, "main clock not found.\n"); - return PTR_ERR(zdev->clk_main); - } + if (IS_ERR(zdev->clk_main)) + return dev_err_probe(&pdev->dev, PTR_ERR(zdev->clk_main), + "main clock not found.\n"); zdev->clk_apb = devm_clk_get(&pdev->dev, "clk_apb"); - if (IS_ERR(zdev->clk_apb)) { - dev_err(&pdev->dev, "apb clock not found.\n"); - return PTR_ERR(zdev->clk_apb); - } + if (IS_ERR(zdev->clk_apb)) + return dev_err_probe(&pdev->dev, PTR_ERR(zdev->clk_apb), + "apb clock not found.\n"); platform_set_drvdata(pdev, zdev); pm_runtime_set_autosuspend_delay(zdev->dev, ZDMA_PM_TIMEOUT); @@ -1085,7 +1083,7 @@ static int zynqmp_dma_probe(struct platform_device *pdev) ret = zynqmp_dma_chan_probe(zdev, pdev); if (ret) { - dev_err(&pdev->dev, "Probing channel failed\n"); + dev_err_probe(&pdev->dev, ret, "Probing channel failed\n"); goto err_disable_pm; } @@ -1097,7 +1095,7 @@ static int zynqmp_dma_probe(struct platform_device *pdev) ret = of_dma_controller_register(pdev->dev.of_node, of_zynqmp_dma_xlate, zdev); if (ret) { - dev_err(&pdev->dev, "Unable to register DMA to DT\n"); + dev_err_probe(&pdev->dev, ret, "Unable to register DMA to DT\n"); dma_async_device_unregister(&zdev->common); goto free_chan_resources; } -- cgit From 4c0f93eb80fbaafcb2cefa09ed1d6c5099dc1939 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Thu, 26 Aug 2021 11:47:37 +0200 Subject: dmaengine: zynqmp_dma: drop message on probe success There is no need to print a message that the ZynqMP DMA driver probed successfully, since it carries no additional information. Drop the message. Signed-off-by: Michael Tretter Link: https://lore.kernel.org/r/20210826094742.1302009-3-m.tretter@pengutronix.de Signed-off-by: Vinod Koul --- drivers/dma/xilinx/zynqmp_dma.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c index 1d077a85f32b..bdeae8a34123 100644 --- a/drivers/dma/xilinx/zynqmp_dma.c +++ b/drivers/dma/xilinx/zynqmp_dma.c @@ -1103,8 +1103,6 @@ static int zynqmp_dma_probe(struct platform_device *pdev) pm_runtime_mark_last_busy(zdev->dev); pm_runtime_put_sync_autosuspend(zdev->dev); - dev_info(&pdev->dev, "ZynqMP DMA driver Probe success\n"); - return 0; free_chan_resources: -- cgit From 7073b5a8bd6ea641b41568e2899b0977f79134e3 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Thu, 26 Aug 2021 11:47:38 +0200 Subject: dmaengine: zynqmp_dma: enable COMPILE_TEST The driver doesn't use anything architecture specific. Allow the compilation on other architectures as well. Signed-off-by: Michael Tretter Link: https://lore.kernel.org/r/20210826094742.1302009-4-m.tretter@pengutronix.de Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 80c2c03cb014..6bcdb4e6a0d1 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -717,7 +717,7 @@ config XILINX_DMA config XILINX_ZYNQMP_DMA tristate "Xilinx ZynqMP DMA Engine" - depends on (ARCH_ZYNQ || MICROBLAZE || ARM64) + depends on ARCH_ZYNQ || MICROBLAZE || ARM64 || COMPILE_TEST select DMA_ENGINE help Enable support for Xilinx ZynqMP DMA controller. -- cgit From 85997fdfd15916dddee2458b7382934b6c857f87 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Thu, 26 Aug 2021 11:47:39 +0200 Subject: dmaengine: zynqmp_dma: cleanup includes The driver includes a few headers that are not actually used, but are probably copy paste errors. Remove them. Signed-off-by: Michael Tretter Link: https://lore.kernel.org/r/20210826094742.1302009-5-m.tretter@pengutronix.de Signed-off-by: Vinod Koul --- drivers/dma/xilinx/zynqmp_dma.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c index bdeae8a34123..2a57d7c38d35 100644 --- a/drivers/dma/xilinx/zynqmp_dma.c +++ b/drivers/dma/xilinx/zynqmp_dma.c @@ -6,15 +6,12 @@ */ #include -#include -#include +#include #include #include #include #include -#include #include -#include #include #include #include -- cgit From 16ed0ef3e931f49b06d73afbe1fb41737bee86b6 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Thu, 26 Aug 2021 11:47:40 +0200 Subject: dmaengine: zynqmp_dma: cleanup after completing all descriptors The current implementation iterates the entire done list for each completed dma descriptor even if there are multiple completed descriptors. Avoid this by first moving all completed descriptors to the done list and afterwards iterating the done list and finishing the descriptors. Signed-off-by: Michael Tretter Link: https://lore.kernel.org/r/20210826094742.1302009-6-m.tretter@pengutronix.de Signed-off-by: Vinod Koul --- drivers/dma/xilinx/zynqmp_dma.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c index 2a57d7c38d35..aa1374c24498 100644 --- a/drivers/dma/xilinx/zynqmp_dma.c +++ b/drivers/dma/xilinx/zynqmp_dma.c @@ -758,10 +758,11 @@ static void zynqmp_dma_do_tasklet(struct tasklet_struct *t) while (count) { zynqmp_dma_complete_descriptor(chan); - zynqmp_dma_chan_desc_cleanup(chan); count--; } + zynqmp_dma_chan_desc_cleanup(chan); + if (chan->idle) zynqmp_dma_start_transfer(chan); -- cgit From 193a750df59580ddda6779290fa3898ba3216d3c Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Thu, 26 Aug 2021 11:47:41 +0200 Subject: dmaengine: zynqmp_dma: refine dma descriptor locking The descriptor lists are locked for the entire tasklet that completes the descriptors. This is not necessary, because the lock actually only protects the descriptor lists. Make the spin lock more fine-grained and only protect functions that actually operate on the descriptor lists. This decreases the time when the lock is held. Signed-off-by: Michael Tretter Link: https://lore.kernel.org/r/20210826094742.1302009-7-m.tretter@pengutronix.de Signed-off-by: Vinod Koul --- drivers/dma/xilinx/zynqmp_dma.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c index aa1374c24498..b4220cb88da6 100644 --- a/drivers/dma/xilinx/zynqmp_dma.c +++ b/drivers/dma/xilinx/zynqmp_dma.c @@ -600,6 +600,9 @@ static void zynqmp_dma_start_transfer(struct zynqmp_dma_chan *chan) static void zynqmp_dma_chan_desc_cleanup(struct zynqmp_dma_chan *chan) { struct zynqmp_dma_desc_sw *desc, *next; + unsigned long irqflags; + + spin_lock_irqsave(&chan->lock, irqflags); list_for_each_entry_safe(desc, next, &chan->done_list, node) { dma_async_tx_callback callback; @@ -616,6 +619,8 @@ static void zynqmp_dma_chan_desc_cleanup(struct zynqmp_dma_chan *chan) /* Run any dependencies, then free the descriptor */ zynqmp_dma_free_descriptor(chan, desc); } + + spin_unlock_irqrestore(&chan->lock, irqflags); } /** @@ -655,9 +660,13 @@ static void zynqmp_dma_issue_pending(struct dma_chan *dchan) */ static void zynqmp_dma_free_descriptors(struct zynqmp_dma_chan *chan) { + unsigned long irqflags; + + spin_lock_irqsave(&chan->lock, irqflags); zynqmp_dma_free_desc_list(chan, &chan->active_list); zynqmp_dma_free_desc_list(chan, &chan->pending_list); zynqmp_dma_free_desc_list(chan, &chan->done_list); + spin_unlock_irqrestore(&chan->lock, irqflags); } /** @@ -667,11 +676,8 @@ static void zynqmp_dma_free_descriptors(struct zynqmp_dma_chan *chan) static void zynqmp_dma_free_chan_resources(struct dma_chan *dchan) { struct zynqmp_dma_chan *chan = to_chan(dchan); - unsigned long irqflags; - spin_lock_irqsave(&chan->lock, irqflags); zynqmp_dma_free_descriptors(chan); - spin_unlock_irqrestore(&chan->lock, irqflags); dma_free_coherent(chan->dev, (2 * ZYNQMP_DMA_DESC_SIZE(chan) * ZYNQMP_DMA_NUM_DESCS), chan->desc_pool_v, chan->desc_pool_p); @@ -686,11 +692,16 @@ static void zynqmp_dma_free_chan_resources(struct dma_chan *dchan) */ static void zynqmp_dma_reset(struct zynqmp_dma_chan *chan) { + unsigned long irqflags; + writel(ZYNQMP_DMA_IDS_DEFAULT_MASK, chan->regs + ZYNQMP_DMA_IDS); + spin_lock_irqsave(&chan->lock, irqflags); zynqmp_dma_complete_descriptor(chan); + spin_unlock_irqrestore(&chan->lock, irqflags); zynqmp_dma_chan_desc_cleanup(chan); zynqmp_dma_free_descriptors(chan); + zynqmp_dma_init(chan); } @@ -746,28 +757,27 @@ static void zynqmp_dma_do_tasklet(struct tasklet_struct *t) u32 count; unsigned long irqflags; - spin_lock_irqsave(&chan->lock, irqflags); - if (chan->err) { zynqmp_dma_reset(chan); chan->err = false; - goto unlock; + return; } + spin_lock_irqsave(&chan->lock, irqflags); count = readl(chan->regs + ZYNQMP_DMA_IRQ_DST_ACCT); - while (count) { zynqmp_dma_complete_descriptor(chan); count--; } + spin_unlock_irqrestore(&chan->lock, irqflags); zynqmp_dma_chan_desc_cleanup(chan); - if (chan->idle) + if (chan->idle) { + spin_lock_irqsave(&chan->lock, irqflags); zynqmp_dma_start_transfer(chan); - -unlock: - spin_unlock_irqrestore(&chan->lock, irqflags); + spin_unlock_irqrestore(&chan->lock, irqflags); + } } /** @@ -779,12 +789,9 @@ unlock: static int zynqmp_dma_device_terminate_all(struct dma_chan *dchan) { struct zynqmp_dma_chan *chan = to_chan(dchan); - unsigned long irqflags; - spin_lock_irqsave(&chan->lock, irqflags); writel(ZYNQMP_DMA_IDS_DEFAULT_MASK, chan->regs + ZYNQMP_DMA_IDS); zynqmp_dma_free_descriptors(chan); - spin_unlock_irqrestore(&chan->lock, irqflags); return 0; } -- cgit From 9558cf4ad07e8913c14e83959212ae8fdf60cfea Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Thu, 26 Aug 2021 11:47:42 +0200 Subject: dmaengine: zynqmp_dma: fix lockdep warning in tasklet The tasklet that handles the completed dma transfers uses spin_unlock for unlocking a spin lock that was previously locked with spin_lock_irqsave. This caused the following lockdep warning about an inconsistent lock state: inconsistent {HARDIRQ-ON-W} -> {IN-HARDIRQ-W} usage. We must use spin_lock_irqsave, because it is possible to queue DMA transfers from an irq handler. Replace the spin_unlock and spin_lock by spin_unlock_irqrestore and spin_lock_irqsave. Signed-off-by: Michael Tretter Link: https://lore.kernel.org/r/20210826094742.1302009-8-m.tretter@pengutronix.de Signed-off-by: Vinod Koul --- drivers/dma/xilinx/zynqmp_dma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c index b4220cb88da6..54adac6391ef 100644 --- a/drivers/dma/xilinx/zynqmp_dma.c +++ b/drivers/dma/xilinx/zynqmp_dma.c @@ -611,9 +611,9 @@ static void zynqmp_dma_chan_desc_cleanup(struct zynqmp_dma_chan *chan) callback = desc->async_tx.callback; callback_param = desc->async_tx.callback_param; if (callback) { - spin_unlock(&chan->lock); + spin_unlock_irqrestore(&chan->lock, irqflags); callback(callback_param); - spin_lock(&chan->lock); + spin_lock_irqsave(&chan->lock, irqflags); } /* Run any dependencies, then free the descriptor */ -- cgit From ae8f13f0a6fdd7562e420b756daa9b807e05f775 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 29 Sep 2021 17:29:22 -0500 Subject: dmaengine: stm32-mdma: Use struct_size() helper in devm_kzalloc() Make use of the struct_size() helper instead of an open-coded version, in order to avoid any potential type mistakes or integer overflows that, in the worse scenario, could lead to heap overflows. Link: https://github.com/KSPP/linux/issues/160 Signed-off-by: Gustavo A. R. Silva Reviewed-by: Amelie Delaunay Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20210929222922.GA357509@embeddedor Signed-off-by: Vinod Koul --- drivers/dma/stm32-mdma.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c index 18cbd1e43c2e..d30a4a28d3bf 100644 --- a/drivers/dma/stm32-mdma.c +++ b/drivers/dma/stm32-mdma.c @@ -1566,7 +1566,8 @@ static int stm32_mdma_probe(struct platform_device *pdev) if (count < 0) count = 0; - dmadev = devm_kzalloc(&pdev->dev, sizeof(*dmadev) + sizeof(u32) * count, + dmadev = devm_kzalloc(&pdev->dev, + struct_size(dmadev, ahb_addr_masks, count), GFP_KERNEL); if (!dmadev) return -ENOMEM; -- cgit From 85f604af9c83a4656b1d07bec73298c3ba7d7c1e Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Wed, 29 Sep 2021 12:15:38 -0700 Subject: dmaengine: idxd: move out percpu_ref_exit() to ensure it's outside submission percpu_ref_tryget_live() is safe to call as long as ref is between init and exit according to the function comment. Move percpu_ref_exit() so it is called after the dma channel is no longer valid to ensure this holds true. Fixes: 93a40a6d7428 ("dmaengine: idxd: add percpu_ref to descriptor submission path") Suggested-by: Kevin Tian Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/163294293832.914350.10326422026738506152.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/device.c | 1 - drivers/dma/idxd/dma.c | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index 83a5ff2ecf2a..cbbfa17d8d11 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -427,7 +427,6 @@ void idxd_wq_quiesce(struct idxd_wq *wq) { percpu_ref_kill(&wq->wq_active); wait_for_completion(&wq->wq_dead); - percpu_ref_exit(&wq->wq_active); } /* Device control bits */ diff --git a/drivers/dma/idxd/dma.c b/drivers/dma/idxd/dma.c index e0f056c1d1f5..b90b085d18cf 100644 --- a/drivers/dma/idxd/dma.c +++ b/drivers/dma/idxd/dma.c @@ -311,6 +311,7 @@ static int idxd_dmaengine_drv_probe(struct idxd_dev *idxd_dev) err_dma: idxd_wq_quiesce(wq); + percpu_ref_exit(&wq->wq_active); err_ref: idxd_wq_free_resources(wq); err_res_alloc: @@ -329,6 +330,7 @@ static void idxd_dmaengine_drv_remove(struct idxd_dev *idxd_dev) idxd_wq_quiesce(wq); idxd_unregister_dma_channel(wq); __drv_disable_wq(wq); + percpu_ref_exit(&wq->wq_active); idxd_wq_free_resources(wq); wq->type = IDXD_WQT_NONE; mutex_unlock(&wq->wq_lock); -- cgit From 3109151c47343c80300177ec7704e0757064efdc Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 27 Sep 2021 14:02:40 +0100 Subject: rtc: mcp795: Add SPI ID table Currently autoloading for SPI devices does not use the DT ID table, it uses SPI modalises. Supporting OF modalises is going to be difficult if not impractical, an attempt was made but has been reverted, so ensure that module autoloading works for this driver by adding an id_table listing the SPI IDs for everything. Fixes: 96c8395e2166 ("spi: Revert modalias changes") Signed-off-by: Mark Brown Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210927130240.33693-1-broonie@kernel.org --- drivers/rtc/rtc-mcp795.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/rtc/rtc-mcp795.c b/drivers/rtc/rtc-mcp795.c index bad7792b6ca5..0d515b3df571 100644 --- a/drivers/rtc/rtc-mcp795.c +++ b/drivers/rtc/rtc-mcp795.c @@ -430,12 +430,19 @@ static const struct of_device_id mcp795_of_match[] = { MODULE_DEVICE_TABLE(of, mcp795_of_match); #endif +static const struct spi_device_id mcp795_spi_ids[] = { + { .name = "mcp795" }, + { } +}; +MODULE_DEVICE_TABLE(spi, mcp795_spi_ids); + static struct spi_driver mcp795_driver = { .driver = { .name = "rtc-mcp795", .of_match_table = of_match_ptr(mcp795_of_match), }, .probe = mcp795_probe, + .id_table = mcp795_spi_ids, }; module_spi_driver(mcp795_driver); -- cgit From f3606687b447c41d28a011c98373b62b1cd52345 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 28 Sep 2021 14:46:54 +0100 Subject: rtc: msc313: Fix unintentional sign extension issues with left shift of a u16 Shifting the u16 value returned by readw by 16 bits to the left will be promoted to a 32 bit signed int and then sign-extended to an unsigned long. If the top bit of the readw is set then the shifted value will be sign extended and the top 32 bits of the result will be set. Fixes: be7d9c9161b9 ("rtc: Add support for the MSTAR MSC313 RTC") Signed-off-by: Colin Ian King Reviewed-by: Romain Perier Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210928134654.991923-1-colin.king@canonical.com --- drivers/rtc/rtc-msc313.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-msc313.c b/drivers/rtc/rtc-msc313.c index 5f178d29cfd8..f3fde013c4b8 100644 --- a/drivers/rtc/rtc-msc313.c +++ b/drivers/rtc/rtc-msc313.c @@ -53,7 +53,7 @@ static int msc313_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) unsigned long seconds; seconds = readw(priv->rtc_base + REG_RTC_MATCH_VAL_L) - | (readw(priv->rtc_base + REG_RTC_MATCH_VAL_H) << 16); + | ((unsigned long)readw(priv->rtc_base + REG_RTC_MATCH_VAL_H) << 16); rtc_time64_to_tm(seconds, &alarm->time); @@ -122,7 +122,7 @@ static int msc313_rtc_read_time(struct device *dev, struct rtc_time *tm) udelay(1); seconds = readw(priv->rtc_base + REG_RTC_CNT_VAL_L) - | (readw(priv->rtc_base + REG_RTC_CNT_VAL_H) << 16); + | ((unsigned long)readw(priv->rtc_base + REG_RTC_CNT_VAL_H) << 16); rtc_time64_to_tm(seconds, tm); -- cgit From 7caadcfa8a7c6f8e754d982b99d959a222e7f863 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 25 Sep 2021 23:34:41 +0100 Subject: rtc: m41t80: return NULL rather than a plain 0 integer Function m41t80_sqw_register_clk returns a pointer to struct clk, so returning a plain 0 integer isn't good practice. Fix this by returning a NULL instead. Signed-off-by: Colin Ian King Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210925223441.182673-1-colin.king@canonical.com --- drivers/rtc/rtc-m41t80.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index f736f8c22e96..6d383b629d20 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -557,7 +557,7 @@ static struct clk *m41t80_sqw_register_clk(struct m41t80_data *m41t80) * registered automatically when being referenced. */ of_node_put(fixed_clock); - return 0; + return NULL; } /* First disable the clock */ -- cgit From 5c4c2c8e6fac26fa0b80c234d6e9f75d637193af Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 1 Oct 2021 21:20:49 -0700 Subject: Input: ariel-pwrbutton - add SPI device ID table Currently autoloading for SPI devices does not use the DT ID table, it uses SPI modalises. Supporting OF modalises is going to be difficult if not impractical, an attempt was made but has been reverted, so ensure that module autoloading works for this driver by adding a SPI device ID table. Fixes: 96c8395e2166 ("spi: Revert modalias changes") Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20210927134104.38648-1-broonie@kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/misc/ariel-pwrbutton.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/input/misc/ariel-pwrbutton.c b/drivers/input/misc/ariel-pwrbutton.c index 17bbaac8b80c..cdc80715b5fd 100644 --- a/drivers/input/misc/ariel-pwrbutton.c +++ b/drivers/input/misc/ariel-pwrbutton.c @@ -149,12 +149,19 @@ static const struct of_device_id ariel_pwrbutton_of_match[] = { }; MODULE_DEVICE_TABLE(of, ariel_pwrbutton_of_match); +static const struct spi_device_id ariel_pwrbutton_spi_ids[] = { + { .name = "wyse-ariel-ec-input" }, + { } +}; +MODULE_DEVICE_TABLE(spi, ariel_pwrbutton_spi_ids); + static struct spi_driver ariel_pwrbutton_driver = { .driver = { .name = "dell-wyse-ariel-ec-input", .of_match_table = ariel_pwrbutton_of_match, }, .probe = ariel_pwrbutton_probe, + .id_table = ariel_pwrbutton_spi_ids, }; module_spi_driver(ariel_pwrbutton_driver); -- cgit From b8228aea5a19d5111a7bf44f7de6749d1f5d487a Mon Sep 17 00:00:00 2001 From: Kewei Xu Date: Fri, 17 Sep 2021 18:14:10 +0800 Subject: i2c: mediatek: fixing the incorrect register offset The reason for the modification here is that the previous offset information is incorrect, OFFSET_DEBUGSTAT = 0xE4 is the correct value. Fixes: 25708278f810 ("i2c: mediatek: Add i2c support for MediaTek MT8183") Signed-off-by: Kewei Xu Reviewed-by: Chen-Yu Tsai Reviewed-by: Qii Wang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mt65xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c index 477480d1de6b..32518081b5a4 100644 --- a/drivers/i2c/busses/i2c-mt65xx.c +++ b/drivers/i2c/busses/i2c-mt65xx.c @@ -193,7 +193,7 @@ static const u16 mt_i2c_regs_v2[] = { [OFFSET_CLOCK_DIV] = 0x48, [OFFSET_SOFTRESET] = 0x50, [OFFSET_SCL_MIS_COMP_POINT] = 0x90, - [OFFSET_DEBUGSTAT] = 0xe0, + [OFFSET_DEBUGSTAT] = 0xe4, [OFFSET_DEBUGCTRL] = 0xe8, [OFFSET_FIFO_STAT] = 0xf4, [OFFSET_FIFO_THRESH] = 0xf8, -- cgit From 511899ec34b605af5f8577f0f53866a8a60939f6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 16 Sep 2021 19:05:17 +0200 Subject: i2c: pxa: drop unneeded MODULE_ALIAS The MODULE_DEVICE_TABLE already creates proper alias for platform driver. Having another MODULE_ALIAS causes the alias to be duplicated. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-pxa.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index a636ea0eb50a..690188a9ffff 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -1547,7 +1547,6 @@ static void __exit i2c_adap_pxa_exit(void) } MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:pxa2xx-i2c"); subsys_initcall(i2c_adap_pxa_init); module_exit(i2c_adap_pxa_exit); -- cgit From cf9ae42c435c4a434b7c3d248f010699d43d684e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 24 Sep 2021 15:35:49 +0200 Subject: i2c: exynos: describe drivers in KConfig Describe better which driver applies to which SoC, to make configuring kernel for Samsung SoC easier. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index e17790fe35a7..1df19ccc310b 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -615,7 +615,10 @@ config I2C_EXYNOS5 depends on ARCH_EXYNOS || COMPILE_TEST default y if ARCH_EXYNOS help - High-speed I2C controller on Exynos5 and newer Samsung SoCs. + High-speed I2C controller on Samsung Exynos5 and newer Samsung SoCs: + Exynos5250, Exynos5260, Exynos5410, Exynos542x, Exynos5800, + Exynos5433 and Exynos7. + Choose Y here only if you build for such Samsung SoC. config I2C_GPIO tristate "GPIO-based bitbanging I2C" -- cgit From d56baf6efaf14e2910610216c581ca71d6940012 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 22 Aug 2021 21:38:12 +0200 Subject: i2c: switch from 'pci_' to 'dma_' API The wrappers in include/linux/pci-dma-compat.h should go away. The patch has been generated with the coccinelle script below. It has been hand modified to use 'dma_set_mask_and_coherent()' instead of 'pci_set_dma_mask()/pci_set_consistent_dma_mask()' when applicable. This is less verbose. While at it a 'dev_err()' message has been slightly simplified. It has been compile tested. @@ @@ - PCI_DMA_BIDIRECTIONAL + DMA_BIDIRECTIONAL @@ @@ - PCI_DMA_TODEVICE + DMA_TO_DEVICE @@ @@ - PCI_DMA_FROMDEVICE + DMA_FROM_DEVICE @@ @@ - PCI_DMA_NONE + DMA_NONE @@ expression e1, e2, e3; @@ - pci_alloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3; @@ - pci_zalloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3, e4; @@ - pci_free_consistent(e1, e2, e3, e4) + dma_free_coherent(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_single(e1, e2, e3, e4) + dma_map_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_single(e1, e2, e3, e4) + dma_unmap_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4, e5; @@ - pci_map_page(e1, e2, e3, e4, e5) + dma_map_page(&e1->dev, e2, e3, e4, e5) @@ expression e1, e2, e3, e4; @@ - pci_unmap_page(e1, e2, e3, e4) + dma_unmap_page(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_sg(e1, e2, e3, e4) + dma_map_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_sg(e1, e2, e3, e4) + dma_unmap_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_cpu(e1, e2, e3, e4) + dma_sync_single_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_device(e1, e2, e3, e4) + dma_sync_single_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_cpu(e1, e2, e3, e4) + dma_sync_sg_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_device(e1, e2, e3, e4) + dma_sync_sg_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2; @@ - pci_dma_mapping_error(e1, e2) + dma_mapping_error(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_dma_mask(e1, e2) + dma_set_mask(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_consistent_dma_mask(e1, e2) + dma_set_coherent_mask(&e1->dev, e2) Signed-off-by: Christophe JAILLET Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-amd-mp2-pci.c | 4 ++-- drivers/i2c/busses/i2c-ismt.c | 12 +++++------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/i2c/busses/i2c-amd-mp2-pci.c b/drivers/i2c/busses/i2c-amd-mp2-pci.c index ce130a821ea5..adf0e8c1ec01 100644 --- a/drivers/i2c/busses/i2c-amd-mp2-pci.c +++ b/drivers/i2c/busses/i2c-amd-mp2-pci.c @@ -307,9 +307,9 @@ static int amd_mp2_pci_init(struct amd_mp2_dev *privdata, pci_set_master(pci_dev); - rc = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(64)); + rc = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(64)); if (rc) { - rc = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)); + rc = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32)); if (rc) goto err_dma_mask; } diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c index a6187cbec2c9..f4820fd3dc13 100644 --- a/drivers/i2c/busses/i2c-ismt.c +++ b/drivers/i2c/busses/i2c-ismt.c @@ -918,13 +918,11 @@ ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id) return -ENODEV; } - if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) || - (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0)) { - if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) || - (pci_set_consistent_dma_mask(pdev, - DMA_BIT_MASK(32)) != 0)) { - dev_err(&pdev->dev, "pci_set_dma_mask fail %p\n", - pdev); + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (err) { + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (err) { + dev_err(&pdev->dev, "dma_set_mask fail\n"); return -ENODEV; } } -- cgit From 72698a8789268cb11da21c018041b45233b82cbb Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 30 Sep 2021 19:11:01 -0700 Subject: openrisc: time: don't mark comment as kernel-doc Fix a kernel-doc warning by unmarking the comment as being in kernel-doc notation. Fixes this warning: arch/openrisc/kernel/time.c:137: warning: expecting prototype for Clocksource(). Prototype was for openrisc_timer_read() instead Fixes: b731fbbd246e ("OpenRISC: Timekeeping") Signed-off-by: Randy Dunlap Reported-by: kernel test robot Cc: Jonas Bonn Cc: Stefan Kristiansson Cc: Stafford Horne Cc: openrisc@lists.librecores.org Signed-off-by: Stafford Horne --- arch/openrisc/kernel/time.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/openrisc/kernel/time.c b/arch/openrisc/kernel/time.c index b82866061958..a6e69386f82a 100644 --- a/arch/openrisc/kernel/time.c +++ b/arch/openrisc/kernel/time.c @@ -127,7 +127,7 @@ irqreturn_t __irq_entry timer_interrupt(struct pt_regs *regs) return IRQ_HANDLED; } -/** +/* * Clocksource: Based on OpenRISC timer/counter * * This sets up the OpenRISC Tick Timer as a clock source. The tick timer -- cgit From ef5825e3cf0d0af657f5fb4dd86d750ed42fee0a Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 2 Sep 2021 11:14:47 +1000 Subject: NFSD: move filehandle format declarations out of "uapi". A small part of the declaration concerning filehandle format are currently in the "uapi" include directory: include/uapi/linux/nfsd/nfsfh.h There is a lot more to the filehandle format, including "enum fid_type" and "enum nfsd_fsid" which are not exported via "uapi". This small part of the filehandle definition is of minimal use outside of the kernel, and I can find no evidence that an other code is using it. Certainly nfs-utils and wireshark (The most likely candidates) do not use these declarations. So move it out of "uapi" by copying the content from include/uapi/linux/nfsd/nfsfh.h into fs/nfsd/nfsfh.h A few unnecessary "#include" directives are not copied, and neither is the #define of fh_auth, which is annotated as being for userspace only. The copyright claims in the uapi file are identical to those in the nfsd file, so there is no need to copy those. The "__u32" style integer types are only needed in "uapi". In kernel-only code we can use the more familiar "u32" style. Signed-off-by: NeilBrown Signed-off-by: J. Bruce Fields --- fs/nfsd/nfsfh.h | 97 ++++++++++++++++++++++++++++++++- fs/nfsd/vfs.c | 1 + include/uapi/linux/nfsd/nfsfh.h | 115 ---------------------------------------- 3 files changed, 97 insertions(+), 116 deletions(-) delete mode 100644 include/uapi/linux/nfsd/nfsfh.h diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h index 6106697adc04..ad47f16676a8 100644 --- a/fs/nfsd/nfsfh.h +++ b/fs/nfsd/nfsfh.h @@ -10,9 +10,104 @@ #include #include -#include #include #include +#include + + +/* + * This is the old "dentry style" Linux NFSv2 file handle. + * + * The xino and xdev fields are currently used to transport the + * ino/dev of the exported inode. + */ +struct nfs_fhbase_old { + u32 fb_dcookie; /* dentry cookie - always 0xfeebbaca */ + u32 fb_ino; /* our inode number */ + u32 fb_dirino; /* dir inode number, 0 for directories */ + u32 fb_dev; /* our device */ + u32 fb_xdev; + u32 fb_xino; + u32 fb_generation; +}; + +/* + * This is the new flexible, extensible style NFSv2/v3/v4 file handle. + * + * The file handle starts with a sequence of four-byte words. + * The first word contains a version number (1) and three descriptor bytes + * that tell how the remaining 3 variable length fields should be handled. + * These three bytes are auth_type, fsid_type and fileid_type. + * + * All four-byte values are in host-byte-order. + * + * The auth_type field is deprecated and must be set to 0. + * + * The fsid_type identifies how the filesystem (or export point) is + * encoded. + * Current values: + * 0 - 4 byte device id (ms-2-bytes major, ls-2-bytes minor), 4byte inode number + * NOTE: we cannot use the kdev_t device id value, because kdev_t.h + * says we mustn't. We must break it up and reassemble. + * 1 - 4 byte user specified identifier + * 2 - 4 byte major, 4 byte minor, 4 byte inode number - DEPRECATED + * 3 - 4 byte device id, encoded for user-space, 4 byte inode number + * 4 - 4 byte inode number and 4 byte uuid + * 5 - 8 byte uuid + * 6 - 16 byte uuid + * 7 - 8 byte inode number and 16 byte uuid + * + * The fileid_type identified how the file within the filesystem is encoded. + * The values for this field are filesystem specific, exccept that + * filesystems must not use the values '0' or '0xff'. 'See enum fid_type' + * in include/linux/exportfs.h for currently registered values. + */ +struct nfs_fhbase_new { + union { + struct { + u8 fb_version_aux; /* == 1, even => nfs_fhbase_old */ + u8 fb_auth_type_aux; + u8 fb_fsid_type_aux; + u8 fb_fileid_type_aux; + u32 fb_auth[1]; + /* u32 fb_fsid[0]; floating */ + /* u32 fb_fileid[0]; floating */ + }; + struct { + u8 fb_version; /* == 1, even => nfs_fhbase_old */ + u8 fb_auth_type; + u8 fb_fsid_type; + u8 fb_fileid_type; + u32 fb_auth_flex[]; /* flexible-array member */ + }; + }; +}; + +struct knfsd_fh { + unsigned int fh_size; /* significant for NFSv3. + * Points to the current size while building + * a new file handle + */ + union { + struct nfs_fhbase_old fh_old; + u32 fh_pad[NFS4_FHSIZE/4]; + struct nfs_fhbase_new fh_new; + } fh_base; +}; + +#define ofh_dcookie fh_base.fh_old.fb_dcookie +#define ofh_ino fh_base.fh_old.fb_ino +#define ofh_dirino fh_base.fh_old.fb_dirino +#define ofh_dev fh_base.fh_old.fb_dev +#define ofh_xdev fh_base.fh_old.fb_xdev +#define ofh_xino fh_base.fh_old.fb_xino +#define ofh_generation fh_base.fh_old.fb_generation + +#define fh_version fh_base.fh_new.fb_version +#define fh_fsid_type fh_base.fh_new.fb_fsid_type +#define fh_auth_type fh_base.fh_new.fb_auth_type +#define fh_fileid_type fh_base.fh_new.fb_fileid_type +#define fh_fsid fh_base.fh_new.fb_auth_flex static inline __u32 ino_t_to_u32(ino_t ino) { diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 738d564ca4ce..e9c406fd05b6 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -244,6 +244,7 @@ out_nfserr: * returned. Otherwise the covered directory is returned. * NOTE: this mountpoint crossing is not supported properly by all * clients and is explicitly disallowed for NFSv3 + * NeilBrown */ __be32 nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, diff --git a/include/uapi/linux/nfsd/nfsfh.h b/include/uapi/linux/nfsd/nfsfh.h deleted file mode 100644 index e29e8accc4f4..000000000000 --- a/include/uapi/linux/nfsd/nfsfh.h +++ /dev/null @@ -1,115 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * This file describes the layout of the file handles as passed - * over the wire. - * - * Copyright (C) 1995, 1996, 1997 Olaf Kirch - */ - -#ifndef _UAPI_LINUX_NFSD_FH_H -#define _UAPI_LINUX_NFSD_FH_H - -#include -#include -#include -#include -#include - -/* - * This is the old "dentry style" Linux NFSv2 file handle. - * - * The xino and xdev fields are currently used to transport the - * ino/dev of the exported inode. - */ -struct nfs_fhbase_old { - __u32 fb_dcookie; /* dentry cookie - always 0xfeebbaca */ - __u32 fb_ino; /* our inode number */ - __u32 fb_dirino; /* dir inode number, 0 for directories */ - __u32 fb_dev; /* our device */ - __u32 fb_xdev; - __u32 fb_xino; - __u32 fb_generation; -}; - -/* - * This is the new flexible, extensible style NFSv2/v3/v4 file handle. - * - * The file handle starts with a sequence of four-byte words. - * The first word contains a version number (1) and three descriptor bytes - * that tell how the remaining 3 variable length fields should be handled. - * These three bytes are auth_type, fsid_type and fileid_type. - * - * All four-byte values are in host-byte-order. - * - * The auth_type field is deprecated and must be set to 0. - * - * The fsid_type identifies how the filesystem (or export point) is - * encoded. - * Current values: - * 0 - 4 byte device id (ms-2-bytes major, ls-2-bytes minor), 4byte inode number - * NOTE: we cannot use the kdev_t device id value, because kdev_t.h - * says we mustn't. We must break it up and reassemble. - * 1 - 4 byte user specified identifier - * 2 - 4 byte major, 4 byte minor, 4 byte inode number - DEPRECATED - * 3 - 4 byte device id, encoded for user-space, 4 byte inode number - * 4 - 4 byte inode number and 4 byte uuid - * 5 - 8 byte uuid - * 6 - 16 byte uuid - * 7 - 8 byte inode number and 16 byte uuid - * - * The fileid_type identified how the file within the filesystem is encoded. - * The values for this field are filesystem specific, exccept that - * filesystems must not use the values '0' or '0xff'. 'See enum fid_type' - * in include/linux/exportfs.h for currently registered values. - */ -struct nfs_fhbase_new { - union { - struct { - __u8 fb_version_aux; /* == 1, even => nfs_fhbase_old */ - __u8 fb_auth_type_aux; - __u8 fb_fsid_type_aux; - __u8 fb_fileid_type_aux; - __u32 fb_auth[1]; - /* __u32 fb_fsid[0]; floating */ - /* __u32 fb_fileid[0]; floating */ - }; - struct { - __u8 fb_version; /* == 1, even => nfs_fhbase_old */ - __u8 fb_auth_type; - __u8 fb_fsid_type; - __u8 fb_fileid_type; - __u32 fb_auth_flex[]; /* flexible-array member */ - }; - }; -}; - -struct knfsd_fh { - unsigned int fh_size; /* significant for NFSv3. - * Points to the current size while building - * a new file handle - */ - union { - struct nfs_fhbase_old fh_old; - __u32 fh_pad[NFS4_FHSIZE/4]; - struct nfs_fhbase_new fh_new; - } fh_base; -}; - -#define ofh_dcookie fh_base.fh_old.fb_dcookie -#define ofh_ino fh_base.fh_old.fb_ino -#define ofh_dirino fh_base.fh_old.fb_dirino -#define ofh_dev fh_base.fh_old.fb_dev -#define ofh_xdev fh_base.fh_old.fb_xdev -#define ofh_xino fh_base.fh_old.fb_xino -#define ofh_generation fh_base.fh_old.fb_generation - -#define fh_version fh_base.fh_new.fb_version -#define fh_fsid_type fh_base.fh_new.fb_fsid_type -#define fh_auth_type fh_base.fh_new.fb_auth_type -#define fh_fileid_type fh_base.fh_new.fb_fileid_type -#define fh_fsid fh_base.fh_new.fb_auth_flex - -/* Do not use, provided for userspace compatiblity. */ -#define fh_auth fh_base.fh_new.fb_auth - -#endif /* _UAPI_LINUX_NFSD_FH_H */ -- cgit From c645a883df34ee10b884ec921e850def54b7f461 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 2 Sep 2021 11:15:29 +1000 Subject: NFSD: drop support for ancient filehandles Filehandles not in the "new" or "version 1" format have not been handed out for new mounts since Linux 2.4 which was released 20 years ago. I think it is safe to say that no such file handles are still in use, and that we can drop support for them. Signed-off-by: NeilBrown Signed-off-by: J. Bruce Fields --- fs/nfsd/nfsfh.c | 160 ++++++++++++++++++-------------------------------------- fs/nfsd/nfsfh.h | 34 ++---------- 2 files changed, 54 insertions(+), 140 deletions(-) diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index c475d2271f9c..149f9bbc48a4 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -154,11 +154,12 @@ static inline __be32 check_pseudo_root(struct svc_rqst *rqstp, static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp) { struct knfsd_fh *fh = &fhp->fh_handle; - struct fid *fid = NULL, sfid; + struct fid *fid = NULL; struct svc_export *exp; struct dentry *dentry; int fileid_type; int data_left = fh->fh_size/4; + int len; __be32 error; error = nfserr_stale; @@ -167,48 +168,35 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp) if (rqstp->rq_vers == 4 && fh->fh_size == 0) return nfserr_nofilehandle; - if (fh->fh_version == 1) { - int len; - - if (--data_left < 0) - return error; - if (fh->fh_auth_type != 0) - return error; - len = key_len(fh->fh_fsid_type) / 4; - if (len == 0) - return error; - if (fh->fh_fsid_type == FSID_MAJOR_MINOR) { - /* deprecated, convert to type 3 */ - len = key_len(FSID_ENCODE_DEV)/4; - fh->fh_fsid_type = FSID_ENCODE_DEV; - /* - * struct knfsd_fh uses host-endian fields, which are - * sometimes used to hold net-endian values. This - * confuses sparse, so we must use __force here to - * keep it from complaining. - */ - fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl((__force __be32)fh->fh_fsid[0]), - ntohl((__force __be32)fh->fh_fsid[1]))); - fh->fh_fsid[1] = fh->fh_fsid[2]; - } - data_left -= len; - if (data_left < 0) - return error; - exp = rqst_exp_find(rqstp, fh->fh_fsid_type, fh->fh_fsid); - fid = (struct fid *)(fh->fh_fsid + len); - } else { - __u32 tfh[2]; - dev_t xdev; - ino_t xino; - - if (fh->fh_size != NFS_FHSIZE) - return error; - /* assume old filehandle format */ - xdev = old_decode_dev(fh->ofh_xdev); - xino = u32_to_ino_t(fh->ofh_xino); - mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL); - exp = rqst_exp_find(rqstp, FSID_DEV, tfh); + if (fh->fh_version != 1) + return error; + + if (--data_left < 0) + return error; + if (fh->fh_auth_type != 0) + return error; + len = key_len(fh->fh_fsid_type) / 4; + if (len == 0) + return error; + if (fh->fh_fsid_type == FSID_MAJOR_MINOR) { + /* deprecated, convert to type 3 */ + len = key_len(FSID_ENCODE_DEV)/4; + fh->fh_fsid_type = FSID_ENCODE_DEV; + /* + * struct knfsd_fh uses host-endian fields, which are + * sometimes used to hold net-endian values. This + * confuses sparse, so we must use __force here to + * keep it from complaining. + */ + fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl((__force __be32)fh->fh_fsid[0]), + ntohl((__force __be32)fh->fh_fsid[1]))); + fh->fh_fsid[1] = fh->fh_fsid[2]; } + data_left -= len; + if (data_left < 0) + return error; + exp = rqst_exp_find(rqstp, fh->fh_fsid_type, fh->fh_fsid); + fid = (struct fid *)(fh->fh_fsid + len); error = nfserr_stale; if (IS_ERR(exp)) { @@ -253,18 +241,7 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp) if (rqstp->rq_vers > 2) error = nfserr_badhandle; - if (fh->fh_version != 1) { - sfid.i32.ino = fh->ofh_ino; - sfid.i32.gen = fh->ofh_generation; - sfid.i32.parent_ino = fh->ofh_dirino; - fid = &sfid; - data_left = 3; - if (fh->ofh_dirino == 0) - fileid_type = FILEID_INO32_GEN; - else - fileid_type = FILEID_INO32_GEN_PARENT; - } else - fileid_type = fh->fh_fileid_type; + fileid_type = fh->fh_fileid_type; if (fileid_type == FILEID_ROOT) dentry = dget(exp->ex_path.dentry); @@ -452,20 +429,6 @@ static void _fh_update(struct svc_fh *fhp, struct svc_export *exp, } } -/* - * for composing old style file handles - */ -static inline void _fh_update_old(struct dentry *dentry, - struct svc_export *exp, - struct knfsd_fh *fh) -{ - fh->ofh_ino = ino_t_to_u32(d_inode(dentry)->i_ino); - fh->ofh_generation = d_inode(dentry)->i_generation; - if (d_is_dir(dentry) || - (exp->ex_flags & NFSEXP_NOSUBTREECHECK)) - fh->ofh_dirino = 0; -} - static bool is_root_export(struct svc_export *exp) { return exp->ex_path.dentry == exp->ex_path.dentry->d_sb->s_root; @@ -562,9 +525,6 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, /* ref_fh is a reference file handle. * if it is non-null and for the same filesystem, then we should compose * a filehandle which is of the same version, where possible. - * Currently, that means that if ref_fh->fh_handle.fh_version == 0xca - * Then create a 32byte filehandle using nfs_fhbase_old - * */ struct inode * inode = d_inode(dentry); @@ -600,35 +560,21 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, fhp->fh_dentry = dget(dentry); /* our internal copy */ fhp->fh_export = exp_get(exp); - if (fhp->fh_handle.fh_version == 0xca) { - /* old style filehandle please */ - memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE); - fhp->fh_handle.fh_size = NFS_FHSIZE; - fhp->fh_handle.ofh_dcookie = 0xfeebbaca; - fhp->fh_handle.ofh_dev = old_encode_dev(ex_dev); - fhp->fh_handle.ofh_xdev = fhp->fh_handle.ofh_dev; - fhp->fh_handle.ofh_xino = - ino_t_to_u32(d_inode(exp->ex_path.dentry)->i_ino); - fhp->fh_handle.ofh_dirino = ino_t_to_u32(parent_ino(dentry)); - if (inode) - _fh_update_old(dentry, exp, &fhp->fh_handle); - } else { - fhp->fh_handle.fh_size = - key_len(fhp->fh_handle.fh_fsid_type) + 4; - fhp->fh_handle.fh_auth_type = 0; - - mk_fsid(fhp->fh_handle.fh_fsid_type, - fhp->fh_handle.fh_fsid, - ex_dev, - d_inode(exp->ex_path.dentry)->i_ino, - exp->ex_fsid, exp->ex_uuid); - - if (inode) - _fh_update(fhp, exp, dentry); - if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID) { - fh_put(fhp); - return nfserr_opnotsupp; - } + fhp->fh_handle.fh_size = + key_len(fhp->fh_handle.fh_fsid_type) + 4; + fhp->fh_handle.fh_auth_type = 0; + + mk_fsid(fhp->fh_handle.fh_fsid_type, + fhp->fh_handle.fh_fsid, + ex_dev, + d_inode(exp->ex_path.dentry)->i_ino, + exp->ex_fsid, exp->ex_uuid); + + if (inode) + _fh_update(fhp, exp, dentry); + if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID) { + fh_put(fhp); + return nfserr_opnotsupp; } return 0; @@ -649,16 +595,12 @@ fh_update(struct svc_fh *fhp) dentry = fhp->fh_dentry; if (d_really_is_negative(dentry)) goto out_negative; - if (fhp->fh_handle.fh_version != 1) { - _fh_update_old(dentry, fhp->fh_export, &fhp->fh_handle); - } else { - if (fhp->fh_handle.fh_fileid_type != FILEID_ROOT) - return 0; + if (fhp->fh_handle.fh_fileid_type != FILEID_ROOT) + return 0; - _fh_update(fhp, fhp->fh_export, dentry); - if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID) - return nfserr_opnotsupp; - } + _fh_update(fhp, fhp->fh_export, dentry); + if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID) + return nfserr_opnotsupp; return 0; out_bad: printk(KERN_ERR "fh_update: fh not verified!\n"); diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h index ad47f16676a8..8b5587f274a7 100644 --- a/fs/nfsd/nfsfh.h +++ b/fs/nfsd/nfsfh.h @@ -14,26 +14,7 @@ #include #include - -/* - * This is the old "dentry style" Linux NFSv2 file handle. - * - * The xino and xdev fields are currently used to transport the - * ino/dev of the exported inode. - */ -struct nfs_fhbase_old { - u32 fb_dcookie; /* dentry cookie - always 0xfeebbaca */ - u32 fb_ino; /* our inode number */ - u32 fb_dirino; /* dir inode number, 0 for directories */ - u32 fb_dev; /* our device */ - u32 fb_xdev; - u32 fb_xino; - u32 fb_generation; -}; - /* - * This is the new flexible, extensible style NFSv2/v3/v4 file handle. - * * The file handle starts with a sequence of four-byte words. * The first word contains a version number (1) and three descriptor bytes * that tell how the remaining 3 variable length fields should be handled. @@ -57,7 +38,7 @@ struct nfs_fhbase_old { * 6 - 16 byte uuid * 7 - 8 byte inode number and 16 byte uuid * - * The fileid_type identified how the file within the filesystem is encoded. + * The fileid_type identifies how the file within the filesystem is encoded. * The values for this field are filesystem specific, exccept that * filesystems must not use the values '0' or '0xff'. 'See enum fid_type' * in include/linux/exportfs.h for currently registered values. @@ -65,7 +46,7 @@ struct nfs_fhbase_old { struct nfs_fhbase_new { union { struct { - u8 fb_version_aux; /* == 1, even => nfs_fhbase_old */ + u8 fb_version_aux; /* == 1 */ u8 fb_auth_type_aux; u8 fb_fsid_type_aux; u8 fb_fileid_type_aux; @@ -74,7 +55,7 @@ struct nfs_fhbase_new { /* u32 fb_fileid[0]; floating */ }; struct { - u8 fb_version; /* == 1, even => nfs_fhbase_old */ + u8 fb_version; /* == 1 */ u8 fb_auth_type; u8 fb_fsid_type; u8 fb_fileid_type; @@ -89,20 +70,11 @@ struct knfsd_fh { * a new file handle */ union { - struct nfs_fhbase_old fh_old; u32 fh_pad[NFS4_FHSIZE/4]; struct nfs_fhbase_new fh_new; } fh_base; }; -#define ofh_dcookie fh_base.fh_old.fb_dcookie -#define ofh_ino fh_base.fh_old.fb_ino -#define ofh_dirino fh_base.fh_old.fb_dirino -#define ofh_dev fh_base.fh_old.fb_dev -#define ofh_xdev fh_base.fh_old.fb_xdev -#define ofh_xino fh_base.fh_old.fb_xino -#define ofh_generation fh_base.fh_old.fb_generation - #define fh_version fh_base.fh_new.fb_version #define fh_fsid_type fh_base.fh_new.fb_fsid_type #define fh_auth_type fh_base.fh_new.fb_auth_type -- cgit From d8b26071e65e80a348602b939e333242f989221b Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 2 Sep 2021 11:16:32 +1000 Subject: NFSD: simplify struct nfsfh Most of the fields in 'struct knfsd_fh' are 2 levels deep (a union and a struct) and are accessed using macros like: #define fh_FOO fh_base.fh_new.fb_FOO This patch makes the union and struct anonymous, so that "fh_FOO" can be a name directly within 'struct knfsd_fh' and the #defines aren't needed. The file handle as a whole is sometimes accessed as "fh_base" or "fh_base.fh_pad", neither of which are particularly helpful names. As the struct holding the filehandle is now anonymous, we cannot use the name of that, so we union it with 'fh_raw' and use that where the raw filehandle is needed. fh_raw also ensure the structure is large enough for the largest possible filehandle. fh_raw is a 'char' array, removing any need to cast it for memcpy etc. SVCFH_fmt() is simplified using the "%ph" printk format. This changes the appearance of filehandles in dprintk() debugging, making them a little more precise. Reviewed-by: Christoph Hellwig Signed-off-by: NeilBrown Signed-off-by: J. Bruce Fields --- fs/nfsd/flexfilelayout.c | 2 +- fs/nfsd/lockd.c | 2 +- fs/nfsd/nfs3xdr.c | 4 ++-- fs/nfsd/nfs4callback.c | 2 +- fs/nfsd/nfs4proc.c | 4 ++-- fs/nfsd/nfs4state.c | 4 ++-- fs/nfsd/nfs4xdr.c | 4 ++-- fs/nfsd/nfsctl.c | 6 +++--- fs/nfsd/nfsfh.c | 13 ++++--------- fs/nfsd/nfsfh.h | 50 +++++++++++++++--------------------------------- fs/nfsd/nfsxdr.c | 4 ++-- 11 files changed, 35 insertions(+), 60 deletions(-) diff --git a/fs/nfsd/flexfilelayout.c b/fs/nfsd/flexfilelayout.c index db7ef07ae50c..2e2f1d5e9f62 100644 --- a/fs/nfsd/flexfilelayout.c +++ b/fs/nfsd/flexfilelayout.c @@ -61,7 +61,7 @@ nfsd4_ff_proc_layoutget(struct inode *inode, const struct svc_fh *fhp, goto out_error; fl->fh.size = fhp->fh_handle.fh_size; - memcpy(fl->fh.data, &fhp->fh_handle.fh_base, fl->fh.size); + memcpy(fl->fh.data, &fhp->fh_handle.fh_raw, fl->fh.size); /* Give whole file layout segments */ seg->offset = 0; diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c index 606fa155c28a..46a7f9b813e5 100644 --- a/fs/nfsd/lockd.c +++ b/fs/nfsd/lockd.c @@ -35,7 +35,7 @@ nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp, /* must initialize before using! but maxsize doesn't matter */ fh_init(&fh,0); fh.fh_handle.fh_size = f->size; - memcpy((char*)&fh.fh_handle.fh_base, f->data, f->size); + memcpy(&fh.fh_handle.fh_raw, f->data, f->size); fh.fh_export = NULL; access = (mode == O_WRONLY) ? NFSD_MAY_WRITE : NFSD_MAY_READ; diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 0a5ebc52e6a9..3d37923afb06 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -92,7 +92,7 @@ svcxdr_decode_nfs_fh3(struct xdr_stream *xdr, struct svc_fh *fhp) return false; fh_init(fhp, NFS3_FHSIZE); fhp->fh_handle.fh_size = size; - memcpy(&fhp->fh_handle.fh_base, p, size); + memcpy(&fhp->fh_handle.fh_raw, p, size); return true; } @@ -131,7 +131,7 @@ svcxdr_encode_nfs_fh3(struct xdr_stream *xdr, const struct svc_fh *fhp) *p++ = cpu_to_be32(size); if (size) p[XDR_QUADLEN(size) - 1] = 0; - memcpy(p, &fhp->fh_handle.fh_base, size); + memcpy(p, &fhp->fh_handle.fh_raw, size); return true; } diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 0f8b10f363e7..11f8715d92d6 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -121,7 +121,7 @@ static void encode_nfs_fh4(struct xdr_stream *xdr, const struct knfsd_fh *fh) BUG_ON(length > NFS4_FHSIZE); p = xdr_reserve_space(xdr, 4 + length); - xdr_encode_opaque(p, &fh->fh_base, length); + xdr_encode_opaque(p, &fh->fh_raw, length); } /* diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 486c5dba4b65..3f7e59ec4e32 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -519,7 +519,7 @@ nfsd4_putfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, fh_put(&cstate->current_fh); cstate->current_fh.fh_handle.fh_size = putfh->pf_fhlen; - memcpy(&cstate->current_fh.fh_handle.fh_base, putfh->pf_fhval, + memcpy(&cstate->current_fh.fh_handle.fh_raw, putfh->pf_fhval, putfh->pf_fhlen); ret = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_BYPASS_GSS); #ifdef CONFIG_NFSD_V4_2_INTER_SSC @@ -1383,7 +1383,7 @@ nfsd4_setup_inter_ssc(struct svc_rqst *rqstp, s_fh = &cstate->save_fh; copy->c_fh.size = s_fh->fh_handle.fh_size; - memcpy(copy->c_fh.data, &s_fh->fh_handle.fh_base, copy->c_fh.size); + memcpy(copy->c_fh.data, &s_fh->fh_handle.fh_raw, copy->c_fh.size); copy->stateid.seqid = cpu_to_be32(s_stid->si_generation); memcpy(copy->stateid.other, (void *)&s_stid->si_opaque, sizeof(stateid_opaque_t)); diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 42356416f0a0..88c0a5cd7b75 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1010,7 +1010,7 @@ static int delegation_blocked(struct knfsd_fh *fh) } spin_unlock(&blocked_delegations_lock); } - hash = jhash(&fh->fh_base, fh->fh_size, 0); + hash = jhash(&fh->fh_raw, fh->fh_size, 0); if (test_bit(hash&255, bd->set[0]) && test_bit((hash>>8)&255, bd->set[0]) && test_bit((hash>>16)&255, bd->set[0])) @@ -1029,7 +1029,7 @@ static void block_delegations(struct knfsd_fh *fh) u32 hash; struct bloom_pair *bd = &blocked_delegations; - hash = jhash(&fh->fh_base, fh->fh_size, 0); + hash = jhash(&fh->fh_raw, fh->fh_size, 0); spin_lock(&blocked_delegations_lock); __set_bit(hash&255, bd->set[bd->new]); diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 7abeccb975b2..a54b2845473b 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3110,7 +3110,7 @@ out_acl: p = xdr_reserve_space(xdr, fhp->fh_handle.fh_size + 4); if (!p) goto out_resource; - p = xdr_encode_opaque(p, &fhp->fh_handle.fh_base, + p = xdr_encode_opaque(p, &fhp->fh_handle.fh_raw, fhp->fh_handle.fh_size); } if (bmval0 & FATTR4_WORD0_FILEID) { @@ -3667,7 +3667,7 @@ nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh p = xdr_reserve_space(xdr, len + 4); if (!p) return nfserr_resource; - p = xdr_encode_opaque(p, &fhp->fh_handle.fh_base, len); + p = xdr_encode_opaque(p, &fhp->fh_handle.fh_raw, len); return 0; } diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index c2c3d9077dc5..5e48bc48942e 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -395,12 +395,12 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size) auth_domain_put(dom); if (len) return len; - + mesg = buf; len = SIMPLE_TRANSACTION_LIMIT; - qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size); + qword_addhex(&mesg, &len, fh.fh_raw, fh.fh_size); mesg[-1] = '\n'; - return mesg - buf; + return mesg - buf; } /* diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 149f9bbc48a4..f3779fa72c89 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -640,16 +640,11 @@ fh_put(struct svc_fh *fhp) char * SVCFH_fmt(struct svc_fh *fhp) { struct knfsd_fh *fh = &fhp->fh_handle; + static char buf[2+1+1+64*3+1]; - static char buf[80]; - sprintf(buf, "%d: %08x %08x %08x %08x %08x %08x", - fh->fh_size, - fh->fh_base.fh_pad[0], - fh->fh_base.fh_pad[1], - fh->fh_base.fh_pad[2], - fh->fh_base.fh_pad[3], - fh->fh_base.fh_pad[4], - fh->fh_base.fh_pad[5]); + if (fh->fh_size < 0 || fh->fh_size> 64) + return "bad-fh"; + sprintf(buf, "%d: %*ph", fh->fh_size, fh->fh_size, fh->fh_raw); return buf; } diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h index 8b5587f274a7..d11e4b6870d6 100644 --- a/fs/nfsd/nfsfh.h +++ b/fs/nfsd/nfsfh.h @@ -43,44 +43,24 @@ * filesystems must not use the values '0' or '0xff'. 'See enum fid_type' * in include/linux/exportfs.h for currently registered values. */ -struct nfs_fhbase_new { - union { - struct { - u8 fb_version_aux; /* == 1 */ - u8 fb_auth_type_aux; - u8 fb_fsid_type_aux; - u8 fb_fileid_type_aux; - u32 fb_auth[1]; - /* u32 fb_fsid[0]; floating */ - /* u32 fb_fileid[0]; floating */ - }; - struct { - u8 fb_version; /* == 1 */ - u8 fb_auth_type; - u8 fb_fsid_type; - u8 fb_fileid_type; - u32 fb_auth_flex[]; /* flexible-array member */ - }; - }; -}; struct knfsd_fh { - unsigned int fh_size; /* significant for NFSv3. - * Points to the current size while building - * a new file handle + unsigned int fh_size; /* + * Points to the current size while + * building a new file handle. */ union { - u32 fh_pad[NFS4_FHSIZE/4]; - struct nfs_fhbase_new fh_new; - } fh_base; + char fh_raw[NFS4_FHSIZE]; + struct { + u8 fh_version; /* == 1 */ + u8 fh_auth_type; /* deprecated */ + u8 fh_fsid_type; + u8 fh_fileid_type; + u32 fh_fsid[]; /* flexible-array member */ + }; + }; }; -#define fh_version fh_base.fh_new.fb_version -#define fh_fsid_type fh_base.fh_new.fb_fsid_type -#define fh_auth_type fh_base.fh_new.fb_auth_type -#define fh_fileid_type fh_base.fh_new.fb_fileid_type -#define fh_fsid fh_base.fh_new.fb_auth_flex - static inline __u32 ino_t_to_u32(ino_t ino) { return (__u32) ino; @@ -255,7 +235,7 @@ static inline void fh_copy_shallow(struct knfsd_fh *dst, struct knfsd_fh *src) { dst->fh_size = src->fh_size; - memcpy(&dst->fh_base, &src->fh_base, src->fh_size); + memcpy(&dst->fh_raw, &src->fh_raw, src->fh_size); } static __inline__ struct svc_fh * @@ -270,7 +250,7 @@ static inline bool fh_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2) { if (fh1->fh_size != fh2->fh_size) return false; - if (memcmp(fh1->fh_base.fh_pad, fh2->fh_base.fh_pad, fh1->fh_size) != 0) + if (memcmp(fh1->fh_raw, fh2->fh_raw, fh1->fh_size) != 0) return false; return true; } @@ -294,7 +274,7 @@ static inline bool fh_fsid_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2) */ static inline u32 knfsd_fh_hash(const struct knfsd_fh *fh) { - return ~crc32_le(0xFFFFFFFF, (unsigned char *)&fh->fh_base, fh->fh_size); + return ~crc32_le(0xFFFFFFFF, fh->fh_raw, fh->fh_size); } #else static inline u32 knfsd_fh_hash(const struct knfsd_fh *fh) diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index a06c05fe3b42..082449c7d0db 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c @@ -64,7 +64,7 @@ svcxdr_decode_fhandle(struct xdr_stream *xdr, struct svc_fh *fhp) if (!p) return false; fh_init(fhp, NFS_FHSIZE); - memcpy(&fhp->fh_handle.fh_base, p, NFS_FHSIZE); + memcpy(&fhp->fh_handle.fh_raw, p, NFS_FHSIZE); fhp->fh_handle.fh_size = NFS_FHSIZE; return true; @@ -78,7 +78,7 @@ svcxdr_encode_fhandle(struct xdr_stream *xdr, const struct svc_fh *fhp) p = xdr_reserve_space(xdr, NFS_FHSIZE); if (!p) return false; - memcpy(p, &fhp->fh_handle.fh_base, NFS_FHSIZE); + memcpy(p, &fhp->fh_handle.fh_raw, NFS_FHSIZE); return true; } -- cgit From 8e70bf27fd20cc17e87150327a640e546bfbee64 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 25 Sep 2021 23:58:41 +0100 Subject: NFSD: Initialize pointer ni with NULL and not plain integer 0 Pointer ni is being initialized with plain integer zero. Fix this by initializing with NULL. Signed-off-by: Colin Ian King Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4proc.c | 2 +- fs/nfsd/nfs4state.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 3f7e59ec4e32..3dc40c1d32bc 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1178,7 +1178,7 @@ extern void nfs_sb_deactive(struct super_block *sb); static __be32 nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr, struct nfsd4_ssc_umount_item **retwork, struct vfsmount **ss_mnt) { - struct nfsd4_ssc_umount_item *ni = 0; + struct nfsd4_ssc_umount_item *ni = NULL; struct nfsd4_ssc_umount_item *work = NULL; struct nfsd4_ssc_umount_item *tmp; DEFINE_WAIT(wait); diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 88c0a5cd7b75..e49a38cd585f 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -5531,7 +5531,7 @@ static void nfsd4_ssc_shutdown_umount(struct nfsd_net *nn) static void nfsd4_ssc_expire_umount(struct nfsd_net *nn) { bool do_wakeup = false; - struct nfsd4_ssc_umount_item *ni = 0; + struct nfsd4_ssc_umount_item *ni = NULL; struct nfsd4_ssc_umount_item *tmp; spin_lock(&nn->nfsd_ssc_lock); -- cgit From f49b68ddc9d7dddf1530312108a648dd815a2f30 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 30 Sep 2021 17:06:15 -0400 Subject: SUNRPC: xdr_stream_subsegment() must handle non-zero page_bases xdr_stream_subsegment() was introduced in commit c1346a1216ab ("NFSD: Replace the internals of the READ_BUF() macro"). There are two call sites for xdr_stream_subsegment(). One is nfsd4_decode_write(), and the other is nfsd4_decode_setxattr(). Currently neither of these call sites calls this API when xdr_buf::page_base is a non-zero value. However, I'm about to add a case where page_base will sometimes not be zero when nfsd4_decode_write() invokes this API. Replace the logic in xdr_stream_subsegment() that advances to the next data item in the xdr_stream with something more generic in order to handle this new use case. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- net/sunrpc/xdr.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index ca10ba2626f2..df194cc07035 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -1633,7 +1633,7 @@ EXPORT_SYMBOL_GPL(xdr_buf_subsegment); * Sets up @subbuf to represent a portion of @xdr. The portion * starts at the current offset in @xdr, and extends for a length * of @nbytes. If this is successful, @xdr is advanced to the next - * position following that portion. + * XDR data item following that portion. * * Return values: * %true: @subbuf has been initialized, and @xdr has been advanced. @@ -1642,29 +1642,31 @@ EXPORT_SYMBOL_GPL(xdr_buf_subsegment); bool xdr_stream_subsegment(struct xdr_stream *xdr, struct xdr_buf *subbuf, unsigned int nbytes) { - unsigned int remaining, offset, len; + unsigned int start = xdr_stream_pos(xdr); + unsigned int remaining, len; - if (xdr_buf_subsegment(xdr->buf, subbuf, xdr_stream_pos(xdr), nbytes)) + /* Extract @subbuf and bounds-check the fn arguments */ + if (xdr_buf_subsegment(xdr->buf, subbuf, start, nbytes)) return false; - if (subbuf->head[0].iov_len) - if (!__xdr_inline_decode(xdr, subbuf->head[0].iov_len)) - return false; - - remaining = subbuf->page_len; - offset = subbuf->page_base; - while (remaining) { - len = min_t(unsigned int, remaining, PAGE_SIZE) - offset; - + /* Advance @xdr by @nbytes */ + for (remaining = nbytes; remaining;) { if (xdr->p == xdr->end && !xdr_set_next_buffer(xdr)) return false; - if (!__xdr_inline_decode(xdr, len)) - return false; + len = (char *)xdr->end - (char *)xdr->p; + if (remaining <= len) { + xdr->p = (__be32 *)((char *)xdr->p + + (remaining + xdr_pad_size(nbytes))); + break; + } + + xdr->p = (__be32 *)((char *)xdr->p + len); + xdr->end = xdr->p; remaining -= len; - offset = 0; } + xdr_stream_set_pos(xdr, start + nbytes); return true; } EXPORT_SYMBOL_GPL(xdr_stream_subsegment); -- cgit From dae9a6cab8009e526570e7477ce858dcdfeb256e Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 30 Sep 2021 17:06:21 -0400 Subject: NFSD: Have legacy NFSD WRITE decoders use xdr_stream_subsegment() Refactor. Now that the NFSv2 and NFSv3 XDR decoders have been converted to use xdr_streams, the WRITE decoder functions can use xdr_stream_subsegment() to extract the WRITE payload into its own xdr_buf, just as the NFSv4 WRITE XDR decoder currently does. That makes it possible to pass the first kvec, pages array + length, page_base, and total payload length via a single function parameter. The payload's page_base is not yet assigned or used, but will be in subsequent patches. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs3proc.c | 3 +-- fs/nfsd/nfs3xdr.c | 12 ++---------- fs/nfsd/nfs4proc.c | 3 +-- fs/nfsd/nfsproc.c | 3 +-- fs/nfsd/nfsxdr.c | 9 +-------- fs/nfsd/xdr.h | 2 +- fs/nfsd/xdr3.h | 2 +- include/linux/sunrpc/svc.h | 3 +-- net/sunrpc/svc.c | 11 ++++++----- 9 files changed, 15 insertions(+), 33 deletions(-) diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 17715a6c7a40..4418517f6f12 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -201,8 +201,7 @@ nfsd3_proc_write(struct svc_rqst *rqstp) fh_copy(&resp->fh, &argp->fh); resp->committed = argp->stable; - nvecs = svc_fill_write_vector(rqstp, rqstp->rq_arg.pages, - &argp->first, cnt); + nvecs = svc_fill_write_vector(rqstp, &argp->payload); if (!nvecs) { resp->status = nfserr_io; goto out; diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 3d37923afb06..267e56f218af 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -621,9 +621,6 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p) struct xdr_stream *xdr = &rqstp->rq_arg_stream; struct nfsd3_writeargs *args = rqstp->rq_argp; u32 max_blocksize = svc_max_payload(rqstp); - struct kvec *head = rqstp->rq_arg.head; - struct kvec *tail = rqstp->rq_arg.tail; - size_t remaining; if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) return 0; @@ -641,17 +638,12 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p) /* request sanity */ if (args->count != args->len) return 0; - remaining = head->iov_len + rqstp->rq_arg.page_len + tail->iov_len; - remaining -= xdr_stream_pos(xdr); - if (remaining < xdr_align_size(args->len)) - return 0; if (args->count > max_blocksize) { args->count = max_blocksize; args->len = max_blocksize; } - - args->first.iov_base = xdr->p; - args->first.iov_len = head->iov_len - xdr_stream_pos(xdr); + if (!xdr_stream_subsegment(xdr, &args->payload, args->count)) + return 0; return 1; } diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 3dc40c1d32bc..5895bbeba373 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1033,8 +1033,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, write->wr_how_written = write->wr_stable_how; - nvecs = svc_fill_write_vector(rqstp, write->wr_payload.pages, - write->wr_payload.head, write->wr_buflen); + nvecs = svc_fill_write_vector(rqstp, &write->wr_payload); WARN_ON_ONCE(nvecs > ARRAY_SIZE(rqstp->rq_vec)); status = nfsd_vfs_write(rqstp, &cstate->current_fh, nf, diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 90fcd6178823..eea5b59b6a6c 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -234,8 +234,7 @@ nfsd_proc_write(struct svc_rqst *rqstp) SVCFH_fmt(&argp->fh), argp->len, argp->offset); - nvecs = svc_fill_write_vector(rqstp, rqstp->rq_arg.pages, - &argp->first, cnt); + nvecs = svc_fill_write_vector(rqstp, &argp->payload); if (!nvecs) { resp->status = nfserr_io; goto out; diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index 082449c7d0db..ddcc18adfeb1 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c @@ -325,10 +325,7 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p) { struct xdr_stream *xdr = &rqstp->rq_arg_stream; struct nfsd_writeargs *args = rqstp->rq_argp; - struct kvec *head = rqstp->rq_arg.head; - struct kvec *tail = rqstp->rq_arg.tail; u32 beginoffset, totalcount; - size_t remaining; if (!svcxdr_decode_fhandle(xdr, &args->fh)) return 0; @@ -346,12 +343,8 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p) return 0; if (args->len > NFSSVC_MAXBLKSIZE_V2) return 0; - remaining = head->iov_len + rqstp->rq_arg.page_len + tail->iov_len; - remaining -= xdr_stream_pos(xdr); - if (remaining < xdr_align_size(args->len)) + if (!xdr_stream_subsegment(xdr, &args->payload, args->len)) return 0; - args->first.iov_base = xdr->p; - args->first.iov_len = head->iov_len - xdr_stream_pos(xdr); return 1; } diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h index f45b4bc93f52..80fd6d7f3404 100644 --- a/fs/nfsd/xdr.h +++ b/fs/nfsd/xdr.h @@ -33,7 +33,7 @@ struct nfsd_writeargs { svc_fh fh; __u32 offset; int len; - struct kvec first; + struct xdr_buf payload; }; struct nfsd_createargs { diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h index 933008382bbe..712c117300cb 100644 --- a/fs/nfsd/xdr3.h +++ b/fs/nfsd/xdr3.h @@ -40,7 +40,7 @@ struct nfsd3_writeargs { __u32 count; int stable; __u32 len; - struct kvec first; + struct xdr_buf payload; }; struct nfsd3_createargs { diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 064c96157d1f..6263410c948a 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -532,8 +532,7 @@ int svc_encode_result_payload(struct svc_rqst *rqstp, unsigned int offset, unsigned int length); unsigned int svc_fill_write_vector(struct svc_rqst *rqstp, - struct page **pages, - struct kvec *first, size_t total); + struct xdr_buf *payload); char *svc_fill_symlink_pathname(struct svc_rqst *rqstp, struct kvec *first, void *p, size_t total); diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index a3bbe5ce4570..08ca797bb8a4 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -1676,16 +1676,17 @@ EXPORT_SYMBOL_GPL(svc_encode_result_payload); /** * svc_fill_write_vector - Construct data argument for VFS write call * @rqstp: svc_rqst to operate on - * @pages: list of pages containing data payload - * @first: buffer containing first section of write payload - * @total: total number of bytes of write payload + * @payload: xdr_buf containing only the write data payload * * Fills in rqstp::rq_vec, and returns the number of elements. */ -unsigned int svc_fill_write_vector(struct svc_rqst *rqstp, struct page **pages, - struct kvec *first, size_t total) +unsigned int svc_fill_write_vector(struct svc_rqst *rqstp, + struct xdr_buf *payload) { + struct page **pages = payload->pages; + struct kvec *first = payload->head; struct kvec *vec = rqstp->rq_vec; + size_t total = payload->len; unsigned int i; /* Some types of transport can present the write payload -- cgit From 342a67f0884293639bd17ea44df754ead799e669 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 7 Jul 2021 22:08:32 -0400 Subject: NFS: Label the dentry with a verifier in nfs_link(), nfs_symlink() After the success of an operation such as link(), or symlink(), we expect to add the dentry back to the dcache as an ordinary positive dentry. However in NFS, unless it is labelled with the appropriate verifier for the parent directory state, then nfs_lookup_revalidate will end up discarding that dentry and forcing a new lookup. The fix is to ensure that we relabel the dentry appropriately on success. Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 1a6d2867fba4..baca036f3890 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -2352,6 +2352,8 @@ int nfs_symlink(struct user_namespace *mnt_userns, struct inode *dir, return error; } + nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); + /* * No big deal if we can't add this page to the page cache here. * READLINK will get the missing page from the server if needed. @@ -2385,6 +2387,7 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) d_drop(dentry); error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name); if (error == 0) { + nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); ihold(inode); d_add(dentry, inode); } -- cgit From 9019fb391de02cbff422090768b73afe9f6174df Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 7 Jul 2021 21:43:09 -0400 Subject: NFS: Label the dentry with a verifier in nfs_rmdir() and nfs_unlink() After the success of an operation such as rmdir() or unlink(), we expect to add the dentry back to the dcache as an ordinary negative dentry. However in NFS, unless it is labelled with the appropriate verifier for the parent directory state, then nfs_lookup_revalidate will end up discarding that dentry and forcing a new lookup. The fix is to ensure that we relabel the dentry appropriately on success. Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index baca036f3890..1ce1fa0a5926 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -2197,6 +2197,18 @@ static void nfs_dentry_handle_enoent(struct dentry *dentry) d_delete(dentry); } +static void nfs_dentry_remove_handle_error(struct inode *dir, + struct dentry *dentry, int error) +{ + switch (error) { + case -ENOENT: + d_delete(dentry); + fallthrough; + case 0: + nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); + } +} + int nfs_rmdir(struct inode *dir, struct dentry *dentry) { int error; @@ -2219,6 +2231,7 @@ int nfs_rmdir(struct inode *dir, struct dentry *dentry) up_write(&NFS_I(d_inode(dentry))->rmdir_sem); } else error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name); + nfs_dentry_remove_handle_error(dir, dentry, error); trace_nfs_rmdir_exit(dir, dentry, error); return error; @@ -2288,9 +2301,8 @@ int nfs_unlink(struct inode *dir, struct dentry *dentry) } spin_unlock(&dentry->d_lock); error = nfs_safe_remove(dentry); - if (!error || error == -ENOENT) { - nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); - } else if (need_rehash) + nfs_dentry_remove_handle_error(dir, dentry, error); + if (need_rehash) d_rehash(dentry); out: trace_nfs_unlink_exit(dir, dentry, error); -- cgit From ca05cbae2a0468e5d78e9b4605936a8bf5da328b Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Jul 2021 18:07:14 -0400 Subject: NFS: Fix up nfs_ctx_key_to_expire() If the cached credential exists but doesn't have any expiration callback then exit early. Fix up atomicity issues when replacing the credential with a new one since the existing code could lead to refcount leaks. Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 4 ++-- fs/nfs/write.c | 41 ++++++++++++++++++++++++++++------------- include/linux/nfs_fs.h | 2 +- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 853213b3a209..4f45281c47cf 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1024,7 +1024,7 @@ struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, ctx->cred = get_cred(filp->f_cred); else ctx->cred = get_current_cred(); - ctx->ll_cred = NULL; + rcu_assign_pointer(ctx->ll_cred, NULL); ctx->state = NULL; ctx->mode = f_mode; ctx->flags = 0; @@ -1063,7 +1063,7 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync) put_cred(ctx->cred); dput(ctx->dentry); nfs_sb_deactive(sb); - put_rpccred(ctx->ll_cred); + put_rpccred(rcu_dereference_protected(ctx->ll_cred, 1)); kfree(ctx->mdsthreshold); kfree_rcu(ctx, rcu_head); } diff --git a/fs/nfs/write.c b/fs/nfs/write.c index eae9bf114041..773ea2c8504d 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -1246,7 +1246,7 @@ nfs_key_timeout_notify(struct file *filp, struct inode *inode) struct nfs_open_context *ctx = nfs_file_open_context(filp); if (nfs_ctx_key_to_expire(ctx, inode) && - !ctx->ll_cred) + !rcu_access_pointer(ctx->ll_cred)) /* Already expired! */ return -EACCES; return 0; @@ -1258,23 +1258,38 @@ nfs_key_timeout_notify(struct file *filp, struct inode *inode) bool nfs_ctx_key_to_expire(struct nfs_open_context *ctx, struct inode *inode) { struct rpc_auth *auth = NFS_SERVER(inode)->client->cl_auth; - struct rpc_cred *cred = ctx->ll_cred; + struct rpc_cred *cred, *new, *old = NULL; struct auth_cred acred = { .cred = ctx->cred, }; + bool ret = false; - if (cred && !cred->cr_ops->crmatch(&acred, cred, 0)) { - put_rpccred(cred); - ctx->ll_cred = NULL; - cred = NULL; - } - if (!cred) - cred = auth->au_ops->lookup_cred(auth, &acred, 0); - if (!cred || IS_ERR(cred)) + rcu_read_lock(); + cred = rcu_dereference(ctx->ll_cred); + if (cred && !(cred->cr_ops->crkey_timeout && + cred->cr_ops->crkey_timeout(cred))) + goto out; + rcu_read_unlock(); + + new = auth->au_ops->lookup_cred(auth, &acred, 0); + if (new == cred) { + put_rpccred(new); return true; - ctx->ll_cred = cred; - return !!(cred->cr_ops->crkey_timeout && - cred->cr_ops->crkey_timeout(cred)); + } + if (IS_ERR_OR_NULL(new)) { + new = NULL; + ret = true; + } else if (new->cr_ops->crkey_timeout && + new->cr_ops->crkey_timeout(new)) + ret = true; + + rcu_read_lock(); + old = rcu_dereference_protected(xchg(&ctx->ll_cred, + RCU_INITIALIZER(new)), 1); +out: + rcu_read_unlock(); + put_rpccred(old); + return ret; } /* diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index b9a8b925db43..9b75448ce0df 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -81,7 +81,7 @@ struct nfs_open_context { fl_owner_t flock_owner; struct dentry *dentry; const struct cred *cred; - struct rpc_cred *ll_cred; /* low-level cred - use to check for expiry */ + struct rpc_cred __rcu *ll_cred; /* low-level cred - use to check for expiry */ struct nfs4_state *state; fmode_t mode; -- cgit From ea7a1019d8baf8503ecd6e3ec8436dec283569e6 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 12 Jul 2021 09:52:59 -0400 Subject: SUNRPC: Partial revert of commit 6f9f17287e78 The premise of commit 6f9f17287e78 ("SUNRPC: Mitigate cond_resched() in xprt_transmit()") was that cond_resched() is expensive and unnecessary when there has been just a single send. The point of cond_resched() is to ensure that tasks that should pre-empt this one get a chance to do so when it is safe to do so. The code prior to commit 6f9f17287e78 failed to take into account that it was keeping a rpc_task pinned for longer than it needed to, and so rather than doing a full revert, let's just move the cond_resched. Signed-off-by: Trond Myklebust --- net/sunrpc/xprt.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index cfd681700d1a..d4aeee83763e 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1603,15 +1603,14 @@ xprt_transmit(struct rpc_task *task) { struct rpc_rqst *next, *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; - int counter, status; + int status; spin_lock(&xprt->queue_lock); - counter = 0; - while (!list_empty(&xprt->xmit_queue)) { - if (++counter == 20) + for (;;) { + next = list_first_entry_or_null(&xprt->xmit_queue, + struct rpc_rqst, rq_xmit); + if (!next) break; - next = list_first_entry(&xprt->xmit_queue, - struct rpc_rqst, rq_xmit); xprt_pin_rqst(next); spin_unlock(&xprt->queue_lock); status = xprt_request_transmit(next, task); @@ -1619,13 +1618,16 @@ xprt_transmit(struct rpc_task *task) status = 0; spin_lock(&xprt->queue_lock); xprt_unpin_rqst(next); - if (status == 0) { - if (!xprt_request_data_received(task) || - test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) - continue; - } else if (test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) - task->tk_status = status; - break; + if (status < 0) { + if (test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) + task->tk_status = status; + break; + } + /* Was @task transmitted, and has it received a reply? */ + if (xprt_request_data_received(task) && + !test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) + break; + cond_resched_lock(&xprt->queue_lock); } spin_unlock(&xprt->queue_lock); } -- cgit From 47dd8796a31e132f9e2b93a4f558a9f924a7388f Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 12 Jul 2021 09:57:08 -0400 Subject: SUNRPC: Add cond_resched() at the appropriate point in __rpc_execute() Allow tasks that need to pre-empt rpciod/xprtiod to do so when it is safe. Signed-off-by: Trond Myklebust --- net/sunrpc/sched.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index c045f63d11fa..dc46130d46a0 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -903,8 +903,10 @@ static void __rpc_execute(struct rpc_task *task) /* * Lockless check for whether task is sleeping or not. */ - if (!RPC_IS_QUEUED(task)) + if (!RPC_IS_QUEUED(task)) { + cond_resched(); continue; + } /* * Signalled tasks should exit rather than sleep. -- cgit From 6dbcbe3f78bec62a4a96ac9cfddaf894a140b821 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 12 Jul 2021 11:57:15 -0400 Subject: SUNRPC: Remove WQ_HIGHPRI from xprtiod Don't let xprtiod pre-empt softirq. Signed-off-by: Trond Myklebust --- net/sunrpc/sched.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index dc46130d46a0..b21457cec8a5 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -1232,8 +1232,7 @@ static int rpciod_start(void) if (!wq) goto out_failed; rpciod_workqueue = wq; - /* Note: highpri because network receive is latency sensitive */ - wq = alloc_workqueue("xprtiod", WQ_UNBOUND|WQ_MEM_RECLAIM|WQ_HIGHPRI, 0); + wq = alloc_workqueue("xprtiod", WQ_UNBOUND | WQ_MEM_RECLAIM, 0); if (!wq) goto free_rpciod; xprtiod_workqueue = wq; -- cgit From b9f8713f42af11ae6d7f63075334ba5298436be6 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 12 Jul 2021 12:24:15 -0400 Subject: SUNRPC: Remove unnecessary memory barriers The only check for RPC_TASK_RUNNING is the one in rpc_make_runnable(), which happens under the same spin lock held when we call rpc_clear_running(). Ditto, the last check for RPC_TASK_QUEUED in rpc_execute() is performed under the same lock as the one held when we call rpc_clear_queued(). Signed-off-by: Trond Myklebust --- include/linux/sunrpc/sched.h | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index a237b8dbf608..db964bb63912 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -150,25 +150,13 @@ struct rpc_task_setup { #define RPC_TASK_MSG_PIN_WAIT 5 #define RPC_TASK_SIGNALLED 6 -#define RPC_IS_RUNNING(t) test_bit(RPC_TASK_RUNNING, &(t)->tk_runstate) -#define rpc_set_running(t) set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate) #define rpc_test_and_set_running(t) \ test_and_set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate) -#define rpc_clear_running(t) \ - do { \ - smp_mb__before_atomic(); \ - clear_bit(RPC_TASK_RUNNING, &(t)->tk_runstate); \ - smp_mb__after_atomic(); \ - } while (0) +#define rpc_clear_running(t) clear_bit(RPC_TASK_RUNNING, &(t)->tk_runstate) #define RPC_IS_QUEUED(t) test_bit(RPC_TASK_QUEUED, &(t)->tk_runstate) #define rpc_set_queued(t) set_bit(RPC_TASK_QUEUED, &(t)->tk_runstate) -#define rpc_clear_queued(t) \ - do { \ - smp_mb__before_atomic(); \ - clear_bit(RPC_TASK_QUEUED, &(t)->tk_runstate); \ - smp_mb__after_atomic(); \ - } while (0) +#define rpc_clear_queued(t) clear_bit(RPC_TASK_QUEUED, &(t)->tk_runstate) #define RPC_IS_ACTIVATED(t) test_bit(RPC_TASK_ACTIVE, &(t)->tk_runstate) -- cgit From 33c3214bf450051db99d352cfeef7e0ffcbb8614 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 12 Jul 2021 12:34:34 -0400 Subject: SUNRPC: xprt_clear_locked() only needs release memory semantics The clearing of the XPRT_LOCKED bit has to happen after we clear xprt->snd_task, but we don't require any extra memory barriers after that. Signed-off-by: Trond Myklebust --- net/sunrpc/xprt.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index d4aeee83763e..48560188e84d 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -246,11 +246,9 @@ EXPORT_SYMBOL_GPL(xprt_find_transport_ident); static void xprt_clear_locked(struct rpc_xprt *xprt) { xprt->snd_task = NULL; - if (!test_bit(XPRT_CLOSE_WAIT, &xprt->state)) { - smp_mb__before_atomic(); - clear_bit(XPRT_LOCKED, &xprt->state); - smp_mb__after_atomic(); - } else + if (!test_bit(XPRT_CLOSE_WAIT, &xprt->state)) + clear_bit_unlock(XPRT_LOCKED, &xprt->state); + else queue_work(xprtiod_workqueue, &xprt->task_cleanup); } -- cgit From 43d20e80e2880a1791d87d8b3fc062e91cd2ec4b Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 13 Jul 2021 12:28:22 -0400 Subject: NFS: Fix a few more clear_bit() instances that need release semantics All these bits are being used as bit locks. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4state.c | 5 +---- fs/nfs/pagelist.c | 10 ++-------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index f22818a80c2c..ecc4594299d6 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1194,10 +1194,7 @@ static int nfs4_run_state_manager(void *); static void nfs4_clear_state_manager_bit(struct nfs_client *clp) { - smp_mb__before_atomic(); - clear_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state); - smp_mb__after_atomic(); - wake_up_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING); + clear_and_wake_up_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state); rpc_wake_up(&clp->cl_rpcwaitq); } diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index cc232d1f16f2..72333bcaa4c4 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -271,8 +271,7 @@ nfs_page_set_headlock(struct nfs_page *req) void nfs_page_clear_headlock(struct nfs_page *req) { - smp_mb__before_atomic(); - clear_bit(PG_HEADLOCK, &req->wb_flags); + clear_bit_unlock(PG_HEADLOCK, &req->wb_flags); smp_mb__after_atomic(); if (!test_bit(PG_CONTENDED1, &req->wb_flags)) return; @@ -525,12 +524,7 @@ nfs_create_subreq(struct nfs_page *req, */ void nfs_unlock_request(struct nfs_page *req) { - if (!NFS_WBACK_BUSY(req)) { - printk(KERN_ERR "NFS: Invalid unlock attempted\n"); - BUG(); - } - smp_mb__before_atomic(); - clear_bit(PG_BUSY, &req->wb_flags); + clear_bit_unlock(PG_BUSY, &req->wb_flags); smp_mb__after_atomic(); if (!test_bit(PG_CONTENDED2, &req->wb_flags)) return; -- cgit From a1e7f30a86062380ac804b50491fd24bb9dfb99f Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 14 Jul 2021 13:00:58 -0400 Subject: NFSv4: Retrieve ACCESS on open if we're not using NFS4_CREATE_EXCLUSIVE NFS4_CREATE_EXCLUSIVE does not allow the caller to set an access mode, so for most Linux filesystems, the access call ends up returning no permissions. However both NFS4_CREATE_EXCLUSIVE4_1 and NFS4_CREATE_GUARDED allow the client to set the access mode. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index e1214bb6b7ee..9e89198ea21f 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1388,27 +1388,22 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, sizeof(p->o_arg.u.verifier.data)); } } - /* don't put an ACCESS op in OPEN compound if O_EXCL, because ACCESS - * will return permission denied for all bits until close */ - if (!(flags & O_EXCL)) { - /* ask server to check for all possible rights as results - * are cached */ - switch (p->o_arg.claim) { - default: - break; - case NFS4_OPEN_CLAIM_NULL: - case NFS4_OPEN_CLAIM_FH: - p->o_arg.access = NFS4_ACCESS_READ | - NFS4_ACCESS_MODIFY | - NFS4_ACCESS_EXTEND | - NFS4_ACCESS_EXECUTE; + /* ask server to check for all possible rights as results + * are cached */ + switch (p->o_arg.claim) { + default: + break; + case NFS4_OPEN_CLAIM_NULL: + case NFS4_OPEN_CLAIM_FH: + p->o_arg.access = NFS4_ACCESS_READ | NFS4_ACCESS_MODIFY | + NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE | + NFS4_ACCESS_EXECUTE; #ifdef CONFIG_NFS_V4_2 - if (server->caps & NFS_CAP_XATTR) - p->o_arg.access |= NFS4_ACCESS_XAREAD | - NFS4_ACCESS_XAWRITE | - NFS4_ACCESS_XALIST; + if (!(server->caps & NFS_CAP_XATTR)) + break; + p->o_arg.access |= NFS4_ACCESS_XAREAD | NFS4_ACCESS_XAWRITE | + NFS4_ACCESS_XALIST; #endif - } } p->o_arg.clientid = server->nfs_client->cl_clientid; p->o_arg.id.create_time = ktime_to_ns(sp->so_seqid.create_time); @@ -2472,11 +2467,15 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) /* Set the create mode (note dependency on the session type) */ data->o_arg.createmode = NFS4_CREATE_UNCHECKED; if (data->o_arg.open_flags & O_EXCL) { - data->o_arg.createmode = NFS4_CREATE_EXCLUSIVE; - if (nfs4_has_persistent_session(clp)) + data->o_arg.createmode = NFS4_CREATE_EXCLUSIVE4_1; + if (clp->cl_mvops->minor_version == 0) { + data->o_arg.createmode = NFS4_CREATE_EXCLUSIVE; + /* don't put an ACCESS op in OPEN compound if O_EXCL, + * because ACCESS will return permission denied for + * all bits until close */ + data->o_res.access_request = data->o_arg.access = 0; + } else if (nfs4_has_persistent_session(clp)) data->o_arg.createmode = NFS4_CREATE_GUARDED; - else if (clp->cl_mvops->minor_version > 0) - data->o_arg.createmode = NFS4_CREATE_EXCLUSIVE4_1; } return; unlock_no_action: -- cgit From eea413308f2e6deb00f061f18081a53f3ecc8cc6 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 26 Sep 2021 14:05:04 -0400 Subject: NFS: Default change_attr_type to NFS4_CHANGE_TYPE_IS_UNDEFINED Both NFSv3 and NFSv2 generate their change attribute from the ctime value that was supplied by the server. However the problem is that there are plenty of servers out there with ctime resolutions of 1ms or worse. In a modern performance system, this is insufficient when trying to decide which is the most recent set of attributes when, for instance, a READ or GETATTR call races with a WRITE or SETATTR. For this reason, let's revert to labelling the NFSv2/v3 change attributes as NFS4_CHANGE_TYPE_IS_UNDEFINED. This will ensure we protect against such races. Fixes: 7b24dacf0840 ("NFS: Another inode revalidation improvement") Signed-off-by: Trond Myklebust Tested-by: Chuck Lever --- fs/nfs/inode.c | 4 +++- fs/nfs/nfs3xdr.c | 2 +- fs/nfs/proc.c | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 4f45281c47cf..0f092ccb0ca1 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1777,8 +1777,10 @@ static int nfs_inode_finish_partial_attr_update(const struct nfs_fattr *fattr, NFS_INO_INVALID_BLOCKS | NFS_INO_INVALID_OTHER | NFS_INO_INVALID_NLINK; unsigned long cache_validity = NFS_I(inode)->cache_validity; + enum nfs4_change_attr_type ctype = NFS_SERVER(inode)->change_attr_type; - if (!(cache_validity & NFS_INO_INVALID_CHANGE) && + if (ctype != NFS4_CHANGE_TYPE_IS_UNDEFINED && + !(cache_validity & NFS_INO_INVALID_CHANGE) && (cache_validity & check_valid) != 0 && (fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 && nfs_inode_attrs_cmp_monotonic(fattr, inode) == 0) diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index e6eca1d7481b..9274c9c5efea 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c @@ -2227,7 +2227,7 @@ static int decode_fsinfo3resok(struct xdr_stream *xdr, /* ignore properties */ result->lease_time = 0; - result->change_attr_type = NFS4_CHANGE_TYPE_IS_TIME_METADATA; + result->change_attr_type = NFS4_CHANGE_TYPE_IS_UNDEFINED; return 0; } diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index ea19dbf12301..ecc4e717808c 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -91,7 +91,7 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, info->dtpref = fsinfo.tsize; info->maxfilesize = 0x7FFFFFFF; info->lease_time = 0; - info->change_attr_type = NFS4_CHANGE_TYPE_IS_TIME_METADATA; + info->change_attr_type = NFS4_CHANGE_TYPE_IS_UNDEFINED; return 0; } -- cgit From 488796ec1e39fb9194cc8175f770823d40fbf0ed Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 28 Sep 2021 11:15:53 -0400 Subject: NFS: Don't set NFS_INO_DATA_INVAL_DEFER and NFS_INO_INVALID_DATA NFS_INO_DATA_INVAL_DEFER and NFS_INO_INVALID_DATA should be considered mutually exclusive. Fixes: 1c341b777501 ("NFS: Add deferred cache invalidation for close-to-open consistency violations") Signed-off-by: Trond Myklebust Tested-by: Benjamin Coddington Reviewed-by: Benjamin Coddington --- fs/nfs/inode.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 0f092ccb0ca1..dcb885b7ad73 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -210,10 +210,15 @@ void nfs_set_cache_invalid(struct inode *inode, unsigned long flags) flags &= ~NFS_INO_INVALID_XATTR; if (flags & NFS_INO_INVALID_DATA) nfs_fscache_invalidate(inode); - if (inode->i_mapping->nrpages == 0) - flags &= ~(NFS_INO_INVALID_DATA|NFS_INO_DATA_INVAL_DEFER); flags &= ~(NFS_INO_REVAL_PAGECACHE | NFS_INO_REVAL_FORCED); + nfsi->cache_validity |= flags; + + if (inode->i_mapping->nrpages == 0) + nfsi->cache_validity &= ~(NFS_INO_INVALID_DATA | + NFS_INO_DATA_INVAL_DEFER); + else if (nfsi->cache_validity & NFS_INO_INVALID_DATA) + nfsi->cache_validity &= ~NFS_INO_DATA_INVAL_DEFER; } EXPORT_SYMBOL_GPL(nfs_set_cache_invalid); -- cgit From a6a361c4ca3cc3e6f3b39d1b6bca1de90f5f4b11 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 28 Sep 2021 11:24:57 -0400 Subject: NFS: Ignore the directory size when marking for revalidation If we want to revalidate the directory, then just mark the change attribute as invalid. Fixes: 13c0b082b6a9 ("NFS: Replace use of NFS_INO_REVAL_PAGECACHE when checking cache validity") Signed-off-by: Trond Myklebust Tested-by: Benjamin Coddington Reviewed-by: Benjamin Coddington --- fs/nfs/dir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 1ce1fa0a5926..f2df664db020 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1413,7 +1413,7 @@ out_force: static void nfs_mark_dir_for_revalidate(struct inode *inode) { spin_lock(&inode->i_lock); - nfs_set_cache_invalid(inode, NFS_INO_REVAL_PAGECACHE); + nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE); spin_unlock(&inode->i_lock); } -- cgit From 2929bc3329f4c7e4df400acca2b1844492650bfd Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 28 Sep 2021 12:37:05 -0400 Subject: NFS: Fix up nfs_readdir_inode_mapping_valid() The check for duplicate readdir cookies should only care if the change attribute is invalid or the data cache is invalid. Signed-off-by: Trond Myklebust Tested-by: Benjamin Coddington Reviewed-by: Benjamin Coddington --- fs/nfs/dir.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index f2df664db020..fa4d33687d2b 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -411,7 +411,8 @@ out_eof: static bool nfs_readdir_inode_mapping_valid(struct nfs_inode *nfsi) { - if (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA)) + if (nfsi->cache_validity & (NFS_INO_INVALID_CHANGE | + NFS_INO_INVALID_DATA)) return false; smp_rmb(); return !test_bit(NFS_INO_INVALIDATING, &nfsi->flags); -- cgit From ff81dfb5d721fff87bd516c558847f6effb70031 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 28 Sep 2021 14:33:44 -0400 Subject: NFS: Further optimisations for 'ls -l' If a user is doing 'ls -l', we have a heuristic in GETATTR that tells the readdir code to try to use READDIRPLUS in order to refresh the inode attributes. In certain cirumstances, we also try to invalidate the remaining directory entries in order to ensure this refresh. If there are multiple readers of the directory, we probably should avoid invalidating the page cache, since the heuristic breaks down in that situation anyway. Signed-off-by: Trond Myklebust Tested-by: Benjamin Coddington Reviewed-by: Benjamin Coddington --- fs/nfs/dir.c | 16 +++++++++++----- include/linux/nfs_fs.h | 5 ++--- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index fa4d33687d2b..33cfff8ea551 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -78,6 +78,7 @@ static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir ctx->attr_gencount = nfsi->attr_gencount; ctx->dir_cookie = 0; ctx->dup_cookie = 0; + ctx->page_index = 0; spin_lock(&dir->i_lock); if (list_empty(&nfsi->open_files) && (nfsi->cache_validity & NFS_INO_DATA_INVAL_DEFER)) @@ -85,6 +86,7 @@ static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir NFS_INO_INVALID_DATA | NFS_INO_REVAL_FORCED); list_add(&ctx->list, &nfsi->open_files); + clear_bit(NFS_INO_FORCE_READDIR, &nfsi->flags); spin_unlock(&dir->i_lock); return ctx; } @@ -627,8 +629,7 @@ void nfs_force_use_readdirplus(struct inode *dir) if (nfs_server_capable(dir, NFS_CAP_READDIRPLUS) && !list_empty(&nfsi->open_files)) { set_bit(NFS_INO_ADVISE_RDPLUS, &nfsi->flags); - invalidate_mapping_pages(dir->i_mapping, - nfsi->page_index + 1, -1); + set_bit(NFS_INO_FORCE_READDIR, &nfsi->flags); } } @@ -938,10 +939,8 @@ static int find_and_lock_cache_page(struct nfs_readdir_descriptor *desc) sizeof(nfsi->cookieverf)); } res = nfs_readdir_search_array(desc); - if (res == 0) { - nfsi->page_index = desc->page_index; + if (res == 0) return 0; - } nfs_readdir_page_unlock_and_put_cached(desc); return res; } @@ -1080,6 +1079,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx) struct nfs_inode *nfsi = NFS_I(inode); struct nfs_open_dir_context *dir_ctx = file->private_data; struct nfs_readdir_descriptor *desc; + pgoff_t page_index; int res; dfprintk(FILE, "NFS: readdir(%pD2) starting at cookie %llu\n", @@ -1110,10 +1110,15 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx) desc->dir_cookie = dir_ctx->dir_cookie; desc->dup_cookie = dir_ctx->dup_cookie; desc->duped = dir_ctx->duped; + page_index = dir_ctx->page_index; desc->attr_gencount = dir_ctx->attr_gencount; memcpy(desc->verf, dir_ctx->verf, sizeof(desc->verf)); spin_unlock(&file->f_lock); + if (test_and_clear_bit(NFS_INO_FORCE_READDIR, &nfsi->flags) && + list_is_singular(&nfsi->open_files)) + invalidate_mapping_pages(inode->i_mapping, page_index + 1, -1); + do { res = readdir_search_pagecache(desc); @@ -1150,6 +1155,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx) dir_ctx->dup_cookie = desc->dup_cookie; dir_ctx->duped = desc->duped; dir_ctx->attr_gencount = desc->attr_gencount; + dir_ctx->page_index = desc->page_index; memcpy(dir_ctx->verf, desc->verf, sizeof(dir_ctx->verf)); spin_unlock(&file->f_lock); diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 9b75448ce0df..ca547cc5458c 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -103,6 +103,7 @@ struct nfs_open_dir_context { __be32 verf[NFS_DIR_VERIFIER_SIZE]; __u64 dir_cookie; __u64 dup_cookie; + pgoff_t page_index; signed char duped; }; @@ -181,9 +182,6 @@ struct nfs_inode { struct rw_semaphore rmdir_sem; struct mutex commit_mutex; - /* track last access to cached pages */ - unsigned long page_index; - #if IS_ENABLED(CONFIG_NFS_V4) struct nfs4_cached_acl *nfs4_acl; /* NFSv4 state */ @@ -272,6 +270,7 @@ struct nfs4_copy_state { #define NFS_INO_INVALIDATING (3) /* inode is being invalidated */ #define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */ #define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */ +#define NFS_INO_FORCE_READDIR (7) /* force readdirplus */ #define NFS_INO_LAYOUTCOMMIT (9) /* layoutcommit required */ #define NFS_INO_LAYOUTCOMMITTING (10) /* layoutcommit inflight */ #define NFS_INO_LAYOUTSTATS (11) /* layoutstats inflight */ -- cgit From cec08f452a687fce9dfdf47946d00a1d12a8bec5 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 29 Sep 2021 08:12:53 -0400 Subject: NFS: Fix dentry verifier races If the directory changed while we were revalidating the dentry, then don't update the dentry verifier. There is no value in setting the verifier to an older value, and we could end up overwriting a more up to date verifier from a parallel revalidation. Fixes: efeda80da38d ("NFSv4: Fix revalidation of dentries with delegations") Signed-off-by: Trond Myklebust Tested-by: Benjamin Coddington Reviewed-by: Benjamin Coddington --- fs/nfs/dir.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 33cfff8ea551..3fafecdb2070 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1276,13 +1276,12 @@ static bool nfs_verifier_is_delegated(struct dentry *dentry) static void nfs_set_verifier_locked(struct dentry *dentry, unsigned long verf) { struct inode *inode = d_inode(dentry); + struct inode *dir = d_inode(dentry->d_parent); - if (!nfs_verifier_is_delegated(dentry) && - !nfs_verify_change_attribute(d_inode(dentry->d_parent), verf)) - goto out; + if (!nfs_verify_change_attribute(dir, verf)) + return; if (inode && NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) nfs_set_verifier_delegated(&verf); -out: dentry->d_time = verf; } -- cgit From b97583b26326ad559d1b1ba7dafec98712ffd834 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 2 Oct 2021 19:04:59 -0400 Subject: NFS: Do not flush the readdir cache in nfs_dentry_iput() The original premise in commit 83672d392f7b ("NFS: Fix directory caching problem - with test case and patch.") was that readdirplus was caching attribute information and replaying it later. This is no longer the case. Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 3fafecdb2070..210c5945ac2b 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1727,10 +1727,6 @@ static void nfs_drop_nlink(struct inode *inode) */ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode) { - if (S_ISDIR(inode->i_mode)) - /* drop any readdir cache as it could easily be old */ - nfs_set_cache_invalid(inode, NFS_INO_INVALID_DATA); - if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { nfs_complete_unlink(dentry, inode); nfs_drop_nlink(inode); -- cgit From 36a10a3c4cb6ea7c8bd895c16b3f59e1f0db2f6a Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 2 Oct 2021 19:21:49 -0400 Subject: NFS: Remove unnecessary page cache invalidations Remove cache invalidations that are already covered by change attribute updates. Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index dcb885b7ad73..3bd0ae438663 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1451,8 +1451,6 @@ static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr) && (fattr->valid & NFS_ATTR_FATTR_MTIME) && timespec64_equal(&ts, &fattr->pre_mtime)) { inode->i_mtime = fattr->mtime; - if (S_ISDIR(inode->i_mode)) - nfs_set_cache_invalid(inode, NFS_INO_INVALID_DATA); } if ((fattr->valid & NFS_ATTR_FATTR_PRESIZE) && (fattr->valid & NFS_ATTR_FATTR_SIZE) @@ -2162,11 +2160,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) save_cache_validity & NFS_INO_INVALID_OTHER; if (fattr->valid & NFS_ATTR_FATTR_NLINK) { - if (inode->i_nlink != fattr->nlink) { - if (S_ISDIR(inode->i_mode)) - invalid |= NFS_INO_INVALID_DATA; + if (inode->i_nlink != fattr->nlink) set_nlink(inode, fattr->nlink); - } } else if (fattr_supported & NFS_ATTR_FATTR_NLINK) nfsi->cache_validity |= save_cache_validity & NFS_INO_INVALID_NLINK; -- cgit From a2915fa06227b056a8f9b0d79b61dca08ad5cfc6 Mon Sep 17 00:00:00 2001 From: Baptiste Lepers Date: Mon, 6 Sep 2021 11:59:24 +1000 Subject: pnfs/flexfiles: Fix misplaced barrier in nfs4_ff_layout_prepare_ds _nfs4_pnfs_v3/v4_ds_connect do some work smp_wmb ds->ds_clp = clp; And nfs4_ff_layout_prepare_ds currently does smp_rmb if(ds->ds_clp) ... This patch places the smp_rmb after the if. This ensures that following reads only happen once nfs4_ff_layout_prepare_ds has checked that data has been properly initialized. Fixes: d67ae825a59d6 ("pnfs/flexfiles: Add the FlexFile Layout Driver") Signed-off-by: Baptiste Lepers Signed-off-by: Trond Myklebust --- fs/nfs/flexfilelayout/flexfilelayoutdev.c | 4 ++-- fs/nfs/pnfs_nfs.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c index c9b61b818ec1..bfa7202ca7be 100644 --- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c +++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c @@ -378,10 +378,10 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, goto noconnect; ds = mirror->mirror_ds->ds; + if (READ_ONCE(ds->ds_clp)) + goto out; /* matching smp_wmb() in _nfs4_pnfs_v3/4_ds_connect */ smp_rmb(); - if (ds->ds_clp) - goto out; /* FIXME: For now we assume the server sent only one version of NFS * to use for the DS. diff --git a/fs/nfs/pnfs_nfs.c b/fs/nfs/pnfs_nfs.c index cf19914fec81..02bd6e83961d 100644 --- a/fs/nfs/pnfs_nfs.c +++ b/fs/nfs/pnfs_nfs.c @@ -895,7 +895,7 @@ static int _nfs4_pnfs_v3_ds_connect(struct nfs_server *mds_srv, } smp_wmb(); - ds->ds_clp = clp; + WRITE_ONCE(ds->ds_clp, clp); dprintk("%s [new] addr: %s\n", __func__, ds->ds_remotestr); out: return status; @@ -973,7 +973,7 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv, } smp_wmb(); - ds->ds_clp = clp; + WRITE_ONCE(ds->ds_clp, clp); dprintk("%s [new] addr: %s\n", __func__, ds->ds_remotestr); out: return status; -- cgit From 8b7912f4cb6c29a1223ca7f2472bf12c44cc285e Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Thu, 30 Sep 2021 15:39:08 +0530 Subject: opp: Fix required-opps phandle array count check The 'required-opps' property is optional. So of_count_phandle_with_args() can return -ENOENT when queried for required-opps. Handle this case. Signed-off-by: Pavankumar Kondeti Signed-off-by: Viresh Kumar --- drivers/opp/of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/opp/of.c b/drivers/opp/of.c index 2a97c6535c4c..5437085fb380 100644 --- a/drivers/opp/of.c +++ b/drivers/opp/of.c @@ -170,7 +170,7 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table, } count = of_count_phandle_with_args(np, "required-opps", NULL); - if (!count) + if (count <= 0) goto put_np; required_opp_tables = kcalloc(count, sizeof(*required_opp_tables), -- cgit From b860b9346e2d5667fbae2cefc571bdb6ce665b53 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 13 Sep 2021 16:08:33 +0200 Subject: s390/ftrace: remove dead code ftrace_shared_hotpatch_trampoline() never returns NULL, therefore quite a bit of code can be removed. Acked-by: Ilya Leoshkevich Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/kernel/ftrace.c | 86 ++++------------------------------------------- 1 file changed, 6 insertions(+), 80 deletions(-) diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c index 1d94ffdf347b..5d0c45c13b5f 100644 --- a/arch/s390/kernel/ftrace.c +++ b/arch/s390/kernel/ftrace.c @@ -80,17 +80,6 @@ asm( #ifdef CONFIG_MODULES static char *ftrace_plt; - -asm( - " .data\n" - "ftrace_plt_template:\n" - " basr %r1,%r0\n" - " lg %r1,0f-.(%r1)\n" - " br %r1\n" - "0: .quad ftrace_caller\n" - "ftrace_plt_template_end:\n" - " .previous\n" -); #endif /* CONFIG_MODULES */ static const char *ftrace_shared_hotpatch_trampoline(const char **end) @@ -116,7 +105,7 @@ static const char *ftrace_shared_hotpatch_trampoline(const char **end) bool ftrace_need_init_nop(void) { - return ftrace_shared_hotpatch_trampoline(NULL); + return true; } int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec) @@ -175,28 +164,6 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, return 0; } -static void ftrace_generate_nop_insn(struct ftrace_insn *insn) -{ - /* brcl 0,0 */ - insn->opc = 0xc004; - insn->disp = 0; -} - -static void ftrace_generate_call_insn(struct ftrace_insn *insn, - unsigned long ip) -{ - unsigned long target; - - /* brasl r0,ftrace_caller */ - target = FTRACE_ADDR; -#ifdef CONFIG_MODULES - if (is_module_addr((void *)ip)) - target = (unsigned long)ftrace_plt; -#endif /* CONFIG_MODULES */ - insn->opc = 0xc005; - insn->disp = (target - ip) / 2; -} - static void brcl_disable(void *brcl) { u8 op = 0x04; /* set mask field to zero */ @@ -207,23 +174,7 @@ static void brcl_disable(void *brcl) int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr) { - struct ftrace_insn orig, new, old; - - if (ftrace_shared_hotpatch_trampoline(NULL)) { - brcl_disable((void *)rec->ip); - return 0; - } - - if (copy_from_kernel_nofault(&old, (void *) rec->ip, sizeof(old))) - return -EFAULT; - /* Replace ftrace call with a nop. */ - ftrace_generate_call_insn(&orig, rec->ip); - ftrace_generate_nop_insn(&new); - - /* Verify that the to be replaced code matches what we expect. */ - if (memcmp(&orig, &old, sizeof(old))) - return -EINVAL; - s390_kernel_write((void *) rec->ip, &new, sizeof(new)); + brcl_disable((void *)rec->ip); return 0; } @@ -236,23 +187,7 @@ static void brcl_enable(void *brcl) int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) { - struct ftrace_insn orig, new, old; - - if (ftrace_shared_hotpatch_trampoline(NULL)) { - brcl_enable((void *)rec->ip); - return 0; - } - - if (copy_from_kernel_nofault(&old, (void *) rec->ip, sizeof(old))) - return -EFAULT; - /* Replace nop with an ftrace call. */ - ftrace_generate_nop_insn(&orig); - ftrace_generate_call_insn(&new, rec->ip); - - /* Verify that the to be replaced code matches what we expect. */ - if (memcmp(&orig, &old, sizeof(old))) - return -EINVAL; - s390_kernel_write((void *) rec->ip, &new, sizeof(new)); + brcl_enable((void *)rec->ip); return 0; } @@ -269,10 +204,7 @@ int __init ftrace_dyn_arch_init(void) void arch_ftrace_update_code(int command) { - if (ftrace_shared_hotpatch_trampoline(NULL)) - ftrace_modify_all_code(command); - else - ftrace_run_stop_machine(command); + ftrace_modify_all_code(command); } static void __ftrace_sync(void *dummy) @@ -281,10 +213,8 @@ static void __ftrace_sync(void *dummy) int ftrace_arch_code_modify_post_process(void) { - if (ftrace_shared_hotpatch_trampoline(NULL)) { - /* Send SIGP to the other CPUs, so they see the new code. */ - smp_call_function(__ftrace_sync, NULL, 1); - } + /* Send SIGP to the other CPUs, so they see the new code. */ + smp_call_function(__ftrace_sync, NULL, 1); return 0; } @@ -299,10 +229,6 @@ static int __init ftrace_plt_init(void) panic("cannot allocate ftrace plt\n"); start = ftrace_shared_hotpatch_trampoline(&end); - if (!start) { - start = ftrace_plt_template; - end = ftrace_plt_template_end; - } memcpy(ftrace_plt, start, end - start); set_memory_ro((unsigned long)ftrace_plt, 1); return 0; -- cgit From 4df898dc06da83052c73a2ce9a6a4df5640a0905 Mon Sep 17 00:00:00 2001 From: Sven Schnelle Date: Mon, 6 Sep 2021 11:25:38 +0200 Subject: s390/kprobes: add sanity check Check whether the specified address points to the start of an instruction to prevent users from setting a kprobe in the mid of an instruction which would crash the kernel. Signed-off-by: Sven Schnelle Reviewed-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/kernel/kprobes.c | 48 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index 52d056a5f89f..0093c326a239 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c @@ -120,9 +120,55 @@ static void s390_free_insn_slot(struct kprobe *p) } NOKPROBE_SYMBOL(s390_free_insn_slot); +/* Check if paddr is at an instruction boundary */ +static bool can_probe(unsigned long paddr) +{ + unsigned long addr, offset = 0; + kprobe_opcode_t insn; + struct kprobe *kp; + + if (paddr & 0x01) + return false; + + if (!kallsyms_lookup_size_offset(paddr, NULL, &offset)) + return false; + + /* Decode instructions */ + addr = paddr - offset; + while (addr < paddr) { + if (copy_from_kernel_nofault(&insn, (void *)addr, sizeof(insn))) + return false; + + if (insn >> 8 == 0) { + if (insn != BREAKPOINT_INSTRUCTION) { + /* + * Note that QEMU inserts opcode 0x0000 to implement + * software breakpoints for guests. Since the size of + * the original instruction is unknown, stop following + * instructions and prevent setting a kprobe. + */ + return false; + } + /* + * Check if the instruction has been modified by another + * kprobe, in which case the original instruction is + * decoded. + */ + kp = get_kprobe((void *)addr); + if (!kp) { + /* not a kprobe */ + return false; + } + insn = kp->opcode; + } + addr += insn_length(insn >> 8); + } + return addr == paddr; +} + int arch_prepare_kprobe(struct kprobe *p) { - if ((unsigned long) p->addr & 0x01) + if (!can_probe((unsigned long)p->addr)) return -EINVAL; /* Make sure the probe isn't going on a difficult instruction */ if (probe_is_prohibited_opcode(p->addr)) -- cgit From 1c8174fdc798489159a79466fca782daa231219a Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Tue, 7 Sep 2021 16:43:29 +0200 Subject: s390/pci: tolerate inconsistent handle in recover Since commit 8256adda1f44 ("s390/pci: handle FH state mismatch only on disable") zpci_disable_device() returns -EINVAL when the platform detects an attempt to disable a PCI function that it sees as already disabled. In most situations we want to abort whenever this happens and abort is possible since it either means that the device vanished but we haven't gotten an availability event yet, or the FH got out of sync which should not happen. Unfortunately there is an inconsistency between the LPAR and z/VM hypervisors on whether error events for PCI functions contain an an enabled or a general handle. So under z/VM it can happen that our most up to date function handle is enabled but trying to disable the function results in the aforementioned error. Since recover is designed to be used to recover functions from the error state let's make it robust to this inconsistency by explicitly treating it as a successful disable. Acked-by: Pierre Morel Signed-off-by: Niklas Schnelle Signed-off-by: Vasily Gorbik --- arch/s390/pci/pci_sysfs.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/s390/pci/pci_sysfs.c b/arch/s390/pci/pci_sysfs.c index 335c281811c7..cae280e5c047 100644 --- a/arch/s390/pci/pci_sysfs.c +++ b/arch/s390/pci/pci_sysfs.c @@ -90,6 +90,14 @@ static ssize_t recover_store(struct device *dev, struct device_attribute *attr, if (zdev_enabled(zdev)) { ret = zpci_disable_device(zdev); + /* + * Due to a z/VM vs LPAR inconsistency in the error + * state the FH may indicate an enabled device but + * disable says the device is already disabled don't + * treat it as an error here. + */ + if (ret == -EINVAL) + ret = 0; if (ret) goto out; } -- cgit From fa172f043f5bc21c357c54a6ca2e9c8acd18c3db Mon Sep 17 00:00:00 2001 From: Vineeth Vijayan Date: Wed, 15 Sep 2021 13:39:16 +0200 Subject: s390/cio: unregister the subchannel while purging The cio_ignore list is used to create and maintain the list of devices which is to be ignored by Linux. During boot-time, this list is adjusted and accommodate all the devices which are configured on the HMC interface. Once these devices are accessible, they are then available to Linux and set online. cio_ignore purge function should align with this functionality. But currently, the subchannel associated with the offline-devices are not unregistered during purge. Add an explicit subchannel-unregister function in the purge_fn callback. Signed-off-by: Vineeth Vijayan Reviewed-by: Peter Oberparleiter Signed-off-by: Vasily Gorbik --- drivers/s390/cio/device.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 8d14569823d7..07a17613fab5 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1322,6 +1322,7 @@ static int purge_fn(struct device *dev, void *data) { struct ccw_device *cdev = to_ccwdev(dev); struct ccw_dev_id *id = &cdev->private->dev_id; + struct subchannel *sch = to_subchannel(cdev->dev.parent); spin_lock_irq(cdev->ccwlock); if (is_blacklisted(id->ssid, id->devno) && @@ -1330,6 +1331,7 @@ static int purge_fn(struct device *dev, void *data) CIO_MSG_EVENT(3, "ccw: purging 0.%x.%04x\n", id->ssid, id->devno); ccw_device_sched_todo(cdev, CDEV_TODO_UNREG); + css_sched_sch_todo(sch, SCH_TODO_UNREG); atomic_set(&cdev->private->onoff, 0); } spin_unlock_irq(cdev->ccwlock); -- cgit From 6526a597a2e856df9ae94512f9903caccd5196d6 Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Wed, 15 Sep 2021 17:08:44 +0200 Subject: s390/pci: add simpler s390dbf traces for events We often need to figure out what operations were performed in response to an error or availability event. The operations are easily accessible in s390dbf/pci_msg but the events have to be correlated with these from either the kernel log or s390dbf/pci_err. Improve this situation by logging the most important data from error and availability events that is the FID, PEC and FH together with the operations. Reviewed-by: Matthew Rosato Signed-off-by: Niklas Schnelle Signed-off-by: Vasily Gorbik --- arch/s390/pci/pci_event.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/s390/pci/pci_event.c b/arch/s390/pci/pci_event.c index c856f80cb21b..461bfb12a3a3 100644 --- a/arch/s390/pci/pci_event.c +++ b/arch/s390/pci/pci_event.c @@ -52,6 +52,8 @@ static void __zpci_event_error(struct zpci_ccdf_err *ccdf) struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid); struct pci_dev *pdev = NULL; + zpci_dbg(3, "err fid:%x, fh:%x, pec:%x\n", + ccdf->fid, ccdf->fh, ccdf->pec); zpci_err("error CCDF:\n"); zpci_err_hex(ccdf, sizeof(*ccdf)); @@ -96,6 +98,8 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf) struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid); enum zpci_state state; + zpci_dbg(3, "avl fid:%x, fh:%x, pec:%x\n", + ccdf->fid, ccdf->fh, ccdf->pec); zpci_err("avail CCDF:\n"); zpci_err_hex(ccdf, sizeof(*ccdf)); -- cgit From 0c3812c347bfb0dc213556a195e79850c55702f5 Mon Sep 17 00:00:00 2001 From: Vineeth Vijayan Date: Fri, 17 Sep 2021 15:04:01 +0200 Subject: s390/cio: derive cdev information only for IO-subchannels cdev->online for the purge function must not be checked for the non-IO subchannel type. Make sure that we are deriving the cdev only from sch-type SUBCHANNEL_TYPE_IO. Signed-off-by: Vineeth Vijayan Reviewed-by: Peter Oberparleiter Signed-off-by: Vasily Gorbik --- drivers/s390/cio/css.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 44461928aab8..2bc55ccf3f23 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -792,10 +792,13 @@ static int __unset_online(struct device *dev, void *data) { struct idset *set = data; struct subchannel *sch = to_subchannel(dev); - struct ccw_device *cdev = sch_get_cdev(sch); + struct ccw_device *cdev; - if (cdev && cdev->online) - idset_sch_del(set, sch->schid); + if (sch->st == SUBCHANNEL_TYPE_IO) { + cdev = sch_get_cdev(sch); + if (cdev && cdev->online) + idset_sch_del(set, sch->schid); + } return 0; } -- cgit From 54235d5cfea05f2891dca71d51d7ab097b53d22b Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Thu, 23 Sep 2021 12:42:02 +0200 Subject: s390/sclp_sd: fix warnings about missing parameter description Fix these warnings that are reported when compiling with W=1: drivers/s390/char/sclp_sd.c:132: warning: Function parameter or member 'listener' not described in 'sclp_sd_listener_init' drivers/s390/char/sclp_sd.c:408: warning: Function parameter or member 'cookie' not described in 'sclp_sd_file_update_async' drivers/s390/char/sclp_sd.c:422: warning: Function parameter or member 'attr' not described in 'reload_store' drivers/s390/char/sclp_sd.c:422: warning: Function parameter or member 'buf' not described in 'reload_store' drivers/s390/char/sclp_sd.c:422: warning: Function parameter or member 'count' not described in 'reload_store' drivers/s390/char/sclp_sd.c:457: warning: Function parameter or member 'file' not described in 'data_read' drivers/s390/char/sclp_sd.c:457: warning: Function parameter or member 'attr' not described in 'data_read' Signed-off-by: Peter Oberparleiter Signed-off-by: Vasily Gorbik --- drivers/s390/char/sclp_sd.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/s390/char/sclp_sd.c b/drivers/s390/char/sclp_sd.c index 1e244f78f192..a5dd4e9f5b1b 100644 --- a/drivers/s390/char/sclp_sd.c +++ b/drivers/s390/char/sclp_sd.c @@ -122,6 +122,7 @@ static void sclp_sd_listener_remove(struct sclp_sd_listener *listener) /** * sclp_sd_listener_init() - Initialize a Store Data response listener + * @listener: Response listener to initialize * @id: Event ID to listen for * * Initialize a listener for asynchronous Store Data responses. This listener @@ -403,6 +404,7 @@ static int sclp_sd_file_update(struct sclp_sd_file *sd_file) /** * sclp_sd_file_update_async() - Wrapper for asynchronous update call * @data: Object to update + * @cookie: Unused */ static void sclp_sd_file_update_async(void *data, async_cookie_t cookie) { @@ -414,6 +416,9 @@ static void sclp_sd_file_update_async(void *data, async_cookie_t cookie) /** * reload_store() - Store function for "reload" sysfs attribute * @kobj: Kobject of sclp_sd_file object + * @attr: Reload attribute + * @buf: Data written to sysfs attribute + * @count: Count of bytes written * * Initiate a reload of the data associated with an sclp_sd_file object. */ @@ -441,8 +446,10 @@ static struct kobj_type sclp_sd_file_ktype = { }; /** - * data_read() - Read function for "read" sysfs attribute + * data_read() - Read function for "data" sysfs attribute + * @file: Open file pointer * @kobj: Kobject of sclp_sd_file object + * @attr: Data attribute * @buffer: Target buffer * @off: Requested file offset * @size: Requested number of bytes -- cgit From f768a20c0a6e5f2396b9ab99bbbfd39d91228df9 Mon Sep 17 00:00:00 2001 From: Sven Schnelle Date: Fri, 24 Sep 2021 15:03:07 +0200 Subject: s390/ftrace: add FTRACE_GEN_NOP_ASM macro FTRACE_GEN_NOP_ASM(name) can be used to generate assembly functions with the required information added to allow tracing via kprobes/ftrace. It adds the nop instruction which will be patched by ftrace later. If the compiler supports -mnop-mcount it will also add an entry to the __mcount_loc section. Signed-off-by: Sven Schnelle Acked-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/ftrace.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h index e8b460f39c58..d1841f4176be 100644 --- a/arch/s390/include/asm/ftrace.h +++ b/arch/s390/include/asm/ftrace.h @@ -68,4 +68,32 @@ static inline bool arch_syscall_match_sym_name(const char *sym, } #endif /* __ASSEMBLY__ */ + +#ifdef CONFIG_FUNCTION_TRACER + +#define FTRACE_NOP_INSN .word 0xc004, 0x0000, 0x0000 /* brcl 0,0 */ + +#ifndef CC_USING_HOTPATCH + +#define FTRACE_GEN_MCOUNT_RECORD(name) \ + .section __mcount_loc, "a", @progbits; \ + .quad name; \ + .previous; + +#else /* !CC_USING_HOTPATCH */ + +#define FTRACE_GEN_MCOUNT_RECORD(name) + +#endif /* !CC_USING_HOTPATCH */ + +#define FTRACE_GEN_NOP_ASM(name) \ + FTRACE_GEN_MCOUNT_RECORD(name) \ + FTRACE_NOP_INSN + +#else /* CONFIG_FUNCTION_TRACER */ + +#define FTRACE_GEN_NOP_ASM(name) + +#endif /* CONFIG_FUNCTION_TRACER */ + #endif /* _ASM_S390_FTRACE_H */ -- cgit From d340d28a968ec479d0ed3c38ab716ed821d82ad8 Mon Sep 17 00:00:00 2001 From: Sven Schnelle Date: Thu, 9 Sep 2021 20:59:17 +0200 Subject: kprobes: add testcases for s390 Add a few testcases to make sure that it's not possible to place a kprobe in the mid of an instruction on s390. Signed-off-by: Sven Schnelle Acked-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/Kconfig | 12 +++++++ arch/s390/configs/debug_defconfig | 1 + arch/s390/lib/Makefile | 2 ++ arch/s390/lib/test_kprobes.c | 75 +++++++++++++++++++++++++++++++++++++++ arch/s390/lib/test_kprobes.h | 10 ++++++ arch/s390/lib/test_kprobes_asm.S | 45 +++++++++++++++++++++++ 6 files changed, 145 insertions(+) create mode 100644 arch/s390/lib/test_kprobes.c create mode 100644 arch/s390/lib/test_kprobes.h create mode 100644 arch/s390/lib/test_kprobes_asm.S diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index b86de61b8caa..4d63662a919d 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -946,4 +946,16 @@ config S390_UNWIND_SELFTEST Say N if you are unsure. +config S390_KPROBES_SANITY_TEST + def_tristate n + prompt "Enable s390 specific kprobes tests" + depends on KPROBES + depends on KUNIT + help + This option enables an s390 specific kprobes test module. This option + is not useful for distributions or general kernels, but only for kernel + developers working on architecture code. + + Say N if you are unsure. + endmenu diff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig index 6aad18ee131d..1818d67c2c1c 100644 --- a/arch/s390/configs/debug_defconfig +++ b/arch/s390/configs/debug_defconfig @@ -62,6 +62,7 @@ CONFIG_CMM=m CONFIG_APPLDATA_BASE=y CONFIG_KVM=m CONFIG_S390_UNWIND_SELFTEST=y +CONFIG_S390_KPROBES_SANITY_TEST=y CONFIG_KPROBES=y CONFIG_JUMP_LABEL=y CONFIG_STATIC_KEYS_SELFTEST=y diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile index 678333936f78..707cd4622c13 100644 --- a/arch/s390/lib/Makefile +++ b/arch/s390/lib/Makefile @@ -7,6 +7,8 @@ lib-y += delay.o string.o uaccess.o find.o spinlock.o obj-y += mem.o xor.o lib-$(CONFIG_KPROBES) += probes.o lib-$(CONFIG_UPROBES) += probes.o +obj-$(CONFIG_S390_KPROBES_SANITY_TEST) += test_kprobes_s390.o +test_kprobes_s390-objs += test_kprobes_asm.o test_kprobes.o # Instrumenting memory accesses to __user data (in different address space) # produce false positives diff --git a/arch/s390/lib/test_kprobes.c b/arch/s390/lib/test_kprobes.c new file mode 100644 index 000000000000..9e62d62812e5 --- /dev/null +++ b/arch/s390/lib/test_kprobes.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include +#include +#include +#include +#include "test_kprobes.h" + +static struct kprobe kp; + +static void setup_kprobe(struct kunit *test, struct kprobe *kp, + const char *symbol, int offset) +{ + kp->offset = offset; + kp->addr = NULL; + kp->symbol_name = symbol; +} + +static void test_kprobe_offset(struct kunit *test, struct kprobe *kp, + const char *target, int offset) +{ + int ret; + + setup_kprobe(test, kp, target, 0); + ret = register_kprobe(kp); + if (!ret) + unregister_kprobe(kp); + KUNIT_EXPECT_EQ(test, 0, ret); + setup_kprobe(test, kp, target, offset); + ret = register_kprobe(kp); + KUNIT_EXPECT_EQ(test, -EINVAL, ret); + if (!ret) + unregister_kprobe(kp); +} + +static void test_kprobe_odd(struct kunit *test) +{ + test_kprobe_offset(test, &kp, "kprobes_target_odd", + kprobes_target_odd_offs); +} + +static void test_kprobe_in_insn4(struct kunit *test) +{ + test_kprobe_offset(test, &kp, "kprobes_target_in_insn4", + kprobes_target_in_insn4_offs); +} + +static void test_kprobe_in_insn6_lo(struct kunit *test) +{ + test_kprobe_offset(test, &kp, "kprobes_target_in_insn6_lo", + kprobes_target_in_insn6_lo_offs); +} + +static void test_kprobe_in_insn6_hi(struct kunit *test) +{ + test_kprobe_offset(test, &kp, "kprobes_target_in_insn6_hi", + kprobes_target_in_insn6_hi_offs); +} + +static struct kunit_case kprobes_testcases[] = { + KUNIT_CASE(test_kprobe_odd), + KUNIT_CASE(test_kprobe_in_insn4), + KUNIT_CASE(test_kprobe_in_insn6_lo), + KUNIT_CASE(test_kprobe_in_insn6_hi), + {} +}; + +static struct kunit_suite kprobes_test_suite = { + .name = "kprobes_test_s390", + .test_cases = kprobes_testcases, +}; + +kunit_test_suites(&kprobes_test_suite); + +MODULE_LICENSE("GPL"); diff --git a/arch/s390/lib/test_kprobes.h b/arch/s390/lib/test_kprobes.h new file mode 100644 index 000000000000..2b4c9bc337f1 --- /dev/null +++ b/arch/s390/lib/test_kprobes.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +#ifndef TEST_KPROBES_H +#define TEST_KPROBES_H + +extern unsigned long kprobes_target_odd_offs; +extern unsigned long kprobes_target_in_insn4_offs; +extern unsigned long kprobes_target_in_insn6_lo_offs; +extern unsigned long kprobes_target_in_insn6_hi_offs; + +#endif diff --git a/arch/s390/lib/test_kprobes_asm.S b/arch/s390/lib/test_kprobes_asm.S new file mode 100644 index 000000000000..ade7a3042334 --- /dev/null +++ b/arch/s390/lib/test_kprobes_asm.S @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#include +#include + +#define KPROBES_TARGET_START(name) \ + SYM_FUNC_START(name); \ + FTRACE_GEN_NOP_ASM(name) + +#define KPROBES_TARGET_END(name) \ + SYM_FUNC_END(name); \ + SYM_DATA(name##_offs, .quad 1b - name) + +KPROBES_TARGET_START(kprobes_target_in_insn4) + .word 0x4700 // bc 0,0 +1: .word 0x0000 + br %r14 +KPROBES_TARGET_END(kprobes_target_in_insn4) + +KPROBES_TARGET_START(kprobes_target_in_insn6_lo) + .word 0xe310 // ly 1,0 +1: .word 0x0000 + .word 0x0058 + br %r14 +KPROBES_TARGET_END(kprobes_target_in_insn6_lo) + +KPROBES_TARGET_START(kprobes_target_in_insn6_hi) + .word 0xe310 // ly 1,0 + .word 0x0000 +1: .word 0x0058 + br %r14 +KPROBES_TARGET_END(kprobes_target_in_insn6_hi) + +KPROBES_TARGET_START(kprobes_target_bp) + nop + .word 0x0000 + nop +1: br %r14 +KPROBES_TARGET_END(kprobes_target_bp) + +KPROBES_TARGET_START(kprobes_target_odd) + .byte 0x07 +1: .byte 0x07 + br %r14 +KPROBES_TARGET_END(kprobes_target_odd) -- cgit From bca2d0428e3d83b1a39ec46033e69fba8624280f Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 27 Sep 2021 14:56:47 -0700 Subject: s390/sclp_vt220: fix unused function warning When CONFIG_SCLP_VT220_TTY=y and CONFIG_SCLP_VT220_CONSOLE is not set: ../drivers/s390/char/sclp_vt220.c:771:13: warning: '__sclp_vt220_flush_buffer' defined but not used [-Wunused-function] 771 | static void __sclp_vt220_flush_buffer(void) so move this function inside the #ifdef block where it is used. Signed-off-by: Randy Dunlap Cc: Vasily Gorbik Cc: Christian Borntraeger Link: https://lore.kernel.org/r/20210927215647.11506-1-rdunlap@infradead.org Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- drivers/s390/char/sclp_vt220.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 29a6a0099f83..7bc4e4a10937 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -768,6 +768,8 @@ out_driver: } __initcall(sclp_vt220_tty_init); +#ifdef CONFIG_SCLP_VT220_CONSOLE + static void __sclp_vt220_flush_buffer(void) { unsigned long flags; @@ -784,8 +786,6 @@ static void __sclp_vt220_flush_buffer(void) spin_unlock_irqrestore(&sclp_vt220_lock, flags); } -#ifdef CONFIG_SCLP_VT220_CONSOLE - static void sclp_vt220_con_write(struct console *con, const char *buf, unsigned int count) { -- cgit From 584315ed87a7dce663ef3f07956b5f363f83c7bd Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Tue, 3 Aug 2021 19:42:32 +0200 Subject: s390/boot: initialize control registers in decompressor Partially revert commit 4555b9f34296 ("s390/boot: move dma sections from decompressor to decompressed kernel"). This is a prerequisite to allow initialization of virtual memory in decompressor and avoid overwriting of ASCEs in the decompressed kernel otherwise. Since the control registers 2, 5 and 15 are reinitialized in the decompressed kernel again, this change does not prevent relocating of amode31 section in any way. Reviewed-by: Heiko Carstens Signed-off-by: Alexander Gordeev Signed-off-by: Vasily Gorbik --- arch/s390/boot/head.S | 17 +++++++++++++++++ arch/s390/kernel/head64.S | 18 ------------------ 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/arch/s390/boot/head.S b/arch/s390/boot/head.S index 40f4cff538b8..7e843d8e794e 100644 --- a/arch/s390/boot/head.S +++ b/arch/s390/boot/head.S @@ -317,6 +317,7 @@ SYM_CODE_START_LOCAL(startup_normal) xc 0x300(256),0x300 xc 0xe00(256),0xe00 xc 0xf00(256),0xf00 + lctlg %c0,%c15,.Lctl-.LPG0(%r13) # load control registers stcke __LC_BOOT_CLOCK mvc __LC_LAST_UPDATE_CLOCK(8),__LC_BOOT_CLOCK+1 spt 6f-.LPG0(%r13) @@ -335,6 +336,22 @@ SYM_CODE_END(startup_normal) .quad 0x0000000180000000,startup_pgm_check_handler .Lio_new_psw: .quad 0x0002000180000000,0x1f0 # disabled wait +.Lctl: .quad 0x04040000 # cr0: AFP registers & secondary space + .quad 0 # cr1: primary space segment table + .quad 0 # cr2: dispatchable unit control table + .quad 0 # cr3: instruction authorization + .quad 0xffff # cr4: instruction authorization + .quad 0 # cr5: primary-aste origin + .quad 0 # cr6: I/O interrupts + .quad 0 # cr7: secondary space segment table + .quad 0x0000000000008000 # cr8: access registers translation + .quad 0 # cr9: tracing off + .quad 0 # cr10: tracing off + .quad 0 # cr11: tracing off + .quad 0 # cr12: tracing off + .quad 0 # cr13: home space segment table + .quad 0xc0000000 # cr14: machine check handling off + .quad 0 # cr15: linkage stack operations #include "head_kdump.S" diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index 114b5490ad8e..42f9a325a257 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S @@ -20,8 +20,6 @@ __HEAD ENTRY(startup_continue) larl %r1,tod_clock_base mvc 0(16,%r1),__LC_BOOT_CLOCK - larl %r13,.LPG1 # get base - lctlg %c0,%c15,.Lctl-.LPG1(%r13) # load control registers # # Setup stack # @@ -42,19 +40,3 @@ ENTRY(startup_continue) .align 16 .LPG1: .Ldw: .quad 0x0002000180000000,0x0000000000000000 -.Lctl: .quad 0x04040000 # cr0: AFP registers & secondary space - .quad 0 # cr1: primary space segment table - .quad 0 # cr2: dispatchable unit control table - .quad 0 # cr3: instruction authorization - .quad 0xffff # cr4: instruction authorization - .quad 0 # cr5: primary-aste origin - .quad 0 # cr6: I/O interrupts - .quad 0 # cr7: secondary space segment table - .quad 0x0000000000008000 # cr8: access registers translation - .quad 0 # cr9: tracing off - .quad 0 # cr10: tracing off - .quad 0 # cr11: tracing off - .quad 0 # cr12: tracing off - .quad 0 # cr13: home space segment table - .quad 0xc0000000 # cr14: machine check handling off - .quad 0 # cr15: linkage stack operations -- cgit From e3ec8e0f5711d73f7e5d5c3cffdf4fad4f1487b9 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Mon, 27 Sep 2021 14:18:26 +0200 Subject: s390/boot: allocate amode31 section in decompressor The memory for amode31 section is allocated from the decompressed kernel. Instead, allocate that memory from the decompressor. This is a prerequisite to allow initialization of the virtual memory before the decompressed kernel takes over. Reviewed-by: Heiko Carstens Signed-off-by: Alexander Gordeev Signed-off-by: Vasily Gorbik --- arch/s390/boot/compressed/decompressor.h | 1 + arch/s390/boot/startup.c | 8 ++++++++ arch/s390/kernel/entry.h | 1 + arch/s390/kernel/setup.c | 22 +++++++++------------- arch/s390/kernel/vmlinux.lds.S | 1 + 5 files changed, 20 insertions(+), 13 deletions(-) diff --git a/arch/s390/boot/compressed/decompressor.h b/arch/s390/boot/compressed/decompressor.h index a59f75c5b049..f75cc31a77dd 100644 --- a/arch/s390/boot/compressed/decompressor.h +++ b/arch/s390/boot/compressed/decompressor.h @@ -24,6 +24,7 @@ struct vmlinux_info { unsigned long dynsym_start; unsigned long rela_dyn_start; unsigned long rela_dyn_end; + unsigned long amode31_size; }; /* Symbols defined by linker scripts */ diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c index 6dc8d0a53864..7571dee72a0c 100644 --- a/arch/s390/boot/startup.c +++ b/arch/s390/boot/startup.c @@ -15,6 +15,7 @@ #include "uv.h" unsigned long __bootdata_preserved(__kaslr_offset); +unsigned long __bootdata(__amode31_base); unsigned long __bootdata_preserved(VMALLOC_START); unsigned long __bootdata_preserved(VMALLOC_END); struct page *__bootdata_preserved(vmemmap); @@ -259,6 +260,12 @@ static void offset_vmlinux_info(unsigned long offset) vmlinux.dynsym_start += offset; } +static unsigned long reserve_amode31(unsigned long safe_addr) +{ + __amode31_base = PAGE_ALIGN(safe_addr); + return safe_addr + vmlinux.amode31_size; +} + void startup_kernel(void) { unsigned long random_lma; @@ -273,6 +280,7 @@ void startup_kernel(void) setup_lpp(); store_ipl_parmblock(); safe_addr = mem_safe_offset(); + safe_addr = reserve_amode31(safe_addr); safe_addr = read_ipl_report(safe_addr); uv_query_info(); rescue_initrd(safe_addr); diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h index 7f2696e8d511..6083090be1f4 100644 --- a/arch/s390/kernel/entry.h +++ b/arch/s390/kernel/entry.h @@ -70,5 +70,6 @@ extern struct exception_table_entry _stop_amode31_ex_table[]; #define __amode31_data __section(".amode31.data") #define __amode31_ref __section(".amode31.refs") extern long _start_amode31_refs[], _end_amode31_refs[]; +extern unsigned long __amode31_base; #endif /* _ENTRY_H */ diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 67e5fff96ee0..191fc96a41b2 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -95,10 +95,10 @@ EXPORT_SYMBOL(console_irq); * relocated above 2 GB, because it has to use 31 bit addresses. * Such code and data is part of the .amode31 section. */ -unsigned long __amode31_ref __samode31 = __pa(&_samode31); -unsigned long __amode31_ref __eamode31 = __pa(&_eamode31); -unsigned long __amode31_ref __stext_amode31 = __pa(&_stext_amode31); -unsigned long __amode31_ref __etext_amode31 = __pa(&_etext_amode31); +unsigned long __amode31_ref __samode31 = (unsigned long)&_samode31; +unsigned long __amode31_ref __eamode31 = (unsigned long)&_eamode31; +unsigned long __amode31_ref __stext_amode31 = (unsigned long)&_stext_amode31; +unsigned long __amode31_ref __etext_amode31 = (unsigned long)&_etext_amode31; struct exception_table_entry __amode31_ref *__start_amode31_ex_table = _start_amode31_ex_table; struct exception_table_entry __amode31_ref *__stop_amode31_ex_table = _stop_amode31_ex_table; @@ -149,6 +149,7 @@ struct mem_detect_info __bootdata(mem_detect); struct initrd_data __bootdata(initrd_data); unsigned long __bootdata_preserved(__kaslr_offset); +unsigned long __bootdata(__amode31_base); unsigned int __bootdata_preserved(zlib_dfltcc_support); EXPORT_SYMBOL(zlib_dfltcc_support); u64 __bootdata_preserved(stfle_fac_list[16]); @@ -808,6 +809,7 @@ static void __init reserve_kernel(void) memblock_reserve(0, STARTUP_NORMAL_OFFSET); memblock_reserve((unsigned long)sclp_early_sccb, EXT_SCCB_READ_SCP); + memblock_reserve(__amode31_base, __eamode31 - __samode31); memblock_reserve((unsigned long)_stext, PFN_PHYS(start_pfn) - (unsigned long)_stext); } @@ -831,20 +833,14 @@ static void __init setup_memory(void) static void __init relocate_amode31_section(void) { - unsigned long amode31_addr, amode31_size; - long amode31_offset; + unsigned long amode31_size = __eamode31 - __samode31; + long amode31_offset = __amode31_base - __samode31; long *ptr; - /* Allocate a new AMODE31 capable memory region */ - amode31_size = __eamode31 - __samode31; pr_info("Relocating AMODE31 section of size 0x%08lx\n", amode31_size); - amode31_addr = (unsigned long)memblock_alloc_low(amode31_size, PAGE_SIZE); - if (!amode31_addr) - panic("Failed to allocate memory for AMODE31 section\n"); - amode31_offset = amode31_addr - __samode31; /* Move original AMODE31 section to the new one */ - memmove((void *)amode31_addr, (void *)__samode31, amode31_size); + memmove((void *)__amode31_base, (void *)__samode31, amode31_size); /* Zero out the old AMODE31 section to catch invalid accesses within it */ memset((void *)__samode31, 0, amode31_size); diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index 63bdb9e1bfc1..42c43521878f 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -212,6 +212,7 @@ SECTIONS QUAD(__dynsym_start) /* dynsym_start */ QUAD(__rela_dyn_start) /* rela_dyn_start */ QUAD(__rela_dyn_end) /* rela_dyn_end */ + QUAD(_eamode31 - _samode31) /* amode31_size */ } :NONE /* Debugging sections. */ -- cgit From 11dfe199eb31079a6f2517a59c380ad55f156696 Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Mon, 27 Sep 2021 15:02:30 -0700 Subject: s390/block/dasd_genhd: add error handling support for add_disk() We never checked for errors on add_disk() as this function returned void. Now that this is fixed, use the shiny new error handling. Be sure to call dasd_gendisk_free() on error. Signed-off-by: Luis Chamberlain Link: https://lore.kernel.org/r/20210927220232.1071926-5-mcgrof@kernel.org Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- drivers/s390/block/dasd_genhd.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c index fa966e0db6ca..80673dbfb1f9 100644 --- a/drivers/s390/block/dasd_genhd.c +++ b/drivers/s390/block/dasd_genhd.c @@ -33,7 +33,7 @@ int dasd_gendisk_alloc(struct dasd_block *block) { struct gendisk *gdp; struct dasd_device *base; - int len; + int len, rc; /* Make sure the minor for this device exists. */ base = block->base; @@ -79,7 +79,13 @@ int dasd_gendisk_alloc(struct dasd_block *block) dasd_add_link_to_gendisk(gdp, base); block->gdp = gdp; set_capacity(block->gdp, 0); - device_add_disk(&base->cdev->dev, block->gdp, NULL); + + rc = device_add_disk(&base->cdev->dev, block->gdp, NULL); + if (rc) { + dasd_gendisk_free(block); + return rc; + } + return 0; } -- cgit From 1a5db707c859a4f63c1066c5b88864d3f1c21c12 Mon Sep 17 00:00:00 2001 From: Gerald Schaefer Date: Mon, 27 Sep 2021 15:02:31 -0700 Subject: s390/block/dcssblk: add error handling support for add_disk() We never checked for errors on add_disk() as this function returned void. Now that this is fixed, use the shiny new error handling. Signed-off-by: Luis Chamberlain Signed-off-by: Gerald Schaefer Link: https://lore.kernel.org/r/20210927220232.1071926-6-mcgrof@kernel.org Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- drivers/s390/block/dcssblk.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 5be3d1c39a78..0741a9321712 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -696,7 +696,9 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char } get_device(&dev_info->dev); - device_add_disk(&dev_info->dev, dev_info->gd, NULL); + rc = device_add_disk(&dev_info->dev, dev_info->gd, NULL); + if (rc) + goto out_dax; switch (dev_info->segment_type) { case SEG_TYPE_SR: @@ -712,6 +714,10 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char rc = count; goto out; +out_dax: + put_device(&dev_info->dev); + kill_dax(dev_info->dax_dev); + put_dax(dev_info->dax_dev); put_dev: list_del(&dev_info->lh); blk_cleanup_disk(dev_info->gd); -- cgit From f367c7d9fb326996862f6b5cf2aff7a2df64692d Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Mon, 27 Sep 2021 15:02:32 -0700 Subject: s390/block/scm_blk: add error handling support for add_disk() We never checked for errors on add_disk() as this function returned void. Now that this is fixed, use the shiny new error handling. Acked-by: Heiko Carstens Signed-off-by: Luis Chamberlain Link: https://lore.kernel.org/r/20210927220232.1071926-7-mcgrof@kernel.org Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- drivers/s390/block/scm_blk.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/s390/block/scm_blk.c b/drivers/s390/block/scm_blk.c index 88cba6212ee2..61ecdcb2cc6a 100644 --- a/drivers/s390/block/scm_blk.c +++ b/drivers/s390/block/scm_blk.c @@ -495,9 +495,14 @@ int scm_blk_dev_setup(struct scm_blk_dev *bdev, struct scm_device *scmdev) /* 512 byte sectors */ set_capacity(bdev->gendisk, scmdev->size >> 9); - device_add_disk(&scmdev->dev, bdev->gendisk, NULL); + ret = device_add_disk(&scmdev->dev, bdev->gendisk, NULL); + if (ret) + goto out_cleanup_disk; + return 0; +out_cleanup_disk: + blk_cleanup_disk(bdev->gendisk); out_tag: blk_mq_free_tag_set(&bdev->tag_set); out: -- cgit From 3734b9f2cee01d9dde2fbbda742ba6dd6ba10a29 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 27 Sep 2021 01:40:24 +0300 Subject: opp: Change type of dev_pm_opp_attach_genpd(names) argument Elements of the 'names' array are not changed by the code, constify them for consistency. Signed-off-by: Dmitry Osipenko Signed-off-by: Viresh Kumar --- drivers/opp/core.c | 6 +++--- include/linux/pm_opp.h | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/opp/core.c b/drivers/opp/core.c index 04b4691a8aac..3057beabd370 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -2348,12 +2348,12 @@ static void _opp_detach_genpd(struct opp_table *opp_table) * "required-opps" are added in DT. */ struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, - const char **names, struct device ***virt_devs) + const char * const *names, struct device ***virt_devs) { struct opp_table *opp_table; struct device *virt_dev; int index = 0, ret = -EINVAL; - const char **name = names; + const char * const *name = names; opp_table = _add_opp_table(dev, false); if (IS_ERR(opp_table)) @@ -2457,7 +2457,7 @@ static void devm_pm_opp_detach_genpd(void *data) * * Return: 0 on success and errorno otherwise. */ -int devm_pm_opp_attach_genpd(struct device *dev, const char **names, +int devm_pm_opp_attach_genpd(struct device *dev, const char * const *names, struct device ***virt_devs) { struct opp_table *opp_table; diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index 84150a22fd7c..7f1f066fc377 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h @@ -156,9 +156,9 @@ int devm_pm_opp_set_clkname(struct device *dev, const char *name); struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data)); void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table); int devm_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data)); -struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char **names, struct device ***virt_devs); +struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char * const *names, struct device ***virt_devs); void dev_pm_opp_detach_genpd(struct opp_table *opp_table); -int devm_pm_opp_attach_genpd(struct device *dev, const char **names, struct device ***virt_devs); +int devm_pm_opp_attach_genpd(struct device *dev, const char * const *names, struct device ***virt_devs); struct dev_pm_opp *dev_pm_opp_xlate_required_opp(struct opp_table *src_table, struct opp_table *dst_table, struct dev_pm_opp *src_opp); int dev_pm_opp_xlate_performance_state(struct opp_table *src_table, struct opp_table *dst_table, unsigned int pstate); int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq); @@ -376,7 +376,7 @@ static inline int devm_pm_opp_set_clkname(struct device *dev, const char *name) return -EOPNOTSUPP; } -static inline struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char **names, struct device ***virt_devs) +static inline struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char * const *names, struct device ***virt_devs) { return ERR_PTR(-EOPNOTSUPP); } @@ -384,7 +384,7 @@ static inline struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, cons static inline void dev_pm_opp_detach_genpd(struct opp_table *opp_table) {} static inline int devm_pm_opp_attach_genpd(struct device *dev, - const char **names, + const char * const *names, struct device ***virt_devs) { return -EOPNOTSUPP; -- cgit From e69709f6861aaba80b4eaab6825e8c522a2afb5c Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 20 Sep 2021 20:22:46 +0300 Subject: opp: Add more resource-managed variants of dev_pm_opp_of_add_table() Add resource-managed variants of dev_pm_opp_of_add_table_indexed() and dev_pm_opp_of_add_table_noclk(), allowing drivers to remove boilerplate code. Signed-off-by: Dmitry Osipenko [ Viresh: Added underscore to devm_of_add_table_indexed() ] Signed-off-by: Viresh Kumar --- drivers/opp/of.c | 46 +++++++++++++++++++++++++++++++++++++++------- include/linux/pm_opp.h | 12 ++++++++++++ 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/drivers/opp/of.c b/drivers/opp/of.c index 5437085fb380..fe218af735b0 100644 --- a/drivers/opp/of.c +++ b/drivers/opp/of.c @@ -1081,6 +1081,17 @@ static void devm_pm_opp_of_table_release(void *data) dev_pm_opp_of_remove_table(data); } +static int _devm_of_add_table_indexed(struct device *dev, int index, bool getclk) +{ + int ret; + + ret = _of_add_table_indexed(dev, index, getclk); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, devm_pm_opp_of_table_release, dev); +} + /** * devm_pm_opp_of_add_table() - Initialize opp table from device tree * @dev: device pointer used to lookup OPP table. @@ -1102,13 +1113,7 @@ static void devm_pm_opp_of_table_release(void *data) */ int devm_pm_opp_of_add_table(struct device *dev) { - int ret; - - ret = dev_pm_opp_of_add_table(dev); - if (ret) - return ret; - - return devm_add_action_or_reset(dev, devm_pm_opp_of_table_release, dev); + return _devm_of_add_table_indexed(dev, 0, true); } EXPORT_SYMBOL_GPL(devm_pm_opp_of_add_table); @@ -1151,6 +1156,19 @@ int dev_pm_opp_of_add_table_indexed(struct device *dev, int index) } EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table_indexed); +/** + * devm_pm_opp_of_add_table_indexed() - Initialize indexed opp table from device tree + * @dev: device pointer used to lookup OPP table. + * @index: Index number. + * + * This is a resource-managed variant of dev_pm_opp_of_add_table_indexed(). + */ +int devm_pm_opp_of_add_table_indexed(struct device *dev, int index) +{ + return _devm_of_add_table_indexed(dev, index, true); +} +EXPORT_SYMBOL_GPL(devm_pm_opp_of_add_table_indexed); + /** * dev_pm_opp_of_add_table_noclk() - Initialize indexed opp table from device * tree without getting clk for device. @@ -1169,6 +1187,20 @@ int dev_pm_opp_of_add_table_noclk(struct device *dev, int index) } EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table_noclk); +/** + * devm_pm_opp_of_add_table_noclk() - Initialize indexed opp table from device + * tree without getting clk for device. + * @dev: device pointer used to lookup OPP table. + * @index: Index number. + * + * This is a resource-managed variant of dev_pm_opp_of_add_table_noclk(). + */ +int devm_pm_opp_of_add_table_noclk(struct device *dev, int index) +{ + return _devm_of_add_table_indexed(dev, index, false); +} +EXPORT_SYMBOL_GPL(devm_pm_opp_of_add_table_noclk); + /* CPU device specific helpers */ /** diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index 7f1f066fc377..879c138c7b8e 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h @@ -439,7 +439,9 @@ static inline int dev_pm_opp_sync_regulators(struct device *dev) #if defined(CONFIG_PM_OPP) && defined(CONFIG_OF) int dev_pm_opp_of_add_table(struct device *dev); int dev_pm_opp_of_add_table_indexed(struct device *dev, int index); +int devm_pm_opp_of_add_table_indexed(struct device *dev, int index); int dev_pm_opp_of_add_table_noclk(struct device *dev, int index); +int devm_pm_opp_of_add_table_noclk(struct device *dev, int index); void dev_pm_opp_of_remove_table(struct device *dev); int devm_pm_opp_of_add_table(struct device *dev); int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask); @@ -465,11 +467,21 @@ static inline int dev_pm_opp_of_add_table_indexed(struct device *dev, int index) return -EOPNOTSUPP; } +static inline int devm_pm_opp_of_add_table_indexed(struct device *dev, int index) +{ + return -EOPNOTSUPP; +} + static inline int dev_pm_opp_of_add_table_noclk(struct device *dev, int index) { return -EOPNOTSUPP; } +static inline int devm_pm_opp_of_add_table_noclk(struct device *dev, int index) +{ + return -EOPNOTSUPP; +} + static inline void dev_pm_opp_of_remove_table(struct device *dev) { } -- cgit From be8ecc57f180415e8a7c1cc5620c5236be2a7e56 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Thu, 16 Sep 2021 14:09:39 +0200 Subject: perf srcline: Use long-running addr2line per DSO Invoking addr2line in a separate subprocess, one for each required lookup, takes a terribly long time. This patch introduces a long-running addr2line process for each DSO, *DRAMATICALLY* speeding up runs of perf. What used to take tens of minutes now takes tens of seconds. Debian bug report about this issue: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=911815 Signed-off-by: Tony Garnock-Jones Tested-by: Ian Rogers Cc: Ingo Molnar Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20210916120939.453536-1-tonyg@leastfixedpoint.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/srcline.c | 338 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 250 insertions(+), 88 deletions(-) diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c index 5b7d6c16d33f..af468e3bb6fa 100644 --- a/tools/perf/util/srcline.c +++ b/tools/perf/util/srcline.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 #include +#include #include #include #include +#include #include #include @@ -15,6 +17,7 @@ #include "srcline.h" #include "string2.h" #include "symbol.h" +#include "subcmd/run-command.h" bool srcline_full_filename; @@ -119,6 +122,8 @@ static struct symbol *new_inline_sym(struct dso *dso, return inline_sym; } +#define MAX_INLINE_NEST 1024 + #ifdef HAVE_LIBBFD_SUPPORT /* @@ -273,8 +278,6 @@ static void addr2line_cleanup(struct a2l_data *a2l) free(a2l); } -#define MAX_INLINE_NEST 1024 - static int inline_list__append_dso_a2l(struct dso *dso, struct inline_node *node, struct symbol *sym) @@ -361,26 +364,14 @@ void dso__free_a2l(struct dso *dso) dso->a2l = NULL; } -static struct inline_node *addr2inlines(const char *dso_name, u64 addr, - struct dso *dso, struct symbol *sym) -{ - struct inline_node *node; - - node = zalloc(sizeof(*node)); - if (node == NULL) { - perror("not enough memory for the inline node"); - return NULL; - } - - INIT_LIST_HEAD(&node->val); - node->addr = addr; - - addr2line(dso_name, addr, NULL, NULL, dso, true, node, sym); - return node; -} - #else /* HAVE_LIBBFD_SUPPORT */ +struct a2l_subprocess { + struct child_process addr2line; + FILE *to_child; + FILE *from_child; +}; + static int filename_split(char *filename, unsigned int *line_nr) { char *sep; @@ -402,114 +393,285 @@ static int filename_split(char *filename, unsigned int *line_nr) return 0; } -static int addr2line(const char *dso_name, u64 addr, - char **file, unsigned int *line_nr, - struct dso *dso __maybe_unused, - bool unwind_inlines __maybe_unused, - struct inline_node *node __maybe_unused, - struct symbol *sym __maybe_unused) +static void addr2line_subprocess_cleanup(struct a2l_subprocess *a2l) { - FILE *fp; - char cmd[PATH_MAX]; - char *filename = NULL; - size_t len; - int ret = 0; + if (a2l->addr2line.pid != -1) { + kill(a2l->addr2line.pid, SIGKILL); + finish_command(&a2l->addr2line); /* ignore result, we don't care */ + a2l->addr2line.pid = -1; + } - scnprintf(cmd, sizeof(cmd), "addr2line -e %s %016"PRIx64, - dso_name, addr); + if (a2l->to_child != NULL) { + fclose(a2l->to_child); + a2l->to_child = NULL; + } - fp = popen(cmd, "r"); - if (fp == NULL) { - pr_warning("popen failed for %s\n", dso_name); - return 0; + if (a2l->from_child != NULL) { + fclose(a2l->from_child); + a2l->from_child = NULL; + } + + free(a2l); +} + +static struct a2l_subprocess *addr2line_subprocess_init(const char *path) +{ + const char *argv[] = { "addr2line", "-e", path, "-i", "-f", NULL }; + struct a2l_subprocess *a2l = zalloc(sizeof(*a2l)); + int start_command_status = 0; + + if (a2l == NULL) + goto out; + + a2l->to_child = NULL; + a2l->from_child = NULL; + + a2l->addr2line.pid = -1; + a2l->addr2line.in = -1; + a2l->addr2line.out = -1; + a2l->addr2line.no_stderr = 1; + + a2l->addr2line.argv = argv; + start_command_status = start_command(&a2l->addr2line); + a2l->addr2line.argv = NULL; /* it's not used after start_command; avoid dangling pointers */ + + if (start_command_status != 0) { + pr_warning("could not start addr2line for %s: start_command return code %d\n", + path, + start_command_status); + goto out; } - if (getline(&filename, &len, fp) < 0 || !len) { - pr_warning("addr2line has no output for %s\n", dso_name); + a2l->to_child = fdopen(a2l->addr2line.in, "w"); + if (a2l->to_child == NULL) { + pr_warning("could not open write-stream to addr2line of %s\n", path); goto out; } - ret = filename_split(filename, line_nr); - if (ret != 1) { - free(filename); + a2l->from_child = fdopen(a2l->addr2line.out, "r"); + if (a2l->from_child == NULL) { + pr_warning("could not open read-stream from addr2line of %s\n", path); goto out; } - *file = filename; + return a2l; out: - pclose(fp); - return ret; + if (a2l) + addr2line_subprocess_cleanup(a2l); + + return NULL; } -void dso__free_a2l(struct dso *dso __maybe_unused) +static int read_addr2line_record(struct a2l_subprocess *a2l, + char **function, + char **filename, + unsigned int *line_nr) { + /* + * Returns: + * -1 ==> error + * 0 ==> sentinel (or other ill-formed) record read + * 1 ==> a genuine record read + */ + char *line = NULL; + size_t line_len = 0; + unsigned int dummy_line_nr = 0; + int ret = -1; + + if (function != NULL) + zfree(function); + + if (filename != NULL) + zfree(filename); + + if (line_nr != NULL) + *line_nr = 0; + + if (getline(&line, &line_len, a2l->from_child) < 0 || !line_len) + goto error; + + if (function != NULL) + *function = strdup(strim(line)); + + zfree(&line); + line_len = 0; + + if (getline(&line, &line_len, a2l->from_child) < 0 || !line_len) + goto error; + + if (filename_split(line, line_nr == NULL ? &dummy_line_nr : line_nr) == 0) { + ret = 0; + goto error; + } + + if (filename != NULL) + *filename = strdup(line); + + zfree(&line); + line_len = 0; + + return 1; + +error: + free(line); + if (function != NULL) + zfree(function); + if (filename != NULL) + zfree(filename); + return ret; } -static struct inline_node *addr2inlines(const char *dso_name, u64 addr, - struct dso *dso __maybe_unused, - struct symbol *sym) +static int inline_list__append_record(struct dso *dso, + struct inline_node *node, + struct symbol *sym, + const char *function, + const char *filename, + unsigned int line_nr) { - FILE *fp; - char cmd[PATH_MAX]; - struct inline_node *node; - char *filename = NULL; - char *funcname = NULL; - size_t filelen, funclen; - unsigned int line_nr = 0; + struct symbol *inline_sym = new_inline_sym(dso, sym, function); - scnprintf(cmd, sizeof(cmd), "addr2line -e %s -i -f %016"PRIx64, - dso_name, addr); + return inline_list__append(inline_sym, srcline_from_fileline(filename, line_nr), node); +} - fp = popen(cmd, "r"); - if (fp == NULL) { - pr_err("popen failed for %s\n", dso_name); - return NULL; +static int addr2line(const char *dso_name, u64 addr, + char **file, unsigned int *line_nr, + struct dso *dso, + bool unwind_inlines, + struct inline_node *node, + struct symbol *sym __maybe_unused) +{ + struct a2l_subprocess *a2l = dso->a2l; + char *record_function = NULL; + char *record_filename = NULL; + unsigned int record_line_nr = 0; + int record_status = -1; + int ret = 0; + size_t inline_count = 0; + + if (!a2l) { + dso->a2l = addr2line_subprocess_init(dso_name); + a2l = dso->a2l; } - node = zalloc(sizeof(*node)); - if (node == NULL) { - perror("not enough memory for the inline node"); + if (a2l == NULL) { + if (!symbol_conf.disable_add2line_warn) + pr_warning("%s %s: addr2line_subprocess_init failed\n", __func__, dso_name); goto out; } - INIT_LIST_HEAD(&node->val); - node->addr = addr; - - /* addr2line -f generates two lines for each inlined functions */ - while (getline(&funcname, &funclen, fp) != -1) { - char *srcline; - struct symbol *inline_sym; + /* + * Send our request and then *deliberately* send something that can't be interpreted as + * a valid address to ask addr2line about (namely, ","). This causes addr2line to first + * write out the answer to our request, in an unbounded/unknown number of records, and + * then to write out the lines "??" and "??:0", so that we can detect when it has + * finished giving us anything useful. We have to be careful about the first record, + * though, because it may be genuinely unknown, in which case we'll get two sets of + * "??"/"??:0" lines. + */ + if (fprintf(a2l->to_child, "%016"PRIx64"\n,\n", addr) < 0 || fflush(a2l->to_child) != 0) { + pr_warning("%s %s: could not send request\n", __func__, dso_name); + goto out; + } - strim(funcname); + switch (read_addr2line_record(a2l, &record_function, &record_filename, &record_line_nr)) { + case -1: + pr_warning("%s %s: could not read first record\n", __func__, dso_name); + goto out; + case 0: + /* + * The first record was invalid, so return failure, but first read another + * record, since we asked a junk question and have to clear the answer out. + */ + switch (read_addr2line_record(a2l, NULL, NULL, NULL)) { + case -1: + pr_warning("%s %s: could not read delimiter record\n", __func__, dso_name); + break; + case 0: + /* As expected. */ + break; + default: + pr_warning("%s %s: unexpected record instead of sentinel", + __func__, dso_name); + break; + } + goto out; + default: + break; + } - if (getline(&filename, &filelen, fp) == -1) - goto out; + if (file) { + *file = strdup(record_filename); + ret = 1; + } + if (line_nr) + *line_nr = record_line_nr; - if (filename_split(filename, &line_nr) != 1) + if (unwind_inlines) { + if (node && inline_list__append_record(dso, node, sym, + record_function, + record_filename, + record_line_nr)) { + ret = 0; goto out; + } + } - srcline = srcline_from_fileline(filename, line_nr); - inline_sym = new_inline_sym(dso, sym, funcname); - - if (inline_list__append(inline_sym, srcline, node) != 0) { - free(srcline); - if (inline_sym && inline_sym->inlined) - symbol__delete(inline_sym); - goto out; + /* We have to read the records even if we don't care about the inline info. */ + while ((record_status = read_addr2line_record(a2l, + &record_function, + &record_filename, + &record_line_nr)) == 1) { + if (unwind_inlines && node && inline_count++ < MAX_INLINE_NEST) { + if (inline_list__append_record(dso, node, sym, + record_function, + record_filename, + record_line_nr)) { + ret = 0; + goto out; + } + ret = 1; /* found at least one inline frame */ } } out: - pclose(fp); - free(filename); - free(funcname); + free(record_function); + free(record_filename); + return ret; +} - return node; +void dso__free_a2l(struct dso *dso) +{ + struct a2l_subprocess *a2l = dso->a2l; + + if (!a2l) + return; + + addr2line_subprocess_cleanup(a2l); + + dso->a2l = NULL; } #endif /* HAVE_LIBBFD_SUPPORT */ +static struct inline_node *addr2inlines(const char *dso_name, u64 addr, + struct dso *dso, struct symbol *sym) +{ + struct inline_node *node; + + node = zalloc(sizeof(*node)); + if (node == NULL) { + perror("not enough memory for the inline node"); + return NULL; + } + + INIT_LIST_HEAD(&node->val); + node->addr = addr; + + addr2line(dso_name, addr, NULL, NULL, dso, true, node, sym); + return node; +} + /* * Number of addr2line failures (without success) before disabling it for that * dso. -- cgit From faf88ed1c083017d1f4478f45c4f375e7a3f8bdc Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 4 Oct 2021 13:52:57 +0300 Subject: remoteproc: meson-mx-ao-arc: fix a bit test The MESON_AO_RPROC_SRAM_USABLE_BITS macro is used like this: if (priv->sram_pa & ~MESON_AO_RPROC_SRAM_USABLE_BITS) { dev_err(dev, "SRAM address contains unusable bits\n"); The problem is that "->sram_pa" is type phys_addr_t which is potentially 64 bits. That means the MESON_AO_RPROC_SRAM_USABLE_BITS macro needs to be a 64 bit type as well to ensure that high 32 bits are cleared. Fixes: 6cb58ea897dd ("remoteproc: meson-mx-ao-arc: Add a driver for the AO ARC remote procesor") Signed-off-by: Dan Carpenter Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211004105257.GA27301@kili --- drivers/remoteproc/meson_mx_ao_arc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/remoteproc/meson_mx_ao_arc.c b/drivers/remoteproc/meson_mx_ao_arc.c index 3d8f927ae448..462cddab6518 100644 --- a/drivers/remoteproc/meson_mx_ao_arc.c +++ b/drivers/remoteproc/meson_mx_ao_arc.c @@ -39,7 +39,7 @@ #define AO_SECURE_REG0_AHB_SRAM_BITS_19_12 GENMASK(15, 8) /* Only bits [31:20] and [17:14] are usable, all other bits must be zero */ -#define MESON_AO_RPROC_SRAM_USABLE_BITS 0xfff3c000 +#define MESON_AO_RPROC_SRAM_USABLE_BITS 0xfff3c000ULL #define MESON_AO_RPROC_MEMORY_OFFSET 0x10000000 -- cgit From 8dcc5721da7888685dde82be765018c8a379298c Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 4 Oct 2021 10:16:08 -0400 Subject: svcrdma: Split the svcrdma_wc_receive() tracepoint There are currently three separate purposes being served by a single tracepoint here. They need to be split up. svcrdma_wc_recv: - status is always zero, so there's no value in recording it. - vendor_err is meaningless unless status is not zero, so there's no value in recording it. - This tracepoint is needed only when developing modifications, so it should be left disabled most of the time. svcrdma_wc_recv_flush: - As above, needed only rarely, and not an error. svcrdma_wc_recv_err: - received is always zero, so there's no value in recording it. - This tracepoint can be left enabled because completion errors are run-time problems (except for FLUSHED_ERR). - Tracepoint name now ends in _err to reflect its purpose. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- include/trace/events/rpcrdma.h | 75 ++++++++++++++++++++++++++++++++- net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 9 +++- 2 files changed, 81 insertions(+), 3 deletions(-) diff --git a/include/trace/events/rpcrdma.h b/include/trace/events/rpcrdma.h index de4195499592..342d6d7b5cd9 100644 --- a/include/trace/events/rpcrdma.h +++ b/include/trace/events/rpcrdma.h @@ -145,6 +145,77 @@ DECLARE_EVENT_CLASS(rpcrdma_receive_completion_class, ), \ TP_ARGS(wc, cid)) +DECLARE_EVENT_CLASS(rpcrdma_receive_success_class, + TP_PROTO( + const struct ib_wc *wc, + const struct rpc_rdma_cid *cid + ), + + TP_ARGS(wc, cid), + + TP_STRUCT__entry( + __field(u32, cq_id) + __field(int, completion_id) + __field(u32, received) + ), + + TP_fast_assign( + __entry->cq_id = cid->ci_queue_id; + __entry->completion_id = cid->ci_completion_id; + __entry->received = wc->byte_len; + ), + + TP_printk("cq.id=%u cid=%d received=%u", + __entry->cq_id, __entry->completion_id, + __entry->received + ) +); + +#define DEFINE_RECEIVE_SUCCESS_EVENT(name) \ + DEFINE_EVENT(rpcrdma_receive_success_class, name, \ + TP_PROTO( \ + const struct ib_wc *wc, \ + const struct rpc_rdma_cid *cid \ + ), \ + TP_ARGS(wc, cid)) + +DECLARE_EVENT_CLASS(rpcrdma_receive_flush_class, + TP_PROTO( + const struct ib_wc *wc, + const struct rpc_rdma_cid *cid + ), + + TP_ARGS(wc, cid), + + TP_STRUCT__entry( + __field(u32, cq_id) + __field(int, completion_id) + __field(unsigned long, status) + __field(unsigned int, vendor_err) + ), + + TP_fast_assign( + __entry->cq_id = cid->ci_queue_id; + __entry->completion_id = cid->ci_completion_id; + __entry->status = wc->status; + __entry->vendor_err = wc->vendor_err; + ), + + TP_printk("cq.id=%u cid=%d status=%s (%lu/0x%x)", + __entry->cq_id, __entry->completion_id, + rdma_show_wc_status(__entry->status), + __entry->status, __entry->vendor_err + ) +); + +#define DEFINE_RECEIVE_FLUSH_EVENT(name) \ + DEFINE_EVENT(rpcrdma_receive_flush_class, name, \ + TP_PROTO( \ + const struct ib_wc *wc, \ + const struct rpc_rdma_cid *cid \ + ), \ + TP_ARGS(wc, cid)) + DECLARE_EVENT_CLASS(xprtrdma_reply_class, TP_PROTO( const struct rpcrdma_rep *rep @@ -1892,7 +1963,9 @@ TRACE_EVENT(svcrdma_post_recv, ) ); -DEFINE_RECEIVE_COMPLETION_EVENT(svcrdma_wc_receive); +DEFINE_RECEIVE_SUCCESS_EVENT(svcrdma_wc_recv); +DEFINE_RECEIVE_FLUSH_EVENT(svcrdma_wc_recv_flush); +DEFINE_RECEIVE_FLUSH_EVENT(svcrdma_wc_recv_err); TRACE_EVENT(svcrdma_rq_post_err, TP_PROTO( diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c index 6be23ce7a93d..cf76a6ad127b 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c @@ -330,9 +330,9 @@ static void svc_rdma_wc_receive(struct ib_cq *cq, struct ib_wc *wc) /* WARNING: Only wc->wr_cqe and wc->status are reliable */ ctxt = container_of(cqe, struct svc_rdma_recv_ctxt, rc_cqe); - trace_svcrdma_wc_receive(wc, &ctxt->rc_cid); if (wc->status != IB_WC_SUCCESS) goto flushed; + trace_svcrdma_wc_recv(wc, &ctxt->rc_cid); /* If receive posting fails, the connection is about to be * lost anyway. The server will not be able to send a reply @@ -345,7 +345,7 @@ static void svc_rdma_wc_receive(struct ib_cq *cq, struct ib_wc *wc) */ if (rdma->sc_pending_recvs < rdma->sc_max_requests) if (!svc_rdma_refresh_recvs(rdma, rdma->sc_recv_batch, false)) - goto flushed; + goto dropped; /* All wc fields are now known to be valid */ ctxt->rc_byte_len = wc->byte_len; @@ -360,6 +360,11 @@ static void svc_rdma_wc_receive(struct ib_cq *cq, struct ib_wc *wc) return; flushed: + if (wc->status == IB_WC_WR_FLUSH_ERR) + trace_svcrdma_wc_recv_flush(wc, &ctxt->rc_cid); + else + trace_svcrdma_wc_recv_err(wc, &ctxt->rc_cid); +dropped: svc_rdma_recv_ctxt_put(rdma, ctxt); svc_xprt_deferred_close(&rdma->sc_xprt); } -- cgit From eef2d8d47c33aba5f430fc5f91a17e360f99a591 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 4 Oct 2021 10:16:14 -0400 Subject: svcrdma: Split the svcrdma_wc_send() tracepoint There are currently three separate purposes being served by a single tracepoint here. They need to be split up. svcrdma_wc_send: - status is always zero, so there's no value in recording it. - vendor_err is meaningless unless status is not zero, so there's no value in recording it. - This tracepoint is needed only when developing modifications, so it should be left disabled most of the time. svcrdma_wc_send_flush: - As above, needed only rarely, and not an error. svcrdma_wc_send_err: - This tracepoint can be left persistently enabled because completion errors are run-time problems (except for FLUSHED_ERR). - Tracepoint name now ends in _err to reflect its purpose. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- include/trace/events/rpcrdma.h | 72 ++++++++++++++++++++++++++++++++++- net/sunrpc/xprtrdma/svc_rdma_sendto.c | 14 +++++-- 2 files changed, 82 insertions(+), 4 deletions(-) diff --git a/include/trace/events/rpcrdma.h b/include/trace/events/rpcrdma.h index 342d6d7b5cd9..1d7c12f65f87 100644 --- a/include/trace/events/rpcrdma.h +++ b/include/trace/events/rpcrdma.h @@ -60,6 +60,74 @@ DECLARE_EVENT_CLASS(rpcrdma_completion_class, ), \ TP_ARGS(wc, cid)) +DECLARE_EVENT_CLASS(rpcrdma_send_completion_class, + TP_PROTO( + const struct ib_wc *wc, + const struct rpc_rdma_cid *cid + ), + + TP_ARGS(wc, cid), + + TP_STRUCT__entry( + __field(u32, cq_id) + __field(int, completion_id) + ), + + TP_fast_assign( + __entry->cq_id = cid->ci_queue_id; + __entry->completion_id = cid->ci_completion_id; + ), + + TP_printk("cq.id=%u cid=%d", + __entry->cq_id, __entry->completion_id + ) +); + +#define DEFINE_SEND_COMPLETION_EVENT(name) \ + DEFINE_EVENT(rpcrdma_send_completion_class, name, \ + TP_PROTO( \ + const struct ib_wc *wc, \ + const struct rpc_rdma_cid *cid \ + ), \ + TP_ARGS(wc, cid)) + +DECLARE_EVENT_CLASS(rpcrdma_send_flush_class, + TP_PROTO( + const struct ib_wc *wc, + const struct rpc_rdma_cid *cid + ), + + TP_ARGS(wc, cid), + + TP_STRUCT__entry( + __field(u32, cq_id) + __field(int, completion_id) + __field(unsigned long, status) + __field(unsigned int, vendor_err) + ), + + TP_fast_assign( + __entry->cq_id = cid->ci_queue_id; + __entry->completion_id = cid->ci_completion_id; + __entry->status = wc->status; + __entry->vendor_err = wc->vendor_err; + ), + + TP_printk("cq.id=%u cid=%d status=%s (%lu/0x%x)", + __entry->cq_id, __entry->completion_id, + rdma_show_wc_status(__entry->status), + __entry->status, __entry->vendor_err + ) +); + +#define DEFINE_SEND_FLUSH_EVENT(name) \ + DEFINE_EVENT(rpcrdma_send_flush_class, name, \ + TP_PROTO( \ + const struct ib_wc *wc, \ + const struct rpc_rdma_cid *cid \ + ), \ + TP_ARGS(wc, cid)) + DECLARE_EVENT_CLASS(rpcrdma_mr_completion_class, TP_PROTO( const struct ib_wc *wc, @@ -1939,7 +2007,9 @@ TRACE_EVENT(svcrdma_post_send, ) ); -DEFINE_COMPLETION_EVENT(svcrdma_wc_send); +DEFINE_SEND_COMPLETION_EVENT(svcrdma_wc_send); +DEFINE_SEND_FLUSH_EVENT(svcrdma_wc_send_flush); +DEFINE_SEND_FLUSH_EVENT(svcrdma_wc_send_err); TRACE_EVENT(svcrdma_post_recv, TP_PROTO( diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c index 599021b2391d..22a871e6fe4d 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c +++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c @@ -280,13 +280,21 @@ static void svc_rdma_wc_send(struct ib_cq *cq, struct ib_wc *wc) struct svc_rdma_send_ctxt *ctxt = container_of(cqe, struct svc_rdma_send_ctxt, sc_cqe); - trace_svcrdma_wc_send(wc, &ctxt->sc_cid); - svc_rdma_wake_send_waiters(rdma, 1); complete(&ctxt->sc_done); if (unlikely(wc->status != IB_WC_SUCCESS)) - svc_xprt_deferred_close(&rdma->sc_xprt); + goto flushed; + + trace_svcrdma_wc_send(wc, &ctxt->sc_cid); + return; + +flushed: + if (wc->status != IB_WC_WR_FLUSH_ERR) + trace_svcrdma_wc_send_err(wc, &ctxt->sc_cid); + else + trace_svcrdma_wc_send_flush(wc, &ctxt->sc_cid); + svc_xprt_deferred_close(&rdma->sc_xprt); } /** -- cgit From 45f135846815ef787b41767ad3823194de5ccfdf Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 4 Oct 2021 10:16:20 -0400 Subject: svcrdma: Split svcrmda_wc_{read,write} tracepoints There are currently three separate purposes being served by single tracepoints. Split them up, as was done with wc_send. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- include/trace/events/rpcrdma.h | 38 ++++++++++++++++++++++++++++++++++++-- net/sunrpc/xprtrdma/svc_rdma_rw.c | 30 ++++++++++++++++++++++++++---- 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/include/trace/events/rpcrdma.h b/include/trace/events/rpcrdma.h index 1d7c12f65f87..b5a1388e51a4 100644 --- a/include/trace/events/rpcrdma.h +++ b/include/trace/events/rpcrdma.h @@ -2099,8 +2099,42 @@ DEFINE_POST_CHUNK_EVENT(read); DEFINE_POST_CHUNK_EVENT(write); DEFINE_POST_CHUNK_EVENT(reply); -DEFINE_COMPLETION_EVENT(svcrdma_wc_read); -DEFINE_COMPLETION_EVENT(svcrdma_wc_write); +TRACE_EVENT(svcrdma_wc_read, + TP_PROTO( + const struct ib_wc *wc, + const struct rpc_rdma_cid *cid, + unsigned int totalbytes, + const ktime_t posttime + ), + + TP_ARGS(wc, cid, totalbytes, posttime), + + TP_STRUCT__entry( + __field(u32, cq_id) + __field(int, completion_id) + __field(s64, read_latency) + __field(unsigned int, totalbytes) + ), + + TP_fast_assign( + __entry->cq_id = cid->ci_queue_id; + __entry->completion_id = cid->ci_completion_id; + __entry->totalbytes = totalbytes; + __entry->read_latency = ktime_us_delta(ktime_get(), posttime); + ), + + TP_printk("cq.id=%u cid=%d totalbytes=%u latency-us=%lld", + __entry->cq_id, __entry->completion_id, + __entry->totalbytes, __entry->read_latency + ) +); + +DEFINE_SEND_FLUSH_EVENT(svcrdma_wc_read_flush); +DEFINE_SEND_FLUSH_EVENT(svcrdma_wc_read_err); + +DEFINE_SEND_COMPLETION_EVENT(svcrdma_wc_write); +DEFINE_SEND_FLUSH_EVENT(svcrdma_wc_write_flush); +DEFINE_SEND_FLUSH_EVENT(svcrdma_wc_write_err); TRACE_EVENT(svcrdma_qp_error, TP_PROTO( diff --git a/net/sunrpc/xprtrdma/svc_rdma_rw.c b/net/sunrpc/xprtrdma/svc_rdma_rw.c index e27433f08ca7..5f0155fdefc7 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_rw.c +++ b/net/sunrpc/xprtrdma/svc_rdma_rw.c @@ -155,6 +155,7 @@ struct svc_rdma_chunk_ctxt { struct ib_cqe cc_cqe; struct svcxprt_rdma *cc_rdma; struct list_head cc_rwctxts; + ktime_t cc_posttime; int cc_sqecount; enum ib_wc_status cc_status; struct completion cc_done; @@ -267,7 +268,16 @@ static void svc_rdma_write_done(struct ib_cq *cq, struct ib_wc *wc) struct svc_rdma_write_info *info = container_of(cc, struct svc_rdma_write_info, wi_cc); - trace_svcrdma_wc_write(wc, &cc->cc_cid); + switch (wc->status) { + case IB_WC_SUCCESS: + trace_svcrdma_wc_write(wc, &cc->cc_cid); + break; + case IB_WC_WR_FLUSH_ERR: + trace_svcrdma_wc_write_flush(wc, &cc->cc_cid); + break; + default: + trace_svcrdma_wc_write_err(wc, &cc->cc_cid); + } svc_rdma_wake_send_waiters(rdma, cc->cc_sqecount); @@ -320,11 +330,22 @@ static void svc_rdma_wc_read_done(struct ib_cq *cq, struct ib_wc *wc) struct ib_cqe *cqe = wc->wr_cqe; struct svc_rdma_chunk_ctxt *cc = container_of(cqe, struct svc_rdma_chunk_ctxt, cc_cqe); - struct svcxprt_rdma *rdma = cc->cc_rdma; + struct svc_rdma_read_info *info; - trace_svcrdma_wc_read(wc, &cc->cc_cid); + switch (wc->status) { + case IB_WC_SUCCESS: + info = container_of(cc, struct svc_rdma_read_info, ri_cc); + trace_svcrdma_wc_read(wc, &cc->cc_cid, info->ri_totalbytes, + cc->cc_posttime); + break; + case IB_WC_WR_FLUSH_ERR: + trace_svcrdma_wc_read_flush(wc, &cc->cc_cid); + break; + default: + trace_svcrdma_wc_read_err(wc, &cc->cc_cid); + } - svc_rdma_wake_send_waiters(rdma, cc->cc_sqecount); + svc_rdma_wake_send_waiters(cc->cc_rdma, cc->cc_sqecount); cc->cc_status = wc->status; complete(&cc->cc_done); return; @@ -363,6 +384,7 @@ static int svc_rdma_post_chunk_ctxt(struct svc_rdma_chunk_ctxt *cc) do { if (atomic_sub_return(cc->cc_sqecount, &rdma->sc_sq_avail) > 0) { + cc->cc_posttime = ktime_get(); ret = ib_post_send(rdma->sc_qp, first_wr, &bad_wr); if (ret) break; -- cgit From 22a027e8c03f9a7794d16daa3b4b117ac6d340c3 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 4 Oct 2021 10:16:26 -0400 Subject: SUNRPC: Add trace event when alloc_pages_bulk() makes no progress This is an operational low memory situation that needs to be flagged. The new tracepoint records a timestamp and the nfsd thread that failed to allocate pages. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- include/trace/events/sunrpc.h | 18 ++++++++++++++++++ net/sunrpc/svc_xprt.c | 1 + 2 files changed, 19 insertions(+) diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h index 2d04eb96d418..fb016308c185 100644 --- a/include/trace/events/sunrpc.h +++ b/include/trace/events/sunrpc.h @@ -1859,6 +1859,24 @@ TRACE_EVENT(svc_wake_up, TP_printk("pid=%d", __entry->pid) ); +TRACE_EVENT(svc_alloc_arg_err, + TP_PROTO( + unsigned int pages + ), + + TP_ARGS(pages), + + TP_STRUCT__entry( + __field(unsigned int, pages) + ), + + TP_fast_assign( + __entry->pages = pages; + ), + + TP_printk("pages=%u", __entry->pages) +); + TRACE_EVENT(svc_handle_xprt, TP_PROTO(struct svc_xprt *xprt, int len), diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 6316bd2b8f37..1e99ba1b9d72 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -687,6 +687,7 @@ static int svc_alloc_arg(struct svc_rqst *rqstp) set_current_state(TASK_RUNNING); return -EINTR; } + trace_svc_alloc_arg_err(pages); schedule_timeout(msecs_to_jiffies(500)); } rqstp->rq_page_end = &rqstp->rq_pages[pages]; -- cgit From 35940a58f9f1db96e5688e426d713f330ead70b8 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 4 Oct 2021 10:16:32 -0400 Subject: SUNRPC: Capture value of xdr_buf::page_base This value is usually zero, but will be non-zero more often in the future. Knowing its value can be important diagnostic information. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- include/trace/events/sunrpc.h | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h index fb016308c185..9ea59959a2fe 100644 --- a/include/trace/events/sunrpc.h +++ b/include/trace/events/sunrpc.h @@ -62,6 +62,7 @@ DECLARE_EVENT_CLASS(rpc_xdr_buf_class, __field(size_t, head_len) __field(const void *, tail_base) __field(size_t, tail_len) + __field(unsigned int, page_base) __field(unsigned int, page_len) __field(unsigned int, msg_len) ), @@ -74,14 +75,17 @@ DECLARE_EVENT_CLASS(rpc_xdr_buf_class, __entry->head_len = xdr->head[0].iov_len; __entry->tail_base = xdr->tail[0].iov_base; __entry->tail_len = xdr->tail[0].iov_len; + __entry->page_base = xdr->page_base; __entry->page_len = xdr->page_len; __entry->msg_len = xdr->len; ), - TP_printk("task:%u@%u head=[%p,%zu] page=%u tail=[%p,%zu] len=%u", + TP_printk("task:%u@%u head=[%p,%zu] page=%u(%u) tail=[%p,%zu] len=%u", __entry->task_id, __entry->client_id, - __entry->head_base, __entry->head_len, __entry->page_len, - __entry->tail_base, __entry->tail_len, __entry->msg_len + __entry->head_base, __entry->head_len, + __entry->page_len, __entry->page_base, + __entry->tail_base, __entry->tail_len, + __entry->msg_len ) ); @@ -1496,6 +1500,7 @@ DECLARE_EVENT_CLASS(svc_xdr_buf_class, __field(size_t, head_len) __field(const void *, tail_base) __field(size_t, tail_len) + __field(unsigned int, page_base) __field(unsigned int, page_len) __field(unsigned int, msg_len) ), @@ -1506,14 +1511,17 @@ DECLARE_EVENT_CLASS(svc_xdr_buf_class, __entry->head_len = xdr->head[0].iov_len; __entry->tail_base = xdr->tail[0].iov_base; __entry->tail_len = xdr->tail[0].iov_len; + __entry->page_base = xdr->page_base; __entry->page_len = xdr->page_len; __entry->msg_len = xdr->len; ), - TP_printk("xid=0x%08x head=[%p,%zu] page=%u tail=[%p,%zu] len=%u", + TP_printk("xid=0x%08x head=[%p,%zu] page=%u(%u) tail=[%p,%zu] len=%u", __entry->xid, - __entry->head_base, __entry->head_len, __entry->page_len, - __entry->tail_base, __entry->tail_len, __entry->msg_len + __entry->head_base, __entry->head_len, + __entry->page_len, __entry->page_base, + __entry->tail_base, __entry->tail_len, + __entry->msg_len ) ); -- cgit From 669b2e4aa1a869def4dc207ea084fdd77366d646 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 23 Aug 2021 17:45:03 +0300 Subject: i2c: mlxcpld: Reduce polling time for performance improvement Decrease polling time 'MLXCPLD_I2C_POLL_TIME' from 400 usec to 200 usec. It improves performance of I2C transactions. Reliability of setting polling time to 200 usec has been validated across all the supported systems. Signed-off-by: Vadim Pasternak Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mlxcpld.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c index 4e0b7c2882ce..520db32ad467 100644 --- a/drivers/i2c/busses/i2c-mlxcpld.c +++ b/drivers/i2c/busses/i2c-mlxcpld.c @@ -27,7 +27,7 @@ #define MLXCPLD_I2C_MAX_ADDR_LEN 4 #define MLXCPLD_I2C_RETR_NUM 2 #define MLXCPLD_I2C_XFER_TO 500000 /* usec */ -#define MLXCPLD_I2C_POLL_TIME 400 /* usec */ +#define MLXCPLD_I2C_POLL_TIME 200 /* usec */ /* LPC I2C registers */ #define MLXCPLD_LPCI2C_CPBLTY_REG 0x0 -- cgit From dffe11e280a42c2501e5b0cdebd85a77f539bb05 Mon Sep 17 00:00:00 2001 From: Tong Tiangen Date: Wed, 1 Sep 2021 03:20:25 +0000 Subject: riscv/vdso: Add support for time namespaces Implement generic vdso time namespace support which also enables time namespaces for riscv. This is quite similar to what arm64 does. selftest/timens test result: 1..10 ok 1 Passed for CLOCK_BOOTTIME (syscall) ok 2 Passed for CLOCK_BOOTTIME (vdso) ok 3 # SKIP CLOCK_BOOTTIME_ALARM isn't supported ok 4 # SKIP CLOCK_BOOTTIME_ALARM isn't supported ok 5 Passed for CLOCK_MONOTONIC (syscall) ok 6 Passed for CLOCK_MONOTONIC (vdso) ok 7 Passed for CLOCK_MONOTONIC_COARSE (syscall) ok 8 Passed for CLOCK_MONOTONIC_COARSE (vdso) ok 9 Passed for CLOCK_MONOTONIC_RAW (syscall) ok 10 Passed for CLOCK_MONOTONIC_RAW (vdso) # Totals: pass:8 fail:0 xfail:0 xpass:0 skip:2 error:0 Signed-off-by: Tong Tiangen Signed-off-by: Palmer Dabbelt --- arch/riscv/Kconfig | 1 + arch/riscv/include/asm/page.h | 2 + arch/riscv/include/asm/vdso.h | 2 +- arch/riscv/include/asm/vdso/gettimeofday.h | 7 + arch/riscv/kernel/vdso.c | 250 +++++++++++++++++++++++------ arch/riscv/kernel/vdso/vdso.lds.S | 3 + 6 files changed, 211 insertions(+), 54 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index c3f3fd583e04..ea16fa2dd768 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -62,6 +62,7 @@ config RISCV select GENERIC_SCHED_CLOCK select GENERIC_SMP_IDLE_THREAD select GENERIC_TIME_VSYSCALL if MMU && 64BIT + select GENERIC_VDSO_TIME_NS if HAVE_GENERIC_VDSO select HANDLE_DOMAIN_IRQ select HAVE_ARCH_AUDITSYSCALL select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h index 109c97e991a6..b3e5ff0125fe 100644 --- a/arch/riscv/include/asm/page.h +++ b/arch/riscv/include/asm/page.h @@ -157,6 +157,8 @@ extern phys_addr_t __phys_addr_symbol(unsigned long x); #define page_to_bus(page) (page_to_phys(page)) #define phys_to_page(paddr) (pfn_to_page(phys_to_pfn(paddr))) +#define sym_to_pfn(x) __phys_to_pfn(__pa_symbol(x)) + #ifdef CONFIG_FLATMEM #define pfn_valid(pfn) \ (((pfn) >= ARCH_PFN_OFFSET) && (((pfn) - ARCH_PFN_OFFSET) < max_mapnr)) diff --git a/arch/riscv/include/asm/vdso.h b/arch/riscv/include/asm/vdso.h index 208e31bc5d1c..e310b22fe3f3 100644 --- a/arch/riscv/include/asm/vdso.h +++ b/arch/riscv/include/asm/vdso.h @@ -22,7 +22,7 @@ */ #ifdef CONFIG_MMU -#define __VVAR_PAGES 1 +#define __VVAR_PAGES 2 #ifndef __ASSEMBLY__ #include diff --git a/arch/riscv/include/asm/vdso/gettimeofday.h b/arch/riscv/include/asm/vdso/gettimeofday.h index f839f16e0d2a..77d9c2f721c4 100644 --- a/arch/riscv/include/asm/vdso/gettimeofday.h +++ b/arch/riscv/include/asm/vdso/gettimeofday.h @@ -76,6 +76,13 @@ static __always_inline const struct vdso_data *__arch_get_vdso_data(void) return _vdso_data; } +#ifdef CONFIG_TIME_NS +static __always_inline +const struct vdso_data *__arch_get_timens_vdso_data(const struct vdso_data *vd) +{ + return _timens_data; +} +#endif #endif /* !__ASSEMBLY__ */ #endif /* __ASM_VDSO_GETTIMEOFDAY_H */ diff --git a/arch/riscv/kernel/vdso.c b/arch/riscv/kernel/vdso.c index b70956d80408..a9436a65161a 100644 --- a/arch/riscv/kernel/vdso.c +++ b/arch/riscv/kernel/vdso.c @@ -13,6 +13,7 @@ #include #include #include +#include #ifdef CONFIG_GENERIC_TIME_VSYSCALL #include @@ -25,14 +26,12 @@ extern char vdso_start[], vdso_end[]; enum vvar_pages { VVAR_DATA_PAGE_OFFSET, + VVAR_TIMENS_PAGE_OFFSET, VVAR_NR_PAGES, }; #define VVAR_SIZE (VVAR_NR_PAGES << PAGE_SHIFT) -static unsigned int vdso_pages __ro_after_init; -static struct page **vdso_pagelist __ro_after_init; - /* * The vDSO data page. */ @@ -42,83 +41,228 @@ static union { } vdso_data_store __page_aligned_data; struct vdso_data *vdso_data = &vdso_data_store.data; -static int __init vdso_init(void) +struct __vdso_info { + const char *name; + const char *vdso_code_start; + const char *vdso_code_end; + unsigned long vdso_pages; + /* Data Mapping */ + struct vm_special_mapping *dm; + /* Code Mapping */ + struct vm_special_mapping *cm; +}; + +static struct __vdso_info vdso_info __ro_after_init = { + .name = "vdso", + .vdso_code_start = vdso_start, + .vdso_code_end = vdso_end, +}; + +static int vdso_mremap(const struct vm_special_mapping *sm, + struct vm_area_struct *new_vma) +{ + current->mm->context.vdso = (void *)new_vma->vm_start; + + return 0; +} + +static int __init __vdso_init(void) { unsigned int i; + struct page **vdso_pagelist; + unsigned long pfn; - vdso_pages = (vdso_end - vdso_start) >> PAGE_SHIFT; - vdso_pagelist = - kcalloc(vdso_pages + VVAR_NR_PAGES, sizeof(struct page *), GFP_KERNEL); - if (unlikely(vdso_pagelist == NULL)) { - pr_err("vdso: pagelist allocation failed\n"); - return -ENOMEM; + if (memcmp(vdso_info.vdso_code_start, "\177ELF", 4)) { + pr_err("vDSO is not a valid ELF object!\n"); + return -EINVAL; } - for (i = 0; i < vdso_pages; i++) { - struct page *pg; + vdso_info.vdso_pages = ( + vdso_info.vdso_code_end - + vdso_info.vdso_code_start) >> + PAGE_SHIFT; + + vdso_pagelist = kcalloc(vdso_info.vdso_pages, + sizeof(struct page *), + GFP_KERNEL); + if (vdso_pagelist == NULL) + return -ENOMEM; + + /* Grab the vDSO code pages. */ + pfn = sym_to_pfn(vdso_info.vdso_code_start); + + for (i = 0; i < vdso_info.vdso_pages; i++) + vdso_pagelist[i] = pfn_to_page(pfn + i); + + vdso_info.cm->pages = vdso_pagelist; + + return 0; +} + +#ifdef CONFIG_TIME_NS +struct vdso_data *arch_get_vdso_data(void *vvar_page) +{ + return (struct vdso_data *)(vvar_page); +} + +/* + * The vvar mapping contains data for a specific time namespace, so when a task + * changes namespace we must unmap its vvar data for the old namespace. + * Subsequent faults will map in data for the new namespace. + * + * For more details see timens_setup_vdso_data(). + */ +int vdso_join_timens(struct task_struct *task, struct time_namespace *ns) +{ + struct mm_struct *mm = task->mm; + struct vm_area_struct *vma; + + mmap_read_lock(mm); - pg = virt_to_page(vdso_start + (i << PAGE_SHIFT)); - vdso_pagelist[i] = pg; + for (vma = mm->mmap; vma; vma = vma->vm_next) { + unsigned long size = vma->vm_end - vma->vm_start; + + if (vma_is_special_mapping(vma, vdso_info.dm)) + zap_page_range(vma, vma->vm_start, size); } - vdso_pagelist[i] = virt_to_page(vdso_data); + mmap_read_unlock(mm); return 0; } + +static struct page *find_timens_vvar_page(struct vm_area_struct *vma) +{ + if (likely(vma->vm_mm == current->mm)) + return current->nsproxy->time_ns->vvar_page; + + /* + * VM_PFNMAP | VM_IO protect .fault() handler from being called + * through interfaces like /proc/$pid/mem or + * process_vm_{readv,writev}() as long as there's no .access() + * in special_mapping_vmops. + * For more details check_vma_flags() and __access_remote_vm() + */ + WARN(1, "vvar_page accessed remotely"); + + return NULL; +} +#else +static struct page *find_timens_vvar_page(struct vm_area_struct *vma) +{ + return NULL; +} +#endif + +static vm_fault_t vvar_fault(const struct vm_special_mapping *sm, + struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct page *timens_page = find_timens_vvar_page(vma); + unsigned long pfn; + + switch (vmf->pgoff) { + case VVAR_DATA_PAGE_OFFSET: + if (timens_page) + pfn = page_to_pfn(timens_page); + else + pfn = sym_to_pfn(vdso_data); + break; +#ifdef CONFIG_TIME_NS + case VVAR_TIMENS_PAGE_OFFSET: + /* + * If a task belongs to a time namespace then a namespace + * specific VVAR is mapped with the VVAR_DATA_PAGE_OFFSET and + * the real VVAR page is mapped with the VVAR_TIMENS_PAGE_OFFSET + * offset. + * See also the comment near timens_setup_vdso_data(). + */ + if (!timens_page) + return VM_FAULT_SIGBUS; + pfn = sym_to_pfn(vdso_data); + break; +#endif /* CONFIG_TIME_NS */ + default: + return VM_FAULT_SIGBUS; + } + + return vmf_insert_pfn(vma, vmf->address, pfn); +} + +enum rv_vdso_map { + RV_VDSO_MAP_VVAR, + RV_VDSO_MAP_VDSO, +}; + +static struct vm_special_mapping rv_vdso_maps[] __ro_after_init = { + [RV_VDSO_MAP_VVAR] = { + .name = "[vvar]", + .fault = vvar_fault, + }, + [RV_VDSO_MAP_VDSO] = { + .name = "[vdso]", + .mremap = vdso_mremap, + }, +}; + +static int __init vdso_init(void) +{ + vdso_info.dm = &rv_vdso_maps[RV_VDSO_MAP_VVAR]; + vdso_info.cm = &rv_vdso_maps[RV_VDSO_MAP_VDSO]; + + return __vdso_init(); +} arch_initcall(vdso_init); -int arch_setup_additional_pages(struct linux_binprm *bprm, - int uses_interp) +static int __setup_additional_pages(struct mm_struct *mm, + struct linux_binprm *bprm, + int uses_interp) { - struct mm_struct *mm = current->mm; - unsigned long vdso_base, vdso_len; - int ret; + unsigned long vdso_base, vdso_text_len, vdso_mapping_len; + void *ret; BUILD_BUG_ON(VVAR_NR_PAGES != __VVAR_PAGES); - vdso_len = (vdso_pages + VVAR_NR_PAGES) << PAGE_SHIFT; + vdso_text_len = vdso_info.vdso_pages << PAGE_SHIFT; + /* Be sure to map the data page */ + vdso_mapping_len = vdso_text_len + VVAR_SIZE; - if (mmap_write_lock_killable(mm)) - return -EINTR; - - vdso_base = get_unmapped_area(NULL, 0, vdso_len, 0, 0); + vdso_base = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0); if (IS_ERR_VALUE(vdso_base)) { - ret = vdso_base; - goto end; + ret = ERR_PTR(vdso_base); + goto up_fail; } - mm->context.vdso = NULL; - ret = install_special_mapping(mm, vdso_base, VVAR_SIZE, - (VM_READ | VM_MAYREAD), &vdso_pagelist[vdso_pages]); - if (unlikely(ret)) - goto end; + ret = _install_special_mapping(mm, vdso_base, VVAR_SIZE, + (VM_READ | VM_MAYREAD | VM_PFNMAP), vdso_info.dm); + if (IS_ERR(ret)) + goto up_fail; + vdso_base += VVAR_SIZE; + mm->context.vdso = (void *)vdso_base; ret = - install_special_mapping(mm, vdso_base + VVAR_SIZE, - vdso_pages << PAGE_SHIFT, + _install_special_mapping(mm, vdso_base, vdso_text_len, (VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC), - vdso_pagelist); + vdso_info.cm); - if (unlikely(ret)) - goto end; + if (IS_ERR(ret)) + goto up_fail; - /* - * Put vDSO base into mm struct. We need to do this before calling - * install_special_mapping or the perf counter mmap tracking code - * will fail to recognise it as a vDSO (since arch_vma_name fails). - */ - mm->context.vdso = (void *)vdso_base + VVAR_SIZE; + return 0; -end: - mmap_write_unlock(mm); - return ret; +up_fail: + mm->context.vdso = NULL; + return PTR_ERR(ret); } -const char *arch_vma_name(struct vm_area_struct *vma) +int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) { - if (vma->vm_mm && (vma->vm_start == (long)vma->vm_mm->context.vdso)) - return "[vdso]"; - if (vma->vm_mm && (vma->vm_start == - (long)vma->vm_mm->context.vdso - VVAR_SIZE)) - return "[vdso_data]"; - return NULL; + struct mm_struct *mm = current->mm; + int ret; + + if (mmap_write_lock_killable(mm)) + return -EINTR; + + ret = __setup_additional_pages(mm, bprm, uses_interp); + mmap_write_unlock(mm); + + return ret; } diff --git a/arch/riscv/kernel/vdso/vdso.lds.S b/arch/riscv/kernel/vdso/vdso.lds.S index e9111f700af0..01d94aae5bf5 100644 --- a/arch/riscv/kernel/vdso/vdso.lds.S +++ b/arch/riscv/kernel/vdso/vdso.lds.S @@ -10,6 +10,9 @@ OUTPUT_ARCH(riscv) SECTIONS { PROVIDE(_vdso_data = . - __VVAR_PAGES * PAGE_SIZE); +#ifdef CONFIG_TIME_NS + PROVIDE(_timens_data = _vdso_data + PAGE_SIZE); +#endif . = SIZEOF_HEADERS; .hash : { *(.hash) } :text -- cgit From f2928e224d85e7cc139009ab17cefdfec2df5d11 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Tue, 7 Sep 2021 01:28:47 +0100 Subject: riscv: set default pm_power_off to NULL Set pm_power_off to NULL like on all other architectures, check if it is set in machine_halt() and machine_power_off() and fallback to default_power_off if no other power driver got registered. This brings riscv architecture inline with all other architectures, and allows to reuse exiting power drivers unmodified. Kernels without legacy SBI v0.1 extensions (CONFIG_RISCV_SBI_V01 is not set), do not set pm_power_off to sbi_shutdown(). There is no support for SBI v0.3 system reset extension either. This prevents using gpio_poweroff on SiFive HiFive Unmatched. Tested on SiFive HiFive unmatched, with a dtb specifying gpio-poweroff node and kernel complied without CONFIG_RISCV_SBI_V01. BugLink: https://bugs.launchpad.net/bugs/1942806 Signed-off-by: Dimitri John Ledkov Reviewed-by: Anup Patel Tested-by: Ron Economos Signed-off-by: Palmer Dabbelt --- arch/riscv/kernel/reset.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/riscv/kernel/reset.c b/arch/riscv/kernel/reset.c index ee5878d968cc..9c842c41684a 100644 --- a/arch/riscv/kernel/reset.c +++ b/arch/riscv/kernel/reset.c @@ -12,7 +12,7 @@ static void default_power_off(void) wait_for_interrupt(); } -void (*pm_power_off)(void) = default_power_off; +void (*pm_power_off)(void) = NULL; EXPORT_SYMBOL(pm_power_off); void machine_restart(char *cmd) @@ -23,10 +23,16 @@ void machine_restart(char *cmd) void machine_halt(void) { - pm_power_off(); + if (pm_power_off != NULL) + pm_power_off(); + else + default_power_off(); } void machine_power_off(void) { - pm_power_off(); + if (pm_power_off != NULL) + pm_power_off(); + else + default_power_off(); } -- cgit From 21ccdccd21e4b0efc92fd95c9a99673c455838f0 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Wed, 8 Sep 2021 10:30:29 -0700 Subject: riscv: mm: don't advertise 1 num_asid for 0 asid bits Even if mmu doesn't support ASID, current code calculates @num_asids=1 which is misleading, so avoid setting any asid related variables in such case. Also while here, print the number of asid bits discovered even for the disabled case. Verified this on Hifive Unmatched. Reviewed-by: Anup Patel Signed-off-by: Vineet Gupta Signed-off-by: Palmer Dabbelt --- arch/riscv/mm/context.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/riscv/mm/context.c b/arch/riscv/mm/context.c index ee3459cb6750..ea54cc0c9106 100644 --- a/arch/riscv/mm/context.c +++ b/arch/riscv/mm/context.c @@ -233,8 +233,10 @@ static int __init asids_init(void) local_flush_tlb_all(); /* Pre-compute ASID details */ - num_asids = 1 << asid_bits; - asid_mask = num_asids - 1; + if (asid_bits) { + num_asids = 1 << asid_bits; + asid_mask = num_asids - 1; + } /* * Use ASID allocator only if number of HW ASIDs are @@ -255,7 +257,7 @@ static int __init asids_init(void) pr_info("ASID allocator using %lu bits (%lu entries)\n", asid_bits, num_asids); } else { - pr_info("ASID allocator disabled\n"); + pr_info("ASID allocator disabled (%lu bits)\n", asid_bits); } return 0; -- cgit From 5d4595db0e1ca4c7fbe9c6870007df3578d1a20b Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 11 Sep 2021 20:45:38 -0700 Subject: riscv: add rv32 and rv64 randconfig build targets Add the ability to do randconfig build targets for both rv32 and rv64. Based on a similar patch by Michael Ellerman for PowerPC. Usage: make ARCH=riscv rv32_randconfig or make ARCH=riscv rv64_randconfig Signed-off-by: Randy Dunlap Signed-off-by: Palmer Dabbelt --- arch/riscv/Makefile | 10 ++++++++++ arch/riscv/configs/32-bit.config | 2 ++ arch/riscv/configs/64-bit.config | 2 ++ 3 files changed, 14 insertions(+) create mode 100644 arch/riscv/configs/32-bit.config create mode 100644 arch/riscv/configs/64-bit.config diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 0eb4568fbd29..9247407b95d6 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -140,3 +140,13 @@ install zinstall: archclean: $(Q)$(MAKE) $(clean)=$(boot) + +PHONY += rv32_randconfig +rv32_randconfig: + $(Q)$(MAKE) KCONFIG_ALLCONFIG=$(srctree)/arch/riscv/configs/32-bit.config \ + -f $(srctree)/Makefile randconfig + +PHONY += rv64_randconfig +rv64_randconfig: + $(Q)$(MAKE) KCONFIG_ALLCONFIG=$(srctree)/arch/riscv/configs/64-bit.config \ + -f $(srctree)/Makefile randconfig diff --git a/arch/riscv/configs/32-bit.config b/arch/riscv/configs/32-bit.config new file mode 100644 index 000000000000..43f41323b67e --- /dev/null +++ b/arch/riscv/configs/32-bit.config @@ -0,0 +1,2 @@ +CONFIG_ARCH_RV32I=y +CONFIG_32BIT=y diff --git a/arch/riscv/configs/64-bit.config b/arch/riscv/configs/64-bit.config new file mode 100644 index 000000000000..313edc554d84 --- /dev/null +++ b/arch/riscv/configs/64-bit.config @@ -0,0 +1,2 @@ +CONFIG_ARCH_RV64I=y +CONFIG_64BIT=y -- cgit From e9076e7f23aa087f8b7257f3be9e9586f341e3b1 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 29 Sep 2021 11:23:18 -0700 Subject: scsi: core: Fix spelling in a source code comment The typo in this source code comment makes the comment confusing. Clear up the confusion by fixing the typo. Link: https://lore.kernel.org/r/20210929182318.2060489-1-bvanassche@acm.org Fixes: bc85dc500f9d ("scsi: remove scsi_end_request") Cc: Christoph Hellwig Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index dcf105287a76..5f5ad22512f5 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -949,7 +949,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) /* * If there had been no error, but we have leftover bytes in the - * requeues just queue the command up again. + * request just queue the command up again. */ if (likely(result == 0)) scsi_io_completion_reprep(cmd, q); -- cgit From 1da3b0141e74c18c2377d4c2655406a90a87742f Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Wed, 29 Sep 2021 22:06:38 +0200 Subject: scsi: ufs: core: Fix NULL pointer dereference Calling ufshcd_rpm_{get/put}_sync() prior to ufshcd_scsi_add_wlus() being called will trigger a NULL pointer dereference. This is because hba->sdev_ufs_device is initialized in ufshcd_scsi_add_wlus(). Unable to handle kernel NULL pointer dereference at virtual address 0000000000000348 Mem abort info: ESR = 0x96000004 EC = 0x25: DABT (current EL), IL = 32 bits SET = 0, FnV = 0 EA = 0, S1PTW = 0 FSC = 0x04: level 0 translation fault Data abort info: ISV = 0, ISS = 0x00000004 CM = 0, WnR = 0 [0000000000000348] user address but active_mm is swapper Internal error: Oops: 96000004 [#1] PREEMPT SMP Modules linked in: CPU: 0 PID: 91 Comm: kworker/u16:1 Not tainted 5.15.0-rc1-beanhuo-linaro-1423 Hardware name: MicronRB (DT) Workqueue: events_unbound async_run_entry_fn pstate: 20000005 (nzCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : pm_runtime_drop_link+0x128/0x338 lr : ufshpb_get_dev_info+0x8c/0x148 sp : ffff800012573c10 x29: ffff800012573c10 x28: 0000000000000000 x27: 0000000000000003 x26: ffff000001d21298 x25: 000000005abcea60 x24: ffff800011d89000 x23: 0000000000000001 x22: ffff000001d21880 x21: ffff000001ec9300 x20: 0000000000000004 x19: 0000000000000198 x18: ffffffffffffffff x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000041400 x14: 5eee00201100200a x13: 000000000000bb03 x12: 0000000000000000 x11: 0000000000000100 x10: 0200000000000000 x9 : bb0000021a162c01 x8 : 0302010021021003 x7 : 0000000000000000 x6 : ffff800012573af0 x5 : 0000000000000001 x4 : 0000000000000001 x3 : 0000000000000200 x2 : 0000000000000348 x1 : 0000000000000348 x0 : ffff80001095308c Call trace: pm_runtime_drop_link+0x128/0x338 ufshpb_get_dev_info+0x8c/0x148 ufshcd_probe_hba+0xda0/0x11b8 ufshcd_async_scan+0x34/0x330 async_run_entry_fn+0x38/0x180 process_one_work+0x1f4/0x498 worker_thread+0x48/0x480 kthread+0x140/0x158 ret_from_fork+0x10/0x20 Code: 88027c01 35ffffa2 17fff6c4 f9800051 (885f7c40) ---[ end trace 2ba541335f595c95 ] ufshpb_get_dev_info() is only called during asynchronous scanning and at that time pm_runtime_get_sync() has been called: ... /* Hold auto suspend until async scan completes */ pm_runtime_get_sync(dev); atomic_set(&hba->scsi_block_reqs_cnt, 0); ... ufshcd_async_scan() ufshcd_probe_hba(hba, true); ufshcd_device_params_init(hba); ufshpb_get_dev_info(); ... pm_runtime_put_sync(hba->dev); Remove ufshcd_rpm_{get/put}_sync() from ufshpb_get_dev_info() to fix this problem. Link: https://lore.kernel.org/r/20210929200640.828611-2-huobean@gmail.com Fixes: 351b3a849ac7 ("scsi: ufs: ufshpb: Use proper power management API") Signed-off-by: Bean Huo Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshpb.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c index 9ea639bf6a59..33a38c06a296 100644 --- a/drivers/scsi/ufs/ufshpb.c +++ b/drivers/scsi/ufs/ufshpb.c @@ -2877,11 +2877,8 @@ void ufshpb_get_dev_info(struct ufs_hba *hba, u8 *desc_buf) if (version == HPB_SUPPORT_LEGACY_VERSION) hpb_dev_info->is_legacy = true; - ufshcd_rpm_get_sync(hba); ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR, QUERY_ATTR_IDN_MAX_HPB_SINGLE_CMD, 0, 0, &max_hpb_single_cmd); - ufshcd_rpm_put_sync(hba); - if (ret) dev_err(hba->dev, "%s: idn: read max size of single hpb cmd query request failed", __func__); -- cgit From 68444d73d6a5864ede12df6366bd6602e022ae5b Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Wed, 29 Sep 2021 22:06:39 +0200 Subject: scsi: ufs: core: Fix ufshcd_probe_hba() prototype to match the definition Since commit 568dd9959611 ("scsi: ufs: Rename the second ufshcd_probe_hba() argument"), the second ufshcd_probe_hba() argument has been changed to init_dev_params. Link: https://lore.kernel.org/r/20210929200640.828611-3-huobean@gmail.com Fixes: 568dd9959611 ("scsi: ufs: Rename the second ufshcd_probe_hba() argument") Reviewed-by: Bart Van Assche Signed-off-by: Bean Huo Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 9faf02cbb9ad..e9120e6c5d62 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -225,7 +225,7 @@ static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd); static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag); static void ufshcd_hba_exit(struct ufs_hba *hba); static int ufshcd_clear_ua_wluns(struct ufs_hba *hba); -static int ufshcd_probe_hba(struct ufs_hba *hba, bool async); +static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params); static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on); static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba); static int ufshcd_host_reset_and_restore(struct ufs_hba *hba); -- cgit From f44abcfc3f9f570970f71e790ec625cf26a27021 Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Wed, 29 Sep 2021 22:06:40 +0200 Subject: scsi: ufs: core: Remove return statement in void function Return statement is not useful at the end of "void" function. Link: https://lore.kernel.org/r/20210929200640.828611-4-huobean@gmail.com Signed-off-by: Bean Huo Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index e9120e6c5d62..7126b7a88b56 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -5845,7 +5845,6 @@ static void ufshcd_exception_event_handler(struct work_struct *work) ufs_debugfs_exception_event(hba, status); out: ufshcd_scsi_unblock_requests(hba); - return; } /* Complete requests that have door-bell cleared */ -- cgit From af21c3fd5b3ec540a97b367a70b26616ff7e0c55 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 1 Oct 2021 11:20:14 -0700 Subject: scsi: ufs: core: Retry START_STOP on UNIT_ATTENTION Commit 57d104c153d3 ("ufs: add UFS power management support") made the UFS driver submit a REQUEST SENSE command before submitting a power management command to a WLUN to clear the POWER ON unit attention. Instead of submitting a REQUEST SENSE command before submitting a power management command, retry the power management command until it succeeds. This is the preparation to get rid of all UNIT ATTENTION code which should be handled by users. Link: https://lore.kernel.org/r/20211001182015.1347587-2-jaegeuk@kernel.org Cc: Adrian Hunter Reviewed-by: Bart Van Assche Signed-off-by: Jaegeuk Kim Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 7126b7a88b56..db5f375d89c5 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -8675,7 +8675,7 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba, struct scsi_sense_hdr sshdr; struct scsi_device *sdp; unsigned long flags; - int ret; + int ret, retries; spin_lock_irqsave(hba->host->host_lock, flags); sdp = hba->sdev_ufs_device; @@ -8710,8 +8710,14 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba, * callbacks hence set the RQF_PM flag so that it doesn't resume the * already suspended childs. */ - ret = scsi_execute(sdp, cmd, DMA_NONE, NULL, 0, NULL, &sshdr, - START_STOP_TIMEOUT, 0, 0, RQF_PM, NULL); + for (retries = 3; retries > 0; --retries) { + ret = scsi_execute(sdp, cmd, DMA_NONE, NULL, 0, NULL, &sshdr, + START_STOP_TIMEOUT, 0, 0, RQF_PM, NULL); + if (!scsi_status_is_check_condition(ret) || + !scsi_sense_valid(&sshdr) || + sshdr.sense_key != UNIT_ATTENTION) + break; + } if (ret) { sdev_printk(KERN_WARNING, sdp, "START_STOP failed for power mode: %d, result %x\n", -- cgit From edc0596cc04bf0ac3a69c66e994d3ff8b650ff71 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 1 Oct 2021 11:20:15 -0700 Subject: scsi: ufs: core: Stop clearing UNIT ATTENTIONS Commit aa53f580e67b ("scsi: ufs: Minor adjustments to error handling") introduced a ufshcd_clear_ua_wluns() call in ufshcd_err_handling_unprepare(). As explained in detail by Adrian Hunter, this can trigger a deadlock. Avoid that deadlock by removing the code that clears the unit attention. This is safe because the only software that relies on clearing unit attentions is the Android Trusty software and because support for handling unit attentions has been added in the Trusty software. See also https://lore.kernel.org/linux-scsi/20210930124224.114031-2-adrian.hunter@intel.com/ Note that "scsi: ufs: Retry START_STOP on UNIT_ATTENTION" is a prerequisite for this commit. Link: https://lore.kernel.org/r/20211001182015.1347587-3-jaegeuk@kernel.org Fixes: aa53f580e67b ("scsi: ufs: Minor adjustments to error handling") Cc: Adrian Hunter Signed-off-by: Bart Van Assche Signed-off-by: Jaegeuk Kim Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 184 +--------------------------------------------- drivers/scsi/ufs/ufshcd.h | 14 ---- 2 files changed, 1 insertion(+), 197 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index db5f375d89c5..47236ee93a0e 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -224,7 +224,6 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba); static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd); static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag); static void ufshcd_hba_exit(struct ufs_hba *hba); -static int ufshcd_clear_ua_wluns(struct ufs_hba *hba); static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params); static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on); static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba); @@ -4108,8 +4107,6 @@ int ufshcd_link_recovery(struct ufs_hba *hba) if (ret) dev_err(hba->dev, "%s: link recovery failed, err %d", __func__, ret); - else - ufshcd_clear_ua_wluns(hba); return ret; } @@ -5994,7 +5991,6 @@ static void ufshcd_err_handling_unprepare(struct ufs_hba *hba) ufshcd_release(hba); if (ufshcd_is_clkscaling_supported(hba)) ufshcd_clk_scaling_suspend(hba, false); - ufshcd_clear_ua_wluns(hba); ufshcd_rpm_put(hba); } @@ -7952,8 +7948,6 @@ static int ufshcd_add_lus(struct ufs_hba *hba) if (ret) goto out; - ufshcd_clear_ua_wluns(hba); - /* Initialize devfreq after UFS device is detected */ if (ufshcd_is_clkscaling_supported(hba)) { memcpy(&hba->clk_scaling.saved_pwr_info.info, @@ -7979,116 +7973,6 @@ out: return ret; } -static void ufshcd_request_sense_done(struct request *rq, blk_status_t error) -{ - if (error != BLK_STS_OK) - pr_err("%s: REQUEST SENSE failed (%d)\n", __func__, error); - kfree(rq->end_io_data); - blk_put_request(rq); -} - -static int -ufshcd_request_sense_async(struct ufs_hba *hba, struct scsi_device *sdev) -{ - /* - * Some UFS devices clear unit attention condition only if the sense - * size used (UFS_SENSE_SIZE in this case) is non-zero. - */ - static const u8 cmd[6] = {REQUEST_SENSE, 0, 0, 0, UFS_SENSE_SIZE, 0}; - struct scsi_request *rq; - struct request *req; - char *buffer; - int ret; - - buffer = kzalloc(UFS_SENSE_SIZE, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - req = blk_get_request(sdev->request_queue, REQ_OP_DRV_IN, - /*flags=*/BLK_MQ_REQ_PM); - if (IS_ERR(req)) { - ret = PTR_ERR(req); - goto out_free; - } - - ret = blk_rq_map_kern(sdev->request_queue, req, - buffer, UFS_SENSE_SIZE, GFP_NOIO); - if (ret) - goto out_put; - - rq = scsi_req(req); - rq->cmd_len = ARRAY_SIZE(cmd); - memcpy(rq->cmd, cmd, rq->cmd_len); - rq->retries = 3; - req->timeout = 1 * HZ; - req->rq_flags |= RQF_PM | RQF_QUIET; - req->end_io_data = buffer; - - blk_execute_rq_nowait(/*bd_disk=*/NULL, req, /*at_head=*/true, - ufshcd_request_sense_done); - return 0; - -out_put: - blk_put_request(req); -out_free: - kfree(buffer); - return ret; -} - -static int ufshcd_clear_ua_wlun(struct ufs_hba *hba, u8 wlun) -{ - struct scsi_device *sdp; - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(hba->host->host_lock, flags); - if (wlun == UFS_UPIU_UFS_DEVICE_WLUN) - sdp = hba->sdev_ufs_device; - else if (wlun == UFS_UPIU_RPMB_WLUN) - sdp = hba->sdev_rpmb; - else - BUG(); - if (sdp) { - ret = scsi_device_get(sdp); - if (!ret && !scsi_device_online(sdp)) { - ret = -ENODEV; - scsi_device_put(sdp); - } - } else { - ret = -ENODEV; - } - spin_unlock_irqrestore(hba->host->host_lock, flags); - if (ret) - goto out_err; - - ret = ufshcd_request_sense_async(hba, sdp); - scsi_device_put(sdp); -out_err: - if (ret) - dev_err(hba->dev, "%s: UAC clear LU=%x ret = %d\n", - __func__, wlun, ret); - return ret; -} - -static int ufshcd_clear_ua_wluns(struct ufs_hba *hba) -{ - int ret = 0; - - if (!hba->wlun_dev_clr_ua) - goto out; - - ret = ufshcd_clear_ua_wlun(hba, UFS_UPIU_UFS_DEVICE_WLUN); - if (!ret) - ret = ufshcd_clear_ua_wlun(hba, UFS_UPIU_RPMB_WLUN); - if (!ret) - hba->wlun_dev_clr_ua = false; -out: - if (ret) - dev_err(hba->dev, "%s: Failed to clear UAC WLUNS ret = %d\n", - __func__, ret); - return ret; -} - /** * ufshcd_probe_hba - probe hba to detect device and initialize it * @hba: per-adapter instance @@ -8139,8 +8023,6 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params) /* UFS device is also active now */ ufshcd_set_ufs_dev_active(hba); ufshcd_force_reset_auto_bkops(hba); - hba->wlun_dev_clr_ua = true; - hba->wlun_rpmb_clr_ua = true; /* Gear up to HS gear if supported */ if (hba->max_pwr_info.is_valid) { @@ -8700,8 +8582,6 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba, * handling context. */ hba->host->eh_noresume = 1; - if (hba->wlun_dev_clr_ua) - ufshcd_clear_ua_wlun(hba, UFS_UPIU_UFS_DEVICE_WLUN); cmd[4] = pwr_mode << 4; @@ -9767,10 +9647,6 @@ void ufshcd_resume_complete(struct device *dev) ufshcd_rpm_put(hba); hba->complete_put = false; } - if (hba->rpmb_complete_put) { - ufshcd_rpmb_rpm_put(hba); - hba->rpmb_complete_put = false; - } } EXPORT_SYMBOL_GPL(ufshcd_resume_complete); @@ -9793,10 +9669,6 @@ int ufshcd_suspend_prepare(struct device *dev) } hba->complete_put = true; } - if (hba->sdev_rpmb) { - ufshcd_rpmb_rpm_get_sync(hba); - hba->rpmb_complete_put = true; - } return 0; } EXPORT_SYMBOL_GPL(ufshcd_suspend_prepare); @@ -9865,49 +9737,6 @@ static struct scsi_driver ufs_dev_wlun_template = { }, }; -static int ufshcd_rpmb_probe(struct device *dev) -{ - return is_rpmb_wlun(to_scsi_device(dev)) ? 0 : -ENODEV; -} - -static inline int ufshcd_clear_rpmb_uac(struct ufs_hba *hba) -{ - int ret = 0; - - if (!hba->wlun_rpmb_clr_ua) - return 0; - ret = ufshcd_clear_ua_wlun(hba, UFS_UPIU_RPMB_WLUN); - if (!ret) - hba->wlun_rpmb_clr_ua = 0; - return ret; -} - -#ifdef CONFIG_PM -static int ufshcd_rpmb_resume(struct device *dev) -{ - struct ufs_hba *hba = wlun_dev_to_hba(dev); - - if (hba->sdev_rpmb) - ufshcd_clear_rpmb_uac(hba); - return 0; -} -#endif - -static const struct dev_pm_ops ufs_rpmb_pm_ops = { - SET_RUNTIME_PM_OPS(NULL, ufshcd_rpmb_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(NULL, ufshcd_rpmb_resume) -}; - -/* ufs_rpmb_wlun_template - Describes UFS RPMB WLUN. Used only to send UAC. */ -static struct scsi_driver ufs_rpmb_wlun_template = { - .gendrv = { - .name = "ufs_rpmb_wlun", - .owner = THIS_MODULE, - .probe = ufshcd_rpmb_probe, - .pm = &ufs_rpmb_pm_ops, - }, -}; - static int __init ufshcd_core_init(void) { int ret; @@ -9916,24 +9745,13 @@ static int __init ufshcd_core_init(void) ret = scsi_register_driver(&ufs_dev_wlun_template.gendrv); if (ret) - goto debugfs_exit; - - ret = scsi_register_driver(&ufs_rpmb_wlun_template.gendrv); - if (ret) - goto unregister; - - return ret; -unregister: - scsi_unregister_driver(&ufs_dev_wlun_template.gendrv); -debugfs_exit: - ufs_debugfs_exit(); + ufs_debugfs_exit(); return ret; } static void __exit ufshcd_core_exit(void) { ufs_debugfs_exit(); - scsi_unregister_driver(&ufs_rpmb_wlun_template.gendrv); scsi_unregister_driver(&ufs_dev_wlun_template.gendrv); } diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index ed960d206260..782bbe6d5a52 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -875,9 +875,6 @@ struct ufs_hba { struct ufs_vreg_info vreg_info; struct list_head clk_list_head; - bool wlun_dev_clr_ua; - bool wlun_rpmb_clr_ua; - /* Number of requests aborts */ int req_abort_count; @@ -924,7 +921,6 @@ struct ufs_hba { #endif u32 luns_avail; bool complete_put; - bool rpmb_complete_put; }; /* Returns true if clocks can be gated. Otherwise false */ @@ -1408,14 +1404,4 @@ static inline int ufshcd_rpm_put(struct ufs_hba *hba) return pm_runtime_put(&hba->sdev_ufs_device->sdev_gendev); } -static inline int ufshcd_rpmb_rpm_get_sync(struct ufs_hba *hba) -{ - return pm_runtime_get_sync(&hba->sdev_rpmb->sdev_gendev); -} - -static inline int ufshcd_rpmb_rpm_put(struct ufs_hba *hba) -{ - return pm_runtime_put(&hba->sdev_rpmb->sdev_gendev); -} - #endif /* End of Header */ -- cgit From 54a4045342a8bffabde1827bfd6d86b63163111d Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Sat, 2 Oct 2021 18:45:49 +0300 Subject: scsi: ufs: core: Do not exit ufshcd_reset_and_restore() unless operational or dead Callers of ufshcd_reset_and_restore() expect it to return in an operational state. However, the code only checks direct errors and so the ufshcd_state may not be UFSHCD_STATE_OPERATIONAL due to error interrupts. Fix by also checking ufshcd_state, still allowing non-fatal errors which are left for the error handler to deal with. Link: https://lore.kernel.org/r/20211002154550.128511-2-adrian.hunter@intel.com Reviewed-by: Avri altman Signed-off-by: Adrian Hunter Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 47236ee93a0e..9f53a154cde5 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -7151,31 +7151,41 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba) */ static int ufshcd_reset_and_restore(struct ufs_hba *hba) { - u32 saved_err; - u32 saved_uic_err; + u32 saved_err = 0; + u32 saved_uic_err = 0; int err = 0; unsigned long flags; int retries = MAX_HOST_RESET_RETRIES; - /* - * This is a fresh start, cache and clear saved error first, - * in case new error generated during reset and restore. - */ spin_lock_irqsave(hba->host->host_lock, flags); - saved_err = hba->saved_err; - saved_uic_err = hba->saved_uic_err; - hba->saved_err = 0; - hba->saved_uic_err = 0; - spin_unlock_irqrestore(hba->host->host_lock, flags); - do { + /* + * This is a fresh start, cache and clear saved error first, + * in case new error generated during reset and restore. + */ + saved_err |= hba->saved_err; + saved_uic_err |= hba->saved_uic_err; + hba->saved_err = 0; + hba->saved_uic_err = 0; + hba->force_reset = false; + hba->ufshcd_state = UFSHCD_STATE_RESET; + spin_unlock_irqrestore(hba->host->host_lock, flags); + /* Reset the attached device */ ufshcd_device_reset(hba); err = ufshcd_host_reset_and_restore(hba); + + spin_lock_irqsave(hba->host->host_lock, flags); + if (err) + continue; + /* Do not exit unless operational or dead */ + if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL && + hba->ufshcd_state != UFSHCD_STATE_ERROR && + hba->ufshcd_state != UFSHCD_STATE_EH_SCHEDULED_NON_FATAL) + err = -EAGAIN; } while (err && --retries); - spin_lock_irqsave(hba->host->host_lock, flags); /* * Inform scsi mid-layer that we did reset and allow to handle * Unit Attention properly. -- cgit From 87bf6a6bbe8bd62b5924b00161d28a0d6df151ca Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Sat, 2 Oct 2021 18:45:50 +0300 Subject: scsi: ufs: core: Do not exit ufshcd_err_handler() unless operational or dead Callers of ufshcd_err_handler() expect it to return in an operational state. However, the code does not check the state before exiting. Add a check for the state and perform retries until either success or the maximum number of retries is reached. Link: https://lore.kernel.org/r/20211002154550.128511-3-adrian.hunter@intel.com Reviewed-by: Avri Altman Signed-off-by: Adrian Hunter Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 9f53a154cde5..d91a405fd181 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -64,6 +64,9 @@ /* maximum number of reset retries before giving up */ #define MAX_HOST_RESET_RETRIES 5 +/* Maximum number of error handler retries before giving up */ +#define MAX_ERR_HANDLER_RETRIES 5 + /* Expose the flag value from utp_upiu_query.value */ #define MASK_QUERY_UPIU_FLAG_LOC 0xFF @@ -6065,12 +6068,14 @@ static bool ufshcd_is_pwr_mode_restore_needed(struct ufs_hba *hba) static void ufshcd_err_handler(struct Scsi_Host *host) { struct ufs_hba *hba = shost_priv(host); + int retries = MAX_ERR_HANDLER_RETRIES; unsigned long flags; - bool err_xfer = false; - bool err_tm = false; - int err = 0, pmc_err; + bool needs_restore; + bool needs_reset; + bool err_xfer; + bool err_tm; + int pmc_err; int tag; - bool needs_reset = false, needs_restore = false; down(&hba->host_sem); spin_lock_irqsave(hba->host->host_lock, flags); @@ -6088,6 +6093,12 @@ static void ufshcd_err_handler(struct Scsi_Host *host) /* Complete requests that have door-bell cleared by h/w */ ufshcd_complete_requests(hba); spin_lock_irqsave(hba->host->host_lock, flags); +again: + needs_restore = false; + needs_reset = false; + err_xfer = false; + err_tm = false; + if (hba->ufshcd_state != UFSHCD_STATE_ERROR) hba->ufshcd_state = UFSHCD_STATE_RESET; /* @@ -6208,6 +6219,8 @@ lock_skip_pending_xfer_clear: do_reset: /* Fatal errors need reset */ if (needs_reset) { + int err; + hba->force_reset = false; spin_unlock_irqrestore(hba->host->host_lock, flags); err = ufshcd_reset_and_restore(hba); @@ -6227,6 +6240,13 @@ skip_err_handling: dev_err_ratelimited(hba->dev, "%s: exit: saved_err 0x%x saved_uic_err 0x%x", __func__, hba->saved_err, hba->saved_uic_err); } + /* Exit in an operational state or dead */ + if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL && + hba->ufshcd_state != UFSHCD_STATE_ERROR) { + if (--retries) + goto again; + hba->ufshcd_state = UFSHCD_STATE_ERROR; + } ufshcd_clear_eh_in_progress(hba); spin_unlock_irqrestore(hba->host->host_lock, flags); ufshcd_err_handling_unprepare(hba); -- cgit From 05787e3456ffcc8598aab632fcd5d160894619b3 Mon Sep 17 00:00:00 2001 From: Konstantin Shelekhin Date: Wed, 29 Sep 2021 14:50:00 +0300 Subject: scsi: target: core: Make logs less verbose Change the log level of the following message to debug: Unsupported SCSI Opcode 0xXX, sending CHECK_CONDITION. This message is mostly helpful during debugging sessions in order to understand errors on the initiator side. But most of the time it's just useless and makes reading logs much harder. It gets particularly annoying if there are many initiators that come and go or if an initiator runs a program that does not care whether the command is supported and just keeps sending it. Link: https://lore.kernel.org/r/20210929114959.705852-1-k.shelekhin@yadro.com Reviewed-by: Roman Bolshakov Reviewed-by: Lee Duncan Signed-off-by: Konstantin Shelekhin Signed-off-by: Martin K. Petersen --- drivers/target/target_core_transport.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 14c6f2bb1b01..4a0055ab9151 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1511,10 +1511,10 @@ target_cmd_parse_cdb(struct se_cmd *cmd) ret = dev->transport->parse_cdb(cmd); if (ret == TCM_UNSUPPORTED_SCSI_OPCODE) - pr_warn_ratelimited("%s/%s: Unsupported SCSI Opcode 0x%02x, sending CHECK_CONDITION.\n", - cmd->se_tfo->fabric_name, - cmd->se_sess->se_node_acl->initiatorname, - cmd->t_task_cdb[0]); + pr_debug_ratelimited("%s/%s: Unsupported SCSI Opcode 0x%02x, sending CHECK_CONDITION.\n", + cmd->se_tfo->fabric_name, + cmd->se_sess->se_node_acl->initiatorname, + cmd->t_task_cdb[0]); if (ret) return ret; -- cgit From d4996c6eac4c81b8872043e9391563f67f13e406 Mon Sep 17 00:00:00 2001 From: Guo Zhi Date: Wed, 29 Sep 2021 20:25:37 +0800 Subject: scsi: advansys: Fix kernel pointer leak Pointers should be printed with %p or %px rather than cast to 'unsigned long' and printed with %lx. Change %lx to %p to print the hashed pointer. Link: https://lore.kernel.org/r/20210929122538.1158235-1-qtxuning1999@sjtu.edu.cn Signed-off-by: Guo Zhi Signed-off-by: Martin K. Petersen --- drivers/scsi/advansys.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index e341b3372482..2df2a843a5ff 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -3308,8 +3308,8 @@ static void asc_prt_adv_board_info(struct seq_file *m, struct Scsi_Host *shost) shost->host_no); seq_printf(m, - " iop_base 0x%lx, cable_detect: %X, err_code %u\n", - (unsigned long)v->iop_base, + " iop_base 0x%p, cable_detect: %X, err_code %u\n", + v->iop_base, AdvReadWordRegister(iop_base,IOPW_SCSI_CFG1) & CABLE_DETECT, v->err_code); -- cgit From e7dcc514a49e74051b869697d5ab0370f6301d57 Mon Sep 17 00:00:00 2001 From: Sumit Saxena Date: Wed, 29 Sep 2021 18:10:20 +0530 Subject: scsi: megaraid_sas: Fix concurrent access to ISR between IRQ polling and real interrupt IRQ polling thread calls ISR after enable_irq() to handle any missed I/O completion. The atomic flag "in_used" was added to have the synchronization between the IRQ polling thread and the interrupt context. There is a bug around it leading to a race condition. Below is the sequence: - IRQ polling thread accesses ISR, fetches the reply descriptor. - Real interrupt arrives and pre-empts polling thread (enable_irq() is already called). - Interrupt context picks the same reply descriptor as fetched by polling thread, processes it, and exits. - Polling thread resumes and processes the descriptor which is already processed by interrupt thread leads to kernel crash. Setting the "in_used" flag before fetching the reply descriptor ensures synchronized access to ISR. Link: https://www.spinics.net/lists/linux-scsi/msg159440.html Link: https://lore.kernel.org/r/20210929124022.24605-2-sumit.saxena@broadcom.com Fixes: 9bedd36e9146 ("scsi: megaraid_sas: Handle missing interrupts while re-enabling IRQs") Signed-off-by: Sumit Saxena Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_fusion.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 26d0cf9353dd..eb5ceb75a15e 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -3530,6 +3530,9 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex, if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) return IRQ_HANDLED; + if (irq_context && !atomic_add_unless(&irq_context->in_used, 1, 1)) + return 0; + desc = fusion->reply_frames_desc[MSIxIndex] + fusion->last_reply_idx[MSIxIndex]; @@ -3540,11 +3543,11 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex, reply_descript_type = reply_desc->ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; - if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) + if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) { + if (irq_context) + atomic_dec(&irq_context->in_used); return IRQ_NONE; - - if (irq_context && !atomic_add_unless(&irq_context->in_used, 1, 1)) - return 0; + } num_completed = 0; -- cgit From 4c32edc350e4bebd93db1d63f506f4f343e23bd1 Mon Sep 17 00:00:00 2001 From: Sumit Saxena Date: Wed, 29 Sep 2021 18:10:21 +0530 Subject: scsi: megaraid_sas: Add helper functions for irq_context Adding helper functions for ISR access and release to improve readability. Link: https://lore.kernel.org/r/20210929124022.24605-3-sumit.saxena@broadcom.com Signed-off-by: Sumit Saxena Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_fusion.c | 45 +++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index eb5ceb75a15e..109782e3ec44 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -3497,6 +3497,41 @@ megasas_complete_r1_command(struct megasas_instance *instance, } } +/** + * access_irq_context: Access to reply processing + * @irq_context: IRQ context + * + * Synchronize access to reply processing. + * + * Return: true on success, false on failure. + */ +static inline +bool access_irq_context(struct megasas_irq_context *irq_context) +{ + if (!irq_context) + return true; + + if (atomic_add_unless(&irq_context->in_used, 1, 1)) + return true; + + return false; +} + +/** + * release_irq_context: Release reply processing + * @irq_context: IRQ context + * + * Release access of reply processing. + * + * Return: Nothing. + */ +static inline +void release_irq_context(struct megasas_irq_context *irq_context) +{ + if (irq_context) + atomic_dec(&irq_context->in_used); +} + /** * complete_cmd_fusion - Completes command * @instance: Adapter soft state @@ -3530,7 +3565,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex, if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) return IRQ_HANDLED; - if (irq_context && !atomic_add_unless(&irq_context->in_used, 1, 1)) + if (!access_irq_context(irq_context)) return 0; desc = fusion->reply_frames_desc[MSIxIndex] + @@ -3544,8 +3579,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex, MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) { - if (irq_context) - atomic_dec(&irq_context->in_used); + release_irq_context(irq_context); return IRQ_NONE; } @@ -3663,7 +3697,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex, irq_context->irq_line_enable = true; irq_poll_sched(&irq_context->irqpoll); } - atomic_dec(&irq_context->in_used); + release_irq_context(irq_context); return num_completed; } } @@ -3682,8 +3716,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex, megasas_check_and_restore_queue_depth(instance); } - if (irq_context) - atomic_dec(&irq_context->in_used); + release_irq_context(irq_context); return num_completed; } -- cgit From cdf7f6a10d48589a819a98f0e3dd262079a38120 Mon Sep 17 00:00:00 2001 From: Sumit Saxena Date: Wed, 29 Sep 2021 18:10:22 +0530 Subject: scsi: megaraid_sas: Driver version update to 07.719.03.00-rc1 Link: https://lore.kernel.org/r/20210929124022.24605-4-sumit.saxena@broadcom.com Signed-off-by: Sumit Saxena Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 7af2c23652b0..2c9d1b796475 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -21,8 +21,8 @@ /* * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "07.717.02.00-rc1" -#define MEGASAS_RELDATE "May 19, 2021" +#define MEGASAS_VERSION "07.719.03.00-rc1" +#define MEGASAS_RELDATE "Sep 29, 2021" #define MEGASAS_MSIX_NAME_LEN 32 -- cgit From 80ed33c8ba932480be99f73dc3f29e1f7da1582c Mon Sep 17 00:00:00 2001 From: Dmitry Bogdanov Date: Fri, 10 Sep 2021 11:41:27 +0300 Subject: scsi: target: core: Add common tpg/enable attribute Many fabric modules provide their own implementation of enable attribute in tpg. Provide a way to remove code duplication in the fabric modules and automatically add "enable" attribute if a fabric module has an implementation of fabric_enable_tpg(). Link: https://lore.kernel.org/r/20210910084133.17956-2-d.bogdanov@yadro.com Reviewed-by: Roman Bolshakov Reviewed-by: Mike Christie Signed-off-by: Dmitry Bogdanov Signed-off-by: Martin K. Petersen --- drivers/target/target_core_configfs.c | 1 + drivers/target/target_core_fabric_configfs.c | 78 +++++++++++++++++++++++++++- include/target/target_core_base.h | 1 + include/target/target_core_fabric.h | 1 + 4 files changed, 79 insertions(+), 2 deletions(-) diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 102ec644bc8a..3b9e50c1ccef 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -490,6 +490,7 @@ void target_unregister_template(const struct target_core_fabric_ops *fo) * fabric driver unload of TFO->module to proceed. */ rcu_barrier(); + kfree(t->tf_tpg_base_cit.ct_attrs); kfree(t); return; } diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index fc7edc04ee09..0b65de9f2df1 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -815,8 +815,76 @@ static struct configfs_item_operations target_fabric_tpg_base_item_ops = { .release = target_fabric_tpg_release, }; -TF_CIT_SETUP_DRV(tpg_base, &target_fabric_tpg_base_item_ops, NULL); +static ssize_t target_fabric_tpg_base_enable_show(struct config_item *item, + char *page) +{ + return sysfs_emit(page, "%d\n", to_tpg(item)->enabled); +} + +static ssize_t target_fabric_tpg_base_enable_store(struct config_item *item, + const char *page, + size_t count) +{ + struct se_portal_group *se_tpg = to_tpg(item); + int ret; + bool op; + + ret = strtobool(page, &op); + if (ret) + return ret; + + if (se_tpg->enabled == op) + return count; + + ret = se_tpg->se_tpg_tfo->fabric_enable_tpg(se_tpg, op); + if (ret) + return ret; + + se_tpg->enabled = op; + + return count; +} + +CONFIGFS_ATTR(target_fabric_tpg_base_, enable); +static int +target_fabric_setup_tpg_base_cit(struct target_fabric_configfs *tf) +{ + struct config_item_type *cit = &tf->tf_tpg_base_cit; + struct configfs_attribute **attrs = NULL; + size_t nr_attrs = 0; + int i = 0; + + if (tf->tf_ops->tfc_tpg_base_attrs) + while (tf->tf_ops->tfc_tpg_base_attrs[nr_attrs] != NULL) + nr_attrs++; + + if (tf->tf_ops->fabric_enable_tpg) + nr_attrs++; + + if (nr_attrs == 0) + goto done; + + /* + 1 for final NULL in the array */ + attrs = kcalloc(nr_attrs + 1, sizeof(*attrs), GFP_KERNEL); + if (!attrs) + return -ENOMEM; + + if (tf->tf_ops->tfc_tpg_base_attrs) + for (; tf->tf_ops->tfc_tpg_base_attrs[i] != NULL; i++) + attrs[i] = tf->tf_ops->tfc_tpg_base_attrs[i]; + + if (tf->tf_ops->fabric_enable_tpg) + attrs[i] = &target_fabric_tpg_base_attr_enable; + +done: + cit->ct_item_ops = &target_fabric_tpg_base_item_ops; + cit->ct_attrs = attrs; + cit->ct_owner = tf->tf_ops->module; + pr_debug("Setup generic tpg_base\n"); + + return 0; +} /* End of tfc_tpg_base_cit */ /* Start of tfc_tpg_cit */ @@ -1028,12 +1096,18 @@ TF_CIT_SETUP_DRV(discovery, NULL, NULL); int target_fabric_setup_cits(struct target_fabric_configfs *tf) { + int ret; + target_fabric_setup_discovery_cit(tf); target_fabric_setup_wwn_cit(tf); target_fabric_setup_wwn_fabric_stats_cit(tf); target_fabric_setup_wwn_param_cit(tf); target_fabric_setup_tpg_cit(tf); - target_fabric_setup_tpg_base_cit(tf); + + ret = target_fabric_setup_tpg_base_cit(tf); + if (ret) + return ret; + target_fabric_setup_tpg_port_cit(tf); target_fabric_setup_tpg_port_stat_cit(tf); target_fabric_setup_tpg_lun_cit(tf); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index fb11c7693b25..2130f102798d 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -900,6 +900,7 @@ struct se_portal_group { * Negative values can be used by fabric drivers for internal use TPGs. */ int proto_id; + bool enabled; /* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */ atomic_t tpg_pr_ref_count; /* Spinlock for adding/removing ACLed Nodes */ diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 3c5ade7a04a6..38f0662476d1 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -89,6 +89,7 @@ struct target_core_fabric_ops { void (*add_wwn_groups)(struct se_wwn *); struct se_portal_group *(*fabric_make_tpg)(struct se_wwn *, const char *); + int (*fabric_enable_tpg)(struct se_portal_group *se_tpg, bool enable); void (*fabric_drop_tpg)(struct se_portal_group *); int (*fabric_post_link)(struct se_portal_group *, struct se_lun *); -- cgit From 382731ec01b376ab32b29b9463e6718bbc18467b Mon Sep 17 00:00:00 2001 From: Dmitry Bogdanov Date: Fri, 10 Sep 2021 11:41:28 +0300 Subject: scsi: target: iscsi: Replace tpg enable attr with ops.enable Remove tpg/enable attribute. Add fabric ops enable_tpg implementation instead. Link: https://lore.kernel.org/r/20210910084133.17956-3-d.bogdanov@yadro.com Reviewed-by: Roman Bolshakov Reviewed-by: Mike Christie Signed-off-by: Dmitry Bogdanov Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target_configfs.c | 91 ++++++++++------------------ 1 file changed, 32 insertions(+), 59 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index f4a24fa5058e..2a9de24a8bbe 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -1005,74 +1005,15 @@ static struct configfs_attribute *lio_target_tpg_param_attrs[] = { /* Start items for lio_target_tpg_cit */ -static ssize_t lio_target_tpg_enable_show(struct config_item *item, char *page) -{ - struct se_portal_group *se_tpg = to_tpg(item); - struct iscsi_portal_group *tpg = container_of(se_tpg, - struct iscsi_portal_group, tpg_se_tpg); - ssize_t len; - - spin_lock(&tpg->tpg_state_lock); - len = sprintf(page, "%d\n", - (tpg->tpg_state == TPG_STATE_ACTIVE) ? 1 : 0); - spin_unlock(&tpg->tpg_state_lock); - - return len; -} - -static ssize_t lio_target_tpg_enable_store(struct config_item *item, - const char *page, size_t count) -{ - struct se_portal_group *se_tpg = to_tpg(item); - struct iscsi_portal_group *tpg = container_of(se_tpg, - struct iscsi_portal_group, tpg_se_tpg); - u32 op; - int ret; - - ret = kstrtou32(page, 0, &op); - if (ret) - return ret; - if ((op != 1) && (op != 0)) { - pr_err("Illegal value for tpg_enable: %u\n", op); - return -EINVAL; - } - - ret = iscsit_get_tpg(tpg); - if (ret < 0) - return -EINVAL; - - if (op) { - ret = iscsit_tpg_enable_portal_group(tpg); - if (ret < 0) - goto out; - } else { - /* - * iscsit_tpg_disable_portal_group() assumes force=1 - */ - ret = iscsit_tpg_disable_portal_group(tpg, 1); - if (ret < 0) - goto out; - } - - iscsit_put_tpg(tpg); - return count; -out: - iscsit_put_tpg(tpg); - return -EINVAL; -} - - static ssize_t lio_target_tpg_dynamic_sessions_show(struct config_item *item, char *page) { return target_show_dynamic_sessions(to_tpg(item), page); } -CONFIGFS_ATTR(lio_target_tpg_, enable); CONFIGFS_ATTR_RO(lio_target_tpg_, dynamic_sessions); static struct configfs_attribute *lio_target_tpg_attrs[] = { - &lio_target_tpg_attr_enable, &lio_target_tpg_attr_dynamic_sessions, NULL, }; @@ -1129,6 +1070,37 @@ free_out: return NULL; } +static int lio_target_tiqn_enabletpg(struct se_portal_group *se_tpg, + bool enable) +{ + struct iscsi_portal_group *tpg = container_of(se_tpg, + struct iscsi_portal_group, tpg_se_tpg); + int ret; + + ret = iscsit_get_tpg(tpg); + if (ret < 0) + return -EINVAL; + + if (enable) { + ret = iscsit_tpg_enable_portal_group(tpg); + if (ret < 0) + goto out; + } else { + /* + * iscsit_tpg_disable_portal_group() assumes force=1 + */ + ret = iscsit_tpg_disable_portal_group(tpg, 1); + if (ret < 0) + goto out; + } + + iscsit_put_tpg(tpg); + return 0; +out: + iscsit_put_tpg(tpg); + return -EINVAL; +} + static void lio_target_tiqn_deltpg(struct se_portal_group *se_tpg) { struct iscsi_portal_group *tpg; @@ -1556,6 +1528,7 @@ const struct target_core_fabric_ops iscsi_ops = { .fabric_drop_wwn = lio_target_call_coredeltiqn, .add_wwn_groups = lio_target_add_wwn_groups, .fabric_make_tpg = lio_target_tiqn_addtpg, + .fabric_enable_tpg = lio_target_tiqn_enabletpg, .fabric_drop_tpg = lio_target_tiqn_deltpg, .fabric_make_np = lio_target_call_addnptotpg, .fabric_drop_np = lio_target_call_delnpfromtpg, -- cgit From cb8717a720a9e911095e0421be6693a80b3abd49 Mon Sep 17 00:00:00 2001 From: Dmitry Bogdanov Date: Fri, 10 Sep 2021 11:41:29 +0300 Subject: scsi: target: qla2xxx: Replace enable attr with ops.enable Remove tpg/enable attribute. Add fabric ops enable_tpg implementation instead. Link: https://lore.kernel.org/r/20210910084133.17956-4-d.bogdanov@yadro.com Reviewed-by: Roman Bolshakov Reviewed-by: Mike Christie Signed-off-by: Dmitry Bogdanov Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 73 +++++++------------------------------- 1 file changed, 12 insertions(+), 61 deletions(-) diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 03de1bcf1461..8fa0056b56dd 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -915,40 +915,17 @@ static struct configfs_attribute *tcm_qla2xxx_tpg_attrib_attrs[] = { /* End items for tcm_qla2xxx_tpg_attrib_cit */ -static ssize_t tcm_qla2xxx_tpg_enable_show(struct config_item *item, - char *page) -{ - struct se_portal_group *se_tpg = to_tpg(item); - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, - struct tcm_qla2xxx_tpg, se_tpg); - - return snprintf(page, PAGE_SIZE, "%d\n", - atomic_read(&tpg->lport_tpg_enabled)); -} - -static ssize_t tcm_qla2xxx_tpg_enable_store(struct config_item *item, - const char *page, size_t count) +static int tcm_qla2xxx_enable_tpg(struct se_portal_group *se_tpg, + bool enable) { - struct se_portal_group *se_tpg = to_tpg(item); struct se_wwn *se_wwn = se_tpg->se_tpg_wwn; struct tcm_qla2xxx_lport *lport = container_of(se_wwn, struct tcm_qla2xxx_lport, lport_wwn); struct scsi_qla_host *vha = lport->qla_vha; struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, struct tcm_qla2xxx_tpg, se_tpg); - unsigned long op; - int rc; - rc = kstrtoul(page, 0, &op); - if (rc < 0) { - pr_err("kstrtoul() returned %d\n", rc); - return -EINVAL; - } - if ((op != 1) && (op != 0)) { - pr_err("Illegal value for tpg_enable: %lu\n", op); - return -EINVAL; - } - if (op) { + if (enable) { if (atomic_read(&tpg->lport_tpg_enabled)) return -EEXIST; @@ -956,14 +933,14 @@ static ssize_t tcm_qla2xxx_tpg_enable_store(struct config_item *item, qlt_enable_vha(vha); } else { if (!atomic_read(&tpg->lport_tpg_enabled)) - return count; + return 0; atomic_set(&tpg->lport_tpg_enabled, 0); qlt_stop_phase1(vha->vha_tgt.qla_tgt); qlt_stop_phase2(vha->vha_tgt.qla_tgt); } - return count; + return 0; } static ssize_t tcm_qla2xxx_tpg_dynamic_sessions_show(struct config_item *item, @@ -1004,12 +981,10 @@ static ssize_t tcm_qla2xxx_tpg_fabric_prot_type_show(struct config_item *item, return sprintf(page, "%d\n", tpg->tpg_attrib.fabric_prot_type); } -CONFIGFS_ATTR(tcm_qla2xxx_tpg_, enable); CONFIGFS_ATTR_RO(tcm_qla2xxx_tpg_, dynamic_sessions); CONFIGFS_ATTR(tcm_qla2xxx_tpg_, fabric_prot_type); static struct configfs_attribute *tcm_qla2xxx_tpg_attrs[] = { - &tcm_qla2xxx_tpg_attr_enable, &tcm_qla2xxx_tpg_attr_dynamic_sessions, &tcm_qla2xxx_tpg_attr_fabric_prot_type, NULL, @@ -1083,35 +1058,17 @@ static void tcm_qla2xxx_drop_tpg(struct se_portal_group *se_tpg) kfree(tpg); } -static ssize_t tcm_qla2xxx_npiv_tpg_enable_show(struct config_item *item, - char *page) -{ - return tcm_qla2xxx_tpg_enable_show(item, page); -} - -static ssize_t tcm_qla2xxx_npiv_tpg_enable_store(struct config_item *item, - const char *page, size_t count) +static int tcm_qla2xxx_npiv_enable_tpg(struct se_portal_group *se_tpg, + bool enable) { - struct se_portal_group *se_tpg = to_tpg(item); struct se_wwn *se_wwn = se_tpg->se_tpg_wwn; struct tcm_qla2xxx_lport *lport = container_of(se_wwn, struct tcm_qla2xxx_lport, lport_wwn); struct scsi_qla_host *vha = lport->qla_vha; struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, struct tcm_qla2xxx_tpg, se_tpg); - unsigned long op; - int rc; - rc = kstrtoul(page, 0, &op); - if (rc < 0) { - pr_err("kstrtoul() returned %d\n", rc); - return -EINVAL; - } - if ((op != 1) && (op != 0)) { - pr_err("Illegal value for tpg_enable: %lu\n", op); - return -EINVAL; - } - if (op) { + if (enable) { if (atomic_read(&tpg->lport_tpg_enabled)) return -EEXIST; @@ -1119,23 +1076,16 @@ static ssize_t tcm_qla2xxx_npiv_tpg_enable_store(struct config_item *item, qlt_enable_vha(vha); } else { if (!atomic_read(&tpg->lport_tpg_enabled)) - return count; + return 0; atomic_set(&tpg->lport_tpg_enabled, 0); qlt_stop_phase1(vha->vha_tgt.qla_tgt); qlt_stop_phase2(vha->vha_tgt.qla_tgt); } - return count; + return 0; } -CONFIGFS_ATTR(tcm_qla2xxx_npiv_tpg_, enable); - -static struct configfs_attribute *tcm_qla2xxx_npiv_tpg_attrs[] = { - &tcm_qla2xxx_npiv_tpg_attr_enable, - NULL, -}; - static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg(struct se_wwn *wwn, const char *name) { @@ -1878,6 +1828,7 @@ static const struct target_core_fabric_ops tcm_qla2xxx_ops = { .fabric_make_wwn = tcm_qla2xxx_make_lport, .fabric_drop_wwn = tcm_qla2xxx_drop_lport, .fabric_make_tpg = tcm_qla2xxx_make_tpg, + .fabric_enable_tpg = tcm_qla2xxx_enable_tpg, .fabric_drop_tpg = tcm_qla2xxx_drop_tpg, .fabric_init_nodeacl = tcm_qla2xxx_init_nodeacl, @@ -1918,11 +1869,11 @@ static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { .fabric_make_wwn = tcm_qla2xxx_npiv_make_lport, .fabric_drop_wwn = tcm_qla2xxx_npiv_drop_lport, .fabric_make_tpg = tcm_qla2xxx_npiv_make_tpg, + .fabric_enable_tpg = tcm_qla2xxx_npiv_enable_tpg, .fabric_drop_tpg = tcm_qla2xxx_drop_tpg, .fabric_init_nodeacl = tcm_qla2xxx_init_nodeacl, .tfc_wwn_attrs = tcm_qla2xxx_wwn_attrs, - .tfc_tpg_base_attrs = tcm_qla2xxx_npiv_tpg_attrs, }; static int tcm_qla2xxx_register_configfs(void) -- cgit From fb00af92e5db24f69bba8c05a2c1926bf4a5cdc6 Mon Sep 17 00:00:00 2001 From: Dmitry Bogdanov Date: Fri, 10 Sep 2021 11:41:30 +0300 Subject: scsi: target: sbp: Replace enable attr with ops.enable Remove tpg/enable attribute. Add fabric ops enable_tpg implementation instead. Link: https://lore.kernel.org/r/20210910084133.17956-5-d.bogdanov@yadro.com Reviewed-by: Roman Bolshakov Reviewed-by: Bart Van Assche Reviewed-by: Mike Christie Signed-off-by: Dmitry Bogdanov Signed-off-by: Martin K. Petersen --- drivers/target/sbp/sbp_target.c | 30 +++++------------------------- 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index b9f9fb5d7e63..504670994fb4 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -2125,32 +2125,13 @@ static ssize_t sbp_tpg_directory_id_store(struct config_item *item, return count; } -static ssize_t sbp_tpg_enable_show(struct config_item *item, char *page) +static int sbp_enable_tpg(struct se_portal_group *se_tpg, bool enable) { - struct se_portal_group *se_tpg = to_tpg(item); struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg); struct sbp_tport *tport = tpg->tport; - return sprintf(page, "%d\n", tport->enable); -} - -static ssize_t sbp_tpg_enable_store(struct config_item *item, - const char *page, size_t count) -{ - struct se_portal_group *se_tpg = to_tpg(item); - struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg); - struct sbp_tport *tport = tpg->tport; - unsigned long val; int ret; - if (kstrtoul(page, 0, &val) < 0) - return -EINVAL; - if ((val != 0) && (val != 1)) - return -EINVAL; - - if (tport->enable == val) - return count; - - if (val) { + if (enable) { if (sbp_count_se_tpg_luns(&tpg->se_tpg) == 0) { pr_err("Cannot enable a target with no LUNs!\n"); return -EINVAL; @@ -2165,7 +2146,7 @@ static ssize_t sbp_tpg_enable_store(struct config_item *item, spin_unlock_bh(&se_tpg->session_lock); } - tport->enable = val; + tport->enable = enable; ret = sbp_update_unit_directory(tport); if (ret < 0) { @@ -2173,15 +2154,13 @@ static ssize_t sbp_tpg_enable_store(struct config_item *item, return ret; } - return count; + return 0; } CONFIGFS_ATTR(sbp_tpg_, directory_id); -CONFIGFS_ATTR(sbp_tpg_, enable); static struct configfs_attribute *sbp_tpg_base_attrs[] = { &sbp_tpg_attr_directory_id, - &sbp_tpg_attr_enable, NULL, }; @@ -2319,6 +2298,7 @@ static const struct target_core_fabric_ops sbp_ops = { .fabric_make_wwn = sbp_make_tport, .fabric_drop_wwn = sbp_drop_tport, .fabric_make_tpg = sbp_make_tpg, + .fabric_enable_tpg = sbp_enable_tpg, .fabric_drop_tpg = sbp_drop_tpg, .fabric_post_link = sbp_post_link_lun, .fabric_pre_unlink = sbp_pre_unlink_lun, -- cgit From 9465b4871af07de6d4ad0ad4522f258e0c15b51a Mon Sep 17 00:00:00 2001 From: Dmitry Bogdanov Date: Fri, 10 Sep 2021 11:41:31 +0300 Subject: scsi: target: srpt: Replace enable attr with ops.enable Remove tpg/enable attribute. Add fabric ops enable_tpg implementation instead. Link: https://lore.kernel.org/r/20210910084133.17956-6-d.bogdanov@yadro.com Reviewed-by: Roman Bolshakov Reviewed-by: Bart Van Assche Reviewed-by: Mike Christie Signed-off-by: Dmitry Bogdanov Signed-off-by: Martin K. Petersen --- drivers/infiniband/ulp/srpt/ib_srpt.c | 38 ++++------------------------------- 1 file changed, 4 insertions(+), 34 deletions(-) diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 3cadf1295417..f86ee1c4b970 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -3705,47 +3705,17 @@ static struct configfs_attribute *srpt_da_attrs[] = { NULL, }; -static ssize_t srpt_tpg_enable_show(struct config_item *item, char *page) +static int srpt_enable_tpg(struct se_portal_group *se_tpg, bool enable) { - struct se_portal_group *se_tpg = to_tpg(item); struct srpt_port *sport = srpt_tpg_to_sport(se_tpg); - return sysfs_emit(page, "%d\n", sport->enabled); -} - -static ssize_t srpt_tpg_enable_store(struct config_item *item, - const char *page, size_t count) -{ - struct se_portal_group *se_tpg = to_tpg(item); - struct srpt_port *sport = srpt_tpg_to_sport(se_tpg); - unsigned long tmp; - int ret; - - ret = kstrtoul(page, 0, &tmp); - if (ret < 0) { - pr_err("Unable to extract srpt_tpg_store_enable\n"); - return -EINVAL; - } - - if ((tmp != 0) && (tmp != 1)) { - pr_err("Illegal value for srpt_tpg_store_enable: %lu\n", tmp); - return -EINVAL; - } - mutex_lock(&sport->mutex); - srpt_set_enabled(sport, tmp); + srpt_set_enabled(sport, enable); mutex_unlock(&sport->mutex); - return count; + return 0; } -CONFIGFS_ATTR(srpt_tpg_, enable); - -static struct configfs_attribute *srpt_tpg_attrs[] = { - &srpt_tpg_attr_enable, - NULL, -}; - /** * srpt_make_tpg - configfs callback invoked for mkdir /sys/kernel/config/target/$driver/$port/$tpg * @wwn: Corresponds to $driver/$port. @@ -3856,12 +3826,12 @@ static const struct target_core_fabric_ops srpt_template = { .fabric_make_wwn = srpt_make_tport, .fabric_drop_wwn = srpt_drop_tport, .fabric_make_tpg = srpt_make_tpg, + .fabric_enable_tpg = srpt_enable_tpg, .fabric_drop_tpg = srpt_drop_tpg, .fabric_init_nodeacl = srpt_init_nodeacl, .tfc_discovery_attrs = srpt_da_attrs, .tfc_wwn_attrs = srpt_wwn_attrs, - .tfc_tpg_base_attrs = srpt_tpg_attrs, .tfc_tpg_attrib_attrs = srpt_tpg_attrib_attrs, }; -- cgit From d7e2932bba1bd17b476e056c48ab1324f3a2c18d Mon Sep 17 00:00:00 2001 From: Dmitry Bogdanov Date: Fri, 10 Sep 2021 11:41:32 +0300 Subject: scsi: target: ibm_vscsi: Replace enable attr with ops.enable Remove tpg/enable attribute. Add fabric ops enable_tpg implementation instead. Link: https://lore.kernel.org/r/20210910084133.17956-7-d.bogdanov@yadro.com Reviewed-by: Roman Bolshakov Reviewed-by: Mike Christie Signed-off-by: Dmitry Bogdanov Signed-off-by: Martin K. Petersen --- drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c | 42 +++----------------------------- 1 file changed, 4 insertions(+), 38 deletions(-) diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c index 10b6c6daaacd..61f06f6885a5 100644 --- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c +++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c @@ -3948,41 +3948,16 @@ static struct configfs_attribute *ibmvscsis_wwn_attrs[] = { NULL, }; -static ssize_t ibmvscsis_tpg_enable_show(struct config_item *item, - char *page) -{ - struct se_portal_group *se_tpg = to_tpg(item); - struct ibmvscsis_tport *tport = container_of(se_tpg, - struct ibmvscsis_tport, - se_tpg); - return snprintf(page, PAGE_SIZE, "%d\n", (tport->enabled) ? 1 : 0); -} - -static ssize_t ibmvscsis_tpg_enable_store(struct config_item *item, - const char *page, size_t count) +static int ibmvscsis_enable_tpg(struct se_portal_group *se_tpg, bool enable) { - struct se_portal_group *se_tpg = to_tpg(item); struct ibmvscsis_tport *tport = container_of(se_tpg, struct ibmvscsis_tport, se_tpg); struct scsi_info *vscsi = container_of(tport, struct scsi_info, tport); - unsigned long tmp; - int rc; long lrc; - rc = kstrtoul(page, 0, &tmp); - if (rc < 0) { - dev_err(&vscsi->dev, "Unable to extract srpt_tpg_store_enable\n"); - return -EINVAL; - } - - if ((tmp != 0) && (tmp != 1)) { - dev_err(&vscsi->dev, "Illegal value for srpt_tpg_store_enable\n"); - return -EINVAL; - } - - if (tmp) { + if (enable) { spin_lock_bh(&vscsi->intr_lock); tport->enabled = true; lrc = ibmvscsis_enable_change_state(vscsi); @@ -3998,17 +3973,8 @@ static ssize_t ibmvscsis_tpg_enable_store(struct config_item *item, spin_unlock_bh(&vscsi->intr_lock); } - dev_dbg(&vscsi->dev, "tpg_enable_store, tmp %ld, state %d\n", tmp, - vscsi->state); - - return count; + return 0; } -CONFIGFS_ATTR(ibmvscsis_tpg_, enable); - -static struct configfs_attribute *ibmvscsis_tpg_attrs[] = { - &ibmvscsis_tpg_attr_enable, - NULL, -}; static const struct target_core_fabric_ops ibmvscsis_ops = { .module = THIS_MODULE, @@ -4038,10 +4004,10 @@ static const struct target_core_fabric_ops ibmvscsis_ops = { .fabric_make_wwn = ibmvscsis_make_tport, .fabric_drop_wwn = ibmvscsis_drop_tport, .fabric_make_tpg = ibmvscsis_make_tpg, + .fabric_enable_tpg = ibmvscsis_enable_tpg, .fabric_drop_tpg = ibmvscsis_drop_tpg, .tfc_wwn_attrs = ibmvscsis_wwn_attrs, - .tfc_tpg_base_attrs = ibmvscsis_tpg_attrs, }; static void ibmvscsis_dev_release(struct device *dev) {}; -- cgit From 5384ee089d1f79b027bb62b0cfa729890ca71f8b Mon Sep 17 00:00:00 2001 From: Dmitry Bogdanov Date: Fri, 10 Sep 2021 11:41:33 +0300 Subject: scsi: target: usb: Replace enable attr with ops.enable Remove tpg/enable attribute. Add fabric ops enable_tpg implementation instead. Link: https://lore.kernel.org/r/20210910084133.17956-8-d.bogdanov@yadro.com Reviewed-by: Roman Bolshakov Reviewed-by: Mike Christie Signed-off-by: Dmitry Bogdanov Signed-off-by: Martin K. Petersen --- drivers/usb/gadget/function/f_tcm.c | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c index de161ee0b1f9..8e17ac831be0 100644 --- a/drivers/usb/gadget/function/f_tcm.c +++ b/drivers/usb/gadget/function/f_tcm.c @@ -1495,42 +1495,24 @@ static struct configfs_attribute *usbg_wwn_attrs[] = { NULL, }; -static ssize_t tcm_usbg_tpg_enable_show(struct config_item *item, char *page) -{ - struct se_portal_group *se_tpg = to_tpg(item); - struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg); - - return snprintf(page, PAGE_SIZE, "%u\n", tpg->gadget_connect); -} - static int usbg_attach(struct usbg_tpg *); static void usbg_detach(struct usbg_tpg *); -static ssize_t tcm_usbg_tpg_enable_store(struct config_item *item, - const char *page, size_t count) +static int usbg_enable_tpg(struct se_portal_group *se_tpg, bool enable) { - struct se_portal_group *se_tpg = to_tpg(item); struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg); - bool op; - ssize_t ret; - - ret = strtobool(page, &op); - if (ret) - return ret; - - if ((op && tpg->gadget_connect) || (!op && !tpg->gadget_connect)) - return -EINVAL; + int ret = 0; - if (op) + if (enable) ret = usbg_attach(tpg); else usbg_detach(tpg); if (ret) return ret; - tpg->gadget_connect = op; + tpg->gadget_connect = enable; - return count; + return 0; } static ssize_t tcm_usbg_tpg_nexus_show(struct config_item *item, char *page) @@ -1673,11 +1655,9 @@ static ssize_t tcm_usbg_tpg_nexus_store(struct config_item *item, return count; } -CONFIGFS_ATTR(tcm_usbg_tpg_, enable); CONFIGFS_ATTR(tcm_usbg_tpg_, nexus); static struct configfs_attribute *usbg_base_attrs[] = { - &tcm_usbg_tpg_attr_enable, &tcm_usbg_tpg_attr_nexus, NULL, }; @@ -1730,6 +1710,7 @@ static const struct target_core_fabric_ops usbg_ops = { .fabric_make_wwn = usbg_make_tport, .fabric_drop_wwn = usbg_drop_tport, .fabric_make_tpg = usbg_make_tpg, + .fabric_enable_tpg = usbg_enable_tpg, .fabric_drop_tpg = usbg_drop_tpg, .fabric_post_link = usbg_port_link, .fabric_pre_unlink = usbg_port_unlink, -- cgit From c20bda341946c8ee77baec3bec7c5cd615ddf869 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 27 Sep 2021 17:43:44 -0500 Subject: scsi: target: tcmu: Use struct_size() helper in kmalloc() Make use of the struct_size() helper instead of an open-coded version, in order to avoid any potential type mistakes or integer overflows that, in the worst scenario, could lead to heap overflows. Link: https://github.com/KSPP/linux/issues/160 Link: https://lore.kernel.org/r/20210927224344.GA190701@embeddedor Reviewed-by: Bodo Stroesser Signed-off-by: Gustavo A. R. Silva Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 9f552f48084c..dc220fad06fa 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1255,7 +1255,6 @@ tcmu_tmr_notify(struct se_device *se_dev, enum tcm_tmreq_table tmf, { int i = 0, cmd_cnt = 0; bool unqueued = false; - uint16_t *cmd_ids = NULL; struct tcmu_cmd *cmd; struct se_cmd *se_cmd; struct tcmu_tmr *tmr; @@ -1292,7 +1291,7 @@ tcmu_tmr_notify(struct se_device *se_dev, enum tcm_tmreq_table tmf, pr_debug("TMR event %d on dev %s, aborted cmds %d, afflicted cmd_ids %d\n", tcmu_tmr_type(tmf), udev->name, i, cmd_cnt); - tmr = kmalloc(sizeof(*tmr) + cmd_cnt * sizeof(*cmd_ids), GFP_NOIO); + tmr = kmalloc(struct_size(tmr, tmr_cmd_ids, cmd_cnt), GFP_NOIO); if (!tmr) goto unlock; -- cgit From 4f632918e7a87d0da7c0bcb3f8242f62725dad44 Mon Sep 17 00:00:00 2001 From: Igor Pylypiv Date: Tue, 28 Sep 2021 19:58:07 -0700 Subject: scsi: pm80xx: Replace open coded check with dev_is_expander() This is a follow up cleanup to the commit 924a3541eab0 ("scsi: libsas: aic94xx: hisi_sas: mvsas: pm8001: Use dev_is_expander()") Link: https://lore.kernel.org/r/20210929025807.646589-1-ipylypiv@google.com Reviewed-by: Vishakha Channapattan Acked-by: Jack Wang Signed-off-by: Igor Pylypiv Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_hwi.c | 3 +-- drivers/scsi/pm8001/pm80xx_hwi.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index c9ecddd0d719..275bc322a6f3 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -4481,8 +4481,7 @@ static int pm8001_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, if (pm8001_dev->dev_type == SAS_SATA_DEV) stp_sspsmp_sata = 0x00; /* stp*/ else if (pm8001_dev->dev_type == SAS_END_DEVICE || - pm8001_dev->dev_type == SAS_EDGE_EXPANDER_DEVICE || - pm8001_dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE) + dev_is_expander(pm8001_dev->dev_type)) stp_sspsmp_sata = 0x01; /*ssp or smp*/ } if (parent_dev && dev_is_expander(parent_dev->dev_type)) diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 1ae2f5c6042c..b9f6d83ff380 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -4865,8 +4865,7 @@ static int pm80xx_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, if (pm8001_dev->dev_type == SAS_SATA_DEV) stp_sspsmp_sata = 0x00; /* stp*/ else if (pm8001_dev->dev_type == SAS_END_DEVICE || - pm8001_dev->dev_type == SAS_EDGE_EXPANDER_DEVICE || - pm8001_dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE) + dev_is_expander(pm8001_dev->dev_type)) stp_sspsmp_sata = 0x01; /*ssp or smp*/ } if (parent_dev && dev_is_expander(parent_dev->dev_type)) -- cgit From 4084a7235d38311a77c86ba69ba849bd787db87b Mon Sep 17 00:00:00 2001 From: Igor Pylypiv Date: Tue, 28 Sep 2021 19:58:47 -0700 Subject: scsi: pm80xx: Fix misleading log statement in pm8001_mpi_get_nvmd_resp() pm8001_mpi_get_nvmd_resp() handles a GET_NVMD_DATA response, not a SET_NVMD_DATA response, as the log statement implies. Fixes: 1f889b58716a ("scsi: pm80xx: Fix pm8001_mpi_get_nvmd_resp() race condition") Link: https://lore.kernel.org/r/20210929025847.646999-1-ipylypiv@google.com Reviewed-by: Changyuan Lyu Acked-by: Jack Wang Signed-off-by: Igor Pylypiv Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_hwi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 275bc322a6f3..124cb69740c6 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -3169,7 +3169,7 @@ pm8001_mpi_get_nvmd_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) * fw_control_context->usrAddr */ complete(pm8001_ha->nvmd_completion); - pm8001_dbg(pm8001_ha, MSG, "Set nvm data complete!\n"); + pm8001_dbg(pm8001_ha, MSG, "Get nvmd data complete!\n"); ccb->task = NULL; ccb->ccb_tag = 0xFFFFFFFF; pm8001_tag_free(pm8001_ha, tag); -- cgit From 76a4f7cc5973608556c68ac1da60d29c4a6c1d30 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 16 Sep 2021 16:26:05 +0300 Subject: scsi: mpi3mr: Clean up mpi3mr_print_ioc_info() This function is more complicated than necessary. If we change from scnprintf() to snprintf() that lets us remove the if bytes_wrote < sizeof(protocol) checks. Also, we can use bytes_wrote ? "," : "" to print the comma and remove the separate if statement and the "is_string_nonempty" variable. [mkp: a few formatting cleanups and s/wrote/written/] Link: https://lore.kernel.org/r/20210916132605.GF25094@kili Signed-off-by: Dan Carpenter Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_fw.c | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index 4a8316c6bd41..e34417a2429a 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -3018,11 +3018,10 @@ static const struct { static void mpi3mr_print_ioc_info(struct mpi3mr_ioc *mrioc) { - int i = 0, bytes_wrote = 0; + int i = 0, bytes_written = 0; char personality[16]; char protocol[50] = {0}; char capabilities[100] = {0}; - bool is_string_nonempty = false; struct mpi3mr_compimg_ver *fwver = &mrioc->facts.fw_ver; switch (mrioc->facts.personality) { @@ -3046,39 +3045,26 @@ mpi3mr_print_ioc_info(struct mpi3mr_ioc *mrioc) for (i = 0; i < ARRAY_SIZE(mpi3mr_protocols); i++) { if (mrioc->facts.protocol_flags & mpi3mr_protocols[i].protocol) { - if (is_string_nonempty && - (bytes_wrote < sizeof(protocol))) - bytes_wrote += snprintf(protocol + bytes_wrote, - (sizeof(protocol) - bytes_wrote), ","); - - if (bytes_wrote < sizeof(protocol)) - bytes_wrote += snprintf(protocol + bytes_wrote, - (sizeof(protocol) - bytes_wrote), "%s", + bytes_written += snprintf(protocol + bytes_written, + sizeof(protocol) - bytes_written, "%s%s", + bytes_written ? "," : "", mpi3mr_protocols[i].name); - is_string_nonempty = true; } } - bytes_wrote = 0; - is_string_nonempty = false; + bytes_written = 0; for (i = 0; i < ARRAY_SIZE(mpi3mr_capabilities); i++) { if (mrioc->facts.protocol_flags & mpi3mr_capabilities[i].capability) { - if (is_string_nonempty && - (bytes_wrote < sizeof(capabilities))) - bytes_wrote += snprintf(capabilities + bytes_wrote, - (sizeof(capabilities) - bytes_wrote), ","); - - if (bytes_wrote < sizeof(capabilities)) - bytes_wrote += snprintf(capabilities + bytes_wrote, - (sizeof(capabilities) - bytes_wrote), "%s", + bytes_written += snprintf(capabilities + bytes_written, + sizeof(capabilities) - bytes_written, "%s%s", + bytes_written ? "," : "", mpi3mr_capabilities[i].name); - is_string_nonempty = true; } } ioc_info(mrioc, "Protocol=(%s), Capabilities=(%s)\n", - protocol, capabilities); + protocol, capabilities); } /** -- cgit From 819225b03dc73294a563d3ee9e24e04c71e7afe0 Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 28 Sep 2021 18:54:32 -0500 Subject: scsi: smartpqi: Update device removal management Update device removal path to handle issues for: - rmmod: Correct stack trace when removing devices. - rmmod: Synchronize SCSI cache. - Update handling for removing devices using sysfs. Link: https://lore.kernel.org/r/20210928235442.201875-2-don.brace@microchip.com Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Reviewed-by: Mike McGowen Acked-by: John Donnelly Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 64 +++++++++++++++-------------------- 1 file changed, 28 insertions(+), 36 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index ecb2af3f43ca..97027574eb1f 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -1693,8 +1693,6 @@ static inline void pqi_remove_device(struct pqi_ctrl_info *ctrl_info, struct pqi { int rc; - pqi_device_remove_start(device); - rc = pqi_device_wait_for_pending_io(ctrl_info, device, PQI_REMOVE_DEVICE_PENDING_IO_TIMEOUT_MSECS); if (rc) @@ -1708,6 +1706,8 @@ static inline void pqi_remove_device(struct pqi_ctrl_info *ctrl_info, struct pqi scsi_remove_device(device->sdev); else pqi_remove_sas_device(device); + + pqi_device_remove_start(device); } /* Assumes the SCSI device list lock is held. */ @@ -1986,7 +1986,7 @@ static void pqi_update_device_list(struct pqi_ctrl_info *ctrl_info, list_for_each_entry_safe(device, next, &ctrl_info->scsi_device_list, scsi_device_list_entry) { if (device->device_gone) { - list_del_init(&device->scsi_device_list_entry); + list_del(&device->scsi_device_list_entry); list_add_tail(&device->delete_list_entry, &delete_list); } } @@ -2025,15 +2025,13 @@ static void pqi_update_device_list(struct pqi_ctrl_info *ctrl_info, if (device->volume_offline) { pqi_dev_info(ctrl_info, "offline", device); pqi_show_volume_status(ctrl_info, device); - } - list_del(&device->delete_list_entry); - if (pqi_is_device_added(device)) { - pqi_remove_device(ctrl_info, device); } else { - if (!device->volume_offline) - pqi_dev_info(ctrl_info, "removed", device); - pqi_free_device(device); + pqi_dev_info(ctrl_info, "removed", device); } + if (pqi_is_device_added(device)) + pqi_remove_device(ctrl_info, device); + list_del(&device->delete_list_entry); + pqi_free_device(device); } /* @@ -2328,6 +2326,25 @@ out: return rc; } +static void pqi_remove_all_scsi_devices(struct pqi_ctrl_info *ctrl_info) +{ + unsigned long flags; + struct pqi_scsi_dev *device; + struct pqi_scsi_dev *next; + + spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags); + + list_for_each_entry_safe(device, next, &ctrl_info->scsi_device_list, + scsi_device_list_entry) { + if (pqi_is_device_added(device)) + pqi_remove_device(ctrl_info, device); + list_del(&device->scsi_device_list_entry); + pqi_free_device(device); + } + + spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags); +} + static int pqi_scan_scsi_devices(struct pqi_ctrl_info *ctrl_info) { int rc; @@ -6120,31 +6137,6 @@ static int pqi_slave_configure(struct scsi_device *sdev) return 0; } -static void pqi_slave_destroy(struct scsi_device *sdev) -{ - unsigned long flags; - struct pqi_scsi_dev *device; - struct pqi_ctrl_info *ctrl_info; - - ctrl_info = shost_to_hba(sdev->host); - - spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags); - - device = sdev->hostdata; - if (device) { - sdev->hostdata = NULL; - if (!list_empty(&device->scsi_device_list_entry)) - list_del(&device->scsi_device_list_entry); - } - - spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags); - - if (device) { - pqi_dev_info(ctrl_info, "removed", device); - pqi_free_device(device); - } -} - static int pqi_getpciinfo_ioctl(struct pqi_ctrl_info *ctrl_info, void __user *arg) { struct pci_dev *pci_dev; @@ -6938,7 +6930,6 @@ static struct scsi_host_template pqi_driver_template = { .ioctl = pqi_ioctl, .slave_alloc = pqi_slave_alloc, .slave_configure = pqi_slave_configure, - .slave_destroy = pqi_slave_destroy, .map_queues = pqi_map_queues, .sdev_attrs = pqi_sdev_attrs, .shost_attrs = pqi_shost_attrs, @@ -8169,6 +8160,7 @@ static void pqi_remove_ctrl(struct pqi_ctrl_info *ctrl_info) { pqi_cancel_rescan_worker(ctrl_info); pqi_cancel_update_time_worker(ctrl_info); + pqi_remove_all_scsi_devices(ctrl_info); pqi_unregister_scsi(ctrl_info); if (ctrl_info->pqi_mode_enabled) pqi_revert_to_sis_mode(ctrl_info); -- cgit From 9ee5d6e9ac52a3c8625697535f8e35864d9fd38c Mon Sep 17 00:00:00 2001 From: Mahesh Rajashekhara Date: Tue, 28 Sep 2021 18:54:33 -0500 Subject: scsi: smartpqi: Add controller handshake during kdump Correct kdump hangs when controller is locked up. There are occasions when a controller reboot (controller soft reset) is issued when a controller firmware crash dump is in progress. This leads to incomplete controller firmware crash dump: - When the controller crash dump is in progress, and a kdump is initiated, the driver issues inbound doorbell reset to bring back the controller in SIS mode. - If the controller is in locked up state, the inbound doorbell reset does not work causing controller initialization failures. This results in the driver hanging waiting for SIS mode. To avoid an incomplete controller crash dump, add in a controller crash dump handshake: - Controller will indicate start and end of the controller crash dump by setting some register bits. - Driver will look these bits when a kdump is initiated. If a controller crash dump is in progress, the driver will wait for the controller crash dump to complete before issuing the controller soft reset then complete driver initialization. Link: https://lore.kernel.org/r/20210928235442.201875-3-don.brace@microchip.com Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Reviewed-by: Mike McGowen Acked-by: John Donnelly Signed-off-by: Mahesh Rajashekhara Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 41 ++++++++++++++++++++++++++-- drivers/scsi/smartpqi/smartpqi_sis.c | 51 +++++++++++++++++++++++++++++++++++ drivers/scsi/smartpqi/smartpqi_sis.h | 1 + 3 files changed, 91 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 97027574eb1f..5655d240f7a7 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -234,15 +234,46 @@ static inline bool pqi_is_hba_lunid(u8 *scsi3addr) return pqi_scsi3addr_equal(scsi3addr, RAID_CTLR_LUNID); } +#define PQI_DRIVER_SCRATCH_PQI_MODE 0x1 +#define PQI_DRIVER_SCRATCH_FW_TRIAGE_SUPPORTED 0x2 + static inline enum pqi_ctrl_mode pqi_get_ctrl_mode(struct pqi_ctrl_info *ctrl_info) { - return sis_read_driver_scratch(ctrl_info); + return sis_read_driver_scratch(ctrl_info) & PQI_DRIVER_SCRATCH_PQI_MODE ? PQI_MODE : SIS_MODE; } static inline void pqi_save_ctrl_mode(struct pqi_ctrl_info *ctrl_info, enum pqi_ctrl_mode mode) { - sis_write_driver_scratch(ctrl_info, mode); + u32 driver_scratch; + + driver_scratch = sis_read_driver_scratch(ctrl_info); + + if (mode == PQI_MODE) + driver_scratch |= PQI_DRIVER_SCRATCH_PQI_MODE; + else + driver_scratch &= ~PQI_DRIVER_SCRATCH_PQI_MODE; + + sis_write_driver_scratch(ctrl_info, driver_scratch); +} + +static inline bool pqi_is_fw_triage_supported(struct pqi_ctrl_info *ctrl_info) +{ + return (sis_read_driver_scratch(ctrl_info) & PQI_DRIVER_SCRATCH_FW_TRIAGE_SUPPORTED) != 0; +} + +static inline void pqi_save_fw_triage_setting(struct pqi_ctrl_info *ctrl_info, bool is_supported) +{ + u32 driver_scratch; + + driver_scratch = sis_read_driver_scratch(ctrl_info); + + if (is_supported) + driver_scratch |= PQI_DRIVER_SCRATCH_FW_TRIAGE_SUPPORTED; + else + driver_scratch &= ~PQI_DRIVER_SCRATCH_FW_TRIAGE_SUPPORTED; + + sis_write_driver_scratch(ctrl_info, driver_scratch); } static inline void pqi_ctrl_block_scan(struct pqi_ctrl_info *ctrl_info) @@ -7292,6 +7323,7 @@ static void pqi_ctrl_update_feature_flags(struct pqi_ctrl_info *ctrl_info, ctrl_info->unique_wwid_in_report_phys_lun_supported = firmware_feature->enabled; break; + pqi_save_fw_triage_setting(ctrl_info, firmware_feature->enabled); } pqi_firmware_feature_status(ctrl_info, firmware_feature); @@ -7618,6 +7650,11 @@ static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info) u32 product_id; if (reset_devices) { + if (pqi_is_fw_triage_supported(ctrl_info)) { + rc = sis_wait_for_fw_triage_completion(ctrl_info); + if (rc) + return rc; + } sis_soft_reset(ctrl_info); msleep(PQI_POST_RESET_DELAY_SECS * PQI_HZ); } else { diff --git a/drivers/scsi/smartpqi/smartpqi_sis.c b/drivers/scsi/smartpqi/smartpqi_sis.c index d63c46a8e38b..8acd3a80f582 100644 --- a/drivers/scsi/smartpqi/smartpqi_sis.c +++ b/drivers/scsi/smartpqi/smartpqi_sis.c @@ -51,12 +51,20 @@ #define SIS_BASE_STRUCT_REVISION 9 #define SIS_BASE_STRUCT_ALIGNMENT 16 +#define SIS_CTRL_KERNEL_FW_TRIAGE 0x3 #define SIS_CTRL_KERNEL_UP 0x80 #define SIS_CTRL_KERNEL_PANIC 0x100 #define SIS_CTRL_READY_TIMEOUT_SECS 180 #define SIS_CTRL_READY_RESUME_TIMEOUT_SECS 90 #define SIS_CTRL_READY_POLL_INTERVAL_MSECS 10 +enum sis_fw_triage_status { + FW_TRIAGE_NOT_STARTED = 0, + FW_TRIAGE_STARTED, + FW_TRIAGE_COND_INVALID, + FW_TRIAGE_COMPLETED +}; + #pragma pack(1) /* for use with SIS_CMD_INIT_BASE_STRUCT_ADDRESS command */ @@ -419,12 +427,55 @@ u32 sis_read_driver_scratch(struct pqi_ctrl_info *ctrl_info) return readl(&ctrl_info->registers->sis_driver_scratch); } +static inline enum sis_fw_triage_status + sis_read_firmware_triage_status(struct pqi_ctrl_info *ctrl_info) +{ + return ((enum sis_fw_triage_status)(readl(&ctrl_info->registers->sis_firmware_status) & + SIS_CTRL_KERNEL_FW_TRIAGE)); +} + void sis_soft_reset(struct pqi_ctrl_info *ctrl_info) { writel(SIS_SOFT_RESET, &ctrl_info->registers->sis_host_to_ctrl_doorbell); } +#define SIS_FW_TRIAGE_STATUS_TIMEOUT_SECS 300 +#define SIS_FW_TRIAGE_STATUS_POLL_INTERVAL_SECS 1 + +int sis_wait_for_fw_triage_completion(struct pqi_ctrl_info *ctrl_info) +{ + int rc; + enum sis_fw_triage_status status; + unsigned long timeout; + + timeout = (SIS_FW_TRIAGE_STATUS_TIMEOUT_SECS * PQI_HZ) + jiffies; + while (1) { + status = sis_read_firmware_triage_status(ctrl_info); + if (status == FW_TRIAGE_COND_INVALID) { + dev_err(&ctrl_info->pci_dev->dev, + "firmware triage condition invalid\n"); + rc = -EINVAL; + break; + } else if (status == FW_TRIAGE_NOT_STARTED || + status == FW_TRIAGE_COMPLETED) { + rc = 0; + break; + } + + if (time_after(jiffies, timeout)) { + dev_err(&ctrl_info->pci_dev->dev, + "timed out waiting for firmware triage status\n"); + rc = -ETIMEDOUT; + break; + } + + ssleep(SIS_FW_TRIAGE_STATUS_POLL_INTERVAL_SECS); + } + + return rc; +} + static void __attribute__((unused)) verify_structures(void) { BUILD_BUG_ON(offsetof(struct sis_base_struct, diff --git a/drivers/scsi/smartpqi/smartpqi_sis.h b/drivers/scsi/smartpqi/smartpqi_sis.h index d29c1352a826..c1db93054c86 100644 --- a/drivers/scsi/smartpqi/smartpqi_sis.h +++ b/drivers/scsi/smartpqi/smartpqi_sis.h @@ -28,5 +28,6 @@ void sis_write_driver_scratch(struct pqi_ctrl_info *ctrl_info, u32 value); u32 sis_read_driver_scratch(struct pqi_ctrl_info *ctrl_info); void sis_soft_reset(struct pqi_ctrl_info *ctrl_info); u32 sis_get_product_id(struct pqi_ctrl_info *ctrl_info); +int sis_wait_for_fw_triage_completion(struct pqi_ctrl_info *ctrl_info); #endif /* _SMARTPQI_SIS_H */ -- cgit From 5d1f03e6f49ae80d417dc72d1ee16a3379e2c026 Mon Sep 17 00:00:00 2001 From: Murthy Bhat Date: Tue, 28 Sep 2021 18:54:34 -0500 Subject: scsi: smartpqi: Capture controller reason codes In some rare cases, the driver can halt the controller. Add a reason code describing why the controller was halted. Store this reason code in a controller register to aid in debugging the issue. Link: https://lore.kernel.org/r/20210928235442.201875-4-don.brace@microchip.com Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Reviewed-by: Mike McGowen Acked-by: John Donnelly Signed-off-by: Murthy Bhat Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi.h | 25 +++++++++++++++++++--- drivers/scsi/smartpqi/smartpqi_init.c | 40 +++++++++++++++++++++++------------ drivers/scsi/smartpqi/smartpqi_sis.c | 9 +++++--- drivers/scsi/smartpqi/smartpqi_sis.h | 3 ++- 4 files changed, 57 insertions(+), 20 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h index 70eca203d72f..d66863f8d1cf 100644 --- a/drivers/scsi/smartpqi/smartpqi.h +++ b/drivers/scsi/smartpqi/smartpqi.h @@ -82,9 +82,11 @@ struct pqi_ctrl_registers { __le32 sis_product_identifier; /* B4h */ u8 reserved5[0xbc - (0xb4 + sizeof(__le32))]; __le32 sis_firmware_status; /* BCh */ - u8 reserved6[0x1000 - (0xbc + sizeof(__le32))]; + u8 reserved6[0xcc - (0xbc + sizeof(__le32))]; + __le32 sis_ctrl_shutdown_reason_code; /* CCh */ + u8 reserved7[0x1000 - (0xcc + sizeof(__le32))]; __le32 sis_mailbox[8]; /* 1000h */ - u8 reserved7[0x4000 - (0x1000 + (sizeof(__le32) * 8))]; + u8 reserved8[0x4000 - (0x1000 + (sizeof(__le32) * 8))]; /* * The PQI spec states that the PQI registers should be at * offset 0 from the PCIe BAR 0. However, we can't map @@ -102,6 +104,21 @@ struct pqi_ctrl_registers { #define PQI_DEVICE_REGISTERS_OFFSET 0x4000 +/* shutdown reasons for taking the controller offline */ +enum pqi_ctrl_shutdown_reason { + PQI_IQ_NOT_DRAINED_TIMEOUT = 1, + PQI_LUN_RESET_TIMEOUT = 2, + PQI_IO_PENDING_POST_LUN_RESET_TIMEOUT = 3, + PQI_NO_HEARTBEAT = 4, + PQI_FIRMWARE_KERNEL_NOT_UP = 5, + PQI_OFA_RESPONSE_TIMEOUT = 6, + PQI_INVALID_REQ_ID = 7, + PQI_UNMATCHED_REQ_ID = 8, + PQI_IO_PI_OUT_OF_RANGE = 9, + PQI_EVENT_PI_OUT_OF_RANGE = 10, + PQI_UNEXPECTED_IU_TYPE = 11 +}; + enum pqi_io_path { RAID_PATH = 0, AIO_PATH = 1 @@ -850,7 +867,8 @@ struct pqi_config_table_firmware_features { #define PQI_FIRMWARE_FEATURE_TMF_IU_TIMEOUT 14 #define PQI_FIRMWARE_FEATURE_RAID_BYPASS_ON_ENCRYPTED_NVME 15 #define PQI_FIRMWARE_FEATURE_UNIQUE_WWID_IN_REPORT_PHYS_LUN 16 -#define PQI_FIRMWARE_FEATURE_MAXIMUM 16 +#define PQI_FIRMWARE_FEATURE_FW_TRIAGE 17 +#define PQI_FIRMWARE_FEATURE_MAXIMUM 17 struct pqi_config_table_debug { struct pqi_config_table_section_header header; @@ -1297,6 +1315,7 @@ struct pqi_ctrl_info { u8 raid_iu_timeout_supported : 1; u8 tmf_iu_timeout_supported : 1; u8 unique_wwid_in_report_phys_lun_supported : 1; + u8 firmware_triage_supported : 1; u8 enable_r1_writes : 1; u8 enable_r5_writes : 1; u8 enable_r6_writes : 1; diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 5655d240f7a7..b6ac4d607664 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -54,7 +54,8 @@ MODULE_DESCRIPTION("Driver for Microchip Smart Family Controller version " MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); -static void pqi_take_ctrl_offline(struct pqi_ctrl_info *ctrl_info); +static void pqi_take_ctrl_offline(struct pqi_ctrl_info *ctrl_info, + enum pqi_ctrl_shutdown_reason ctrl_shutdown_reason); static void pqi_ctrl_offline_worker(struct work_struct *work); static int pqi_scan_scsi_devices(struct pqi_ctrl_info *ctrl_info); static void pqi_scan_start(struct Scsi_Host *shost); @@ -226,7 +227,7 @@ static inline void pqi_check_ctrl_health(struct pqi_ctrl_info *ctrl_info) { if (ctrl_info->controller_online) if (!sis_is_firmware_running(ctrl_info)) - pqi_take_ctrl_offline(ctrl_info); + pqi_take_ctrl_offline(ctrl_info, PQI_FIRMWARE_KERNEL_NOT_UP); } static inline bool pqi_is_hba_lunid(u8 *scsi3addr) @@ -3180,9 +3181,10 @@ static int pqi_interpret_task_management_response(struct pqi_ctrl_info *ctrl_inf return rc; } -static inline void pqi_invalid_response(struct pqi_ctrl_info *ctrl_info) +static inline void pqi_invalid_response(struct pqi_ctrl_info *ctrl_info, + enum pqi_ctrl_shutdown_reason ctrl_shutdown_reason) { - pqi_take_ctrl_offline(ctrl_info); + pqi_take_ctrl_offline(ctrl_info, ctrl_shutdown_reason); } static int pqi_process_io_intr(struct pqi_ctrl_info *ctrl_info, struct pqi_queue_group *queue_group) @@ -3200,7 +3202,7 @@ static int pqi_process_io_intr(struct pqi_ctrl_info *ctrl_info, struct pqi_queue while (1) { oq_pi = readl(queue_group->oq_pi); if (oq_pi >= ctrl_info->num_elements_per_oq) { - pqi_invalid_response(ctrl_info); + pqi_invalid_response(ctrl_info, PQI_IO_PI_OUT_OF_RANGE); dev_err(&ctrl_info->pci_dev->dev, "I/O interrupt: producer index (%u) out of range (0-%u): consumer index: %u\n", oq_pi, ctrl_info->num_elements_per_oq - 1, oq_ci); @@ -3215,7 +3217,7 @@ static int pqi_process_io_intr(struct pqi_ctrl_info *ctrl_info, struct pqi_queue request_id = get_unaligned_le16(&response->request_id); if (request_id >= ctrl_info->max_io_slots) { - pqi_invalid_response(ctrl_info); + pqi_invalid_response(ctrl_info, PQI_INVALID_REQ_ID); dev_err(&ctrl_info->pci_dev->dev, "request ID in response (%u) out of range (0-%u): producer index: %u consumer index: %u\n", request_id, ctrl_info->max_io_slots - 1, oq_pi, oq_ci); @@ -3224,7 +3226,7 @@ static int pqi_process_io_intr(struct pqi_ctrl_info *ctrl_info, struct pqi_queue io_request = &ctrl_info->io_request_pool[request_id]; if (atomic_read(&io_request->refcount) == 0) { - pqi_invalid_response(ctrl_info); + pqi_invalid_response(ctrl_info, PQI_UNMATCHED_REQ_ID); dev_err(&ctrl_info->pci_dev->dev, "request ID in response (%u) does not match an outstanding I/O request: producer index: %u consumer index: %u\n", request_id, oq_pi, oq_ci); @@ -3260,7 +3262,7 @@ static int pqi_process_io_intr(struct pqi_ctrl_info *ctrl_info, struct pqi_queue pqi_process_io_error(response->header.iu_type, io_request); break; default: - pqi_invalid_response(ctrl_info); + pqi_invalid_response(ctrl_info, PQI_UNEXPECTED_IU_TYPE); dev_err(&ctrl_info->pci_dev->dev, "unexpected IU type: 0x%x: producer index: %u consumer index: %u\n", response->header.iu_type, oq_pi, oq_ci); @@ -3442,7 +3444,7 @@ static void pqi_process_soft_reset(struct pqi_ctrl_info *ctrl_info) pqi_ofa_free_host_buffer(ctrl_info); pqi_ctrl_ofa_done(ctrl_info); pqi_ofa_ctrl_unquiesce(ctrl_info); - pqi_take_ctrl_offline(ctrl_info); + pqi_take_ctrl_offline(ctrl_info, PQI_OFA_RESPONSE_TIMEOUT); break; } } @@ -3567,7 +3569,7 @@ static void pqi_heartbeat_timer_handler(struct timer_list *t) dev_err(&ctrl_info->pci_dev->dev, "no heartbeat detected - last heartbeat count: %u\n", heartbeat_count); - pqi_take_ctrl_offline(ctrl_info); + pqi_take_ctrl_offline(ctrl_info, PQI_NO_HEARTBEAT); return; } } else { @@ -3631,7 +3633,7 @@ static int pqi_process_event_intr(struct pqi_ctrl_info *ctrl_info) while (1) { oq_pi = readl(event_queue->oq_pi); if (oq_pi >= PQI_NUM_EVENT_QUEUE_ELEMENTS) { - pqi_invalid_response(ctrl_info); + pqi_invalid_response(ctrl_info, PQI_EVENT_PI_OUT_OF_RANGE); dev_err(&ctrl_info->pci_dev->dev, "event interrupt: producer index (%u) out of range (0-%u): consumer index: %u\n", oq_pi, PQI_NUM_EVENT_QUEUE_ELEMENTS - 1, oq_ci); @@ -7323,7 +7325,10 @@ static void pqi_ctrl_update_feature_flags(struct pqi_ctrl_info *ctrl_info, ctrl_info->unique_wwid_in_report_phys_lun_supported = firmware_feature->enabled; break; + case PQI_FIRMWARE_FEATURE_FW_TRIAGE: + ctrl_info->firmware_triage_supported = firmware_feature->enabled; pqi_save_fw_triage_setting(ctrl_info, firmware_feature->enabled); + break; } pqi_firmware_feature_status(ctrl_info, firmware_feature); @@ -7419,6 +7424,11 @@ static struct pqi_firmware_feature pqi_firmware_features[] = { .feature_bit = PQI_FIRMWARE_FEATURE_UNIQUE_WWID_IN_REPORT_PHYS_LUN, .feature_status = pqi_ctrl_update_feature_flags, }, + { + .feature_name = "Firmware Triage", + .feature_bit = PQI_FIRMWARE_FEATURE_FW_TRIAGE, + .feature_status = pqi_ctrl_update_feature_flags, + }, }; static void pqi_process_firmware_features( @@ -7519,6 +7529,7 @@ static void pqi_ctrl_reset_config(struct pqi_ctrl_info *ctrl_info) ctrl_info->raid_iu_timeout_supported = false; ctrl_info->tmf_iu_timeout_supported = false; ctrl_info->unique_wwid_in_report_phys_lun_supported = false; + ctrl_info->firmware_triage_supported = false; } static int pqi_process_config_table(struct pqi_ctrl_info *ctrl_info) @@ -8459,7 +8470,8 @@ static void pqi_ctrl_offline_worker(struct work_struct *work) pqi_take_ctrl_offline_deferred(ctrl_info); } -static void pqi_take_ctrl_offline(struct pqi_ctrl_info *ctrl_info) +static void pqi_take_ctrl_offline(struct pqi_ctrl_info *ctrl_info, + enum pqi_ctrl_shutdown_reason ctrl_shutdown_reason) { if (!ctrl_info->controller_online) return; @@ -8468,7 +8480,7 @@ static void pqi_take_ctrl_offline(struct pqi_ctrl_info *ctrl_info) ctrl_info->pqi_mode_enabled = false; pqi_ctrl_block_requests(ctrl_info); if (!pqi_disable_ctrl_shutdown) - sis_shutdown_ctrl(ctrl_info); + sis_shutdown_ctrl(ctrl_info, ctrl_shutdown_reason); pci_disable_device(ctrl_info->pci_dev); dev_err(&ctrl_info->pci_dev->dev, "controller offline\n"); schedule_work(&ctrl_info->ctrl_offline_work); @@ -9303,6 +9315,8 @@ static void __attribute__((unused)) verify_structures(void) sis_product_identifier) != 0xb4); BUILD_BUG_ON(offsetof(struct pqi_ctrl_registers, sis_firmware_status) != 0xbc); + BUILD_BUG_ON(offsetof(struct pqi_ctrl_registers, + sis_ctrl_shutdown_reason_code) != 0xcc); BUILD_BUG_ON(offsetof(struct pqi_ctrl_registers, sis_mailbox) != 0x1000); BUILD_BUG_ON(offsetof(struct pqi_ctrl_registers, diff --git a/drivers/scsi/smartpqi/smartpqi_sis.c b/drivers/scsi/smartpqi/smartpqi_sis.c index 8acd3a80f582..d66eb8ea161c 100644 --- a/drivers/scsi/smartpqi/smartpqi_sis.c +++ b/drivers/scsi/smartpqi/smartpqi_sis.c @@ -397,14 +397,17 @@ void sis_enable_intx(struct pqi_ctrl_info *ctrl_info) sis_set_doorbell_bit(ctrl_info, SIS_ENABLE_INTX); } -void sis_shutdown_ctrl(struct pqi_ctrl_info *ctrl_info) +void sis_shutdown_ctrl(struct pqi_ctrl_info *ctrl_info, + enum pqi_ctrl_shutdown_reason ctrl_shutdown_reason) { if (readl(&ctrl_info->registers->sis_firmware_status) & SIS_CTRL_KERNEL_PANIC) return; - writel(SIS_TRIGGER_SHUTDOWN, - &ctrl_info->registers->sis_host_to_ctrl_doorbell); + if (ctrl_info->firmware_triage_supported) + writel(ctrl_shutdown_reason, &ctrl_info->registers->sis_ctrl_shutdown_reason_code); + + writel(SIS_TRIGGER_SHUTDOWN, &ctrl_info->registers->sis_host_to_ctrl_doorbell); } int sis_pqi_reset_quiesce(struct pqi_ctrl_info *ctrl_info) diff --git a/drivers/scsi/smartpqi/smartpqi_sis.h b/drivers/scsi/smartpqi/smartpqi_sis.h index c1db93054c86..bd92ff49f385 100644 --- a/drivers/scsi/smartpqi/smartpqi_sis.h +++ b/drivers/scsi/smartpqi/smartpqi_sis.h @@ -21,7 +21,8 @@ int sis_get_pqi_capabilities(struct pqi_ctrl_info *ctrl_info); int sis_init_base_struct_addr(struct pqi_ctrl_info *ctrl_info); void sis_enable_msix(struct pqi_ctrl_info *ctrl_info); void sis_enable_intx(struct pqi_ctrl_info *ctrl_info); -void sis_shutdown_ctrl(struct pqi_ctrl_info *ctrl_info); +void sis_shutdown_ctrl(struct pqi_ctrl_info *ctrl_info, + enum pqi_ctrl_shutdown_reason ctrl_shutdown_reason); int sis_pqi_reset_quiesce(struct pqi_ctrl_info *ctrl_info); int sis_reenable_sis_mode(struct pqi_ctrl_info *ctrl_info); void sis_write_driver_scratch(struct pqi_ctrl_info *ctrl_info, u32 value); -- cgit From 6ce1ddf53252dfd9debaef87648488c85d84a482 Mon Sep 17 00:00:00 2001 From: Kevin Barnett Date: Tue, 28 Sep 2021 18:54:35 -0500 Subject: scsi: smartpqi: Update LUN reset handler Enhance check for commands queued to the controller. Add new function pqi_nonempty_inbound_queue_count() that will wait for all I/O queued for submission to controller across all queue groups to drain. Add helper functions to obtain queue command counts for each queue group. These queues should drain quickly as they are already staged to be submitted down to the controller's IB queue. Enhance check for outstanding command completion. Update the count of outstanding commands while waiting. This value was not re-obtained and was potentially causing infinite wait for all completions. Link: https://lore.kernel.org/r/20210928235442.201875-5-don.brace@microchip.com Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Reviewed-by: Mike McGowen Acked-by: John Donnelly Signed-off-by: Kevin Barnett Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 105 +++++++++++++++++++++------------- 1 file changed, 66 insertions(+), 39 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index b6ac4d607664..01330fd67500 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -5799,64 +5799,91 @@ out: return rc; } -static int pqi_wait_until_queued_io_drained(struct pqi_ctrl_info *ctrl_info, - struct pqi_queue_group *queue_group) +static unsigned int pqi_queued_io_count(struct pqi_ctrl_info *ctrl_info) { + unsigned int i; unsigned int path; unsigned long flags; - bool list_is_empty; + unsigned int queued_io_count; + struct pqi_queue_group *queue_group; + struct pqi_io_request *io_request; - for (path = 0; path < 2; path++) { - while (1) { - spin_lock_irqsave( - &queue_group->submit_lock[path], flags); - list_is_empty = - list_empty(&queue_group->request_list[path]); - spin_unlock_irqrestore( - &queue_group->submit_lock[path], flags); - if (list_is_empty) - break; - pqi_check_ctrl_health(ctrl_info); - if (pqi_ctrl_offline(ctrl_info)) - return -ENXIO; - usleep_range(1000, 2000); + queued_io_count = 0; + + for (i = 0; i < ctrl_info->num_queue_groups; i++) { + queue_group = &ctrl_info->queue_groups[i]; + for (path = 0; path < 2; path++) { + spin_lock_irqsave(&queue_group->submit_lock[path], flags); + list_for_each_entry(io_request, &queue_group->request_list[path], request_list_entry) + queued_io_count++; + spin_unlock_irqrestore(&queue_group->submit_lock[path], flags); } } - return 0; + return queued_io_count; } -static int pqi_wait_until_inbound_queues_empty(struct pqi_ctrl_info *ctrl_info) +static unsigned int pqi_nonempty_inbound_queue_count(struct pqi_ctrl_info *ctrl_info) { - int rc; unsigned int i; unsigned int path; + unsigned int nonempty_inbound_queue_count; struct pqi_queue_group *queue_group; pqi_index_t iq_pi; pqi_index_t iq_ci; + nonempty_inbound_queue_count = 0; + for (i = 0; i < ctrl_info->num_queue_groups; i++) { queue_group = &ctrl_info->queue_groups[i]; - - rc = pqi_wait_until_queued_io_drained(ctrl_info, queue_group); - if (rc) - return rc; - for (path = 0; path < 2; path++) { iq_pi = queue_group->iq_pi_copy[path]; + iq_ci = readl(queue_group->iq_ci[path]); + if (iq_ci != iq_pi) + nonempty_inbound_queue_count++; + } + } - while (1) { - iq_ci = readl(queue_group->iq_ci[path]); - if (iq_ci == iq_pi) - break; - pqi_check_ctrl_health(ctrl_info); - if (pqi_ctrl_offline(ctrl_info)) - return -ENXIO; - usleep_range(1000, 2000); - } + return nonempty_inbound_queue_count; +} + +#define PQI_INBOUND_QUEUES_NONEMPTY_WARNING_TIMEOUT_SECS 10 + +static int pqi_wait_until_inbound_queues_empty(struct pqi_ctrl_info *ctrl_info) +{ + unsigned long start_jiffies; + unsigned long warning_timeout; + unsigned int queued_io_count; + unsigned int nonempty_inbound_queue_count; + bool displayed_warning; + + displayed_warning = false; + start_jiffies = jiffies; + warning_timeout = (PQI_INBOUND_QUEUES_NONEMPTY_WARNING_TIMEOUT_SECS * PQI_HZ) + start_jiffies; + + while (1) { + queued_io_count = pqi_queued_io_count(ctrl_info); + nonempty_inbound_queue_count = pqi_nonempty_inbound_queue_count(ctrl_info); + if (queued_io_count == 0 && nonempty_inbound_queue_count == 0) + break; + pqi_check_ctrl_health(ctrl_info); + if (pqi_ctrl_offline(ctrl_info)) + return -ENXIO; + if (time_after(jiffies, warning_timeout)) { + dev_warn(&ctrl_info->pci_dev->dev, + "waiting %u seconds for queued I/O to drain (queued I/O count: %u; non-empty inbound queue count: %u)\n", + jiffies_to_msecs(jiffies - start_jiffies) / 1000, queued_io_count, nonempty_inbound_queue_count); + displayed_warning = true; + warning_timeout = (PQI_INBOUND_QUEUES_NONEMPTY_WARNING_TIMEOUT_SECS * PQI_HZ) + jiffies; } + usleep_range(1000, 2000); } + if (displayed_warning) + dev_warn(&ctrl_info->pci_dev->dev, + "queued I/O drained after waiting for %u seconds\n", + jiffies_to_msecs(jiffies - start_jiffies) / 1000); + return 0; } @@ -5922,7 +5949,7 @@ static int pqi_device_wait_for_pending_io(struct pqi_ctrl_info *ctrl_info, if (pqi_ctrl_offline(ctrl_info)) return -ENXIO; msecs_waiting = jiffies_to_msecs(jiffies - start_jiffies); - if (msecs_waiting > timeout_msecs) { + if (msecs_waiting >= timeout_msecs) { dev_err(&ctrl_info->pci_dev->dev, "scsi %d:%d:%d:%d: timed out after %lu seconds waiting for %d outstanding command(s)\n", ctrl_info->scsi_host->host_no, device->bus, device->target, @@ -5957,6 +5984,7 @@ static int pqi_wait_for_lun_reset_completion(struct pqi_ctrl_info *ctrl_info, { int rc; unsigned int wait_secs; + int cmds_outstanding; wait_secs = 0; @@ -5974,11 +6002,10 @@ static int pqi_wait_for_lun_reset_completion(struct pqi_ctrl_info *ctrl_info, } wait_secs += PQI_LUN_RESET_POLL_COMPLETION_SECS; - + cmds_outstanding = atomic_read(&device->scsi_cmds_outstanding); dev_warn(&ctrl_info->pci_dev->dev, - "scsi %d:%d:%d:%d: waiting %u seconds for LUN reset to complete\n", - ctrl_info->scsi_host->host_no, device->bus, device->target, device->lun, - wait_secs); + "scsi %d:%d:%d:%d: waiting %u seconds for LUN reset to complete (%d command(s) outstanding)\n", + ctrl_info->scsi_host->host_no, device->bus, device->target, device->lun, wait_secs, cmds_outstanding); } return rc; -- cgit From be76f90668d8406dccb4c05d6edde89f48ad04d8 Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 28 Sep 2021 18:54:36 -0500 Subject: scsi: smartpqi: Add TEST UNIT READY check for SANITIZE operation Send a TEST UNIT READY to HBA disks and do not present them to the OS if 0x02/0x04/0x1b (SANITIZE IN PROGRESS) is returned. During boot-up, some OSes appear to hang when there are one or more disks undergoing a sanitize operation. According to SCSI SBC4 specification section 4.11.2 "Commands allowed during SANITIZE", some SCSI commands are permitted, but read/write operations are not. When the OS attempts to read the disk partition table a CHECK CONDITION ASC 0x04 ASCQ 0x1b is returned which causes the OS to retry the read until SANITIZE has completed. This can take hours. According to document HPE Smart Storage Administrator User Guide, during the sanitize erase operation, the drive is unusable. I.e. the expected behavior for SANITIZE is the that disk remains offline even after SANITIZE has completed. The customer is expected to re-enable the disk using the management utility. Link: https://lore.kernel.org/r/20210928235442.201875-6-don.brace@microchip.com Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Reviewed-by: Mike McGowen Acked-by: John Donnelly Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 87 +++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 01330fd67500..838274d8fadf 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -555,6 +555,10 @@ static int pqi_build_raid_path_request(struct pqi_ctrl_info *ctrl_info, cdb = request->cdb; switch (cmd) { + case TEST_UNIT_READY: + request->data_direction = SOP_READ_FLAG; + cdb[0] = TEST_UNIT_READY; + break; case INQUIRY: request->data_direction = SOP_READ_FLAG; cdb[0] = INQUIRY; @@ -1575,6 +1579,85 @@ out: return rc; } +/* + * Prevent adding drive to OS for some corner cases such as a drive + * undergoing a sanitize operation. Some OSes will continue to poll + * the drive until the sanitize completes, which can take hours, + * resulting in long bootup delays. Commands such as TUR, READ_CAP + * are allowed, but READ/WRITE cause check condition. So the OS + * cannot check/read the partition table. + * Note: devices that have completed sanitize must be re-enabled + * using the management utility. + */ +static bool pqi_keep_device_offline(struct pqi_ctrl_info *ctrl_info, + struct pqi_scsi_dev *device) +{ + u8 scsi_status; + int rc; + enum dma_data_direction dir; + char *buffer; + int buffer_length = 64; + size_t sense_data_length; + struct scsi_sense_hdr sshdr; + struct pqi_raid_path_request request; + struct pqi_raid_error_info error_info; + bool offline = false; /* Assume keep online */ + + /* Do not check controllers. */ + if (pqi_is_hba_lunid(device->scsi3addr)) + return false; + + /* Do not check LVs. */ + if (pqi_is_logical_device(device)) + return false; + + buffer = kmalloc(buffer_length, GFP_KERNEL); + if (!buffer) + return false; /* Assume not offline */ + + /* Check for SANITIZE in progress using TUR */ + rc = pqi_build_raid_path_request(ctrl_info, &request, + TEST_UNIT_READY, RAID_CTLR_LUNID, buffer, + buffer_length, 0, &dir); + if (rc) + goto out; /* Assume not offline */ + + memcpy(request.lun_number, device->scsi3addr, sizeof(request.lun_number)); + + rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header, 0, &error_info); + + if (rc) + goto out; /* Assume not offline */ + + scsi_status = error_info.status; + sense_data_length = get_unaligned_le16(&error_info.sense_data_length); + if (sense_data_length == 0) + sense_data_length = + get_unaligned_le16(&error_info.response_data_length); + if (sense_data_length) { + if (sense_data_length > sizeof(error_info.data)) + sense_data_length = sizeof(error_info.data); + + /* + * Check for sanitize in progress: asc:0x04, ascq: 0x1b + */ + if (scsi_status == SAM_STAT_CHECK_CONDITION && + scsi_normalize_sense(error_info.data, + sense_data_length, &sshdr) && + sshdr.sense_key == NOT_READY && + sshdr.asc == 0x04 && + sshdr.ascq == 0x1b) { + device->device_offline = true; + offline = true; + goto out; /* Keep device offline */ + } + } + +out: + kfree(buffer); + return offline; +} + static int pqi_get_device_info(struct pqi_ctrl_info *ctrl_info, struct pqi_scsi_dev *device, struct bmic_identify_physical_device *id_phys) @@ -2296,6 +2379,10 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info) if (!pqi_is_supported_device(device)) continue; + /* Do not present disks that the OS cannot fully probe */ + if (pqi_keep_device_offline(ctrl_info, device)) + continue; + /* Gather information about the device. */ rc = pqi_get_device_info(ctrl_info, device, id_phys); if (rc == -ENOMEM) { -- cgit From 4f3cefc3084d543d8fece39cf7388e3c0ef9e44d Mon Sep 17 00:00:00 2001 From: Mahesh Rajashekhara Date: Tue, 28 Sep 2021 18:54:37 -0500 Subject: scsi: smartpqi: Avoid failing I/Os for offline devices Prevent kernel crash by failing outstanding I/O request when the OS takes device offline. When posted I/Os to the controller's inbound queue are not picked by the controller, the driver will halt the controller and take the controller offline. When the driver takes the controller offline, the driver will fail all the outstanding requests which can sometimes lead to an OS crash. Link: https://lore.kernel.org/r/20210928235442.201875-7-don.brace@microchip.com Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Acked-by: John Donnelly Signed-off-by: Mahesh Rajashekhara Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 838274d8fadf..c9f2a3d54663 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -8544,6 +8544,7 @@ static void pqi_fail_all_outstanding_requests(struct pqi_ctrl_info *ctrl_info) unsigned int i; struct pqi_io_request *io_request; struct scsi_cmnd *scmd; + struct scsi_device *sdev; for (i = 0; i < ctrl_info->max_io_slots; i++) { io_request = &ctrl_info->io_request_pool[i]; @@ -8552,7 +8553,13 @@ static void pqi_fail_all_outstanding_requests(struct pqi_ctrl_info *ctrl_info) scmd = io_request->scmd; if (scmd) { - set_host_byte(scmd, DID_NO_CONNECT); + sdev = scmd->device; + if (!sdev || !scsi_device_online(sdev)) { + pqi_free_io_request(io_request); + continue; + } else { + set_host_byte(scmd, DID_NO_CONNECT); + } } else { io_request->status = -ENXIO; io_request->error_info = -- cgit From 28ca6d876c5a375094847606046e0bf5d044d9b4 Mon Sep 17 00:00:00 2001 From: Mike McGowen Date: Tue, 28 Sep 2021 18:54:38 -0500 Subject: scsi: smartpqi: Add extended report physical LUNs Add support for the new extended formats in the data returned from the Report Physical LUNs command for controllers that enable this feature. The new formats allow the reporting of 16-byte WWIDs. Link: https://lore.kernel.org/r/20210928235442.201875-8-don.brace@microchip.com Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Acked-by: John Donnelly Signed-off-by: Mike McGowen Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi.h | 37 ++++-- drivers/scsi/smartpqi/smartpqi_init.c | 163 ++++++++++++++++++------- drivers/scsi/smartpqi/smartpqi_sas_transport.c | 6 +- 3 files changed, 147 insertions(+), 59 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h index d66863f8d1cf..c439583a4ca5 100644 --- a/drivers/scsi/smartpqi/smartpqi.h +++ b/drivers/scsi/smartpqi/smartpqi.h @@ -868,7 +868,8 @@ struct pqi_config_table_firmware_features { #define PQI_FIRMWARE_FEATURE_RAID_BYPASS_ON_ENCRYPTED_NVME 15 #define PQI_FIRMWARE_FEATURE_UNIQUE_WWID_IN_REPORT_PHYS_LUN 16 #define PQI_FIRMWARE_FEATURE_FW_TRIAGE 17 -#define PQI_FIRMWARE_FEATURE_MAXIMUM 17 +#define PQI_FIRMWARE_FEATURE_RPL_EXTENDED_FORMAT_4_5 18 +#define PQI_FIRMWARE_FEATURE_MAXIMUM 18 struct pqi_config_table_debug { struct pqi_config_table_section_header header; @@ -943,19 +944,21 @@ struct report_lun_header { #define CISS_REPORT_LOG_FLAG_QUEUE_DEPTH (1 << 5) #define CISS_REPORT_LOG_FLAG_DRIVE_TYPE_MIX (1 << 6) -#define CISS_REPORT_PHYS_FLAG_OTHER (1 << 1) +#define CISS_REPORT_PHYS_FLAG_EXTENDED_FORMAT_2 0x2 +#define CISS_REPORT_PHYS_FLAG_EXTENDED_FORMAT_4 0x4 +#define CISS_REPORT_PHYS_FLAG_EXTENDED_FORMAT_MASK 0xf -struct report_log_lun_extended_entry { +struct report_log_lun { u8 lunid[8]; u8 volume_id[16]; }; -struct report_log_lun_extended { +struct report_log_lun_list { struct report_lun_header header; - struct report_log_lun_extended_entry lun_entries[1]; + struct report_log_lun lun_entries[1]; }; -struct report_phys_lun_extended_entry { +struct report_phys_lun_8byte_wwid { u8 lunid[8]; __be64 wwid; u8 device_type; @@ -965,12 +968,27 @@ struct report_phys_lun_extended_entry { u32 aio_handle; }; +struct report_phys_lun_16byte_wwid { + u8 lunid[8]; + u8 wwid[16]; + u8 device_type; + u8 device_flags; + u8 lun_count; /* number of LUNs in a multi-LUN device */ + u8 redundant_paths; + u32 aio_handle; +}; + /* for device_flags field of struct report_phys_lun_extended_entry */ #define CISS_REPORT_PHYS_DEV_FLAG_AIO_ENABLED 0x8 -struct report_phys_lun_extended { +struct report_phys_lun_8byte_wwid_list { + struct report_lun_header header; + struct report_phys_lun_8byte_wwid lun_entries[1]; +}; + +struct report_phys_lun_16byte_wwid_list { struct report_lun_header header; - struct report_phys_lun_extended_entry lun_entries[1]; + struct report_phys_lun_16byte_wwid lun_entries[1]; }; struct raid_map_disk_data { @@ -1077,7 +1095,7 @@ struct pqi_scsi_dev { int target; int lun; u8 scsi3addr[8]; - __be64 wwid; + u8 wwid[16]; u8 volume_id[16]; u8 is_physical_device : 1; u8 is_external_raid_device : 1; @@ -1316,6 +1334,7 @@ struct pqi_ctrl_info { u8 tmf_iu_timeout_supported : 1; u8 unique_wwid_in_report_phys_lun_supported : 1; u8 firmware_triage_supported : 1; + u8 rpl_extended_format_4_5_supported : 1; u8 enable_r1_writes : 1; u8 enable_r5_writes : 1; u8 enable_r6_writes : 1; diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index c9f2a3d54663..1e27e6ba0159 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -572,10 +572,14 @@ static int pqi_build_raid_path_request(struct pqi_ctrl_info *ctrl_info, case CISS_REPORT_PHYS: request->data_direction = SOP_READ_FLAG; cdb[0] = cmd; - if (cmd == CISS_REPORT_PHYS) - cdb[1] = CISS_REPORT_PHYS_FLAG_OTHER; - else + if (cmd == CISS_REPORT_PHYS) { + if (ctrl_info->rpl_extended_format_4_5_supported) + cdb[1] = CISS_REPORT_PHYS_FLAG_EXTENDED_FORMAT_4; + else + cdb[1] = CISS_REPORT_PHYS_FLAG_EXTENDED_FORMAT_2; + } else { cdb[1] = ctrl_info->ciss_report_log_flags; + } put_unaligned_be32(cdb_length, &cdb[6]); break; case CISS_GET_RAID_MAP: @@ -1132,7 +1136,64 @@ out: static inline int pqi_report_phys_luns(struct pqi_ctrl_info *ctrl_info, void **buffer) { - return pqi_report_phys_logical_luns(ctrl_info, CISS_REPORT_PHYS, buffer); + int rc; + unsigned int i; + u8 rpl_response_format; + u32 num_physicals; + size_t rpl_16byte_wwid_list_length; + void *rpl_list; + struct report_lun_header *rpl_header; + struct report_phys_lun_8byte_wwid_list *rpl_8byte_wwid_list; + struct report_phys_lun_16byte_wwid_list *rpl_16byte_wwid_list; + + rc = pqi_report_phys_logical_luns(ctrl_info, CISS_REPORT_PHYS, &rpl_list); + if (rc) + return rc; + + if (ctrl_info->rpl_extended_format_4_5_supported) { + rpl_header = rpl_list; + rpl_response_format = rpl_header->flags & CISS_REPORT_PHYS_FLAG_EXTENDED_FORMAT_MASK; + if (rpl_response_format == CISS_REPORT_PHYS_FLAG_EXTENDED_FORMAT_4) { + *buffer = rpl_list; + return 0; + } else if (rpl_response_format != CISS_REPORT_PHYS_FLAG_EXTENDED_FORMAT_2) { + dev_err(&ctrl_info->pci_dev->dev, + "RPL returned unsupported data format %u\n", + rpl_response_format); + return -EINVAL; + } else { + dev_warn(&ctrl_info->pci_dev->dev, + "RPL returned extended format 2 instead of 4\n"); + } + } + + rpl_8byte_wwid_list = rpl_list; + num_physicals = get_unaligned_be32(&rpl_8byte_wwid_list->header.list_length) / sizeof(rpl_8byte_wwid_list->lun_entries[0]); + rpl_16byte_wwid_list_length = sizeof(struct report_lun_header) + (num_physicals * sizeof(struct report_phys_lun_16byte_wwid)); + + rpl_16byte_wwid_list = kmalloc(rpl_16byte_wwid_list_length, GFP_KERNEL); + if (!rpl_16byte_wwid_list) + return -ENOMEM; + + put_unaligned_be32(num_physicals * sizeof(struct report_phys_lun_16byte_wwid), + &rpl_16byte_wwid_list->header.list_length); + rpl_16byte_wwid_list->header.flags = rpl_8byte_wwid_list->header.flags; + + for (i = 0; i < num_physicals; i++) { + memcpy(&rpl_16byte_wwid_list->lun_entries[i].lunid, &rpl_8byte_wwid_list->lun_entries[i].lunid, sizeof(rpl_8byte_wwid_list->lun_entries[i].lunid)); + memset(&rpl_16byte_wwid_list->lun_entries[i].wwid, 0, 8); + memcpy(&rpl_16byte_wwid_list->lun_entries[i].wwid[8], &rpl_8byte_wwid_list->lun_entries[i].wwid, sizeof(rpl_8byte_wwid_list->lun_entries[i].wwid)); + rpl_16byte_wwid_list->lun_entries[i].device_type = rpl_8byte_wwid_list->lun_entries[i].device_type; + rpl_16byte_wwid_list->lun_entries[i].device_flags = rpl_8byte_wwid_list->lun_entries[i].device_flags; + rpl_16byte_wwid_list->lun_entries[i].lun_count = rpl_8byte_wwid_list->lun_entries[i].lun_count; + rpl_16byte_wwid_list->lun_entries[i].redundant_paths = rpl_8byte_wwid_list->lun_entries[i].redundant_paths; + rpl_16byte_wwid_list->lun_entries[i].aio_handle = rpl_8byte_wwid_list->lun_entries[i].aio_handle; + } + + kfree(rpl_8byte_wwid_list); + *buffer = rpl_16byte_wwid_list; + + return 0; } static inline int pqi_report_logical_luns(struct pqi_ctrl_info *ctrl_info, void **buffer) @@ -1141,14 +1202,14 @@ static inline int pqi_report_logical_luns(struct pqi_ctrl_info *ctrl_info, void } static int pqi_get_device_lists(struct pqi_ctrl_info *ctrl_info, - struct report_phys_lun_extended **physdev_list, - struct report_log_lun_extended **logdev_list) + struct report_phys_lun_16byte_wwid_list **physdev_list, + struct report_log_lun_list **logdev_list) { int rc; size_t logdev_list_length; size_t logdev_data_length; - struct report_log_lun_extended *internal_logdev_list; - struct report_log_lun_extended *logdev_data; + struct report_log_lun_list *internal_logdev_list; + struct report_log_lun_list *logdev_data; struct report_lun_header report_lun_header; rc = pqi_report_phys_luns(ctrl_info, (void **)physdev_list); @@ -1173,7 +1234,7 @@ static int pqi_get_device_lists(struct pqi_ctrl_info *ctrl_info, } else { memset(&report_lun_header, 0, sizeof(report_lun_header)); logdev_data = - (struct report_log_lun_extended *)&report_lun_header; + (struct report_log_lun_list *)&report_lun_header; logdev_list_length = 0; } @@ -1181,7 +1242,7 @@ static int pqi_get_device_lists(struct pqi_ctrl_info *ctrl_info, logdev_list_length; internal_logdev_list = kmalloc(logdev_data_length + - sizeof(struct report_log_lun_extended), GFP_KERNEL); + sizeof(struct report_log_lun), GFP_KERNEL); if (!internal_logdev_list) { kfree(*logdev_list); *logdev_list = NULL; @@ -1190,9 +1251,9 @@ static int pqi_get_device_lists(struct pqi_ctrl_info *ctrl_info, memcpy(internal_logdev_list, logdev_data, logdev_data_length); memset((u8 *)internal_logdev_list + logdev_data_length, 0, - sizeof(struct report_log_lun_extended_entry)); + sizeof(struct report_log_lun)); put_unaligned_be32(logdev_list_length + - sizeof(struct report_log_lun_extended_entry), + sizeof(struct report_log_lun), &internal_logdev_list->header.list_length); kfree(*logdev_list); @@ -1845,7 +1906,7 @@ static inline bool pqi_device_equal(struct pqi_scsi_dev *dev1, struct pqi_scsi_d return false; if (dev1->is_physical_device) - return dev1->wwid == dev2->wwid; + return memcmp(dev1->wwid, dev2->wwid, sizeof(dev1->wwid)) == 0; return memcmp(dev1->volume_id, dev2->volume_id, sizeof(dev1->volume_id)) == 0; } @@ -1915,7 +1976,9 @@ static void pqi_dev_info(struct pqi_ctrl_info *ctrl_info, else count += scnprintf(buffer + count, PQI_DEV_INFO_BUFFER_LENGTH - count, - " %016llx", device->sas_address); + " %016llx%016llx", + get_unaligned_be64(&device->wwid[0]), + get_unaligned_be64(&device->wwid[8])); count += scnprintf(buffer + count, PQI_DEV_INFO_BUFFER_LENGTH - count, " %s %.8s %.16s ", @@ -2229,13 +2292,14 @@ static inline bool pqi_expose_device(struct pqi_scsi_dev *device) } static inline void pqi_set_physical_device_wwid(struct pqi_ctrl_info *ctrl_info, - struct pqi_scsi_dev *device, struct report_phys_lun_extended_entry *phys_lun_ext_entry) + struct pqi_scsi_dev *device, struct report_phys_lun_16byte_wwid *phys_lun) { if (ctrl_info->unique_wwid_in_report_phys_lun_supported || + ctrl_info->rpl_extended_format_4_5_supported || pqi_is_device_with_sas_address(device)) - device->wwid = phys_lun_ext_entry->wwid; + memcpy(device->wwid, phys_lun->wwid, sizeof(device->wwid)); else - device->wwid = cpu_to_be64(get_unaligned_be64(&device->page_83_identifier)); + memcpy(&device->wwid[8], device->page_83_identifier, 8); } static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info) @@ -2243,10 +2307,10 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info) int i; int rc; LIST_HEAD(new_device_list_head); - struct report_phys_lun_extended *physdev_list = NULL; - struct report_log_lun_extended *logdev_list = NULL; - struct report_phys_lun_extended_entry *phys_lun_ext_entry; - struct report_log_lun_extended_entry *log_lun_ext_entry; + struct report_phys_lun_16byte_wwid_list *physdev_list = NULL; + struct report_log_lun_list *logdev_list = NULL; + struct report_phys_lun_16byte_wwid *phys_lun; + struct report_log_lun *log_lun; struct bmic_identify_physical_device *id_phys = NULL; u32 num_physicals; u32 num_logicals; @@ -2297,10 +2361,9 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info) if (pqi_hide_vsep) { for (i = num_physicals - 1; i >= 0; i--) { - phys_lun_ext_entry = - &physdev_list->lun_entries[i]; - if (CISS_GET_DRIVE_NUMBER(phys_lun_ext_entry->lunid) == PQI_VSEP_CISS_BTL) { - pqi_mask_device(phys_lun_ext_entry->lunid); + phys_lun = &physdev_list->lun_entries[i]; + if (CISS_GET_DRIVE_NUMBER(phys_lun->lunid) == PQI_VSEP_CISS_BTL) { + pqi_mask_device(phys_lun->lunid); break; } } @@ -2344,16 +2407,14 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info) if ((!pqi_expose_ld_first && i < num_physicals) || (pqi_expose_ld_first && i >= num_logicals)) { is_physical_device = true; - phys_lun_ext_entry = - &physdev_list->lun_entries[physical_index++]; - log_lun_ext_entry = NULL; - scsi3addr = phys_lun_ext_entry->lunid; + phys_lun = &physdev_list->lun_entries[physical_index++]; + log_lun = NULL; + scsi3addr = phys_lun->lunid; } else { is_physical_device = false; - phys_lun_ext_entry = NULL; - log_lun_ext_entry = - &logdev_list->lun_entries[logical_index++]; - scsi3addr = log_lun_ext_entry->lunid; + phys_lun = NULL; + log_lun = &logdev_list->lun_entries[logical_index++]; + scsi3addr = log_lun->lunid; } if (is_physical_device && pqi_skip_device(scsi3addr)) @@ -2368,7 +2429,7 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info) memcpy(device->scsi3addr, scsi3addr, sizeof(device->scsi3addr)); device->is_physical_device = is_physical_device; if (is_physical_device) { - device->device_type = phys_lun_ext_entry->device_type; + device->device_type = phys_lun->device_type; if (device->device_type == SA_DEVICE_TYPE_EXPANDER_SMP) device->is_expander_smp_device = true; } else { @@ -2393,8 +2454,9 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info) if (rc) { if (device->is_physical_device) dev_warn(&ctrl_info->pci_dev->dev, - "obtaining device info failed, skipping physical device %016llx\n", - get_unaligned_be64(&phys_lun_ext_entry->wwid)); + "obtaining device info failed, skipping physical device %016llx%016llx\n", + get_unaligned_be64(&phys_lun->wwid[0]), + get_unaligned_be64(&phys_lun->wwid[8])); else dev_warn(&ctrl_info->pci_dev->dev, "obtaining device info failed, skipping logical device %08x%08x\n", @@ -2407,21 +2469,21 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info) pqi_assign_bus_target_lun(device); if (device->is_physical_device) { - pqi_set_physical_device_wwid(ctrl_info, device, phys_lun_ext_entry); - if ((phys_lun_ext_entry->device_flags & + pqi_set_physical_device_wwid(ctrl_info, device, phys_lun); + if ((phys_lun->device_flags & CISS_REPORT_PHYS_DEV_FLAG_AIO_ENABLED) && - phys_lun_ext_entry->aio_handle) { + phys_lun->aio_handle) { device->aio_enabled = true; device->aio_handle = - phys_lun_ext_entry->aio_handle; + phys_lun->aio_handle; } } else { - memcpy(device->volume_id, log_lun_ext_entry->volume_id, + memcpy(device->volume_id, log_lun->volume_id, sizeof(device->volume_id)); } if (pqi_is_device_with_sas_address(device)) - device->sas_address = get_unaligned_be64(&device->wwid); + device->sas_address = get_unaligned_be64(&device->wwid[8]); new_device_list[num_valid_devices++] = device; } @@ -6804,12 +6866,10 @@ static ssize_t pqi_unique_id_show(struct device *dev, return -ENODEV; } - if (device->is_physical_device) { - memset(unique_id, 0, 8); - memcpy(unique_id + 8, &device->wwid, sizeof(device->wwid)); - } else { + if (device->is_physical_device) + memcpy(unique_id, device->wwid, sizeof(device->wwid)); + else memcpy(unique_id, device->volume_id, sizeof(device->volume_id)); - } spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags); @@ -7443,6 +7503,9 @@ static void pqi_ctrl_update_feature_flags(struct pqi_ctrl_info *ctrl_info, ctrl_info->firmware_triage_supported = firmware_feature->enabled; pqi_save_fw_triage_setting(ctrl_info, firmware_feature->enabled); break; + case PQI_FIRMWARE_FEATURE_RPL_EXTENDED_FORMAT_4_5: + ctrl_info->rpl_extended_format_4_5_supported = firmware_feature->enabled; + break; } pqi_firmware_feature_status(ctrl_info, firmware_feature); @@ -7543,6 +7606,11 @@ static struct pqi_firmware_feature pqi_firmware_features[] = { .feature_bit = PQI_FIRMWARE_FEATURE_FW_TRIAGE, .feature_status = pqi_ctrl_update_feature_flags, }, + { + .feature_name = "RPL Extended Formats 4 and 5", + .feature_bit = PQI_FIRMWARE_FEATURE_RPL_EXTENDED_FORMAT_4_5, + .feature_status = pqi_ctrl_update_feature_flags, + }, }; static void pqi_process_firmware_features( @@ -7644,6 +7712,7 @@ static void pqi_ctrl_reset_config(struct pqi_ctrl_info *ctrl_info) ctrl_info->tmf_iu_timeout_supported = false; ctrl_info->unique_wwid_in_report_phys_lun_supported = false; ctrl_info->firmware_triage_supported = false; + ctrl_info->rpl_extended_format_4_5_supported = false; } static int pqi_process_config_table(struct pqi_ctrl_info *ctrl_info) diff --git a/drivers/scsi/smartpqi/smartpqi_sas_transport.c b/drivers/scsi/smartpqi/smartpqi_sas_transport.c index afd9bafebd1d..dea4ebaf1677 100644 --- a/drivers/scsi/smartpqi/smartpqi_sas_transport.c +++ b/drivers/scsi/smartpqi/smartpqi_sas_transport.c @@ -343,7 +343,7 @@ static int pqi_sas_get_enclosure_identifier(struct sas_rphy *rphy, } if (found_device->devtype == TYPE_ENCLOSURE) { - *identifier = get_unaligned_be64(&found_device->wwid); + *identifier = get_unaligned_be64(&found_device->wwid[8]); rc = 0; goto out; } @@ -364,7 +364,7 @@ static int pqi_sas_get_enclosure_identifier(struct sas_rphy *rphy, memcmp(device->phys_connector, found_device->phys_connector, 2) == 0) { *identifier = - get_unaligned_be64(&device->wwid); + get_unaligned_be64(&device->wwid[8]); rc = 0; goto out; } @@ -380,7 +380,7 @@ static int pqi_sas_get_enclosure_identifier(struct sas_rphy *rphy, if (device->devtype == TYPE_ENCLOSURE && CISS_GET_DRIVE_NUMBER(device->scsi3addr) == PQI_VSEP_CISS_BTL) { - *identifier = get_unaligned_be64(&device->wwid); + *identifier = get_unaligned_be64(&device->wwid[8]); rc = 0; goto out; } -- cgit From 987d35605b7e82745bf69104611725d6505ed5a3 Mon Sep 17 00:00:00 2001 From: Mike McGowen Date: Tue, 28 Sep 2021 18:54:39 -0500 Subject: scsi: smartpqi: Fix boot failure during LUN rebuild Move the delay in the register polling loop to the beginning of the loop to ensure there is always a delay between writing the register and reading it. Link: https://lore.kernel.org/r/20210928235442.201875-9-don.brace@microchip.com Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Acked-by: John Donnelly Signed-off-by: Mike McGowen Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 1e27e6ba0159..c28eb7ea4a24 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -4278,12 +4278,12 @@ static int pqi_create_admin_queues(struct pqi_ctrl_info *ctrl_info) timeout = PQI_ADMIN_QUEUE_CREATE_TIMEOUT_JIFFIES + jiffies; while (1) { + msleep(PQI_ADMIN_QUEUE_CREATE_POLL_INTERVAL_MSECS); status = readb(&pqi_registers->function_and_status_code); if (status == PQI_STATUS_IDLE) break; if (time_after(jiffies, timeout)) return -ETIMEDOUT; - msleep(PQI_ADMIN_QUEUE_CREATE_POLL_INTERVAL_MSECS); } /* -- cgit From d4dc6aea93cb40f454e3a4d0eb139633874d0f72 Mon Sep 17 00:00:00 2001 From: Kevin Barnett Date: Tue, 28 Sep 2021 18:54:40 -0500 Subject: scsi: smartpqi: Fix duplicate device nodes for tape changers Stop the OS from re-discovering multiple LUNs for tape drive and medium changer. Duplicate device nodes for Ultrium tape drive and medium changer are being created. The Ultrium tape drive is a multi-LUN SCSI target. It presents a LUN for the tape drive and a 2nd LUN for the medium changer. Our controller FW lists both LUNs in the RPL results. As a result, the smartpqi driver exposes both devices to the OS. Then the OS does its normal device discovery via the SCSI REPORT LUNS command, which causes it to re-discover both devices a 2nd time, which results in the duplicate device nodes. Link: https://lore.kernel.org/r/20210928235442.201875-10-don.brace@microchip.com Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Reviewed-by: Mike McGowen Acked-by: John Donnelly Signed-off-by: Kevin Barnett Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi.h | 1 + drivers/scsi/smartpqi/smartpqi_init.c | 23 +++++++++++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h index c439583a4ca5..aac88ac0a0b7 100644 --- a/drivers/scsi/smartpqi/smartpqi.h +++ b/drivers/scsi/smartpqi/smartpqi.h @@ -1106,6 +1106,7 @@ struct pqi_scsi_dev { u8 keep_device : 1; u8 volume_offline : 1; u8 rescan : 1; + u8 ignore_device : 1; bool aio_enabled; /* only valid for physical disks */ bool in_remove; bool device_offline; diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index c28eb7ea4a24..8be116992cb0 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -6297,9 +6297,13 @@ static int pqi_slave_alloc(struct scsi_device *sdev) rphy = target_to_rphy(starget); device = pqi_find_device_by_sas_rphy(ctrl_info, rphy); if (device) { - device->target = sdev_id(sdev); - device->lun = sdev->lun; - device->target_lun_valid = true; + if (device->target_lun_valid) { + device->ignore_device = true; + } else { + device->target = sdev_id(sdev); + device->lun = sdev->lun; + device->target_lun_valid = true; + } } } else { device = pqi_find_scsi_dev(ctrl_info, sdev_channel(sdev), @@ -6336,14 +6340,25 @@ static int pqi_map_queues(struct Scsi_Host *shost) ctrl_info->pci_dev, 0); } +static inline bool pqi_is_tape_changer_device(struct pqi_scsi_dev *device) +{ + return device->devtype == TYPE_TAPE || device->devtype == TYPE_MEDIUM_CHANGER; +} + static int pqi_slave_configure(struct scsi_device *sdev) { + int rc = 0; struct pqi_scsi_dev *device; device = sdev->hostdata; device->devtype = sdev->type; - return 0; + if (pqi_is_tape_changer_device(device) && device->ignore_device) { + rc = -ENXIO; + device->ignore_device = false; + } + + return rc; } static int pqi_getpciinfo_ioctl(struct pqi_ctrl_info *ctrl_info, void __user *arg) -- cgit From 80982656b78ec23cb4918a90ee723ac2db83df1c Mon Sep 17 00:00:00 2001 From: Mike McGowen Date: Tue, 28 Sep 2021 18:54:41 -0500 Subject: scsi: smartpqi: Add 3252-8i PCI id Add PCI ID information for the Adaptec SmartRAID 3252-8i controller: 9005 / 028F / 9005 / 14A2 Link: https://lore.kernel.org/r/20210928235442.201875-11-don.brace@microchip.com Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Acked-by: John Donnelly Signed-off-by: Mike McGowen Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 8be116992cb0..ffa217874352 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -9287,6 +9287,10 @@ static const struct pci_device_id pqi_pci_id_table[] = { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, PCI_VENDOR_ID_ADAPTEC2, 0x14a1) }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + PCI_VENDOR_ID_ADAPTEC2, 0x14a2) + }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, PCI_VENDOR_ID_ADAPTEC2, 0x14b0) -- cgit From 605ae389ea0243344713648294cd86b442d255ee Mon Sep 17 00:00:00 2001 From: Don Brace Date: Tue, 28 Sep 2021 18:54:42 -0500 Subject: scsi: smartpqi: Update version to 2.1.12-055 Update driver version to reflect changes. Link: https://lore.kernel.org/r/20210928235442.201875-12-don.brace@microchip.com Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Reviewed-by: Mike McGowen Acked-by: John Donnelly Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index ffa217874352..b966ce3b4385 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -33,11 +33,11 @@ #define BUILD_TIMESTAMP #endif -#define DRIVER_VERSION "2.1.10-020" +#define DRIVER_VERSION "2.1.12-055" #define DRIVER_MAJOR 2 #define DRIVER_MINOR 1 -#define DRIVER_RELEASE 10 -#define DRIVER_REVISION 20 +#define DRIVER_RELEASE 12 +#define DRIVER_REVISION 55 #define DRIVER_NAME "Microchip SmartPQI Driver (v" \ DRIVER_VERSION BUILD_TIMESTAMP ")" -- cgit From 1cc55204b0dbba0ca09cc14624cbbeeb2d35742f Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 20 Sep 2021 20:22:47 +0300 Subject: PM / devfreq: Add devm_devfreq_add_governor() Add resource-managed variant of devfreq_add_governor(). Signed-off-by: Dmitry Osipenko Acked-by: Chanwoo Choi Signed-off-by: Viresh Kumar --- drivers/devfreq/devfreq.c | 26 ++++++++++++++++++++++++++ drivers/devfreq/governor.h | 3 +++ 2 files changed, 29 insertions(+) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 85faa7a5c7d1..4579eefb8fe7 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -1301,6 +1301,32 @@ err_out: } EXPORT_SYMBOL(devfreq_add_governor); +static void devm_devfreq_remove_governor(void *governor) +{ + WARN_ON(devfreq_remove_governor(governor)); +} + +/** + * devm_devfreq_add_governor() - Add devfreq governor + * @dev: device which adds devfreq governor + * @governor: the devfreq governor to be added + * + * This is a resource-managed variant of devfreq_add_governor(). + */ +int devm_devfreq_add_governor(struct device *dev, + struct devfreq_governor *governor) +{ + int err; + + err = devfreq_add_governor(governor); + if (err) + return err; + + return devm_add_action_or_reset(dev, devm_devfreq_remove_governor, + governor); +} +EXPORT_SYMBOL(devm_devfreq_add_governor); + /** * devfreq_remove_governor() - Remove devfreq feature from a device. * @governor: the devfreq governor to be removed diff --git a/drivers/devfreq/governor.h b/drivers/devfreq/governor.h index 2d69a0ce6291..002a7d67e39d 100644 --- a/drivers/devfreq/governor.h +++ b/drivers/devfreq/governor.h @@ -84,6 +84,9 @@ void devfreq_update_interval(struct devfreq *devfreq, unsigned int *delay); int devfreq_add_governor(struct devfreq_governor *governor); int devfreq_remove_governor(struct devfreq_governor *governor); +int devm_devfreq_add_governor(struct device *dev, + struct devfreq_governor *governor); + int devfreq_update_status(struct devfreq *devfreq, unsigned long freq); int devfreq_update_target(struct devfreq *devfreq, unsigned long freq); -- cgit From 68b79f285540842225bda8e9ded4a9b78664ed1a Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 20 Sep 2021 20:22:48 +0300 Subject: PM / devfreq: tegra30: Use resource-managed helpers Use resource-managed API helpers to simplify driver's probe() function, making code cleaner. Signed-off-by: Dmitry Osipenko Acked-by: Chanwoo Choi Signed-off-by: Viresh Kumar --- drivers/devfreq/tegra30-devfreq.c | 107 ++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 61 deletions(-) diff --git a/drivers/devfreq/tegra30-devfreq.c b/drivers/devfreq/tegra30-devfreq.c index 10661eb2aed8..d83fdc2713ed 100644 --- a/drivers/devfreq/tegra30-devfreq.c +++ b/drivers/devfreq/tegra30-devfreq.c @@ -178,7 +178,6 @@ struct tegra_devfreq_soc_data { struct tegra_devfreq { struct devfreq *devfreq; - struct opp_table *opp_table; struct reset_control *reset; struct clk *clock; @@ -789,6 +788,39 @@ static struct devfreq_governor tegra_devfreq_governor = { .event_handler = tegra_governor_event_handler, }; +static void devm_tegra_devfreq_deinit_hw(void *data) +{ + struct tegra_devfreq *tegra = data; + + reset_control_reset(tegra->reset); + clk_disable_unprepare(tegra->clock); +} + +static int devm_tegra_devfreq_init_hw(struct device *dev, + struct tegra_devfreq *tegra) +{ + int err; + + err = clk_prepare_enable(tegra->clock); + if (err) { + dev_err(dev, "Failed to prepare and enable ACTMON clock\n"); + return err; + } + + err = devm_add_action_or_reset(dev, devm_tegra_devfreq_deinit_hw, + tegra); + if (err) + return err; + + err = reset_control_reset(tegra->reset); + if (err) { + dev_err(dev, "Failed to reset hardware: %d\n", err); + return err; + } + + return err; +} + static int tegra_devfreq_probe(struct platform_device *pdev) { u32 hw_version = BIT(tegra_sku_info.soc_speedo_id); @@ -842,38 +874,26 @@ static int tegra_devfreq_probe(struct platform_device *pdev) return err; } - tegra->opp_table = dev_pm_opp_set_supported_hw(&pdev->dev, - &hw_version, 1); - err = PTR_ERR_OR_ZERO(tegra->opp_table); + err = devm_pm_opp_set_supported_hw(&pdev->dev, &hw_version, 1); if (err) { dev_err(&pdev->dev, "Failed to set supported HW: %d\n", err); return err; } - err = dev_pm_opp_of_add_table_noclk(&pdev->dev, 0); + err = devm_pm_opp_of_add_table_noclk(&pdev->dev, 0); if (err) { dev_err(&pdev->dev, "Failed to add OPP table: %d\n", err); - goto put_hw; - } - - err = clk_prepare_enable(tegra->clock); - if (err) { - dev_err(&pdev->dev, - "Failed to prepare and enable ACTMON clock\n"); - goto remove_table; + return err; } - err = reset_control_reset(tegra->reset); - if (err) { - dev_err(&pdev->dev, "Failed to reset hardware: %d\n", err); - goto disable_clk; - } + err = devm_tegra_devfreq_init_hw(&pdev->dev, tegra); + if (err) + return err; rate = clk_round_rate(tegra->emc_clock, ULONG_MAX); if (rate < 0) { dev_err(&pdev->dev, "Failed to round clock rate: %ld\n", rate); - err = rate; - goto disable_clk; + return rate; } tegra->max_freq = rate / KHZ; @@ -892,52 +912,18 @@ static int tegra_devfreq_probe(struct platform_device *pdev) INIT_DELAYED_WORK(&tegra->cpufreq_update_work, tegra_actmon_delayed_update); - err = devfreq_add_governor(&tegra_devfreq_governor); + err = devm_devfreq_add_governor(&pdev->dev, &tegra_devfreq_governor); if (err) { dev_err(&pdev->dev, "Failed to add governor: %d\n", err); - goto remove_opps; + return err; } tegra_devfreq_profile.initial_freq = clk_get_rate(tegra->emc_clock); - devfreq = devfreq_add_device(&pdev->dev, &tegra_devfreq_profile, - "tegra_actmon", NULL); - if (IS_ERR(devfreq)) { - err = PTR_ERR(devfreq); - goto remove_governor; - } - - return 0; - -remove_governor: - devfreq_remove_governor(&tegra_devfreq_governor); - -remove_opps: - dev_pm_opp_remove_all_dynamic(&pdev->dev); - - reset_control_reset(tegra->reset); -disable_clk: - clk_disable_unprepare(tegra->clock); -remove_table: - dev_pm_opp_of_remove_table(&pdev->dev); -put_hw: - dev_pm_opp_put_supported_hw(tegra->opp_table); - - return err; -} - -static int tegra_devfreq_remove(struct platform_device *pdev) -{ - struct tegra_devfreq *tegra = platform_get_drvdata(pdev); - - devfreq_remove_device(tegra->devfreq); - devfreq_remove_governor(&tegra_devfreq_governor); - - reset_control_reset(tegra->reset); - clk_disable_unprepare(tegra->clock); - - dev_pm_opp_of_remove_table(&pdev->dev); - dev_pm_opp_put_supported_hw(tegra->opp_table); + devfreq = devm_devfreq_add_device(&pdev->dev, &tegra_devfreq_profile, + "tegra_actmon", NULL); + if (IS_ERR(devfreq)) + return PTR_ERR(devfreq); return 0; } @@ -967,7 +953,6 @@ MODULE_DEVICE_TABLE(of, tegra_devfreq_of_match); static struct platform_driver tegra_devfreq_driver = { .probe = tegra_devfreq_probe, - .remove = tegra_devfreq_remove, .driver = { .name = "tegra-devfreq", .of_match_table = tegra_devfreq_of_match, -- cgit From 4844bdbe9166bc3d194b1d20d13dc1f01d3c1bb7 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 20 Sep 2021 20:22:49 +0300 Subject: PM / devfreq: tegra30: Check whether clk_round_rate() returns zero rate EMC clock is always-on and can't be zero. Check whether clk_round_rate() returns zero rate and error out if it does. It can return zero if clock tree isn't initialized properly. Acked-by: Chanwoo Choi Signed-off-by: Dmitry Osipenko Signed-off-by: Viresh Kumar --- drivers/devfreq/tegra30-devfreq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/devfreq/tegra30-devfreq.c b/drivers/devfreq/tegra30-devfreq.c index d83fdc2713ed..65ecf17a36f4 100644 --- a/drivers/devfreq/tegra30-devfreq.c +++ b/drivers/devfreq/tegra30-devfreq.c @@ -891,9 +891,9 @@ static int tegra_devfreq_probe(struct platform_device *pdev) return err; rate = clk_round_rate(tegra->emc_clock, ULONG_MAX); - if (rate < 0) { + if (rate <= 0) { dev_err(&pdev->dev, "Failed to round clock rate: %ld\n", rate); - return rate; + return rate ?: -EINVAL; } tegra->max_freq = rate / KHZ; -- cgit From e68ce0faf29c7c268666e11e95bf27dca97d28b0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 2 Sep 2021 14:47:48 +0200 Subject: mfd: hi6421-spmi-pmic: Cleanup drvdata to only include regmap There are lots of fields in struct hi6421_spmi_pmic that aren't used. As a matter of fact, only regmap is needed. So, drop the struct as a whole, and set regmap as the drvdata. Signed-off-by: Mauro Carvalho Chehab Acked-by: Mark Brown Acked-by: Greg Kroah-Hartman Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/1828cb783b1ebca0b98bf0b3077d8701adb228f7.1630586862.git.mchehab+huawei@kernel.org --- drivers/mfd/hi6421-spmi-pmic.c | 16 +++++----------- drivers/misc/hi6421v600-irq.c | 9 ++++----- drivers/regulator/hi6421v600-regulator.c | 10 +++++----- include/linux/mfd/hi6421-spmi-pmic.h | 25 ------------------------- 4 files changed, 14 insertions(+), 46 deletions(-) delete mode 100644 include/linux/mfd/hi6421-spmi-pmic.h diff --git a/drivers/mfd/hi6421-spmi-pmic.c b/drivers/mfd/hi6421-spmi-pmic.c index 4f136826681b..c9c0c3d7011f 100644 --- a/drivers/mfd/hi6421-spmi-pmic.c +++ b/drivers/mfd/hi6421-spmi-pmic.c @@ -8,7 +8,6 @@ */ #include -#include #include #include #include @@ -30,19 +29,14 @@ static const struct regmap_config regmap_config = { static int hi6421_spmi_pmic_probe(struct spmi_device *sdev) { struct device *dev = &sdev->dev; + struct regmap *regmap; int ret; - struct hi6421_spmi_pmic *ddata; - ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); - if (!ddata) - return -ENOMEM; - ddata->regmap = devm_regmap_init_spmi_ext(sdev, ®map_config); - if (IS_ERR(ddata->regmap)) - return PTR_ERR(ddata->regmap); + regmap = devm_regmap_init_spmi_ext(sdev, ®map_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); - ddata->dev = dev; - - dev_set_drvdata(&sdev->dev, ddata); + dev_set_drvdata(&sdev->dev, regmap); ret = devm_mfd_add_devices(&sdev->dev, PLATFORM_DEVID_NONE, hi6421v600_devs, ARRAY_SIZE(hi6421v600_devs), diff --git a/drivers/misc/hi6421v600-irq.c b/drivers/misc/hi6421v600-irq.c index 08535e97ff43..1c763796cf1f 100644 --- a/drivers/misc/hi6421v600-irq.c +++ b/drivers/misc/hi6421v600-irq.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -220,7 +219,7 @@ static int hi6421v600_irq_probe(struct platform_device *pdev) struct platform_device *pmic_pdev; struct device *dev = &pdev->dev; struct hi6421v600_irq *priv; - struct hi6421_spmi_pmic *pmic; + struct regmap *regmap; unsigned int virq; int i, ret; @@ -229,8 +228,8 @@ static int hi6421v600_irq_probe(struct platform_device *pdev) * which should first set drvdata. If this doesn't happen, hit * a warn on and return. */ - pmic = dev_get_drvdata(pmic_dev); - if (WARN_ON(!pmic)) + regmap = dev_get_drvdata(pmic_dev); + if (WARN_ON(!regmap)) return -ENODEV; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -238,7 +237,7 @@ static int hi6421v600_irq_probe(struct platform_device *pdev) return -ENOMEM; priv->dev = dev; - priv->regmap = pmic->regmap; + priv->regmap = regmap; spin_lock_init(&priv->lock); diff --git a/drivers/regulator/hi6421v600-regulator.c b/drivers/regulator/hi6421v600-regulator.c index 662d87ae61cb..4671678f6b19 100644 --- a/drivers/regulator/hi6421v600-regulator.c +++ b/drivers/regulator/hi6421v600-regulator.c @@ -9,8 +9,8 @@ // Guodong Xu #include -#include #include +#include #include #include #include @@ -237,7 +237,7 @@ static int hi6421_spmi_regulator_probe(struct platform_device *pdev) struct hi6421_spmi_reg_priv *priv; struct hi6421_spmi_reg_info *info; struct device *dev = &pdev->dev; - struct hi6421_spmi_pmic *pmic; + struct regmap *regmap; struct regulator_dev *rdev; int i; @@ -246,8 +246,8 @@ static int hi6421_spmi_regulator_probe(struct platform_device *pdev) * which should first set drvdata. If this doesn't happen, hit * a warn on and return. */ - pmic = dev_get_drvdata(pmic_dev); - if (WARN_ON(!pmic)) + regmap = dev_get_drvdata(pmic_dev); + if (WARN_ON(!regmap)) return -ENODEV; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -261,7 +261,7 @@ static int hi6421_spmi_regulator_probe(struct platform_device *pdev) config.dev = pdev->dev.parent; config.driver_data = priv; - config.regmap = pmic->regmap; + config.regmap = regmap; rdev = devm_regulator_register(dev, &info->desc, &config); if (IS_ERR(rdev)) { diff --git a/include/linux/mfd/hi6421-spmi-pmic.h b/include/linux/mfd/hi6421-spmi-pmic.h deleted file mode 100644 index e5b8dbf828b6..000000000000 --- a/include/linux/mfd/hi6421-spmi-pmic.h +++ /dev/null @@ -1,25 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Header file for device driver Hi6421 PMIC - * - * Copyright (c) 2013 Linaro Ltd. - * Copyright (C) 2011 Hisilicon. - * Copyright (c) 2020-2021 Huawei Technologies Co., Ltd - * - * Guodong Xu - */ - -#ifndef __HISI_PMIC_H -#define __HISI_PMIC_H - -#include -#include - -struct hi6421_spmi_pmic { - struct resource *res; - struct device *dev; - void __iomem *regs; - struct regmap *regmap; -}; - -#endif /* __HISI_PMIC_H */ -- cgit From 65315ec52c9bd518e22fde1c9ce1e787b9122b4a Mon Sep 17 00:00:00 2001 From: Krzysztof Wilczyński Date: Sun, 3 Oct 2021 02:54:39 +0000 Subject: PCI: imx6: Remove unused assignment to variable ret MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, the maximum link speed was set following an "fsl,max-link-speed" property read, and should the read failed, then the PCIe generation was manually set to PCIe Gen1 and thus limiting the link speed to 2.5 GT/s. Code refactoring completed in the commit 39bc5006501c ("PCI: dwc: Centralize link gen setting") changed to the logic that was previously used to limit the maximum link speed leaving behind an unused assignment to a variable "ret". Since the value returned from the of_property_read_u32() and stored in the variable "ret" is never used in any meaningful way, and it's also immediately reassigned in the code that follows, the assignment can be removed. Link: https://lore.kernel.org/r/20211003025439.84783-1-kw@linux.com Signed-off-by: Krzysztof Wilczyński Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-imx6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 80fc98acf097..26f49f797b0f 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -1132,7 +1132,7 @@ static int imx6_pcie_probe(struct platform_device *pdev) /* Limit link speed */ pci->link_gen = 1; - ret = of_property_read_u32(node, "fsl,max-link-speed", &pci->link_gen); + of_property_read_u32(node, "fsl,max-link-speed", &pci->link_gen); imx6_pcie->vpcie = devm_regulator_get_optional(&pdev->dev, "vpcie"); if (IS_ERR(imx6_pcie->vpcie)) { -- cgit From 3f491d11d8cbc3e4b4ff67bfc7f065e1cb56bcef Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Fri, 24 Sep 2021 00:40:26 +0530 Subject: MAINTAINERS: Add spi-nor device tree binding under SPI NOR maintainers The binding is for the SPI NOR subsystem so the patches should be sent to its maintainers. Currently the patches get sent to Rob Herring and MTD maintainers who might not always have the full picture. Signed-off-by: Pratyush Yadav Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20210923191026.19184-1-p.yadav@ti.com --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index abdcbcfef73d..3913d1114324 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17652,6 +17652,7 @@ W: http://www.linux-mtd.infradead.org/ Q: http://patchwork.ozlabs.org/project/linux-mtd/list/ C: irc://irc.oftc.net/mtd T: git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git spi-nor/next +F: Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml F: drivers/mtd/spi-nor/ F: include/linux/mtd/spi-nor.h -- cgit From 1f59342be6c075a9520679981c4cfd08bb26c659 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 5 Oct 2021 13:27:26 -0700 Subject: Input: analog - fix invalid snprintf() call Overlapping input and output arguments to snprintf() are undefined behavior in C99: drivers/input/joystick/analog.c: In function 'analog_name': drivers/input/joystick/analog.c:428:3: error: 'snprintf' argument 4 overlaps destination object 'analog' [-Werror=restrict] 428 | snprintf(analog->name, sizeof(analog->name), "%s %d-hat", | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 429 | analog->name, hweight16(analog->mask & ANALOG_HATS_ALL)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/input/joystick/analog.c:420:40: note: destination object referenced by 'restrict'-qualified argument 1 was declared here 420 | static void analog_name(struct analog *analog) | ~~~~~~~~~~~~~~~^~~~~~ Change this function to use the simpler seq_buf interface instead. Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20210927101416.1569609-1-arnd@kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/analog.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c index f798922a4598..d9f866ffde6b 100644 --- a/drivers/input/joystick/analog.c +++ b/drivers/input/joystick/analog.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -419,23 +420,24 @@ static void analog_calibrate_timer(struct analog_port *port) static void analog_name(struct analog *analog) { - snprintf(analog->name, sizeof(analog->name), "Analog %d-axis %d-button", + struct seq_buf s; + + seq_buf_init(&s, analog->name, sizeof(analog->name)); + seq_buf_printf(&s, "Analog %d-axis %d-button", hweight8(analog->mask & ANALOG_AXES_STD), hweight8(analog->mask & ANALOG_BTNS_STD) + !!(analog->mask & ANALOG_BTNS_CHF) * 2 + hweight16(analog->mask & ANALOG_BTNS_GAMEPAD) + !!(analog->mask & ANALOG_HBTN_CHF) * 4); if (analog->mask & ANALOG_HATS_ALL) - snprintf(analog->name, sizeof(analog->name), "%s %d-hat", - analog->name, hweight16(analog->mask & ANALOG_HATS_ALL)); + seq_buf_printf(&s, " %d-hat", + hweight16(analog->mask & ANALOG_HATS_ALL)); if (analog->mask & ANALOG_HAT_FCS) - strlcat(analog->name, " FCS", sizeof(analog->name)); + seq_buf_printf(&s, " FCS"); if (analog->mask & ANALOG_ANY_CHF) - strlcat(analog->name, (analog->mask & ANALOG_SAITEK) ? " Saitek" : " CHF", - sizeof(analog->name)); + seq_buf_printf(&s, (analog->mask & ANALOG_SAITEK) ? " Saitek" : " CHF"); - strlcat(analog->name, (analog->mask & ANALOG_GAMEPAD) ? " gamepad": " joystick", - sizeof(analog->name)); + seq_buf_printf(&s, (analog->mask & ANALOG_GAMEPAD) ? " gamepad" : " joystick"); } /* -- cgit From a41392e0877a271007e9209e63c34cab7527eb43 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Tue, 5 Oct 2021 13:33:25 -0700 Subject: MAINTAINERS: rectify entry for CHIPONE ICN8318 I2C TOUCHSCREEN DRIVER Commit 04647773d648 ("dt-bindings: input: Convert ChipOne ICN8318 binding to a schema") converts chipone_icn8318.txt to chipone,icn8318.yaml, but missed to adjust its reference in MAINTAINERS. Hence, ./scripts/get_maintainer.pl --self-test=patterns complains about a broken reference. Repair this file reference in CHIPONE ICN8318 I2C TOUCHSCREEN DRIVER. Signed-off-by: Lukas Bulwahn Link: https://lore.kernel.org/r/20211005075451.29691-12-lukas.bulwahn@gmail.com Signed-off-by: Dmitry Torokhov --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 7ab4a058fe4d..5122b3a3bf56 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4301,7 +4301,7 @@ CHIPONE ICN8318 I2C TOUCHSCREEN DRIVER M: Hans de Goede L: linux-input@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/input/touchscreen/chipone_icn8318.txt +F: Documentation/devicetree/bindings/input/touchscreen/chipone,icn8318.yaml F: drivers/input/touchscreen/chipone_icn8318.c CHIPONE ICN8505 I2C TOUCHSCREEN DRIVER -- cgit From 15184965783aab3ca7ee4f939e2598943b3f40f9 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 9 Jul 2021 02:03:29 +0300 Subject: drm/bridge/lontium-lt9611uxc: fix provided connector suport - set DRM_CONNECTOR_POLL_HPD as the connector will generate hotplug events on its own - do not call drm_kms_helper_hotplug_event() unless mode_config.funcs pointer is not NULL to remove possible kernel oops. Fixes: bc6fa8676ebb ("drm/bridge/lontium-lt9611uxc: move HPD notification out of IRQ handler") Signed-off-by: Dmitry Baryshkov Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20210708230329.395976-1-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c index 3cac16db970f..010657ea7af7 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c @@ -167,9 +167,10 @@ static void lt9611uxc_hpd_work(struct work_struct *work) struct lt9611uxc *lt9611uxc = container_of(work, struct lt9611uxc, work); bool connected; - if (lt9611uxc->connector.dev) - drm_kms_helper_hotplug_event(lt9611uxc->connector.dev); - else { + if (lt9611uxc->connector.dev) { + if (lt9611uxc->connector.dev->mode_config.funcs) + drm_kms_helper_hotplug_event(lt9611uxc->connector.dev); + } else { mutex_lock(<9611uxc->ocm_lock); connected = lt9611uxc->hdmi_connected; @@ -339,6 +340,8 @@ static int lt9611uxc_connector_init(struct drm_bridge *bridge, struct lt9611uxc return -ENODEV; } + lt9611uxc->connector.polled = DRM_CONNECTOR_POLL_HPD; + drm_connector_helper_add(<9611uxc->connector, <9611uxc_bridge_connector_helper_funcs); ret = drm_connector_init(bridge->dev, <9611uxc->connector, -- cgit From 7be28bd73f23e53d6e7f5fe891ba9503fc0c7210 Mon Sep 17 00:00:00 2001 From: "Alex Xu (Hello71)" Date: Thu, 7 Oct 2021 02:37:06 -0400 Subject: drm/plane-helper: fix uninitialized variable reference drivers/gpu/drm/drm_plane_helper.c: In function 'drm_primary_helper_update': drivers/gpu/drm/drm_plane_helper.c:113:32: error: 'visible' is used uninitialized [-Werror=uninitialized] 113 | struct drm_plane_state plane_state = { | ^~~~~~~~~~~ drivers/gpu/drm/drm_plane_helper.c:178:14: note: 'visible' was declared here 178 | bool visible; | ^~~~~~~ cc1: all warnings being treated as errors visible is an output, not an input. in practice this use might turn out OK but it's still UB. Fixes: df86af9133b4 ("drm/plane-helper: Add drm_plane_helper_check_state()") Reviewed-by: Simon Ser Signed-off-by: Alex Xu (Hello71) Signed-off-by: Simon Ser Link: https://patchwork.freedesktop.org/patch/msgid/20211007063706.305984-1-alex_y_xu@yahoo.ca --- drivers/gpu/drm/drm_plane_helper.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 5b2d0ca03705..838b32b70bce 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -123,7 +123,6 @@ static int drm_plane_helper_check_update(struct drm_plane *plane, .crtc_w = drm_rect_width(dst), .crtc_h = drm_rect_height(dst), .rotation = rotation, - .visible = *visible, }; struct drm_crtc_state crtc_state = { .crtc = crtc, -- cgit From a0a33067b957dfab876ae26b32695f09cdc2706d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 4 Oct 2021 09:12:50 +0000 Subject: drm/connector: refer to CTA-861-G in the "content type" prop docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The KMS documentation doesn't say much about the meaning of each content type. Add a reference to the specification defining them. Signed-off-by: Simon Ser Cc: Emmanuel Gil Peyrot Cc: Daniel Vetter Cc: Jani Nikula Reviewed-by: Ville Syrjälä Reviewed-by: Pekka Paalanen Link: https://patchwork.freedesktop.org/patch/msgid/20211004091236.82010-1-contact@emersion.fr --- drivers/gpu/drm/drm_connector.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 3bc782b630b9..79d8163686cd 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -1397,6 +1397,8 @@ EXPORT_SYMBOL(drm_connector_attach_dp_subconnector_property); * Game: * Content type is game * + * The meaning of each content type is defined in CTA-861-G table 15. + * * Drivers can set up this property by calling * drm_connector_attach_content_type_property(). Decoding to * infoframe values is done through drm_hdmi_avi_infoframe_content_type(). -- cgit From 5baaac3184ab896d74993825858f1b1a46c460ce Mon Sep 17 00:00:00 2001 From: Christian König Date: Tue, 15 Jun 2021 15:10:03 +0200 Subject: dma-buf: add dma_resv_for_each_fence v3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A simpler version of the iterator to be used when the dma_resv object is locked. v2: fix index check here as well v3: minor coding improvement, some documentation cleanup Signed-off-by: Christian König Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20211006123609.2026-1-christian.koenig@amd.com --- drivers/dma-buf/dma-resv.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/dma-resv.h | 20 ++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c index a480af9581bd..2f98caa68ae5 100644 --- a/drivers/dma-buf/dma-resv.c +++ b/drivers/dma-buf/dma-resv.c @@ -423,6 +423,57 @@ struct dma_fence *dma_resv_iter_next_unlocked(struct dma_resv_iter *cursor) } EXPORT_SYMBOL(dma_resv_iter_next_unlocked); +/** + * dma_resv_iter_first - first fence from a locked dma_resv object + * @cursor: cursor to record the current position + * + * Return the first fence in the dma_resv object while holding the + * &dma_resv.lock. + */ +struct dma_fence *dma_resv_iter_first(struct dma_resv_iter *cursor) +{ + struct dma_fence *fence; + + dma_resv_assert_held(cursor->obj); + + cursor->index = 0; + if (cursor->all_fences) + cursor->fences = dma_resv_shared_list(cursor->obj); + else + cursor->fences = NULL; + + fence = dma_resv_excl_fence(cursor->obj); + if (!fence) + fence = dma_resv_iter_next(cursor); + + cursor->is_restarted = true; + return fence; +} +EXPORT_SYMBOL_GPL(dma_resv_iter_first); + +/** + * dma_resv_iter_next - next fence from a locked dma_resv object + * @cursor: cursor to record the current position + * + * Return the next fences from the dma_resv object while holding the + * &dma_resv.lock. + */ +struct dma_fence *dma_resv_iter_next(struct dma_resv_iter *cursor) +{ + unsigned int idx; + + dma_resv_assert_held(cursor->obj); + + cursor->is_restarted = false; + if (!cursor->fences || cursor->index >= cursor->fences->shared_count) + return NULL; + + idx = cursor->index++; + return rcu_dereference_protected(cursor->fences->shared[idx], + dma_resv_held(cursor->obj)); +} +EXPORT_SYMBOL_GPL(dma_resv_iter_next); + /** * dma_resv_copy_fences - Copy all fences from src to dst. * @dst: the destination reservation object diff --git a/include/linux/dma-resv.h b/include/linux/dma-resv.h index 764138ad8583..491359cea54c 100644 --- a/include/linux/dma-resv.h +++ b/include/linux/dma-resv.h @@ -179,6 +179,8 @@ struct dma_resv_iter { struct dma_fence *dma_resv_iter_first_unlocked(struct dma_resv_iter *cursor); struct dma_fence *dma_resv_iter_next_unlocked(struct dma_resv_iter *cursor); +struct dma_fence *dma_resv_iter_first(struct dma_resv_iter *cursor); +struct dma_fence *dma_resv_iter_next(struct dma_resv_iter *cursor); /** * dma_resv_iter_begin - initialize a dma_resv_iter object @@ -244,6 +246,24 @@ static inline bool dma_resv_iter_is_restarted(struct dma_resv_iter *cursor) for (fence = dma_resv_iter_first_unlocked(cursor); \ fence; fence = dma_resv_iter_next_unlocked(cursor)) +/** + * dma_resv_for_each_fence - fence iterator + * @cursor: a struct dma_resv_iter pointer + * @obj: a dma_resv object pointer + * @all_fences: true if all fences should be returned + * @fence: the current fence + * + * Iterate over the fences in a struct dma_resv object while holding the + * &dma_resv.lock. @all_fences controls if the shared fences are returned as + * well. The cursor initialisation is part of the iterator and the fence stays + * valid as long as the lock is held and so no extra reference to the fence is + * taken. + */ +#define dma_resv_for_each_fence(cursor, obj, all_fences, fence) \ + for (dma_resv_iter_begin(cursor, obj, all_fences), \ + fence = dma_resv_iter_first(cursor); fence; \ + fence = dma_resv_iter_next(cursor)) + #define dma_resv_held(obj) lockdep_is_held(&(obj)->lock.base) #define dma_resv_assert_held(obj) lockdep_assert_held(&(obj)->lock.base) -- cgit From 63639d013a6ff202665f0fb7f4d810a5b6d46d79 Mon Sep 17 00:00:00 2001 From: Christian König Date: Thu, 23 Sep 2021 10:28:42 +0200 Subject: dma-buf: use the new iterator in dma_buf_debug_show MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplifying the code a bit. Signed-off-by: Christian König Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20211005113742.1101-9-christian.koenig@amd.com --- drivers/dma-buf/dma-buf.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 61e20ae7b08b..8242b5d9baeb 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -1356,10 +1356,9 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused) { struct dma_buf *buf_obj; struct dma_buf_attachment *attach_obj; - struct dma_resv *robj; - struct dma_resv_list *fobj; + struct dma_resv_iter cursor; struct dma_fence *fence; - int count = 0, attach_count, shared_count, i; + int count = 0, attach_count; size_t size = 0; int ret; @@ -1386,21 +1385,10 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused) file_inode(buf_obj->file)->i_ino, buf_obj->name ?: ""); - robj = buf_obj->resv; - fence = dma_resv_excl_fence(robj); - if (fence) - seq_printf(s, "\tExclusive fence: %s %s %ssignalled\n", - fence->ops->get_driver_name(fence), - fence->ops->get_timeline_name(fence), - dma_fence_is_signaled(fence) ? "" : "un"); - - fobj = rcu_dereference_protected(robj->fence, - dma_resv_held(robj)); - shared_count = fobj ? fobj->shared_count : 0; - for (i = 0; i < shared_count; i++) { - fence = rcu_dereference_protected(fobj->shared[i], - dma_resv_held(robj)); - seq_printf(s, "\tShared fence: %s %s %ssignalled\n", + dma_resv_for_each_fence(&cursor, buf_obj->resv, true, fence) { + seq_printf(s, "\t%s fence: %s %s %ssignalled\n", + dma_resv_iter_is_exclusive(&cursor) ? + "Exclusive" : "Shared", fence->ops->get_driver_name(fence), fence->ops->get_timeline_name(fence), dma_fence_is_signaled(fence) ? "" : "un"); -- cgit From 0a42016d9319db24d15789574fe132d8159d7578 Mon Sep 17 00:00:00 2001 From: Christian König Date: Fri, 24 Sep 2021 11:31:22 +0200 Subject: dma-buf: use the new iterator in dma_resv_poll MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify the code a bit. Signed-off-by: Christian König Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20211005113742.1101-10-christian.koenig@amd.com --- drivers/dma-buf/dma-buf.c | 36 ++++++------------------------------ 1 file changed, 6 insertions(+), 30 deletions(-) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 8242b5d9baeb..beb504a92d60 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -209,19 +209,14 @@ static void dma_buf_poll_cb(struct dma_fence *fence, struct dma_fence_cb *cb) dma_fence_put(fence); } -static bool dma_buf_poll_shared(struct dma_resv *resv, +static bool dma_buf_poll_add_cb(struct dma_resv *resv, bool write, struct dma_buf_poll_cb_t *dcb) { - struct dma_resv_list *fobj = dma_resv_shared_list(resv); + struct dma_resv_iter cursor; struct dma_fence *fence; - int i, r; - - if (!fobj) - return false; + int r; - for (i = 0; i < fobj->shared_count; ++i) { - fence = rcu_dereference_protected(fobj->shared[i], - dma_resv_held(resv)); + dma_resv_for_each_fence(&cursor, resv, write, fence) { dma_fence_get(fence); r = dma_fence_add_callback(fence, &dcb->cb, dma_buf_poll_cb); if (!r) @@ -232,24 +227,6 @@ static bool dma_buf_poll_shared(struct dma_resv *resv, return false; } -static bool dma_buf_poll_excl(struct dma_resv *resv, - struct dma_buf_poll_cb_t *dcb) -{ - struct dma_fence *fence = dma_resv_excl_fence(resv); - int r; - - if (!fence) - return false; - - dma_fence_get(fence); - r = dma_fence_add_callback(fence, &dcb->cb, dma_buf_poll_cb); - if (!r) - return true; - dma_fence_put(fence); - - return false; -} - static __poll_t dma_buf_poll(struct file *file, poll_table *poll) { struct dma_buf *dmabuf; @@ -282,8 +259,7 @@ static __poll_t dma_buf_poll(struct file *file, poll_table *poll) spin_unlock_irq(&dmabuf->poll.lock); if (events & EPOLLOUT) { - if (!dma_buf_poll_shared(resv, dcb) && - !dma_buf_poll_excl(resv, dcb)) + if (!dma_buf_poll_add_cb(resv, true, dcb)) /* No callback queued, wake up any other waiters */ dma_buf_poll_cb(NULL, &dcb->cb); else @@ -303,7 +279,7 @@ static __poll_t dma_buf_poll(struct file *file, poll_table *poll) spin_unlock_irq(&dmabuf->poll.lock); if (events & EPOLLIN) { - if (!dma_buf_poll_excl(resv, dcb)) + if (!dma_buf_poll_add_cb(resv, false, dcb)) /* No callback queued, wake up any other waiters */ dma_buf_poll_cb(NULL, &dcb->cb); else -- cgit From dbcae3bfcbca771e73e562a59c3d23f76426e0f9 Mon Sep 17 00:00:00 2001 From: Christian König Date: Tue, 15 Jun 2021 15:57:22 +0200 Subject: drm/ttm: use the new iterator in ttm_bo_flush_all_fences MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is probably a fix since we didn't even grabed a reference to the fences. Signed-off-by: Christian König Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20211005113742.1101-11-christian.koenig@amd.com --- drivers/gpu/drm/ttm/ttm_bo.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index d62b2013c367..3934ee225c78 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -269,23 +269,15 @@ static int ttm_bo_individualize_resv(struct ttm_buffer_object *bo) static void ttm_bo_flush_all_fences(struct ttm_buffer_object *bo) { struct dma_resv *resv = &bo->base._resv; - struct dma_resv_list *fobj; + struct dma_resv_iter cursor; struct dma_fence *fence; - int i; - - rcu_read_lock(); - fobj = dma_resv_shared_list(resv); - fence = dma_resv_excl_fence(resv); - if (fence && !fence->ops->signaled) - dma_fence_enable_sw_signaling(fence); - - for (i = 0; fobj && i < fobj->shared_count; ++i) { - fence = rcu_dereference(fobj->shared[i]); + dma_resv_iter_begin(&cursor, resv, true); + dma_resv_for_each_fence_unlocked(&cursor, fence) { if (!fence->ops->signaled) dma_fence_enable_sw_signaling(fence); } - rcu_read_unlock(); + dma_resv_iter_end(&cursor); } /** -- cgit From 9c2ba265352afc633a1e24d89c3ca499a9e429f4 Mon Sep 17 00:00:00 2001 From: Christian König Date: Mon, 13 Sep 2021 11:28:19 +0200 Subject: drm/scheduler: use new iterator in drm_sched_job_add_implicit_dependencies v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplifying the code a bit. v2: use dma_resv_for_each_fence Signed-off-by: Christian König Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20211005113742.1101-17-christian.koenig@amd.com --- drivers/gpu/drm/scheduler/sched_main.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index 042c16b5d54a..5bc5f775abe1 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -699,30 +699,16 @@ int drm_sched_job_add_implicit_dependencies(struct drm_sched_job *job, struct drm_gem_object *obj, bool write) { + struct dma_resv_iter cursor; + struct dma_fence *fence; int ret; - struct dma_fence **fences; - unsigned int i, fence_count; - - if (!write) { - struct dma_fence *fence = dma_resv_get_excl_unlocked(obj->resv); - - return drm_sched_job_add_dependency(job, fence); - } - - ret = dma_resv_get_fences(obj->resv, NULL, &fence_count, &fences); - if (ret || !fence_count) - return ret; - for (i = 0; i < fence_count; i++) { - ret = drm_sched_job_add_dependency(job, fences[i]); + dma_resv_for_each_fence(&cursor, obj->resv, write, fence) { + ret = drm_sched_job_add_dependency(job, fence); if (ret) - break; + return ret; } - - for (; i < fence_count; i++) - dma_fence_put(fences[i]); - kfree(fences); - return ret; + return 0; } EXPORT_SYMBOL(drm_sched_job_add_implicit_dependencies); -- cgit From a585070f268223766fcab4b9eb9eade28381eb48 Mon Sep 17 00:00:00 2001 From: Christian König Date: Mon, 13 Sep 2021 12:36:42 +0200 Subject: drm/i915: use the new iterator in i915_request_await_object v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplifying the code a bit. v2: add missing rcu_read_lock()/rcu_read_unlock() v3: use dma_resv_for_each_fence instead Signed-off-by: Christian König Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20211005113742.1101-20-christian.koenig@amd.com --- drivers/gpu/drm/i915/i915_request.c | 34 +++++----------------------------- 1 file changed, 5 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index ce446716d092..3839712ebd23 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -1509,38 +1509,14 @@ i915_request_await_object(struct i915_request *to, struct drm_i915_gem_object *obj, bool write) { - struct dma_fence *excl; + struct dma_resv_iter cursor; + struct dma_fence *fence; int ret = 0; - if (write) { - struct dma_fence **shared; - unsigned int count, i; - - ret = dma_resv_get_fences(obj->base.resv, &excl, &count, - &shared); + dma_resv_for_each_fence(&cursor, obj->base.resv, write, fence) { + ret = i915_request_await_dma_fence(to, fence); if (ret) - return ret; - - for (i = 0; i < count; i++) { - ret = i915_request_await_dma_fence(to, shared[i]); - if (ret) - break; - - dma_fence_put(shared[i]); - } - - for (; i < count; i++) - dma_fence_put(shared[i]); - kfree(shared); - } else { - excl = dma_resv_get_excl_unlocked(obj->base.resv); - } - - if (excl) { - if (ret == 0) - ret = i915_request_await_dma_fence(to, excl); - - dma_fence_put(excl); + break; } return ret; -- cgit From 7cd80132aeab30e4699f04e80d909678d231a558 Mon Sep 17 00:00:00 2001 From: Christian König Date: Mon, 13 Sep 2021 13:44:01 +0200 Subject: drm: use new iterator in drm_gem_fence_array_add_implicit v3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplifying the code a bit. v2: add missing rcu_read_lock()/unlock() v3: switch to locked version Signed-off-by: Christian König Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20211005113742.1101-24-christian.koenig@amd.com --- drivers/gpu/drm/drm_gem.c | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 09c820045859..4dcdec6487bb 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -1340,31 +1340,15 @@ int drm_gem_fence_array_add_implicit(struct xarray *fence_array, struct drm_gem_object *obj, bool write) { - int ret; - struct dma_fence **fences; - unsigned int i, fence_count; - - if (!write) { - struct dma_fence *fence = - dma_resv_get_excl_unlocked(obj->resv); - - return drm_gem_fence_array_add(fence_array, fence); - } + struct dma_resv_iter cursor; + struct dma_fence *fence; + int ret = 0; - ret = dma_resv_get_fences(obj->resv, NULL, - &fence_count, &fences); - if (ret || !fence_count) - return ret; - - for (i = 0; i < fence_count; i++) { - ret = drm_gem_fence_array_add(fence_array, fences[i]); + dma_resv_for_each_fence(&cursor, obj->resv, write, fence) { + ret = drm_gem_fence_array_add(fence_array, fence); if (ret) break; } - - for (; i < fence_count; i++) - dma_fence_put(fences[i]); - kfree(fences); return ret; } EXPORT_SYMBOL(drm_gem_fence_array_add_implicit); -- cgit From 460275f124fb072dca218a6b43b6370eebbab20d Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Tue, 5 Oct 2021 20:09:40 +0200 Subject: PCI: Add PCI_EXP_DEVCTL_PAYLOAD_* macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define a macro PCI_EXP_DEVCTL_PAYLOAD_* for every possible Max Payload Size in linux/pci_regs.h, in the same style as PCI_EXP_DEVCTL_READRQ_*. Link: https://lore.kernel.org/r/20211005180952.6812-2-kabel@kernel.org Signed-off-by: Pali Rohár Signed-off-by: Marek Behún Signed-off-by: Lorenzo Pieralisi Reviewed-by: Marek Behún Reviewed-by: Bjorn Helgaas --- include/uapi/linux/pci_regs.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h index e709ae8235e7..ff6ccbc6efe9 100644 --- a/include/uapi/linux/pci_regs.h +++ b/include/uapi/linux/pci_regs.h @@ -504,6 +504,12 @@ #define PCI_EXP_DEVCTL_URRE 0x0008 /* Unsupported Request Reporting En. */ #define PCI_EXP_DEVCTL_RELAX_EN 0x0010 /* Enable relaxed ordering */ #define PCI_EXP_DEVCTL_PAYLOAD 0x00e0 /* Max_Payload_Size */ +#define PCI_EXP_DEVCTL_PAYLOAD_128B 0x0000 /* 128 Bytes */ +#define PCI_EXP_DEVCTL_PAYLOAD_256B 0x0020 /* 256 Bytes */ +#define PCI_EXP_DEVCTL_PAYLOAD_512B 0x0040 /* 512 Bytes */ +#define PCI_EXP_DEVCTL_PAYLOAD_1024B 0x0060 /* 1024 Bytes */ +#define PCI_EXP_DEVCTL_PAYLOAD_2048B 0x0080 /* 2048 Bytes */ +#define PCI_EXP_DEVCTL_PAYLOAD_4096B 0x00a0 /* 4096 Bytes */ #define PCI_EXP_DEVCTL_EXT_TAG 0x0100 /* Extended Tag Field Enable */ #define PCI_EXP_DEVCTL_PHANTOM 0x0200 /* Phantom Functions Enable */ #define PCI_EXP_DEVCTL_AUX_PME 0x0400 /* Auxiliary Power PM Enable */ -- cgit From a4e17d65dafdd3513042d8f00404c9b6068a825c Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Tue, 5 Oct 2021 20:09:41 +0200 Subject: PCI: aardvark: Fix PCIe Max Payload Size setting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change PCIe Max Payload Size setting in PCIe Device Control register to 512 bytes to align with PCIe Link Initialization sequence as defined in Marvell Armada 3700 Functional Specification. According to the specification, maximal Max Payload Size supported by this device is 512 bytes. Without this kernel prints suspicious line: pci 0000:01:00.0: Upstream bridge's Max Payload Size set to 256 (was 16384, max 512) With this change it changes to: pci 0000:01:00.0: Upstream bridge's Max Payload Size set to 256 (was 512, max 512) Link: https://lore.kernel.org/r/20211005180952.6812-3-kabel@kernel.org Fixes: 8c39d710363c ("PCI: aardvark: Add Aardvark PCI host controller driver") Signed-off-by: Pali Rohár Signed-off-by: Marek Behún Signed-off-by: Lorenzo Pieralisi Reviewed-by: Marek Behún Cc: stable@vger.kernel.org --- drivers/pci/controller/pci-aardvark.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index 596ebcfcc82d..884510630bae 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -488,8 +488,9 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie) reg = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + PCI_EXP_DEVCTL); reg &= ~PCI_EXP_DEVCTL_RELAX_EN; reg &= ~PCI_EXP_DEVCTL_NOSNOOP_EN; + reg &= ~PCI_EXP_DEVCTL_PAYLOAD; reg &= ~PCI_EXP_DEVCTL_READRQ; - reg |= PCI_EXP_DEVCTL_PAYLOAD; /* Set max payload size */ + reg |= PCI_EXP_DEVCTL_PAYLOAD_512B; reg |= PCI_EXP_DEVCTL_READRQ_512B; advk_writel(pcie, reg, PCIE_CORE_PCIEXP_CAP + PCI_EXP_DEVCTL); -- cgit From 464de7e7fff767e87429cd7be09c4f2cb50a6ccb Mon Sep 17 00:00:00 2001 From: Marek Behún Date: Tue, 5 Oct 2021 20:09:42 +0200 Subject: PCI: aardvark: Don't spam about PIO Response Status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use dev_dbg() instead of dev_err() in advk_pcie_check_pio_status(). For example CRS is not an error status, it just says that the request should be retried. Link: https://lore.kernel.org/r/20211005180952.6812-4-kabel@kernel.org Fixes: 8c39d710363c1 ("PCI: aardvark: Add Aardvark PCI host controller driver") Signed-off-by: Marek Behún Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/pci-aardvark.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index 884510630bae..a7903c531aa3 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -683,7 +683,7 @@ static int advk_pcie_check_pio_status(struct advk_pcie *pcie, bool allow_crs, u3 else str_posted = "Posted"; - dev_err(dev, "%s PIO Response Status: %s, %#x @ %#x\n", + dev_dbg(dev, "%s PIO Response Status: %s, %#x @ %#x\n", str_posted, strcomp_status, reg, advk_readl(pcie, PIO_ADDR_LS)); return -EFAULT; -- cgit From d419052bc6c60fa4ab2b5a51d5f1e55a66e2b4ff Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Tue, 5 Oct 2021 20:09:43 +0200 Subject: PCI: aardvark: Fix preserving PCI_EXP_RTCTL_CRSSVE flag on emulated bridge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 43f5c77bcbd2 ("PCI: aardvark: Fix reporting CRS value") started using CRSSVE flag for handling CRS responses. PCI_EXP_RTCTL_CRSSVE flag is stored only in emulated config space buffer and there is handler for PCI_EXP_RTCTL register. So every read operation from config space automatically clears CRSSVE flag as it is not defined in PCI_EXP_RTCTL read handler. Fix this by reading current CRSSVE bit flag from emulated space buffer and appending it to PCI_EXP_RTCTL read response. Link: https://lore.kernel.org/r/20211005180952.6812-5-kabel@kernel.org Fixes: 43f5c77bcbd2 ("PCI: aardvark: Fix reporting CRS value") Signed-off-by: Pali Rohár Signed-off-by: Marek Behún Signed-off-by: Lorenzo Pieralisi Reviewed-by: Marek Behún --- drivers/pci/controller/pci-aardvark.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index a7903c531aa3..bb57ca6aed35 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -724,6 +724,7 @@ advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge, case PCI_EXP_RTCTL: { u32 val = advk_readl(pcie, PCIE_ISR0_MASK_REG); *value = (val & PCIE_MSG_PM_PME_MASK) ? 0 : PCI_EXP_RTCTL_PMEIE; + *value |= le16_to_cpu(bridge->pcie_conf.rootctl) & PCI_EXP_RTCTL_CRSSVE; *value |= PCI_EXP_RTCAP_CRSVIS << 16; return PCI_BRIDGE_EMUL_HANDLED; } -- cgit From 46ef6090dbf590711cb12680b6eafde5fa21fe87 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Tue, 5 Oct 2021 20:09:44 +0200 Subject: PCI: aardvark: Fix configuring Reference clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 366697018c9a ("PCI: aardvark: Add PHY support") introduced configuration of PCIe Reference clock via PCIE_CORE_REF_CLK_REG register, but did it incorrectly. PCIe Reference clock differential pair is routed from system board to endpoint card, so on CPU side it has output direction. Therefore it is required to enable transmitting and disable receiving. Default configuration according to Armada 3700 Functional Specifications is enabled receiver part and disabled transmitter. We need this change because otherwise PCIe Reference clock is configured to some undefined state when differential pair is used for both transmitting and receiving. Fix this by disabling receiver part. Link: https://lore.kernel.org/r/20211005180952.6812-6-kabel@kernel.org Fixes: 366697018c9a ("PCI: aardvark: Add PHY support") Signed-off-by: Pali Rohár Signed-off-by: Marek Behún Signed-off-by: Lorenzo Pieralisi Reviewed-by: Marek Behún Cc: stable@vger.kernel.org --- drivers/pci/controller/pci-aardvark.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index bb57ca6aed35..d5d6f92e5143 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -99,6 +99,7 @@ #define PCIE_CORE_CTRL2_MSI_ENABLE BIT(10) #define PCIE_CORE_REF_CLK_REG (CONTROL_BASE_ADDR + 0x14) #define PCIE_CORE_REF_CLK_TX_ENABLE BIT(1) +#define PCIE_CORE_REF_CLK_RX_ENABLE BIT(2) #define PCIE_MSG_LOG_REG (CONTROL_BASE_ADDR + 0x30) #define PCIE_ISR0_REG (CONTROL_BASE_ADDR + 0x40) #define PCIE_MSG_PM_PME_MASK BIT(7) @@ -451,9 +452,15 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie) u32 reg; int i; - /* Enable TX */ + /* + * Configure PCIe Reference clock. Direction is from the PCIe + * controller to the endpoint card, so enable transmitting of + * Reference clock differential signal off-chip and disable + * receiving off-chip differential signal. + */ reg = advk_readl(pcie, PCIE_CORE_REF_CLK_REG); reg |= PCIE_CORE_REF_CLK_TX_ENABLE; + reg &= ~PCIE_CORE_REF_CLK_RX_ENABLE; advk_writel(pcie, reg, PCIE_CORE_REF_CLK_REG); /* Set to Direct mode */ -- cgit From a7ca6d7fa3c02c032db5440ff392d96c04684c21 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Tue, 5 Oct 2021 20:09:45 +0200 Subject: PCI: aardvark: Do not clear status bits of masked interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PCIE_ISR1_REG says which interrupts are currently set / active, including those which are masked. The driver currently reads this register and looks if some unmasked interrupts are active, and if not, it clears status bits of _all_ interrupts, including the masked ones. This is incorrect, since, for example, some drivers may poll these bits. Remove this clearing, and also remove this early return statement completely, since it does not change functionality in any way. Link: https://lore.kernel.org/r/20211005180952.6812-7-kabel@kernel.org Fixes: 8c39d710363c ("PCI: aardvark: Add Aardvark PCI host controller driver") Signed-off-by: Pali Rohár Signed-off-by: Marek Behún Signed-off-by: Lorenzo Pieralisi Reviewed-by: Marek Behún Cc: stable@vger.kernel.org --- drivers/pci/controller/pci-aardvark.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index d5d6f92e5143..f7eebf453e83 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -1295,12 +1295,6 @@ static void advk_pcie_handle_int(struct advk_pcie *pcie) isr1_mask = advk_readl(pcie, PCIE_ISR1_MASK_REG); isr1_status = isr1_val & ((~isr1_mask) & PCIE_ISR1_ALL_MASK); - if (!isr0_status && !isr1_status) { - advk_writel(pcie, isr0_val, PCIE_ISR0_REG); - advk_writel(pcie, isr1_val, PCIE_ISR1_REG); - return; - } - /* Process MSI interrupts */ if (isr0_status & PCIE_ISR0_MSI_INT_PENDING) advk_pcie_handle_msi(pcie); -- cgit From 1fb95d7d3c7a926b002fe8a6bd27a1cb428b46dc Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Tue, 5 Oct 2021 20:09:46 +0200 Subject: PCI: aardvark: Do not unmask unused interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are lot of undocumented interrupt bits. To prevent unwanted spurious interrupts, fix all *_ALL_MASK macros to define all interrupt bits, so that driver can properly mask all interrupts, including those which are undocumented. Link: https://lore.kernel.org/r/20211005180952.6812-8-kabel@kernel.org Fixes: 8c39d710363c ("PCI: aardvark: Add Aardvark PCI host controller driver") Signed-off-by: Pali Rohár Signed-off-by: Marek Behún Signed-off-by: Lorenzo Pieralisi Reviewed-by: Marek Behún Cc: stable@vger.kernel.org --- drivers/pci/controller/pci-aardvark.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index f7eebf453e83..3448a8c446d4 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -107,13 +107,13 @@ #define PCIE_ISR0_MSI_INT_PENDING BIT(24) #define PCIE_ISR0_INTX_ASSERT(val) BIT(16 + (val)) #define PCIE_ISR0_INTX_DEASSERT(val) BIT(20 + (val)) -#define PCIE_ISR0_ALL_MASK GENMASK(26, 0) +#define PCIE_ISR0_ALL_MASK GENMASK(31, 0) #define PCIE_ISR1_REG (CONTROL_BASE_ADDR + 0x48) #define PCIE_ISR1_MASK_REG (CONTROL_BASE_ADDR + 0x4C) #define PCIE_ISR1_POWER_STATE_CHANGE BIT(4) #define PCIE_ISR1_FLUSH BIT(5) #define PCIE_ISR1_INTX_ASSERT(val) BIT(8 + (val)) -#define PCIE_ISR1_ALL_MASK GENMASK(11, 4) +#define PCIE_ISR1_ALL_MASK GENMASK(31, 0) #define PCIE_MSI_ADDR_LOW_REG (CONTROL_BASE_ADDR + 0x50) #define PCIE_MSI_ADDR_HIGH_REG (CONTROL_BASE_ADDR + 0x54) #define PCIE_MSI_STATUS_REG (CONTROL_BASE_ADDR + 0x58) @@ -199,7 +199,7 @@ #define PCIE_IRQ_MSI_INT2_DET BIT(21) #define PCIE_IRQ_RC_DBELL_DET BIT(22) #define PCIE_IRQ_EP_STATUS BIT(23) -#define PCIE_IRQ_ALL_MASK 0xfff0fb +#define PCIE_IRQ_ALL_MASK GENMASK(31, 0) #define PCIE_IRQ_ENABLE_INTS_MASK PCIE_IRQ_CORE_INT /* Transaction types */ -- cgit From 67cb2a4c93499c2c22704998fd1fd2bc35194d8e Mon Sep 17 00:00:00 2001 From: Marek Behún Date: Tue, 5 Oct 2021 20:09:47 +0200 Subject: PCI: aardvark: Deduplicate code in advk_pcie_rd_conf() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid code repetition in advk_pcie_rd_conf() by handling errors with goto jump, as is customary in kernel. Link: https://lore.kernel.org/r/20211005180952.6812-9-kabel@kernel.org Fixes: 43f5c77bcbd2 ("PCI: aardvark: Fix reporting CRS value") Signed-off-by: Marek Behún Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/pci-aardvark.c | 48 +++++++++++++++-------------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index 3448a8c446d4..cd5be284789e 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -920,18 +920,8 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn, (le16_to_cpu(pcie->bridge.pcie_conf.rootctl) & PCI_EXP_RTCTL_CRSSVE); - if (advk_pcie_pio_is_running(pcie)) { - /* - * If it is possible return Completion Retry Status so caller - * tries to issue the request again instead of failing. - */ - if (allow_crs) { - *val = CFG_RD_CRS_VAL; - return PCIBIOS_SUCCESSFUL; - } - *val = 0xffffffff; - return PCIBIOS_SET_FAILED; - } + if (advk_pcie_pio_is_running(pcie)) + goto try_crs; /* Program the control register */ reg = advk_readl(pcie, PIO_CTRL); @@ -955,25 +945,13 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn, advk_writel(pcie, 1, PIO_START); ret = advk_pcie_wait_pio(pcie); - if (ret < 0) { - /* - * If it is possible return Completion Retry Status so caller - * tries to issue the request again instead of failing. - */ - if (allow_crs) { - *val = CFG_RD_CRS_VAL; - return PCIBIOS_SUCCESSFUL; - } - *val = 0xffffffff; - return PCIBIOS_SET_FAILED; - } + if (ret < 0) + goto try_crs; /* Check PIO status and get the read result */ ret = advk_pcie_check_pio_status(pcie, allow_crs, val); - if (ret < 0) { - *val = 0xffffffff; - return PCIBIOS_SET_FAILED; - } + if (ret < 0) + goto fail; if (size == 1) *val = (*val >> (8 * (where & 3))) & 0xff; @@ -981,6 +959,20 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn, *val = (*val >> (8 * (where & 3))) & 0xffff; return PCIBIOS_SUCCESSFUL; + +try_crs: + /* + * If it is possible, return Completion Retry Status so that caller + * tries to issue the request again instead of failing. + */ + if (allow_crs) { + *val = CFG_RD_CRS_VAL; + return PCIBIOS_SUCCESSFUL; + } + +fail: + *val = 0xffffffff; + return PCIBIOS_SET_FAILED; } static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn, -- cgit From 223dec14a05337a4155f1deed46d2becce4d00fd Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Tue, 5 Oct 2021 20:09:48 +0200 Subject: PCI: aardvark: Implement re-issuing config requests on CRS response MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 43f5c77bcbd2 ("PCI: aardvark: Fix reporting CRS value") fixed handling of CRS response and when CRSSVE flag was not enabled it marked CRS response as failed transaction (due to simplicity). But pci-aardvark.c driver is already waiting up to the PIO_RETRY_CNT count for PIO config response and so we can with a small change implement re-issuing of config requests as described in PCIe base specification. This change implements re-issuing of config requests when response is CRS. Set upper bound of wait cycles to around PIO_RETRY_CNT, afterwards the transaction is marked as failed and an all-ones value is returned as before. We do this by returning appropriate error codes from function advk_pcie_check_pio_status(). On CRS we return -EAGAIN and caller then reissues transaction. Link: https://lore.kernel.org/r/20211005180952.6812-10-kabel@kernel.org Signed-off-by: Pali Rohár Signed-off-by: Marek Behún Signed-off-by: Lorenzo Pieralisi Reviewed-by: Marek Behún --- drivers/pci/controller/pci-aardvark.c | 67 ++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index cd5be284789e..efe8b5f7bf8c 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -603,6 +603,7 @@ static int advk_pcie_check_pio_status(struct advk_pcie *pcie, bool allow_crs, u3 u32 reg; unsigned int status; char *strcomp_status, *str_posted; + int ret; reg = advk_readl(pcie, PIO_STAT); status = (reg & PIO_COMPLETION_STATUS_MASK) >> @@ -627,6 +628,7 @@ static int advk_pcie_check_pio_status(struct advk_pcie *pcie, bool allow_crs, u3 case PIO_COMPLETION_STATUS_OK: if (reg & PIO_ERR_STATUS) { strcomp_status = "COMP_ERR"; + ret = -EFAULT; break; } /* Get the read result */ @@ -634,9 +636,11 @@ static int advk_pcie_check_pio_status(struct advk_pcie *pcie, bool allow_crs, u3 *val = advk_readl(pcie, PIO_RD_DATA); /* No error */ strcomp_status = NULL; + ret = 0; break; case PIO_COMPLETION_STATUS_UR: strcomp_status = "UR"; + ret = -EOPNOTSUPP; break; case PIO_COMPLETION_STATUS_CRS: if (allow_crs && val) { @@ -654,6 +658,7 @@ static int advk_pcie_check_pio_status(struct advk_pcie *pcie, bool allow_crs, u3 */ *val = CFG_RD_CRS_VAL; strcomp_status = NULL; + ret = 0; break; } /* PCIe r4.0, sec 2.3.2, says: @@ -669,21 +674,24 @@ static int advk_pcie_check_pio_status(struct advk_pcie *pcie, bool allow_crs, u3 * Request and taking appropriate action, e.g., complete the * Request to the host as a failed transaction. * - * To simplify implementation do not re-issue the Configuration - * Request and complete the Request as a failed transaction. + * So return -EAGAIN and caller (pci-aardvark.c driver) will + * re-issue request again up to the PIO_RETRY_CNT retries. */ strcomp_status = "CRS"; + ret = -EAGAIN; break; case PIO_COMPLETION_STATUS_CA: strcomp_status = "CA"; + ret = -ECANCELED; break; default: strcomp_status = "Unknown"; + ret = -EINVAL; break; } if (!strcomp_status) - return 0; + return ret; if (reg & PIO_NON_POSTED_REQ) str_posted = "Non-posted"; @@ -693,7 +701,7 @@ static int advk_pcie_check_pio_status(struct advk_pcie *pcie, bool allow_crs, u3 dev_dbg(dev, "%s PIO Response Status: %s, %#x @ %#x\n", str_posted, strcomp_status, reg, advk_readl(pcie, PIO_ADDR_LS)); - return -EFAULT; + return ret; } static int advk_pcie_wait_pio(struct advk_pcie *pcie) @@ -701,13 +709,13 @@ static int advk_pcie_wait_pio(struct advk_pcie *pcie) struct device *dev = &pcie->pdev->dev; int i; - for (i = 0; i < PIO_RETRY_CNT; i++) { + for (i = 1; i <= PIO_RETRY_CNT; i++) { u32 start, isr; start = advk_readl(pcie, PIO_START); isr = advk_readl(pcie, PIO_ISR); if (!start && isr) - return 0; + return i; udelay(PIO_RETRY_DELAY); } @@ -898,6 +906,7 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where, int size, u32 *val) { struct advk_pcie *pcie = bus->sysdata; + int retry_count; bool allow_crs; u32 reg; int ret; @@ -940,16 +949,22 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn, /* Program the data strobe */ advk_writel(pcie, 0xf, PIO_WR_DATA_STRB); - /* Clear PIO DONE ISR and start the transfer */ - advk_writel(pcie, 1, PIO_ISR); - advk_writel(pcie, 1, PIO_START); + retry_count = 0; + do { + /* Clear PIO DONE ISR and start the transfer */ + advk_writel(pcie, 1, PIO_ISR); + advk_writel(pcie, 1, PIO_START); - ret = advk_pcie_wait_pio(pcie); - if (ret < 0) - goto try_crs; + ret = advk_pcie_wait_pio(pcie); + if (ret < 0) + goto try_crs; + + retry_count += ret; + + /* Check PIO status and get the read result */ + ret = advk_pcie_check_pio_status(pcie, allow_crs, val); + } while (ret == -EAGAIN && retry_count < PIO_RETRY_CNT); - /* Check PIO status and get the read result */ - ret = advk_pcie_check_pio_status(pcie, allow_crs, val); if (ret < 0) goto fail; @@ -981,6 +996,7 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn, struct advk_pcie *pcie = bus->sysdata; u32 reg; u32 data_strobe = 0x0; + int retry_count; int offset; int ret; @@ -1022,19 +1038,22 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn, /* Program the data strobe */ advk_writel(pcie, data_strobe, PIO_WR_DATA_STRB); - /* Clear PIO DONE ISR and start the transfer */ - advk_writel(pcie, 1, PIO_ISR); - advk_writel(pcie, 1, PIO_START); + retry_count = 0; + do { + /* Clear PIO DONE ISR and start the transfer */ + advk_writel(pcie, 1, PIO_ISR); + advk_writel(pcie, 1, PIO_START); - ret = advk_pcie_wait_pio(pcie); - if (ret < 0) - return PCIBIOS_SET_FAILED; + ret = advk_pcie_wait_pio(pcie); + if (ret < 0) + return PCIBIOS_SET_FAILED; - ret = advk_pcie_check_pio_status(pcie, false, NULL); - if (ret < 0) - return PCIBIOS_SET_FAILED; + retry_count += ret; - return PCIBIOS_SUCCESSFUL; + ret = advk_pcie_check_pio_status(pcie, false, NULL); + } while (ret == -EAGAIN && retry_count < PIO_RETRY_CNT); + + return ret < 0 ? PCIBIOS_SET_FAILED : PCIBIOS_SUCCESSFUL; } static struct pci_ops advk_pcie_ops = { -- cgit From 454c53271fc11f3aa5e44e41fd99ca181bd32c62 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Tue, 5 Oct 2021 20:09:49 +0200 Subject: PCI: aardvark: Simplify initialization of rootcap on virtual bridge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PCIe config space can be initialized also before pci_bridge_emul_init() call, so move rootcap initialization after PCI config space initialization. This simplifies the function a little since it removes one if (ret < 0) check. Link: https://lore.kernel.org/r/20211005180952.6812-11-kabel@kernel.org Signed-off-by: Pali Rohár Signed-off-by: Marek Behún Signed-off-by: Lorenzo Pieralisi Reviewed-by: Marek Behún --- drivers/pci/controller/pci-aardvark.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index efe8b5f7bf8c..9c509d5a9afa 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -822,7 +822,6 @@ static struct pci_bridge_emul_ops advk_pci_bridge_emul_ops = { static int advk_sw_pci_bridge_init(struct advk_pcie *pcie) { struct pci_bridge_emul *bridge = &pcie->bridge; - int ret; bridge->conf.vendor = cpu_to_le16(advk_readl(pcie, PCIE_CORE_DEV_ID_REG) & 0xffff); @@ -842,19 +841,14 @@ static int advk_sw_pci_bridge_init(struct advk_pcie *pcie) /* Support interrupt A for MSI feature */ bridge->conf.intpin = PCIE_CORE_INT_A_ASSERT_ENABLE; + /* Indicates supports for Completion Retry Status */ + bridge->pcie_conf.rootcap = cpu_to_le16(PCI_EXP_RTCAP_CRSVIS); + bridge->has_pcie = true; bridge->data = pcie; bridge->ops = &advk_pci_bridge_emul_ops; - /* PCIe config space can be initialized after pci_bridge_emul_init() */ - ret = pci_bridge_emul_init(bridge, 0); - if (ret < 0) - return ret; - - /* Indicates supports for Completion Retry Status */ - bridge->pcie_conf.rootcap = cpu_to_le16(PCI_EXP_RTCAP_CRSVIS); - - return 0; + return pci_bridge_emul_init(bridge, 0); } static bool advk_pcie_valid_device(struct advk_pcie *pcie, struct pci_bus *bus, -- cgit From f76b36d40beee0a13aa8f6aa011df0d7cbbb8a7f Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Tue, 5 Oct 2021 20:09:50 +0200 Subject: PCI: aardvark: Fix link training MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix multiple link training issues in aardvark driver. The main reason of these issues was misunderstanding of what certain registers do, since their names and comments were misleading: before commit 96be36dbffac ("PCI: aardvark: Replace custom macros by standard linux/pci_regs.h macros"), the pci-aardvark.c driver used custom macros for accessing standard PCIe Root Bridge registers, and misleading comments did not help to understand what the code was really doing. After doing more tests and experiments I've come to the conclusion that the SPEED_GEN register in aardvark sets the PCIe revision / generation compliance and forces maximal link speed. Both GEN3 and GEN2 values set the read-only PCI_EXP_FLAGS_VERS bits (PCIe capabilities version of Root Bridge) to value 2, while GEN1 value sets PCI_EXP_FLAGS_VERS to 1, which matches with PCI Express specifications revisions 3, 2 and 1 respectively. Changing SPEED_GEN also sets the read-only bits PCI_EXP_LNKCAP_SLS and PCI_EXP_LNKCAP2_SLS to corresponding speed. (Note that PCI Express rev 1 specification does not define PCI_EXP_LNKCAP2 and PCI_EXP_LNKCTL2 registers and when SPEED_GEN is set to GEN1 (which also sets PCI_EXP_FLAGS_VERS set to 1), lspci cannot access PCI_EXP_LNKCAP2 and PCI_EXP_LNKCTL2 registers.) Changing PCIe link speed can be done via PCI_EXP_LNKCTL2_TLS bits of PCI_EXP_LNKCTL2 register. Armada 3700 Functional Specifications says that the default value of PCI_EXP_LNKCTL2_TLS is based on SPEED_GEN value, but tests showed that the default value is always 8.0 GT/s, independently of speed set by SPEED_GEN. So after setting SPEED_GEN, we must also set value in PCI_EXP_LNKCTL2 register via PCI_EXP_LNKCTL2_TLS bits. Triggering PCI_EXP_LNKCTL_RL bit immediately after setting LINK_TRAINING_EN bit actually doesn't do anything. Tests have shown that a delay is needed after enabling LINK_TRAINING_EN bit. As triggering PCI_EXP_LNKCTL_RL currently does nothing, remove it. Commit 43fc679ced18 ("PCI: aardvark: Improve link training") introduced code which sets SPEED_GEN register based on negotiated link speed from PCI_EXP_LNKSTA_CLS bits of PCI_EXP_LNKSTA register. This code was added to fix detection of Compex WLE900VX (Atheros QCA9880) WiFi GEN1 PCIe cards, as otherwise these cards were "invisible" on PCIe bus (probably because they crashed). But apparently more people reported the same issues with these cards also with other PCIe controllers [1] and I was able to reproduce this issue also with other "noname" WiFi cards based on Atheros QCA9890 chip (with the same PCI vendor/device ids as Atheros QCA9880). So this is not an issue in aardvark but rather an issue in Atheros QCA98xx chips. Also, this issue only exists if the kernel is compiled with PCIe ASPM support, and a generic workaround for this is to change PCIe Bridge to 2.5 GT/s link speed via PCI_EXP_LNKCTL2_TLS_2_5GT bits in PCI_EXP_LNKCTL2 register [2], before triggering PCI_EXP_LNKCTL_RL bit. This workaround also works when SPEED_GEN is set to value GEN2 (5 GT/s). So remove this hack completely in the aardvark driver and always set SPEED_GEN to value from 'max-link-speed' DT property. Fix for Atheros QCA98xx chips is handled separately by patch [2]. These two things (code for triggering PCI_EXP_LNKCTL_RL bit and changing SPEED_GEN value) also explain why commit 6964494582f5 ("PCI: aardvark: Train link immediately after enabling training") somehow fixed detection of those problematic Compex cards with Atheros chips: if triggering link retraining (via PCI_EXP_LNKCTL_RL bit) was done immediately after enabling link training (via LINK_TRAINING_EN), it did nothing. If there was a specific delay, aardvark HW already initialized PCIe link and therefore triggering link retraining caused the above issue. Compex cards triggered link down event and disappeared from the PCIe bus. Commit f4c7d053d7f7 ("PCI: aardvark: Wait for endpoint to be ready before training link") added 100ms sleep before calling 'Start link training' command and explained that it is a requirement of PCI Express specification. But the code after this 100ms sleep was not doing 'Start link training', rather it triggered PCI_EXP_LNKCTL_RL bit via PCIe Root Bridge to put link into Recovery state. The required delay after fundamental reset is already done in function advk_pcie_wait_for_link() which also checks whether PCIe link is up. So after removing the code which triggers PCI_EXP_LNKCTL_RL bit on PCIe Root Bridge, there is no need to wait 100ms again. Remove the extra msleep() call and update comment about the delay required by the PCI Express specification. According to Marvell Armada 3700 Functional Specifications, Link training should be enabled via aardvark register LINK_TRAINING_EN after selecting PCIe generation and x1 lane. There is no need to disable it prior resetting card via PERST# signal. This disabling code was introduced in commit 5169a9851daa ("PCI: aardvark: Issue PERST via GPIO") as a workaround for some Atheros cards. It turns out that this also is Atheros specific issue and affects any PCIe controller, not only aardvark. Moreover this Atheros issue was triggered by juggling with PCI_EXP_LNKCTL_RL, LINK_TRAINING_EN and SPEED_GEN bits interleaved with sleeps. Now, after removing triggering PCI_EXP_LNKCTL_RL, there is no need to explicitly disable LINK_TRAINING_EN bit. So remove this code too. The problematic Compex cards described in previous git commits are correctly detected in advk_pcie_train_link() function even after applying all these changes. Note that with this patch, and also prior this patch, some NVMe disks which support PCIe GEN3 with 8 GT/s speed are negotiated only at the lowest link speed 2.5 GT/s, independently of SPEED_GEN value. After manually triggering PCI_EXP_LNKCTL_RL bit (e.g. from userspace via setpci), these NVMe disks change link speed to 5 GT/s when SPEED_GEN was configured to GEN2. This issue first needs to be properly investigated. I will send a fix in the future. On the other hand, some other GEN2 PCIe cards with 5 GT/s speed are autonomously by HW autonegotiated at full 5 GT/s speed without need of any software interaction. Armada 3700 Functional Specifications describes the following steps for link training: set SPEED_GEN to GEN2, enable LINK_TRAINING_EN, poll until link training is complete, trigger PCI_EXP_LNKCTL_RL, poll until signal rate is 5 GT/s, poll until link training is complete, enable ASPM L0s. The requirement for triggering PCI_EXP_LNKCTL_RL can be explained by the need to achieve 5 GT/s speed (as changing link speed is done by throw to recovery state entered by PCI_EXP_LNKCTL_RL) or maybe as a part of enabling ASPM L0s (but in this case ASPM L0s should have been enabled prior PCI_EXP_LNKCTL_RL). It is unknown why the original pci-aardvark.c driver was triggering PCI_EXP_LNKCTL_RL bit before waiting for the link to be up. This does not align with neither PCIe base specifications nor with Armada 3700 Functional Specification. (Note that in older versions of aardvark, this bit was called incorrectly PCIE_CORE_LINK_TRAINING, so this may be the reason.) It is also unknown why Armada 3700 Functional Specification says that it is needed to trigger PCI_EXP_LNKCTL_RL for GEN2 mode, as according to PCIe base specification 5 GT/s speed negotiation is supposed to be entirely autonomous, even if initial speed is 2.5 GT/s. [1] - https://lore.kernel.org/linux-pci/87h7l8axqp.fsf@toke.dk/ [2] - https://lore.kernel.org/linux-pci/20210326124326.21163-1-pali@kernel.org/ Link: https://lore.kernel.org/r/20211005180952.6812-12-kabel@kernel.org Signed-off-by: Pali Rohár Signed-off-by: Marek Behún Signed-off-by: Lorenzo Pieralisi Reviewed-by: Marek Behún --- drivers/pci/controller/pci-aardvark.c | 117 ++++++++++------------------------ 1 file changed, 34 insertions(+), 83 deletions(-) diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index 9c509d5a9afa..2c66cdbb8dd6 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -258,11 +258,6 @@ static inline u32 advk_readl(struct advk_pcie *pcie, u64 reg) return readl(pcie->base + reg); } -static inline u16 advk_read16(struct advk_pcie *pcie, u64 reg) -{ - return advk_readl(pcie, (reg & ~0x3)) >> ((reg & 0x3) * 8); -} - static int advk_pcie_link_up(struct advk_pcie *pcie) { u32 val, ltssm_state; @@ -300,23 +295,9 @@ static void advk_pcie_wait_for_retrain(struct advk_pcie *pcie) static void advk_pcie_issue_perst(struct advk_pcie *pcie) { - u32 reg; - if (!pcie->reset_gpio) return; - /* - * As required by PCI Express spec (PCI Express Base Specification, REV. - * 4.0 PCI Express, February 19 2014, 6.6.1 Conventional Reset) a delay - * for at least 100ms after de-asserting PERST# signal is needed before - * link training is enabled. So ensure that link training is disabled - * prior de-asserting PERST# signal to fulfill that PCI Express spec - * requirement. - */ - reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG); - reg &= ~LINK_TRAINING_EN; - advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG); - /* 10ms delay is needed for some cards */ dev_info(&pcie->pdev->dev, "issuing PERST via reset GPIO for 10ms\n"); gpiod_set_value_cansleep(pcie->reset_gpio, 1); @@ -324,53 +305,46 @@ static void advk_pcie_issue_perst(struct advk_pcie *pcie) gpiod_set_value_cansleep(pcie->reset_gpio, 0); } -static int advk_pcie_train_at_gen(struct advk_pcie *pcie, int gen) +static void advk_pcie_train_link(struct advk_pcie *pcie) { - int ret, neg_gen; + struct device *dev = &pcie->pdev->dev; u32 reg; + int ret; - /* Setup link speed */ + /* + * Setup PCIe rev / gen compliance based on device tree property + * 'max-link-speed' which also forces maximal link speed. + */ reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG); reg &= ~PCIE_GEN_SEL_MSK; - if (gen == 3) + if (pcie->link_gen == 3) reg |= SPEED_GEN_3; - else if (gen == 2) + else if (pcie->link_gen == 2) reg |= SPEED_GEN_2; else reg |= SPEED_GEN_1; advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG); /* - * Enable link training. This is not needed in every call to this - * function, just once suffices, but it does not break anything either. + * Set maximal link speed value also into PCIe Link Control 2 register. + * Armada 3700 Functional Specification says that default value is based + * on SPEED_GEN but tests showed that default value is always 8.0 GT/s. */ + reg = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + PCI_EXP_LNKCTL2); + reg &= ~PCI_EXP_LNKCTL2_TLS; + if (pcie->link_gen == 3) + reg |= PCI_EXP_LNKCTL2_TLS_8_0GT; + else if (pcie->link_gen == 2) + reg |= PCI_EXP_LNKCTL2_TLS_5_0GT; + else + reg |= PCI_EXP_LNKCTL2_TLS_2_5GT; + advk_writel(pcie, reg, PCIE_CORE_PCIEXP_CAP + PCI_EXP_LNKCTL2); + + /* Enable link training after selecting PCIe generation */ reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG); reg |= LINK_TRAINING_EN; advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG); - /* - * Start link training immediately after enabling it. - * This solves problems for some buggy cards. - */ - reg = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + PCI_EXP_LNKCTL); - reg |= PCI_EXP_LNKCTL_RL; - advk_writel(pcie, reg, PCIE_CORE_PCIEXP_CAP + PCI_EXP_LNKCTL); - - ret = advk_pcie_wait_for_link(pcie); - if (ret) - return ret; - - reg = advk_read16(pcie, PCIE_CORE_PCIEXP_CAP + PCI_EXP_LNKSTA); - neg_gen = reg & PCI_EXP_LNKSTA_CLS; - - return neg_gen; -} - -static void advk_pcie_train_link(struct advk_pcie *pcie) -{ - struct device *dev = &pcie->pdev->dev; - int neg_gen = -1, gen; - /* * Reset PCIe card via PERST# signal. Some cards are not detected * during link training when they are in some non-initial state. @@ -381,41 +355,18 @@ static void advk_pcie_train_link(struct advk_pcie *pcie) * PERST# signal could have been asserted by pinctrl subsystem before * probe() callback has been called or issued explicitly by reset gpio * function advk_pcie_issue_perst(), making the endpoint going into - * fundamental reset. As required by PCI Express spec a delay for at - * least 100ms after such a reset before link training is needed. - */ - msleep(PCI_PM_D3COLD_WAIT); - - /* - * Try link training at link gen specified by device tree property - * 'max-link-speed'. If this fails, iteratively train at lower gen. - */ - for (gen = pcie->link_gen; gen > 0; --gen) { - neg_gen = advk_pcie_train_at_gen(pcie, gen); - if (neg_gen > 0) - break; - } - - if (neg_gen < 0) - goto err; - - /* - * After successful training if negotiated gen is lower than requested, - * train again on negotiated gen. This solves some stability issues for - * some buggy gen1 cards. + * fundamental reset. As required by PCI Express spec (PCI Express + * Base Specification, REV. 4.0 PCI Express, February 19 2014, 6.6.1 + * Conventional Reset) a delay for at least 100ms after such a reset + * before sending a Configuration Request to the device is needed. + * So wait until PCIe link is up. Function advk_pcie_wait_for_link() + * waits for link at least 900ms. */ - if (neg_gen < gen) { - gen = neg_gen; - neg_gen = advk_pcie_train_at_gen(pcie, gen); - } - - if (neg_gen == gen) { - dev_info(dev, "link up at gen %i\n", gen); - return; - } - -err: - dev_err(dev, "link never came up\n"); + ret = advk_pcie_wait_for_link(pcie); + if (ret < 0) + dev_err(dev, "link never came up\n"); + else + dev_info(dev, "link up\n"); } /* -- cgit From 661c399a651c11aaf83c45cbfe0b4a1fb7bc3179 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Tue, 5 Oct 2021 20:09:51 +0200 Subject: PCI: aardvark: Fix checking for link up via LTSSM state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Current implementation of advk_pcie_link_up() is wrong as it marks also link disabled or hot reset states as link up. Fix it by marking link up only to those states which are defined in PCIe Base specification 3.0, Table 4-14: Link Status Mapped to the LTSSM. To simplify implementation, Define macros for every LTSSM state which aardvark hardware can return in CFG_REG register. Fix also checking for link training according to the same Table 4-14. Define a new function advk_pcie_link_training() for this purpose. Link: https://lore.kernel.org/r/20211005180952.6812-13-kabel@kernel.org Fixes: 8c39d710363c ("PCI: aardvark: Add Aardvark PCI host controller driver") Signed-off-by: Pali Rohár Signed-off-by: Marek Behún Signed-off-by: Lorenzo Pieralisi Reviewed-by: Marek Behún Cc: stable@vger.kernel.org Cc: Remi Pommarel --- drivers/pci/controller/pci-aardvark.c | 76 ++++++++++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 6 deletions(-) diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index 2c66cdbb8dd6..f831f7d197bd 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -165,8 +165,50 @@ #define CFG_REG (LMI_BASE_ADDR + 0x0) #define LTSSM_SHIFT 24 #define LTSSM_MASK 0x3f -#define LTSSM_L0 0x10 #define RC_BAR_CONFIG 0x300 + +/* LTSSM values in CFG_REG */ +enum { + LTSSM_DETECT_QUIET = 0x0, + LTSSM_DETECT_ACTIVE = 0x1, + LTSSM_POLLING_ACTIVE = 0x2, + LTSSM_POLLING_COMPLIANCE = 0x3, + LTSSM_POLLING_CONFIGURATION = 0x4, + LTSSM_CONFIG_LINKWIDTH_START = 0x5, + LTSSM_CONFIG_LINKWIDTH_ACCEPT = 0x6, + LTSSM_CONFIG_LANENUM_ACCEPT = 0x7, + LTSSM_CONFIG_LANENUM_WAIT = 0x8, + LTSSM_CONFIG_COMPLETE = 0x9, + LTSSM_CONFIG_IDLE = 0xa, + LTSSM_RECOVERY_RCVR_LOCK = 0xb, + LTSSM_RECOVERY_SPEED = 0xc, + LTSSM_RECOVERY_RCVR_CFG = 0xd, + LTSSM_RECOVERY_IDLE = 0xe, + LTSSM_L0 = 0x10, + LTSSM_RX_L0S_ENTRY = 0x11, + LTSSM_RX_L0S_IDLE = 0x12, + LTSSM_RX_L0S_FTS = 0x13, + LTSSM_TX_L0S_ENTRY = 0x14, + LTSSM_TX_L0S_IDLE = 0x15, + LTSSM_TX_L0S_FTS = 0x16, + LTSSM_L1_ENTRY = 0x17, + LTSSM_L1_IDLE = 0x18, + LTSSM_L2_IDLE = 0x19, + LTSSM_L2_TRANSMIT_WAKE = 0x1a, + LTSSM_DISABLED = 0x20, + LTSSM_LOOPBACK_ENTRY_MASTER = 0x21, + LTSSM_LOOPBACK_ACTIVE_MASTER = 0x22, + LTSSM_LOOPBACK_EXIT_MASTER = 0x23, + LTSSM_LOOPBACK_ENTRY_SLAVE = 0x24, + LTSSM_LOOPBACK_ACTIVE_SLAVE = 0x25, + LTSSM_LOOPBACK_EXIT_SLAVE = 0x26, + LTSSM_HOT_RESET = 0x27, + LTSSM_RECOVERY_EQUALIZATION_PHASE0 = 0x28, + LTSSM_RECOVERY_EQUALIZATION_PHASE1 = 0x29, + LTSSM_RECOVERY_EQUALIZATION_PHASE2 = 0x2a, + LTSSM_RECOVERY_EQUALIZATION_PHASE3 = 0x2b, +}; + #define VENDOR_ID_REG (LMI_BASE_ADDR + 0x44) /* PCIe core controller registers */ @@ -258,13 +300,35 @@ static inline u32 advk_readl(struct advk_pcie *pcie, u64 reg) return readl(pcie->base + reg); } -static int advk_pcie_link_up(struct advk_pcie *pcie) +static u8 advk_pcie_ltssm_state(struct advk_pcie *pcie) { - u32 val, ltssm_state; + u32 val; + u8 ltssm_state; val = advk_readl(pcie, CFG_REG); ltssm_state = (val >> LTSSM_SHIFT) & LTSSM_MASK; - return ltssm_state >= LTSSM_L0; + return ltssm_state; +} + +static inline bool advk_pcie_link_up(struct advk_pcie *pcie) +{ + /* check if LTSSM is in normal operation - some L* state */ + u8 ltssm_state = advk_pcie_ltssm_state(pcie); + return ltssm_state >= LTSSM_L0 && ltssm_state < LTSSM_DISABLED; +} + +static inline bool advk_pcie_link_training(struct advk_pcie *pcie) +{ + /* + * According to PCIe Base specification 3.0, Table 4-14: Link + * Status Mapped to the LTSSM is Link Training mapped to LTSSM + * Configuration and Recovery states. + */ + u8 ltssm_state = advk_pcie_ltssm_state(pcie); + return ((ltssm_state >= LTSSM_CONFIG_LINKWIDTH_START && + ltssm_state < LTSSM_L0) || + (ltssm_state >= LTSSM_RECOVERY_EQUALIZATION_PHASE0 && + ltssm_state <= LTSSM_RECOVERY_EQUALIZATION_PHASE3)); } static int advk_pcie_wait_for_link(struct advk_pcie *pcie) @@ -287,7 +351,7 @@ static void advk_pcie_wait_for_retrain(struct advk_pcie *pcie) size_t retries; for (retries = 0; retries < RETRAIN_WAIT_MAX_RETRIES; ++retries) { - if (!advk_pcie_link_up(pcie)) + if (advk_pcie_link_training(pcie)) break; udelay(RETRAIN_WAIT_USLEEP_US); } @@ -706,7 +770,7 @@ advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge, /* u32 contains both PCI_EXP_LNKCTL and PCI_EXP_LNKSTA */ u32 val = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg) & ~(PCI_EXP_LNKSTA_LT << 16); - if (!advk_pcie_link_up(pcie)) + if (advk_pcie_link_training(pcie)) val |= (PCI_EXP_LNKSTA_LT << 16); *value = val; return PCI_BRIDGE_EMUL_HANDLED; -- cgit From 2b650b7ff20eb7ea8ef9031d20fb657286ab90cc Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Tue, 5 Oct 2021 20:09:52 +0200 Subject: PCI: aardvark: Fix reporting Data Link Layer Link Active MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for reporting PCI_EXP_LNKSTA_DLLLA bit in Link Control register on emulated bridge via current LTSSM state. Also correctly indicate DLLLA capability via PCI_EXP_LNKCAP_DLLLARC bit in Link Control Capability register. Link: https://lore.kernel.org/r/20211005180952.6812-14-kabel@kernel.org Fixes: 8a3ebd8de328 ("PCI: aardvark: Implement emulated root PCI bridge config space") Signed-off-by: Pali Rohár Signed-off-by: Marek Behún Signed-off-by: Lorenzo Pieralisi Reviewed-by: Marek Behún Cc: stable@vger.kernel.org --- drivers/pci/controller/pci-aardvark.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index f831f7d197bd..10476c00b312 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -317,6 +317,20 @@ static inline bool advk_pcie_link_up(struct advk_pcie *pcie) return ltssm_state >= LTSSM_L0 && ltssm_state < LTSSM_DISABLED; } +static inline bool advk_pcie_link_active(struct advk_pcie *pcie) +{ + /* + * According to PCIe Base specification 3.0, Table 4-14: Link + * Status Mapped to the LTSSM, and 4.2.6.3.6 Configuration.Idle + * is Link Up mapped to LTSSM Configuration.Idle, Recovery, L0, + * L0s, L1 and L2 states. And according to 3.2.1. Data Link + * Control and Management State Machine Rules is DL Up status + * reported in DL Active state. + */ + u8 ltssm_state = advk_pcie_ltssm_state(pcie); + return ltssm_state >= LTSSM_CONFIG_IDLE && ltssm_state < LTSSM_DISABLED; +} + static inline bool advk_pcie_link_training(struct advk_pcie *pcie) { /* @@ -766,12 +780,26 @@ advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge, return PCI_BRIDGE_EMUL_HANDLED; } + case PCI_EXP_LNKCAP: { + u32 val = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg); + /* + * PCI_EXP_LNKCAP_DLLLARC bit is hardwired in aardvark HW to 0. + * But support for PCI_EXP_LNKSTA_DLLLA is emulated via ltssm + * state so explicitly enable PCI_EXP_LNKCAP_DLLLARC flag. + */ + val |= PCI_EXP_LNKCAP_DLLLARC; + *value = val; + return PCI_BRIDGE_EMUL_HANDLED; + } + case PCI_EXP_LNKCTL: { /* u32 contains both PCI_EXP_LNKCTL and PCI_EXP_LNKSTA */ u32 val = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg) & ~(PCI_EXP_LNKSTA_LT << 16); if (advk_pcie_link_training(pcie)) val |= (PCI_EXP_LNKSTA_LT << 16); + if (advk_pcie_link_active(pcie)) + val |= (PCI_EXP_LNKSTA_DLLLA << 16); *value = val; return PCI_BRIDGE_EMUL_HANDLED; } @@ -779,7 +807,6 @@ advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge, case PCI_CAP_LIST_ID: case PCI_EXP_DEVCAP: case PCI_EXP_DEVCTL: - case PCI_EXP_LNKCAP: *value = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg); return PCI_BRIDGE_EMUL_HANDLED; default: -- cgit From 2908a0d81f5b24081e95219b8bdc5b93a310f537 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 23 Jun 2021 17:01:02 +0300 Subject: PCI: dwc: Clean up Kconfig dependencies (PCIE_DW_HOST) The "depends on" Kconfig construct is a no-op in options that are selected and therefore has no effect. Remove it. Furthermore, there is no need to repeat menu dependencies (PCI). Clean up the users of PCIE_DW_HOST and introduce idiom depends on PCI_MSI_IRQ_DOMAIN select PCIE_DW_HOST for all of them. Link: https://lore.kernel.org/r/20210623140103.47818-1-andriy.shevchenko@linux.intel.com Signed-off-by: Andy Shevchenko Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/Kconfig | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig index 9892a1135678..8c2028e2eca6 100644 --- a/drivers/pci/controller/dwc/Kconfig +++ b/drivers/pci/controller/dwc/Kconfig @@ -8,7 +8,6 @@ config PCIE_DW config PCIE_DW_HOST bool - depends on PCI_MSI_IRQ_DOMAIN select PCIE_DW config PCIE_DW_EP @@ -22,8 +21,8 @@ config PCI_DRA7XX config PCI_DRA7XX_HOST tristate "TI DRA7xx PCIe controller Host Mode" depends on SOC_DRA7XX || COMPILE_TEST - depends on PCI_MSI_IRQ_DOMAIN depends on OF && HAS_IOMEM && TI_PIPE3 + depends on PCI_MSI_IRQ_DOMAIN select PCIE_DW_HOST select PCI_DRA7XX default y if SOC_DRA7XX @@ -55,7 +54,7 @@ config PCIE_DW_PLAT config PCIE_DW_PLAT_HOST bool "Platform bus based DesignWare PCIe Controller - Host mode" - depends on PCI && PCI_MSI_IRQ_DOMAIN + depends on PCI_MSI_IRQ_DOMAIN select PCIE_DW_HOST select PCIE_DW_PLAT help @@ -138,8 +137,8 @@ config PCI_LAYERSCAPE bool "Freescale Layerscape PCIe controller - Host mode" depends on OF && (ARM || ARCH_LAYERSCAPE || COMPILE_TEST) depends on PCI_MSI_IRQ_DOMAIN - select MFD_SYSCON select PCIE_DW_HOST + select MFD_SYSCON help Say Y here if you want to enable PCIe controller support on Layerscape SoCs to work in Host mode. @@ -283,8 +282,8 @@ config PCIE_HISI_STB config PCI_MESON tristate "MESON PCIe controller" - depends on PCI_MSI_IRQ_DOMAIN default m if ARCH_MESON + depends on PCI_MSI_IRQ_DOMAIN select PCIE_DW_HOST help Say Y here if you want to enable PCI controller support on Amlogic -- cgit From 8faa1d2defb795806cc46c21d16ad01bb37d23c4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 23 Jun 2021 17:01:03 +0300 Subject: PCI: dwc: Clean up Kconfig dependencies (PCIE_DW_EP) The "depends on" Kconfig construct is a no-op in options that are selected and therefore has no effect. Remove it. Clean up the users of PCIE_DW_EP and introduce idiom depends on PCI_ENDPOINT select PCIE_DW_EP for all of them. Link: https://lore.kernel.org/r/20210623140103.47818-2-andriy.shevchenko@linux.intel.com Signed-off-by: Andy Shevchenko Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig index 8c2028e2eca6..6c4ee84053b5 100644 --- a/drivers/pci/controller/dwc/Kconfig +++ b/drivers/pci/controller/dwc/Kconfig @@ -12,7 +12,6 @@ config PCIE_DW_HOST config PCIE_DW_EP bool - depends on PCI_ENDPOINT select PCIE_DW config PCI_DRA7XX @@ -37,8 +36,8 @@ config PCI_DRA7XX_HOST config PCI_DRA7XX_EP tristate "TI DRA7xx PCIe controller Endpoint Mode" depends on SOC_DRA7XX || COMPILE_TEST - depends on PCI_ENDPOINT depends on OF && HAS_IOMEM && TI_PIPE3 + depends on PCI_ENDPOINT select PCIE_DW_EP select PCI_DRA7XX help -- cgit From 5b8402562e553983fc941bb955e2c14d1a69215f Mon Sep 17 00:00:00 2001 From: Krzysztof Wilczyński Date: Thu, 7 Oct 2021 12:28:48 +0000 Subject: PCI: visconti: Remove surplus dev_err() when using platform_get_irq_byname() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no need to call the dev_err() function directly to print a custom message when handling an error from either the platform_get_irq() or platform_get_irq_byname() functions as both are going to display an appropriate error message in case of a failure. This change is as per suggestions from Coccinelle, e.g., drivers/pci/controller/dwc/pcie-visconti.c:286:2-9: line 286 is redundant because platform_get_irq() already prints an error Related: https://lore.kernel.org/all/20210310131913.2802385-1-kw@linux.com/ https://lore.kernel.org/all/20200802142601.1635926-1-kw@linux.com/ Link: https://lore.kernel.org/r/20211007122848.3366-1-kw@linux.com Signed-off-by: Krzysztof Wilczyński Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-visconti.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-visconti.c b/drivers/pci/controller/dwc/pcie-visconti.c index a88eab6829bb..50f80f07e4db 100644 --- a/drivers/pci/controller/dwc/pcie-visconti.c +++ b/drivers/pci/controller/dwc/pcie-visconti.c @@ -279,13 +279,10 @@ static int visconti_add_pcie_port(struct visconti_pcie *pcie, { struct dw_pcie *pci = &pcie->pci; struct pcie_port *pp = &pci->pp; - struct device *dev = &pdev->dev; pp->irq = platform_get_irq_byname(pdev, "intr"); - if (pp->irq < 0) { - dev_err(dev, "Interrupt intr is missing"); + if (pp->irq < 0) return pp->irq; - } pp->ops = &visconti_pcie_host_ops; -- cgit From 42da7911b83a462373c2d093a587d052f02211b0 Mon Sep 17 00:00:00 2001 From: Chunguang Xu Date: Fri, 17 Sep 2021 21:13:24 +0800 Subject: PCI: vmd: Assign a number to each VMD controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the system has multiple VMD controllers, the driver does not assign a number to each controller, so when analyzing the interrupt through /proc/interrupts, the names of all controllers are the same, which is not very convenient for problem analysis. Here, try to assign a number to each VMD controller. Link: https://lore.kernel.org/r/1631884404-24141-1-git-send-email-brookxu.cn@gmail.com Signed-off-by: Chunguang Xu Signed-off-by: Lorenzo Pieralisi Reviewed-by: Jon Derrick Reviewed-by: Krzysztof Wilczyński --- drivers/pci/controller/vmd.c | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c index a5987e52700e..1b3e94a96414 100644 --- a/drivers/pci/controller/vmd.c +++ b/drivers/pci/controller/vmd.c @@ -70,6 +70,8 @@ enum vmd_features { VMD_FEAT_CAN_BYPASS_MSI_REMAP = (1 << 4), }; +static DEFINE_IDA(vmd_instance_ida); + /* * Lock for manipulating VMD IRQ lists. */ @@ -120,6 +122,8 @@ struct vmd_dev { struct pci_bus *bus; u8 busn_start; u8 first_vec; + char *name; + int instance; }; static inline struct vmd_dev *vmd_from_bus(struct pci_bus *bus) @@ -650,7 +654,7 @@ static int vmd_alloc_irqs(struct vmd_dev *vmd) INIT_LIST_HEAD(&vmd->irqs[i].irq_list); err = devm_request_irq(&dev->dev, pci_irq_vector(dev, i), vmd_irq, IRQF_NO_THREAD, - "vmd", &vmd->irqs[i]); + vmd->name, &vmd->irqs[i]); if (err) return err; } @@ -834,18 +838,32 @@ static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id) return -ENOMEM; vmd->dev = dev; + vmd->instance = ida_simple_get(&vmd_instance_ida, 0, 0, GFP_KERNEL); + if (vmd->instance < 0) + return vmd->instance; + + vmd->name = kasprintf(GFP_KERNEL, "vmd%d", vmd->instance); + if (!vmd->name) { + err = -ENOMEM; + goto out_release_instance; + } + err = pcim_enable_device(dev); if (err < 0) - return err; + goto out_release_instance; vmd->cfgbar = pcim_iomap(dev, VMD_CFGBAR, 0); - if (!vmd->cfgbar) - return -ENOMEM; + if (!vmd->cfgbar) { + err = -ENOMEM; + goto out_release_instance; + } pci_set_master(dev); if (dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(64)) && - dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32))) - return -ENODEV; + dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32))) { + err = -ENODEV; + goto out_release_instance; + } if (features & VMD_FEAT_OFFSET_FIRST_VECTOR) vmd->first_vec = 1; @@ -854,11 +872,16 @@ static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id) pci_set_drvdata(dev, vmd); err = vmd_enable_domain(vmd, features); if (err) - return err; + goto out_release_instance; dev_info(&vmd->dev->dev, "Bound to PCI domain %04x\n", vmd->sysdata.domain); return 0; + + out_release_instance: + ida_simple_remove(&vmd_instance_ida, vmd->instance); + kfree(vmd->name); + return err; } static void vmd_cleanup_srcu(struct vmd_dev *vmd) @@ -879,6 +902,8 @@ static void vmd_remove(struct pci_dev *dev) vmd_cleanup_srcu(vmd); vmd_detach_resources(vmd); vmd_remove_irq_domain(vmd); + ida_simple_remove(&vmd_instance_ida, vmd->instance); + kfree(vmd->name); } #ifdef CONFIG_PM_SLEEP @@ -903,7 +928,7 @@ static int vmd_resume(struct device *dev) for (i = 0; i < vmd->msix_count; i++) { err = devm_request_irq(dev, pci_irq_vector(pdev, i), vmd_irq, IRQF_NO_THREAD, - "vmd", &vmd->irqs[i]); + vmd->name, &vmd->irqs[i]); if (err) return err; } -- cgit From a090fe638e8d31e1753d5d1bcad99e2cd93e345f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 27 Sep 2021 14:50:39 +0200 Subject: dt-bindings: mmc: cdns: document Microchip MPFS MMC/SDHCI controller The Microchip PolarFire SoC FPGA DTSI uses Cadence SD/SDIO/eMMC Host Controller without any additional vendor compatible: arch/riscv/boot/dts/microchip/microchip-mpfs-icicle-kit.dt.yaml: mmc@20008000: compatible:0: 'cdns,sd4hc' is not one of ['socionext,uniphier-sd4hc'] arch/riscv/boot/dts/microchip/microchip-mpfs-icicle-kit.dt.yaml: mmc@20008000: compatible: ['cdns,sd4hc'] is too short Signed-off-by: Krzysztof Kozlowski Reviewed-by: Geert Uytterhoeven Acked-by: Rob Herring Reviewed-by: Conor Dooley Signed-off-by: Palmer Dabbelt --- Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml b/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml index af7442f73881..4207fed62dfe 100644 --- a/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml +++ b/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml @@ -17,6 +17,7 @@ properties: compatible: items: - enum: + - microchip,mpfs-sd4hc - socionext,uniphier-sd4hc - const: cdns,sd4hc -- cgit From 80a9609c93ef4601a4c640d4df079c05287186f9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 27 Sep 2021 14:50:40 +0200 Subject: riscv: dts: microchip: drop duplicated nodes The DTSI file defines soc node and address/size cells, so there is no point in duplicating it in DTS file. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Geert Uytterhoeven Signed-off-by: Palmer Dabbelt --- arch/riscv/boot/dts/microchip/microchip-mpfs-icicle-kit.dts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/riscv/boot/dts/microchip/microchip-mpfs-icicle-kit.dts b/arch/riscv/boot/dts/microchip/microchip-mpfs-icicle-kit.dts index b254c60589a1..3b04ef17e8da 100644 --- a/arch/riscv/boot/dts/microchip/microchip-mpfs-icicle-kit.dts +++ b/arch/riscv/boot/dts/microchip/microchip-mpfs-icicle-kit.dts @@ -9,8 +9,6 @@ #define RTCCLK_FREQ 1000000 / { - #address-cells = <2>; - #size-cells = <2>; model = "Microchip PolarFire-SoC Icicle Kit"; compatible = "microchip,mpfs-icicle-kit"; @@ -35,9 +33,6 @@ reg = <0x0 0x80000000 0x0 0x40000000>; clocks = <&clkcfg 26>; }; - - soc { - }; }; &serial0 { -- cgit From fd86dd2a5dc5ff1044423c19fef3907862f591c4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 27 Sep 2021 14:50:41 +0200 Subject: riscv: dts: microchip: fix board compatible According to bindings, the compatible must include microchip,mpfs. This fixes dtbs_check warning: arch/riscv/boot/dts/microchip/microchip-mpfs-icicle-kit.dt.yaml: /: compatible: ['microchip,mpfs-icicle-kit'] is too short Signed-off-by: Krzysztof Kozlowski Reviewed-by: Conor Dooley Reviewed-by: Geert Uytterhoeven Signed-off-by: Palmer Dabbelt --- arch/riscv/boot/dts/microchip/microchip-mpfs-icicle-kit.dts | 2 +- arch/riscv/boot/dts/microchip/microchip-mpfs.dtsi | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/riscv/boot/dts/microchip/microchip-mpfs-icicle-kit.dts b/arch/riscv/boot/dts/microchip/microchip-mpfs-icicle-kit.dts index 3b04ef17e8da..07f1f3cab686 100644 --- a/arch/riscv/boot/dts/microchip/microchip-mpfs-icicle-kit.dts +++ b/arch/riscv/boot/dts/microchip/microchip-mpfs-icicle-kit.dts @@ -10,7 +10,7 @@ / { model = "Microchip PolarFire-SoC Icicle Kit"; - compatible = "microchip,mpfs-icicle-kit"; + compatible = "microchip,mpfs-icicle-kit", "microchip,mpfs"; aliases { ethernet0 = &emac1; diff --git a/arch/riscv/boot/dts/microchip/microchip-mpfs.dtsi b/arch/riscv/boot/dts/microchip/microchip-mpfs.dtsi index 9d2fbbc1f777..446f41d6a87e 100644 --- a/arch/riscv/boot/dts/microchip/microchip-mpfs.dtsi +++ b/arch/riscv/boot/dts/microchip/microchip-mpfs.dtsi @@ -6,8 +6,8 @@ / { #address-cells = <2>; #size-cells = <2>; - model = "Microchip MPFS Icicle Kit"; - compatible = "microchip,mpfs-icicle-kit"; + model = "Microchip PolarFire SoC"; + compatible = "microchip,mpfs"; chosen { }; -- cgit From 42a57a47bb0c0f531321a7001972a3ca121409bd Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 27 Sep 2021 14:50:42 +0200 Subject: riscv: dts: microchip: drop duplicated MMC/SDHC node Devicetree source is a description of hardware and hardware has only one block @20008000 which can be configured either as eMMC or SDHC. Having two node for different modes is an obscure, unusual and confusing way to configure it. Instead the board file is supposed to customize the block to its needs, e.g. to SDHC mode. This fixes dtbs_check warning: arch/riscv/boot/dts/microchip/microchip-mpfs-icicle-kit.dt.yaml: sdhc@20008000: $nodename:0: 'sdhc@20008000' does not match '^mmc(@.*)?$' Signed-off-by: Krzysztof Kozlowski Signed-off-by: Palmer Dabbelt --- .../dts/microchip/microchip-mpfs-icicle-kit.dts | 11 +++++++- arch/riscv/boot/dts/microchip/microchip-mpfs.dtsi | 29 ++-------------------- 2 files changed, 12 insertions(+), 28 deletions(-) diff --git a/arch/riscv/boot/dts/microchip/microchip-mpfs-icicle-kit.dts b/arch/riscv/boot/dts/microchip/microchip-mpfs-icicle-kit.dts index 07f1f3cab686..fc1e5869df1b 100644 --- a/arch/riscv/boot/dts/microchip/microchip-mpfs-icicle-kit.dts +++ b/arch/riscv/boot/dts/microchip/microchip-mpfs-icicle-kit.dts @@ -51,8 +51,17 @@ status = "okay"; }; -&sdcard { +&mmc { status = "okay"; + + bus-width = <4>; + disable-wp; + cap-sd-highspeed; + card-detect-delay = <200>; + sd-uhs-sdr12; + sd-uhs-sdr25; + sd-uhs-sdr50; + sd-uhs-sdr104; }; &emac0 { diff --git a/arch/riscv/boot/dts/microchip/microchip-mpfs.dtsi b/arch/riscv/boot/dts/microchip/microchip-mpfs.dtsi index 446f41d6a87e..b12fd594e717 100644 --- a/arch/riscv/boot/dts/microchip/microchip-mpfs.dtsi +++ b/arch/riscv/boot/dts/microchip/microchip-mpfs.dtsi @@ -262,39 +262,14 @@ status = "disabled"; }; - emmc: mmc@20008000 { + /* Common node entry for emmc/sd */ + mmc: mmc@20008000 { compatible = "cdns,sd4hc"; reg = <0x0 0x20008000 0x0 0x1000>; interrupt-parent = <&plic>; interrupts = <88 89>; pinctrl-names = "default"; clocks = <&clkcfg 6>; - bus-width = <4>; - cap-mmc-highspeed; - mmc-ddr-3_3v; - max-frequency = <200000000>; - non-removable; - no-sd; - no-sdio; - voltage-ranges = <3300 3300>; - status = "disabled"; - }; - - sdcard: sdhc@20008000 { - compatible = "cdns,sd4hc"; - reg = <0x0 0x20008000 0x0 0x1000>; - interrupt-parent = <&plic>; - interrupts = <88>; - pinctrl-names = "default"; - clocks = <&clkcfg 6>; - bus-width = <4>; - disable-wp; - cap-sd-highspeed; - card-detect-delay = <200>; - sd-uhs-sdr12; - sd-uhs-sdr25; - sd-uhs-sdr50; - sd-uhs-sdr104; max-frequency = <200000000>; status = "disabled"; }; -- cgit From 33f736366b2c9b2664fbcb0ef0212866acd53fe0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 27 Sep 2021 14:50:43 +0200 Subject: riscv: dts: microchip: drop unused pinctrl-names pinctrl-names without pinctrl-0 does not have any sense: arch/riscv/boot/dts/microchip/microchip-mpfs-icicle-kit.dt.yaml: sdhc@20008000: 'pinctrl-0' is a dependency of 'pinctrl-names' Signed-off-by: Krzysztof Kozlowski Reviewed-by: Geert Uytterhoeven Signed-off-by: Palmer Dabbelt --- arch/riscv/boot/dts/microchip/microchip-mpfs.dtsi | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/riscv/boot/dts/microchip/microchip-mpfs.dtsi b/arch/riscv/boot/dts/microchip/microchip-mpfs.dtsi index b12fd594e717..ea500a36d2da 100644 --- a/arch/riscv/boot/dts/microchip/microchip-mpfs.dtsi +++ b/arch/riscv/boot/dts/microchip/microchip-mpfs.dtsi @@ -268,7 +268,6 @@ reg = <0x0 0x20008000 0x0 0x1000>; interrupt-parent = <&plic>; interrupts = <88 89>; - pinctrl-names = "default"; clocks = <&clkcfg 6>; max-frequency = <200000000>; status = "disabled"; -- cgit From 9406369ae6278532cb8d9d3cf3a8f1354662fb80 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 27 Sep 2021 14:50:44 +0200 Subject: riscv: dts: microchip: use vendor compatible for Cadence SD4HC Licensed IP blocks should have their own vendor compatible. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Conor Dooley Reviewed-by: Geert Uytterhoeven Signed-off-by: Palmer Dabbelt --- arch/riscv/boot/dts/microchip/microchip-mpfs.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/boot/dts/microchip/microchip-mpfs.dtsi b/arch/riscv/boot/dts/microchip/microchip-mpfs.dtsi index ea500a36d2da..923fa8f45790 100644 --- a/arch/riscv/boot/dts/microchip/microchip-mpfs.dtsi +++ b/arch/riscv/boot/dts/microchip/microchip-mpfs.dtsi @@ -264,7 +264,7 @@ /* Common node entry for emmc/sd */ mmc: mmc@20008000 { - compatible = "cdns,sd4hc"; + compatible = "microchip,mpfs-sd4hc", "cdns,sd4hc"; reg = <0x0 0x20008000 0x0 0x1000>; interrupt-parent = <&plic>; interrupts = <88 89>; -- cgit From 27ff8187f13ecfec8a26fb1928e906f46f326cc5 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 8 Oct 2021 15:46:52 +0800 Subject: opp: Fix return in _opp_add_static_v2() Fix sparse warning: drivers/opp/of.c:924 _opp_add_static_v2() warn: passing zero to 'ERR_PTR' For duplicate OPPs 'ret' be set to zero. Fixes: deac8703da5f ("PM / OPP: _of_add_opp_table_v2(): increment count only if OPP is added") Signed-off-by: YueHaibing Signed-off-by: Viresh Kumar --- drivers/opp/of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/opp/of.c b/drivers/opp/of.c index fe218af735b0..2f40afa4e65c 100644 --- a/drivers/opp/of.c +++ b/drivers/opp/of.c @@ -921,7 +921,7 @@ free_required_opps: free_opp: _opp_free(new_opp); - return ERR_PTR(ret); + return ret ? ERR_PTR(ret) : NULL; } /* Initializes OPP tables based on new bindings */ -- cgit From 91a45b12d49e2b43d86caba25ed59fae43344ab8 Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Thu, 7 Oct 2021 14:34:26 -0700 Subject: cxl/acpi: Do not fail cxl_acpi_probe() based on a missing CHBS When an ACPI0016 Host Bridge device is present yet no corresponding CEDT Host Bridge Structure (CHBS) exists, the ACPI probe method fails. Rather than fail, emit this warning and continue: cxl_acpi ACPI0017:00: No CHBS found for Host Bridge: ACPI0016:02 This error may occur on systems that are not compliant with the ACPI specification. Compliant systems include a CHBS entry for every CXL host bridge that is present at boot. Suggested-by: Ira Weiny Signed-off-by: Alison Schofield Tested-by: Vishal Verma Reviewed-by: Ira Weiny Link: https://lore.kernel.org/r/20211007213426.392644-1-alison.schofield@intel.com Signed-off-by: Dan Williams --- drivers/cxl/acpi.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c index af1c6c1875ac..dadc7f64b9ff 100644 --- a/drivers/cxl/acpi.c +++ b/drivers/cxl/acpi.c @@ -288,7 +288,7 @@ static int add_host_bridge_uport(struct device *match, void *arg) dport = find_dport_by_dev(root_port, match); if (!dport) { dev_dbg(host, "host bridge expected and not found\n"); - return -ENODEV; + return 0; } port = devm_cxl_add_port(host, match, dport->component_reg_phys, @@ -377,9 +377,11 @@ static int add_host_bridge_dport(struct device *match, void *arg) } chbs = cxl_acpi_match_chbs(host, uid); - if (IS_ERR(chbs)) - dev_dbg(host, "No CHBS found for Host Bridge: %s\n", - dev_name(match)); + if (IS_ERR(chbs)) { + dev_warn(host, "No CHBS found for Host Bridge: %s\n", + dev_name(match)); + return 0; + } rc = cxl_add_dport(root_port, match, uid, get_chbcr(chbs)); if (rc) { -- cgit From 24417d5b0c006fd4208284f3462f4012ae79151c Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 7 Sep 2021 04:40:38 +0200 Subject: drm/bridge: ti-sn65dsi83: Implement .detach callback Move detach implementation from sn65dsi83_remove() to dedicated .detach callback. There is no functional change to the code, but that detach is now in the correct location. Signed-off-by: Marek Vasut Cc: Jagan Teki Cc: Laurent Pinchart Cc: Linus Walleij Cc: Robert Foss Cc: Sam Ravnborg Cc: dri-devel@lists.freedesktop.org Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20210907024038.871299-1-marex@denx.de --- drivers/gpu/drm/bridge/ti-sn65dsi83.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c index a32f70bc68ea..ba1160ec6d6e 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c @@ -288,6 +288,19 @@ err_dsi_attach: return ret; } +static void sn65dsi83_detach(struct drm_bridge *bridge) +{ + struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge); + + if (!ctx->dsi) + return; + + mipi_dsi_detach(ctx->dsi); + mipi_dsi_device_unregister(ctx->dsi); + drm_bridge_remove(&ctx->bridge); + ctx->dsi = NULL; +} + static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge, struct drm_bridge_state *old_bridge_state) { @@ -583,6 +596,7 @@ sn65dsi83_atomic_get_input_bus_fmts(struct drm_bridge *bridge, static const struct drm_bridge_funcs sn65dsi83_funcs = { .attach = sn65dsi83_attach, + .detach = sn65dsi83_detach, .atomic_pre_enable = sn65dsi83_atomic_pre_enable, .atomic_enable = sn65dsi83_atomic_enable, .atomic_disable = sn65dsi83_atomic_disable, @@ -697,9 +711,6 @@ static int sn65dsi83_remove(struct i2c_client *client) { struct sn65dsi83 *ctx = i2c_get_clientdata(client); - mipi_dsi_detach(ctx->dsi); - mipi_dsi_device_unregister(ctx->dsi); - drm_bridge_remove(&ctx->bridge); of_node_put(ctx->host_node); return 0; -- cgit From 73e40c9bd44ce91fd0fcee6f0a3480dcd97963b6 Mon Sep 17 00:00:00 2001 From: Riccardo Mancini Date: Sat, 21 Aug 2021 11:19:07 +0200 Subject: libperf cpumap: Use binary search in perf_cpu_map__idx() as array are sorted Since 7074674e7338863e ("perf cpumap: Maintain cpumaps ordered and without dups") perf_cpu_map elements are sorted in ascending order. This patch improves perf_cpu_map__idx() by using a binary search. Signed-off-by: Riccardo Mancini Cc: Andi Kleen Cc: Ian Rogers Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/f1543c15797169c21e8b205a4a6751159180580d.1629490974.git.rickyman7@gmail.com [ Removed 'else' after if + return, declared variables where needed ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/perf/cpumap.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tools/lib/perf/cpumap.c b/tools/lib/perf/cpumap.c index 6d8e521c59e1..adaad3dddf6e 100644 --- a/tools/lib/perf/cpumap.c +++ b/tools/lib/perf/cpumap.c @@ -270,11 +270,19 @@ bool perf_cpu_map__empty(const struct perf_cpu_map *map) int perf_cpu_map__idx(struct perf_cpu_map *cpus, int cpu) { - int i; + int low = 0, high = cpus->nr; - for (i = 0; i < cpus->nr; ++i) { - if (cpus->map[i] == cpu) - return i; + while (low < high) { + int idx = (low + high) / 2, + cpu_at_idx = cpus->map[idx]; + + if (cpu_at_idx == cpu) + return idx; + + if (cpu_at_idx > cpu) + high = idx; + else + low = idx + 1; } return -1; -- cgit From c65bd90dc93e1b2f8e776f619ffbb0335a7a16ec Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 1 Oct 2021 14:16:09 +0200 Subject: PCI: rcar-ep: Remove unneeded includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove includes that are not needed, to speed up (re)compilation. Include , which is needed, and was included implicitly through before. Most of these are relics from splitting the driver in a host and a common part and adding endpoint support. [bhelgaas: use driver tag consistent with cadence-ep, designware-ep] Link: https://lore.kernel.org/r/7c708841a2bf84f85b14a963271c3e99c8ba38a5.1633090444.git.geert+renesas@glider.be Signed-off-by: Geert Uytterhoeven Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Reviewed-by: Niklas Söderlund --- drivers/pci/controller/pcie-rcar-ep.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/pci/controller/pcie-rcar-ep.c b/drivers/pci/controller/pcie-rcar-ep.c index aa1cf24a5a72..f9682df1da61 100644 --- a/drivers/pci/controller/pcie-rcar-ep.c +++ b/drivers/pci/controller/pcie-rcar-ep.c @@ -6,16 +6,13 @@ * Author: Lad Prabhakar */ -#include #include #include -#include -#include #include #include #include -#include #include +#include #include "pcie-rcar.h" -- cgit From 6bd006c6eb7fdadbe36de84377af4447da4ffabb Mon Sep 17 00:00:00 2001 From: Riccardo Mancini Date: Sat, 21 Aug 2021 11:19:10 +0200 Subject: perf mmap: Introduce mmap_cpu_mask__duplicate() This patch adds a new function in util/mmap.c to duplicate a mmap_cpu_mask. This new function will be used in patches in the workqueue patchkit. Signed-off-by: Riccardo Mancini Cc: Ian Rogers Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/8943a548ef7a3dd3e015095afad7e9a8b2154c05.1629490974.git.rickyman7@gmail.com [ bitmap_alloc() was renamed to bitmap_zalloc() ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/mmap.c | 11 +++++++++++ tools/perf/util/mmap.h | 3 +++ 2 files changed, 14 insertions(+) diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c index 512dc8b9c168..23ecdba9e670 100644 --- a/tools/perf/util/mmap.c +++ b/tools/perf/util/mmap.c @@ -350,3 +350,14 @@ int perf_mmap__push(struct mmap *md, void *to, out: return rc; } + +int mmap_cpu_mask__duplicate(struct mmap_cpu_mask *original, struct mmap_cpu_mask *clone) +{ + clone->nbits = original->nbits; + clone->bits = bitmap_zalloc(original->nbits); + if (!clone->bits) + return -ENOMEM; + + memcpy(clone->bits, original->bits, MMAP_CPU_MASK_BYTES(original)); + return 0; +} diff --git a/tools/perf/util/mmap.h b/tools/perf/util/mmap.h index af33118354dd..8e259b9610f8 100644 --- a/tools/perf/util/mmap.h +++ b/tools/perf/util/mmap.h @@ -64,4 +64,7 @@ size_t mmap__mmap_len(struct mmap *map); void mmap_cpu_mask__scnprintf(struct mmap_cpu_mask *mask, const char *tag); +int mmap_cpu_mask__duplicate(struct mmap_cpu_mask *original, + struct mmap_cpu_mask *clone); + #endif /*__PERF_MMAP_H */ -- cgit From 861e133ba268bef4765ea62c9602d4116b9c63ec Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 1 Oct 2021 14:16:43 +0200 Subject: PCI: rcar-host: Remove unneeded includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove includes that are not needed, to speed up (re)compilation. Most of these are relics from splitting the driver in a host and a common part. [bhelgaas: use driver tag analogous to rcar-ep] Link: https://lore.kernel.org/r/54bed9a0e6991490ddb2b07e5abfaf40a7a62928.1633090577.git.geert+renesas@glider.be Signed-off-by: Geert Uytterhoeven Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Reviewed-by: Niklas Söderlund --- drivers/pci/controller/pcie-rcar-host.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/pci/controller/pcie-rcar-host.c b/drivers/pci/controller/pcie-rcar-host.c index 8f3131844e77..e12c2d8be05a 100644 --- a/drivers/pci/controller/pcie-rcar-host.c +++ b/drivers/pci/controller/pcie-rcar-host.c @@ -24,13 +24,11 @@ #include #include #include -#include #include #include #include #include #include -#include #include "pcie-rcar.h" -- cgit From c2d4fab01f5e69adbe697c82f35cc31cf200bf93 Mon Sep 17 00:00:00 2001 From: Riccardo Mancini Date: Sat, 21 Aug 2021 11:19:42 +0200 Subject: perf test evlist-open-close: Use inline func to convert timeval to usec This patch introduces a new inline function to convert a timeval to usec. This function will be used also in the next patch. Signed-off-by: Riccardo Mancini Cc: Ian Rogers Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/b95035ec4a125355be8ea843f7275c4580da6398.1629490974.git.rickyman7@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/bench/evlist-open-close.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/perf/bench/evlist-open-close.c b/tools/perf/bench/evlist-open-close.c index 83e9897c64a1..75a53919126b 100644 --- a/tools/perf/bench/evlist-open-close.c +++ b/tools/perf/bench/evlist-open-close.c @@ -25,6 +25,11 @@ static int iterations = 100; static int nr_events = 1; static const char *event_string = "dummy"; +static inline u64 timeval2usec(struct timeval *tv) +{ + return tv->tv_sec * USEC_PER_SEC + tv->tv_usec; +} + static struct record_opts opts = { .sample_time = true, .mmap_pages = UINT_MAX, @@ -167,7 +172,7 @@ static int bench_evlist_open_close__run(char *evstr) gettimeofday(&end, NULL); timersub(&end, &start, &diff); - runtime_us = diff.tv_sec * USEC_PER_SEC + diff.tv_usec; + runtime_us = timeval2usec(&diff); update_stats(&time_stats, runtime_us); evlist__delete(evlist); -- cgit From 31c9ef00258075df2f1fe5ef812cd7e9b6a1dc55 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 20 Sep 2021 12:29:44 +0530 Subject: dt-bindings: PCI: Add Qualcomm PCIe Endpoint controller Add devicetree binding for Qualcomm PCIe Endpoint controller used in platforms like SDX55. The Endpoint controller is based on the DesignWare core with Qualcomm-specific wrappers. Link: https://lore.kernel.org/r/20210920065946.15090-2-manivannan.sadhasivam@linaro.org Signed-off-by: Manivannan Sadhasivam Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Reviewed-by: Rob Herring --- .../devicetree/bindings/pci/qcom,pcie-ep.yaml | 158 +++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 Documentation/devicetree/bindings/pci/qcom,pcie-ep.yaml diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie-ep.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie-ep.yaml new file mode 100644 index 000000000000..3d23599e5e91 --- /dev/null +++ b/Documentation/devicetree/bindings/pci/qcom,pcie-ep.yaml @@ -0,0 +1,158 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pci/qcom,pcie-ep.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm PCIe Endpoint Controller binding + +maintainers: + - Manivannan Sadhasivam + +allOf: + - $ref: "pci-ep.yaml#" + +properties: + compatible: + const: qcom,sdx55-pcie-ep + + reg: + items: + - description: Qualcomm-specific PARF configuration registers + - description: DesignWare PCIe registers + - description: External local bus interface registers + - description: Address Translation Unit (ATU) registers + - description: Memory region used to map remote RC address space + - description: BAR memory region + + reg-names: + items: + - const: parf + - const: dbi + - const: elbi + - const: atu + - const: addr_space + - const: mmio + + clocks: + items: + - description: PCIe Auxiliary clock + - description: PCIe CFG AHB clock + - description: PCIe Master AXI clock + - description: PCIe Slave AXI clock + - description: PCIe Slave Q2A AXI clock + - description: PCIe Sleep clock + - description: PCIe Reference clock + + clock-names: + items: + - const: aux + - const: cfg + - const: bus_master + - const: bus_slave + - const: slave_q2a + - const: sleep + - const: ref + + qcom,perst-regs: + description: Reference to a syscon representing TCSR followed by the two + offsets within syscon for Perst enable and Perst separation + enable registers + $ref: "/schemas/types.yaml#/definitions/phandle-array" + items: + minItems: 3 + maxItems: 3 + + interrupts: + items: + - description: PCIe Global interrupt + - description: PCIe Doorbell interrupt + + interrupt-names: + items: + - const: global + - const: doorbell + + reset-gpios: + description: GPIO used as PERST# input signal + maxItems: 1 + + wake-gpios: + description: GPIO used as WAKE# output signal + maxItems: 1 + + resets: + maxItems: 1 + + reset-names: + const: core + + power-domains: + maxItems: 1 + + phys: + maxItems: 1 + + phy-names: + const: pciephy + + num-lanes: + default: 2 + +required: + - compatible + - reg + - reg-names + - clocks + - clock-names + - qcom,perst-regs + - interrupts + - interrupt-names + - reset-gpios + - resets + - reset-names + - power-domains + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + pcie_ep: pcie-ep@40000000 { + compatible = "qcom,sdx55-pcie-ep"; + reg = <0x01c00000 0x3000>, + <0x40000000 0xf1d>, + <0x40000f20 0xc8>, + <0x40001000 0x1000>, + <0x40002000 0x1000>, + <0x01c03000 0x3000>; + reg-names = "parf", "dbi", "elbi", "atu", "addr_space", + "mmio"; + + clocks = <&gcc GCC_PCIE_AUX_CLK>, + <&gcc GCC_PCIE_CFG_AHB_CLK>, + <&gcc GCC_PCIE_MSTR_AXI_CLK>, + <&gcc GCC_PCIE_SLV_AXI_CLK>, + <&gcc GCC_PCIE_SLV_Q2A_AXI_CLK>, + <&gcc GCC_PCIE_SLEEP_CLK>, + <&gcc GCC_PCIE_0_CLKREF_CLK>; + clock-names = "aux", "cfg", "bus_master", "bus_slave", + "slave_q2a", "sleep", "ref"; + + qcom,perst-regs = <&tcsr 0xb258 0xb270>; + + interrupts = , + ; + interrupt-names = "global", "doorbell"; + reset-gpios = <&tlmm 57 GPIO_ACTIVE_LOW>; + wake-gpios = <&tlmm 53 GPIO_ACTIVE_LOW>; + resets = <&gcc GCC_PCIE_BCR>; + reset-names = "core"; + power-domains = <&gcc PCIE_GDSC>; + phys = <&pcie0_lane>; + phy-names = "pciephy"; + max-link-speed = <3>; + num-lanes = <2>; + }; -- cgit From e539a77e44c7bc4ca3822ed14fba01cf8936ee97 Mon Sep 17 00:00:00 2001 From: Philip Chen Date: Wed, 29 Sep 2021 17:34:57 -0700 Subject: dt-bindings: drm/bridge: ps8640: Add aux-bus child dp-aux-bus.yaml says we can list an eDP panel as a child of an eDP controller node to represent the fact that the panel is connected to the controller's DP AUX bus. Let's add it to the ps8640 bindings. Signed-off-by: Philip Chen Reviewed-by: Douglas Anderson Reviewed-by: Stephen Boyd Reviewed-by: Rob Herring Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20210929173343.v2.2.I6050ba184b24d887e92692a72ee3054d643d6091@changeid --- .../devicetree/bindings/display/bridge/ps8640.yaml | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/bridge/ps8640.yaml b/Documentation/devicetree/bindings/display/bridge/ps8640.yaml index fce82b605c8b..cdaf7a7a8f88 100644 --- a/Documentation/devicetree/bindings/display/bridge/ps8640.yaml +++ b/Documentation/devicetree/bindings/display/bridge/ps8640.yaml @@ -40,6 +40,9 @@ properties: vdd33-supply: description: Regulator for 3.3V digital core power. + aux-bus: + $ref: /schemas/display/dp-aux-bus.yaml# + ports: $ref: /schemas/graph.yaml#/properties/ports @@ -98,7 +101,21 @@ examples: reg = <1>; ps8640_out: endpoint { remote-endpoint = <&panel_in>; - }; + }; + }; + }; + + aux-bus { + panel { + compatible = "boe,nv133fhm-n62"; + power-supply = <&pp3300_dx_edp>; + backlight = <&backlight>; + + port { + panel_in: endpoint { + remote-endpoint = <&ps8640_out>; + }; + }; }; }; }; -- cgit From c6c00900c751c2fab9e34ee27f5e883fc1a20fc6 Mon Sep 17 00:00:00 2001 From: Guo Zhengkui Date: Wed, 6 Oct 2021 14:22:34 +0800 Subject: perf daemon: Remove duplicate sys/file.h include There is a "#include " in line 10, so remove a duplicate one in line 1124. Signed-off-by: Guo Zhengkui Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/20211006062235.6364-1-guozhengkui@vivo.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-daemon.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/perf/builtin-daemon.c b/tools/perf/builtin-daemon.c index c13201fb09c3..6cb3f6cc36d0 100644 --- a/tools/perf/builtin-daemon.c +++ b/tools/perf/builtin-daemon.c @@ -1121,8 +1121,6 @@ static int setup_config(struct daemon *daemon) #ifndef F_TLOCK #define F_TLOCK 2 -#include - static int lockf(int fd, int cmd, off_t len) { if (cmd != F_TLOCK || len != 0) -- cgit From 08f3e0873ac203449465c2b8473d684e2f9f41d1 Mon Sep 17 00:00:00 2001 From: James Clark Date: Thu, 7 Oct 2021 12:05:40 +0100 Subject: perf vendor-events: Fix all remaining invalid JSON files Remove trailing commas. A later commit will make the parser more strict and these will not be valid anymore. Reviewed-by: Andi Kleen Reviewed-by: John Garry Reviewed-by: Kajol Jain Signed-off-by: James Clark Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andrew.Kilroy@arm.com Cc: Leo Yan Cc: Mark Rutland Cc: Mathieu Poirier Cc: Namhyung Kim Cc: Nick.Forrington@arm.com Cc: Will Deacon Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20211007110543.564963-2-james.clark@arm.com Signed-off-by: Arnaldo Carvalho de Melo --- .../perf/pmu-events/arch/arm64/ampere/emag/bus.json | 2 +- .../pmu-events/arch/arm64/ampere/emag/cache.json | 20 ++++++++++---------- .../pmu-events/arch/arm64/ampere/emag/clock.json | 2 +- .../pmu-events/arch/arm64/ampere/emag/exception.json | 4 ++-- .../arch/arm64/ampere/emag/instruction.json | 10 +++++----- .../pmu-events/arch/arm64/ampere/emag/memory.json | 4 ++-- .../arch/arm64/hisilicon/hip08/metrics.json | 2 +- tools/perf/pmu-events/arch/nds32/n13/atcpmu.json | 2 +- tools/perf/pmu-events/arch/s390/cf_z10/basic.json | 2 +- tools/perf/pmu-events/arch/s390/cf_z10/crypto.json | 2 +- tools/perf/pmu-events/arch/s390/cf_z10/extended.json | 2 +- tools/perf/pmu-events/arch/s390/cf_z13/basic.json | 2 +- tools/perf/pmu-events/arch/s390/cf_z13/crypto.json | 2 +- tools/perf/pmu-events/arch/s390/cf_z13/extended.json | 2 +- tools/perf/pmu-events/arch/s390/cf_z14/basic.json | 2 +- tools/perf/pmu-events/arch/s390/cf_z14/crypto.json | 2 +- tools/perf/pmu-events/arch/s390/cf_z14/extended.json | 2 +- tools/perf/pmu-events/arch/s390/cf_z15/basic.json | 2 +- tools/perf/pmu-events/arch/s390/cf_z15/crypto.json | 2 +- tools/perf/pmu-events/arch/s390/cf_z15/crypto6.json | 2 +- tools/perf/pmu-events/arch/s390/cf_z15/extended.json | 2 +- tools/perf/pmu-events/arch/s390/cf_z196/basic.json | 2 +- tools/perf/pmu-events/arch/s390/cf_z196/crypto.json | 2 +- .../perf/pmu-events/arch/s390/cf_z196/extended.json | 2 +- tools/perf/pmu-events/arch/s390/cf_zec12/basic.json | 2 +- tools/perf/pmu-events/arch/s390/cf_zec12/crypto.json | 2 +- .../perf/pmu-events/arch/s390/cf_zec12/extended.json | 2 +- .../pmu-events/arch/test/test_soc/cpu/uncore.json | 2 +- .../pmu-events/arch/x86/icelakex/icx-metrics.json | 2 +- 29 files changed, 44 insertions(+), 44 deletions(-) diff --git a/tools/perf/pmu-events/arch/arm64/ampere/emag/bus.json b/tools/perf/pmu-events/arch/arm64/ampere/emag/bus.json index 9bea1ba1c4d2..cf48d0dfc759 100644 --- a/tools/perf/pmu-events/arch/arm64/ampere/emag/bus.json +++ b/tools/perf/pmu-events/arch/arm64/ampere/emag/bus.json @@ -18,6 +18,6 @@ "ArchStdEvent": "BUS_ACCESS_PERIPH" }, { - "ArchStdEvent": "BUS_ACCESS", + "ArchStdEvent": "BUS_ACCESS" } ] diff --git a/tools/perf/pmu-events/arch/arm64/ampere/emag/cache.json b/tools/perf/pmu-events/arch/arm64/ampere/emag/cache.json index 1e25f2ae4ae0..4cc50b7da526 100644 --- a/tools/perf/pmu-events/arch/arm64/ampere/emag/cache.json +++ b/tools/perf/pmu-events/arch/arm64/ampere/emag/cache.json @@ -39,31 +39,31 @@ "ArchStdEvent": "L2D_CACHE_INVAL" }, { - "ArchStdEvent": "L1I_CACHE_REFILL", + "ArchStdEvent": "L1I_CACHE_REFILL" }, { - "ArchStdEvent": "L1I_TLB_REFILL", + "ArchStdEvent": "L1I_TLB_REFILL" }, { - "ArchStdEvent": "L1D_CACHE_REFILL", + "ArchStdEvent": "L1D_CACHE_REFILL" }, { - "ArchStdEvent": "L1D_CACHE", + "ArchStdEvent": "L1D_CACHE" }, { - "ArchStdEvent": "L1D_TLB_REFILL", + "ArchStdEvent": "L1D_TLB_REFILL" }, { - "ArchStdEvent": "L1I_CACHE", + "ArchStdEvent": "L1I_CACHE" }, { - "ArchStdEvent": "L2D_CACHE", + "ArchStdEvent": "L2D_CACHE" }, { - "ArchStdEvent": "L2D_CACHE_REFILL", + "ArchStdEvent": "L2D_CACHE_REFILL" }, { - "ArchStdEvent": "L2D_CACHE_WB", + "ArchStdEvent": "L2D_CACHE_WB" }, { "PublicDescription": "This event counts any load or store operation which accesses the data L1 TLB", @@ -72,7 +72,7 @@ }, { "PublicDescription": "This event counts any instruction fetch which accesses the instruction L1 TLB", - "ArchStdEvent": "L1I_TLB", + "ArchStdEvent": "L1I_TLB" }, { "PublicDescription": "Level 2 access to data TLB that caused a page table walk. This event counts on any data access which causes L2D_TLB_REFILL to count", diff --git a/tools/perf/pmu-events/arch/arm64/ampere/emag/clock.json b/tools/perf/pmu-events/arch/arm64/ampere/emag/clock.json index 9076ca2daf9e..927a6f629a03 100644 --- a/tools/perf/pmu-events/arch/arm64/ampere/emag/clock.json +++ b/tools/perf/pmu-events/arch/arm64/ampere/emag/clock.json @@ -1,7 +1,7 @@ [ { "PublicDescription": "The number of core clock cycles", - "ArchStdEvent": "CPU_CYCLES", + "ArchStdEvent": "CPU_CYCLES" }, { "PublicDescription": "FSU clocking gated off cycle", diff --git a/tools/perf/pmu-events/arch/arm64/ampere/emag/exception.json b/tools/perf/pmu-events/arch/arm64/ampere/emag/exception.json index 9761433ad329..ada052e19632 100644 --- a/tools/perf/pmu-events/arch/arm64/ampere/emag/exception.json +++ b/tools/perf/pmu-events/arch/arm64/ampere/emag/exception.json @@ -36,9 +36,9 @@ "ArchStdEvent": "EXC_TRAP_FIQ" }, { - "ArchStdEvent": "EXC_TAKEN", + "ArchStdEvent": "EXC_TAKEN" }, { - "ArchStdEvent": "EXC_RETURN", + "ArchStdEvent": "EXC_RETURN" } ] diff --git a/tools/perf/pmu-events/arch/arm64/ampere/emag/instruction.json b/tools/perf/pmu-events/arch/arm64/ampere/emag/instruction.json index 482aa3f19e58..62f6276e3016 100644 --- a/tools/perf/pmu-events/arch/arm64/ampere/emag/instruction.json +++ b/tools/perf/pmu-events/arch/arm64/ampere/emag/instruction.json @@ -44,25 +44,25 @@ "BriefDescription": "Software increment" }, { - "ArchStdEvent": "INST_RETIRED", + "ArchStdEvent": "INST_RETIRED" }, { "ArchStdEvent": "CID_WRITE_RETIRED", "BriefDescription": "Write to CONTEXTIDR" }, { - "ArchStdEvent": "INST_SPEC", + "ArchStdEvent": "INST_SPEC" }, { - "ArchStdEvent": "TTBR_WRITE_RETIRED", + "ArchStdEvent": "TTBR_WRITE_RETIRED" }, { "PublicDescription": "This event counts all branches, taken or not. This excludes exception entries, debug entries and CCFAIL branches", - "ArchStdEvent": "BR_RETIRED", + "ArchStdEvent": "BR_RETIRED" }, { "PublicDescription": "This event counts any branch counted by BR_RETIRED which is not correctly predicted and causes a pipeline flush", - "ArchStdEvent": "BR_MIS_PRED_RETIRED", + "ArchStdEvent": "BR_MIS_PRED_RETIRED" }, { "PublicDescription": "Operation speculatively executed, NOP", diff --git a/tools/perf/pmu-events/arch/arm64/ampere/emag/memory.json b/tools/perf/pmu-events/arch/arm64/ampere/emag/memory.json index 2e7555696caf..50157e8c2005 100644 --- a/tools/perf/pmu-events/arch/arm64/ampere/emag/memory.json +++ b/tools/perf/pmu-events/arch/arm64/ampere/emag/memory.json @@ -15,10 +15,10 @@ "ArchStdEvent": "UNALIGNED_LDST_SPEC" }, { - "ArchStdEvent": "MEM_ACCESS", + "ArchStdEvent": "MEM_ACCESS" }, { "PublicDescription": "This event counts any correctable or uncorrectable memory error (ECC or parity) in the protected core RAMs", - "ArchStdEvent": "MEMORY_ERROR", + "ArchStdEvent": "MEMORY_ERROR" } ] diff --git a/tools/perf/pmu-events/arch/arm64/hisilicon/hip08/metrics.json b/tools/perf/pmu-events/arch/arm64/hisilicon/hip08/metrics.json index dda8e59149d2..6970203cb247 100644 --- a/tools/perf/pmu-events/arch/arm64/hisilicon/hip08/metrics.json +++ b/tools/perf/pmu-events/arch/arm64/hisilicon/hip08/metrics.json @@ -229,5 +229,5 @@ "BriefDescription": "Store bound L3 topdown metric", "MetricGroup": "TopDownL3", "MetricName": "store_bound" - }, + } ] diff --git a/tools/perf/pmu-events/arch/nds32/n13/atcpmu.json b/tools/perf/pmu-events/arch/nds32/n13/atcpmu.json index 5347350c360c..3e7ac409d894 100644 --- a/tools/perf/pmu-events/arch/nds32/n13/atcpmu.json +++ b/tools/perf/pmu-events/arch/nds32/n13/atcpmu.json @@ -286,5 +286,5 @@ "EventCode": "0x21e", "EventName": "pop25_inst", "BriefDescription": "V3 POP25 instructions" - }, + } ] diff --git a/tools/perf/pmu-events/arch/s390/cf_z10/basic.json b/tools/perf/pmu-events/arch/s390/cf_z10/basic.json index 2dd8dafff2ef..783de7f1aeaa 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z10/basic.json +++ b/tools/perf/pmu-events/arch/s390/cf_z10/basic.json @@ -82,5 +82,5 @@ "EventName": "PROBLEM_STATE_L1D_PENALTY_CYCLES", "BriefDescription": "Problem-State L1D Penalty Cycles", "PublicDescription": "Problem-State Level-1 D-Cache Penalty Cycle Count" - }, + } ] diff --git a/tools/perf/pmu-events/arch/s390/cf_z10/crypto.json b/tools/perf/pmu-events/arch/s390/cf_z10/crypto.json index db286f19e7b6..3f28007d3892 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z10/crypto.json +++ b/tools/perf/pmu-events/arch/s390/cf_z10/crypto.json @@ -110,5 +110,5 @@ "EventName": "AES_BLOCKED_CYCLES", "BriefDescription": "AES Blocked Cycles", "PublicDescription": "Total number of CPU cycles blocked for the AES functions issued by the CPU because the DEA/AES coprocessor is busy performing a function issued by another CPU" - }, + } ] diff --git a/tools/perf/pmu-events/arch/s390/cf_z10/extended.json b/tools/perf/pmu-events/arch/s390/cf_z10/extended.json index b6b7f29ca831..86bd8ba9391d 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z10/extended.json +++ b/tools/perf/pmu-events/arch/s390/cf_z10/extended.json @@ -124,5 +124,5 @@ "EventName": "L2C_STORES_SENT", "BriefDescription": "L2C Stores Sent", "PublicDescription": "Incremented by one for every store sent to Level-2 (L1.5) cache" - }, + } ] diff --git a/tools/perf/pmu-events/arch/s390/cf_z13/basic.json b/tools/perf/pmu-events/arch/s390/cf_z13/basic.json index 2dd8dafff2ef..783de7f1aeaa 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z13/basic.json +++ b/tools/perf/pmu-events/arch/s390/cf_z13/basic.json @@ -82,5 +82,5 @@ "EventName": "PROBLEM_STATE_L1D_PENALTY_CYCLES", "BriefDescription": "Problem-State L1D Penalty Cycles", "PublicDescription": "Problem-State Level-1 D-Cache Penalty Cycle Count" - }, + } ] diff --git a/tools/perf/pmu-events/arch/s390/cf_z13/crypto.json b/tools/perf/pmu-events/arch/s390/cf_z13/crypto.json index db286f19e7b6..3f28007d3892 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z13/crypto.json +++ b/tools/perf/pmu-events/arch/s390/cf_z13/crypto.json @@ -110,5 +110,5 @@ "EventName": "AES_BLOCKED_CYCLES", "BriefDescription": "AES Blocked Cycles", "PublicDescription": "Total number of CPU cycles blocked for the AES functions issued by the CPU because the DEA/AES coprocessor is busy performing a function issued by another CPU" - }, + } ] diff --git a/tools/perf/pmu-events/arch/s390/cf_z13/extended.json b/tools/perf/pmu-events/arch/s390/cf_z13/extended.json index 5da8296b667e..1a5e4f89c57e 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z13/extended.json +++ b/tools/perf/pmu-events/arch/s390/cf_z13/extended.json @@ -390,5 +390,5 @@ "EventName": "MT_DIAG_CYCLES_TWO_THR_ACTIVE", "BriefDescription": "Cycle count with two threads active", "PublicDescription": "Cycle count with two threads active" - }, + } ] diff --git a/tools/perf/pmu-events/arch/s390/cf_z14/basic.json b/tools/perf/pmu-events/arch/s390/cf_z14/basic.json index 17fb5241928b..fc762e9f1d6e 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z14/basic.json +++ b/tools/perf/pmu-events/arch/s390/cf_z14/basic.json @@ -54,5 +54,5 @@ "EventName": "PROBLEM_STATE_INSTRUCTIONS", "BriefDescription": "Problem-State Instructions", "PublicDescription": "Problem-State Instruction Count" - }, + } ] diff --git a/tools/perf/pmu-events/arch/s390/cf_z14/crypto.json b/tools/perf/pmu-events/arch/s390/cf_z14/crypto.json index db286f19e7b6..3f28007d3892 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z14/crypto.json +++ b/tools/perf/pmu-events/arch/s390/cf_z14/crypto.json @@ -110,5 +110,5 @@ "EventName": "AES_BLOCKED_CYCLES", "BriefDescription": "AES Blocked Cycles", "PublicDescription": "Total number of CPU cycles blocked for the AES functions issued by the CPU because the DEA/AES coprocessor is busy performing a function issued by another CPU" - }, + } ] diff --git a/tools/perf/pmu-events/arch/s390/cf_z14/extended.json b/tools/perf/pmu-events/arch/s390/cf_z14/extended.json index 89e070727e1b..4942b20a1ea1 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z14/extended.json +++ b/tools/perf/pmu-events/arch/s390/cf_z14/extended.json @@ -369,5 +369,5 @@ "EventName": "MT_DIAG_CYCLES_TWO_THR_ACTIVE", "BriefDescription": "Cycle count with two threads active", "PublicDescription": "Cycle count with two threads active" - }, + } ] diff --git a/tools/perf/pmu-events/arch/s390/cf_z15/basic.json b/tools/perf/pmu-events/arch/s390/cf_z15/basic.json index 17fb5241928b..fc762e9f1d6e 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z15/basic.json +++ b/tools/perf/pmu-events/arch/s390/cf_z15/basic.json @@ -54,5 +54,5 @@ "EventName": "PROBLEM_STATE_INSTRUCTIONS", "BriefDescription": "Problem-State Instructions", "PublicDescription": "Problem-State Instruction Count" - }, + } ] diff --git a/tools/perf/pmu-events/arch/s390/cf_z15/crypto.json b/tools/perf/pmu-events/arch/s390/cf_z15/crypto.json index db286f19e7b6..3f28007d3892 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z15/crypto.json +++ b/tools/perf/pmu-events/arch/s390/cf_z15/crypto.json @@ -110,5 +110,5 @@ "EventName": "AES_BLOCKED_CYCLES", "BriefDescription": "AES Blocked Cycles", "PublicDescription": "Total number of CPU cycles blocked for the AES functions issued by the CPU because the DEA/AES coprocessor is busy performing a function issued by another CPU" - }, + } ] diff --git a/tools/perf/pmu-events/arch/s390/cf_z15/crypto6.json b/tools/perf/pmu-events/arch/s390/cf_z15/crypto6.json index c998e4f1d1d2..ad79189050a0 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z15/crypto6.json +++ b/tools/perf/pmu-events/arch/s390/cf_z15/crypto6.json @@ -26,5 +26,5 @@ "EventName": "ECC_BLOCKED_CYCLES_COUNT", "BriefDescription": "ECC Blocked Cycles Count", "PublicDescription": "This counter counts the total number of CPU cycles blocked for the elliptic-curve cryptography (ECC) functions issued by the CPU because the ECC coprocessor is busy performing a function issued by another CPU." - }, + } ] diff --git a/tools/perf/pmu-events/arch/s390/cf_z15/extended.json b/tools/perf/pmu-events/arch/s390/cf_z15/extended.json index 24c4ba2a9ae5..8ac61f8f286b 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z15/extended.json +++ b/tools/perf/pmu-events/arch/s390/cf_z15/extended.json @@ -397,5 +397,5 @@ "EventName": "MT_DIAG_CYCLES_TWO_THR_ACTIVE", "BriefDescription": "Cycle count with two threads active", "PublicDescription": "Cycle count with two threads active" - }, + } ] diff --git a/tools/perf/pmu-events/arch/s390/cf_z196/basic.json b/tools/perf/pmu-events/arch/s390/cf_z196/basic.json index 2dd8dafff2ef..783de7f1aeaa 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z196/basic.json +++ b/tools/perf/pmu-events/arch/s390/cf_z196/basic.json @@ -82,5 +82,5 @@ "EventName": "PROBLEM_STATE_L1D_PENALTY_CYCLES", "BriefDescription": "Problem-State L1D Penalty Cycles", "PublicDescription": "Problem-State Level-1 D-Cache Penalty Cycle Count" - }, + } ] diff --git a/tools/perf/pmu-events/arch/s390/cf_z196/crypto.json b/tools/perf/pmu-events/arch/s390/cf_z196/crypto.json index db286f19e7b6..3f28007d3892 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z196/crypto.json +++ b/tools/perf/pmu-events/arch/s390/cf_z196/crypto.json @@ -110,5 +110,5 @@ "EventName": "AES_BLOCKED_CYCLES", "BriefDescription": "AES Blocked Cycles", "PublicDescription": "Total number of CPU cycles blocked for the AES functions issued by the CPU because the DEA/AES coprocessor is busy performing a function issued by another CPU" - }, + } ] diff --git a/tools/perf/pmu-events/arch/s390/cf_z196/extended.json b/tools/perf/pmu-events/arch/s390/cf_z196/extended.json index b7b42a870bb0..86b29fd181cf 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z196/extended.json +++ b/tools/perf/pmu-events/arch/s390/cf_z196/extended.json @@ -166,5 +166,5 @@ "EventName": "L1I_OFFCHIP_L3_SOURCED_WRITES", "BriefDescription": "L1I Off-Chip L3 Sourced Writes", "PublicDescription": "A directory write to the Level-1 I-Cache directory where the returned cache line was sourced from an Off Chip/On Book Level-3 cache" - }, + } ] diff --git a/tools/perf/pmu-events/arch/s390/cf_zec12/basic.json b/tools/perf/pmu-events/arch/s390/cf_zec12/basic.json index 2dd8dafff2ef..783de7f1aeaa 100644 --- a/tools/perf/pmu-events/arch/s390/cf_zec12/basic.json +++ b/tools/perf/pmu-events/arch/s390/cf_zec12/basic.json @@ -82,5 +82,5 @@ "EventName": "PROBLEM_STATE_L1D_PENALTY_CYCLES", "BriefDescription": "Problem-State L1D Penalty Cycles", "PublicDescription": "Problem-State Level-1 D-Cache Penalty Cycle Count" - }, + } ] diff --git a/tools/perf/pmu-events/arch/s390/cf_zec12/crypto.json b/tools/perf/pmu-events/arch/s390/cf_zec12/crypto.json index db286f19e7b6..3f28007d3892 100644 --- a/tools/perf/pmu-events/arch/s390/cf_zec12/crypto.json +++ b/tools/perf/pmu-events/arch/s390/cf_zec12/crypto.json @@ -110,5 +110,5 @@ "EventName": "AES_BLOCKED_CYCLES", "BriefDescription": "AES Blocked Cycles", "PublicDescription": "Total number of CPU cycles blocked for the AES functions issued by the CPU because the DEA/AES coprocessor is busy performing a function issued by another CPU" - }, + } ] diff --git a/tools/perf/pmu-events/arch/s390/cf_zec12/extended.json b/tools/perf/pmu-events/arch/s390/cf_zec12/extended.json index 162251037219..f40cbed89418 100644 --- a/tools/perf/pmu-events/arch/s390/cf_zec12/extended.json +++ b/tools/perf/pmu-events/arch/s390/cf_zec12/extended.json @@ -243,5 +243,5 @@ "EventName": "TX_C_TABORT_SPECIAL", "BriefDescription": "Aborted transactions in constrained TX mode using special completion logic", "PublicDescription": "A transaction abort has occurred in a constrained transactional-execution mode and the CPU is using special logic to allow the transaction to complete" - }, + } ] diff --git a/tools/perf/pmu-events/arch/test/test_soc/cpu/uncore.json b/tools/perf/pmu-events/arch/test/test_soc/cpu/uncore.json index 788766f45dbc..73089c682f80 100644 --- a/tools/perf/pmu-events/arch/test/test_soc/cpu/uncore.json +++ b/tools/perf/pmu-events/arch/test/test_soc/cpu/uncore.json @@ -38,5 +38,5 @@ "BriefDescription": "Total cache hits", "PublicDescription": "Total cache hits", "Unit": "imc" - }, + } ] diff --git a/tools/perf/pmu-events/arch/x86/icelakex/icx-metrics.json b/tools/perf/pmu-events/arch/x86/icelakex/icx-metrics.json index 57ddbb9f9b31..14b9a8ab15b9 100644 --- a/tools/perf/pmu-events/arch/x86/icelakex/icx-metrics.json +++ b/tools/perf/pmu-events/arch/x86/icelakex/icx-metrics.json @@ -311,5 +311,5 @@ "MetricExpr": "(cstate_pkg@c6\\-residency@ / msr@tsc@) * 100", "MetricGroup": "Power", "MetricName": "C6_Pkg_Residency" - }, + } ] -- cgit From 21813684e46df1c979f714b20b369b3474f5e933 Mon Sep 17 00:00:00 2001 From: James Clark Date: Thu, 7 Oct 2021 12:05:41 +0100 Subject: perf tools: Make the JSON parser more conformant when in strict mode Return an error when a trailing comma is found or a new item is encountered before a comma or an opening brace. This ensures that the perf JSON files conform more closely to the spec at https://www.json.org Reviewed-by: Andi Kleen Reviewed-by: Kajol Jain Signed-off-by: James Clark Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andrew.Kilroy@arm.com Cc: John Garry Cc: Leo Yan Cc: Mark Rutland Cc: Mathieu Poirier Cc: Namhyung Kim Cc: Nick.Forrington@arm.com Cc: Will Deacon Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20211007110543.564963-3-james.clark@arm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/pmu-events/jsmn.c | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/tools/perf/pmu-events/jsmn.c b/tools/perf/pmu-events/jsmn.c index 11d1fa18bfa5..8124d2d3ff0c 100644 --- a/tools/perf/pmu-events/jsmn.c +++ b/tools/perf/pmu-events/jsmn.c @@ -176,6 +176,14 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmnerr_t r; int i; jsmntok_t *token; +#ifdef JSMN_STRICT + /* + * Keeps track of whether a new object/list/primitive is expected. New items are only + * allowed after an opening brace, comma or colon. A closing brace after a comma is not + * valid JSON. + */ + int expecting_item = 1; +#endif for (; parser->pos < len; parser->pos++) { char c; @@ -185,6 +193,10 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len, switch (c) { case '{': case '[': +#ifdef JSMN_STRICT + if (!expecting_item) + return JSMN_ERROR_INVAL; +#endif token = jsmn_alloc_token(parser, tokens, num_tokens); if (token == NULL) return JSMN_ERROR_NOMEM; @@ -196,6 +208,10 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len, break; case '}': case ']': +#ifdef JSMN_STRICT + if (expecting_item) + return JSMN_ERROR_INVAL; +#endif type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); for (i = parser->toknext - 1; i >= 0; i--) { token = &tokens[i]; @@ -219,6 +235,11 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len, } break; case '\"': +#ifdef JSMN_STRICT + if (!expecting_item) + return JSMN_ERROR_INVAL; + expecting_item = 0; +#endif r = jsmn_parse_string(parser, js, len, tokens, num_tokens); if (r < 0) @@ -229,11 +250,15 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len, case '\t': case '\r': case '\n': - case ':': - case ',': case ' ': break; #ifdef JSMN_STRICT + case ':': + case ',': + if (expecting_item) + return JSMN_ERROR_INVAL; + expecting_item = 1; + break; /* * In strict mode primitives are: * numbers and booleans. @@ -253,6 +278,9 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len, case 'f': case 'n': #else + case ':': + case ',': + break; /* * In non-strict mode every unquoted value * is a primitive. @@ -260,6 +288,12 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len, /*FALL THROUGH */ default: #endif + +#ifdef JSMN_STRICT + if (!expecting_item) + return JSMN_ERROR_INVAL; + expecting_item = 0; +#endif r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); if (r < 0) @@ -282,7 +316,11 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len, return JSMN_ERROR_PART; } +#ifdef JSMN_STRICT + return expecting_item ? JSMN_ERROR_INVAL : JSMN_SUCCESS; +#else return JSMN_SUCCESS; +#endif } /* -- cgit From eda1a84cb4e9375984563c23a950377f915e7e1b Mon Sep 17 00:00:00 2001 From: James Clark Date: Thu, 7 Oct 2021 12:05:42 +0100 Subject: perf tools: Enable strict JSON parsing This is to ensure that the PMU event files can always be parsed by other tools. Testing ======= * There are no errors when parsing files for all architectures: # pmu-events/jevents nds32 pmu-events/arch/ test # pmu-events/jevents s390 pmu-events/arch/ test # pmu-events/jevents powerpc pmu-events/arch/ test # pmu-events/jevents arm64 pmu-events/arch/ test # pmu-events/jevents test pmu-events/arch/ test # pmu-events/jevents x86 pmu-events/arch/ test * Trailing and leading commas now cause a parse error * Double commas now cause a parse error * Compilation and parsing works with strict mode disabled and enabled * A diff of the output files shows no changes Reviewed-by: Andi Kleen Reviewed-by: Kajol Jain Signed-off-by: James Clark Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andrew.Kilroy@arm.com Cc: John Garry Cc: Leo Yan Cc: Mark Rutland Cc: Mathieu Poirier Cc: Namhyung Kim Cc: Nick.Forrington@arm.com Cc: Will Deacon Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20211007110543.564963-4-james.clark@arm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/pmu-events/jsmn.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/pmu-events/jsmn.c b/tools/perf/pmu-events/jsmn.c index 8124d2d3ff0c..831dc44c4558 100644 --- a/tools/perf/pmu-events/jsmn.c +++ b/tools/perf/pmu-events/jsmn.c @@ -24,6 +24,7 @@ #include #include "jsmn.h" +#define JSMN_STRICT /* * Allocates a fresh unused token from the token pool. -- cgit From f792cf8a094eac29e1d4e3d588dffbe68c7741a6 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 22 Sep 2021 14:20:31 -0700 Subject: perf kmem: Improve man page for record options Since: https://lore.kernel.org/lkml/20200708183919.4141023-1-irogers@google.com/ The output option works for 'perf kmem', however, it must appear after 'record'. This is different to 'stat' where '-i' for the input must appear before. Try to capture this complication in the man page. Signed-off-by: Ian Rogers Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lore.kernel.org/lkml/20210922212031.485950-1-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-kmem.txt | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tools/perf/Documentation/perf-kmem.txt b/tools/perf/Documentation/perf-kmem.txt index 85b8ac695c87..f378ac59353d 100644 --- a/tools/perf/Documentation/perf-kmem.txt +++ b/tools/perf/Documentation/perf-kmem.txt @@ -8,22 +8,25 @@ perf-kmem - Tool to trace/measure kernel memory properties SYNOPSIS -------- [verse] -'perf kmem' {record|stat} [] +'perf kmem' [] {record|stat} DESCRIPTION ----------- There are two variants of perf kmem: - 'perf kmem record ' to record the kmem events - of an arbitrary workload. + 'perf kmem [] record [] ' to + record the kmem events of an arbitrary workload. Additional 'perf + record' options may be specified after record, such as '-o' to + change the output file name. - 'perf kmem stat' to report kernel memory statistics. + 'perf kmem [] stat' to report kernel memory statistics. OPTIONS ------- -i :: --input=:: - Select the input file (default: perf.data unless stdin is a fifo) + For stat, select the input file (default: perf.data unless stdin is a + fifo) -f:: --force:: -- cgit From b2105b9f39b57ac80fb909b7ae4da3d343af9f7d Mon Sep 17 00:00:00 2001 From: Krzysztof Wilczyński Date: Wed, 6 Oct 2021 23:38:27 +0000 Subject: PCI: Correct misspelled and remove duplicated words MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Correct a number of misspelled words and remove any words that were duplicated in the PCI tree. No change to functionality intended. Link: https://lore.kernel.org/r/20211006233827.147328-1-kw@linux.com Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas --- drivers/pci/controller/pci-xgene-msi.c | 2 +- drivers/pci/controller/pcie-brcmstb.c | 2 +- drivers/pci/controller/pcie-iproc.c | 2 +- drivers/pci/endpoint/pci-epc-core.c | 2 +- drivers/pci/endpoint/pci-epf-core.c | 4 ++-- drivers/pci/hotplug/acpiphp_glue.c | 2 +- drivers/pci/hotplug/cpqphp_ctrl.c | 4 ++-- drivers/pci/hotplug/ibmphp.h | 4 ++-- drivers/pci/hotplug/shpchp_hpc.c | 2 +- drivers/pci/pci-driver.c | 2 +- drivers/pci/pcie/aer.c | 2 +- drivers/pci/quirks.c | 2 +- 12 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/pci/controller/pci-xgene-msi.c b/drivers/pci/controller/pci-xgene-msi.c index b7a8e062fcc5..c50ff279903c 100644 --- a/drivers/pci/controller/pci-xgene-msi.c +++ b/drivers/pci/controller/pci-xgene-msi.c @@ -302,7 +302,7 @@ static void xgene_msi_isr(struct irq_desc *desc) /* * MSIINTn (n is 0..F) indicates if there is a pending MSI interrupt - * If bit x of this register is set (x is 0..7), one or more interupts + * If bit x of this register is set (x is 0..7), one or more interrupts * corresponding to MSInIRx is set. */ grp_select = xgene_msi_int_read(xgene_msi, msi_grp); diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c index cc30215f5a43..1fc7bd49a7ad 100644 --- a/drivers/pci/controller/pcie-brcmstb.c +++ b/drivers/pci/controller/pcie-brcmstb.c @@ -145,7 +145,7 @@ #define BRCM_INT_PCI_MSI_LEGACY_NR 8 #define BRCM_INT_PCI_MSI_SHIFT 0 -/* MSI target adresses */ +/* MSI target addresses */ #define BRCM_MSI_TARGET_ADDR_LT_4GB 0x0fffffffcULL #define BRCM_MSI_TARGET_ADDR_GT_4GB 0xffffffffcULL diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c index 30ac5fbefbbf..36b9d2c46cfa 100644 --- a/drivers/pci/controller/pcie-iproc.c +++ b/drivers/pci/controller/pcie-iproc.c @@ -249,7 +249,7 @@ enum iproc_pcie_reg { /* * To hold the address of the register where the MSI writes are - * programed. When ARM GICv3 ITS is used, this should be programmed + * programmed. When ARM GICv3 ITS is used, this should be programmed * with the address of the GITS_TRANSLATER register. */ IPROC_PCIE_MSI_ADDR_LO, diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c index ecbb0fb3b653..38621558d397 100644 --- a/drivers/pci/endpoint/pci-epc-core.c +++ b/drivers/pci/endpoint/pci-epc-core.c @@ -700,7 +700,7 @@ EXPORT_SYMBOL_GPL(pci_epc_linkup); /** * pci_epc_init_notify() - Notify the EPF device that EPC device's core * initialization is completed. - * @epc: the EPC device whose core initialization is completeds + * @epc: the EPC device whose core initialization is completed * * Invoke to Notify the EPF device that the EPC device's initialization * is completed. diff --git a/drivers/pci/endpoint/pci-epf-core.c b/drivers/pci/endpoint/pci-epf-core.c index 8aea16380870..9ed556936f48 100644 --- a/drivers/pci/endpoint/pci-epf-core.c +++ b/drivers/pci/endpoint/pci-epf-core.c @@ -224,7 +224,7 @@ EXPORT_SYMBOL_GPL(pci_epf_add_vepf); * be removed * @epf_vf: the virtual EP function to be removed * - * Invoke to remove a virtual endpoint function from the physcial endpoint + * Invoke to remove a virtual endpoint function from the physical endpoint * function. */ void pci_epf_remove_vepf(struct pci_epf *epf_pf, struct pci_epf *epf_vf) @@ -432,7 +432,7 @@ EXPORT_SYMBOL_GPL(pci_epf_destroy); /** * pci_epf_create() - create a new PCI EPF device * @name: the name of the PCI EPF device. This name will be used to bind the - * the EPF device to a EPF driver + * EPF device to a EPF driver * * Invoke to create a new PCI EPF device by providing the name of the function * device. diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index f031302ad401..12f4b351be67 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -22,7 +22,7 @@ * when the bridge is scanned and it loses a refcount when the bridge * is removed. * - When a P2P bridge is present, we elevate the refcount on the subordinate - * bus. It loses the refcount when the the driver unloads. + * bus. It loses the refcount when the driver unloads. */ #define pr_fmt(fmt) "acpiphp_glue: " fmt diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c index 1b26ca0b3701..ed7b58eb64d2 100644 --- a/drivers/pci/hotplug/cpqphp_ctrl.c +++ b/drivers/pci/hotplug/cpqphp_ctrl.c @@ -519,7 +519,7 @@ error: * @head: list to search * @size: size of node to find, must be a power of two. * - * Description: This function sorts the resource list by size and then returns + * Description: This function sorts the resource list by size and then * returns the first node of "size" length that is not in the ISA aliasing * window. If it finds a node larger than "size" it will split it up. */ @@ -1202,7 +1202,7 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_ mdelay(5); - /* Reenable interrupts */ + /* Re-enable interrupts */ writel(0, ctrl->hpc_reg + INT_MASK); pci_write_config_byte(ctrl->pci_dev, 0x41, reg); diff --git a/drivers/pci/hotplug/ibmphp.h b/drivers/pci/hotplug/ibmphp.h index e90a4ebf6550..0399c60d2ec1 100644 --- a/drivers/pci/hotplug/ibmphp.h +++ b/drivers/pci/hotplug/ibmphp.h @@ -352,7 +352,7 @@ struct resource_node { u32 len; int type; /* MEM, IO, PFMEM */ u8 fromMem; /* this is to indicate that the range is from - * from the Memory bucket rather than from PFMem */ + * the Memory bucket rather than from PFMem */ struct resource_node *next; struct resource_node *nextRange; /* for the other mem range on bus */ }; @@ -736,7 +736,7 @@ struct controller { int ibmphp_init_devno(struct slot **); /* This function is called from EBDA, so we need it not be static */ int ibmphp_do_disable_slot(struct slot *slot_cur); -int ibmphp_update_slot_info(struct slot *); /* This function is called from HPC, so we need it to not be be static */ +int ibmphp_update_slot_info(struct slot *); /* This function is called from HPC, so we need it to not be static */ int ibmphp_configure_card(struct pci_func *, u8); int ibmphp_unconfigure_card(struct slot **, int); extern const struct hotplug_slot_ops ibmphp_hotplug_slot_ops; diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 9e3b27744305..bd7557ca4910 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -295,7 +295,7 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) mutex_lock(&slot->ctrl->cmd_lock); if (!shpc_poll_ctrl_busy(ctrl)) { - /* After 1 sec and and the controller is still busy */ + /* After 1 sec and the controller is still busy */ ctrl_err(ctrl, "Controller is still busy after 1 sec\n"); retval = -EBUSY; goto out; diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 2761ab86490d..df3bd7b40542 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -576,7 +576,7 @@ static int pci_pm_reenable_device(struct pci_dev *pci_dev) { int retval; - /* if the device was enabled before suspend, reenable */ + /* if the device was enabled before suspend, re-enable */ retval = pci_reenable_device(pci_dev); /* * if the device was busmaster before the suspend, make it busmaster diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 9784fdcf3006..9fa1f97e5b27 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -57,7 +57,7 @@ struct aer_stats { * "as seen by this device". Note that this may mean that if an * end point is causing problems, the AER counters may increment * at its link partner (e.g. root port) because the errors will be - * "seen" by the link partner and not the the problematic end point + * "seen" by the link partner and not the problematic end point * itself (which may report all counters as 0 as it never saw any * problems). */ diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 4537d1ea14fd..881c5d7c3d02 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2700,7 +2700,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, * then the device can't use INTx interrupts. Tegra's PCIe root ports don't * generate MSI interrupts for PME and AER events instead only INTx interrupts * are generated. Though Tegra's PCIe root ports can generate MSI interrupts - * for other events, since PCIe specificiation doesn't support using a mix of + * for other events, since PCIe specification doesn't support using a mix of * INTx and MSI/MSI-X, it is required to disable MSI interrupts to avoid port * service drivers registering their respective ISRs for MSIs. */ -- cgit From bc774a3887cb513be08e846726bc4402897b267a Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Mon, 12 Jul 2021 14:37:49 +0200 Subject: rpmsg: char: Remove useless include No facility requests the include of rpmsg_internal.h header file. Signed-off-by: Arnaud Pouliquen Reviewed-by: Mathieu Poirier Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210712123752.10449-2-arnaud.pouliquen@foss.st.com --- drivers/rpmsg/rpmsg_char.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index 2bebc9b2d163..b5907b80727c 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -22,8 +22,6 @@ #include #include -#include "rpmsg_internal.h" - #define RPMSG_DEV_MAX (MINORMASK + 1) static dev_t rpmsg_major; -- cgit From f0d1be1482aaab1aaadf68aa959f6d4c098a8e8f Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 11 Aug 2021 20:31:25 +0800 Subject: rpmsg: virtio: Remove unused including Remove including that don't need it. Signed-off-by: Cai Huoqing Reviewed-by: Mathieu Poirier Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210811123125.143-1-caihuoqing@baidu.com --- drivers/rpmsg/virtio_rpmsg_bus.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c index 8e49a3bacfc7..a0634ef0420b 100644 --- a/drivers/rpmsg/virtio_rpmsg_bus.c +++ b/drivers/rpmsg/virtio_rpmsg_bus.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include -- cgit From 63b8d79916672d35069962d87d1540c534cb2438 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Tue, 28 Sep 2021 16:29:02 +0300 Subject: rpmsg: virtio_rpmsg_bus: use dev_warn_ratelimited for msg with no recipient Even though it may be user-space's fault for this error (some application terminated or crashed without cleaning up it's endpoint), the rpmsg communication should not overflow the syslog with too many messages. A dev_warn_ratelimited() seems like a good alternative in case this can occur. Signed-off-by: Alexandru Ardelean Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210928132902.1594277-1-aardelean@deviqon.com --- drivers/rpmsg/virtio_rpmsg_bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c index a0634ef0420b..5da622eb1c8f 100644 --- a/drivers/rpmsg/virtio_rpmsg_bus.c +++ b/drivers/rpmsg/virtio_rpmsg_bus.c @@ -748,7 +748,7 @@ static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev, /* farewell, ept, we don't need you anymore */ kref_put(&ept->refcount, __ept_release); } else - dev_warn(dev, "msg received with no recipient\n"); + dev_warn_ratelimited(dev, "msg received with no recipient\n"); /* publish the real size of the buffer */ rpmsg_sg_init(&sg, msg, vrp->buf_size); -- cgit From 97f921ff264e0edbfae65a8a14e864aefd76bc1f Mon Sep 17 00:00:00 2001 From: Nikola Pavlica Date: Sat, 2 Oct 2021 22:29:04 +0200 Subject: dt-bindings: add vendor prefix for Vivax Add vendor prefix for the Vivax brand by M SAN Grupa d.o.o. Source (in Croatian): https://www.vivax.com/hr/o-nama.aspx Signed-off-by: Nikola Pavlica Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20211002202905.509437-1-pavlica.nikola@gmail.com --- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index a867f7102c35..1a7d9ca02c44 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -1264,6 +1264,8 @@ patternProperties: description: Vitesse Semiconductor Corporation "^vivante,.*": description: Vivante Corporation + "^vivax,.*": + description: Vivax brand by M SAN Grupa d.o.o. "^vocore,.*": description: VoCore Studio "^voipac,.*": -- cgit From f474bb3000b6114b8beea3170d9cbed963593467 Mon Sep 17 00:00:00 2001 From: Nikola Pavlica Date: Sat, 2 Oct 2021 22:29:05 +0200 Subject: dt-bindings: display: simple: Add Vivax TPC-9150 panel This tablet display is unique and hence must be added to documentation. Unfortunately, it's real make and number is not known due to obscure and missing documentation and lack of writing on the display assembly itself. So the natural alternative that came to mind is to name the panel after the device that contained it (an Android tablet). Hopefully that isn't an issue. I can confirm that the parameters that I've obtained are correct since they came from a dump of the original Android OS. Signed-off-by: Nikola Pavlica Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20211002202905.509437-2-pavlica.nikola@gmail.com --- Documentation/devicetree/bindings/display/panel/panel-simple.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index 335776c45474..1bea31fd9e2e 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -309,6 +309,8 @@ properties: - urt,umsh-8596md-11t - urt,umsh-8596md-19t - urt,umsh-8596md-20t + # Vivax TPC-9150 tablet 9.0" WSVGA TFT LCD panel + - vivax,tpc9150-panel # VXT 800x480 color TFT LCD panel - vxt,vl050-8048nt-c01 # Winstar Display Corporation 3.5" QVGA (320x240) TFT LCD panel -- cgit From 76f7456838589dc51e22834c8469412689708e77 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Thu, 30 Sep 2021 12:04:59 +0200 Subject: dt-bindings: display: simple: add Innolux G070Y2-T02 panel Add binding for the Innolux G070Y2-T02 panel. It is 7" WVGA (800x480) TFT LCD panel with TTL interface and a backlight unit. Signed-off-by: Oleksij Rempel Acked-by: Rob Herring Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210930100501.15690-1-o.rempel@pengutronix.de --- Documentation/devicetree/bindings/display/panel/panel-simple.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index 1bea31fd9e2e..f81e79bf56b4 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -166,6 +166,8 @@ properties: - innolux,at070tn92 # Innolux G070Y2-L01 7" WVGA (800x480) TFT LCD panel - innolux,g070y2-l01 + # Innolux G070Y2-T02 7" WVGA (800x480) TFT LCD TTL panel + - innolux,g070y2-t02 # Innolux Corporation 10.1" G101ICE-L01 WXGA (1280x800) LVDS panel - innolux,g101ice-l01 # Innolux Corporation 12.1" WXGA (1280x800) TFT LCD panel -- cgit From 19f036eaaffa581449c907aa78b98b1f147af336 Mon Sep 17 00:00:00 2001 From: Søren Andersen Date: Thu, 30 Sep 2021 12:05:01 +0200 Subject: drm/panel: panel-simple: add LOGIC Technologies LTTD800480070-L2RT panel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the Logic Technologies LTTD800x480 L2RT 7" 800x480 TFT Resistive Touch Module. Signed-off-by: Søren Andersen Signed-off-by: Oleksij Rempel Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210930100501.15690-3-o.rempel@pengutronix.de --- drivers/gpu/drm/panel/panel-simple.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 7f3e1b84b5f5..eb475a3a774b 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -2370,6 +2370,38 @@ static const struct panel_desc logictechno_lt170410_2whc = { .connector_type = DRM_MODE_CONNECTOR_LVDS, }; +static const struct drm_display_mode logictechno_lttd800480070_l2rt_mode = { + .clock = 33000, + .hdisplay = 800, + .hsync_start = 800 + 112, + .hsync_end = 800 + 112 + 3, + .htotal = 800 + 112 + 3 + 85, + .vdisplay = 480, + .vsync_start = 480 + 38, + .vsync_end = 480 + 38 + 3, + .vtotal = 480 + 38 + 3 + 29, + .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, +}; + +static const struct panel_desc logictechno_lttd800480070_l2rt = { + .modes = &logictechno_lttd800480070_l2rt_mode, + .num_modes = 1, + .bpc = 8, + .size = { + .width = 154, + .height = 86, + }, + .delay = { + .prepare = 45, + .enable = 100, + .disable = 100, + .unprepare = 45 + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X24, + .bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE, + .connector_type = DRM_MODE_CONNECTOR_DPI, +}; + static const struct drm_display_mode logictechno_lttd800480070_l6wh_rt_mode = { .clock = 33000, .hdisplay = 800, @@ -3750,6 +3782,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "logictechno,lt170410-2whc", .data = &logictechno_lt170410_2whc, + }, { + .compatible = "logictechno,lttd800480070-l2rt", + .data = &logictechno_lttd800480070_l2rt, }, { .compatible = "logictechno,lttd800480070-l6wh-rt", .data = &logictechno_lttd800480070_l6wh_rt, -- cgit From c38171a5857402dfc26985fb59029926bda802fb Mon Sep 17 00:00:00 2001 From: David Heidelberg Date: Mon, 27 Sep 2021 23:45:03 +0200 Subject: dt-bindings: display: simple: hardware can use ddc-i2c-bus Both hardware and driver can communicate DDC over i2c bus. Fixes warnings as: arch/arm/boot/dts/tegra20-paz00.dt.yaml: panel: 'ddc-i2c-bus' does not match any of the regexes: 'pinctrl-[0-9]+' From schema: /home/runner/work/linux/linux/Documentation/devicetree/bindings/display/panel/panel-simple.yaml Signed-off-by: David Heidelberg Acked-by: Rob Herring Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210927214503.36012-1-david@ixit.cz --- Documentation/devicetree/bindings/display/panel/panel-simple.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index f81e79bf56b4..f3c9395d23b6 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -321,6 +321,7 @@ properties: - yes-optoelectronics,ytc700tlag-05-201c backlight: true + ddc-i2c-bus: true enable-gpios: true port: true power-supply: true -- cgit From 230a6f0e6f49d815f1e8d042929b53a16908f674 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sun, 26 Sep 2021 03:10:04 +0300 Subject: dt-bindings: add bindings for the Sharp LS060T1SX01 panel Add devicetree bindings for the Sharp LS060T1SX01 6.0" FullHD panel using NT35695 driver. This panel can be found i.e. in the Dragonboard Display Adapter bundle. Signed-off-by: Dmitry Baryshkov Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210926001005.3442668-2-dmitry.baryshkov@linaro.org --- .../bindings/display/panel/sharp,ls060t1sx01.yaml | 56 ++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/sharp,ls060t1sx01.yaml diff --git a/Documentation/devicetree/bindings/display/panel/sharp,ls060t1sx01.yaml b/Documentation/devicetree/bindings/display/panel/sharp,ls060t1sx01.yaml new file mode 100644 index 000000000000..271c097cc9a4 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/sharp,ls060t1sx01.yaml @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/sharp,ls060t1sx01.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sharp Microelectronics 6.0" FullHD TFT LCD panel + +maintainers: + - Dmitry Baryskov + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + const: sharp,ls060t1sx01 + + reg: true + backlight: true + reset-gpios: true + port: true + + avdd-supply: + description: handle of the regulator that provides the positive supply voltage + avee-supply: + description: handle of the regulator that provides the negative supply voltage + vddi-supply: + description: handle of the regulator that provides the I/O supply voltage + vddh-supply: + description: handle of the regulator that provides the analog supply voltage + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include + + dsi { + #address-cells = <1>; + #size-cells = <0>; + + panel@0 { + compatible = "sharp,ls060t1sx01"; + reg = <0>; + avdd-supply = <&pm8941_l22>; + backlight = <&backlight>; + reset-gpios = <&pm8916_gpios 25 GPIO_ACTIVE_LOW>; + }; + }; + +... -- cgit From 223cce88a926efbbd99d21fe2e540b1a9050410e Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sun, 26 Sep 2021 03:10:05 +0300 Subject: drm/panel: Add support for Sharp LS060T1SX01 panel Add driver to support Sharp LS06T1SX01 FullHD panel. The panel uses nt35695 driver IC. For example this LCD module can be found in the kwaek.ca Dragonboard Display Adapter Bundle. Signed-off-by: Dmitry Baryshkov Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210926001005.3442668-3-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/panel/Kconfig | 10 + drivers/gpu/drm/panel/Makefile | 1 + drivers/gpu/drm/panel/panel-sharp-ls060t1sx01.c | 332 ++++++++++++++++++++++++ 3 files changed, 343 insertions(+) create mode 100644 drivers/gpu/drm/panel/panel-sharp-ls060t1sx01.c diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 369cb76512fe..eb01549a6ccb 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -519,6 +519,16 @@ config DRM_PANEL_SHARP_LS043T1LE01 Say Y here if you want to enable support for Sharp LS043T1LE01 qHD (540x960) DSI panel as found on the Qualcomm APQ8074 Dragonboard +config DRM_PANEL_SHARP_LS060T1SX01 + tristate "Sharp LS060T1SX01 FullHD video mode panel" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for Sharp LS060T1SX01 6.0" + FullHD (1080x1920) DSI panel as found in Dragonboard Display Adapter + Bundle. + config DRM_PANEL_SITRONIX_ST7701 tristate "Sitronix ST7701 panel driver" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 6e30640b9099..bca4cc1f2715 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o obj-$(CONFIG_DRM_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o +obj-$(CONFIG_DRM_PANEL_SHARP_LS060T1SX01) += panel-sharp-ls060t1sx01.o obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7701) += panel-sitronix-st7701.o obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7703) += panel-sitronix-st7703.o obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o diff --git a/drivers/gpu/drm/panel/panel-sharp-ls060t1sx01.c b/drivers/gpu/drm/panel/panel-sharp-ls060t1sx01.c new file mode 100644 index 000000000000..1049810d1f10 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-sharp-ls060t1sx01.c @@ -0,0 +1,332 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2021 Linaro Ltd. +// Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree: +// Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + +#include +#include +#include +#include +#include + +#include