From dea450c90f463de57d7f351711a6ac7e89090843 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 2 Nov 2021 15:17:07 -0400 Subject: [PATCH 0001/1112] fs: dlm: remove obsolete INBUF define This patch removes an obsolete define for some length for an temporary buffer which is not being used anymore. The use of this define is not necessary anymore since commit 4798cbbfbd00 ("fs: dlm: rework receive handling"). Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/dlm_internal.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h index 5f57538b5d450..44a5c67b52134 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h @@ -41,12 +41,6 @@ #include #include "config.h" -/* Size of the temp buffer midcomms allocates on the stack. - We try to make this large enough so most messages fit. - FIXME: should sctp make this unnecessary? */ - -#define DLM_INBUF_LEN 148 - struct dlm_ls; struct dlm_lkb; struct dlm_rsb; -- GitLab From bb6866a5bdc5ff0236147c01394f6a264978a16c Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 2 Nov 2021 15:17:08 -0400 Subject: [PATCH 0002/1112] fs: dlm: fix small lockspace typo This patch fixes a typo from lockspace to lockspace. Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/lockspace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index 10eddfa6c3d7b..b90566502a813 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -868,7 +868,7 @@ static int release_lockspace(struct dlm_ls *ls, int force) * until this returns. * * Force has 4 possible values: - * 0 - don't destroy locksapce if it has any LKBs + * 0 - don't destroy lockspace if it has any LKBs * 1 - destroy lockspace if it has remote LKBs but not if it has local LKBs * 2 - destroy lockspace regardless of LKBs * 3 - destroy lockspace as part of a forced shutdown -- GitLab From 1aafd9c231919dea9b10e654107e24d5c553c60d Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 2 Nov 2021 15:17:09 -0400 Subject: [PATCH 0003/1112] fs: dlm: debug improvements print nodeid This patch improves the debug output for midcomms layer by also printing out the nodeid where users counter belongs to. Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/midcomms.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/dlm/midcomms.c b/fs/dlm/midcomms.c index 7ae39ec8d9b0a..008078f06813d 100644 --- a/fs/dlm/midcomms.c +++ b/fs/dlm/midcomms.c @@ -1231,7 +1231,7 @@ void dlm_midcomms_add_member(int nodeid) } node->users++; - pr_debug("users inc count %d\n", node->users); + pr_debug("node %d users inc count %d\n", nodeid, node->users); spin_unlock(&node->state_lock); srcu_read_unlock(&nodes_srcu, idx); @@ -1254,7 +1254,7 @@ void dlm_midcomms_remove_member(int nodeid) spin_lock(&node->state_lock); node->users--; - pr_debug("users dec count %d\n", node->users); + pr_debug("node %d users dec count %d\n", nodeid, node->users); /* hitting users count to zero means the * other side is running dlm_midcomms_stop() -- GitLab From fe93367541bcedaba1dd5cb9cf138eec0267ea56 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 2 Nov 2021 15:17:10 -0400 Subject: [PATCH 0004/1112] fs: dlm: remove check SCTP is loaded message Since commit 764ff4011424 ("fs: dlm: auto load sctp module") we try load the sctp module before we try to create a sctp kernel socket. That a socket creation fails now has more likely other reasons. This patch removes the part of error to load the sctp module and instead printout the error code. Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/lowcomms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 8f715c620e1f8..bee3757eb4c73 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -1775,7 +1775,7 @@ static int dlm_listen_for_all(void) result = sock_create_kern(&init_net, dlm_local_addr[0]->ss_family, SOCK_STREAM, dlm_proto_ops->proto, &sock); if (result < 0) { - log_print("Can't create comms socket, check SCTP is loaded"); + log_print("Can't create comms socket: %d", result); goto out; } -- GitLab From 658bd576f95ed597e519cdadf1c86ac87c17aea5 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 2 Nov 2021 15:17:11 -0400 Subject: [PATCH 0005/1112] fs: dlm: move version conversion to compile time This patch moves version conversion to little endian from a runtime variable to compile time constant. Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/midcomms.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/dlm/midcomms.c b/fs/dlm/midcomms.c index 008078f06813d..76bdc3a9dc61d 100644 --- a/fs/dlm/midcomms.c +++ b/fs/dlm/midcomms.c @@ -909,11 +909,11 @@ int dlm_process_incoming_buffer(int nodeid, unsigned char *buf, int len) if (msglen > len) break; - switch (le32_to_cpu(hd->h_version)) { - case DLM_VERSION_3_1: + switch (hd->h_version) { + case cpu_to_le32(DLM_VERSION_3_1): dlm_midcomms_receive_buffer_3_1((union dlm_packet *)ptr, nodeid); break; - case DLM_VERSION_3_2: + case cpu_to_le32(DLM_VERSION_3_2): dlm_midcomms_receive_buffer_3_2((union dlm_packet *)ptr, nodeid); break; default: -- GitLab From 3e9736713d0cb2877b11ec7185b231bba7b21936 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 2 Nov 2021 15:17:12 -0400 Subject: [PATCH 0006/1112] fs: dlm: use dlm_recovery_stopped instead of test_bit This patch will change to use dlm_recovery_stopped() which is the dlm way to check if the LSFL_RECOVER_STOP flag in ls_flags by using the helper. It is an atomic operation but the check is still as before to fetch the value if ls_recover_lock is held. There might be more further investigations if the value can be changed afterwards and if it has any side effects. Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/rcom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c index 6cba86470278a..5821b777a1a74 100644 --- a/fs/dlm/rcom.c +++ b/fs/dlm/rcom.c @@ -601,7 +601,7 @@ void dlm_receive_rcom(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid) spin_lock(&ls->ls_recover_lock); status = ls->ls_recover_status; - stop = test_bit(LSFL_RECOVER_STOP, &ls->ls_flags); + stop = dlm_recovery_stopped(ls); seq = ls->ls_recover_seq; spin_unlock(&ls->ls_recover_lock); -- GitLab From e10249b1902d3b0b71e99f518a695c2c39ab4fe6 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 2 Nov 2021 15:17:13 -0400 Subject: [PATCH 0007/1112] fs: dlm: use dlm_recovery_stopped in condition This patch will change to evaluate the dlm_recovery_stopped() in the condition of the if branch instead fetch it before evaluating the condition. As this is an atomic test-set operation it should be evaluated in the condition itself. Reported-by: Andreas Gruenbacher Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/dir.c | 3 +-- fs/dlm/member.c | 3 +-- fs/dlm/recoverd.c | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/fs/dlm/dir.c b/fs/dlm/dir.c index 45ebbe602bbf0..b6692f81ec83e 100644 --- a/fs/dlm/dir.c +++ b/fs/dlm/dir.c @@ -84,8 +84,7 @@ int dlm_recover_directory(struct dlm_ls *ls) for (;;) { int left; - error = dlm_recovery_stopped(ls); - if (error) { + if (dlm_recovery_stopped(ls)) { error = -EINTR; goto out_free; } diff --git a/fs/dlm/member.c b/fs/dlm/member.c index 731d489aa323e..61f906e705db8 100644 --- a/fs/dlm/member.c +++ b/fs/dlm/member.c @@ -442,8 +442,7 @@ static int ping_members(struct dlm_ls *ls) int error = 0; list_for_each_entry(memb, &ls->ls_nodes, list) { - error = dlm_recovery_stopped(ls); - if (error) { + if (dlm_recovery_stopped(ls)) { error = -EINTR; break; } diff --git a/fs/dlm/recoverd.c b/fs/dlm/recoverd.c index 97d052cea5a92..a55dfce705dd2 100644 --- a/fs/dlm/recoverd.c +++ b/fs/dlm/recoverd.c @@ -124,8 +124,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv) dlm_recover_waiters_pre(ls); - error = dlm_recovery_stopped(ls); - if (error) { + if (dlm_recovery_stopped(ls)) { error = -EINTR; goto fail; } -- GitLab From 2f05ec4327ffaa34877de67fc5bb5eb3ab3767f0 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 2 Nov 2021 15:17:14 -0400 Subject: [PATCH 0008/1112] fs: dlm: make dlm_callback_resume quite This patch makes dlm_callback_resume info printout less noisy by accumulate all callback queues into one printout not in 25 times steps. It seems this printout became lately quite noisy in relationship with gfs2. Before: [241767.849302] dlm: bin: dlm_callback_resume 25 [241767.854846] dlm: bin: dlm_callback_resume 25 [241767.860373] dlm: bin: dlm_callback_resume 25 ... [241767.865920] dlm: bin: dlm_callback_resume 25 [241767.871352] dlm: bin: dlm_callback_resume 25 [241767.876733] dlm: bin: dlm_callback_resume 25 After the patch: [ 385.485728] dlm: gfs2: dlm_callback_resume 175 if zero it will not be printed out. Reported-by: Barry Marson Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/ast.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/dlm/ast.c b/fs/dlm/ast.c index 283c7b94eddad..6600930497ccc 100644 --- a/fs/dlm/ast.c +++ b/fs/dlm/ast.c @@ -295,7 +295,7 @@ void dlm_callback_suspend(struct dlm_ls *ls) void dlm_callback_resume(struct dlm_ls *ls) { struct dlm_lkb *lkb, *safe; - int count = 0; + int count = 0, sum = 0; clear_bit(LSFL_CB_DELAY, &ls->ls_flags); @@ -313,12 +313,14 @@ more: } mutex_unlock(&ls->ls_cb_mutex); - if (count) - log_rinfo(ls, "dlm_callback_resume %d", count); + sum += count; if (count == MAX_CB_QUEUE) { count = 0; cond_resched(); goto more; } + + if (sum) + log_rinfo(ls, "%s %d", __func__, sum); } -- GitLab From f1d3b8f91d965c4fd900ac5dd06240cc9df0c7a7 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 2 Nov 2021 15:17:15 -0400 Subject: [PATCH 0009/1112] fs: dlm: initial support for tracepoints This patch adds initial support for dlm tracepoints. It will introduce tracepoints to dlm main functionality dlm_lock()/dlm_unlock() and their complete ast() callback or blocking bast() callback. The lock/unlock functionality has a start and end tracepoint, this is because there exists a race in case if would have a tracepoint at the end position only the complete/blocking callbacks could occur before. To work with eBPF tracing and using their lookup hash functionality there could be problems that an entry was not inserted yet. However use the start functionality for hash insert and check again in end functionality if there was an dlm internal error so there is no ast callback. In further it might also that locks with local masters will occur those callbacks immediately so we must have such functionality. I did not make everything accessible yet, although it seems eBPF can be used to access a lot of internal datastructures if it's aware of the struct definitions of the running kernel instance. We still can change it, if you do eBPF experiments e.g. time measurements between lock and callback functionality you can simple use the local lkb_id field as hash value in combination with the lockspace id if you have multiple lockspaces. Otherwise you can simple use trace-cmd for some functionality, e.g. `trace-cmd record -e dlm` and `trace-cmd report` afterwards. Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/ast.c | 4 + fs/dlm/lock.c | 10 ++ fs/dlm/main.c | 3 + include/trace/events/dlm.h | 220 +++++++++++++++++++++++++++++++++++++ 4 files changed, 237 insertions(+) create mode 100644 include/trace/events/dlm.h diff --git a/fs/dlm/ast.c b/fs/dlm/ast.c index 6600930497ccc..27bae7d4a477a 100644 --- a/fs/dlm/ast.c +++ b/fs/dlm/ast.c @@ -9,6 +9,8 @@ ******************************************************************************* ******************************************************************************/ +#include + #include "dlm_internal.h" #include "lock.h" #include "user.h" @@ -254,10 +256,12 @@ void dlm_callback_work(struct work_struct *work) continue; } else if (callbacks[i].flags & DLM_CB_BAST) { bastfn(lkb->lkb_astparam, callbacks[i].mode); + trace_dlm_bast(ls, lkb, callbacks[i].mode); } else if (callbacks[i].flags & DLM_CB_CAST) { lkb->lkb_lksb->sb_status = callbacks[i].sb_status; lkb->lkb_lksb->sb_flags = callbacks[i].sb_flags; castfn(lkb->lkb_astparam); + trace_dlm_ast(ls, lkb, lkb->lkb_lksb); } } diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index c502c065d0075..feb2e94f5879e 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -53,6 +53,8 @@ R: do_xxxx() L: receive_xxxx_reply() <- R: send_xxxx_reply() */ +#include + #include #include #include @@ -3437,6 +3439,8 @@ int dlm_lock(dlm_lockspace_t *lockspace, if (error) goto out; + trace_dlm_lock_start(ls, lkb, mode, flags); + error = set_lock_args(mode, lksb, flags, namelen, 0, ast, astarg, bast, &args); if (error) @@ -3450,6 +3454,8 @@ int dlm_lock(dlm_lockspace_t *lockspace, if (error == -EINPROGRESS) error = 0; out_put: + trace_dlm_lock_end(ls, lkb, mode, flags, error); + if (convert || error) __put_lkb(ls, lkb); if (error == -EAGAIN || error == -EDEADLK) @@ -3481,6 +3487,8 @@ int dlm_unlock(dlm_lockspace_t *lockspace, if (error) goto out; + trace_dlm_unlock_start(ls, lkb, flags); + error = set_unlock_args(flags, astarg, &args); if (error) goto out_put; @@ -3495,6 +3503,8 @@ int dlm_unlock(dlm_lockspace_t *lockspace, if (error == -EBUSY && (flags & (DLM_LKF_CANCEL | DLM_LKF_FORCEUNLOCK))) error = 0; out_put: + trace_dlm_unlock_end(ls, lkb, flags, error); + dlm_put_lkb(lkb); out: dlm_unlock_recovery(ls); diff --git a/fs/dlm/main.c b/fs/dlm/main.c index afc66a1346d3d..1c5be4b70ac1b 100644 --- a/fs/dlm/main.c +++ b/fs/dlm/main.c @@ -19,6 +19,9 @@ #include "config.h" #include "lowcomms.h" +#define CREATE_TRACE_POINTS +#include + static int __init init_dlm(void) { int error; diff --git a/include/trace/events/dlm.h b/include/trace/events/dlm.h new file mode 100644 index 0000000000000..c97b4c163c3e9 --- /dev/null +++ b/include/trace/events/dlm.h @@ -0,0 +1,220 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM dlm + +#if !defined(_TRACE_DLM_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_DLM_H + +#include +#include +#include + +#include "../../../fs/dlm/dlm_internal.h" + +#define show_lock_flags(flags) __print_flags(flags, "|", \ + { DLM_LKF_NOQUEUE, "NOQUEUE" }, \ + { DLM_LKF_CANCEL, "CANCEL" }, \ + { DLM_LKF_CONVERT, "CONVERT" }, \ + { DLM_LKF_VALBLK, "VALBLK" }, \ + { DLM_LKF_QUECVT, "QUECVT" }, \ + { DLM_LKF_IVVALBLK, "IVVALBLK" }, \ + { DLM_LKF_CONVDEADLK, "CONVDEADLK" }, \ + { DLM_LKF_PERSISTENT, "PERSISTENT" }, \ + { DLM_LKF_NODLCKWT, "NODLCKWT" }, \ + { DLM_LKF_NODLCKBLK, "NODLCKBLK" }, \ + { DLM_LKF_EXPEDITE, "EXPEDITE" }, \ + { DLM_LKF_NOQUEUEBAST, "NOQUEUEBAST" }, \ + { DLM_LKF_HEADQUE, "HEADQUE" }, \ + { DLM_LKF_NOORDER, "NOORDER" }, \ + { DLM_LKF_ORPHAN, "ORPHAN" }, \ + { DLM_LKF_ALTPR, "ALTPR" }, \ + { DLM_LKF_ALTCW, "ALTCW" }, \ + { DLM_LKF_FORCEUNLOCK, "FORCEUNLOCK" }, \ + { DLM_LKF_TIMEOUT, "TIMEOUT" }) + +#define show_lock_mode(mode) __print_symbolic(mode, \ + { DLM_LOCK_IV, "IV"}, \ + { DLM_LOCK_NL, "NL"}, \ + { DLM_LOCK_CR, "CR"}, \ + { DLM_LOCK_CW, "CW"}, \ + { DLM_LOCK_PR, "PR"}, \ + { DLM_LOCK_PW, "PW"}, \ + { DLM_LOCK_EX, "EX"}) + +#define show_dlm_sb_flags(flags) __print_flags(flags, "|", \ + { DLM_SBF_DEMOTED, "DEMOTED" }, \ + { DLM_SBF_VALNOTVALID, "VALNOTVALID" }, \ + { DLM_SBF_ALTMODE, "ALTMODE" }) + +/* note: we begin tracing dlm_lock_start() only if ls and lkb are found */ +TRACE_EVENT(dlm_lock_start, + + TP_PROTO(struct dlm_ls *ls, struct dlm_lkb *lkb, int mode, + __u32 flags), + + TP_ARGS(ls, lkb, mode, flags), + + TP_STRUCT__entry( + __field(__u32, ls_id) + __field(__u32, lkb_id) + __field(int, mode) + __field(__u32, flags) + ), + + TP_fast_assign( + __entry->ls_id = ls->ls_global_id; + __entry->lkb_id = lkb->lkb_id; + __entry->mode = mode; + __entry->flags = flags; + ), + + TP_printk("ls_id=%u lkb_id=%x mode=%s flags=%s", + __entry->ls_id, __entry->lkb_id, + show_lock_mode(__entry->mode), + show_lock_flags(__entry->flags)) + +); + +TRACE_EVENT(dlm_lock_end, + + TP_PROTO(struct dlm_ls *ls, struct dlm_lkb *lkb, int mode, __u32 flags, + int error), + + TP_ARGS(ls, lkb, mode, flags, error), + + TP_STRUCT__entry( + __field(__u32, ls_id) + __field(__u32, lkb_id) + __field(int, mode) + __field(__u32, flags) + __field(int, error) + ), + + TP_fast_assign( + __entry->ls_id = ls->ls_global_id; + __entry->lkb_id = lkb->lkb_id; + __entry->mode = mode; + __entry->flags = flags; + + /* return value will be zeroed in those cases by dlm_lock() + * we do it here again to not introduce more overhead if + * trace isn't running and error reflects the return value. + */ + if (error == -EAGAIN || error == -EDEADLK) + __entry->error = 0; + else + __entry->error = error; + ), + + TP_printk("ls_id=%u lkb_id=%x mode=%s flags=%s error=%d", + __entry->ls_id, __entry->lkb_id, + show_lock_mode(__entry->mode), + show_lock_flags(__entry->flags), __entry->error) + +); + +TRACE_EVENT(dlm_bast, + + TP_PROTO(struct dlm_ls *ls, struct dlm_lkb *lkb, int mode), + + TP_ARGS(ls, lkb, mode), + + TP_STRUCT__entry( + __field(__u32, ls_id) + __field(__u32, lkb_id) + __field(int, mode) + ), + + TP_fast_assign( + __entry->ls_id = ls->ls_global_id; + __entry->lkb_id = lkb->lkb_id; + __entry->mode = mode; + ), + + TP_printk("ls_id=%u lkb_id=%x mode=%s", __entry->ls_id, + __entry->lkb_id, show_lock_mode(__entry->mode)) + +); + +TRACE_EVENT(dlm_ast, + + TP_PROTO(struct dlm_ls *ls, struct dlm_lkb *lkb, struct dlm_lksb *lksb), + + TP_ARGS(ls, lkb, lksb), + + TP_STRUCT__entry( + __field(__u32, ls_id) + __field(__u32, lkb_id) + __field(u8, sb_flags) + __field(int, sb_status) + ), + + TP_fast_assign( + __entry->ls_id = ls->ls_global_id; + __entry->lkb_id = lkb->lkb_id; + __entry->sb_flags = lksb->sb_flags; + __entry->sb_status = lksb->sb_status; + ), + + TP_printk("ls_id=%u lkb_id=%x sb_flags=%s sb_status=%d", + __entry->ls_id, __entry->lkb_id, + show_dlm_sb_flags(__entry->sb_flags), __entry->sb_status) + +); + +/* note: we begin tracing dlm_unlock_start() only if ls and lkb are found */ +TRACE_EVENT(dlm_unlock_start, + + TP_PROTO(struct dlm_ls *ls, struct dlm_lkb *lkb, __u32 flags), + + TP_ARGS(ls, lkb, flags), + + TP_STRUCT__entry( + __field(__u32, ls_id) + __field(__u32, lkb_id) + __field(__u32, flags) + ), + + TP_fast_assign( + __entry->ls_id = ls->ls_global_id; + __entry->lkb_id = lkb->lkb_id; + __entry->flags = flags; + ), + + TP_printk("ls_id=%u lkb_id=%x flags=%s", + __entry->ls_id, __entry->lkb_id, + show_lock_flags(__entry->flags)) + +); + +TRACE_EVENT(dlm_unlock_end, + + TP_PROTO(struct dlm_ls *ls, struct dlm_lkb *lkb, __u32 flags, + int error), + + TP_ARGS(ls, lkb, flags, error), + + TP_STRUCT__entry( + __field(__u32, ls_id) + __field(__u32, lkb_id) + __field(__u32, flags) + __field(int, error) + ), + + TP_fast_assign( + __entry->ls_id = ls->ls_global_id; + __entry->lkb_id = lkb->lkb_id; + __entry->flags = flags; + __entry->error = error; + ), + + TP_printk("ls_id=%u lkb_id=%x flags=%s error=%d", + __entry->ls_id, __entry->lkb_id, + show_lock_flags(__entry->flags), __entry->error) + +); + +#endif /* if !defined(_TRACE_DLM_H) || defined(TRACE_HEADER_MULTI_READ) */ + +/* This part must be outside protection */ +#include -- GitLab From 92732376fd29462b502f41486bcef55f49c5713e Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 2 Nov 2021 15:17:16 -0400 Subject: [PATCH 0010/1112] fs: dlm: trace socket handling This patch adds tracepoints for dlm socket receive and send functionality. We can use it to track how much data was send or received to or from a specific nodeid. Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/lowcomms.c | 4 ++++ include/trace/events/dlm.h | 40 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index bee3757eb4c73..6d6dcf0d5ba97 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -53,6 +53,8 @@ #include #include +#include + #include "dlm_internal.h" #include "lowcomms.h" #include "midcomms.h" @@ -925,6 +927,7 @@ static int receive_from_sock(struct connection *con) msg.msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL; ret = kernel_recvmsg(con->sock, &msg, &iov, 1, iov.iov_len, msg.msg_flags); + trace_dlm_recv(con->nodeid, ret); if (ret == -EAGAIN) break; else if (ret <= 0) @@ -1411,6 +1414,7 @@ static void send_to_sock(struct connection *con) ret = kernel_sendpage(con->sock, e->page, offset, len, msg_flags); + trace_dlm_send(con->nodeid, ret); if (ret == -EAGAIN || ret == 0) { if (ret == -EAGAIN && test_bit(SOCKWQ_ASYNC_NOSPACE, &con->sock->flags) && diff --git a/include/trace/events/dlm.h b/include/trace/events/dlm.h index c97b4c163c3e9..32088c6032445 100644 --- a/include/trace/events/dlm.h +++ b/include/trace/events/dlm.h @@ -214,6 +214,46 @@ TRACE_EVENT(dlm_unlock_end, ); +TRACE_EVENT(dlm_send, + + TP_PROTO(int nodeid, int ret), + + TP_ARGS(nodeid, ret), + + TP_STRUCT__entry( + __field(int, nodeid) + __field(int, ret) + ), + + TP_fast_assign( + __entry->nodeid = nodeid; + __entry->ret = ret; + ), + + TP_printk("nodeid=%d ret=%d", __entry->nodeid, __entry->ret) + +); + +TRACE_EVENT(dlm_recv, + + TP_PROTO(int nodeid, int ret), + + TP_ARGS(nodeid, ret), + + TP_STRUCT__entry( + __field(int, nodeid) + __field(int, ret) + ), + + TP_fast_assign( + __entry->nodeid = nodeid; + __entry->ret = ret; + ), + + TP_printk("nodeid=%d ret=%d", __entry->nodeid, __entry->ret) + +); + #endif /* if !defined(_TRACE_DLM_H) || defined(TRACE_HEADER_MULTI_READ) */ /* This part must be outside protection */ -- GitLab From 164d88abd7608e869b7617d5ff8893344fdda759 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 2 Nov 2021 15:17:17 -0400 Subject: [PATCH 0011/1112] fs: dlm: requestqueue busy wait to event based wait This patch changes the requestqueue busy waiting algorithm to use atomic counter values and wait_event() to wait until the requestqueue is empty. It will slightly reduce the number of holding ls_requestqueue_mutex mutex. Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/dlm_internal.h | 2 ++ fs/dlm/lockspace.c | 2 ++ fs/dlm/requestqueue.c | 15 +++++++-------- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h index 44a5c67b52134..fd1c7a8c44855 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h @@ -626,6 +626,8 @@ struct dlm_ls { struct rw_semaphore ls_in_recovery; /* block local requests */ struct rw_semaphore ls_recv_active; /* block dlm_recv */ struct list_head ls_requestqueue;/* queue remote requests */ + atomic_t ls_requestqueue_cnt; + wait_queue_head_t ls_requestqueue_wait; struct mutex ls_requestqueue_mutex; struct dlm_rcom *ls_recover_buf; int ls_recover_nodeid; /* for debugging */ diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index b90566502a813..4e4181304ca16 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -564,6 +564,8 @@ static int new_lockspace(const char *name, const char *cluster, init_rwsem(&ls->ls_in_recovery); init_rwsem(&ls->ls_recv_active); INIT_LIST_HEAD(&ls->ls_requestqueue); + atomic_set(&ls->ls_requestqueue_cnt, 0); + init_waitqueue_head(&ls->ls_requestqueue_wait); mutex_init(&ls->ls_requestqueue_mutex); mutex_init(&ls->ls_clear_proc_locks); diff --git a/fs/dlm/requestqueue.c b/fs/dlm/requestqueue.c index e89e0ff8bfa3a..d0cf68570dcf6 100644 --- a/fs/dlm/requestqueue.c +++ b/fs/dlm/requestqueue.c @@ -44,6 +44,7 @@ void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_message *ms) e->nodeid = nodeid; memcpy(&e->request, ms, ms->m_header.h_length); + atomic_inc(&ls->ls_requestqueue_cnt); mutex_lock(&ls->ls_requestqueue_mutex); list_add_tail(&e->list, &ls->ls_requestqueue); mutex_unlock(&ls->ls_requestqueue_mutex); @@ -89,6 +90,8 @@ int dlm_process_requestqueue(struct dlm_ls *ls) mutex_lock(&ls->ls_requestqueue_mutex); list_del(&e->list); + if (atomic_dec_and_test(&ls->ls_requestqueue_cnt)) + wake_up(&ls->ls_requestqueue_wait); kfree(e); if (dlm_locking_stopped(ls)) { @@ -115,14 +118,8 @@ int dlm_process_requestqueue(struct dlm_ls *ls) void dlm_wait_requestqueue(struct dlm_ls *ls) { - for (;;) { - mutex_lock(&ls->ls_requestqueue_mutex); - if (list_empty(&ls->ls_requestqueue)) - break; - mutex_unlock(&ls->ls_requestqueue_mutex); - schedule(); - } - mutex_unlock(&ls->ls_requestqueue_mutex); + wait_event(ls->ls_requestqueue_wait, + atomic_read(&ls->ls_requestqueue_cnt) == 0); } static int purge_request(struct dlm_ls *ls, struct dlm_message *ms, int nodeid) @@ -161,6 +158,8 @@ void dlm_purge_requestqueue(struct dlm_ls *ls) if (purge_request(ls, ms, e->nodeid)) { list_del(&e->list); + if (atomic_dec_and_test(&ls->ls_requestqueue_cnt)) + wake_up(&ls->ls_requestqueue_wait); kfree(e); } } -- GitLab From 3cb5977c5214c219b2859f926ed547480d53fdde Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 2 Nov 2021 15:17:18 -0400 Subject: [PATCH 0012/1112] fs: dlm: ls_count busy wait to event based wait This patch changes the ls_count busy wait to use atomic counter values and wait_event() to wait until ls_count reach zero. It will slightly reduce the number of holding lslist_lock. At remove lockspace we need to retry the wait because it a lockspace get could interefere between wait_event() and holding the lock which deletes the lockspace list entry. Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/dlm_internal.h | 3 ++- fs/dlm/lockspace.c | 33 +++++++++++++++++---------------- fs/dlm/requestqueue.c | 2 +- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h index fd1c7a8c44855..019931804af9b 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h @@ -548,8 +548,9 @@ struct dlm_ls { uint32_t ls_generation; uint32_t ls_exflags; int ls_lvblen; - int ls_count; /* refcount of processes in + atomic_t ls_count; /* refcount of processes in the dlm using this ls */ + wait_queue_head_t ls_count_wait; int ls_create_count; /* create/release refcount */ unsigned long ls_flags; /* LSFL_ */ unsigned long ls_scan_time; diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index 4e4181304ca16..2e51bd2bdacce 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -314,7 +314,7 @@ struct dlm_ls *dlm_find_lockspace_global(uint32_t id) list_for_each_entry(ls, &lslist, ls_list) { if (ls->ls_global_id == id) { - ls->ls_count++; + atomic_inc(&ls->ls_count); goto out; } } @@ -331,7 +331,7 @@ struct dlm_ls *dlm_find_lockspace_local(dlm_lockspace_t *lockspace) spin_lock(&lslist_lock); list_for_each_entry(ls, &lslist, ls_list) { if (ls->ls_local_handle == lockspace) { - ls->ls_count++; + atomic_inc(&ls->ls_count); goto out; } } @@ -348,7 +348,7 @@ struct dlm_ls *dlm_find_lockspace_device(int minor) spin_lock(&lslist_lock); list_for_each_entry(ls, &lslist, ls_list) { if (ls->ls_device.minor == minor) { - ls->ls_count++; + atomic_inc(&ls->ls_count); goto out; } } @@ -360,24 +360,24 @@ struct dlm_ls *dlm_find_lockspace_device(int minor) void dlm_put_lockspace(struct dlm_ls *ls) { - spin_lock(&lslist_lock); - ls->ls_count--; - spin_unlock(&lslist_lock); + if (atomic_dec_and_test(&ls->ls_count)) + wake_up(&ls->ls_count_wait); } static void remove_lockspace(struct dlm_ls *ls) { - for (;;) { - spin_lock(&lslist_lock); - if (ls->ls_count == 0) { - WARN_ON(ls->ls_create_count != 0); - list_del(&ls->ls_list); - spin_unlock(&lslist_lock); - return; - } +retry: + wait_event(ls->ls_count_wait, atomic_read(&ls->ls_count) == 0); + + spin_lock(&lslist_lock); + if (atomic_read(&ls->ls_count) != 0) { spin_unlock(&lslist_lock); - ssleep(1); + goto retry; } + + WARN_ON(ls->ls_create_count != 0); + list_del(&ls->ls_list); + spin_unlock(&lslist_lock); } static int threads_start(void) @@ -481,7 +481,8 @@ static int new_lockspace(const char *name, const char *cluster, memcpy(ls->ls_name, name, namelen); ls->ls_namelen = namelen; ls->ls_lvblen = lvblen; - ls->ls_count = 0; + atomic_set(&ls->ls_count, 0); + init_waitqueue_head(&ls->ls_count_wait); ls->ls_flags = 0; ls->ls_scan_time = jiffies; diff --git a/fs/dlm/requestqueue.c b/fs/dlm/requestqueue.c index d0cf68570dcf6..ccb5307c21e90 100644 --- a/fs/dlm/requestqueue.c +++ b/fs/dlm/requestqueue.c @@ -127,7 +127,7 @@ static int purge_request(struct dlm_ls *ls, struct dlm_message *ms, int nodeid) uint32_t type = ms->m_type; /* the ls is being cleaned up and freed by release_lockspace */ - if (!ls->ls_count) + if (!atomic_read(&ls->ls_count)) return 1; if (dlm_is_removed(ls, nodeid)) -- GitLab From 5c16febbc19bb463bfb8e80cb5b24ec6ff1a439f Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 2 Nov 2021 15:17:19 -0400 Subject: [PATCH 0013/1112] fs: dlm: let handle callback data as void This patch changes the dlm_lowcomms_new_msg() function pointer private data from "struct mhandle *" to "void *" to provide different structures than just "struct mhandle". Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/lowcomms.c | 19 +++++++++---------- fs/dlm/lowcomms.h | 4 ++-- fs/dlm/midcomms.c | 4 +++- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 6d6dcf0d5ba97..3f8b015ba7990 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -1205,8 +1205,7 @@ static struct writequeue_entry *new_writequeue_entry(struct connection *con, static struct writequeue_entry *new_wq_entry(struct connection *con, int len, gfp_t allocation, char **ppc, - void (*cb)(struct dlm_mhandle *mh), - struct dlm_mhandle *mh) + void (*cb)(void *data), void *data) { struct writequeue_entry *e; @@ -1218,7 +1217,7 @@ static struct writequeue_entry *new_wq_entry(struct connection *con, int len, *ppc = page_address(e->page) + e->end; if (cb) - cb(mh); + cb(data); e->end += len; e->users++; @@ -1240,7 +1239,7 @@ static struct writequeue_entry *new_wq_entry(struct connection *con, int len, spin_lock(&con->writequeue_lock); if (cb) - cb(mh); + cb(data); list_add_tail(&e->list, &con->writequeue); spin_unlock(&con->writequeue_lock); @@ -1250,8 +1249,8 @@ static struct writequeue_entry *new_wq_entry(struct connection *con, int len, static struct dlm_msg *dlm_lowcomms_new_msg_con(struct connection *con, int len, gfp_t allocation, char **ppc, - void (*cb)(struct dlm_mhandle *mh), - struct dlm_mhandle *mh) + void (*cb)(void *data), + void *data) { struct writequeue_entry *e; struct dlm_msg *msg; @@ -1274,7 +1273,7 @@ static struct dlm_msg *dlm_lowcomms_new_msg_con(struct connection *con, int len, kref_init(&msg->ref); - e = new_wq_entry(con, len, allocation, ppc, cb, mh); + e = new_wq_entry(con, len, allocation, ppc, cb, data); if (!e) { if (sleepable) mutex_unlock(&con->wq_alloc); @@ -1294,8 +1293,8 @@ static struct dlm_msg *dlm_lowcomms_new_msg_con(struct connection *con, int len, } struct dlm_msg *dlm_lowcomms_new_msg(int nodeid, int len, gfp_t allocation, - char **ppc, void (*cb)(struct dlm_mhandle *mh), - struct dlm_mhandle *mh) + char **ppc, void (*cb)(void *data), + void *data) { struct connection *con; struct dlm_msg *msg; @@ -1316,7 +1315,7 @@ struct dlm_msg *dlm_lowcomms_new_msg(int nodeid, int len, gfp_t allocation, return NULL; } - msg = dlm_lowcomms_new_msg_con(con, len, allocation, ppc, cb, mh); + msg = dlm_lowcomms_new_msg_con(con, len, allocation, ppc, cb, data); if (!msg) { srcu_read_unlock(&connections_srcu, idx); return NULL; diff --git a/fs/dlm/lowcomms.h b/fs/dlm/lowcomms.h index 4ccae07cf0058..8108ea24ec301 100644 --- a/fs/dlm/lowcomms.h +++ b/fs/dlm/lowcomms.h @@ -38,8 +38,8 @@ void dlm_lowcomms_stop(void); void dlm_lowcomms_exit(void); int dlm_lowcomms_close(int nodeid); struct dlm_msg *dlm_lowcomms_new_msg(int nodeid, int len, gfp_t allocation, - char **ppc, void (*cb)(struct dlm_mhandle *mh), - struct dlm_mhandle *mh); + char **ppc, void (*cb)(void *data), + void *data); void dlm_lowcomms_commit_msg(struct dlm_msg *msg); void dlm_lowcomms_put_msg(struct dlm_msg *msg); int dlm_lowcomms_resend_msg(struct dlm_msg *msg); diff --git a/fs/dlm/midcomms.c b/fs/dlm/midcomms.c index 76bdc3a9dc61d..95a5643a950e3 100644 --- a/fs/dlm/midcomms.c +++ b/fs/dlm/midcomms.c @@ -1020,8 +1020,10 @@ static void dlm_fill_opts_header(struct dlm_opts *opts, uint16_t inner_len, header_out(&opts->o_header); } -static void midcomms_new_msg_cb(struct dlm_mhandle *mh) +static void midcomms_new_msg_cb(void *data) { + struct dlm_mhandle *mh = data; + atomic_inc(&mh->node->send_queue_cnt); spin_lock(&mh->node->send_queue_lock); -- GitLab From 9af5b8f0ead7cd90161b0555ed8e85ee38f79fa5 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 2 Nov 2021 15:17:20 -0400 Subject: [PATCH 0014/1112] fs: dlm: add debugfs rawmsg send functionality This patch adds a dlm functionality to send a raw dlm message to a specific cluster node. This raw message can be build by user space and send out by writing the message to "rawmsg" dlm debugfs file. There is a in progress scapy dlm module which provides a easy build of DLM messages in user space. For example: DLM(h_cmd=3, o_nextcmd=1, h_nodeid=1, h_lockspace=0xe4f48a18, ...) The goal is to provide an easy reproducable state to crash DLM or to fuzz the DLM kernel stack if there are possible ways to crash it. Note: that if the sequence number is zero and dlm version is not set to 3.1 the kernel will automatic will set a right sequence number, otherwise DLM stack testing is not possible. Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/debug_fs.c | 37 ++++++++++++++++++++++++++++++++++++ fs/dlm/midcomms.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++ fs/dlm/midcomms.h | 2 ++ 3 files changed, 87 insertions(+) diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c index 47e9d57e4cae3..555904eeea8ea 100644 --- a/fs/dlm/debug_fs.c +++ b/fs/dlm/debug_fs.c @@ -768,6 +768,42 @@ static int dlm_version_show(struct seq_file *file, void *offset) } DEFINE_SHOW_ATTRIBUTE(dlm_version); +static ssize_t dlm_rawmsg_write(struct file *fp, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + void *buf; + int ret; + + if (count > PAGE_SIZE || count < sizeof(struct dlm_header)) + return -EINVAL; + + buf = kmalloc(PAGE_SIZE, GFP_NOFS); + if (!buf) + return -ENOMEM; + + if (copy_from_user(buf, user_buf, count)) { + ret = -EFAULT; + goto out; + } + + ret = dlm_midcomms_rawmsg_send(fp->private_data, buf, count); + if (ret) + goto out; + + kfree(buf); + return count; + +out: + kfree(buf); + return ret; +} + +static const struct file_operations dlm_rawmsg_fops = { + .open = simple_open, + .write = dlm_rawmsg_write, + .llseek = no_llseek, +}; + void *dlm_create_debug_comms_file(int nodeid, void *data) { struct dentry *d_node; @@ -782,6 +818,7 @@ void *dlm_create_debug_comms_file(int nodeid, void *data) debugfs_create_file("send_queue_count", 0444, d_node, data, &dlm_send_queue_cnt_fops); debugfs_create_file("version", 0444, d_node, data, &dlm_version_fops); + debugfs_create_file("rawmsg", 0200, d_node, data, &dlm_rawmsg_fops); return d_node; } diff --git a/fs/dlm/midcomms.c b/fs/dlm/midcomms.c index 95a5643a950e3..0b9bce6f04e14 100644 --- a/fs/dlm/midcomms.c +++ b/fs/dlm/midcomms.c @@ -1427,3 +1427,51 @@ int dlm_midcomms_close(int nodeid) return ret; } + +/* debug functionality to send raw dlm msg from user space */ +struct dlm_rawmsg_data { + struct midcomms_node *node; + void *buf; +}; + +static void midcomms_new_rawmsg_cb(void *data) +{ + struct dlm_rawmsg_data *rd = data; + struct dlm_header *h = rd->buf; + + switch (h->h_version) { + case cpu_to_le32(DLM_VERSION_3_1): + break; + default: + switch (h->h_cmd) { + case DLM_OPTS: + if (!h->u.h_seq) + h->u.h_seq = rd->node->seq_send++; + break; + default: + break; + } + break; + } +} + +int dlm_midcomms_rawmsg_send(struct midcomms_node *node, void *buf, + int buflen) +{ + struct dlm_rawmsg_data rd; + struct dlm_msg *msg; + char *msgbuf; + + rd.node = node; + rd.buf = buf; + + msg = dlm_lowcomms_new_msg(node->nodeid, buflen, GFP_NOFS, + &msgbuf, midcomms_new_rawmsg_cb, &rd); + if (!msg) + return -ENOMEM; + + memcpy(msgbuf, buf, buflen); + dlm_lowcomms_commit_msg(msg); + return 0; +} + diff --git a/fs/dlm/midcomms.h b/fs/dlm/midcomms.h index 579abc6929be2..bc63cf73aa872 100644 --- a/fs/dlm/midcomms.h +++ b/fs/dlm/midcomms.h @@ -28,6 +28,8 @@ const char *dlm_midcomms_state(struct midcomms_node *node); unsigned long dlm_midcomms_flags(struct midcomms_node *node); int dlm_midcomms_send_queue_cnt(struct midcomms_node *node); uint32_t dlm_midcomms_version(struct midcomms_node *node); +int dlm_midcomms_rawmsg_send(struct midcomms_node *node, void *buf, + int buflen); #endif /* __MIDCOMMS_DOT_H__ */ -- GitLab From 75d25ffe380a01b88cb3bf604a6b8dc5a562a2e5 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 2 Nov 2021 15:17:21 -0400 Subject: [PATCH 0015/1112] fs: dlm: allow create lkb with specific id range This patch adds functionality to add a lkb with a specific id range. Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/lock.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index feb2e94f5879e..8b30c9d9e545d 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -1180,7 +1180,8 @@ static void detach_lkb(struct dlm_lkb *lkb) } } -static int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret) +static int _create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret, + int start, int end) { struct dlm_lkb *lkb; int rv; @@ -1201,7 +1202,7 @@ static int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret) idr_preload(GFP_NOFS); spin_lock(&ls->ls_lkbidr_spin); - rv = idr_alloc(&ls->ls_lkbidr, lkb, 1, 0, GFP_NOWAIT); + rv = idr_alloc(&ls->ls_lkbidr, lkb, start, end, GFP_NOWAIT); if (rv >= 0) lkb->lkb_id = rv; spin_unlock(&ls->ls_lkbidr_spin); @@ -1217,6 +1218,11 @@ static int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret) return 0; } +static int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret) +{ + return _create_lkb(ls, lkb_ret, 1, 0); +} + static int find_lkb(struct dlm_ls *ls, uint32_t lkid, struct dlm_lkb **lkb_ret) { struct dlm_lkb *lkb; -- GitLab From 5054e79de99984b4f39a073534526bc7c827b1e0 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 2 Nov 2021 15:17:22 -0400 Subject: [PATCH 0016/1112] fs: dlm: add lkb debugfs functionality This patch adds functionality to add an lkb during runtime. This is a highly debugging feature only, wrong input can crash the kernel. It is a early state feature as well. The goal is to provide a user interface for manipulate dlm state and combine it with the rawmsg feature. It is debugfs functionality, we don't care about UAPI breakage. Even it's possible to add lkb's/rsb's which could never be exists in such wat by using normal DLM operation. The user of this interface always need to think before using this feature, not every crash which happens can really occur during normal dlm operation. Future there should be more functionality to add a more realistic lkb which reflects normal DLM state inside the kernel. For now this is enough. Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/debug_fs.c | 32 +++++++++++++++++++++++++++++++- fs/dlm/lock.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ fs/dlm/lock.h | 2 ++ 3 files changed, 79 insertions(+), 1 deletion(-) diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c index 555904eeea8ea..2ead4751d6556 100644 --- a/fs/dlm/debug_fs.c +++ b/fs/dlm/debug_fs.c @@ -635,6 +635,35 @@ static int table_open2(struct inode *inode, struct file *file) return 0; } +static ssize_t table_write2(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct seq_file *seq = file->private_data; + int n, len, lkb_nodeid, lkb_status, error; + char name[DLM_RESNAME_MAXLEN] = {}; + struct dlm_ls *ls = seq->private; + unsigned int lkb_flags; + char buf[256] = {}; + uint32_t lkb_id; + + if (copy_from_user(buf, user_buf, + min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + n = sscanf(buf, "%x %" __stringify(DLM_RESNAME_MAXLEN) "s %x %d %d", + &lkb_id, name, &lkb_flags, &lkb_nodeid, &lkb_status); + if (n != 5) + return -EINVAL; + + len = strnlen(name, DLM_RESNAME_MAXLEN); + error = dlm_debug_add_lkb(ls, lkb_id, name, len, lkb_flags, + lkb_nodeid, lkb_status); + if (error) + return error; + + return count; +} + static int table_open3(struct inode *inode, struct file *file) { struct seq_file *seq; @@ -675,6 +704,7 @@ static const struct file_operations format2_fops = { .owner = THIS_MODULE, .open = table_open2, .read = seq_read, + .write = table_write2, .llseek = seq_lseek, .release = seq_release }; @@ -846,7 +876,7 @@ void dlm_create_debug_file(struct dlm_ls *ls) snprintf(name, DLM_LOCKSPACE_LEN + 8, "%s_locks", ls->ls_name); ls->ls_debug_locks_dentry = debugfs_create_file(name, - S_IFREG | S_IRUGO, + 0644, dlm_root, ls, &format2_fops); diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 8b30c9d9e545d..aeb793693d8c5 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -6317,3 +6317,49 @@ int dlm_user_purge(struct dlm_ls *ls, struct dlm_user_proc *proc, return error; } +/* debug functionality */ +int dlm_debug_add_lkb(struct dlm_ls *ls, uint32_t lkb_id, char *name, int len, + int lkb_nodeid, unsigned int lkb_flags, int lkb_status) +{ + struct dlm_lksb *lksb; + struct dlm_lkb *lkb; + struct dlm_rsb *r; + int error; + + /* we currently can't set a valid user lock */ + if (lkb_flags & DLM_IFL_USER) + return -EOPNOTSUPP; + + lksb = kzalloc(sizeof(*lksb), GFP_NOFS); + if (!lksb) + return -ENOMEM; + + error = _create_lkb(ls, &lkb, lkb_id, lkb_id + 1); + if (error) { + kfree(lksb); + return error; + } + + lkb->lkb_flags = lkb_flags; + lkb->lkb_nodeid = lkb_nodeid; + lkb->lkb_lksb = lksb; + /* user specific pointer, just don't have it NULL for kernel locks */ + if (~lkb_flags & DLM_IFL_USER) + lkb->lkb_astparam = (void *)0xDEADBEEF; + + error = find_rsb(ls, name, len, 0, R_REQUEST, &r); + if (error) { + kfree(lksb); + __put_lkb(ls, lkb); + return error; + } + + lock_rsb(r); + attach_lkb(r, lkb); + add_lkb(r, lkb, lkb_status); + unlock_rsb(r); + put_rsb(r); + + return 0; +} + diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h index 456c6ec3ef6f4..863a66e128a22 100644 --- a/fs/dlm/lock.h +++ b/fs/dlm/lock.h @@ -58,6 +58,8 @@ int dlm_user_purge(struct dlm_ls *ls, struct dlm_user_proc *proc, int nodeid, int pid); int dlm_user_deadlock(struct dlm_ls *ls, uint32_t flags, uint32_t lkid); void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc); +int dlm_debug_add_lkb(struct dlm_ls *ls, uint32_t lkb_id, char *name, int len, + int lkb_nodeid, unsigned int lkb_flags, int lkb_status); static inline int is_master(struct dlm_rsb *r) { -- GitLab From 63eab2b00bcff620682e8570367458c9619a9970 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 2 Nov 2021 15:17:23 -0400 Subject: [PATCH 0017/1112] fs: dlm: add lkb waiters debugfs functionality This patch adds functionality to put a lkb to the waiters state. It can be useful to combine this feature with the "rawmsg" debugfs functionality. It will bring the DLM lkb into a state that a message will be parsed by the kernel. Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/debug_fs.c | 27 ++++++++++++++++++++++++++- fs/dlm/lock.c | 15 +++++++++++++++ fs/dlm/lock.h | 2 ++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c index 2ead4751d6556..df6f3f107be4f 100644 --- a/fs/dlm/debug_fs.c +++ b/fs/dlm/debug_fs.c @@ -754,10 +754,35 @@ static ssize_t waiters_read(struct file *file, char __user *userbuf, return rv; } +static ssize_t waiters_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct dlm_ls *ls = file->private_data; + int mstype, to_nodeid; + char buf[128] = {}; + uint32_t lkb_id; + int n, error; + + if (copy_from_user(buf, user_buf, + min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + n = sscanf(buf, "%x %d %d", &lkb_id, &mstype, &to_nodeid); + if (n != 3) + return -EINVAL; + + error = dlm_debug_add_lkb_to_waiters(ls, lkb_id, mstype, to_nodeid); + if (error) + return error; + + return count; +} + static const struct file_operations waiters_fops = { .owner = THIS_MODULE, .open = simple_open, .read = waiters_read, + .write = waiters_write, .llseek = default_llseek, }; @@ -907,7 +932,7 @@ void dlm_create_debug_file(struct dlm_ls *ls) snprintf(name, DLM_LOCKSPACE_LEN + 8, "%s_waiters", ls->ls_name); ls->ls_debug_waiters_dentry = debugfs_create_file(name, - S_IFREG | S_IRUGO, + 0644, dlm_root, ls, &waiters_fops); diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index aeb793693d8c5..0dbe273566c0b 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -6363,3 +6363,18 @@ int dlm_debug_add_lkb(struct dlm_ls *ls, uint32_t lkb_id, char *name, int len, return 0; } +int dlm_debug_add_lkb_to_waiters(struct dlm_ls *ls, uint32_t lkb_id, + int mstype, int to_nodeid) +{ + struct dlm_lkb *lkb; + int error; + + error = find_lkb(ls, lkb_id, &lkb); + if (error) + return error; + + error = add_to_waiters(lkb, mstype, to_nodeid); + dlm_put_lkb(lkb); + return error; +} + diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h index 863a66e128a22..252a5898f9081 100644 --- a/fs/dlm/lock.h +++ b/fs/dlm/lock.h @@ -60,6 +60,8 @@ int dlm_user_deadlock(struct dlm_ls *ls, uint32_t flags, uint32_t lkid); void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc); int dlm_debug_add_lkb(struct dlm_ls *ls, uint32_t lkb_id, char *name, int len, int lkb_nodeid, unsigned int lkb_flags, int lkb_status); +int dlm_debug_add_lkb_to_waiters(struct dlm_ls *ls, uint32_t lkb_id, + int mstype, int to_nodeid); static inline int is_master(struct dlm_rsb *r) { -- GitLab From 6c2e3bf68f3e5e5a647aa52be246d5f552d7496d Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Tue, 2 Nov 2021 15:17:24 -0400 Subject: [PATCH 0018/1112] fs: dlm: filter user dlm messages for kernel locks This patch fixes the following crash by receiving a invalid message: [ 160.672220] ================================================================== [ 160.676206] BUG: KASAN: user-memory-access in dlm_user_add_ast+0xc3/0x370 [ 160.679659] Read of size 8 at addr 00000000deadbeef by task kworker/u32:13/319 [ 160.681447] [ 160.681824] CPU: 10 PID: 319 Comm: kworker/u32:13 Not tainted 5.14.0-rc2+ #399 [ 160.683472] Hardware name: Red Hat KVM/RHEL-AV, BIOS 1.14.0-1.module+el8.6.0+12648+6ede71a5 04/01/2014 [ 160.685574] Workqueue: dlm_recv process_recv_sockets [ 160.686721] Call Trace: [ 160.687310] dump_stack_lvl+0x56/0x6f [ 160.688169] ? dlm_user_add_ast+0xc3/0x370 [ 160.689116] kasan_report.cold.14+0x116/0x11b [ 160.690138] ? dlm_user_add_ast+0xc3/0x370 [ 160.690832] dlm_user_add_ast+0xc3/0x370 [ 160.691502] _receive_unlock_reply+0x103/0x170 [ 160.692241] _receive_message+0x11df/0x1ec0 [ 160.692926] ? rcu_read_lock_sched_held+0xa1/0xd0 [ 160.693700] ? rcu_read_lock_bh_held+0xb0/0xb0 [ 160.694427] ? lock_acquire+0x175/0x400 [ 160.695058] ? do_purge.isra.51+0x200/0x200 [ 160.695744] ? lock_acquired+0x360/0x5d0 [ 160.696400] ? lock_contended+0x6a0/0x6a0 [ 160.697055] ? lock_release+0x21d/0x5e0 [ 160.697686] ? lock_is_held_type+0xe0/0x110 [ 160.698352] ? lock_is_held_type+0xe0/0x110 [ 160.699026] ? ___might_sleep+0x1cc/0x1e0 [ 160.699698] ? dlm_wait_requestqueue+0x94/0x140 [ 160.700451] ? dlm_process_requestqueue+0x240/0x240 [ 160.701249] ? down_write_killable+0x2b0/0x2b0 [ 160.701988] ? do_raw_spin_unlock+0xa2/0x130 [ 160.702690] dlm_receive_buffer+0x1a5/0x210 [ 160.703385] dlm_process_incoming_buffer+0x726/0x9f0 [ 160.704210] receive_from_sock+0x1c0/0x3b0 [ 160.704886] ? dlm_tcp_shutdown+0x30/0x30 [ 160.705561] ? lock_acquire+0x175/0x400 [ 160.706197] ? rcu_read_lock_sched_held+0xa1/0xd0 [ 160.706941] ? rcu_read_lock_bh_held+0xb0/0xb0 [ 160.707681] process_recv_sockets+0x32/0x40 [ 160.708366] process_one_work+0x55e/0xad0 [ 160.709045] ? pwq_dec_nr_in_flight+0x110/0x110 [ 160.709820] worker_thread+0x65/0x5e0 [ 160.710423] ? process_one_work+0xad0/0xad0 [ 160.711087] kthread+0x1ed/0x220 [ 160.711628] ? set_kthread_struct+0x80/0x80 [ 160.712314] ret_from_fork+0x22/0x30 The issue is that we received a DLM message for a user lock but the destination lock is a kernel lock. Note that the address which is trying to derefence is 00000000deadbeef, which is in a kernel lock lkb->lkb_astparam, this field should never be derefenced by the DLM kernel stack. In case of a user lock lkb->lkb_astparam is lkb->lkb_ua (memory is shared by a union field). The struct lkb_ua will be handled by the DLM kernel stack but on a kernel lock it will contain invalid data and ends in most likely crashing the kernel. It can be reproduced with two cluster nodes. node 2: dlm_tool join test echo "862 fooobaar 1 2 1" > /sys/kernel/debug/dlm/test_locks echo "862 3 1" > /sys/kernel/debug/dlm/test_waiters node 1: dlm_tool join test python: foo = DLM(h_cmd=3, o_nextcmd=1, h_nodeid=1, h_lockspace=0x77222027, \ m_type=7, m_flags=0x1, m_remid=0x862, m_result=0xFFFEFFFE) newFile = open("/sys/kernel/debug/dlm/comms/2/rawmsg", "wb") newFile.write(bytes(foo)) Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/lock.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 0dbe273566c0b..54705d367076b 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -3989,6 +3989,14 @@ static int validate_message(struct dlm_lkb *lkb, struct dlm_message *ms) int from = ms->m_header.h_nodeid; int error = 0; + /* currently mixing of user/kernel locks are not supported */ + if (ms->m_flags & DLM_IFL_USER && ~lkb->lkb_flags & DLM_IFL_USER) { + log_error(lkb->lkb_resource->res_ls, + "got user dlm message for a kernel lock"); + error = -EINVAL; + goto out; + } + switch (ms->m_type) { case DLM_MSG_CONVERT: case DLM_MSG_UNLOCK: @@ -4017,6 +4025,7 @@ static int validate_message(struct dlm_lkb *lkb, struct dlm_message *ms) error = -EINVAL; } +out: if (error) log_error(lkb->lkb_resource->res_ls, "ignore invalid message %d from %d %x %x %x %d", -- GitLab From b87b1883efe385e56384ff48e6f3108a33fde508 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 3 Nov 2021 17:04:18 -0400 Subject: [PATCH 0019/1112] fs: dlm: remove double list_first_entry call This patch removes a list_first_entry() call which is already done by the previous con_next_wq() call. Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/lowcomms.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 3f8b015ba7990..2f070514b3eed 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -1405,7 +1405,6 @@ static void send_to_sock(struct connection *con) if (!e) break; - e = list_first_entry(&con->writequeue, struct writequeue_entry, list); len = e->len; offset = e->offset; BUG_ON(len == 0 && e->users == 0); -- GitLab From c8b9f34e223fcad1e9980f343587f38624331bbc Mon Sep 17 00:00:00 2001 From: Zhang Mingyu Date: Fri, 5 Nov 2021 01:43:20 +0000 Subject: [PATCH 0020/1112] fs: dlm:Remove unneeded semicolon Eliminate the following coccinelle check warning: fs/dlm/midcomms.c:972:2-3 Reported-by: Zeal Robot Signed-off-by: Zhang Mingyu Signed-off-by: David Teigland --- fs/dlm/midcomms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/dlm/midcomms.c b/fs/dlm/midcomms.c index 0b9bce6f04e14..74b4308b912cf 100644 --- a/fs/dlm/midcomms.c +++ b/fs/dlm/midcomms.c @@ -969,7 +969,7 @@ void dlm_midcomms_receive_done(int nodeid) spin_unlock(&node->state_lock); /* do nothing FIN has it's own ack send */ break; - }; + } srcu_read_unlock(&nodes_srcu, idx); } -- GitLab From 6a628fa43810f861da50c593c69f2ead1c829231 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Fri, 12 Nov 2021 10:08:01 -0500 Subject: [PATCH 0021/1112] fs: dlm: fix potential buffer overflow This patch fixes an potential overflow in sscanf and the maximum declared string parsing length which seems to be excluding the null termination symbol. This patch will just add one byte to be prepared on a string with length of DLM_RESNAME_MAXLEN including the null termination symbol. Fixes: 5054e79de999 ("fs: dlm: add lkb debugfs functionality") Reported-by: kernel test robot Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/debug_fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c index df6f3f107be4f..8fb04ebbafb5d 100644 --- a/fs/dlm/debug_fs.c +++ b/fs/dlm/debug_fs.c @@ -640,7 +640,7 @@ static ssize_t table_write2(struct file *file, const char __user *user_buf, { struct seq_file *seq = file->private_data; int n, len, lkb_nodeid, lkb_status, error; - char name[DLM_RESNAME_MAXLEN] = {}; + char name[DLM_RESNAME_MAXLEN + 1] = {}; struct dlm_ls *ls = seq->private; unsigned int lkb_flags; char buf[256] = {}; -- GitLab From 981387ed06b96908223a607f5fba6efa42728fc2 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Mon, 25 Oct 2021 21:56:28 +0100 Subject: [PATCH 0022/1112] mtd: hyperbus: rpc-if: Check return value of rpcif_sw_init() rpcif_sw_init() can fail so make sure we check the return value of it and on error exit rpcif_hb_probe() callback with error code. Fixes: 5de15b610f78 ("mtd: hyperbus: add Renesas RPC-IF driver") Signed-off-by: Lad Prabhakar Signed-off-by: Vignesh Raghavendra Reviewed-by: Biju Das Reviewed-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20211025205631.21151-5-prabhakar.mahadev-lad.rj@bp.renesas.com --- drivers/mtd/hyperbus/rpc-if.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/hyperbus/rpc-if.c b/drivers/mtd/hyperbus/rpc-if.c index ecb050ba95cdf..367b0d72bf622 100644 --- a/drivers/mtd/hyperbus/rpc-if.c +++ b/drivers/mtd/hyperbus/rpc-if.c @@ -124,7 +124,9 @@ static int rpcif_hb_probe(struct platform_device *pdev) if (!hyperbus) return -ENOMEM; - rpcif_sw_init(&hyperbus->rpc, pdev->dev.parent); + error = rpcif_sw_init(&hyperbus->rpc, pdev->dev.parent); + if (error) + return error; platform_set_drvdata(pdev, hyperbus); -- GitLab From c61d8b5791abbc8b1aa51593d45dc88ef8804e4a Mon Sep 17 00:00:00 2001 From: Jacky Bai Date: Fri, 12 Nov 2021 15:18:58 +0800 Subject: [PATCH 0023/1112] dt-bindings: gpio: gpio-vf610: Add imx8ulp compatible string Add the compatible string for i.MX8ULP. Reviewed-by: Linus Walleij Reviewed-by: Dong Aisheng Acked-by: Rob Herring Signed-off-by: Jacky Bai Signed-off-by: Peng Fan Signed-off-by: Bartosz Golaszewski --- Documentation/devicetree/bindings/gpio/gpio-vf610.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/gpio/gpio-vf610.yaml b/Documentation/devicetree/bindings/gpio/gpio-vf610.yaml index 19738a457a58c..e1359391d3a47 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-vf610.yaml +++ b/Documentation/devicetree/bindings/gpio/gpio-vf610.yaml @@ -24,6 +24,9 @@ properties: - items: - const: fsl,imx7ulp-gpio - const: fsl,vf610-gpio + - items: + - const: fsl,imx8ulp-gpio + - const: fsl,imx7ulp-gpio reg: description: The first reg tuple represents the PORT module, the second tuple -- GitLab From ea708ac5bf419d9735354f9deada384c1059700f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 9 Nov 2021 10:12:53 -0600 Subject: [PATCH 0024/1112] gpio: xlp: Remove Netlogic XLP variants Netlogic XLP was removed in commit 95b8a5e0111a ("MIPS: Remove NETLOGIC support"). With those gone, the single platform left to support is Cavium ThunderX2. Remove all the Netlogic variants and DT support. For simplicity, the existing kconfig name is retained. Cc: Linus Walleij Cc: Bartosz Golaszewski Cc: linux-gpio@vger.kernel.org Signed-off-by: Rob Herring Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 10 ++- drivers/gpio/gpio-xlp.c | 142 +++------------------------------------- 2 files changed, 13 insertions(+), 139 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 072ed610f9c66..e05f226b3d5d6 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -730,14 +730,12 @@ config GPIO_XILINX Say yes here to support the Xilinx FPGA GPIO device. config GPIO_XLP - tristate "Netlogic XLP GPIO support" - depends on OF_GPIO && (CPU_XLP || ARCH_THUNDER2 || COMPILE_TEST) + tristate "Cavium ThunderX2 GPIO support" + depends on ARCH_THUNDER2 || COMPILE_TEST select GPIOLIB_IRQCHIP help - This driver provides support for GPIO interface on Netlogic XLP MIPS64 - SoCs. Currently supported XLP variants are XLP8XX, XLP3XX, XLP2XX, - XLP9XX and XLP5XX. The same GPIO controller block is also present in - Cavium's ThunderX2 CN99XX SoCs. + This driver provides support for GPIO interface on Cavium's ThunderX2 + CN99XX SoCs (Originally from Netlogic XLP). If unsure, say N. diff --git a/drivers/gpio/gpio-xlp.c b/drivers/gpio/gpio-xlp.c index 0d94d3aef7521..814cc34aef976 100644 --- a/drivers/gpio/gpio-xlp.c +++ b/drivers/gpio/gpio-xlp.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include @@ -26,16 +25,6 @@ * * where addr is base address of the that feature register and gpio is the pin. */ -#define GPIO_OUTPUT_EN 0x00 -#define GPIO_PADDRV 0x08 -#define GPIO_INT_EN00 0x18 -#define GPIO_INT_EN10 0x20 -#define GPIO_INT_EN20 0x28 -#define GPIO_INT_EN30 0x30 -#define GPIO_INT_POL 0x38 -#define GPIO_INT_TYPE 0x40 -#define GPIO_INT_STAT 0x48 - #define GPIO_9XX_BYTESWAP 0X00 #define GPIO_9XX_CTRL 0X04 #define GPIO_9XX_OUTPUT_EN 0x14 @@ -52,14 +41,6 @@ #define GPIO_9XX_INT_TYPE 0x114 #define GPIO_9XX_INT_STAT 0x124 -#define GPIO_3XX_INT_EN00 0x18 -#define GPIO_3XX_INT_EN10 0x20 -#define GPIO_3XX_INT_EN20 0x28 -#define GPIO_3XX_INT_EN30 0x30 -#define GPIO_3XX_INT_POL 0x78 -#define GPIO_3XX_INT_TYPE 0x80 -#define GPIO_3XX_INT_STAT 0x88 - /* Interrupt type register mask */ #define XLP_GPIO_IRQ_TYPE_LVL 0x0 #define XLP_GPIO_IRQ_TYPE_EDGE 0x1 @@ -72,16 +53,6 @@ #define XLP_GPIO_IRQ_BASE 768 #define XLP_MAX_NR_GPIO 96 -/* XLP variants supported by this driver */ -enum { - XLP_GPIO_VARIANT_XLP832 = 1, - XLP_GPIO_VARIANT_XLP316, - XLP_GPIO_VARIANT_XLP208, - XLP_GPIO_VARIANT_XLP980, - XLP_GPIO_VARIANT_XLP532, - GPIO_VARIANT_VULCAN -}; - struct xlp_gpio_priv { struct gpio_chip chip; DECLARE_BITMAP(gpio_enabled_mask, XLP_MAX_NR_GPIO); @@ -257,44 +228,13 @@ static void xlp_gpio_set(struct gpio_chip *gc, unsigned gpio, int state) xlp_gpio_set_reg(priv->gpio_paddrv, gpio, state); } -static const struct of_device_id xlp_gpio_of_ids[] = { - { - .compatible = "netlogic,xlp832-gpio", - .data = (void *)XLP_GPIO_VARIANT_XLP832, - }, - { - .compatible = "netlogic,xlp316-gpio", - .data = (void *)XLP_GPIO_VARIANT_XLP316, - }, - { - .compatible = "netlogic,xlp208-gpio", - .data = (void *)XLP_GPIO_VARIANT_XLP208, - }, - { - .compatible = "netlogic,xlp980-gpio", - .data = (void *)XLP_GPIO_VARIANT_XLP980, - }, - { - .compatible = "netlogic,xlp532-gpio", - .data = (void *)XLP_GPIO_VARIANT_XLP532, - }, - { - .compatible = "brcm,vulcan-gpio", - .data = (void *)GPIO_VARIANT_VULCAN, - }, - { /* sentinel */ }, -}; -MODULE_DEVICE_TABLE(of, xlp_gpio_of_ids); - static int xlp_gpio_probe(struct platform_device *pdev) { struct gpio_chip *gc; struct gpio_irq_chip *girq; struct xlp_gpio_priv *priv; void __iomem *gpio_base; - int irq_base, irq, err; - int ngpio; - u32 soc_type; + int irq, err; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -308,62 +248,12 @@ static int xlp_gpio_probe(struct platform_device *pdev) if (irq < 0) return irq; - if (pdev->dev.of_node) { - soc_type = (uintptr_t)of_device_get_match_data(&pdev->dev); - } else { - const struct acpi_device_id *acpi_id; - - acpi_id = acpi_match_device(pdev->dev.driver->acpi_match_table, - &pdev->dev); - if (!acpi_id || !acpi_id->driver_data) { - dev_err(&pdev->dev, "Unable to match ACPI ID\n"); - return -ENODEV; - } - soc_type = (uintptr_t) acpi_id->driver_data; - } - - switch (soc_type) { - case XLP_GPIO_VARIANT_XLP832: - priv->gpio_out_en = gpio_base + GPIO_OUTPUT_EN; - priv->gpio_paddrv = gpio_base + GPIO_PADDRV; - priv->gpio_intr_stat = gpio_base + GPIO_INT_STAT; - priv->gpio_intr_type = gpio_base + GPIO_INT_TYPE; - priv->gpio_intr_pol = gpio_base + GPIO_INT_POL; - priv->gpio_intr_en = gpio_base + GPIO_INT_EN00; - ngpio = 41; - break; - case XLP_GPIO_VARIANT_XLP208: - case XLP_GPIO_VARIANT_XLP316: - priv->gpio_out_en = gpio_base + GPIO_OUTPUT_EN; - priv->gpio_paddrv = gpio_base + GPIO_PADDRV; - priv->gpio_intr_stat = gpio_base + GPIO_3XX_INT_STAT; - priv->gpio_intr_type = gpio_base + GPIO_3XX_INT_TYPE; - priv->gpio_intr_pol = gpio_base + GPIO_3XX_INT_POL; - priv->gpio_intr_en = gpio_base + GPIO_3XX_INT_EN00; - - ngpio = (soc_type == XLP_GPIO_VARIANT_XLP208) ? 42 : 57; - break; - case XLP_GPIO_VARIANT_XLP980: - case XLP_GPIO_VARIANT_XLP532: - case GPIO_VARIANT_VULCAN: - priv->gpio_out_en = gpio_base + GPIO_9XX_OUTPUT_EN; - priv->gpio_paddrv = gpio_base + GPIO_9XX_PADDRV; - priv->gpio_intr_stat = gpio_base + GPIO_9XX_INT_STAT; - priv->gpio_intr_type = gpio_base + GPIO_9XX_INT_TYPE; - priv->gpio_intr_pol = gpio_base + GPIO_9XX_INT_POL; - priv->gpio_intr_en = gpio_base + GPIO_9XX_INT_EN00; - - if (soc_type == XLP_GPIO_VARIANT_XLP980) - ngpio = 66; - else if (soc_type == XLP_GPIO_VARIANT_XLP532) - ngpio = 67; - else - ngpio = 70; - break; - default: - dev_err(&pdev->dev, "Unknown Processor type!\n"); - return -ENODEV; - } + priv->gpio_out_en = gpio_base + GPIO_9XX_OUTPUT_EN; + priv->gpio_paddrv = gpio_base + GPIO_9XX_PADDRV; + priv->gpio_intr_stat = gpio_base + GPIO_9XX_INT_STAT; + priv->gpio_intr_type = gpio_base + GPIO_9XX_INT_TYPE; + priv->gpio_intr_pol = gpio_base + GPIO_9XX_INT_POL; + priv->gpio_intr_en = gpio_base + GPIO_9XX_INT_EN00; bitmap_zero(priv->gpio_enabled_mask, XLP_MAX_NR_GPIO); @@ -373,7 +263,7 @@ static int xlp_gpio_probe(struct platform_device *pdev) gc->label = dev_name(&pdev->dev); gc->base = 0; gc->parent = &pdev->dev; - gc->ngpio = ngpio; + gc->ngpio = 70; gc->of_node = pdev->dev.of_node; gc->direction_output = xlp_gpio_dir_output; gc->direction_input = xlp_gpio_dir_input; @@ -382,19 +272,6 @@ static int xlp_gpio_probe(struct platform_device *pdev) spin_lock_init(&priv->lock); - /* XLP(MIPS) has fixed range for GPIO IRQs, Vulcan(ARM64) does not */ - if (soc_type != GPIO_VARIANT_VULCAN) { - irq_base = devm_irq_alloc_descs(&pdev->dev, -1, - XLP_GPIO_IRQ_BASE, - gc->ngpio, 0); - if (irq_base < 0) { - dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n"); - return irq_base; - } - } else { - irq_base = 0; - } - girq = &gc->irq; girq->chip = &xlp_gpio_irq_chip; girq->parent_handler = xlp_gpio_generic_handler; @@ -405,7 +282,7 @@ static int xlp_gpio_probe(struct platform_device *pdev) if (!girq->parents) return -ENOMEM; girq->parents[0] = irq; - girq->first = irq_base; + girq->first = 0; girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_level_irq; @@ -430,7 +307,6 @@ MODULE_DEVICE_TABLE(acpi, xlp_gpio_acpi_match); static struct platform_driver xlp_gpio_driver = { .driver = { .name = "xlp-gpio", - .of_match_table = xlp_gpio_of_ids, .acpi_match_table = ACPI_PTR(xlp_gpio_acpi_match), }, .probe = xlp_gpio_probe, -- GitLab From 507805b83ff108473dba9d4909e41abd50cf07f5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 10 Nov 2021 15:47:42 +0200 Subject: [PATCH 0025/1112] gpiolib: acpi: Remove never used devm_acpi_dev_remove_driver_gpios() Remove never used devm_acpi_dev_remove_driver_gpios(). Signed-off-by: Andy Shevchenko Reviewed-by: Mika Westerberg --- drivers/gpio/gpiolib-acpi.c | 6 ------ include/linux/gpio/consumer.h | 2 -- 2 files changed, 8 deletions(-) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 985e8589c58ba..25ecc0a37054c 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -604,12 +604,6 @@ int devm_acpi_dev_add_driver_gpios(struct device *dev, } EXPORT_SYMBOL_GPL(devm_acpi_dev_add_driver_gpios); -void devm_acpi_dev_remove_driver_gpios(struct device *dev) -{ - WARN_ON(devres_release(dev, devm_acpi_dev_release_driver_gpios, NULL, NULL)); -} -EXPORT_SYMBOL_GPL(devm_acpi_dev_remove_driver_gpios); - static bool acpi_get_driver_gpio_data(struct acpi_device *adev, const char *name, int index, struct fwnode_reference_args *args, diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index 97a28ad3393b5..3ad67b4a72be9 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -690,7 +690,6 @@ void acpi_dev_remove_driver_gpios(struct acpi_device *adev); int devm_acpi_dev_add_driver_gpios(struct device *dev, const struct acpi_gpio_mapping *gpios); -void devm_acpi_dev_remove_driver_gpios(struct device *dev); struct gpio_desc *acpi_get_and_request_gpiod(char *path, int pin, char *label); @@ -708,7 +707,6 @@ static inline int devm_acpi_dev_add_driver_gpios(struct device *dev, { return -ENXIO; } -static inline void devm_acpi_dev_remove_driver_gpios(struct device *dev) {} #endif /* CONFIG_GPIOLIB && CONFIG_ACPI */ -- GitLab From 2ff64a84bbb3ea0281899766d9a944fd18db7013 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 10 Nov 2021 15:47:43 +0200 Subject: [PATCH 0026/1112] gpiolib: acpi: shrink devm_acpi_dev_add_driver_gpios() If all we want to manage is a single pointer, there's no need to manually allocate and add a new devres. We can simply use devm_add_action_or_reset() and shrink the code by a good bit. Signed-off-by: Andy Shevchenko Reviewed-by: Mika Westerberg --- drivers/gpio/gpiolib-acpi.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 25ecc0a37054c..7dd0484b89c60 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -579,28 +579,22 @@ void acpi_dev_remove_driver_gpios(struct acpi_device *adev) } EXPORT_SYMBOL_GPL(acpi_dev_remove_driver_gpios); -static void devm_acpi_dev_release_driver_gpios(struct device *dev, void *res) +static void acpi_dev_release_driver_gpios(void *adev) { - acpi_dev_remove_driver_gpios(ACPI_COMPANION(dev)); + acpi_dev_remove_driver_gpios(adev); } int devm_acpi_dev_add_driver_gpios(struct device *dev, const struct acpi_gpio_mapping *gpios) { - void *res; + struct acpi_device *adev = ACPI_COMPANION(dev); int ret; - res = devres_alloc(devm_acpi_dev_release_driver_gpios, 0, GFP_KERNEL); - if (!res) - return -ENOMEM; - - ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(dev), gpios); - if (ret) { - devres_free(res); + ret = acpi_dev_add_driver_gpios(adev, gpios); + if (ret) return ret; - } - devres_add(dev, res); - return 0; + + return devm_add_action_or_reset(dev, acpi_dev_release_driver_gpios, adev); } EXPORT_SYMBOL_GPL(devm_acpi_dev_add_driver_gpios); -- GitLab From 45971bdd8ca8b5a99a49f4db86737401c45e246f Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Tue, 2 Nov 2021 16:02:02 -0600 Subject: [PATCH 0027/1112] spi: remove unused header file Commit 6acaadc852f1 ("spi: clps711x: Driver refactor") removed the only use of , but left the header file behind. This file is unused, delete it. Cc: Signed-off-by: Arnd Bergmann Cc: Signed-off-by: Mark Brown Cc: linux-arm-kernel@lists.infradead.org Signed-off-by: Jonathan Corbet Acked-by: Arnd Bergmann Link: https://lore.kernel.org/r/20211102220203.940290-9-corbet@lwn.net Signed-off-by: Mark Brown --- include/linux/platform_data/spi-clps711x.h | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 include/linux/platform_data/spi-clps711x.h diff --git a/include/linux/platform_data/spi-clps711x.h b/include/linux/platform_data/spi-clps711x.h deleted file mode 100644 index efaa596848c9f..0000000000000 --- a/include/linux/platform_data/spi-clps711x.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * CLPS711X SPI bus driver definitions - * - * Copyright (C) 2012 Alexander Shiyan - */ - -#ifndef ____LINUX_PLATFORM_DATA_SPI_CLPS711X_H -#define ____LINUX_PLATFORM_DATA_SPI_CLPS711X_H - -/* Board specific platform_data */ -struct spi_clps711x_pdata { - int *chipselect; /* Array of GPIO-numbers */ - int num_chipselect; /* Total count of GPIOs */ -}; - -#endif -- GitLab From f02bff30114f385d53ae3e45141db602923bca5d Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 9 Nov 2021 11:31:34 +0100 Subject: [PATCH 0028/1112] spi: lpspi: release requested DMA channels The requested DMA channels are never released. Do this in .remove as well as in .probe. spi_register_controller() can return -EPROBE_DEFER if cs-gpios are not probed yet. Signed-off-by: Alexander Stein Link: https://lore.kernel.org/r/20211109103134.184216-1-alexander.stein@ew.tq-group.com Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index c72e501c270fd..4c601294f8fab 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -913,7 +913,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev) ret = devm_spi_register_controller(&pdev->dev, controller); if (ret < 0) { dev_err_probe(&pdev->dev, ret, "spi_register_controller error: %i\n", ret); - goto out_pm_get; + goto free_dma; } pm_runtime_mark_last_busy(fsl_lpspi->dev); @@ -921,6 +921,8 @@ static int fsl_lpspi_probe(struct platform_device *pdev) return 0; +free_dma: + fsl_lpspi_dma_exit(controller); out_pm_get: pm_runtime_dont_use_autosuspend(fsl_lpspi->dev); pm_runtime_put_sync(fsl_lpspi->dev); @@ -937,6 +939,8 @@ static int fsl_lpspi_remove(struct platform_device *pdev) struct fsl_lpspi_data *fsl_lpspi = spi_controller_get_devdata(controller); + fsl_lpspi_dma_exit(controller); + pm_runtime_disable(fsl_lpspi->dev); return 0; } -- GitLab From f7d344f2188c9f16e434cadf2a954b5d40365c14 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 9 Nov 2021 10:13:25 -0600 Subject: [PATCH 0029/1112] spi: xlp: Remove Netlogic XLP variants Netlogic XLP was removed in commit 95b8a5e0111a ("MIPS: Remove NETLOGIC support"). With those gone, the single platform left to support is Cavium ThunderX2. Remove the Netlogic variant and DT support. For simplicity, the existing kconfig name is retained. Cc: Mark Brown Cc: linux-spi@vger.kernel.org Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20211109161325.2203564-1-robh@kernel.org Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 11 +++++------ drivers/spi/spi-xlp.c | 8 -------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 596705d244007..b2a8821971e1d 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -974,14 +974,13 @@ config SPI_XILINX Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)" config SPI_XLP - tristate "Netlogic XLP SPI controller driver" - depends on CPU_XLP || ARCH_THUNDER2 || COMPILE_TEST + tristate "Cavium ThunderX2 SPI controller driver" + depends on ARCH_THUNDER2 || COMPILE_TEST help - Enable support for the SPI controller on the Netlogic XLP SoCs. - Currently supported XLP variants are XLP8XX, XLP3XX, XLP2XX, XLP9XX - and XLP5XX. + Enable support for the SPI controller on the Cavium ThunderX2. + (Originally on Netlogic XLP SoCs.) - If you have a Netlogic XLP platform say Y here. + If you have a Cavium ThunderX2 platform say Y here. If unsure, say N. config SPI_XTENSA_XTFPGA diff --git a/drivers/spi/spi-xlp.c b/drivers/spi/spi-xlp.c index 797ac0ea8fa37..e5707fe5c8f15 100644 --- a/drivers/spi/spi-xlp.c +++ b/drivers/spi/spi-xlp.c @@ -9,7 +9,6 @@ #include #include #include -#include #include /* SPI Configuration Register */ @@ -436,17 +435,10 @@ static const struct acpi_device_id xlp_spi_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, xlp_spi_acpi_match); #endif -static const struct of_device_id xlp_spi_dt_id[] = { - { .compatible = "netlogic,xlp832-spi" }, - { }, -}; -MODULE_DEVICE_TABLE(of, xlp_spi_dt_id); - static struct platform_driver xlp_spi_driver = { .probe = xlp_spi_probe, .driver = { .name = "xlp-spi", - .of_match_table = xlp_spi_dt_id, .acpi_match_table = ACPI_PTR(xlp_spi_acpi_match), }, }; -- GitLab From 4c3d90570bcc2b338f70f61f01110268e281ca3c Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 15 Nov 2021 08:57:05 -0500 Subject: [PATCH 0030/1112] fs: dlm: don't call kernel_getpeername() in error_report() In some cases kernel_getpeername() will held the socket lock which is already held when the socket layer calls error_report() callback. Since commit 9dfc685e0262 ("inet: remove races in inet{6}_getname()") this problem becomes more likely because the socket lock will be held always. You will see something like: bob9-u5 login: [ 562.316860] BUG: spinlock recursion on CPU#7, swapper/7/0 [ 562.318562] lock: 0xffff8f2284720088, .magic: dead4ead, .owner: swapper/7/0, .owner_cpu: 7 [ 562.319522] CPU: 7 PID: 0 Comm: swapper/7 Not tainted 5.15.0+ #135 [ 562.320346] Hardware name: Red Hat KVM/RHEL-AV, BIOS 1.13.0-2.module+el8.3.0+7353+9de0a3cc 04/01/2014 [ 562.321277] Call Trace: [ 562.321529] [ 562.321734] dump_stack_lvl+0x33/0x42 [ 562.322282] do_raw_spin_lock+0x8b/0xc0 [ 562.322674] lock_sock_nested+0x1e/0x50 [ 562.323057] inet_getname+0x39/0x110 [ 562.323425] ? sock_def_readable+0x80/0x80 [ 562.323838] lowcomms_error_report+0x63/0x260 [dlm] [ 562.324338] ? wait_for_completion_interruptible_timeout+0xd2/0x120 [ 562.324949] ? lock_timer_base+0x67/0x80 [ 562.325330] ? do_raw_spin_unlock+0x49/0xc0 [ 562.325735] ? _raw_spin_unlock_irqrestore+0x1e/0x40 [ 562.326218] ? del_timer+0x54/0x80 [ 562.326549] sk_error_report+0x12/0x70 [ 562.326919] tcp_validate_incoming+0x3c8/0x530 [ 562.327347] ? kvm_clock_read+0x14/0x30 [ 562.327718] ? ktime_get+0x3b/0xa0 [ 562.328055] tcp_rcv_established+0x121/0x660 [ 562.328466] tcp_v4_do_rcv+0x132/0x260 [ 562.328835] tcp_v4_rcv+0xcea/0xe20 [ 562.329173] ip_protocol_deliver_rcu+0x35/0x1f0 [ 562.329615] ip_local_deliver_finish+0x54/0x60 [ 562.330050] ip_local_deliver+0xf7/0x110 [ 562.330431] ? inet_rtm_getroute+0x211/0x840 [ 562.330848] ? ip_protocol_deliver_rcu+0x1f0/0x1f0 [ 562.331310] ip_rcv+0xe1/0xf0 [ 562.331603] ? ip_local_deliver+0x110/0x110 [ 562.332011] __netif_receive_skb_core+0x46a/0x1040 [ 562.332476] ? inet_gro_receive+0x263/0x2e0 [ 562.332885] __netif_receive_skb_list_core+0x13b/0x2c0 [ 562.333383] netif_receive_skb_list_internal+0x1c8/0x2f0 [ 562.333896] ? update_load_avg+0x7e/0x5e0 [ 562.334285] gro_normal_list.part.149+0x19/0x40 [ 562.334722] napi_complete_done+0x67/0x160 [ 562.335134] virtnet_poll+0x2ad/0x408 [virtio_net] [ 562.335644] __napi_poll+0x28/0x140 [ 562.336012] net_rx_action+0x23d/0x300 [ 562.336414] __do_softirq+0xf2/0x2ea [ 562.336803] irq_exit_rcu+0xc1/0xf0 [ 562.337173] common_interrupt+0xb9/0xd0 It is and was always forbidden to call kernel_getpeername() in context of error_report(). To get rid of the problem we access the destination address for the peer over the socket structure. While on it we fix to print out the destination port of the inet socket. Fixes: 1a31833d085a ("DLM: Replace nodeid_to_addr with kernel_getpeername") Reported-by: Bob Peterson Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/lowcomms.c | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 2f070514b3eed..c7750849c4954 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -594,8 +594,8 @@ int dlm_lowcomms_nodes_set_mark(int nodeid, unsigned int mark) static void lowcomms_error_report(struct sock *sk) { struct connection *con; - struct sockaddr_storage saddr; void (*orig_report)(struct sock *) = NULL; + struct inet_sock *inet; read_lock_bh(&sk->sk_callback_lock); con = sock2con(sk); @@ -603,33 +603,31 @@ static void lowcomms_error_report(struct sock *sk) goto out; orig_report = listen_sock.sk_error_report; - if (kernel_getpeername(sk->sk_socket, (struct sockaddr *)&saddr) < 0) { - printk_ratelimited(KERN_ERR "dlm: node %d: socket error " - "sending to node %d, port %d, " - "sk_err=%d/%d\n", dlm_our_nodeid(), - con->nodeid, dlm_config.ci_tcp_port, - sk->sk_err, sk->sk_err_soft); - } else if (saddr.ss_family == AF_INET) { - struct sockaddr_in *sin4 = (struct sockaddr_in *)&saddr; + inet = inet_sk(sk); + switch (sk->sk_family) { + case AF_INET: printk_ratelimited(KERN_ERR "dlm: node %d: socket error " - "sending to node %d at %pI4, port %d, " + "sending to node %d at %pI4, dport %d, " "sk_err=%d/%d\n", dlm_our_nodeid(), - con->nodeid, &sin4->sin_addr.s_addr, - dlm_config.ci_tcp_port, sk->sk_err, + con->nodeid, &inet->inet_daddr, + ntohs(inet->inet_dport), sk->sk_err, sk->sk_err_soft); - } else { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&saddr; - + break; + case AF_INET6: printk_ratelimited(KERN_ERR "dlm: node %d: socket error " - "sending to node %d at %u.%u.%u.%u, " - "port %d, sk_err=%d/%d\n", dlm_our_nodeid(), - con->nodeid, sin6->sin6_addr.s6_addr32[0], - sin6->sin6_addr.s6_addr32[1], - sin6->sin6_addr.s6_addr32[2], - sin6->sin6_addr.s6_addr32[3], - dlm_config.ci_tcp_port, sk->sk_err, + "sending to node %d at %pI6c, " + "dport %d, sk_err=%d/%d\n", dlm_our_nodeid(), + con->nodeid, &sk->sk_v6_daddr, + ntohs(inet->inet_dport), sk->sk_err, sk->sk_err_soft); + break; + default: + printk_ratelimited(KERN_ERR "dlm: node %d: socket error " + "invalid socket family %d set, " + "sk_err=%d/%d\n", dlm_our_nodeid(), + sk->sk_family, sk->sk_err, sk->sk_err_soft); + goto out; } /* below sendcon only handling */ -- GitLab From 92c44605381418b01af44c63fd27185cac368866 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 15 Nov 2021 08:57:06 -0500 Subject: [PATCH 0031/1112] fs: dlm: replace use of socket sk_callback_lock with sock_lock This patch will replace the use of socket sk_callback_lock lock and uses socket lock instead. Some users like sunrpc, see commit ea9afca88bbe ("SUNRPC: Replace use of socket sk_callback_lock with sock_lock") moving from sk_callback_lock to sock_lock which seems to be held when the socket callbacks are called. Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/lowcomms.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index c7750849c4954..2034701890111 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -488,11 +488,9 @@ static void lowcomms_data_ready(struct sock *sk) { struct connection *con; - read_lock_bh(&sk->sk_callback_lock); con = sock2con(sk); if (con && !test_and_set_bit(CF_READ_PENDING, &con->flags)) queue_work(recv_workqueue, &con->rwork); - read_unlock_bh(&sk->sk_callback_lock); } static void lowcomms_listen_data_ready(struct sock *sk) @@ -507,15 +505,14 @@ static void lowcomms_write_space(struct sock *sk) { struct connection *con; - read_lock_bh(&sk->sk_callback_lock); con = sock2con(sk); if (!con) - goto out; + return; if (!test_and_set_bit(CF_CONNECTED, &con->flags)) { log_print("successful connected to node %d", con->nodeid); queue_work(send_workqueue, &con->swork); - goto out; + return; } clear_bit(SOCK_NOSPACE, &con->sock->flags); @@ -526,8 +523,6 @@ static void lowcomms_write_space(struct sock *sk) } queue_work(send_workqueue, &con->swork); -out: - read_unlock_bh(&sk->sk_callback_lock); } static inline void lowcomms_connect_sock(struct connection *con) @@ -597,7 +592,6 @@ static void lowcomms_error_report(struct sock *sk) void (*orig_report)(struct sock *) = NULL; struct inet_sock *inet; - read_lock_bh(&sk->sk_callback_lock); con = sock2con(sk); if (con == NULL) goto out; @@ -646,7 +640,6 @@ static void lowcomms_error_report(struct sock *sk) queue_work(send_workqueue, &con->swork); out: - read_unlock_bh(&sk->sk_callback_lock); if (orig_report) orig_report(sk); } @@ -666,20 +659,20 @@ static void restore_callbacks(struct socket *sock) { struct sock *sk = sock->sk; - write_lock_bh(&sk->sk_callback_lock); + lock_sock(sk); sk->sk_user_data = NULL; sk->sk_data_ready = listen_sock.sk_data_ready; sk->sk_state_change = listen_sock.sk_state_change; sk->sk_write_space = listen_sock.sk_write_space; sk->sk_error_report = listen_sock.sk_error_report; - write_unlock_bh(&sk->sk_callback_lock); + release_sock(sk); } static void add_listen_sock(struct socket *sock, struct listen_connection *con) { struct sock *sk = sock->sk; - write_lock_bh(&sk->sk_callback_lock); + lock_sock(sk); save_listen_callbacks(sock); con->sock = sock; @@ -687,7 +680,7 @@ static void add_listen_sock(struct socket *sock, struct listen_connection *con) sk->sk_allocation = GFP_NOFS; /* Install a data_ready callback */ sk->sk_data_ready = lowcomms_listen_data_ready; - write_unlock_bh(&sk->sk_callback_lock); + release_sock(sk); } /* Make a socket active */ @@ -695,7 +688,7 @@ static void add_sock(struct socket *sock, struct connection *con) { struct sock *sk = sock->sk; - write_lock_bh(&sk->sk_callback_lock); + lock_sock(sk); con->sock = sock; sk->sk_user_data = con; @@ -705,7 +698,7 @@ static void add_sock(struct socket *sock, struct connection *con) sk->sk_state_change = lowcomms_state_change; sk->sk_allocation = GFP_NOFS; sk->sk_error_report = lowcomms_error_report; - write_unlock_bh(&sk->sk_callback_lock); + release_sock(sk); } /* Add the port number to an IPv6 or 4 sockaddr and return the address @@ -1680,9 +1673,9 @@ static void _stop_conn(struct connection *con, bool and_other) set_bit(CF_READ_PENDING, &con->flags); set_bit(CF_WRITE_PENDING, &con->flags); if (con->sock && con->sock->sk) { - write_lock_bh(&con->sock->sk->sk_callback_lock); + lock_sock(con->sock->sk); con->sock->sk->sk_user_data = NULL; - write_unlock_bh(&con->sock->sk->sk_callback_lock); + release_sock(con->sock->sk); } if (con->othercon && and_other) _stop_conn(con->othercon, false); -- GitLab From 552a23a0e5d0a84cecd4687043d8030673981d30 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 29 Sep 2021 16:18:03 -0500 Subject: [PATCH 0032/1112] Makefile: Enable -Wcast-function-type In order to make sure new function cast mismatches are not introduced in the kernel (to avoid tripping CFI checking), the kernel should be globally built with -Wcast-function-type. Link: https://github.com/KSPP/linux/issues/20 Co-developed-by: Kees Cook Signed-off-by: Kees Cook Signed-off-by: Gustavo A. R. Silva --- Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Makefile b/Makefile index 9e12c14ea0fbb..5a8cde6a2fbb4 100644 --- a/Makefile +++ b/Makefile @@ -953,6 +953,11 @@ KBUILD_CFLAGS += -Wvla # disable pointer signed / unsigned warnings in gcc 4.0 KBUILD_CFLAGS += -Wno-pointer-sign +# In order to make sure new function cast mismatches are not introduced +# in the kernel (to avoid tripping CFI checking), the kernel should be +# globally built with -Wcast-function-type. +KBUILD_CFLAGS += $(call cc-option, -Wcast-function-type) + # disable stringop warnings in gcc 8+ KBUILD_CFLAGS += $(call cc-disable-warning, stringop-truncation) -- GitLab From 79f960e29cfc87db324479ef982a3f97025328dc Mon Sep 17 00:00:00 2001 From: Len Baker Date: Sat, 23 Oct 2021 17:40:36 +0200 Subject: [PATCH 0033/1112] platform/x86: thinkpad_acpi: Convert platform driver to use dev_groups Platform drivers have the option of having the platform core create and remove any needed sysfs attribute files. So take advantage of that and refactor the attributes management to avoid to register them "by hand". Also, due to some attributes are optionals, refactor the code and move the logic inside the "is_visible" callbacks of the attribute_group structures. Suggested-by: Greg Kroah-Hartman Acked-by: Greg Kroah-Hartman Signed-off-by: Len Baker Link: https://lore.kernel.org/r/20211023154036.6800-1-len.baker@gmx.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/thinkpad_acpi.c | 526 +++++++++++++-------------- 1 file changed, 243 insertions(+), 283 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index b3ac9c3f3b7c6..37aadc64d4e00 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -332,12 +332,11 @@ static struct { u32 battery_force_primary:1; u32 input_device_registered:1; u32 platform_drv_registered:1; - u32 platform_drv_attrs_registered:1; u32 sensors_pdrv_registered:1; - u32 sensors_pdrv_attrs_registered:1; u32 sensors_pdev_attrs_registered:1; u32 hotkey_poll_active:1; u32 has_adaptive_kbd:1; + u32 kbd_lang:1; } tp_features; static struct { @@ -983,20 +982,6 @@ static void tpacpi_shutdown_handler(struct platform_device *pdev) } } -static struct platform_driver tpacpi_pdriver = { - .driver = { - .name = TPACPI_DRVR_NAME, - .pm = &tpacpi_pm, - }, - .shutdown = tpacpi_shutdown_handler, -}; - -static struct platform_driver tpacpi_hwmon_pdriver = { - .driver = { - .name = TPACPI_HWMON_DRVR_NAME, - }, -}; - /************************************************************************* * sysfs support helpers */ @@ -1479,53 +1464,6 @@ static ssize_t uwb_emulstate_store(struct device_driver *drv, const char *buf, static DRIVER_ATTR_RW(uwb_emulstate); #endif -/* --------------------------------------------------------------------- */ - -static struct driver_attribute *tpacpi_driver_attributes[] = { - &driver_attr_debug_level, &driver_attr_version, - &driver_attr_interface_version, -}; - -static int __init tpacpi_create_driver_attributes(struct device_driver *drv) -{ - int i, res; - - i = 0; - res = 0; - while (!res && i < ARRAY_SIZE(tpacpi_driver_attributes)) { - res = driver_create_file(drv, tpacpi_driver_attributes[i]); - i++; - } - -#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES - if (!res && dbg_wlswemul) - res = driver_create_file(drv, &driver_attr_wlsw_emulstate); - if (!res && dbg_bluetoothemul) - res = driver_create_file(drv, &driver_attr_bluetooth_emulstate); - if (!res && dbg_wwanemul) - res = driver_create_file(drv, &driver_attr_wwan_emulstate); - if (!res && dbg_uwbemul) - res = driver_create_file(drv, &driver_attr_uwb_emulstate); -#endif - - return res; -} - -static void tpacpi_remove_driver_attributes(struct device_driver *drv) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++) - driver_remove_file(drv, tpacpi_driver_attributes[i]); - -#ifdef THINKPAD_ACPI_DEBUGFACILITIES - driver_remove_file(drv, &driver_attr_wlsw_emulstate); - driver_remove_file(drv, &driver_attr_bluetooth_emulstate); - driver_remove_file(drv, &driver_attr_wwan_emulstate); - driver_remove_file(drv, &driver_attr_uwb_emulstate); -#endif -} - /************************************************************************* * Firmware Data */ @@ -2999,7 +2937,14 @@ static struct attribute *adaptive_kbd_attributes[] = { NULL }; +static umode_t hadaptive_kbd_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + return tp_features.has_adaptive_kbd ? attr->mode : 0; +} + static const struct attribute_group adaptive_kbd_attr_group = { + .is_visible = hadaptive_kbd_attr_is_visible, .attrs = adaptive_kbd_attributes, }; @@ -3094,8 +3039,6 @@ static void hotkey_exit(void) hotkey_poll_stop_sync(); mutex_unlock(&hotkey_mutex); #endif - sysfs_remove_group(&tpacpi_pdev->dev.kobj, &hotkey_attr_group); - dbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_HKEY, "restoring original HKEY status and mask\n"); /* yes, there is a bitwise or below, we want the @@ -3490,14 +3433,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) */ if (acpi_evalf(hkey_handle, &hotkey_adaptive_all_mask, "MHKA", "dd", 2)) { - if (hotkey_adaptive_all_mask != 0) { + if (hotkey_adaptive_all_mask != 0) tp_features.has_adaptive_kbd = true; - res = sysfs_create_group( - &tpacpi_pdev->dev.kobj, - &adaptive_kbd_attr_group); - if (res) - goto err_exit; - } } else { tp_features.has_adaptive_kbd = false; hotkey_adaptive_all_mask = 0x0U; @@ -3551,9 +3488,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) } tabletsw_state = hotkey_init_tablet_mode(); - res = sysfs_create_group(&tpacpi_pdev->dev.kobj, &hotkey_attr_group); - if (res) - goto err_exit; /* Set up key map */ keymap_id = tpacpi_check_quirks(tpacpi_keymap_qtable, @@ -3650,9 +3584,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) return 0; err_exit: - sysfs_remove_group(&tpacpi_pdev->dev.kobj, &hotkey_attr_group); - sysfs_remove_group(&tpacpi_pdev->dev.kobj, &adaptive_kbd_attr_group); - return (res < 0) ? res : 1; } @@ -4384,7 +4315,14 @@ static struct attribute *bluetooth_attributes[] = { NULL }; +static umode_t bluetooth_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + return tp_features.bluetooth ? attr->mode : 0; +} + static const struct attribute_group bluetooth_attr_group = { + .is_visible = bluetooth_attr_is_visible, .attrs = bluetooth_attributes, }; @@ -4406,11 +4344,7 @@ static void bluetooth_shutdown(void) static void bluetooth_exit(void) { - sysfs_remove_group(&tpacpi_pdev->dev.kobj, - &bluetooth_attr_group); - tpacpi_destroy_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID); - bluetooth_shutdown(); } @@ -4524,17 +4458,7 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) RFKILL_TYPE_BLUETOOTH, TPACPI_RFK_BLUETOOTH_SW_NAME, true); - if (res) - return res; - - res = sysfs_create_group(&tpacpi_pdev->dev.kobj, - &bluetooth_attr_group); - if (res) { - tpacpi_destroy_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID); - return res; - } - - return 0; + return res; } /* procfs -------------------------------------------------------------- */ @@ -4641,7 +4565,14 @@ static struct attribute *wan_attributes[] = { NULL }; +static umode_t wan_attr_is_visible(struct kobject *kobj, struct attribute *attr, + int n) +{ + return tp_features.wan ? attr->mode : 0; +} + static const struct attribute_group wan_attr_group = { + .is_visible = wan_attr_is_visible, .attrs = wan_attributes, }; @@ -4663,11 +4594,7 @@ static void wan_shutdown(void) static void wan_exit(void) { - sysfs_remove_group(&tpacpi_pdev->dev.kobj, - &wan_attr_group); - tpacpi_destroy_rfkill(TPACPI_RFK_WWAN_SW_ID); - wan_shutdown(); } @@ -4711,18 +4638,7 @@ static int __init wan_init(struct ibm_init_struct *iibm) RFKILL_TYPE_WWAN, TPACPI_RFK_WWAN_SW_NAME, true); - if (res) - return res; - - res = sysfs_create_group(&tpacpi_pdev->dev.kobj, - &wan_attr_group); - - if (res) { - tpacpi_destroy_rfkill(TPACPI_RFK_WWAN_SW_ID); - return res; - } - - return 0; + return res; } /* procfs -------------------------------------------------------------- */ @@ -5623,30 +5539,35 @@ static ssize_t cmos_command_store(struct device *dev, static DEVICE_ATTR_WO(cmos_command); +static struct attribute *cmos_attributes[] = { + &dev_attr_cmos_command.attr, + NULL +}; + +static umode_t cmos_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + return cmos_handle ? attr->mode : 0; +} + +static const struct attribute_group cmos_attr_group = { + .is_visible = cmos_attr_is_visible, + .attrs = cmos_attributes, +}; + /* --------------------------------------------------------------------- */ static int __init cmos_init(struct ibm_init_struct *iibm) { - int res; - vdbg_printk(TPACPI_DBG_INIT, - "initializing cmos commands subdriver\n"); + "initializing cmos commands subdriver\n"); TPACPI_ACPIHANDLE_INIT(cmos); vdbg_printk(TPACPI_DBG_INIT, "cmos commands are %s\n", - str_supported(cmos_handle != NULL)); + str_supported(cmos_handle != NULL)); - res = device_create_file(&tpacpi_pdev->dev, &dev_attr_cmos_command); - if (res) - return res; - - return (cmos_handle) ? 0 : 1; -} - -static void cmos_exit(void) -{ - device_remove_file(&tpacpi_pdev->dev, &dev_attr_cmos_command); + return cmos_handle ? 0 : 1; } static int cmos_read(struct seq_file *m) @@ -5687,7 +5608,6 @@ static struct ibm_struct cmos_driver_data = { .name = "cmos", .read = cmos_read, .write = cmos_write, - .exit = cmos_exit, }; /************************************************************************* @@ -6198,7 +6118,6 @@ struct ibm_thermal_sensors_struct { }; static enum thermal_access_mode thermal_read_mode; -static const struct attribute_group *thermal_attr_group; static bool thermal_use_labels; /* idx is zero-based */ @@ -6371,12 +6290,26 @@ static struct attribute *thermal_temp_input_attr[] = { NULL }; -static const struct attribute_group thermal_temp_input16_group = { - .attrs = thermal_temp_input_attr -}; +static umode_t thermal_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + if (thermal_read_mode == TPACPI_THERMAL_NONE) + return 0; -static const struct attribute_group thermal_temp_input8_group = { - .attrs = &thermal_temp_input_attr[8] + if (attr == THERMAL_ATTRS(8) || attr == THERMAL_ATTRS(9) || + attr == THERMAL_ATTRS(10) || attr == THERMAL_ATTRS(11) || + attr == THERMAL_ATTRS(12) || attr == THERMAL_ATTRS(13) || + attr == THERMAL_ATTRS(14) || attr == THERMAL_ATTRS(15)) { + if (thermal_read_mode != TPACPI_THERMAL_TPEC_16) + return 0; + } + + return attr->mode; +} + +static const struct attribute_group thermal_attr_group = { + .is_visible = thermal_attr_is_visible, + .attrs = thermal_temp_input_attr, }; #undef THERMAL_SENSOR_ATTR_TEMP @@ -6400,7 +6333,14 @@ static struct attribute *temp_label_attributes[] = { NULL }; +static umode_t temp_label_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + return thermal_use_labels ? attr->mode : 0; +} + static const struct attribute_group temp_label_attr_group = { + .is_visible = temp_label_attr_is_visible, .attrs = temp_label_attributes, }; @@ -6411,7 +6351,6 @@ static int __init thermal_init(struct ibm_init_struct *iibm) u8 t, ta1, ta2, ver = 0; int i; int acpi_tmp7; - int res; vdbg_printk(TPACPI_DBG_INIT, "initializing thermal subdriver\n"); @@ -6486,42 +6425,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm) str_supported(thermal_read_mode != TPACPI_THERMAL_NONE), thermal_read_mode); - switch (thermal_read_mode) { - case TPACPI_THERMAL_TPEC_16: - thermal_attr_group = &thermal_temp_input16_group; - break; - case TPACPI_THERMAL_TPEC_8: - case TPACPI_THERMAL_ACPI_TMP07: - case TPACPI_THERMAL_ACPI_UPDT: - thermal_attr_group = &thermal_temp_input8_group; - break; - case TPACPI_THERMAL_NONE: - default: - return 1; - } - - res = sysfs_create_group(&tpacpi_hwmon->kobj, thermal_attr_group); - if (res) - return res; - - if (thermal_use_labels) { - res = sysfs_create_group(&tpacpi_hwmon->kobj, &temp_label_attr_group); - if (res) { - sysfs_remove_group(&tpacpi_hwmon->kobj, thermal_attr_group); - return res; - } - } - - return 0; -} - -static void thermal_exit(void) -{ - if (thermal_attr_group) - sysfs_remove_group(&tpacpi_hwmon->kobj, thermal_attr_group); - - if (thermal_use_labels) - sysfs_remove_group(&tpacpi_hwmon->kobj, &temp_label_attr_group); + return thermal_read_mode == TPACPI_THERMAL_NONE ? 1 : 0; } static int thermal_read(struct seq_file *m) @@ -6548,7 +6452,6 @@ static int thermal_read(struct seq_file *m) static struct ibm_struct thermal_driver_data = { .name = "thermal", .read = thermal_read, - .exit = thermal_exit, }; /************************************************************************* @@ -8723,14 +8626,33 @@ static ssize_t fan_watchdog_store(struct device_driver *drv, const char *buf, static DRIVER_ATTR_RW(fan_watchdog); /* --------------------------------------------------------------------- */ + static struct attribute *fan_attributes[] = { - &dev_attr_pwm1_enable.attr, &dev_attr_pwm1.attr, + &dev_attr_pwm1_enable.attr, + &dev_attr_pwm1.attr, &dev_attr_fan1_input.attr, - NULL, /* for fan2_input */ + &dev_attr_fan2_input.attr, + &driver_attr_fan_watchdog.attr, NULL }; +static umode_t fan_attr_is_visible(struct kobject *kobj, struct attribute *attr, + int n) +{ + if (fan_status_access_mode == TPACPI_FAN_NONE && + fan_control_access_mode == TPACPI_FAN_WR_NONE) + return 0; + + if (attr == &dev_attr_fan2_input.attr) { + if (!tp_features.second_fan) + return 0; + } + + return attr->mode; +} + static const struct attribute_group fan_attr_group = { + .is_visible = fan_attr_is_visible, .attrs = fan_attributes, }; @@ -8761,7 +8683,6 @@ static const struct tpacpi_quirk fan_quirk_table[] __initconst = { static int __init fan_init(struct ibm_init_struct *iibm) { - int rc; unsigned long quirks; vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_FAN, @@ -8858,27 +8779,10 @@ static int __init fan_init(struct ibm_init_struct *iibm) fan_get_status_safe(NULL); if (fan_status_access_mode != TPACPI_FAN_NONE || - fan_control_access_mode != TPACPI_FAN_WR_NONE) { - if (tp_features.second_fan) { - /* attach second fan tachometer */ - fan_attributes[ARRAY_SIZE(fan_attributes)-2] = - &dev_attr_fan2_input.attr; - } - rc = sysfs_create_group(&tpacpi_hwmon->kobj, - &fan_attr_group); - if (rc < 0) - return rc; - - rc = driver_create_file(&tpacpi_hwmon_pdriver.driver, - &driver_attr_fan_watchdog); - if (rc < 0) { - sysfs_remove_group(&tpacpi_hwmon->kobj, - &fan_attr_group); - return rc; - } + fan_control_access_mode != TPACPI_FAN_WR_NONE) return 0; - } else - return 1; + + return 1; } static void fan_exit(void) @@ -8886,11 +8790,6 @@ static void fan_exit(void) vdbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_FAN, "cancelling any pending fan watchdog tasks\n"); - /* FIXME: can we really do this unconditionally? */ - sysfs_remove_group(&tpacpi_hwmon->kobj, &fan_attr_group); - driver_remove_file(&tpacpi_hwmon_pdriver.driver, - &driver_attr_fan_watchdog); - cancel_delayed_work(&fan_watchdog_task); flush_workqueue(tpacpi_wq); } @@ -9952,6 +9851,35 @@ static ssize_t palmsensor_show(struct device *dev, } static DEVICE_ATTR_RO(palmsensor); +static struct attribute *proxsensor_attributes[] = { + &dev_attr_dytc_lapmode.attr, + &dev_attr_palmsensor.attr, + NULL +}; + +static umode_t proxsensor_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + if (attr == &dev_attr_dytc_lapmode.attr) { + /* + * Platforms before DYTC version 5 claim to have a lap sensor, + * but it doesn't work, so we ignore them. + */ + if (!has_lapsensor || dytc_version < 5) + return 0; + } else if (attr == &dev_attr_palmsensor.attr) { + if (!has_palmsensor) + return 0; + } + + return attr->mode; +} + +static const struct attribute_group proxsensor_attr_group = { + .is_visible = proxsensor_attr_is_visible, + .attrs = proxsensor_attributes, +}; + static int tpacpi_proxsensor_init(struct ibm_init_struct *iibm) { int palm_err, lap_err, err; @@ -9970,41 +9898,18 @@ static int tpacpi_proxsensor_init(struct ibm_init_struct *iibm) if (lap_err && (lap_err != -ENODEV)) return lap_err; - if (has_palmsensor) { - err = sysfs_create_file(&tpacpi_pdev->dev.kobj, &dev_attr_palmsensor.attr); - if (err) - return err; - } - /* Check if we know the DYTC version, if we don't then get it */ if (!dytc_version) { err = dytc_get_version(); if (err) return err; } - /* - * Platforms before DYTC version 5 claim to have a lap sensor, but it doesn't work, so we - * ignore them - */ - if (has_lapsensor && (dytc_version >= 5)) { - err = sysfs_create_file(&tpacpi_pdev->dev.kobj, &dev_attr_dytc_lapmode.attr); - if (err) - return err; - } - return 0; -} -static void proxsensor_exit(void) -{ - if (has_lapsensor) - sysfs_remove_file(&tpacpi_pdev->dev.kobj, &dev_attr_dytc_lapmode.attr); - if (has_palmsensor) - sysfs_remove_file(&tpacpi_pdev->dev.kobj, &dev_attr_palmsensor.attr); + return 0; } static struct ibm_struct proxsensor_driver_data = { .name = "proximity-sensor", - .exit = proxsensor_exit, }; /************************************************************************* @@ -10421,7 +10326,14 @@ static struct attribute *kbdlang_attributes[] = { NULL }; +static umode_t kbdlang_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + return tp_features.kbd_lang ? attr->mode : 0; +} + static const struct attribute_group kbdlang_attr_group = { + .is_visible = kbdlang_attr_is_visible, .attrs = kbdlang_attributes, }; @@ -10430,28 +10342,12 @@ static int tpacpi_kbdlang_init(struct ibm_init_struct *iibm) int err, output; err = get_keyboard_lang(&output); - /* - * If support isn't available (ENODEV) then don't return an error - * just don't create the sysfs group. - */ - if (err == -ENODEV) - return 0; - - if (err) - return err; - - /* Platform supports this feature - create the sysfs file */ - return sysfs_create_group(&tpacpi_pdev->dev.kobj, &kbdlang_attr_group); -} - -static void kbdlang_exit(void) -{ - sysfs_remove_group(&tpacpi_pdev->dev.kobj, &kbdlang_attr_group); + tp_features.kbd_lang = !err; + return err; } static struct ibm_struct kbdlang_driver_data = { .name = "kbdlang", - .exit = kbdlang_exit, }; /************************************************************************* @@ -10522,41 +10418,131 @@ static ssize_t wwan_antenna_type_show(struct device *dev, } static DEVICE_ATTR_RO(wwan_antenna_type); +static struct attribute *dprc_attributes[] = { + &dev_attr_wwan_antenna_type.attr, + NULL +}; + +static umode_t dprc_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + return has_antennatype ? attr->mode : 0; +} + +static const struct attribute_group dprc_attr_group = { + .is_visible = dprc_attr_is_visible, + .attrs = dprc_attributes, +}; + static int tpacpi_dprc_init(struct ibm_init_struct *iibm) { - int wwanantenna_err, err; + int err = get_wwan_antenna(&wwan_antennatype); - wwanantenna_err = get_wwan_antenna(&wwan_antennatype); /* * If support isn't available (ENODEV) then quit, but don't * return an error. */ - if (wwanantenna_err == -ENODEV) + if (err == -ENODEV) return 0; - /* if there was an error return it */ - if (wwanantenna_err && (wwanantenna_err != -ENODEV)) - return wwanantenna_err; - else if (!wwanantenna_err) - has_antennatype = true; + /* If there was an error return it */ + if (err) + return err; - if (has_antennatype) { - err = sysfs_create_file(&tpacpi_pdev->dev.kobj, &dev_attr_wwan_antenna_type.attr); - if (err) - return err; - } + has_antennatype = true; return 0; } -static void dprc_exit(void) +static struct ibm_struct dprc_driver_data = { + .name = "dprc", +}; + +/* --------------------------------------------------------------------- */ + +static struct attribute *tpacpi_attributes[] = { + &driver_attr_debug_level.attr, + &driver_attr_version.attr, + &driver_attr_interface_version.attr, +#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES + &driver_attr_wlsw_emulstate.attr, + &driver_attr_bluetooth_emulstate.attr, + &driver_attr_wwan_emulstate.attr, + &driver_attr_uwb_emulstate.attr, +#endif + NULL +}; + +#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES +static umode_t tpacpi_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) { - if (has_antennatype) - sysfs_remove_file(&tpacpi_pdev->dev.kobj, &dev_attr_wwan_antenna_type.attr); + if (attr == &driver_attr_wlsw_emulstate.attr) { + if (!dbg_wlswemul) + return 0; + } else if (attr == &driver_attr_bluetooth_emulstate.attr) { + if (!dbg_bluetoothemul) + return 0; + } else if (attr == &driver_attr_wwan_emulstate.attr) { + if (!dbg_wwanemul) + return 0; + } else if (attr == &driver_attr_uwb_emulstate.attr) { + if (!dbg_uwbemul) + return 0; + } + + return attr->mode; } +#endif -static struct ibm_struct dprc_driver_data = { - .name = "dprc", - .exit = dprc_exit, +static const struct attribute_group tpacpi_attr_group = { +#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES + .is_visible = tpacpi_attr_is_visible, +#endif + .attrs = tpacpi_attributes, +}; + +static const struct attribute_group *tpacpi_groups[] = { + &adaptive_kbd_attr_group, + &hotkey_attr_group, + &bluetooth_attr_group, + &wan_attr_group, + &cmos_attr_group, + &proxsensor_attr_group, + &kbdlang_attr_group, + &dprc_attr_group, + &tpacpi_attr_group, + NULL, +}; + +static const struct attribute_group *tpacpi_hwmon_groups[] = { + &thermal_attr_group, + &temp_label_attr_group, + &fan_attr_group, + NULL, +}; + +/**************************************************************************** + **************************************************************************** + * + * Platform drivers + * + **************************************************************************** + ****************************************************************************/ + +static struct platform_driver tpacpi_pdriver = { + .driver = { + .name = TPACPI_DRVR_NAME, + .pm = &tpacpi_pm, + .dev_groups = tpacpi_groups, + }, + .shutdown = tpacpi_shutdown_handler, +}; + +static struct platform_driver tpacpi_hwmon_pdriver = { + .driver = { + .name = TPACPI_HWMON_DRVR_NAME, + .dev_groups = tpacpi_hwmon_groups, + }, }; /**************************************************************************** @@ -11079,8 +11065,6 @@ static int __init set_ibm_param(const char *val, const struct kernel_param *kp) for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { ibm = ibms_init[i].data; - WARN_ON(ibm == NULL); - if (!ibm || !ibm->name) continue; @@ -11210,26 +11194,16 @@ static void thinkpad_acpi_module_exit(void) if (tpacpi_hwmon) hwmon_device_unregister(tpacpi_hwmon); - if (tpacpi_sensors_pdev) platform_device_unregister(tpacpi_sensors_pdev); if (tpacpi_pdev) platform_device_unregister(tpacpi_pdev); - - if (tp_features.sensors_pdrv_attrs_registered) - tpacpi_remove_driver_attributes(&tpacpi_hwmon_pdriver.driver); - if (tp_features.platform_drv_attrs_registered) - tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver); - if (tp_features.sensors_pdrv_registered) platform_driver_unregister(&tpacpi_hwmon_pdriver); - if (tp_features.platform_drv_registered) platform_driver_unregister(&tpacpi_pdriver); - if (proc_dir) remove_proc_entry(TPACPI_PROC_DIR, acpi_root_dir); - if (tpacpi_wq) destroy_workqueue(tpacpi_wq); @@ -11297,20 +11271,6 @@ static int __init thinkpad_acpi_module_init(void) } tp_features.sensors_pdrv_registered = 1; - ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver); - if (!ret) { - tp_features.platform_drv_attrs_registered = 1; - ret = tpacpi_create_driver_attributes( - &tpacpi_hwmon_pdriver.driver); - } - if (ret) { - pr_err("unable to create sysfs driver attributes\n"); - thinkpad_acpi_module_exit(); - return ret; - } - tp_features.sensors_pdrv_attrs_registered = 1; - - /* Device initialization */ tpacpi_pdev = platform_device_register_simple(TPACPI_DRVR_NAME, -1, NULL, 0); -- GitLab From 0f0ac158d28ff78e75c334e869b1cb8e69372a1f Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Sun, 24 Oct 2021 16:37:05 +1300 Subject: [PATCH 0034/1112] platform/x86: asus-wmi: Add support for custom fan curves Add support for custom fan curves found on some ASUS ROG laptops. These laptops have the ability to set a custom curve for the CPU and GPU fans via two ACPI methods. This patch adds two pwm attributes to the hwmon sysfs, pwm1 for CPU fan, pwm2 for GPU fan. Both are under the hwmon of the name `asus_custom_fan_curve`. There is no safety check of the set fan curves - this must be done in userspace. The fans have settings [1,2,3] under pwm_enable: 1. Enable and write settings out 2. Disable and use factory fan mode 3. Same as 2, additionally restoring default factory curve. Use of 2 means that the curve the user has set is still stored and won't be erased, but the laptop will be using its default auto-fan mode. Re-enabling the manual mode then activates the curves again. Notes: - pwm_enable = 0 is an invalid setting. - pwm is actually a percentage and is scaled on writing to device. Signed-off-by: Luke D. Jones Link: https://lore.kernel.org/r/20211024033705.5595-2-luke@ljones.dev Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/asus-wmi.c | 567 ++++++++++++++++++++- include/linux/platform_data/x86/asus-wmi.h | 2 + 2 files changed, 564 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 8f067ac4e9521..ab0c087d40cf8 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -106,8 +106,17 @@ module_param(fnlock_default, bool, 0444); #define WMI_EVENT_MASK 0xFFFF +#define FAN_CURVE_POINTS 8 +#define FAN_CURVE_BUF_LEN (FAN_CURVE_POINTS * 2) +#define FAN_CURVE_DEV_CPU 0x00 +#define FAN_CURVE_DEV_GPU 0x01 +/* Mask to determine if setting temperature or percentage */ +#define FAN_CURVE_PWM_MASK 0x04 + static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL }; +static int throttle_thermal_policy_write(struct asus_wmi *); + static bool ashs_present(void) { int i = 0; @@ -122,7 +131,8 @@ struct bios_args { u32 arg0; u32 arg1; u32 arg2; /* At least TUF Gaming series uses 3 dword input buffer. */ - u32 arg4; + u32 arg3; + u32 arg4; /* Some ROG laptops require a full 5 input args */ u32 arg5; } __packed; @@ -173,6 +183,13 @@ enum fan_type { FAN_TYPE_SPEC83, /* starting in Spec 8.3, use CPU_FAN_CTRL */ }; +struct fan_curve_data { + bool enabled; + u32 device_id; + u8 temps[FAN_CURVE_POINTS]; + u8 percents[FAN_CURVE_POINTS]; +}; + struct asus_wmi { int dsts_id; int spec; @@ -220,6 +237,10 @@ struct asus_wmi { bool throttle_thermal_policy_available; u8 throttle_thermal_policy_mode; + bool cpu_fan_curve_available; + bool gpu_fan_curve_available; + struct fan_curve_data custom_fan_curves[2]; + struct platform_profile_handler platform_profile_handler; bool platform_profile_support; @@ -285,6 +306,103 @@ int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval) } EXPORT_SYMBOL_GPL(asus_wmi_evaluate_method); +static int asus_wmi_evaluate_method5(u32 method_id, + u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4, u32 *retval) +{ + struct bios_args args = { + .arg0 = arg0, + .arg1 = arg1, + .arg2 = arg2, + .arg3 = arg3, + .arg4 = arg4, + }; + struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + acpi_status status; + union acpi_object *obj; + u32 tmp = 0; + + status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id, + &input, &output); + + if (ACPI_FAILURE(status)) + return -EIO; + + obj = (union acpi_object *)output.pointer; + if (obj && obj->type == ACPI_TYPE_INTEGER) + tmp = (u32) obj->integer.value; + + if (retval) + *retval = tmp; + + kfree(obj); + + if (tmp == ASUS_WMI_UNSUPPORTED_METHOD) + return -ENODEV; + + return 0; +} + +/* + * Returns as an error if the method output is not a buffer. Typically this + * means that the method called is unsupported. + */ +static int asus_wmi_evaluate_method_buf(u32 method_id, + u32 arg0, u32 arg1, u8 *ret_buffer, size_t size) +{ + struct bios_args args = { + .arg0 = arg0, + .arg1 = arg1, + .arg2 = 0, + }; + struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + acpi_status status; + union acpi_object *obj; + int err = 0; + + status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id, + &input, &output); + + if (ACPI_FAILURE(status)) + return -EIO; + + obj = (union acpi_object *)output.pointer; + + switch (obj->type) { + case ACPI_TYPE_BUFFER: + if (obj->buffer.length > size) + err = -ENOSPC; + if (obj->buffer.length == 0) + err = -ENODATA; + + memcpy(ret_buffer, obj->buffer.pointer, obj->buffer.length); + break; + case ACPI_TYPE_INTEGER: + err = (u32)obj->integer.value; + + if (err == ASUS_WMI_UNSUPPORTED_METHOD) + err = -ENODEV; + /* + * At least one method returns a 0 with no buffer if no arg + * is provided, such as ASUS_WMI_DEVID_CPU_FAN_CURVE + */ + if (err == 0) + err = -ENODATA; + break; + default: + err = -ENODATA; + break; + } + + kfree(obj); + + if (err) + return err; + + return 0; +} + static int asus_wmi_evaluate_method_agfn(const struct acpi_buffer args) { struct acpi_buffer input; @@ -1806,6 +1924,13 @@ static ssize_t pwm1_enable_store(struct device *dev, } asus->fan_pwm_mode = state; + + /* Must set to disabled if mode is toggled */ + if (asus->cpu_fan_curve_available) + asus->custom_fan_curves[FAN_CURVE_DEV_CPU].enabled = false; + if (asus->gpu_fan_curve_available) + asus->custom_fan_curves[FAN_CURVE_DEV_GPU].enabled = false; + return count; } @@ -1953,9 +2078,9 @@ static int fan_boost_mode_check_present(struct asus_wmi *asus) static int fan_boost_mode_write(struct asus_wmi *asus) { - int err; - u8 value; u32 retval; + u8 value; + int err; value = asus->fan_boost_mode; @@ -2013,10 +2138,10 @@ static ssize_t fan_boost_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int result; - u8 new_mode; struct asus_wmi *asus = dev_get_drvdata(dev); u8 mask = asus->fan_boost_mode_mask; + u8 new_mode; + int result; result = kstrtou8(buf, 10, &new_mode); if (result < 0) { @@ -2043,6 +2168,426 @@ static ssize_t fan_boost_mode_store(struct device *dev, // Fan boost mode: 0 - normal, 1 - overboost, 2 - silent static DEVICE_ATTR_RW(fan_boost_mode); +/* Custom fan curves **********************************************************/ + +static void fan_curve_copy_from_buf(struct fan_curve_data *data, u8 *buf) +{ + int i; + + for (i = 0; i < FAN_CURVE_POINTS; i++) { + data->temps[i] = buf[i]; + } + + for (i = 0; i < FAN_CURVE_POINTS; i++) { + data->percents[i] = + 255 * buf[i + FAN_CURVE_POINTS] / 100; + } +} + +static int fan_curve_get_factory_default(struct asus_wmi *asus, u32 fan_dev) +{ + struct fan_curve_data *curves; + u8 buf[FAN_CURVE_BUF_LEN]; + int fan_idx = 0; + u8 mode = 0; + int err; + + if (asus->throttle_thermal_policy_available) + mode = asus->throttle_thermal_policy_mode; + /* DEVID_PU_FAN_CURVE is switched for OVERBOOST vs SILENT */ + if (mode == 2) + mode = 1; + else if (mode == 1) + mode = 2; + + if (fan_dev == ASUS_WMI_DEVID_GPU_FAN_CURVE) + fan_idx = FAN_CURVE_DEV_GPU; + + curves = &asus->custom_fan_curves[fan_idx]; + err = asus_wmi_evaluate_method_buf(asus->dsts_id, fan_dev, mode, buf, + FAN_CURVE_BUF_LEN); + if (err) + return err; + + fan_curve_copy_from_buf(curves, buf); + curves->device_id = fan_dev; + + return 0; +} + +/* Check if capability exists, and populate defaults */ +static int fan_curve_check_present(struct asus_wmi *asus, bool *available, + u32 fan_dev) +{ + int err; + + *available = false; + + err = fan_curve_get_factory_default(asus, fan_dev); + if (err) { + if (err == -ENODEV) + return 0; + return err; + } + + *available = true; + return 0; +} + +/* Determine which fan the attribute is for if SENSOR_ATTR */ +static struct fan_curve_data *fan_curve_attr_select(struct asus_wmi *asus, + struct device_attribute *attr) +{ + int index = to_sensor_dev_attr(attr)->index; + + return &asus->custom_fan_curves[index & FAN_CURVE_DEV_GPU]; +} + +/* Determine which fan the attribute is for if SENSOR_ATTR_2 */ +static struct fan_curve_data *fan_curve_attr_2_select(struct asus_wmi *asus, + struct device_attribute *attr) +{ + int nr = to_sensor_dev_attr_2(attr)->nr; + + return &asus->custom_fan_curves[nr & FAN_CURVE_DEV_GPU]; +} + +static ssize_t fan_curve_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute_2 *dev_attr = to_sensor_dev_attr_2(attr); + struct asus_wmi *asus = dev_get_drvdata(dev); + struct fan_curve_data *data; + int value, index, nr; + + data = fan_curve_attr_2_select(asus, attr); + index = dev_attr->index; + nr = dev_attr->nr; + + if (nr & FAN_CURVE_PWM_MASK) + value = data->percents[index]; + else + value = data->temps[index]; + + return sysfs_emit(buf, "%d\n", value); +} + +/* + * "fan_dev" is the related WMI method such as ASUS_WMI_DEVID_CPU_FAN_CURVE. + */ +static int fan_curve_write(struct asus_wmi *asus, + struct fan_curve_data *data) +{ + u32 arg1 = 0, arg2 = 0, arg3 = 0, arg4 = 0; + u8 *percents = data->percents; + u8 *temps = data->temps; + int ret, i, shift = 0; + + if (!data->enabled) + return 0; + + for (i = 0; i < FAN_CURVE_POINTS / 2; i++) { + arg1 += (temps[i]) << shift; + arg2 += (temps[i + 4]) << shift; + /* Scale to percentage for device */ + arg3 += (100 * percents[i] / 255) << shift; + arg4 += (100 * percents[i + 4] / 255) << shift; + shift += 8; + } + + return asus_wmi_evaluate_method5(ASUS_WMI_METHODID_DEVS, + data->device_id, + arg1, arg2, arg3, arg4, &ret); +} + +static ssize_t fan_curve_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct sensor_device_attribute_2 *dev_attr = to_sensor_dev_attr_2(attr); + struct asus_wmi *asus = dev_get_drvdata(dev); + struct fan_curve_data *data; + u8 value; + int err; + + int pwm = dev_attr->nr & FAN_CURVE_PWM_MASK; + int index = dev_attr->index; + + data = fan_curve_attr_2_select(asus, attr); + + err = kstrtou8(buf, 10, &value); + if (err < 0) + return err; + + if (pwm) { + data->percents[index] = value; + } else { + data->temps[index] = value; + } + + /* + * Mark as disabled so the user has to explicitly enable to apply a + * changed fan curve. This prevents potential lockups from writing out + * many changes as one-write-per-change. + */ + data->enabled = false; + + return count; +} + +static ssize_t fan_curve_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct asus_wmi *asus = dev_get_drvdata(dev); + struct fan_curve_data *data; + int out = 2; + + data = fan_curve_attr_select(asus, attr); + + if (data->enabled) + out = 1; + + return sysfs_emit(buf, "%d\n", out); +} + +static ssize_t fan_curve_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct asus_wmi *asus = dev_get_drvdata(dev); + struct fan_curve_data *data; + int value, err; + + data = fan_curve_attr_select(asus, attr); + + err = kstrtoint(buf, 10, &value); + if (err < 0) + return err; + + switch (value) { + case 1: + data->enabled = true; + break; + case 2: + data->enabled = false; + break; + /* + * Auto + reset the fan curve data to defaults. Make it an explicit + * option so that users don't accidentally overwrite a set fan curve. + */ + case 3: + err = fan_curve_get_factory_default(asus, data->device_id); + if (err) + return err; + data->enabled = false; + break; + default: + return -EINVAL; + }; + + if (data->enabled) { + err = fan_curve_write(asus, data); + if (err) + return err; + } else { + /* + * For machines with throttle this is the only way to reset fans + * to default mode of operation (does not erase curve data). + */ + if (asus->throttle_thermal_policy_available) { + err = throttle_thermal_policy_write(asus); + if (err) + return err; + /* Similar is true for laptops with this fan */ + } else if (asus->fan_type == FAN_TYPE_SPEC83) { + err = asus_fan_set_auto(asus); + if (err) + return err; + } else { + /* Safeguard against fautly ACPI tables */ + err = fan_curve_get_factory_default(asus, data->device_id); + if (err) + return err; + err = fan_curve_write(asus, data); + if (err) + return err; + } + } + return count; +} + +/* CPU */ +static SENSOR_DEVICE_ATTR_RW(pwm1_enable, fan_curve_enable, FAN_CURVE_DEV_CPU); +static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point1_temp, fan_curve, + FAN_CURVE_DEV_CPU, 0); +static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point2_temp, fan_curve, + FAN_CURVE_DEV_CPU, 1); +static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point3_temp, fan_curve, + FAN_CURVE_DEV_CPU, 2); +static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point4_temp, fan_curve, + FAN_CURVE_DEV_CPU, 3); +static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point5_temp, fan_curve, + FAN_CURVE_DEV_CPU, 4); +static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point6_temp, fan_curve, + FAN_CURVE_DEV_CPU, 5); +static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point7_temp, fan_curve, + FAN_CURVE_DEV_CPU, 6); +static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point8_temp, fan_curve, + FAN_CURVE_DEV_CPU, 7); + +static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point1_pwm, fan_curve, + FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 0); +static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point2_pwm, fan_curve, + FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 1); +static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point3_pwm, fan_curve, + FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 2); +static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point4_pwm, fan_curve, + FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 3); +static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point5_pwm, fan_curve, + FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 4); +static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point6_pwm, fan_curve, + FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 5); +static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point7_pwm, fan_curve, + FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 6); +static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point8_pwm, fan_curve, + FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 7); + +/* GPU */ +static SENSOR_DEVICE_ATTR_RW(pwm2_enable, fan_curve_enable, FAN_CURVE_DEV_GPU); +static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point1_temp, fan_curve, + FAN_CURVE_DEV_GPU, 0); +static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point2_temp, fan_curve, + FAN_CURVE_DEV_GPU, 1); +static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point3_temp, fan_curve, + FAN_CURVE_DEV_GPU, 2); +static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point4_temp, fan_curve, + FAN_CURVE_DEV_GPU, 3); +static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point5_temp, fan_curve, + FAN_CURVE_DEV_GPU, 4); +static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point6_temp, fan_curve, + FAN_CURVE_DEV_GPU, 5); +static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point7_temp, fan_curve, + FAN_CURVE_DEV_GPU, 6); +static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point8_temp, fan_curve, + FAN_CURVE_DEV_GPU, 7); + +static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point1_pwm, fan_curve, + FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 0); +static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point2_pwm, fan_curve, + FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 1); +static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point3_pwm, fan_curve, + FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 2); +static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point4_pwm, fan_curve, + FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 3); +static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point5_pwm, fan_curve, + FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 4); +static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point6_pwm, fan_curve, + FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 5); +static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point7_pwm, fan_curve, + FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 6); +static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point8_pwm, fan_curve, + FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 7); + +static struct attribute *asus_fan_curve_attr[] = { + /* CPU */ + &sensor_dev_attr_pwm1_enable.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point5_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point6_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point7_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point8_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point5_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point6_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point7_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point8_pwm.dev_attr.attr, + /* GPU */ + &sensor_dev_attr_pwm2_enable.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point3_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point4_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point5_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point6_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point7_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point8_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point3_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point4_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point5_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point6_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point7_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point8_pwm.dev_attr.attr, + NULL +}; + +static umode_t asus_fan_curve_is_visible(struct kobject *kobj, + struct attribute *attr, int idx) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct asus_wmi *asus = dev_get_drvdata(dev->parent); + + /* + * Check the char instead of casting attr as there are two attr types + * involved here (attr1 and attr2) + */ + if (asus->cpu_fan_curve_available && attr->name[3] == '1') + return 0644; + + if (asus->gpu_fan_curve_available && attr->name[3] == '2') + return 0644; + + return 0; +} + +static const struct attribute_group asus_fan_curve_attr_group = { + .is_visible = asus_fan_curve_is_visible, + .attrs = asus_fan_curve_attr, +}; +__ATTRIBUTE_GROUPS(asus_fan_curve_attr); + +/* + * Must be initialised after throttle_thermal_policy_check_present() as + * we check the status of throttle_thermal_policy_available during init. + */ +static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus) +{ + struct device *dev = &asus->platform_device->dev; + struct device *hwmon; + int err; + + err = fan_curve_check_present(asus, &asus->cpu_fan_curve_available, + ASUS_WMI_DEVID_CPU_FAN_CURVE); + if (err) + return err; + + err = fan_curve_check_present(asus, &asus->gpu_fan_curve_available, + ASUS_WMI_DEVID_GPU_FAN_CURVE); + if (err) + return err; + + if (!asus->cpu_fan_curve_available && !asus->gpu_fan_curve_available) + return 0; + + hwmon = devm_hwmon_device_register_with_groups( + dev, "asus_custom_fan_curve", asus, asus_fan_curve_attr_groups); + + if (IS_ERR(hwmon)) { + dev_err(dev, + "Could not register asus_custom_fan_curve device\n"); + return PTR_ERR(hwmon); + } + + return 0; +} + /* Throttle thermal policy ****************************************************/ static int throttle_thermal_policy_check_present(struct asus_wmi *asus) @@ -2092,6 +2637,12 @@ static int throttle_thermal_policy_write(struct asus_wmi *asus) return -EIO; } + /* Must set to disabled if mode is toggled */ + if (asus->cpu_fan_curve_available) + asus->custom_fan_curves[FAN_CURVE_DEV_CPU].enabled = false; + if (asus->gpu_fan_curve_available) + asus->custom_fan_curves[FAN_CURVE_DEV_GPU].enabled = false; + return 0; } @@ -3035,6 +3586,10 @@ static int asus_wmi_add(struct platform_device *pdev) if (err) goto fail_hwmon; + err = asus_wmi_custom_fan_curve_init(asus); + if (err) + goto fail_custom_fan_curve; + err = asus_wmi_led_init(asus); if (err) goto fail_leds; @@ -3106,6 +3661,7 @@ fail_input: asus_wmi_sysfs_exit(asus->platform_device); fail_sysfs: fail_throttle_thermal_policy: +fail_custom_fan_curve: fail_platform_profile_setup: if (asus->platform_profile_support) platform_profile_remove(); @@ -3131,6 +3687,7 @@ static int asus_wmi_remove(struct platform_device *device) asus_wmi_debugfs_exit(asus); asus_wmi_sysfs_exit(asus->platform_device); asus_fan_set_auto(asus); + throttle_thermal_policy_set_default(asus); asus_wmi_battery_exit(asus); if (asus->platform_profile_support) diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h index 17dc5cb6f3f29..a571b47ff362f 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -77,6 +77,8 @@ #define ASUS_WMI_DEVID_THERMAL_CTRL 0x00110011 #define ASUS_WMI_DEVID_FAN_CTRL 0x00110012 /* deprecated */ #define ASUS_WMI_DEVID_CPU_FAN_CTRL 0x00110013 +#define ASUS_WMI_DEVID_CPU_FAN_CURVE 0x00110024 +#define ASUS_WMI_DEVID_GPU_FAN_CURVE 0x00110025 /* Power */ #define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012 -- GitLab From 38543b72fbe52b7eec0dedd420d80a06c652d8e4 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 28 Oct 2021 02:22:41 +0200 Subject: [PATCH 0035/1112] platform/surface: aggregator: Make client device removal more generic Currently, there are similar functions defined in the Aggregator Registry and the controller core. Make client device removal more generic and export it. We can then use this function later on to remove client devices from device hubs as well as the controller and avoid re-defining similar things. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20211028002243.1586083-2-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/aggregator/bus.c | 24 ++++++++-------------- drivers/platform/surface/aggregator/bus.h | 3 --- drivers/platform/surface/aggregator/core.c | 3 ++- include/linux/surface_aggregator/device.h | 9 ++++++++ 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/drivers/platform/surface/aggregator/bus.c b/drivers/platform/surface/aggregator/bus.c index 0a40dd9c94ed7..abbbb5b08b073 100644 --- a/drivers/platform/surface/aggregator/bus.c +++ b/drivers/platform/surface/aggregator/bus.c @@ -374,27 +374,19 @@ static int ssam_remove_device(struct device *dev, void *_data) } /** - * ssam_controller_remove_clients() - Remove SSAM client devices registered as - * direct children under the given controller. - * @ctrl: The controller to remove all direct clients for. + * ssam_remove_clients() - Remove SSAM client devices registered as direct + * children under the given parent device. + * @dev: The (parent) device to remove all direct clients for. * - * Remove all SSAM client devices registered as direct children under the - * given controller. Note that this only accounts for direct children of the - * controller device. This does not take care of any client devices where the - * parent device has been manually set before calling ssam_device_add. Refer - * to ssam_device_add()/ssam_device_remove() for more details on those cases. - * - * To avoid new devices being added in parallel to this call, the main - * controller lock (not statelock) must be held during this (and if - * necessary, any subsequent deinitialization) call. + * Remove all SSAM client devices registered as direct children under the given + * device. Note that this only accounts for direct children of the device. + * Refer to ssam_device_add()/ssam_device_remove() for more details. */ -void ssam_controller_remove_clients(struct ssam_controller *ctrl) +void ssam_remove_clients(struct device *dev) { - struct device *dev; - - dev = ssam_controller_device(ctrl); device_for_each_child_reverse(dev, NULL, ssam_remove_device); } +EXPORT_SYMBOL_GPL(ssam_remove_clients); /** * ssam_bus_register() - Register and set-up the SSAM client device bus. diff --git a/drivers/platform/surface/aggregator/bus.h b/drivers/platform/surface/aggregator/bus.h index ed032c2cbdb2d..6964ee84e79c7 100644 --- a/drivers/platform/surface/aggregator/bus.h +++ b/drivers/platform/surface/aggregator/bus.h @@ -12,14 +12,11 @@ #ifdef CONFIG_SURFACE_AGGREGATOR_BUS -void ssam_controller_remove_clients(struct ssam_controller *ctrl); - int ssam_bus_register(void); void ssam_bus_unregister(void); #else /* CONFIG_SURFACE_AGGREGATOR_BUS */ -static inline void ssam_controller_remove_clients(struct ssam_controller *ctrl) {} static inline int ssam_bus_register(void) { return 0; } static inline void ssam_bus_unregister(void) {} diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c index c61bbeeec2dfd..d384d36098c27 100644 --- a/drivers/platform/surface/aggregator/core.c +++ b/drivers/platform/surface/aggregator/core.c @@ -22,6 +22,7 @@ #include #include +#include #include "bus.h" #include "controller.h" @@ -735,7 +736,7 @@ static void ssam_serial_hub_remove(struct serdev_device *serdev) ssam_controller_lock(ctrl); /* Remove all client devices. */ - ssam_controller_remove_clients(ctrl); + ssam_remove_clients(&serdev->dev); /* Act as if suspending to silence events. */ status = ssam_ctrl_notif_display_off(ctrl); diff --git a/include/linux/surface_aggregator/device.h b/include/linux/surface_aggregator/device.h index f636c5310321f..cc257097eb05f 100644 --- a/include/linux/surface_aggregator/device.h +++ b/include/linux/surface_aggregator/device.h @@ -319,6 +319,15 @@ void ssam_device_driver_unregister(struct ssam_device_driver *d); ssam_device_driver_unregister) +/* -- Helpers for controller and hub devices. ------------------------------- */ + +#ifdef CONFIG_SURFACE_AGGREGATOR_BUS +void ssam_remove_clients(struct device *dev); +#else /* CONFIG_SURFACE_AGGREGATOR_BUS */ +static inline void ssam_remove_clients(struct device *dev) {} +#endif /* CONFIG_SURFACE_AGGREGATOR_BUS */ + + /* -- Helpers for client-device requests. ----------------------------------- */ /** -- GitLab From acff7091df0eae74fe40917b961588a444d1d60e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 28 Oct 2021 02:22:42 +0200 Subject: [PATCH 0036/1112] platform/surface: aggregator_registry: Use generic client removal function Use generic client removal function introduced in the previous commit instead of defining our own one. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20211028002243.1586083-3-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- .../surface/surface_aggregator_registry.c | 24 ++++--------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c index e70f4c63554e0..f6c639342b9db 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -258,20 +258,6 @@ static int ssam_uid_from_string(const char *str, struct ssam_device_uid *uid) return 0; } -static int ssam_hub_remove_devices_fn(struct device *dev, void *data) -{ - if (!is_ssam_device(dev)) - return 0; - - ssam_device_remove(to_ssam_device(dev)); - return 0; -} - -static void ssam_hub_remove_devices(struct device *parent) -{ - device_for_each_child_reverse(parent, NULL, ssam_hub_remove_devices_fn); -} - static int ssam_hub_add_device(struct device *parent, struct ssam_controller *ctrl, struct fwnode_handle *node) { @@ -317,7 +303,7 @@ static int ssam_hub_add_devices(struct device *parent, struct ssam_controller *c return 0; err: - ssam_hub_remove_devices(parent); + ssam_remove_clients(parent); return status; } @@ -414,7 +400,7 @@ static void ssam_base_hub_update_workfn(struct work_struct *work) if (hub->state == SSAM_BASE_HUB_CONNECTED) status = ssam_hub_add_devices(&hub->sdev->dev, hub->sdev->ctrl, node); else - ssam_hub_remove_devices(&hub->sdev->dev); + ssam_remove_clients(&hub->sdev->dev); if (status) dev_err(&hub->sdev->dev, "failed to update base-hub devices: %d\n", status); @@ -496,7 +482,7 @@ static int ssam_base_hub_probe(struct ssam_device *sdev) err: ssam_notifier_unregister(sdev->ctrl, &hub->notif); cancel_delayed_work_sync(&hub->update_work); - ssam_hub_remove_devices(&sdev->dev); + ssam_remove_clients(&sdev->dev); return status; } @@ -508,7 +494,7 @@ static void ssam_base_hub_remove(struct ssam_device *sdev) ssam_notifier_unregister(sdev->ctrl, &hub->notif); cancel_delayed_work_sync(&hub->update_work); - ssam_hub_remove_devices(&sdev->dev); + ssam_remove_clients(&sdev->dev); } static const struct ssam_device_id ssam_base_hub_match[] = { @@ -625,7 +611,7 @@ static int ssam_platform_hub_remove(struct platform_device *pdev) { const struct software_node **nodes = platform_get_drvdata(pdev); - ssam_hub_remove_devices(&pdev->dev); + ssam_remove_clients(&pdev->dev); set_secondary_fwnode(&pdev->dev, NULL); software_node_unregister_node_group(nodes); return 0; -- GitLab From b3c3d5881e0ede0526fc996c98949cffac697295 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 28 Oct 2021 02:22:43 +0200 Subject: [PATCH 0037/1112] platform/surface: aggregator_registry: Rename device registration function Rename the device registration function to better align names with the newly introduced device removal function. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20211028002243.1586083-4-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/surface_aggregator_registry.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c index f6c639342b9db..ce2bd88feeaa8 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -283,8 +283,8 @@ static int ssam_hub_add_device(struct device *parent, struct ssam_controller *ct return status; } -static int ssam_hub_add_devices(struct device *parent, struct ssam_controller *ctrl, - struct fwnode_handle *node) +static int ssam_hub_register_clients(struct device *parent, struct ssam_controller *ctrl, + struct fwnode_handle *node) { struct fwnode_handle *child; int status; @@ -398,7 +398,7 @@ static void ssam_base_hub_update_workfn(struct work_struct *work) hub->state = state; if (hub->state == SSAM_BASE_HUB_CONNECTED) - status = ssam_hub_add_devices(&hub->sdev->dev, hub->sdev->ctrl, node); + status = ssam_hub_register_clients(&hub->sdev->dev, hub->sdev->ctrl, node); else ssam_remove_clients(&hub->sdev->dev); @@ -597,7 +597,7 @@ static int ssam_platform_hub_probe(struct platform_device *pdev) set_secondary_fwnode(&pdev->dev, root); - status = ssam_hub_add_devices(&pdev->dev, ctrl, root); + status = ssam_hub_register_clients(&pdev->dev, ctrl, root); if (status) { set_secondary_fwnode(&pdev->dev, NULL); software_node_unregister_node_group(nodes); -- GitLab From f8ae9bb51670ea74b92102e5befc6223c0b45041 Mon Sep 17 00:00:00 2001 From: David Heidelberg Date: Thu, 28 Oct 2021 18:50:08 +0200 Subject: [PATCH 0038/1112] dt-bindings: power: reset: gpio-poweroff: Convert txt bindings to yaml Convert power-off action connected to the GPIO documentation to the YAML syntax. Signed-off-by: David Heidelberg Reviewed-by: Rob Herring Signed-off-by: Sebastian Reichel --- .../bindings/power/reset/gpio-poweroff.txt | 41 ------------- .../bindings/power/reset/gpio-poweroff.yaml | 59 +++++++++++++++++++ 2 files changed, 59 insertions(+), 41 deletions(-) delete mode 100644 Documentation/devicetree/bindings/power/reset/gpio-poweroff.txt create mode 100644 Documentation/devicetree/bindings/power/reset/gpio-poweroff.yaml diff --git a/Documentation/devicetree/bindings/power/reset/gpio-poweroff.txt b/Documentation/devicetree/bindings/power/reset/gpio-poweroff.txt deleted file mode 100644 index 3e56c1b34a4c9..0000000000000 --- a/Documentation/devicetree/bindings/power/reset/gpio-poweroff.txt +++ /dev/null @@ -1,41 +0,0 @@ -Driver a GPIO line that can be used to turn the power off. - -The driver supports both level triggered and edge triggered power off. -At driver load time, the driver will request the given gpio line and -install a handler to power off the system. If the optional properties -'input' is not found, the GPIO line will be driven in the inactive -state. Otherwise its configured as an input. - -When the power-off handler is called, the gpio is configured as an -output, and drive active, so triggering a level triggered power off -condition. This will also cause an inactive->active edge condition, so -triggering positive edge triggered power off. After a delay of 100ms, -the GPIO is set to inactive, thus causing an active->inactive edge, -triggering negative edge triggered power off. After another 100ms -delay the GPIO is driver active again. If the power is still on and -the CPU still running after a 3000ms delay, a WARN_ON(1) is emitted. - -Required properties: -- compatible : should be "gpio-poweroff". -- gpios : The GPIO to set high/low, see "gpios property" in - Documentation/devicetree/bindings/gpio/gpio.txt. If the pin should be - low to power down the board set it to "Active Low", otherwise set - gpio to "Active High". - -Optional properties: -- input : Initially configure the GPIO line as an input. Only reconfigure - it to an output when the power-off handler is called. If this optional - property is not specified, the GPIO is initialized as an output in its - inactive state. -- active-delay-ms: Delay (default 100) to wait after driving gpio active -- inactive-delay-ms: Delay (default 100) to wait after driving gpio inactive -- timeout-ms: Time to wait before asserting a WARN_ON(1). If nothing is - specified, 3000 ms is used. - -Examples: - -gpio-poweroff { - compatible = "gpio-poweroff"; - gpios = <&gpio 4 0>; - timeout-ms = <3000>; -}; diff --git a/Documentation/devicetree/bindings/power/reset/gpio-poweroff.yaml b/Documentation/devicetree/bindings/power/reset/gpio-poweroff.yaml new file mode 100644 index 0000000000000..45d66c7751156 --- /dev/null +++ b/Documentation/devicetree/bindings/power/reset/gpio-poweroff.yaml @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: (GPL-2.0-only or BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/reset/gpio-poweroff.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: GPIO controlled power off + +maintainers: + - Sebastian Reichel + +description: > + System power off support via a GPIO line. When a shutdown is + executed the operating system is expected to switch the GPIO + from inactive to active. After a delay (active-delay-ms) it + is expected to be switched back to inactive. After another + delay (inactive-delay-ms) it is configured as active again. + Finally the operating system assumes the power off failed if + the system is still running after waiting some time (timeout-ms). + +properties: + compatible: + const: gpio-poweroff + + gpios: + maxItems: 1 + + input: + type: boolean + description: > + Initially configure the GPIO line as an input. Only reconfigure + it to an output when the power-off sequence is initiated. If this optional + property is not specified, the GPIO is initialized as an output in its inactive state. + + active-delay-ms: + default: 100 + description: Delay to wait after driving gpio active + + inactive-delay-ms: + default: 100 + description: Delay to wait after driving gpio inactive + + timeout-ms: + default: 3000 + description: Time to wait before assuming the power off sequence failed. + +required: + - compatible + - gpios + +additionalProperties: false + +examples: + - | + gpio-poweroff { + compatible = "gpio-poweroff"; + gpios = <&gpio 4 0>; + timeout-ms = <3000>; + }; -- GitLab From 4950486cd86f450baa847bfc13557244d834526c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 16 Nov 2021 12:09:51 +0100 Subject: [PATCH 0039/1112] regulator: da9121: Emit only one error message in .remove() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When an i2c remove callback fails, the i2c core emits a generic error message and still removes the device. Apart from the message there the return value isn't further used. So don't return an error code after having already emitted a driver specific warning about the problem to prevent two messages about the same issue. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20211116110951.1213566-1-u.kleine-koenig@pengutronix.de Signed-off-by: Mark Brown --- drivers/regulator/da9121-regulator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/da9121-regulator.c b/drivers/regulator/da9121-regulator.c index e669250902580..a5a83b772a854 100644 --- a/drivers/regulator/da9121-regulator.c +++ b/drivers/regulator/da9121-regulator.c @@ -1065,7 +1065,7 @@ static int da9121_i2c_remove(struct i2c_client *i2c) { struct da9121 *chip = i2c_get_clientdata(i2c); const int mask_all[4] = { 0xFF, 0xFF, 0xFF, 0xFF }; - int ret = 0; + int ret; free_irq(chip->chip_irq, chip); cancel_delayed_work_sync(&chip->work); @@ -1073,7 +1073,7 @@ static int da9121_i2c_remove(struct i2c_client *i2c) ret = regmap_bulk_write(chip->regmap, DA9121_REG_SYS_MASK_0, mask_all, 4); if (ret != 0) dev_err(chip->dev, "Failed to set IRQ masks: %d\n", ret); - return ret; + return 0; } static const struct i2c_device_id da9121_i2c_id[] = { -- GitLab From a62bacba81c477a6fd8f15da593ad02305a3d6da Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Mon, 15 Nov 2021 21:19:11 +0300 Subject: [PATCH 0040/1112] spi: dw: Add a symbols namespace for the core module The exported from the DW SPI driver core/DMA symbols are only used by the spi-dw-{mmio,pci,bt1}.o objects. Add these symbols to a separate namespace then and make sure the depended modules have it imported. Signed-off-by: Serge Semin Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211115181917.7521-2-Sergey.Semin@baikalelectronics.ru Signed-off-by: Mark Brown --- drivers/spi/spi-dw-bt1.c | 1 + drivers/spi/spi-dw-core.c | 14 +++++++------- drivers/spi/spi-dw-dma.c | 5 +++-- drivers/spi/spi-dw-mmio.c | 1 + drivers/spi/spi-dw-pci.c | 1 + 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/spi/spi-dw-bt1.c b/drivers/spi/spi-dw-bt1.c index 5be6b7b80c21b..ac7e4f30d1dad 100644 --- a/drivers/spi/spi-dw-bt1.c +++ b/drivers/spi/spi-dw-bt1.c @@ -339,3 +339,4 @@ module_platform_driver(dw_spi_bt1_driver); MODULE_AUTHOR("Serge Semin "); MODULE_DESCRIPTION("Baikal-T1 System Boot SPI Controller driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(SPI_DW_CORE); diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c index a305074c482e8..a14940403ab4e 100644 --- a/drivers/spi/spi-dw-core.c +++ b/drivers/spi/spi-dw-core.c @@ -106,7 +106,7 @@ void dw_spi_set_cs(struct spi_device *spi, bool enable) else dw_writel(dws, DW_SPI_SER, 0); } -EXPORT_SYMBOL_GPL(dw_spi_set_cs); +EXPORT_SYMBOL_NS_GPL(dw_spi_set_cs, SPI_DW_CORE); /* Return the max entries we can fill into tx fifo */ static inline u32 tx_max(struct dw_spi *dws) @@ -210,7 +210,7 @@ int dw_spi_check_status(struct dw_spi *dws, bool raw) return ret; } -EXPORT_SYMBOL_GPL(dw_spi_check_status); +EXPORT_SYMBOL_NS_GPL(dw_spi_check_status, SPI_DW_CORE); static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws) { @@ -345,7 +345,7 @@ void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi, dws->cur_rx_sample_dly = chip->rx_sample_dly; } } -EXPORT_SYMBOL_GPL(dw_spi_update_config); +EXPORT_SYMBOL_NS_GPL(dw_spi_update_config, SPI_DW_CORE); static void dw_spi_irq_setup(struct dw_spi *dws) { @@ -945,7 +945,7 @@ err_free_master: spi_controller_put(master); return ret; } -EXPORT_SYMBOL_GPL(dw_spi_add_host); +EXPORT_SYMBOL_NS_GPL(dw_spi_add_host, SPI_DW_CORE); void dw_spi_remove_host(struct dw_spi *dws) { @@ -960,7 +960,7 @@ void dw_spi_remove_host(struct dw_spi *dws) free_irq(dws->irq, dws->master); } -EXPORT_SYMBOL_GPL(dw_spi_remove_host); +EXPORT_SYMBOL_NS_GPL(dw_spi_remove_host, SPI_DW_CORE); int dw_spi_suspend_host(struct dw_spi *dws) { @@ -973,14 +973,14 @@ int dw_spi_suspend_host(struct dw_spi *dws) spi_shutdown_chip(dws); return 0; } -EXPORT_SYMBOL_GPL(dw_spi_suspend_host); +EXPORT_SYMBOL_NS_GPL(dw_spi_suspend_host, SPI_DW_CORE); int dw_spi_resume_host(struct dw_spi *dws) { spi_hw_init(&dws->master->dev, dws); return spi_controller_resume(dws->master); } -EXPORT_SYMBOL_GPL(dw_spi_resume_host); +EXPORT_SYMBOL_NS_GPL(dw_spi_resume_host, SPI_DW_CORE); MODULE_AUTHOR("Feng Tang "); MODULE_DESCRIPTION("Driver for DesignWare SPI controller core"); diff --git a/drivers/spi/spi-dw-dma.c b/drivers/spi/spi-dw-dma.c index a09831c62192a..ca199eee0f132 100644 --- a/drivers/spi/spi-dw-dma.c +++ b/drivers/spi/spi-dw-dma.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -638,7 +639,7 @@ void dw_spi_dma_setup_mfld(struct dw_spi *dws) { dws->dma_ops = &dw_spi_dma_mfld_ops; } -EXPORT_SYMBOL_GPL(dw_spi_dma_setup_mfld); +EXPORT_SYMBOL_NS_GPL(dw_spi_dma_setup_mfld, SPI_DW_CORE); static const struct dw_spi_dma_ops dw_spi_dma_generic_ops = { .dma_init = dw_spi_dma_init_generic, @@ -653,4 +654,4 @@ void dw_spi_dma_setup_generic(struct dw_spi *dws) { dws->dma_ops = &dw_spi_dma_generic_ops; } -EXPORT_SYMBOL_GPL(dw_spi_dma_setup_generic); +EXPORT_SYMBOL_NS_GPL(dw_spi_dma_setup_generic, SPI_DW_CORE); diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index 3379720cfcb8d..c3bacd5a2843d 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -377,3 +377,4 @@ module_platform_driver(dw_spi_mmio_driver); MODULE_AUTHOR("Jean-Hugues Deschenes "); MODULE_DESCRIPTION("Memory-mapped I/O interface driver for DW SPI Core"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(SPI_DW_CORE); diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c index 8a91cd58102f2..5552240fee55a 100644 --- a/drivers/spi/spi-dw-pci.c +++ b/drivers/spi/spi-dw-pci.c @@ -213,3 +213,4 @@ module_pci_driver(dw_spi_driver); MODULE_AUTHOR("Feng Tang "); MODULE_DESCRIPTION("PCI interface driver for DW SPI Core"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(SPI_DW_CORE); -- GitLab From 21b6b3809b840ad3d3f0689aac227929c04e9518 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Mon, 15 Nov 2021 21:19:12 +0300 Subject: [PATCH 0041/1112] spi: dw: Discard redundant DW SSI Frame Formats enumeration The dw_ssi_type enumeration describes the SPI frame formats the controller supports, like Motorola SPI, Texas Instruments SSP and National Semiconductors Microwire, that is the serial protocol utilized for the SPI-transfers. Depending on the DW SSI IP-core configuration the protocol could be either fixed or selectable. If it is changebale the protocol can be selected by means of the CTRL0.FRF field, which possible values encoded by the dw_ssi_type enumeration. Aside with the denoted enum the field values are also described by a set of SPI_FRF_{SPI,SSP,MICROWIRE} macros. Thus currently the DW SPI driver has got two entities describing the same data. Let's get rid of the enumeration one then, since first it hasn't been used as enumeration-type but merely as a parametrized values set and second that would unify the macro-based CSR read/write interface of the driver. While at it convert the macro names to be more descriptive about the protocols they represent. Signed-off-by: Serge Semin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211115181917.7521-3-Sergey.Semin@baikalelectronics.ru Signed-off-by: Mark Brown --- drivers/spi/spi-dw-core.c | 4 ++-- drivers/spi/spi-dw.h | 12 +++--------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c index a14940403ab4e..da6100fd185f8 100644 --- a/drivers/spi/spi-dw-core.c +++ b/drivers/spi/spi-dw-core.c @@ -273,7 +273,7 @@ static u32 dw_spi_prepare_cr0(struct dw_spi *dws, struct spi_device *spi) if (!(dws->caps & DW_SPI_CAP_DWC_SSI)) { /* CTRLR0[ 5: 4] Frame Format */ - cr0 |= SSI_MOTO_SPI << SPI_FRF_OFFSET; + cr0 |= SPI_FRF_MOTO_SPI << SPI_FRF_OFFSET; /* * SPI mode (SCPOL|SCPH) @@ -287,7 +287,7 @@ static u32 dw_spi_prepare_cr0(struct dw_spi *dws, struct spi_device *spi) cr0 |= ((spi->mode & SPI_LOOP) ? 1 : 0) << SPI_SRL_OFFSET; } else { /* CTRLR0[ 7: 6] Frame Format */ - cr0 |= SSI_MOTO_SPI << DWC_SSI_CTRLR0_FRF_OFFSET; + cr0 |= SPI_FRF_MOTO_SPI << DWC_SSI_CTRLR0_FRF_OFFSET; /* * SPI mode (SCPOL|SCPH) diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index b665e040862cc..467c342bfe56a 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -46,9 +46,9 @@ #define SPI_DFS32_OFFSET 16 #define SPI_FRF_OFFSET 4 -#define SPI_FRF_SPI 0x0 -#define SPI_FRF_SSP 0x1 -#define SPI_FRF_MICROWIRE 0x2 +#define SPI_FRF_MOTO_SPI 0x0 +#define SPI_FRF_TI_SSP 0x1 +#define SPI_FRF_NS_MICROWIRE 0x2 #define SPI_FRF_RESV 0x3 #define SPI_MODE_OFFSET 6 @@ -114,12 +114,6 @@ #define SPI_GET_BYTE(_val, _idx) \ ((_val) >> (BITS_PER_BYTE * (_idx)) & 0xff) -enum dw_ssi_type { - SSI_MOTO_SPI = 0, - SSI_TI_SSP, - SSI_NS_MICROWIRE, -}; - /* DW SPI capabilities */ #define DW_SPI_CAP_CS_OVERRIDE BIT(0) #define DW_SPI_CAP_KEEMBAY_MST BIT(1) -- GitLab From 725b0e3ea899ff1cb799756ade302e7bc13a8559 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Mon, 15 Nov 2021 21:19:13 +0300 Subject: [PATCH 0042/1112] spi: dw: Put the driver entities naming in order Mostly due to a long driver history it's methods and macro names look a bit messy. In particularly that concerns the code their prefixes. A biggest part of the driver functions and macros have got the dw_spi/DW_SPI prefixes. But there are some entities which have been just "spi_/SPI_"-prefixed. Especially that concerns the CSR and their fields macro definitions. It makes the code harder to comprehend since such methods and macros can be easily confused with the global SPI-subsystem exports. In this case the only possible way to more or less quickly distinguish one naming space from another is either by context or by the argument type, which most of the times isn't that easy anyway. In addition to that a new DW SSI IP-core support has been added in the framework of commit e539f435cb9c ("spi: dw: Add support for DesignWare DWC_ssi"), which introduced a new set or macro-prefixes to describe CTRLR0-specific fields and worsen the situation. Finally there are methods with no DW SPI driver-reference prefix at all, that make the code reading even harder. So in order to ease the driver hacking let's bring the code naming to a common base: 1) Each method is supposed to have "dw_spi_" prefix so to be easily distinguished from the kernel API, e.g. SPI-subsystem methods and macros. (Exception is the local implementation of the readl/writel methods since being just the regspace accessors.) 2) Each generically used macro should have DW_SPI_-prefix thus being easily comprehended as the local driver definition. 3) DW APB SSI and DW SSI specific macros should have prefixes as DW_PSSI_ and DW_HSSI_ respectively so referring to the system buses they support (APB and AHB similarly to the DT clocks naming like pclk, hclk). Signed-off-by: Serge Semin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211115181917.7521-4-Sergey.Semin@baikalelectronics.ru Signed-off-by: Mark Brown --- drivers/spi/spi-dw-bt1.c | 8 +-- drivers/spi/spi-dw-core.c | 138 ++++++++++++++++++------------------ drivers/spi/spi-dw-dma.c | 50 ++++++------- drivers/spi/spi-dw-mmio.c | 20 +++--- drivers/spi/spi-dw-pci.c | 59 ++++++++-------- drivers/spi/spi-dw.h | 145 +++++++++++++++++++------------------- 6 files changed, 211 insertions(+), 209 deletions(-) diff --git a/drivers/spi/spi-dw-bt1.c b/drivers/spi/spi-dw-bt1.c index ac7e4f30d1dad..c065534161237 100644 --- a/drivers/spi/spi-dw-bt1.c +++ b/drivers/spi/spi-dw-bt1.c @@ -123,7 +123,7 @@ static ssize_t dw_spi_bt1_dirmap_read(struct spi_mem_dirmap_desc *desc, len = min_t(size_t, len, dwsbt1->map_len - offs); /* Collect the controller configuration required by the operation */ - cfg.tmode = SPI_TMOD_EPROMREAD; + cfg.tmode = DW_SPI_CTRLR0_TMOD_EPROMREAD; cfg.dfs = 8; cfg.ndf = 4; cfg.freq = mem->spi->max_speed_hz; @@ -131,13 +131,13 @@ static ssize_t dw_spi_bt1_dirmap_read(struct spi_mem_dirmap_desc *desc, /* Make sure the corresponding CS is de-asserted on transmission */ dw_spi_set_cs(mem->spi, false); - spi_enable_chip(dws, 0); + dw_spi_enable_chip(dws, 0); dw_spi_update_config(dws, mem->spi, &cfg); - spi_umask_intr(dws, SPI_INT_RXFI); + dw_spi_umask_intr(dws, DW_SPI_INT_RXFI); - spi_enable_chip(dws, 1); + dw_spi_enable_chip(dws, 1); /* * Enable the transparent mode of the System Boot Controller. diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c index da6100fd185f8..57bbffe6d6f94 100644 --- a/drivers/spi/spi-dw-core.c +++ b/drivers/spi/spi-dw-core.c @@ -24,7 +24,7 @@ #endif /* Slave spi_device related */ -struct chip_data { +struct dw_spi_chip_data { u32 cr0; u32 rx_sample_dly; /* RX sample delay */ }; @@ -109,7 +109,7 @@ void dw_spi_set_cs(struct spi_device *spi, bool enable) EXPORT_SYMBOL_NS_GPL(dw_spi_set_cs, SPI_DW_CORE); /* Return the max entries we can fill into tx fifo */ -static inline u32 tx_max(struct dw_spi *dws) +static inline u32 dw_spi_tx_max(struct dw_spi *dws) { u32 tx_room, rxtx_gap; @@ -129,14 +129,14 @@ static inline u32 tx_max(struct dw_spi *dws) } /* Return the max entries we should read out of rx fifo */ -static inline u32 rx_max(struct dw_spi *dws) +static inline u32 dw_spi_rx_max(struct dw_spi *dws) { return min_t(u32, dws->rx_len, dw_readl(dws, DW_SPI_RXFLR)); } static void dw_writer(struct dw_spi *dws) { - u32 max = tx_max(dws); + u32 max = dw_spi_tx_max(dws); u32 txw = 0; while (max--) { @@ -157,7 +157,7 @@ static void dw_writer(struct dw_spi *dws) static void dw_reader(struct dw_spi *dws) { - u32 max = rx_max(dws); + u32 max = dw_spi_rx_max(dws); u32 rxw; while (max--) { @@ -186,24 +186,24 @@ int dw_spi_check_status(struct dw_spi *dws, bool raw) else irq_status = dw_readl(dws, DW_SPI_ISR); - if (irq_status & SPI_INT_RXOI) { + if (irq_status & DW_SPI_INT_RXOI) { dev_err(&dws->master->dev, "RX FIFO overflow detected\n"); ret = -EIO; } - if (irq_status & SPI_INT_RXUI) { + if (irq_status & DW_SPI_INT_RXUI) { dev_err(&dws->master->dev, "RX FIFO underflow detected\n"); ret = -EIO; } - if (irq_status & SPI_INT_TXOI) { + if (irq_status & DW_SPI_INT_TXOI) { dev_err(&dws->master->dev, "TX FIFO overflow detected\n"); ret = -EIO; } /* Generically handle the erroneous situation */ if (ret) { - spi_reset_chip(dws); + dw_spi_reset_chip(dws); if (dws->master->cur_msg) dws->master->cur_msg->status = ret; } @@ -230,7 +230,7 @@ static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws) */ dw_reader(dws); if (!dws->rx_len) { - spi_mask_intr(dws, 0xff); + dw_spi_mask_intr(dws, 0xff); spi_finalize_current_transfer(dws->master); } else if (dws->rx_len <= dw_readl(dws, DW_SPI_RXFTLR)) { dw_writel(dws, DW_SPI_RXFTLR, dws->rx_len - 1); @@ -241,10 +241,10 @@ static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws) * disabled after the data transmission is finished so not to * have the TXE IRQ flood at the final stage of the transfer. */ - if (irq_status & SPI_INT_TXEI) { + if (irq_status & DW_SPI_INT_TXEI) { dw_writer(dws); if (!dws->tx_len) - spi_mask_intr(dws, SPI_INT_TXEI); + dw_spi_mask_intr(dws, DW_SPI_INT_TXEI); } return IRQ_HANDLED; @@ -260,7 +260,7 @@ static irqreturn_t dw_spi_irq(int irq, void *dev_id) return IRQ_NONE; if (!master->cur_msg) { - spi_mask_intr(dws, 0xff); + dw_spi_mask_intr(dws, 0xff); return IRQ_HANDLED; } @@ -271,37 +271,37 @@ static u32 dw_spi_prepare_cr0(struct dw_spi *dws, struct spi_device *spi) { u32 cr0 = 0; - if (!(dws->caps & DW_SPI_CAP_DWC_SSI)) { + if (!(dws->caps & DW_SPI_CAP_DWC_HSSI)) { /* CTRLR0[ 5: 4] Frame Format */ - cr0 |= SPI_FRF_MOTO_SPI << SPI_FRF_OFFSET; + cr0 |= DW_SPI_CTRLR0_FRF_MOTO_SPI << DW_PSSI_CTRLR0_FRF_OFFSET; /* * SPI mode (SCPOL|SCPH) * CTRLR0[ 6] Serial Clock Phase * CTRLR0[ 7] Serial Clock Polarity */ - cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << SPI_SCOL_OFFSET; - cr0 |= ((spi->mode & SPI_CPHA) ? 1 : 0) << SPI_SCPH_OFFSET; + cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << DW_PSSI_CTRLR0_SCOL_OFFSET; + cr0 |= ((spi->mode & SPI_CPHA) ? 1 : 0) << DW_PSSI_CTRLR0_SCPH_OFFSET; /* CTRLR0[11] Shift Register Loop */ - cr0 |= ((spi->mode & SPI_LOOP) ? 1 : 0) << SPI_SRL_OFFSET; + cr0 |= ((spi->mode & SPI_LOOP) ? 1 : 0) << DW_PSSI_CTRLR0_SRL_OFFSET; } else { /* CTRLR0[ 7: 6] Frame Format */ - cr0 |= SPI_FRF_MOTO_SPI << DWC_SSI_CTRLR0_FRF_OFFSET; + cr0 |= DW_SPI_CTRLR0_FRF_MOTO_SPI << DW_HSSI_CTRLR0_FRF_OFFSET; /* * SPI mode (SCPOL|SCPH) * CTRLR0[ 8] Serial Clock Phase * CTRLR0[ 9] Serial Clock Polarity */ - cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << DWC_SSI_CTRLR0_SCPOL_OFFSET; - cr0 |= ((spi->mode & SPI_CPHA) ? 1 : 0) << DWC_SSI_CTRLR0_SCPH_OFFSET; + cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << DW_HSSI_CTRLR0_SCPOL_OFFSET; + cr0 |= ((spi->mode & SPI_CPHA) ? 1 : 0) << DW_HSSI_CTRLR0_SCPH_OFFSET; /* CTRLR0[13] Shift Register Loop */ - cr0 |= ((spi->mode & SPI_LOOP) ? 1 : 0) << DWC_SSI_CTRLR0_SRL_OFFSET; + cr0 |= ((spi->mode & SPI_LOOP) ? 1 : 0) << DW_HSSI_CTRLR0_SRL_OFFSET; if (dws->caps & DW_SPI_CAP_KEEMBAY_MST) - cr0 |= DWC_SSI_CTRLR0_KEEMBAY_MST; + cr0 |= DW_HSSI_CTRLR0_KEEMBAY_MST; } return cr0; @@ -310,7 +310,7 @@ static u32 dw_spi_prepare_cr0(struct dw_spi *dws, struct spi_device *spi) void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi, struct dw_spi_cfg *cfg) { - struct chip_data *chip = spi_get_ctldata(spi); + struct dw_spi_chip_data *chip = spi_get_ctldata(spi); u32 cr0 = chip->cr0; u32 speed_hz; u16 clk_div; @@ -318,16 +318,17 @@ void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi, /* CTRLR0[ 4/3: 0] or CTRLR0[ 20: 16] Data Frame Size */ cr0 |= (cfg->dfs - 1) << dws->dfs_offset; - if (!(dws->caps & DW_SPI_CAP_DWC_SSI)) + if (!(dws->caps & DW_SPI_CAP_DWC_HSSI)) /* CTRLR0[ 9:8] Transfer Mode */ - cr0 |= cfg->tmode << SPI_TMOD_OFFSET; + cr0 |= cfg->tmode << DW_PSSI_CTRLR0_TMOD_OFFSET; else /* CTRLR0[11:10] Transfer Mode */ - cr0 |= cfg->tmode << DWC_SSI_CTRLR0_TMOD_OFFSET; + cr0 |= cfg->tmode << DW_HSSI_CTRLR0_TMOD_OFFSET; dw_writel(dws, DW_SPI_CTRLR0, cr0); - if (cfg->tmode == SPI_TMOD_EPROMREAD || cfg->tmode == SPI_TMOD_RO) + if (cfg->tmode == DW_SPI_CTRLR0_TMOD_EPROMREAD || + cfg->tmode == DW_SPI_CTRLR0_TMOD_RO) dw_writel(dws, DW_SPI_CTRLR1, cfg->ndf ? cfg->ndf - 1 : 0); /* Note DW APB SSI clock divider doesn't support odd numbers */ @@ -335,7 +336,7 @@ void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi, speed_hz = dws->max_freq / clk_div; if (dws->current_freq != speed_hz) { - spi_set_clk(dws, clk_div); + dw_spi_set_clk(dws, clk_div); dws->current_freq = speed_hz; } @@ -363,9 +364,9 @@ static void dw_spi_irq_setup(struct dw_spi *dws) dws->transfer_handler = dw_spi_transfer_handler; - imask = SPI_INT_TXEI | SPI_INT_TXOI | SPI_INT_RXUI | SPI_INT_RXOI | - SPI_INT_RXFI; - spi_umask_intr(dws, imask); + imask = DW_SPI_INT_TXEI | DW_SPI_INT_TXOI | + DW_SPI_INT_RXUI | DW_SPI_INT_RXOI | DW_SPI_INT_RXFI; + dw_spi_umask_intr(dws, imask); } /* @@ -405,11 +406,12 @@ static int dw_spi_poll_transfer(struct dw_spi *dws, } static int dw_spi_transfer_one(struct spi_controller *master, - struct spi_device *spi, struct spi_transfer *transfer) + struct spi_device *spi, + struct spi_transfer *transfer) { struct dw_spi *dws = spi_controller_get_devdata(master); struct dw_spi_cfg cfg = { - .tmode = SPI_TMOD_TR, + .tmode = DW_SPI_CTRLR0_TMOD_TR, .dfs = transfer->bits_per_word, .freq = transfer->speed_hz, }; @@ -425,7 +427,7 @@ static int dw_spi_transfer_one(struct spi_controller *master, /* Ensure the data above is visible for all CPUs */ smp_mb(); - spi_enable_chip(dws, 0); + dw_spi_enable_chip(dws, 0); dw_spi_update_config(dws, spi, &cfg); @@ -436,7 +438,7 @@ static int dw_spi_transfer_one(struct spi_controller *master, dws->dma_mapped = master->cur_msg_mapped; /* For poll mode just disable all interrupts */ - spi_mask_intr(dws, 0xff); + dw_spi_mask_intr(dws, 0xff); if (dws->dma_mapped) { ret = dws->dma_ops->dma_setup(dws, transfer); @@ -444,7 +446,7 @@ static int dw_spi_transfer_one(struct spi_controller *master, return ret; } - spi_enable_chip(dws, 1); + dw_spi_enable_chip(dws, 1); if (dws->dma_mapped) return dws->dma_ops->dma_transfer(dws, transfer); @@ -457,20 +459,20 @@ static int dw_spi_transfer_one(struct spi_controller *master, } static void dw_spi_handle_err(struct spi_controller *master, - struct spi_message *msg) + struct spi_message *msg) { struct dw_spi *dws = spi_controller_get_devdata(master); if (dws->dma_mapped) dws->dma_ops->dma_stop(dws); - spi_reset_chip(dws); + dw_spi_reset_chip(dws); } static int dw_spi_adjust_mem_op_size(struct spi_mem *mem, struct spi_mem_op *op) { if (op->data.dir == SPI_MEM_DATA_IN) - op->data.nbytes = clamp_val(op->data.nbytes, 0, SPI_NDF_MASK + 1); + op->data.nbytes = clamp_val(op->data.nbytes, 0, DW_SPI_NDF_MASK + 1); return 0; } @@ -498,7 +500,7 @@ static int dw_spi_init_mem_buf(struct dw_spi *dws, const struct spi_mem_op *op) if (op->data.dir == SPI_MEM_DATA_OUT) len += op->data.nbytes; - if (len <= SPI_BUF_SIZE) { + if (len <= DW_SPI_BUF_SIZE) { out = dws->buf; } else { out = kzalloc(len, GFP_KERNEL); @@ -512,9 +514,9 @@ static int dw_spi_init_mem_buf(struct dw_spi *dws, const struct spi_mem_op *op) * single buffer in order to speed the data transmission up. */ for (i = 0; i < op->cmd.nbytes; ++i) - out[i] = SPI_GET_BYTE(op->cmd.opcode, op->cmd.nbytes - i - 1); + out[i] = DW_SPI_GET_BYTE(op->cmd.opcode, op->cmd.nbytes - i - 1); for (j = 0; j < op->addr.nbytes; ++i, ++j) - out[i] = SPI_GET_BYTE(op->addr.val, op->addr.nbytes - j - 1); + out[i] = DW_SPI_GET_BYTE(op->addr.val, op->addr.nbytes - j - 1); for (j = 0; j < op->dummy.nbytes; ++i, ++j) out[i] = 0x0; @@ -587,7 +589,7 @@ static int dw_spi_write_then_read(struct dw_spi *dws, struct spi_device *spi) entries = readl_relaxed(dws->regs + DW_SPI_RXFLR); if (!entries) { sts = readl_relaxed(dws->regs + DW_SPI_RISR); - if (sts & SPI_INT_RXOI) { + if (sts & DW_SPI_INT_RXOI) { dev_err(&dws->master->dev, "FIFO overflow on Rx\n"); return -EIO; } @@ -603,12 +605,12 @@ static int dw_spi_write_then_read(struct dw_spi *dws, struct spi_device *spi) static inline bool dw_spi_ctlr_busy(struct dw_spi *dws) { - return dw_readl(dws, DW_SPI_SR) & SR_BUSY; + return dw_readl(dws, DW_SPI_SR) & DW_SPI_SR_BUSY; } static int dw_spi_wait_mem_op_done(struct dw_spi *dws) { - int retry = SPI_WAIT_RETRIES; + int retry = DW_SPI_WAIT_RETRIES; struct spi_delay delay; unsigned long ns, us; u32 nents; @@ -638,9 +640,9 @@ static int dw_spi_wait_mem_op_done(struct dw_spi *dws) static void dw_spi_stop_mem_op(struct dw_spi *dws, struct spi_device *spi) { - spi_enable_chip(dws, 0); + dw_spi_enable_chip(dws, 0); dw_spi_set_cs(spi, true); - spi_enable_chip(dws, 1); + dw_spi_enable_chip(dws, 1); } /* @@ -673,19 +675,19 @@ static int dw_spi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op) cfg.dfs = 8; cfg.freq = clamp(mem->spi->max_speed_hz, 0U, dws->max_mem_freq); if (op->data.dir == SPI_MEM_DATA_IN) { - cfg.tmode = SPI_TMOD_EPROMREAD; + cfg.tmode = DW_SPI_CTRLR0_TMOD_EPROMREAD; cfg.ndf = op->data.nbytes; } else { - cfg.tmode = SPI_TMOD_TO; + cfg.tmode = DW_SPI_CTRLR0_TMOD_TO; } - spi_enable_chip(dws, 0); + dw_spi_enable_chip(dws, 0); dw_spi_update_config(dws, mem->spi, &cfg); - spi_mask_intr(dws, 0xff); + dw_spi_mask_intr(dws, 0xff); - spi_enable_chip(dws, 1); + dw_spi_enable_chip(dws, 1); /* * DW APB SSI controller has very nasty peculiarities. First originally @@ -768,7 +770,7 @@ static void dw_spi_init_mem_ops(struct dw_spi *dws) static int dw_spi_setup(struct spi_device *spi) { struct dw_spi *dws = spi_controller_get_devdata(spi->controller); - struct chip_data *chip; + struct dw_spi_chip_data *chip; /* Only alloc on first setup */ chip = spi_get_ctldata(spi); @@ -776,7 +778,7 @@ static int dw_spi_setup(struct spi_device *spi) struct dw_spi *dws = spi_controller_get_devdata(spi->controller); u32 rx_sample_dly_ns; - chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; spi_set_ctldata(spi, chip); @@ -803,16 +805,16 @@ static int dw_spi_setup(struct spi_device *spi) static void dw_spi_cleanup(struct spi_device *spi) { - struct chip_data *chip = spi_get_ctldata(spi); + struct dw_spi_chip_data *chip = spi_get_ctldata(spi); kfree(chip); spi_set_ctldata(spi, NULL); } /* Restart the controller, disable all interrupts, clean rx fifo */ -static void spi_hw_init(struct device *dev, struct dw_spi *dws) +static void dw_spi_hw_init(struct device *dev, struct dw_spi *dws) { - spi_reset_chip(dws); + dw_spi_reset_chip(dws); /* * Try to detect the FIFO depth if not set by interface driver, @@ -837,18 +839,18 @@ static void spi_hw_init(struct device *dev, struct dw_spi *dws) * writability. Note DWC SSI controller also has the extended DFS, but * with zero offset. */ - if (!(dws->caps & DW_SPI_CAP_DWC_SSI)) { + if (!(dws->caps & DW_SPI_CAP_DWC_HSSI)) { u32 cr0, tmp = dw_readl(dws, DW_SPI_CTRLR0); - spi_enable_chip(dws, 0); + dw_spi_enable_chip(dws, 0); dw_writel(dws, DW_SPI_CTRLR0, 0xffffffff); cr0 = dw_readl(dws, DW_SPI_CTRLR0); dw_writel(dws, DW_SPI_CTRLR0, tmp); - spi_enable_chip(dws, 1); + dw_spi_enable_chip(dws, 1); - if (!(cr0 & SPI_DFS_MASK)) { + if (!(cr0 & DW_PSSI_CTRLR0_DFS_MASK)) { dws->caps |= DW_SPI_CAP_DFS32; - dws->dfs_offset = SPI_DFS32_OFFSET; + dws->dfs_offset = DW_PSSI_CTRLR0_DFS32_OFFSET; dev_dbg(dev, "Detected 32-bits max data frame size\n"); } } else { @@ -878,7 +880,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) spi_controller_set_devdata(master, dws); /* Basic HW init */ - spi_hw_init(dev, dws); + dw_spi_hw_init(dev, dws); ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dev_name(dev), master); @@ -939,7 +941,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) err_dma_exit: if (dws->dma_ops && dws->dma_ops->dma_exit) dws->dma_ops->dma_exit(dws); - spi_enable_chip(dws, 0); + dw_spi_enable_chip(dws, 0); free_irq(dws->irq, master); err_free_master: spi_controller_put(master); @@ -956,7 +958,7 @@ void dw_spi_remove_host(struct dw_spi *dws) if (dws->dma_ops && dws->dma_ops->dma_exit) dws->dma_ops->dma_exit(dws); - spi_shutdown_chip(dws); + dw_spi_shutdown_chip(dws); free_irq(dws->irq, dws->master); } @@ -970,14 +972,14 @@ int dw_spi_suspend_host(struct dw_spi *dws) if (ret) return ret; - spi_shutdown_chip(dws); + dw_spi_shutdown_chip(dws); return 0; } EXPORT_SYMBOL_NS_GPL(dw_spi_suspend_host, SPI_DW_CORE); int dw_spi_resume_host(struct dw_spi *dws) { - spi_hw_init(&dws->master->dev, dws); + dw_spi_hw_init(&dws->master->dev, dws); return spi_controller_resume(dws->master); } EXPORT_SYMBOL_NS_GPL(dw_spi_resume_host, SPI_DW_CORE); diff --git a/drivers/spi/spi-dw-dma.c b/drivers/spi/spi-dw-dma.c index ca199eee0f132..63e5260100ecb 100644 --- a/drivers/spi/spi-dw-dma.c +++ b/drivers/spi/spi-dw-dma.c @@ -18,10 +18,10 @@ #include "spi-dw.h" -#define RX_BUSY 0 -#define RX_BURST_LEVEL 16 -#define TX_BUSY 1 -#define TX_BURST_LEVEL 16 +#define DW_SPI_RX_BUSY 0 +#define DW_SPI_RX_BURST_LEVEL 16 +#define DW_SPI_TX_BUSY 1 +#define DW_SPI_TX_BURST_LEVEL 16 static bool dw_spi_dma_chan_filter(struct dma_chan *chan, void *param) { @@ -46,7 +46,7 @@ static void dw_spi_dma_maxburst_init(struct dw_spi *dws) if (!ret && caps.max_burst) max_burst = caps.max_burst; else - max_burst = RX_BURST_LEVEL; + max_burst = DW_SPI_RX_BURST_LEVEL; dws->rxburst = min(max_burst, def_burst); dw_writel(dws, DW_SPI_DMARDLR, dws->rxburst - 1); @@ -55,7 +55,7 @@ static void dw_spi_dma_maxburst_init(struct dw_spi *dws) if (!ret && caps.max_burst) max_burst = caps.max_burst; else - max_burst = TX_BURST_LEVEL; + max_burst = DW_SPI_TX_BURST_LEVEL; /* * Having a Rx DMA channel serviced with higher priority than a Tx DMA @@ -227,13 +227,13 @@ static int dw_spi_dma_wait(struct dw_spi *dws, unsigned int len, u32 speed) static inline bool dw_spi_dma_tx_busy(struct dw_spi *dws) { - return !(dw_readl(dws, DW_SPI_SR) & SR_TF_EMPT); + return !(dw_readl(dws, DW_SPI_SR) & DW_SPI_SR_TF_EMPT); } static int dw_spi_dma_wait_tx_done(struct dw_spi *dws, struct spi_transfer *xfer) { - int retry = SPI_WAIT_RETRIES; + int retry = DW_SPI_WAIT_RETRIES; struct spi_delay delay; u32 nents; @@ -260,8 +260,8 @@ static void dw_spi_dma_tx_done(void *arg) { struct dw_spi *dws = arg; - clear_bit(TX_BUSY, &dws->dma_chan_busy); - if (test_bit(RX_BUSY, &dws->dma_chan_busy)) + clear_bit(DW_SPI_TX_BUSY, &dws->dma_chan_busy); + if (test_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy)) return; complete(&dws->dma_completion); @@ -305,19 +305,19 @@ static int dw_spi_dma_submit_tx(struct dw_spi *dws, struct scatterlist *sgl, return ret; } - set_bit(TX_BUSY, &dws->dma_chan_busy); + set_bit(DW_SPI_TX_BUSY, &dws->dma_chan_busy); return 0; } static inline bool dw_spi_dma_rx_busy(struct dw_spi *dws) { - return !!(dw_readl(dws, DW_SPI_SR) & SR_RF_NOT_EMPT); + return !!(dw_readl(dws, DW_SPI_SR) & DW_SPI_SR_RF_NOT_EMPT); } static int dw_spi_dma_wait_rx_done(struct dw_spi *dws) { - int retry = SPI_WAIT_RETRIES; + int retry = DW_SPI_WAIT_RETRIES; struct spi_delay delay; unsigned long ns, us; u32 nents; @@ -361,8 +361,8 @@ static void dw_spi_dma_rx_done(void *arg) { struct dw_spi *dws = arg; - clear_bit(RX_BUSY, &dws->dma_chan_busy); - if (test_bit(TX_BUSY, &dws->dma_chan_busy)) + clear_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy); + if (test_bit(DW_SPI_TX_BUSY, &dws->dma_chan_busy)) return; complete(&dws->dma_completion); @@ -406,7 +406,7 @@ static int dw_spi_dma_submit_rx(struct dw_spi *dws, struct scatterlist *sgl, return ret; } - set_bit(RX_BUSY, &dws->dma_chan_busy); + set_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy); return 0; } @@ -431,16 +431,16 @@ static int dw_spi_dma_setup(struct dw_spi *dws, struct spi_transfer *xfer) } /* Set the DMA handshaking interface */ - dma_ctrl = SPI_DMA_TDMAE; + dma_ctrl = DW_SPI_DMACR_TDMAE; if (xfer->rx_buf) - dma_ctrl |= SPI_DMA_RDMAE; + dma_ctrl |= DW_SPI_DMACR_RDMAE; dw_writel(dws, DW_SPI_DMACR, dma_ctrl); /* Set the interrupt mask */ - imr = SPI_INT_TXOI; + imr = DW_SPI_INT_TXOI; if (xfer->rx_buf) - imr |= SPI_INT_RXUI | SPI_INT_RXOI; - spi_umask_intr(dws, imr); + imr |= DW_SPI_INT_RXUI | DW_SPI_INT_RXOI; + dw_spi_umask_intr(dws, imr); reinit_completion(&dws->dma_completion); @@ -616,13 +616,13 @@ static int dw_spi_dma_transfer(struct dw_spi *dws, struct spi_transfer *xfer) static void dw_spi_dma_stop(struct dw_spi *dws) { - if (test_bit(TX_BUSY, &dws->dma_chan_busy)) { + if (test_bit(DW_SPI_TX_BUSY, &dws->dma_chan_busy)) { dmaengine_terminate_sync(dws->txchan); - clear_bit(TX_BUSY, &dws->dma_chan_busy); + clear_bit(DW_SPI_TX_BUSY, &dws->dma_chan_busy); } - if (test_bit(RX_BUSY, &dws->dma_chan_busy)) { + if (test_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy)) { dmaengine_terminate_sync(dws->rxchan); - clear_bit(RX_BUSY, &dws->dma_chan_busy); + clear_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy); } } diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index c3bacd5a2843d..2193c2550e741 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -196,18 +196,18 @@ static int dw_spi_alpine_init(struct platform_device *pdev, return 0; } -static int dw_spi_dw_apb_init(struct platform_device *pdev, - struct dw_spi_mmio *dwsmmio) +static int dw_spi_pssi_init(struct platform_device *pdev, + struct dw_spi_mmio *dwsmmio) { dw_spi_dma_setup_generic(&dwsmmio->dws); return 0; } -static int dw_spi_dwc_ssi_init(struct platform_device *pdev, - struct dw_spi_mmio *dwsmmio) +static int dw_spi_hssi_init(struct platform_device *pdev, + struct dw_spi_mmio *dwsmmio) { - dwsmmio->dws.caps = DW_SPI_CAP_DWC_SSI; + dwsmmio->dws.caps = DW_SPI_CAP_DWC_HSSI; dw_spi_dma_setup_generic(&dwsmmio->dws); @@ -217,7 +217,7 @@ static int dw_spi_dwc_ssi_init(struct platform_device *pdev, static int dw_spi_keembay_init(struct platform_device *pdev, struct dw_spi_mmio *dwsmmio) { - dwsmmio->dws.caps = DW_SPI_CAP_KEEMBAY_MST | DW_SPI_CAP_DWC_SSI; + dwsmmio->dws.caps = DW_SPI_CAP_KEEMBAY_MST | DW_SPI_CAP_DWC_HSSI; return 0; } @@ -342,12 +342,12 @@ static int dw_spi_mmio_remove(struct platform_device *pdev) } static const struct of_device_id dw_spi_mmio_of_match[] = { - { .compatible = "snps,dw-apb-ssi", .data = dw_spi_dw_apb_init}, + { .compatible = "snps,dw-apb-ssi", .data = dw_spi_pssi_init}, { .compatible = "mscc,ocelot-spi", .data = dw_spi_mscc_ocelot_init}, { .compatible = "mscc,jaguar2-spi", .data = dw_spi_mscc_jaguar2_init}, { .compatible = "amazon,alpine-dw-apb-ssi", .data = dw_spi_alpine_init}, - { .compatible = "renesas,rzn1-spi", .data = dw_spi_dw_apb_init}, - { .compatible = "snps,dwc-ssi-1.01a", .data = dw_spi_dwc_ssi_init}, + { .compatible = "renesas,rzn1-spi", .data = dw_spi_pssi_init}, + { .compatible = "snps,dwc-ssi-1.01a", .data = dw_spi_hssi_init}, { .compatible = "intel,keembay-ssi", .data = dw_spi_keembay_init}, { .compatible = "microchip,sparx5-spi", dw_spi_mscc_sparx5_init}, { .compatible = "canaan,k210-spi", dw_spi_canaan_k210_init}, @@ -357,7 +357,7 @@ MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match); #ifdef CONFIG_ACPI static const struct acpi_device_id dw_spi_mmio_acpi_match[] = { - {"HISI0173", (kernel_ulong_t)dw_spi_dw_apb_init}, + {"HISI0173", (kernel_ulong_t)dw_spi_pssi_init}, {}, }; MODULE_DEVICE_TABLE(acpi, dw_spi_mmio_acpi_match); diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c index 5552240fee55a..7c8279d13f319 100644 --- a/drivers/spi/spi-dw-pci.c +++ b/drivers/spi/spi-dw-pci.c @@ -24,14 +24,14 @@ #define CLK_SPI_CDIV_MASK 0x00000e00 #define CLK_SPI_DISABLE_OFFSET 8 -struct spi_pci_desc { +struct dw_spi_pci_desc { int (*setup)(struct dw_spi *); u16 num_cs; u16 bus_num; u32 max_freq; }; -static int spi_mid_init(struct dw_spi *dws) +static int dw_spi_pci_mid_init(struct dw_spi *dws) { void __iomem *clk_reg; u32 clk_cdiv; @@ -53,36 +53,36 @@ static int spi_mid_init(struct dw_spi *dws) return 0; } -static int spi_generic_init(struct dw_spi *dws) +static int dw_spi_pci_generic_init(struct dw_spi *dws) { dw_spi_dma_setup_generic(dws); return 0; } -static struct spi_pci_desc spi_pci_mid_desc_1 = { - .setup = spi_mid_init, +static struct dw_spi_pci_desc dw_spi_pci_mid_desc_1 = { + .setup = dw_spi_pci_mid_init, .num_cs = 5, .bus_num = 0, }; -static struct spi_pci_desc spi_pci_mid_desc_2 = { - .setup = spi_mid_init, +static struct dw_spi_pci_desc dw_spi_pci_mid_desc_2 = { + .setup = dw_spi_pci_mid_init, .num_cs = 2, .bus_num = 1, }; -static struct spi_pci_desc spi_pci_ehl_desc = { - .setup = spi_generic_init, +static struct dw_spi_pci_desc dw_spi_pci_ehl_desc = { + .setup = dw_spi_pci_generic_init, .num_cs = 2, .bus_num = -1, .max_freq = 100000000, }; -static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +static int dw_spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { + struct dw_spi_pci_desc *desc = (struct dw_spi_pci_desc *)ent->driver_data; struct dw_spi *dws; - struct spi_pci_desc *desc = (struct spi_pci_desc *)ent->driver_data; int pci_bar = 0; int ret; @@ -150,7 +150,7 @@ err_free_irq_vectors: return ret; } -static void spi_pci_remove(struct pci_dev *pdev) +static void dw_spi_pci_remove(struct pci_dev *pdev) { struct dw_spi *dws = pci_get_drvdata(pdev); @@ -162,14 +162,14 @@ static void spi_pci_remove(struct pci_dev *pdev) } #ifdef CONFIG_PM_SLEEP -static int spi_suspend(struct device *dev) +static int dw_spi_pci_suspend(struct device *dev) { struct dw_spi *dws = dev_get_drvdata(dev); return dw_spi_suspend_host(dws); } -static int spi_resume(struct device *dev) +static int dw_spi_pci_resume(struct device *dev) { struct dw_spi *dws = dev_get_drvdata(dev); @@ -177,38 +177,37 @@ static int spi_resume(struct device *dev) } #endif -static SIMPLE_DEV_PM_OPS(dw_spi_pm_ops, spi_suspend, spi_resume); +static SIMPLE_DEV_PM_OPS(dw_spi_pci_pm_ops, dw_spi_pci_suspend, dw_spi_pci_resume); -static const struct pci_device_id pci_ids[] = { +static const struct pci_device_id dw_spi_pci_ids[] = { /* Intel MID platform SPI controller 0 */ /* * The access to the device 8086:0801 is disabled by HW, since it's * exclusively used by SCU to communicate with MSIC. */ /* Intel MID platform SPI controller 1 */ - { PCI_VDEVICE(INTEL, 0x0800), (kernel_ulong_t)&spi_pci_mid_desc_1}, + { PCI_VDEVICE(INTEL, 0x0800), (kernel_ulong_t)&dw_spi_pci_mid_desc_1}, /* Intel MID platform SPI controller 2 */ - { PCI_VDEVICE(INTEL, 0x0812), (kernel_ulong_t)&spi_pci_mid_desc_2}, + { PCI_VDEVICE(INTEL, 0x0812), (kernel_ulong_t)&dw_spi_pci_mid_desc_2}, /* Intel Elkhart Lake PSE SPI controllers */ - { PCI_VDEVICE(INTEL, 0x4b84), (kernel_ulong_t)&spi_pci_ehl_desc}, - { PCI_VDEVICE(INTEL, 0x4b85), (kernel_ulong_t)&spi_pci_ehl_desc}, - { PCI_VDEVICE(INTEL, 0x4b86), (kernel_ulong_t)&spi_pci_ehl_desc}, - { PCI_VDEVICE(INTEL, 0x4b87), (kernel_ulong_t)&spi_pci_ehl_desc}, + { PCI_VDEVICE(INTEL, 0x4b84), (kernel_ulong_t)&dw_spi_pci_ehl_desc}, + { PCI_VDEVICE(INTEL, 0x4b85), (kernel_ulong_t)&dw_spi_pci_ehl_desc}, + { PCI_VDEVICE(INTEL, 0x4b86), (kernel_ulong_t)&dw_spi_pci_ehl_desc}, + { PCI_VDEVICE(INTEL, 0x4b87), (kernel_ulong_t)&dw_spi_pci_ehl_desc}, {}, }; -MODULE_DEVICE_TABLE(pci, pci_ids); +MODULE_DEVICE_TABLE(pci, dw_spi_pci_ids); -static struct pci_driver dw_spi_driver = { +static struct pci_driver dw_spi_pci_driver = { .name = DRIVER_NAME, - .id_table = pci_ids, - .probe = spi_pci_probe, - .remove = spi_pci_remove, + .id_table = dw_spi_pci_ids, + .probe = dw_spi_pci_probe, + .remove = dw_spi_pci_remove, .driver = { - .pm = &dw_spi_pm_ops, + .pm = &dw_spi_pci_pm_ops, }, }; - -module_pci_driver(dw_spi_driver); +module_pci_driver(dw_spi_pci_driver); MODULE_AUTHOR("Feng Tang "); MODULE_DESCRIPTION("PCI interface driver for DW SPI Core"); diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index 467c342bfe56a..893b78c43a507 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ -#ifndef DW_SPI_HEADER_H -#define DW_SPI_HEADER_H +#ifndef __SPI_DW_H__ +#define __SPI_DW_H__ #include #include @@ -11,7 +11,7 @@ #include #include -/* Register offsets */ +/* Register offsets (Generic for both DWC APB SSI and DWC SSI IP-cores) */ #define DW_SPI_CTRLR0 0x00 #define DW_SPI_CTRLR1 0x04 #define DW_SPI_SSIENR 0x08 @@ -40,84 +40,85 @@ #define DW_SPI_RX_SAMPLE_DLY 0xf0 #define DW_SPI_CS_OVERRIDE 0xf4 -/* Bit fields in CTRLR0 */ -#define SPI_DFS_OFFSET 0 -#define SPI_DFS_MASK GENMASK(3, 0) -#define SPI_DFS32_OFFSET 16 - -#define SPI_FRF_OFFSET 4 -#define SPI_FRF_MOTO_SPI 0x0 -#define SPI_FRF_TI_SSP 0x1 -#define SPI_FRF_NS_MICROWIRE 0x2 -#define SPI_FRF_RESV 0x3 - -#define SPI_MODE_OFFSET 6 -#define SPI_SCPH_OFFSET 6 -#define SPI_SCOL_OFFSET 7 - -#define SPI_TMOD_OFFSET 8 -#define SPI_TMOD_MASK (0x3 << SPI_TMOD_OFFSET) -#define SPI_TMOD_TR 0x0 /* xmit & recv */ -#define SPI_TMOD_TO 0x1 /* xmit only */ -#define SPI_TMOD_RO 0x2 /* recv only */ -#define SPI_TMOD_EPROMREAD 0x3 /* eeprom read mode */ - -#define SPI_SLVOE_OFFSET 10 -#define SPI_SRL_OFFSET 11 -#define SPI_CFS_OFFSET 12 - -/* Bit fields in CTRLR0 based on DWC_ssi_databook.pdf v1.01a */ -#define DWC_SSI_CTRLR0_SRL_OFFSET 13 -#define DWC_SSI_CTRLR0_TMOD_OFFSET 10 -#define DWC_SSI_CTRLR0_TMOD_MASK GENMASK(11, 10) -#define DWC_SSI_CTRLR0_SCPOL_OFFSET 9 -#define DWC_SSI_CTRLR0_SCPH_OFFSET 8 -#define DWC_SSI_CTRLR0_FRF_OFFSET 6 -#define DWC_SSI_CTRLR0_DFS_OFFSET 0 +/* Bit fields in CTRLR0 (DWC APB SSI) */ +#define DW_PSSI_CTRLR0_DFS_OFFSET 0 +#define DW_PSSI_CTRLR0_DFS_MASK GENMASK(3, 0) +#define DW_PSSI_CTRLR0_DFS32_OFFSET 16 + +#define DW_PSSI_CTRLR0_FRF_OFFSET 4 +#define DW_SPI_CTRLR0_FRF_MOTO_SPI 0x0 +#define DW_SPI_CTRLR0_FRF_TI_SSP 0x1 +#define DW_SPI_CTRLR0_FRF_NS_MICROWIRE 0x2 +#define DW_SPI_CTRLR0_FRF_RESV 0x3 + +#define DW_PSSI_CTRLR0_MODE_OFFSET 6 +#define DW_PSSI_CTRLR0_SCPH_OFFSET 6 +#define DW_PSSI_CTRLR0_SCOL_OFFSET 7 + +#define DW_PSSI_CTRLR0_TMOD_OFFSET 8 +#define DW_PSSI_CTRLR0_TMOD_MASK (0x3 << DW_PSSI_CTRLR0_TMOD_OFFSET) +#define DW_SPI_CTRLR0_TMOD_TR 0x0 /* xmit & recv */ +#define DW_SPI_CTRLR0_TMOD_TO 0x1 /* xmit only */ +#define DW_SPI_CTRLR0_TMOD_RO 0x2 /* recv only */ +#define DW_SPI_CTRLR0_TMOD_EPROMREAD 0x3 /* eeprom read mode */ + +#define DW_PSSI_CTRLR0_SLVOE_OFFSET 10 +#define DW_PSSI_CTRLR0_SRL_OFFSET 11 +#define DW_PSSI_CTRLR0_CFS_OFFSET 12 + +/* Bit fields in CTRLR0 (DWC SSI with AHB interface) */ +#define DW_HSSI_CTRLR0_SRL_OFFSET 13 +#define DW_HSSI_CTRLR0_TMOD_OFFSET 10 +#define DW_HSSI_CTRLR0_TMOD_MASK GENMASK(11, 10) +#define DW_HSSI_CTRLR0_SCPOL_OFFSET 9 +#define DW_HSSI_CTRLR0_SCPH_OFFSET 8 +#define DW_HSSI_CTRLR0_FRF_OFFSET 6 +#define DW_HSSI_CTRLR0_DFS_OFFSET 0 /* * For Keem Bay, CTRLR0[31] is used to select controller mode. * 0: SSI is slave * 1: SSI is master */ -#define DWC_SSI_CTRLR0_KEEMBAY_MST BIT(31) +#define DW_HSSI_CTRLR0_KEEMBAY_MST BIT(31) /* Bit fields in CTRLR1 */ -#define SPI_NDF_MASK GENMASK(15, 0) +#define DW_SPI_NDF_MASK GENMASK(15, 0) /* Bit fields in SR, 7 bits */ -#define SR_MASK 0x7f /* cover 7 bits */ -#define SR_BUSY (1 << 0) -#define SR_TF_NOT_FULL (1 << 1) -#define SR_TF_EMPT (1 << 2) -#define SR_RF_NOT_EMPT (1 << 3) -#define SR_RF_FULL (1 << 4) -#define SR_TX_ERR (1 << 5) -#define SR_DCOL (1 << 6) +#define DW_SPI_SR_MASK 0x7f /* cover 7 bits */ +#define DW_SPI_SR_BUSY (1 << 0) +#define DW_SPI_SR_TF_NOT_FULL (1 << 1) +#define DW_SPI_SR_TF_EMPT (1 << 2) +#define DW_SPI_SR_RF_NOT_EMPT (1 << 3) +#define DW_SPI_SR_RF_FULL (1 << 4) +#define DW_SPI_SR_TX_ERR (1 << 5) +#define DW_SPI_SR_DCOL (1 << 6) /* Bit fields in ISR, IMR, RISR, 7 bits */ -#define SPI_INT_TXEI (1 << 0) -#define SPI_INT_TXOI (1 << 1) -#define SPI_INT_RXUI (1 << 2) -#define SPI_INT_RXOI (1 << 3) -#define SPI_INT_RXFI (1 << 4) -#define SPI_INT_MSTI (1 << 5) +#define DW_SPI_INT_TXEI (1 << 0) +#define DW_SPI_INT_TXOI (1 << 1) +#define DW_SPI_INT_RXUI (1 << 2) +#define DW_SPI_INT_RXOI (1 << 3) +#define DW_SPI_INT_RXFI (1 << 4) +#define DW_SPI_INT_MSTI (1 << 5) /* Bit fields in DMACR */ -#define SPI_DMA_RDMAE (1 << 0) -#define SPI_DMA_TDMAE (1 << 1) +#define DW_SPI_DMACR_RDMAE (1 << 0) +#define DW_SPI_DMACR_TDMAE (1 << 1) -#define SPI_WAIT_RETRIES 5 -#define SPI_BUF_SIZE \ +/* Mem/DMA operations helpers */ +#define DW_SPI_WAIT_RETRIES 5 +#define DW_SPI_BUF_SIZE \ (sizeof_field(struct spi_mem_op, cmd.opcode) + \ sizeof_field(struct spi_mem_op, addr.val) + 256) -#define SPI_GET_BYTE(_val, _idx) \ +#define DW_SPI_GET_BYTE(_val, _idx) \ ((_val) >> (BITS_PER_BYTE * (_idx)) & 0xff) /* DW SPI capabilities */ #define DW_SPI_CAP_CS_OVERRIDE BIT(0) #define DW_SPI_CAP_KEEMBAY_MST BIT(1) -#define DW_SPI_CAP_DWC_SSI BIT(2) +#define DW_SPI_CAP_DWC_HSSI BIT(2) #define DW_SPI_CAP_DFS32 BIT(3) /* Slave spi_transfer/spi_mem_op related */ @@ -162,7 +163,7 @@ struct dw_spi { unsigned int tx_len; void *rx; unsigned int rx_len; - u8 buf[SPI_BUF_SIZE]; + u8 buf[DW_SPI_BUF_SIZE]; int dma_mapped; u8 n_bytes; /* current is a 1/2 bytes op */ irqreturn_t (*transfer_handler)(struct dw_spi *dws); @@ -224,18 +225,18 @@ static inline void dw_write_io_reg(struct dw_spi *dws, u32 offset, u32 val) } } -static inline void spi_enable_chip(struct dw_spi *dws, int enable) +static inline void dw_spi_enable_chip(struct dw_spi *dws, int enable) { dw_writel(dws, DW_SPI_SSIENR, (enable ? 1 : 0)); } -static inline void spi_set_clk(struct dw_spi *dws, u16 div) +static inline void dw_spi_set_clk(struct dw_spi *dws, u16 div) { dw_writel(dws, DW_SPI_BAUDR, div); } /* Disable IRQ bits */ -static inline void spi_mask_intr(struct dw_spi *dws, u32 mask) +static inline void dw_spi_mask_intr(struct dw_spi *dws, u32 mask) { u32 new_mask; @@ -244,7 +245,7 @@ static inline void spi_mask_intr(struct dw_spi *dws, u32 mask) } /* Enable IRQ bits */ -static inline void spi_umask_intr(struct dw_spi *dws, u32 mask) +static inline void dw_spi_umask_intr(struct dw_spi *dws, u32 mask) { u32 new_mask; @@ -257,19 +258,19 @@ static inline void spi_umask_intr(struct dw_spi *dws, u32 mask) * and CS, then re-enables the controller back. Transmit and receive FIFO * buffers are cleared when the device is disabled. */ -static inline void spi_reset_chip(struct dw_spi *dws) +static inline void dw_spi_reset_chip(struct dw_spi *dws) { - spi_enable_chip(dws, 0); - spi_mask_intr(dws, 0xff); + dw_spi_enable_chip(dws, 0); + dw_spi_mask_intr(dws, 0xff); dw_readl(dws, DW_SPI_ICR); dw_writel(dws, DW_SPI_SER, 0); - spi_enable_chip(dws, 1); + dw_spi_enable_chip(dws, 1); } -static inline void spi_shutdown_chip(struct dw_spi *dws) +static inline void dw_spi_shutdown_chip(struct dw_spi *dws) { - spi_enable_chip(dws, 0); - spi_set_clk(dws, 0); + dw_spi_enable_chip(dws, 0); + dw_spi_set_clk(dws, 0); } extern void dw_spi_set_cs(struct spi_device *spi, bool enable); @@ -293,4 +294,4 @@ static inline void dw_spi_dma_setup_generic(struct dw_spi *dws) {} #endif /* !CONFIG_SPI_DW_DMA */ -#endif /* DW_SPI_HEADER_H */ +#endif /* __SPI_DW_H__ */ -- GitLab From ec77c086dc5b2eb422ff588f91cc011137fa9ea3 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Mon, 15 Nov 2021 21:19:14 +0300 Subject: [PATCH 0043/1112] spi: dw: Convert to using the Bitfield access macros The driver has been using the offset/bitwise-shift-based approach for the CSR fields R/W operations since it was merged into the kernel. It can be simplified by using the macros defined in the linux/bitfield.h and linux/bit.h header files like BIT(), GENMASK(), FIELD_PREP(), FIELD_GET(), etc where it is required, for instance in the cached cr0 preparation method. Thus in order to have the FIELD_*()-macros utilized we just need to convert the macros with the CSR-fields offsets to the masks with the corresponding registers fields definition. That's where the GENMASK() and BIT() macros come in handy. After that the masks can be used in the FIELD_*()-macros where it's appropriate. We also need to convert the macros with the CRS-bit flags using the manual bitwise shift operations (x << y) to using the BIT() macro. Thus we'll have a more coherent set of the CSR-related macros. Signed-off-by: Serge Semin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211115181917.7521-5-Sergey.Semin@baikalelectronics.ru Signed-off-by: Mark Brown --- drivers/spi/spi-dw-core.c | 31 +++++++++++-------- drivers/spi/spi-dw.h | 64 +++++++++++++++++++-------------------- 2 files changed, 50 insertions(+), 45 deletions(-) diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c index 57bbffe6d6f94..b9f809989fda5 100644 --- a/drivers/spi/spi-dw-core.c +++ b/drivers/spi/spi-dw-core.c @@ -5,6 +5,7 @@ * Copyright (c) 2009, Intel Corporation. */ +#include #include #include #include @@ -254,7 +255,7 @@ static irqreturn_t dw_spi_irq(int irq, void *dev_id) { struct spi_controller *master = dev_id; struct dw_spi *dws = spi_controller_get_devdata(master); - u16 irq_status = dw_readl(dws, DW_SPI_ISR) & 0x3f; + u16 irq_status = dw_readl(dws, DW_SPI_ISR) & DW_SPI_INT_MASK; if (!irq_status) return IRQ_NONE; @@ -273,32 +274,38 @@ static u32 dw_spi_prepare_cr0(struct dw_spi *dws, struct spi_device *spi) if (!(dws->caps & DW_SPI_CAP_DWC_HSSI)) { /* CTRLR0[ 5: 4] Frame Format */ - cr0 |= DW_SPI_CTRLR0_FRF_MOTO_SPI << DW_PSSI_CTRLR0_FRF_OFFSET; + cr0 |= FIELD_PREP(DW_PSSI_CTRLR0_FRF_MASK, DW_SPI_CTRLR0_FRF_MOTO_SPI); /* * SPI mode (SCPOL|SCPH) * CTRLR0[ 6] Serial Clock Phase * CTRLR0[ 7] Serial Clock Polarity */ - cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << DW_PSSI_CTRLR0_SCOL_OFFSET; - cr0 |= ((spi->mode & SPI_CPHA) ? 1 : 0) << DW_PSSI_CTRLR0_SCPH_OFFSET; + if (spi->mode & SPI_CPOL) + cr0 |= DW_PSSI_CTRLR0_SCPOL; + if (spi->mode & SPI_CPHA) + cr0 |= DW_PSSI_CTRLR0_SCPHA; /* CTRLR0[11] Shift Register Loop */ - cr0 |= ((spi->mode & SPI_LOOP) ? 1 : 0) << DW_PSSI_CTRLR0_SRL_OFFSET; + if (spi->mode & SPI_LOOP) + cr0 |= DW_PSSI_CTRLR0_SRL; } else { /* CTRLR0[ 7: 6] Frame Format */ - cr0 |= DW_SPI_CTRLR0_FRF_MOTO_SPI << DW_HSSI_CTRLR0_FRF_OFFSET; + cr0 |= FIELD_PREP(DW_HSSI_CTRLR0_FRF_MASK, DW_SPI_CTRLR0_FRF_MOTO_SPI); /* * SPI mode (SCPOL|SCPH) * CTRLR0[ 8] Serial Clock Phase * CTRLR0[ 9] Serial Clock Polarity */ - cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << DW_HSSI_CTRLR0_SCPOL_OFFSET; - cr0 |= ((spi->mode & SPI_CPHA) ? 1 : 0) << DW_HSSI_CTRLR0_SCPH_OFFSET; + if (spi->mode & SPI_CPOL) + cr0 |= DW_HSSI_CTRLR0_SCPOL; + if (spi->mode & SPI_CPHA) + cr0 |= DW_HSSI_CTRLR0_SCPHA; /* CTRLR0[13] Shift Register Loop */ - cr0 |= ((spi->mode & SPI_LOOP) ? 1 : 0) << DW_HSSI_CTRLR0_SRL_OFFSET; + if (spi->mode & SPI_LOOP) + cr0 |= DW_HSSI_CTRLR0_SRL; if (dws->caps & DW_SPI_CAP_KEEMBAY_MST) cr0 |= DW_HSSI_CTRLR0_KEEMBAY_MST; @@ -320,10 +327,10 @@ void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi, if (!(dws->caps & DW_SPI_CAP_DWC_HSSI)) /* CTRLR0[ 9:8] Transfer Mode */ - cr0 |= cfg->tmode << DW_PSSI_CTRLR0_TMOD_OFFSET; + cr0 |= FIELD_PREP(DW_PSSI_CTRLR0_TMOD_MASK, cfg->tmode); else /* CTRLR0[11:10] Transfer Mode */ - cr0 |= cfg->tmode << DW_HSSI_CTRLR0_TMOD_OFFSET; + cr0 |= FIELD_PREP(DW_HSSI_CTRLR0_TMOD_MASK, cfg->tmode); dw_writel(dws, DW_SPI_CTRLR0, cr0); @@ -850,7 +857,7 @@ static void dw_spi_hw_init(struct device *dev, struct dw_spi *dws) if (!(cr0 & DW_PSSI_CTRLR0_DFS_MASK)) { dws->caps |= DW_SPI_CAP_DFS32; - dws->dfs_offset = DW_PSSI_CTRLR0_DFS32_OFFSET; + dws->dfs_offset = __bf_shf(DW_PSSI_CTRLR0_DFS32_MASK); dev_dbg(dev, "Detected 32-bits max data frame size\n"); } } else { diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index 893b78c43a507..634085eadad16 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -41,39 +41,36 @@ #define DW_SPI_CS_OVERRIDE 0xf4 /* Bit fields in CTRLR0 (DWC APB SSI) */ -#define DW_PSSI_CTRLR0_DFS_OFFSET 0 #define DW_PSSI_CTRLR0_DFS_MASK GENMASK(3, 0) -#define DW_PSSI_CTRLR0_DFS32_OFFSET 16 +#define DW_PSSI_CTRLR0_DFS32_MASK GENMASK(20, 16) -#define DW_PSSI_CTRLR0_FRF_OFFSET 4 +#define DW_PSSI_CTRLR0_FRF_MASK GENMASK(5, 4) #define DW_SPI_CTRLR0_FRF_MOTO_SPI 0x0 #define DW_SPI_CTRLR0_FRF_TI_SSP 0x1 #define DW_SPI_CTRLR0_FRF_NS_MICROWIRE 0x2 #define DW_SPI_CTRLR0_FRF_RESV 0x3 -#define DW_PSSI_CTRLR0_MODE_OFFSET 6 -#define DW_PSSI_CTRLR0_SCPH_OFFSET 6 -#define DW_PSSI_CTRLR0_SCOL_OFFSET 7 +#define DW_PSSI_CTRLR0_MODE_MASK GENMASK(7, 6) +#define DW_PSSI_CTRLR0_SCPHA BIT(6) +#define DW_PSSI_CTRLR0_SCPOL BIT(7) -#define DW_PSSI_CTRLR0_TMOD_OFFSET 8 -#define DW_PSSI_CTRLR0_TMOD_MASK (0x3 << DW_PSSI_CTRLR0_TMOD_OFFSET) +#define DW_PSSI_CTRLR0_TMOD_MASK GENMASK(9, 8) #define DW_SPI_CTRLR0_TMOD_TR 0x0 /* xmit & recv */ #define DW_SPI_CTRLR0_TMOD_TO 0x1 /* xmit only */ #define DW_SPI_CTRLR0_TMOD_RO 0x2 /* recv only */ #define DW_SPI_CTRLR0_TMOD_EPROMREAD 0x3 /* eeprom read mode */ -#define DW_PSSI_CTRLR0_SLVOE_OFFSET 10 -#define DW_PSSI_CTRLR0_SRL_OFFSET 11 -#define DW_PSSI_CTRLR0_CFS_OFFSET 12 +#define DW_PSSI_CTRLR0_SLV_OE BIT(10) +#define DW_PSSI_CTRLR0_SRL BIT(11) +#define DW_PSSI_CTRLR0_CFS BIT(12) /* Bit fields in CTRLR0 (DWC SSI with AHB interface) */ -#define DW_HSSI_CTRLR0_SRL_OFFSET 13 -#define DW_HSSI_CTRLR0_TMOD_OFFSET 10 +#define DW_HSSI_CTRLR0_DFS_MASK GENMASK(4, 0) +#define DW_HSSI_CTRLR0_FRF_MASK GENMASK(7, 6) +#define DW_HSSI_CTRLR0_SCPHA BIT(8) +#define DW_HSSI_CTRLR0_SCPOL BIT(9) #define DW_HSSI_CTRLR0_TMOD_MASK GENMASK(11, 10) -#define DW_HSSI_CTRLR0_SCPOL_OFFSET 9 -#define DW_HSSI_CTRLR0_SCPH_OFFSET 8 -#define DW_HSSI_CTRLR0_FRF_OFFSET 6 -#define DW_HSSI_CTRLR0_DFS_OFFSET 0 +#define DW_HSSI_CTRLR0_SRL BIT(13) /* * For Keem Bay, CTRLR0[31] is used to select controller mode. @@ -86,26 +83,27 @@ #define DW_SPI_NDF_MASK GENMASK(15, 0) /* Bit fields in SR, 7 bits */ -#define DW_SPI_SR_MASK 0x7f /* cover 7 bits */ -#define DW_SPI_SR_BUSY (1 << 0) -#define DW_SPI_SR_TF_NOT_FULL (1 << 1) -#define DW_SPI_SR_TF_EMPT (1 << 2) -#define DW_SPI_SR_RF_NOT_EMPT (1 << 3) -#define DW_SPI_SR_RF_FULL (1 << 4) -#define DW_SPI_SR_TX_ERR (1 << 5) -#define DW_SPI_SR_DCOL (1 << 6) +#define DW_SPI_SR_MASK GENMASK(6, 0) +#define DW_SPI_SR_BUSY BIT(0) +#define DW_SPI_SR_TF_NOT_FULL BIT(1) +#define DW_SPI_SR_TF_EMPT BIT(2) +#define DW_SPI_SR_RF_NOT_EMPT BIT(3) +#define DW_SPI_SR_RF_FULL BIT(4) +#define DW_SPI_SR_TX_ERR BIT(5) +#define DW_SPI_SR_DCOL BIT(6) /* Bit fields in ISR, IMR, RISR, 7 bits */ -#define DW_SPI_INT_TXEI (1 << 0) -#define DW_SPI_INT_TXOI (1 << 1) -#define DW_SPI_INT_RXUI (1 << 2) -#define DW_SPI_INT_RXOI (1 << 3) -#define DW_SPI_INT_RXFI (1 << 4) -#define DW_SPI_INT_MSTI (1 << 5) +#define DW_SPI_INT_MASK GENMASK(5, 0) +#define DW_SPI_INT_TXEI BIT(0) +#define DW_SPI_INT_TXOI BIT(1) +#define DW_SPI_INT_RXUI BIT(2) +#define DW_SPI_INT_RXOI BIT(3) +#define DW_SPI_INT_RXFI BIT(4) +#define DW_SPI_INT_MSTI BIT(5) /* Bit fields in DMACR */ -#define DW_SPI_DMACR_RDMAE (1 << 0) -#define DW_SPI_DMACR_TDMAE (1 << 1) +#define DW_SPI_DMACR_RDMAE BIT(0) +#define DW_SPI_DMACR_TDMAE BIT(1) /* Mem/DMA operations helpers */ #define DW_SPI_WAIT_RETRIES 5 -- GitLab From 2cc8d9227bbba7d6f3790a86f1ff0d665a75f3b8 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Mon, 15 Nov 2021 21:19:15 +0300 Subject: [PATCH 0044/1112] spi: dw: Introduce Synopsys IP-core versions interface The driver currently supports two IP-core versions. It's DW APB SSI which is older version of the controller with APB system bus interface, and DW SSI controller with AHB bus interface. The later one is supposed to be a new generation high-speed SSI. Even though both of these IP-cores have got an almost identical registers space there are some differences. The driver differentiates these distinctions by the DW_SPI_CAP_DWC_HSSI capability flag. In addition to that each DW SSI IP-core is equipped with a Synopsys Component version register, which encodes the IP-core release ID the has been synthesized from. Seeing we are going to need the later one to differentiate some controller peculiarities it would be better to have a unified interface for both IP-core line and release versions instead of using each of them separately. Introduced here IP-core versioning interface consists of two parts: 1) IDs of the IP-core (virtual) and component versions. 2) a set of macro helpers to identify current IP-core and component versions. So the platform code is supposed to assign a proper IP-core version based on it's platform -knowledge. The main driver initialization method reads the IP-core release ID from the SSI component version register. That data is used by the helpers to distinguish one IP-core release from another. Thus the rest of the driver can use these macros to implement the conditional code execution based on the specified IP-core and version IDs. Collect the IP-core versions interface and the defined capabilities at the top of the header file since they represent a common device description data and so to immediately available for the driver hackers. Signed-off-by: Serge Semin Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211115181917.7521-6-Sergey.Semin@baikalelectronics.ru Signed-off-by: Mark Brown --- drivers/spi/spi-dw-core.c | 14 ++++++++++++++ drivers/spi/spi-dw.h | 36 ++++++++++++++++++++++++++++-------- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c index b9f809989fda5..42536b448dddb 100644 --- a/drivers/spi/spi-dw-core.c +++ b/drivers/spi/spi-dw-core.c @@ -823,6 +823,20 @@ static void dw_spi_hw_init(struct device *dev, struct dw_spi *dws) { dw_spi_reset_chip(dws); + /* + * Retrieve the Synopsys component version if it hasn't been specified + * by the platform. CoreKit version ID is encoded as a 3-chars ASCII + * code enclosed with '*' (typical for the most of Synopsys IP-cores). + */ + if (!dws->ver) { + dws->ver = dw_readl(dws, DW_SPI_VERSION); + + dev_dbg(dev, "Synopsys DWC%sSSI v%c.%c%c\n", + (dws->caps & DW_SPI_CAP_DWC_HSSI) ? " " : " APB ", + DW_SPI_GET_BYTE(dws->ver, 3), DW_SPI_GET_BYTE(dws->ver, 2), + DW_SPI_GET_BYTE(dws->ver, 1)); + } + /* * Try to detect the FIFO depth if not set by interface driver, * the depth could be from 2 to 256 from HW spec diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index 634085eadad16..2f7d77024b485 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -11,6 +11,30 @@ #include #include +/* Synopsys DW SSI IP-core virtual IDs */ +#define DW_PSSI_ID 0 +#define DW_HSSI_ID 1 + +/* Synopsys DW SSI component versions (FourCC sequence) */ +#define DW_HSSI_102A 0x3130322a + +/* DW SSI IP-core ID and version check helpers */ +#define dw_spi_ip_is(_dws, _ip) \ + ((_dws)->ip == DW_ ## _ip ## _ID) + +#define __dw_spi_ver_cmp(_dws, _ip, _ver, _op) \ + (dw_spi_ip_is(_dws, _ip) && (_dws)->ver _op DW_ ## _ip ## _ver) + +#define dw_spi_ver_is(_dws, _ip, _ver) __dw_spi_ver_cmp(_dws, _ip, _ver, ==) + +#define dw_spi_ver_is_ge(_dws, _ip, _ver) __dw_spi_ver_cmp(_dws, _ip, _ver, >=) + +/* DW SPI controller capabilities */ +#define DW_SPI_CAP_CS_OVERRIDE BIT(0) +#define DW_SPI_CAP_KEEMBAY_MST BIT(1) +#define DW_SPI_CAP_DWC_HSSI BIT(2) +#define DW_SPI_CAP_DFS32 BIT(3) + /* Register offsets (Generic for both DWC APB SSI and DWC SSI IP-cores) */ #define DW_SPI_CTRLR0 0x00 #define DW_SPI_CTRLR1 0x04 @@ -113,12 +137,6 @@ #define DW_SPI_GET_BYTE(_val, _idx) \ ((_val) >> (BITS_PER_BYTE * (_idx)) & 0xff) -/* DW SPI capabilities */ -#define DW_SPI_CAP_CS_OVERRIDE BIT(0) -#define DW_SPI_CAP_KEEMBAY_MST BIT(1) -#define DW_SPI_CAP_DWC_HSSI BIT(2) -#define DW_SPI_CAP_DFS32 BIT(3) - /* Slave spi_transfer/spi_mem_op related */ struct dw_spi_cfg { u8 tmode; @@ -141,6 +159,10 @@ struct dw_spi_dma_ops { struct dw_spi { struct spi_controller *master; + u32 ip; /* Synopsys DW SSI IP-core ID */ + u32 ver; /* Synopsys component version */ + u32 caps; /* DW SPI capabilities */ + void __iomem *regs; unsigned long paddr; int irq; @@ -149,8 +171,6 @@ struct dw_spi { u32 max_mem_freq; /* max mem-ops bus freq */ u32 max_freq; /* max bus freq supported */ - u32 caps; /* DW SPI capabilities */ - u32 reg_io_width; /* DR I/O width in bytes */ u16 bus_num; u16 num_cs; /* supported slave numbers */ -- GitLab From 2b8a47e0b6984b9795baa20ddcbd37e9ea9b2a91 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Mon, 15 Nov 2021 21:19:16 +0300 Subject: [PATCH 0045/1112] spi: dw: Replace DWC_HSSI capability with IP-core version checker Since there is a common IP-core and component versions interface available we can use it to differentiate the DW HSSI device features in the code. Let's remove the corresponding DWC_HSSI capability flag then and use the dw_spi_ip_is() macro instead. Signed-off-by: Serge Semin Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211115181917.7521-7-Sergey.Semin@baikalelectronics.ru Signed-off-by: Mark Brown --- drivers/spi/spi-dw-core.c | 8 ++++---- drivers/spi/spi-dw-mmio.c | 5 +++-- drivers/spi/spi-dw.h | 1 - 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c index 42536b448dddb..934cc7a922e85 100644 --- a/drivers/spi/spi-dw-core.c +++ b/drivers/spi/spi-dw-core.c @@ -272,7 +272,7 @@ static u32 dw_spi_prepare_cr0(struct dw_spi *dws, struct spi_device *spi) { u32 cr0 = 0; - if (!(dws->caps & DW_SPI_CAP_DWC_HSSI)) { + if (dw_spi_ip_is(dws, PSSI)) { /* CTRLR0[ 5: 4] Frame Format */ cr0 |= FIELD_PREP(DW_PSSI_CTRLR0_FRF_MASK, DW_SPI_CTRLR0_FRF_MOTO_SPI); @@ -325,7 +325,7 @@ void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi, /* CTRLR0[ 4/3: 0] or CTRLR0[ 20: 16] Data Frame Size */ cr0 |= (cfg->dfs - 1) << dws->dfs_offset; - if (!(dws->caps & DW_SPI_CAP_DWC_HSSI)) + if (dw_spi_ip_is(dws, PSSI)) /* CTRLR0[ 9:8] Transfer Mode */ cr0 |= FIELD_PREP(DW_PSSI_CTRLR0_TMOD_MASK, cfg->tmode); else @@ -832,7 +832,7 @@ static void dw_spi_hw_init(struct device *dev, struct dw_spi *dws) dws->ver = dw_readl(dws, DW_SPI_VERSION); dev_dbg(dev, "Synopsys DWC%sSSI v%c.%c%c\n", - (dws->caps & DW_SPI_CAP_DWC_HSSI) ? " " : " APB ", + dw_spi_ip_is(dws, PSSI) ? " APB " : " ", DW_SPI_GET_BYTE(dws->ver, 3), DW_SPI_GET_BYTE(dws->ver, 2), DW_SPI_GET_BYTE(dws->ver, 1)); } @@ -860,7 +860,7 @@ static void dw_spi_hw_init(struct device *dev, struct dw_spi *dws) * writability. Note DWC SSI controller also has the extended DFS, but * with zero offset. */ - if (!(dws->caps & DW_SPI_CAP_DWC_HSSI)) { + if (dw_spi_ip_is(dws, PSSI)) { u32 cr0, tmp = dw_readl(dws, DW_SPI_CTRLR0); dw_spi_enable_chip(dws, 0); diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index 2193c2550e741..5101c4c6017b6 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -207,7 +207,7 @@ static int dw_spi_pssi_init(struct platform_device *pdev, static int dw_spi_hssi_init(struct platform_device *pdev, struct dw_spi_mmio *dwsmmio) { - dwsmmio->dws.caps = DW_SPI_CAP_DWC_HSSI; + dwsmmio->dws.ip = DW_HSSI_ID; dw_spi_dma_setup_generic(&dwsmmio->dws); @@ -217,7 +217,8 @@ static int dw_spi_hssi_init(struct platform_device *pdev, static int dw_spi_keembay_init(struct platform_device *pdev, struct dw_spi_mmio *dwsmmio) { - dwsmmio->dws.caps = DW_SPI_CAP_KEEMBAY_MST | DW_SPI_CAP_DWC_HSSI; + dwsmmio->dws.ip = DW_HSSI_ID; + dwsmmio->dws.caps = DW_SPI_CAP_KEEMBAY_MST; return 0; } diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index 2f7d77024b485..8334e6b35f89d 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -32,7 +32,6 @@ /* DW SPI controller capabilities */ #define DW_SPI_CAP_CS_OVERRIDE BIT(0) #define DW_SPI_CAP_KEEMBAY_MST BIT(1) -#define DW_SPI_CAP_DWC_HSSI BIT(2) #define DW_SPI_CAP_DFS32 BIT(3) /* Register offsets (Generic for both DWC APB SSI and DWC SSI IP-cores) */ -- GitLab From 44ebcb44584f81d1d38fafb45cf57d651f44616e Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Mon, 15 Nov 2021 21:19:17 +0300 Subject: [PATCH 0046/1112] spi: dw: Define the capabilities in a continuous bit-flags set Since the DW_SPI_CAP_DWC_HSSI capability has just been replaced with using the DW SSI IP-core versions interface, the DW SPI capability flags are now represented with a gap. Let's fix it by redefining the DW_SPI_CAP_DFS32 macro to setting BIT(2) of the capabilities field. Signed-off-by: Serge Semin Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211115181917.7521-8-Sergey.Semin@baikalelectronics.ru Signed-off-by: Mark Brown --- drivers/spi/spi-dw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index 8334e6b35f89d..d5ee5130601e1 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -32,7 +32,7 @@ /* DW SPI controller capabilities */ #define DW_SPI_CAP_CS_OVERRIDE BIT(0) #define DW_SPI_CAP_KEEMBAY_MST BIT(1) -#define DW_SPI_CAP_DFS32 BIT(3) +#define DW_SPI_CAP_DFS32 BIT(2) /* Register offsets (Generic for both DWC APB SSI and DWC SSI IP-cores) */ #define DW_SPI_CTRLR0 0x00 -- GitLab From f9a09de33b47a8ac9a128fea54a549dddf87c6b4 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Mon, 8 Nov 2021 17:27:04 +0100 Subject: [PATCH 0047/1112] dt-bindings: power: supply: add Maxim MAX77976 battery charger Add bindings for the Maxim MAX77976 I2C-controlled battery charger. Signed-off-by: Luca Ceresoli Signed-off-by: Sebastian Reichel --- .../bindings/power/supply/maxim,max77976.yaml | 44 +++++++++++++++++++ MAINTAINERS | 5 +++ 2 files changed, 49 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/supply/maxim,max77976.yaml diff --git a/Documentation/devicetree/bindings/power/supply/maxim,max77976.yaml b/Documentation/devicetree/bindings/power/supply/maxim,max77976.yaml new file mode 100644 index 0000000000000..675b9b26d2337 --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/maxim,max77976.yaml @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/supply/maxim,max77976.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim Integrated MAX77976 Battery charger + +maintainers: + - Luca Ceresoli + +description: | + The Maxim MAX77976 is a 19Vin / 5.5A, 1-Cell Li+ battery charger + configured via I2C. + +allOf: + - $ref: power-supply.yaml# + +properties: + compatible: + const: maxim,max77976 + + reg: + maxItems: 1 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + charger@6b { + compatible = "maxim,max77976"; + reg = <0x6b>; + }; + }; + +... diff --git a/MAINTAINERS b/MAINTAINERS index 7a2345ce85213..b2347950360e9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11580,6 +11580,11 @@ F: Documentation/devicetree/bindings/*/*max77802.txt F: drivers/regulator/max77802-regulator.c F: include/dt-bindings/*/*max77802.h +MAXIM MAX77976 BATTERY CHARGER +M: Luca Ceresoli +S: Supported +F: Documentation/devicetree/bindings/power/supply/maxim,max77976.yaml + MAXIM MUIC CHARGER DRIVERS FOR EXYNOS BASED BOARDS M: Krzysztof Kozlowski M: Bartlomiej Zolnierkiewicz -- GitLab From 77d641baa3c8e18a1056bec6c64c6103c1a17b1e Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Mon, 8 Nov 2021 17:27:05 +0100 Subject: [PATCH 0048/1112] power: supply: core: add POWER_SUPPLY_HEALTH_NO_BATTERY Some chargers can keep the system powered from the mains even when no battery is present. It this case none of the currently defined health statuses applies. Add a new status to report that no battery is present. Suggested-by: Sebastian Reichel Signed-off-by: Luca Ceresoli Signed-off-by: Sebastian Reichel --- Documentation/ABI/testing/sysfs-class-power | 2 +- drivers/power/supply/power_supply_sysfs.c | 1 + include/linux/power_supply.h | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-class-power b/Documentation/ABI/testing/sysfs-class-power index f7904efc4cfa0..a0b2a4280e381 100644 --- a/Documentation/ABI/testing/sysfs-class-power +++ b/Documentation/ABI/testing/sysfs-class-power @@ -413,7 +413,7 @@ Description: "Over voltage", "Unspecified failure", "Cold", "Watchdog timer expire", "Safety timer expire", "Over current", "Calibration required", "Warm", - "Cool", "Hot" + "Cool", "Hot", "No battery" What: /sys/class/power_supply//precharge_current Date: June 2017 diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index c3d7cbcd4fad5..6ac88fbee3cb3 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -106,6 +106,7 @@ static const char * const POWER_SUPPLY_HEALTH_TEXT[] = { [POWER_SUPPLY_HEALTH_WARM] = "Warm", [POWER_SUPPLY_HEALTH_COOL] = "Cool", [POWER_SUPPLY_HEALTH_HOT] = "Hot", + [POWER_SUPPLY_HEALTH_NO_BATTERY] = "No battery", }; static const char * const POWER_SUPPLY_TECHNOLOGY_TEXT[] = { diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 9ca1f120a2117..2d1318fe2455e 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -66,6 +66,7 @@ enum { POWER_SUPPLY_HEALTH_WARM, POWER_SUPPLY_HEALTH_COOL, POWER_SUPPLY_HEALTH_HOT, + POWER_SUPPLY_HEALTH_NO_BATTERY, }; enum { -- GitLab From 715ecbc10d6a77cce1c3bec8ba10e59be5233b4f Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Mon, 8 Nov 2021 17:27:06 +0100 Subject: [PATCH 0049/1112] power: supply: max77976: add Maxim MAX77976 charger driver Add support for the MAX77976 3.5/5.5A 1-Cell Li+ Battery Charger. This is a simple implementation enough to be used as a simple battery charger without OTG and boost. Signed-off-by: Luca Ceresoli Signed-off-by: Sebastian Reichel --- MAINTAINERS | 1 + drivers/power/supply/Kconfig | 12 + drivers/power/supply/Makefile | 1 + drivers/power/supply/max77976_charger.c | 509 ++++++++++++++++++++++++ 4 files changed, 523 insertions(+) create mode 100644 drivers/power/supply/max77976_charger.c diff --git a/MAINTAINERS b/MAINTAINERS index b2347950360e9..96f748c09b629 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11584,6 +11584,7 @@ MAXIM MAX77976 BATTERY CHARGER M: Luca Ceresoli S: Supported F: Documentation/devicetree/bindings/power/supply/maxim,max77976.yaml +F: drivers/power/supply/max77976_charger.c MAXIM MUIC CHARGER DRIVERS FOR EXYNOS BASED BOARDS M: Krzysztof Kozlowski diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 5cf5bb56d2e38..b366e2fd8e97f 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -557,6 +557,18 @@ config CHARGER_MAX77693 help Say Y to enable support for the Maxim MAX77693 battery charger. +config CHARGER_MAX77976 + tristate "Maxim MAX77976 battery charger driver" + depends on I2C + select REGMAP_I2C + help + The Maxim MAX77976 is a 19 Vin, 5.5A 1-Cell Li+ Battery Charger + USB OTG support. It has an I2C interface for configuration. + + Say Y to enable support for the Maxim MAX77976 battery charger. + This driver can also be built as a module. If so, the module will be + called max77976_charger. + config CHARGER_MAX8997 tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver" depends on MFD_MAX8997 && REGULATOR_MAX8997 diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index 4e55a11aab79f..2c1b264b20463 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -75,6 +75,7 @@ obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o obj-$(CONFIG_CHARGER_DETECTOR_MAX14656) += max14656_charger_detector.o obj-$(CONFIG_CHARGER_MAX77650) += max77650-charger.o obj-$(CONFIG_CHARGER_MAX77693) += max77693_charger.o +obj-$(CONFIG_CHARGER_MAX77976) += max77976_charger.o obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o obj-$(CONFIG_CHARGER_MP2629) += mp2629_charger.o diff --git a/drivers/power/supply/max77976_charger.c b/drivers/power/supply/max77976_charger.c new file mode 100644 index 0000000000000..8b6c8cfa75037 --- /dev/null +++ b/drivers/power/supply/max77976_charger.c @@ -0,0 +1,509 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * max77976_charger.c - Driver for the Maxim MAX77976 battery charger + * + * Copyright (C) 2021 Luca Ceresoli + * Author: Luca Ceresoli + */ + +#include +#include +#include +#include + +#define MAX77976_DRIVER_NAME "max77976-charger" +#define MAX77976_CHIP_ID 0x76 + +static const char *max77976_manufacturer = "Maxim Integrated"; +static const char *max77976_model = "MAX77976"; + +/* -------------------------------------------------------------------------- + * Register map + */ + +#define MAX77976_REG_CHIP_ID 0x00 +#define MAX77976_REG_CHIP_REVISION 0x01 +#define MAX77976_REG_CHG_INT_OK 0x12 +#define MAX77976_REG_CHG_DETAILS_01 0x14 +#define MAX77976_REG_CHG_CNFG_00 0x16 +#define MAX77976_REG_CHG_CNFG_02 0x18 +#define MAX77976_REG_CHG_CNFG_06 0x1c +#define MAX77976_REG_CHG_CNFG_09 0x1f + +/* CHG_DETAILS_01.CHG_DTLS values */ +enum max77976_charging_state { + MAX77976_CHARGING_PREQUALIFICATION = 0x0, + MAX77976_CHARGING_FAST_CONST_CURRENT, + MAX77976_CHARGING_FAST_CONST_VOLTAGE, + MAX77976_CHARGING_TOP_OFF, + MAX77976_CHARGING_DONE, + MAX77976_CHARGING_RESERVED_05, + MAX77976_CHARGING_TIMER_FAULT, + MAX77976_CHARGING_SUSPENDED_QBATT_OFF, + MAX77976_CHARGING_OFF, + MAX77976_CHARGING_RESERVED_09, + MAX77976_CHARGING_THERMAL_SHUTDOWN, + MAX77976_CHARGING_WATCHDOG_EXPIRED, + MAX77976_CHARGING_SUSPENDED_JEITA, + MAX77976_CHARGING_SUSPENDED_THM_REMOVAL, + MAX77976_CHARGING_SUSPENDED_PIN, + MAX77976_CHARGING_RESERVED_0F, +}; + +/* CHG_DETAILS_01.BAT_DTLS values */ +enum max77976_battery_state { + MAX77976_BATTERY_BATTERY_REMOVAL = 0x0, + MAX77976_BATTERY_PREQUALIFICATION, + MAX77976_BATTERY_TIMER_FAULT, + MAX77976_BATTERY_REGULAR_VOLTAGE, + MAX77976_BATTERY_LOW_VOLTAGE, + MAX77976_BATTERY_OVERVOLTAGE, + MAX77976_BATTERY_RESERVED, + MAX77976_BATTERY_BATTERY_ONLY, // No valid adapter is present +}; + +/* CHG_CNFG_00.MODE values */ +enum max77976_mode { + MAX77976_MODE_CHARGER_BUCK = 0x5, + MAX77976_MODE_BOOST = 0x9, +}; + +/* CHG_CNFG_02.CHG_CC: charge current limit, 100..5500 mA, 50 mA steps */ +#define MAX77976_CHG_CC_STEP 50000U +#define MAX77976_CHG_CC_MIN 100000U +#define MAX77976_CHG_CC_MAX 5500000U + +/* CHG_CNFG_09.CHGIN_ILIM: input current limit, 100..3200 mA, 100 mA steps */ +#define MAX77976_CHGIN_ILIM_STEP 100000U +#define MAX77976_CHGIN_ILIM_MIN 100000U +#define MAX77976_CHGIN_ILIM_MAX 3200000U + +enum max77976_field_idx { + VERSION, REVISION, /* CHIP_REVISION */ + CHGIN_OK, /* CHG_INT_OK */ + BAT_DTLS, CHG_DTLS, /* CHG_DETAILS_01 */ + MODE, /* CHG_CNFG_00 */ + CHG_CC, /* CHG_CNFG_02 */ + CHGPROT, /* CHG_CNFG_06 */ + CHGIN_ILIM, /* CHG_CNFG_09 */ + MAX77976_N_REGMAP_FIELDS +}; + +static const struct reg_field max77976_reg_field[MAX77976_N_REGMAP_FIELDS] = { + [VERSION] = REG_FIELD(MAX77976_REG_CHIP_REVISION, 4, 7), + [REVISION] = REG_FIELD(MAX77976_REG_CHIP_REVISION, 0, 3), + [CHGIN_OK] = REG_FIELD(MAX77976_REG_CHG_INT_OK, 6, 6), + [CHG_DTLS] = REG_FIELD(MAX77976_REG_CHG_DETAILS_01, 0, 3), + [BAT_DTLS] = REG_FIELD(MAX77976_REG_CHG_DETAILS_01, 4, 6), + [MODE] = REG_FIELD(MAX77976_REG_CHG_CNFG_00, 0, 3), + [CHG_CC] = REG_FIELD(MAX77976_REG_CHG_CNFG_02, 0, 6), + [CHGPROT] = REG_FIELD(MAX77976_REG_CHG_CNFG_06, 2, 3), + [CHGIN_ILIM] = REG_FIELD(MAX77976_REG_CHG_CNFG_09, 0, 5), +}; + +static const struct regmap_config max77976_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x24, +}; + +/* -------------------------------------------------------------------------- + * Data structures + */ + +struct max77976 { + struct i2c_client *client; + struct regmap *regmap; + struct regmap_field *rfield[MAX77976_N_REGMAP_FIELDS]; +}; + +/* -------------------------------------------------------------------------- + * power_supply properties + */ + +static int max77976_get_status(struct max77976 *chg, int *val) +{ + unsigned int regval; + int err; + + err = regmap_field_read(chg->rfield[CHG_DTLS], ®val); + if (err < 0) + return err; + + switch (regval) { + case MAX77976_CHARGING_PREQUALIFICATION: + case MAX77976_CHARGING_FAST_CONST_CURRENT: + case MAX77976_CHARGING_FAST_CONST_VOLTAGE: + case MAX77976_CHARGING_TOP_OFF: + *val = POWER_SUPPLY_STATUS_CHARGING; + break; + case MAX77976_CHARGING_DONE: + *val = POWER_SUPPLY_STATUS_FULL; + break; + case MAX77976_CHARGING_TIMER_FAULT: + case MAX77976_CHARGING_SUSPENDED_QBATT_OFF: + case MAX77976_CHARGING_SUSPENDED_JEITA: + case MAX77976_CHARGING_SUSPENDED_THM_REMOVAL: + case MAX77976_CHARGING_SUSPENDED_PIN: + *val = POWER_SUPPLY_STATUS_NOT_CHARGING; + break; + case MAX77976_CHARGING_OFF: + case MAX77976_CHARGING_THERMAL_SHUTDOWN: + case MAX77976_CHARGING_WATCHDOG_EXPIRED: + *val = POWER_SUPPLY_STATUS_DISCHARGING; + break; + default: + *val = POWER_SUPPLY_STATUS_UNKNOWN; + } + + return 0; +} + +static int max77976_get_charge_type(struct max77976 *chg, int *val) +{ + unsigned int regval; + int err; + + err = regmap_field_read(chg->rfield[CHG_DTLS], ®val); + if (err < 0) + return err; + + switch (regval) { + case MAX77976_CHARGING_PREQUALIFICATION: + *val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; + break; + case MAX77976_CHARGING_FAST_CONST_CURRENT: + case MAX77976_CHARGING_FAST_CONST_VOLTAGE: + *val = POWER_SUPPLY_CHARGE_TYPE_FAST; + break; + case MAX77976_CHARGING_TOP_OFF: + *val = POWER_SUPPLY_CHARGE_TYPE_STANDARD; + break; + case MAX77976_CHARGING_DONE: + case MAX77976_CHARGING_TIMER_FAULT: + case MAX77976_CHARGING_SUSPENDED_QBATT_OFF: + case MAX77976_CHARGING_OFF: + case MAX77976_CHARGING_THERMAL_SHUTDOWN: + case MAX77976_CHARGING_WATCHDOG_EXPIRED: + case MAX77976_CHARGING_SUSPENDED_JEITA: + case MAX77976_CHARGING_SUSPENDED_THM_REMOVAL: + case MAX77976_CHARGING_SUSPENDED_PIN: + *val = POWER_SUPPLY_CHARGE_TYPE_NONE; + break; + default: + *val = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; + } + + return 0; +} + +static int max77976_get_health(struct max77976 *chg, int *val) +{ + unsigned int regval; + int err; + + err = regmap_field_read(chg->rfield[BAT_DTLS], ®val); + if (err < 0) + return err; + + switch (regval) { + case MAX77976_BATTERY_BATTERY_REMOVAL: + *val = POWER_SUPPLY_HEALTH_NO_BATTERY; + break; + case MAX77976_BATTERY_LOW_VOLTAGE: + case MAX77976_BATTERY_REGULAR_VOLTAGE: + *val = POWER_SUPPLY_HEALTH_GOOD; + break; + case MAX77976_BATTERY_TIMER_FAULT: + *val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE; + break; + case MAX77976_BATTERY_OVERVOLTAGE: + *val = POWER_SUPPLY_HEALTH_OVERVOLTAGE; + break; + case MAX77976_BATTERY_PREQUALIFICATION: + case MAX77976_BATTERY_BATTERY_ONLY: + *val = POWER_SUPPLY_HEALTH_UNKNOWN; + break; + default: + *val = POWER_SUPPLY_HEALTH_UNKNOWN; + } + + return 0; +} + +static int max77976_get_online(struct max77976 *chg, int *val) +{ + unsigned int regval; + int err; + + err = regmap_field_read(chg->rfield[CHGIN_OK], ®val); + if (err < 0) + return err; + + *val = (regval ? 1 : 0); + + return 0; +} + +static int max77976_get_integer(struct max77976 *chg, enum max77976_field_idx fidx, + unsigned int clamp_min, unsigned int clamp_max, + unsigned int mult, int *val) +{ + unsigned int regval; + int err; + + err = regmap_field_read(chg->rfield[fidx], ®val); + if (err < 0) + return err; + + *val = clamp_val(regval * mult, clamp_min, clamp_max); + + return 0; +} + +static int max77976_set_integer(struct max77976 *chg, enum max77976_field_idx fidx, + unsigned int clamp_min, unsigned int clamp_max, + unsigned int div, int val) +{ + unsigned int regval; + + regval = clamp_val(val, clamp_min, clamp_max) / div; + + return regmap_field_write(chg->rfield[fidx], regval); +} + +static int max77976_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct max77976 *chg = power_supply_get_drvdata(psy); + int err = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + err = max77976_get_status(chg, &val->intval); + break; + case POWER_SUPPLY_PROP_CHARGE_TYPE: + err = max77976_get_charge_type(chg, &val->intval); + break; + case POWER_SUPPLY_PROP_HEALTH: + err = max77976_get_health(chg, &val->intval); + break; + case POWER_SUPPLY_PROP_ONLINE: + err = max77976_get_online(chg, &val->intval); + break; + case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX: + val->intval = MAX77976_CHG_CC_MAX; + break; + case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: + err = max77976_get_integer(chg, CHG_CC, + MAX77976_CHG_CC_MIN, + MAX77976_CHG_CC_MAX, + MAX77976_CHG_CC_STEP, + &val->intval); + break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + err = max77976_get_integer(chg, CHGIN_ILIM, + MAX77976_CHGIN_ILIM_MIN, + MAX77976_CHGIN_ILIM_MAX, + MAX77976_CHGIN_ILIM_STEP, + &val->intval); + break; + case POWER_SUPPLY_PROP_MODEL_NAME: + val->strval = max77976_model; + break; + case POWER_SUPPLY_PROP_MANUFACTURER: + val->strval = max77976_manufacturer; + break; + default: + err = -EINVAL; + } + + return err; +} + +static int max77976_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct max77976 *chg = power_supply_get_drvdata(psy); + int err = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: + err = max77976_set_integer(chg, CHG_CC, + MAX77976_CHG_CC_MIN, + MAX77976_CHG_CC_MAX, + MAX77976_CHG_CC_STEP, + val->intval); + break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + err = max77976_set_integer(chg, CHGIN_ILIM, + MAX77976_CHGIN_ILIM_MIN, + MAX77976_CHGIN_ILIM_MAX, + MAX77976_CHGIN_ILIM_STEP, + val->intval); + break; + default: + err = -EINVAL; + } + + return err; +}; + +static int max77976_property_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + switch (psp) { + case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + return true; + default: + return false; + } +} + +static enum power_supply_property max77976_psy_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_CHARGE_TYPE, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, + POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + +static const struct power_supply_desc max77976_psy_desc = { + .name = MAX77976_DRIVER_NAME, + .type = POWER_SUPPLY_TYPE_USB, + .properties = max77976_psy_props, + .num_properties = ARRAY_SIZE(max77976_psy_props), + .get_property = max77976_get_property, + .set_property = max77976_set_property, + .property_is_writeable = max77976_property_is_writeable, +}; + +/* -------------------------------------------------------------------------- + * Entry point + */ + +static int max77976_detect(struct max77976 *chg) +{ + struct device *dev = &chg->client->dev; + unsigned int id, ver, rev; + int err; + + err = regmap_read(chg->regmap, MAX77976_REG_CHIP_ID, &id); + if (err) + return dev_err_probe(dev, err, "cannot read chip ID\n"); + + if (id != MAX77976_CHIP_ID) + return dev_err_probe(dev, -ENXIO, "unknown model ID 0x%02x\n", id); + + err = regmap_field_read(chg->rfield[VERSION], &ver); + if (!err) + err = regmap_field_read(chg->rfield[REVISION], &rev); + if (err) + return dev_err_probe(dev, -ENXIO, "cannot read version/revision\n"); + + dev_info(dev, "detected model MAX779%02x ver %u rev %u", id, ver, rev); + + return 0; +} + +static int max77976_configure(struct max77976 *chg) +{ + struct device *dev = &chg->client->dev; + int err; + + /* Magic value to unlock writing to some registers */ + err = regmap_field_write(chg->rfield[CHGPROT], 0x3); + if (err) + goto err; + + /* + * Mode 5 = Charger ON, OTG OFF, buck ON, boost OFF. + * Other modes are not implemented by this driver. + */ + err = regmap_field_write(chg->rfield[MODE], MAX77976_MODE_CHARGER_BUCK); + if (err) + goto err; + + return 0; + +err: + return dev_err_probe(dev, err, "error while configuring"); +} + +static int max77976_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct power_supply_config psy_cfg = {}; + struct power_supply *psy; + struct max77976 *chg; + int err; + int i; + + chg = devm_kzalloc(dev, sizeof(*chg), GFP_KERNEL); + if (!chg) + return -ENOMEM; + + i2c_set_clientdata(client, chg); + psy_cfg.drv_data = chg; + chg->client = client; + + chg->regmap = devm_regmap_init_i2c(client, &max77976_regmap_config); + if (IS_ERR(chg->regmap)) + return dev_err_probe(dev, PTR_ERR(chg->regmap), + "cannot allocate regmap\n"); + + for (i = 0; i < MAX77976_N_REGMAP_FIELDS; i++) { + chg->rfield[i] = devm_regmap_field_alloc(dev, chg->regmap, + max77976_reg_field[i]); + if (IS_ERR(chg->rfield[i])) + return dev_err_probe(dev, PTR_ERR(chg->rfield[i]), + "cannot allocate regmap field\n"); + } + + err = max77976_detect(chg); + if (err) + return err; + + err = max77976_configure(chg); + if (err) + return err; + + psy = devm_power_supply_register_no_ws(dev, &max77976_psy_desc, &psy_cfg); + if (IS_ERR(psy)) + return dev_err_probe(dev, PTR_ERR(psy), "cannot register\n"); + + return 0; +} + +static const struct i2c_device_id max77976_i2c_id[] = { + { MAX77976_DRIVER_NAME, 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, max77976_i2c_id); + +static const struct of_device_id max77976_of_id[] = { + { .compatible = "maxim,max77976" }, + { }, +}; +MODULE_DEVICE_TABLE(of, max77976_of_id); + +static struct i2c_driver max77976_driver = { + .driver = { + .name = MAX77976_DRIVER_NAME, + .of_match_table = max77976_of_id, + }, + .probe_new = max77976_probe, + .id_table = max77976_i2c_id, +}; +module_i2c_driver(max77976_driver); + +MODULE_AUTHOR("Luca Ceresoli "); +MODULE_DESCRIPTION("Maxim MAX77976 charger driver"); +MODULE_LICENSE("GPL v2"); -- GitLab From a360ae43217c45fb7ca37603ffb6c06aad2b3929 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 29 Oct 2021 20:26:09 +0300 Subject: [PATCH 0050/1112] mtd: spi-nor: core: Fix spi_nor_flash_parameter otp description Update the description of the otp member of the struct spi_nor_flash_parameter. Signed-off-by: Tudor Ambarus Reviewed-by: Pratyush Yadav Reviewed-by: Michael Walle Link: https://lore.kernel.org/r/20211029172633.886453-2-tudor.ambarus@microchip.com --- drivers/mtd/spi-nor/core.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index 3348e1dd14452..da3fd3636d3c1 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -250,7 +250,7 @@ struct spi_nor_otp { * higher index in the array, the higher priority. * @erase_map: the erase map parsed from the SFDP Sector Map Parameter * Table. - * @otp_info: describes the OTP regions. + * @otp: SPI NOR OTP info. * @octal_dtr_enable: enables SPI NOR octal DTR mode. * @quad_enable: enables SPI NOR quad mode. * @set_4byte_addr_mode: puts the SPI NOR in 4 byte addressing mode. @@ -262,7 +262,6 @@ struct spi_nor_otp { * e.g. different opcodes, specific address calculation, * page size, etc. * @locking_ops: SPI NOR locking methods. - * @otp: SPI NOR OTP methods. */ struct spi_nor_flash_parameter { u64 size; -- GitLab From 7158c86e560789a4a07fe161cc284f8058d52ccc Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 29 Oct 2021 20:26:10 +0300 Subject: [PATCH 0051/1112] mtd: spi-nor: core: Use container_of to get the pointer to struct spi_nor "struct mtd_info mtd" is member of "struct spi_nor", there's no need to use "mtd->priv". Get the pointer to the containing struct spi_nor by using container_of. While here, make the function inline and get rid of the __maybe_unused. Signed-off-by: Tudor Ambarus Reviewed-by: Michael Walle Reviewed-by: Pratyush Yadav Link: https://lore.kernel.org/r/20211029172633.886453-3-tudor.ambarus@microchip.com --- drivers/mtd/spi-nor/core.c | 1 - drivers/mtd/spi-nor/core.h | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index cc08bd707378f..277d1fde84c84 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -3134,7 +3134,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, if (!mtd->name) mtd->name = dev_name(dev); - mtd->priv = nor; mtd->type = MTD_NORFLASH; mtd->writesize = nor->params->writesize; mtd->flags = MTD_CAP_NORFLASH; diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index da3fd3636d3c1..223a037699506 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -551,9 +551,9 @@ void spi_nor_try_unlock_all(struct spi_nor *nor); void spi_nor_register_locking_ops(struct spi_nor *nor); void spi_nor_otp_init(struct spi_nor *nor); -static struct spi_nor __maybe_unused *mtd_to_spi_nor(struct mtd_info *mtd) +static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd) { - return mtd->priv; + return container_of(mtd, struct spi_nor, mtd); } #endif /* __LINUX_MTD_SPI_NOR_INTERNAL_H */ -- GitLab From 5854d4a6cc356ba3e16d8593ac1c089a32d1759c Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 29 Oct 2021 20:26:12 +0300 Subject: [PATCH 0052/1112] mtd: spi-nor: Get rid of nor->page_size nor->page_size duplicated what nor->params->page_size indicates for no good reason. page_size is a flash parameter of fixed value and it is better suited to be found in nor->params->page_size. Signed-off-by: Tudor Ambarus Reviewed-by: Pratyush Yadav Reviewed-by: Michael Walle Link: https://lore.kernel.org/r/20211029172633.886453-5-tudor.ambarus@microchip.com --- drivers/mtd/spi-nor/core.c | 19 +++++++++---------- drivers/mtd/spi-nor/xilinx.c | 17 ++++++++++------- include/linux/mtd/spi-nor.h | 2 -- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 277d1fde84c84..3ec0959ffc20b 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -1952,6 +1952,7 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, struct spi_nor *nor = mtd_to_spi_nor(mtd); size_t page_offset, page_remain, i; ssize_t ret; + u32 page_size = nor->params->page_size; dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len); @@ -1968,16 +1969,15 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, * calculated with an AND operation. On the other cases we * need to do a modulus operation (more expensive). */ - if (is_power_of_2(nor->page_size)) { - page_offset = addr & (nor->page_size - 1); + if (is_power_of_2(page_size)) { + page_offset = addr & (page_size - 1); } else { uint64_t aux = addr; - page_offset = do_div(aux, nor->page_size); + page_offset = do_div(aux, page_size); } /* the size of data remaining on the first page */ - page_remain = min_t(size_t, - nor->page_size - page_offset, len - i); + page_remain = min_t(size_t, page_size - page_offset, len - i); addr = spi_nor_convert_addr(nor, addr); @@ -3094,7 +3094,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, * We need the bounce buffer early to read/write registers when going * through the spi-mem layer (buffers have to be DMA-able). * For spi-mem drivers, we'll reallocate a new buffer if - * nor->page_size turns out to be greater than PAGE_SIZE (which + * nor->params->page_size turns out to be greater than PAGE_SIZE (which * shouldn't happen before long since NOR pages are usually less * than 1KB) after spi_nor_scan() returns. */ @@ -3170,8 +3170,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, mtd->flags |= MTD_NO_ERASE; mtd->dev.parent = dev; - nor->page_size = nor->params->page_size; - mtd->writebufsize = nor->page_size; + mtd->writebufsize = nor->params->page_size; if (of_property_read_bool(np, "broken-flash-reset")) nor->flags |= SNOR_F_BROKEN_RESET; @@ -3340,8 +3339,8 @@ static int spi_nor_probe(struct spi_mem *spimem) * and add this logic so that if anyone ever adds support for such * a NOR we don't end up with buffer overflows. */ - if (nor->page_size > PAGE_SIZE) { - nor->bouncebuf_size = nor->page_size; + if (nor->params->page_size > PAGE_SIZE) { + nor->bouncebuf_size = nor->params->page_size; devm_kfree(nor->dev, nor->bouncebuf); nor->bouncebuf = devm_kmalloc(nor->dev, nor->bouncebuf_size, diff --git a/drivers/mtd/spi-nor/xilinx.c b/drivers/mtd/spi-nor/xilinx.c index 1138bdbf41998..0658e47564bac 100644 --- a/drivers/mtd/spi-nor/xilinx.c +++ b/drivers/mtd/spi-nor/xilinx.c @@ -28,11 +28,12 @@ static const struct flash_info xilinx_parts[] = { */ static u32 s3an_convert_addr(struct spi_nor *nor, u32 addr) { + u32 page_size = nor->params->page_size; u32 offset, page; - offset = addr % nor->page_size; - page = addr / nor->page_size; - page <<= (nor->page_size > 512) ? 10 : 9; + offset = addr % page_size; + page = addr / page_size; + page <<= (page_size > 512) ? 10 : 9; return page | offset; } @@ -40,6 +41,7 @@ static u32 s3an_convert_addr(struct spi_nor *nor, u32 addr) static int xilinx_nor_setup(struct spi_nor *nor, const struct spi_nor_hwcaps *hwcaps) { + u32 page_size; int ret; ret = spi_nor_xread_sr(nor, nor->bouncebuf); @@ -64,10 +66,11 @@ static int xilinx_nor_setup(struct spi_nor *nor, */ if (nor->bouncebuf[0] & XSR_PAGESIZE) { /* Flash in Power of 2 mode */ - nor->page_size = (nor->page_size == 264) ? 256 : 512; - nor->mtd.writebufsize = nor->page_size; - nor->mtd.size = 8 * nor->page_size * nor->info->n_sectors; - nor->mtd.erasesize = 8 * nor->page_size; + page_size = (nor->params->page_size == 264) ? 256 : 512; + nor->params->page_size = page_size; + nor->mtd.writebufsize = page_size; + nor->mtd.size = 8 * page_size * nor->info->n_sectors; + nor->mtd.erasesize = 8 * page_size; } else { /* Flash in Default addressing mode */ nor->params->convert_addr = s3an_convert_addr; diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index f67457748ed84..fc90fce26e337 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -371,7 +371,6 @@ struct spi_nor_flash_parameter; * @bouncebuf_size: size of the bounce buffer * @info: SPI NOR part JEDEC MFR ID and other info * @manufacturer: SPI NOR manufacturer - * @page_size: the page size of the SPI NOR * @addr_width: number of address bytes * @erase_opcode: the opcode for erasing a sector * @read_opcode: the read opcode @@ -401,7 +400,6 @@ struct spi_nor { size_t bouncebuf_size; const struct flash_info *info; const struct spi_nor_manufacturer *manufacturer; - u32 page_size; u8 addr_width; u8 erase_opcode; u8 read_opcode; -- GitLab From dacc8cfee493891b130507a4646806b3d0597ee7 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 29 Oct 2021 20:26:13 +0300 Subject: [PATCH 0053/1112] mtd: spi-nor: core: Introduce the late_init() hook Flash parameters init is done in a spaghetti way right now. There is the init based on the flash_info data, then there is the default_init() hook, then SFDP init, an intermediary post_bft(), then post_sfdp() and a spi_nor_late_init_params(). Each method can overwrite previuosly initialized parameters. We want to separate what is SFDP and non-SFDP specific. late_init() will replace the default_init() hook and will be used only to initialize flash parameters that are not declared in the JESD216 SFDP standard, or where SFDP tables are not defined at all. We cut a member in the chain of initializing parameters by getting rid of the default_init() hook, and we make it clear that everything that is in late_init() is not covered by the SFDP tables defined by the flash. Signed-off-by: Tudor Ambarus Reviewed-by: Michael Walle Reviewed-by: Pratyush Yadav Link: https://lore.kernel.org/r/20211029172633.886453-6-tudor.ambarus@microchip.com --- drivers/mtd/spi-nor/core.c | 17 +++++++++++++---- drivers/mtd/spi-nor/core.h | 4 ++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 3ec0959ffc20b..88dd0908d1728 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -2666,11 +2666,19 @@ static void spi_nor_post_sfdp_fixups(struct spi_nor *nor) * spi_nor_late_init_params() - Late initialization of default flash parameters. * @nor: pointer to a 'struct spi_nor' * - * Used to set default flash parameters and settings when the ->default_init() - * hook or the SFDP parser let voids. + * Used to initialize flash parameters that are not declared in the JESD216 + * SFDP standard, or where SFDP tables are not defined at all. + * Will replace the spi_nor_manufacturer_init_params() method. */ static void spi_nor_late_init_params(struct spi_nor *nor) { + if (nor->manufacturer && nor->manufacturer->fixups && + nor->manufacturer->fixups->late_init) + nor->manufacturer->fixups->late_init(nor); + + if (nor->info->fixups && nor->info->fixups->late_init) + nor->info->fixups->late_init(nor); + /* * NOR protection support. When locking_ops are not provided, we pick * the default ones. @@ -2712,8 +2720,9 @@ static void spi_nor_late_init_params(struct spi_nor *nor) * wrong). * spi_nor_post_sfdp_fixups() * - * 5/ Late default flash parameters initialization, used when the - * ->default_init() hook or the SFDP parser do not set specific params. + * 5/ Late flash parameters initialization, used to initialize flash + * parameters that are not declared in the JESD216 SFDP standard, or where SFDP + * tables are not defined at all. * spi_nor_late_init_params() */ static int spi_nor_init_params(struct spi_nor *nor) diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index 223a037699506..50bae06bc0244 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -297,6 +297,9 @@ struct spi_nor_flash_parameter { * parameters that could not be extracted by other means (i.e. * when information provided by the SFDP/flash_info tables are * incomplete or wrong). + * @late_init: used to initialize flash parameters that are not declared in the + * JESD216 SFDP standard, or where SFDP tables not defined at all. + * Will replace the default_init() hook. * * Those hooks can be used to tweak the SPI NOR configuration when the SFDP * table is broken or not available. @@ -307,6 +310,7 @@ struct spi_nor_fixups { const struct sfdp_parameter_header *bfpt_header, const struct sfdp_bfpt *bfpt); void (*post_sfdp)(struct spi_nor *nor); + void (*late_init)(struct spi_nor *nor); }; struct flash_info { -- GitLab From b0fa1db7d2f6803783707a8215e34616922ec3e7 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 29 Oct 2021 20:26:14 +0300 Subject: [PATCH 0054/1112] mtd: spi-nor: atmel: Use flash late_init() for locking Locking is not described in JESD216 SFDP standard, place the locking init in late_init(). Signed-off-by: Tudor Ambarus Reviewed-by: Michael Walle Reviewed-by: Pratyush Yadav Link: https://lore.kernel.org/r/20211029172633.886453-7-tudor.ambarus@microchip.com --- drivers/mtd/spi-nor/atmel.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/spi-nor/atmel.c b/drivers/mtd/spi-nor/atmel.c index 1fea5cab492c8..d0e7883b38e30 100644 --- a/drivers/mtd/spi-nor/atmel.c +++ b/drivers/mtd/spi-nor/atmel.c @@ -48,13 +48,13 @@ static const struct spi_nor_locking_ops atmel_at25fs_locking_ops = { .is_locked = atmel_at25fs_is_locked, }; -static void atmel_at25fs_default_init(struct spi_nor *nor) +static void atmel_at25fs_late_init(struct spi_nor *nor) { nor->params->locking_ops = &atmel_at25fs_locking_ops; } static const struct spi_nor_fixups atmel_at25fs_fixups = { - .default_init = atmel_at25fs_default_init, + .late_init = atmel_at25fs_late_init, }; /** @@ -146,13 +146,13 @@ static const struct spi_nor_locking_ops atmel_global_protection_ops = { .is_locked = atmel_is_global_protected, }; -static void atmel_global_protection_default_init(struct spi_nor *nor) +static void atmel_global_protection_late_init(struct spi_nor *nor) { nor->params->locking_ops = &atmel_global_protection_ops; } static const struct spi_nor_fixups atmel_global_protection_fixups = { - .default_init = atmel_global_protection_default_init, + .late_init = atmel_global_protection_late_init, }; static const struct flash_info atmel_parts[] = { -- GitLab From 7d4ff0613fb537315c7a4214de74d32b2615c72a Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 29 Oct 2021 20:26:15 +0300 Subject: [PATCH 0055/1112] mtd: spi-nor: sst: Use flash late_init() for locking Locking is not described in JESD216 SFDP standard, place the locking init in late_init(). Signed-off-by: Tudor Ambarus Reviewed-by: Michael Walle Reviewed-by: Pratyush Yadav Link: https://lore.kernel.org/r/20211029172633.886453-8-tudor.ambarus@microchip.com --- drivers/mtd/spi-nor/sst.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/spi-nor/sst.c b/drivers/mtd/spi-nor/sst.c index 980f4c09c91de..660aabde477a7 100644 --- a/drivers/mtd/spi-nor/sst.c +++ b/drivers/mtd/spi-nor/sst.c @@ -46,13 +46,13 @@ static const struct spi_nor_locking_ops sst26vf_locking_ops = { .is_locked = sst26vf_is_locked, }; -static void sst26vf_default_init(struct spi_nor *nor) +static void sst26vf_late_init(struct spi_nor *nor) { nor->params->locking_ops = &sst26vf_locking_ops; } static const struct spi_nor_fixups sst26vf_fixups = { - .default_init = sst26vf_default_init, + .late_init = sst26vf_late_init, }; static const struct flash_info sst_parts[] = { -- GitLab From 00947a9649497273ec315ab080dd309e2b36ee8e Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 29 Oct 2021 20:26:16 +0300 Subject: [PATCH 0056/1112] mtd: spi-nor: winbond: Use manufacturer late_init() for OTP ops OTP is not described in the JESD216 SFDP standard, place the OTP ops init in late_init(). We can't get rid of the default_init() hook for winbond, as the 4byte_addr_mode is SFDP specific and will require to have all flashes at hand, in order to check which has the SFDP tables defined, in which case there's nothing to do if the SFDP tables are corect, and which of the flashes do not define the SFDP tables in which case each flash should declare a late_init() fixup. Signed-off-by: Tudor Ambarus Reviewed-by: Michael Walle Reviewed-by: Pratyush Yadav Link: https://lore.kernel.org/r/20211029172633.886453-9-tudor.ambarus@microchip.com --- drivers/mtd/spi-nor/winbond.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/mtd/spi-nor/winbond.c b/drivers/mtd/spi-nor/winbond.c index 96573f61caf54..dd4be0f78e67d 100644 --- a/drivers/mtd/spi-nor/winbond.c +++ b/drivers/mtd/spi-nor/winbond.c @@ -147,12 +147,17 @@ static const struct spi_nor_otp_ops winbond_otp_ops = { static void winbond_default_init(struct spi_nor *nor) { nor->params->set_4byte_addr_mode = winbond_set_4byte_addr_mode; +} + +static void winbond_late_init(struct spi_nor *nor) +{ if (nor->params->otp.org->n_regions) nor->params->otp.ops = &winbond_otp_ops; } static const struct spi_nor_fixups winbond_fixups = { .default_init = winbond_default_init, + .late_init = winbond_late_init, }; const struct spi_nor_manufacturer spi_nor_winbond = { -- GitLab From 3fdad69e7fb298020a895cf7e1fc2f9c110ca1c9 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 29 Oct 2021 20:26:17 +0300 Subject: [PATCH 0057/1112] mtd: spi-nor: xilinx: Use manufacturer late_init() to set setup method post_sfdp was misleading in this case, as SFDP is not supported by xilinx. Plus, there's no fixup here, just setting the correct setup method, as required by xilinx parts. Signed-off-by: Tudor Ambarus Reviewed-by: Michael Walle Reviewed-by: Pratyush Yadav Link: https://lore.kernel.org/r/20211029172633.886453-10-tudor.ambarus@microchip.com --- drivers/mtd/spi-nor/xilinx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/spi-nor/xilinx.c b/drivers/mtd/spi-nor/xilinx.c index 0658e47564bac..7e970ccf79030 100644 --- a/drivers/mtd/spi-nor/xilinx.c +++ b/drivers/mtd/spi-nor/xilinx.c @@ -80,13 +80,13 @@ static int xilinx_nor_setup(struct spi_nor *nor, return 0; } -static void xilinx_post_sfdp_fixups(struct spi_nor *nor) +static void xilinx_late_init(struct spi_nor *nor) { nor->params->setup = xilinx_nor_setup; } static const struct spi_nor_fixups xilinx_fixups = { - .post_sfdp = xilinx_post_sfdp_fixups, + .late_init = xilinx_late_init, }; const struct spi_nor_manufacturer spi_nor_xilinx = { -- GitLab From f22a48dbd01b66c01403b6182ad871476c19a813 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 29 Oct 2021 20:26:18 +0300 Subject: [PATCH 0058/1112] mtd: spi-nor: sst: Use manufacturer late_init() to set _write() Setting the correct nor->mtd._write in a fixup hook was misleading, since this is not a fixup, just a specific setting for SST, that differs from the SPI NOR core default init. Signed-off-by: Tudor Ambarus Reviewed-by: Michael Walle Reviewed-by: Pratyush Yadav Link: https://lore.kernel.org/r/20211029172633.886453-11-tudor.ambarus@microchip.com --- drivers/mtd/spi-nor/sst.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/spi-nor/sst.c b/drivers/mtd/spi-nor/sst.c index 660aabde477a7..3593aae0920f0 100644 --- a/drivers/mtd/spi-nor/sst.c +++ b/drivers/mtd/spi-nor/sst.c @@ -177,14 +177,14 @@ out: return ret; } -static void sst_post_sfdp_fixups(struct spi_nor *nor) +static void sst_late_init(struct spi_nor *nor) { if (nor->info->flags & SST_WRITE) nor->mtd._write = sst_write; } static const struct spi_nor_fixups sst_fixups = { - .post_sfdp = sst_post_sfdp_fixups, + .late_init = sst_late_init, }; const struct spi_nor_manufacturer spi_nor_sst = { -- GitLab From d396e735ba0c91911aac5d696b5da090e38e919b Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 29 Oct 2021 20:26:19 +0300 Subject: [PATCH 0059/1112] mtd: spi-nor: spansion: Use manufacturer late_init() spansion_post_sfdp_fixups() was called regardless if the flash defined SFDP tables or not. A better place for this kind of parameters init is in manufacturer's late_init() hook. post_sfdp() should be called only when SFDP is defined. No functional change in this patch. Instead of doing the 4b opcodes settings at manufacturer level, thus also for every flash that will be introduced, this should be done just where it is needed, per flash. I'll let this for other patch. Signed-off-by: Tudor Ambarus Reviewed-by: Michael Walle Reviewed-by: Pratyush Yadav Link: https://lore.kernel.org/r/20211029172633.886453-12-tudor.ambarus@microchip.com --- drivers/mtd/spi-nor/spansion.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index ee82dcd75310c..a3ea0135f7b11 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -276,7 +276,7 @@ static const struct flash_info spansion_parts[] = { }, }; -static void spansion_post_sfdp_fixups(struct spi_nor *nor) +static void spansion_late_init(struct spi_nor *nor) { if (nor->params->size <= SZ_16M) return; @@ -288,7 +288,7 @@ static void spansion_post_sfdp_fixups(struct spi_nor *nor) } static const struct spi_nor_fixups spansion_fixups = { - .post_sfdp = spansion_post_sfdp_fixups, + .late_init = spansion_late_init, }; const struct spi_nor_manufacturer spi_nor_spansion = { -- GitLab From 228e804599602555e15db467e41a11977757489f Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Fri, 29 Oct 2021 23:41:57 +0530 Subject: [PATCH 0060/1112] MAINTAINERS: Add myself as SPI NOR co-maintainer I have been reviewing patches and contributing for over a year. I would like to help maintain the subsystem as well. Signed-off-by: Pratyush Yadav Signed-off-by: Tudor Ambarus Acked-by: Miquel Raynal Acked-by: Richard Weinberger Link: https://lore.kernel.org/r/20211029181157.20623-1-p.yadav@ti.com --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 7a2345ce85213..352a781409eb0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17930,8 +17930,8 @@ F: drivers/pinctrl/spear/ SPI NOR SUBSYSTEM M: Tudor Ambarus +M: Pratyush Yadav R: Michael Walle -R: Pratyush Yadav L: linux-mtd@lists.infradead.org S: Maintained W: http://www.linux-mtd.infradead.org/ -- GitLab From 40fafc8eca3f0d41b9dade5c10afb2dad723aad7 Mon Sep 17 00:00:00 2001 From: oujiefeng Date: Wed, 17 Nov 2021 09:21:19 +0800 Subject: [PATCH 0061/1112] spi: hisi-kunpeng: Fix the debugfs directory name incorrect Change the debugfs directory name from hisi_spi65535 to hisi_spi0. Fixes: 2b2142f247eb ("spi: hisi-kunpeng: Add debugfs support") Signed-off-by: oujiefeng Signed-off-by: Jay Fang Link: https://lore.kernel.org/r/20211117012119.55558-1-f.fangjian@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-hisi-kunpeng.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-hisi-kunpeng.c b/drivers/spi/spi-hisi-kunpeng.c index 58b823a16fc4d..525cc0143a305 100644 --- a/drivers/spi/spi-hisi-kunpeng.c +++ b/drivers/spi/spi-hisi-kunpeng.c @@ -127,7 +127,6 @@ struct hisi_spi { void __iomem *regs; int irq; u32 fifo_len; /* depth of the FIFO buffer */ - u16 bus_num; /* Current message transfer state info */ const void *tx; @@ -165,7 +164,10 @@ static int hisi_spi_debugfs_init(struct hisi_spi *hs) { char name[32]; - snprintf(name, 32, "hisi_spi%d", hs->bus_num); + struct spi_controller *master; + + master = container_of(hs->dev, struct spi_controller, dev); + snprintf(name, 32, "hisi_spi%d", master->bus_num); hs->debugfs = debugfs_create_dir(name, NULL); if (!hs->debugfs) return -ENOMEM; @@ -467,7 +469,6 @@ static int hisi_spi_probe(struct platform_device *pdev) hs = spi_controller_get_devdata(master); hs->dev = dev; hs->irq = irq; - hs->bus_num = pdev->id; hs->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(hs->regs)) @@ -490,7 +491,7 @@ static int hisi_spi_probe(struct platform_device *pdev) master->use_gpio_descriptors = true; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); - master->bus_num = hs->bus_num; + master->bus_num = pdev->id; master->setup = hisi_spi_setup; master->cleanup = hisi_spi_cleanup; master->transfer_one = hisi_spi_transfer_one; @@ -506,15 +507,15 @@ static int hisi_spi_probe(struct platform_device *pdev) return ret; } - if (hisi_spi_debugfs_init(hs)) - dev_info(dev, "failed to create debugfs dir\n"); - ret = spi_register_controller(master); if (ret) { dev_err(dev, "failed to register spi master, ret=%d\n", ret); return ret; } + if (hisi_spi_debugfs_init(hs)) + dev_info(dev, "failed to create debugfs dir\n"); + dev_info(dev, "hw version:0x%x max-freq:%u kHz\n", readl(hs->regs + HISI_SPI_VERSION), master->max_speed_hz / 1000); -- GitLab From 2202e15b2b1a946ce760d96748cd7477589701ab Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 4 Nov 2021 13:27:06 +0100 Subject: [PATCH 0062/1112] kernel/locking: Use a pointer in ww_mutex_trylock(). mutex_acquire_nest() expects a pointer, pass the pointer. Fixes: 12235da8c80a1 ("kernel/locking: Add context to ww_mutex_trylock()") Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Peter Zijlstra (Intel) Link: https://lkml.kernel.org/r/20211104122706.frk52zxbjorso2kv@linutronix.de --- kernel/locking/ww_rt_mutex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/locking/ww_rt_mutex.c b/kernel/locking/ww_rt_mutex.c index 0e00205cf467a..d1473c624105c 100644 --- a/kernel/locking/ww_rt_mutex.c +++ b/kernel/locking/ww_rt_mutex.c @@ -26,7 +26,7 @@ int ww_mutex_trylock(struct ww_mutex *lock, struct ww_acquire_ctx *ww_ctx) if (__rt_mutex_trylock(&rtm->rtmutex)) { ww_mutex_set_context_fastpath(lock, ww_ctx); - mutex_acquire_nest(&rtm->dep_map, 0, 1, ww_ctx->dep_map, _RET_IP_); + mutex_acquire_nest(&rtm->dep_map, 0, 1, &ww_ctx->dep_map, _RET_IP_); return 1; } -- GitLab From 2d3791f116bb3d5b17571dadb8e085e12ae3a3cf Mon Sep 17 00:00:00 2001 From: Liu Xinpeng Date: Mon, 25 Oct 2021 11:46:25 +0800 Subject: [PATCH 0063/1112] psi: Remove repeated verbose comment Comment in function psi_task_switch,there are two same lines. ... * runtime state, the cgroup that contains both tasks * runtime state, the cgroup that contains both tasks ... Signed-off-by: Liu Xinpeng Signed-off-by: Peter Zijlstra (Intel) Acked-by: Johannes Weiner Link: https://lore.kernel.org/r/1635133586-84611-1-git-send-email-liuxp11@chinatelecom.cn --- kernel/sched/psi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/sched/psi.c b/kernel/sched/psi.c index 1652f2bb54b79..526af84ab852f 100644 --- a/kernel/sched/psi.c +++ b/kernel/sched/psi.c @@ -833,7 +833,6 @@ void psi_task_switch(struct task_struct *prev, struct task_struct *next, /* * When switching between tasks that have an identical * runtime state, the cgroup that contains both tasks - * runtime state, the cgroup that contains both tasks * we reach the first common ancestor. Iterate @next's * ancestors only until we encounter @prev's ONCPU. */ -- GitLab From 2fb75e1b642f49253d8848c9e47e8942f5366221 Mon Sep 17 00:00:00 2001 From: Liu Xinpeng Date: Mon, 25 Oct 2021 11:46:26 +0800 Subject: [PATCH 0064/1112] psi: Add a missing SPDX license header Add the missing SPDX license header to include/linux/psi.h include/linux/psi_types.h kernel/sched/psi.c Signed-off-by: Liu Xinpeng Signed-off-by: Peter Zijlstra (Intel) Acked-by: Johannes Weiner Link: https://lore.kernel.org/r/1635133586-84611-2-git-send-email-liuxp11@chinatelecom.cn --- include/linux/psi.h | 1 + include/linux/psi_types.h | 1 + kernel/sched/psi.c | 1 + 3 files changed, 3 insertions(+) diff --git a/include/linux/psi.h b/include/linux/psi.h index 65eb1476ac705..a70ca833c6d77 100644 --- a/include/linux/psi.h +++ b/include/linux/psi.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LINUX_PSI_H #define _LINUX_PSI_H diff --git a/include/linux/psi_types.h b/include/linux/psi_types.h index 0a23300d49af7..bf50068d5d4ba 100644 --- a/include/linux/psi_types.h +++ b/include/linux/psi_types.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LINUX_PSI_TYPES_H #define _LINUX_PSI_TYPES_H diff --git a/kernel/sched/psi.c b/kernel/sched/psi.c index 526af84ab852f..3397fa0011575 100644 --- a/kernel/sched/psi.c +++ b/kernel/sched/psi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Pressure stall information for CPU, memory and IO * -- GitLab From 4feee7d12603deca8775f9f9ae5e121093837444 Mon Sep 17 00:00:00 2001 From: Josh Don Date: Mon, 18 Oct 2021 13:34:28 -0700 Subject: [PATCH 0065/1112] sched/core: Forced idle accounting Adds accounting for "forced idle" time, which is time where a cookie'd task forces its SMT sibling to idle, despite the presence of runnable tasks. Forced idle time is one means to measure the cost of enabling core scheduling (ie. the capacity lost due to the need to force idle). Forced idle time is attributed to the thread responsible for causing the forced idle. A few details: - Forced idle time is displayed via /proc/PID/sched. It also requires that schedstats is enabled. - Forced idle is only accounted when a sibling hyperthread is held idle despite the presence of runnable tasks. No time is charged if a sibling is idle but has no runnable tasks. - Tasks with 0 cookie are never charged forced idle. - For SMT > 2, we scale the amount of forced idle charged based on the number of forced idle siblings. Additionally, we split the time up and evenly charge it to all running tasks, as each is equally responsible for the forced idle. Signed-off-by: Josh Don Signed-off-by: Peter Zijlstra (Intel) Link: https://lkml.kernel.org/r/20211018203428.2025792-1-joshdon@google.com --- include/linux/sched.h | 4 ++ kernel/sched/core.c | 82 +++++++++++++++++++++++++++++---------- kernel/sched/core_sched.c | 66 ++++++++++++++++++++++++++++++- kernel/sched/debug.c | 4 ++ kernel/sched/fair.c | 2 +- kernel/sched/sched.h | 32 ++++++++++++++- 6 files changed, 166 insertions(+), 24 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 78c351e35fec6..d2e261adb8ea2 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -523,7 +523,11 @@ struct sched_statistics { u64 nr_wakeups_affine_attempts; u64 nr_wakeups_passive; u64 nr_wakeups_idle; + +#ifdef CONFIG_SCHED_CORE + u64 core_forceidle_sum; #endif +#endif /* CONFIG_SCHEDSTATS */ } ____cacheline_aligned; struct sched_entity { diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 3c9b0fda64ac0..beaa8be6241e1 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -144,7 +144,7 @@ static inline bool __sched_core_less(struct task_struct *a, struct task_struct * return false; /* flip prio, so high prio is leftmost */ - if (prio_less(b, a, task_rq(a)->core->core_forceidle)) + if (prio_less(b, a, !!task_rq(a)->core->core_forceidle_count)) return true; return false; @@ -181,15 +181,23 @@ void sched_core_enqueue(struct rq *rq, struct task_struct *p) rb_add(&p->core_node, &rq->core_tree, rb_sched_core_less); } -void sched_core_dequeue(struct rq *rq, struct task_struct *p) +void sched_core_dequeue(struct rq *rq, struct task_struct *p, int flags) { rq->core->core_task_seq++; - if (!sched_core_enqueued(p)) - return; + if (sched_core_enqueued(p)) { + rb_erase(&p->core_node, &rq->core_tree); + RB_CLEAR_NODE(&p->core_node); + } - rb_erase(&p->core_node, &rq->core_tree); - RB_CLEAR_NODE(&p->core_node); + /* + * Migrating the last task off the cpu, with the cpu in forced idle + * state. Reschedule to create an accounting edge for forced idle, + * and re-examine whether the core is still in forced idle state. + */ + if (!(flags & DEQUEUE_SAVE) && rq->nr_running == 1 && + rq->core->core_forceidle_count && rq->curr == rq->idle) + resched_curr(rq); } /* @@ -280,6 +288,8 @@ static void __sched_core_flip(bool enabled) for_each_cpu(t, smt_mask) cpu_rq(t)->core_enabled = enabled; + cpu_rq(cpu)->core->core_forceidle_start = 0; + sched_core_unlock(cpu, &flags); cpumask_andnot(&sched_core_mask, &sched_core_mask, smt_mask); @@ -364,7 +374,8 @@ void sched_core_put(void) #else /* !CONFIG_SCHED_CORE */ static inline void sched_core_enqueue(struct rq *rq, struct task_struct *p) { } -static inline void sched_core_dequeue(struct rq *rq, struct task_struct *p) { } +static inline void +sched_core_dequeue(struct rq *rq, struct task_struct *p, int flags) { } #endif /* CONFIG_SCHED_CORE */ @@ -2005,7 +2016,7 @@ static inline void enqueue_task(struct rq *rq, struct task_struct *p, int flags) static inline void dequeue_task(struct rq *rq, struct task_struct *p, int flags) { if (sched_core_enabled(rq)) - sched_core_dequeue(rq, p); + sched_core_dequeue(rq, p, flags); if (!(flags & DEQUEUE_NOCLOCK)) update_rq_clock(rq); @@ -5244,6 +5255,7 @@ void scheduler_tick(void) if (sched_feat(LATENCY_WARN)) resched_latency = cpu_resched_latency(rq); calc_global_load_tick(rq); + sched_core_tick(rq); rq_unlock(rq, &rf); @@ -5656,6 +5668,7 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf) struct task_struct *next, *p, *max = NULL; const struct cpumask *smt_mask; bool fi_before = false; + bool core_clock_updated = (rq == rq->core); unsigned long cookie; int i, cpu, occ = 0; struct rq *rq_i; @@ -5708,10 +5721,18 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf) /* reset state */ rq->core->core_cookie = 0UL; - if (rq->core->core_forceidle) { + if (rq->core->core_forceidle_count) { + if (!core_clock_updated) { + update_rq_clock(rq->core); + core_clock_updated = true; + } + sched_core_account_forceidle(rq); + /* reset after accounting force idle */ + rq->core->core_forceidle_start = 0; + rq->core->core_forceidle_count = 0; + rq->core->core_forceidle_occupation = 0; need_sync = true; fi_before = true; - rq->core->core_forceidle = false; } /* @@ -5753,7 +5774,12 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf) for_each_cpu_wrap(i, smt_mask, cpu) { rq_i = cpu_rq(i); - if (i != cpu) + /* + * Current cpu always has its clock updated on entrance to + * pick_next_task(). If the current cpu is not the core, + * the core may also have been updated above. + */ + if (i != cpu && (rq_i != rq->core || !core_clock_updated)) update_rq_clock(rq_i); p = rq_i->core_pick = pick_task(rq_i); @@ -5783,7 +5809,7 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf) if (p == rq_i->idle) { if (rq_i->nr_running) { - rq->core->core_forceidle = true; + rq->core->core_forceidle_count++; if (!fi_before) rq->core->core_forceidle_seq++; } @@ -5792,6 +5818,12 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf) } } + if (schedstat_enabled() && rq->core->core_forceidle_count) { + if (cookie) + rq->core->core_forceidle_start = rq_clock(rq->core); + rq->core->core_forceidle_occupation = occ; + } + rq->core->core_pick_seq = rq->core->core_task_seq; next = rq->core_pick; rq->core_sched_seq = rq->core->core_pick_seq; @@ -5828,8 +5860,8 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf) * 1 0 1 * 1 1 0 */ - if (!(fi_before && rq->core->core_forceidle)) - task_vruntime_update(rq_i, rq_i->core_pick, rq->core->core_forceidle); + if (!(fi_before && rq->core->core_forceidle_count)) + task_vruntime_update(rq_i, rq_i->core_pick, !!rq->core->core_forceidle_count); rq_i->core_pick->core_occupation = occ; @@ -6033,11 +6065,19 @@ static void sched_core_cpu_deactivate(unsigned int cpu) goto unlock; /* copy the shared state to the new leader */ - core_rq->core_task_seq = rq->core_task_seq; - core_rq->core_pick_seq = rq->core_pick_seq; - core_rq->core_cookie = rq->core_cookie; - core_rq->core_forceidle = rq->core_forceidle; - core_rq->core_forceidle_seq = rq->core_forceidle_seq; + core_rq->core_task_seq = rq->core_task_seq; + core_rq->core_pick_seq = rq->core_pick_seq; + core_rq->core_cookie = rq->core_cookie; + core_rq->core_forceidle_count = rq->core_forceidle_count; + core_rq->core_forceidle_seq = rq->core_forceidle_seq; + core_rq->core_forceidle_occupation = rq->core_forceidle_occupation; + + /* + * Accounting edge for forced idle is handled in pick_next_task(). + * Don't need another one here, since the hotplug thread shouldn't + * have a cookie. + */ + core_rq->core_forceidle_start = 0; /* install new leader */ for_each_cpu(t, smt_mask) { @@ -9413,7 +9453,9 @@ void __init sched_init(void) rq->core_pick = NULL; rq->core_enabled = 0; rq->core_tree = RB_ROOT; - rq->core_forceidle = false; + rq->core_forceidle_count = 0; + rq->core_forceidle_occupation = 0; + rq->core_forceidle_start = 0; rq->core_cookie = 0UL; #endif diff --git a/kernel/sched/core_sched.c b/kernel/sched/core_sched.c index 517f72b008f50..1fb45672ec850 100644 --- a/kernel/sched/core_sched.c +++ b/kernel/sched/core_sched.c @@ -73,7 +73,7 @@ static unsigned long sched_core_update_cookie(struct task_struct *p, enqueued = sched_core_enqueued(p); if (enqueued) - sched_core_dequeue(rq, p); + sched_core_dequeue(rq, p, DEQUEUE_SAVE); old_cookie = p->core_cookie; p->core_cookie = cookie; @@ -85,6 +85,10 @@ static unsigned long sched_core_update_cookie(struct task_struct *p, * If task is currently running, it may not be compatible anymore after * the cookie change, so enter the scheduler on its CPU to schedule it * away. + * + * Note that it is possible that as a result of this cookie change, the + * core has now entered/left forced idle state. Defer accounting to the + * next scheduling edge, rather than always forcing a reschedule here. */ if (task_running(rq, p)) resched_curr(rq); @@ -232,3 +236,63 @@ out: return err; } +#ifdef CONFIG_SCHEDSTATS + +/* REQUIRES: rq->core's clock recently updated. */ +void __sched_core_account_forceidle(struct rq *rq) +{ + const struct cpumask *smt_mask = cpu_smt_mask(cpu_of(rq)); + u64 delta, now = rq_clock(rq->core); + struct rq *rq_i; + struct task_struct *p; + int i; + + lockdep_assert_rq_held(rq); + + WARN_ON_ONCE(!rq->core->core_forceidle_count); + + if (rq->core->core_forceidle_start == 0) + return; + + delta = now - rq->core->core_forceidle_start; + if (unlikely((s64)delta <= 0)) + return; + + rq->core->core_forceidle_start = now; + + if (WARN_ON_ONCE(!rq->core->core_forceidle_occupation)) { + /* can't be forced idle without a running task */ + } else if (rq->core->core_forceidle_count > 1 || + rq->core->core_forceidle_occupation > 1) { + /* + * For larger SMT configurations, we need to scale the charged + * forced idle amount since there can be more than one forced + * idle sibling and more than one running cookied task. + */ + delta *= rq->core->core_forceidle_count; + delta = div_u64(delta, rq->core->core_forceidle_occupation); + } + + for_each_cpu(i, smt_mask) { + rq_i = cpu_rq(i); + p = rq_i->core_pick ?: rq_i->curr; + + if (!p->core_cookie) + continue; + + __schedstat_add(p->stats.core_forceidle_sum, delta); + } +} + +void __sched_core_tick(struct rq *rq) +{ + if (!rq->core->core_forceidle_count) + return; + + if (rq != rq->core) + update_rq_clock(rq->core); + + __sched_core_account_forceidle(rq); +} + +#endif /* CONFIG_SCHEDSTATS */ diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c index 7dcbaa31c5d91..aa29211de1bf8 100644 --- a/kernel/sched/debug.c +++ b/kernel/sched/debug.c @@ -1023,6 +1023,10 @@ void proc_sched_show_task(struct task_struct *p, struct pid_namespace *ns, __PN(avg_atom); __PN(avg_per_cpu); + +#ifdef CONFIG_SCHED_CORE + PN_SCHEDSTAT(core_forceidle_sum); +#endif } __P(nr_switches); diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 6e476f6d94351..884f29d079637 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -11068,7 +11068,7 @@ static inline void task_tick_core(struct rq *rq, struct task_struct *curr) * MIN_NR_TASKS_DURING_FORCEIDLE - 1 tasks and use that to check * if we need to give up the CPU. */ - if (rq->core->core_forceidle && rq->cfs.nr_running == 1 && + if (rq->core->core_forceidle_count && rq->cfs.nr_running == 1 && __entity_slice_used(&curr->se, MIN_NR_TASKS_DURING_FORCEIDLE)) resched_curr(rq); } diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 0e66749486e75..eb971151e7e45 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1111,8 +1111,10 @@ struct rq { unsigned int core_task_seq; unsigned int core_pick_seq; unsigned long core_cookie; - unsigned char core_forceidle; + unsigned int core_forceidle_count; unsigned int core_forceidle_seq; + unsigned int core_forceidle_occupation; + u64 core_forceidle_start; #endif }; @@ -1253,7 +1255,7 @@ static inline bool sched_core_enqueued(struct task_struct *p) } extern void sched_core_enqueue(struct rq *rq, struct task_struct *p); -extern void sched_core_dequeue(struct rq *rq, struct task_struct *p); +extern void sched_core_dequeue(struct rq *rq, struct task_struct *p, int flags); extern void sched_core_get(void); extern void sched_core_put(void); @@ -1854,6 +1856,32 @@ static inline void flush_smp_call_function_from_idle(void) { } #include "stats.h" #include "autogroup.h" +#if defined(CONFIG_SCHED_CORE) && defined(CONFIG_SCHEDSTATS) + +extern void __sched_core_account_forceidle(struct rq *rq); + +static inline void sched_core_account_forceidle(struct rq *rq) +{ + if (schedstat_enabled()) + __sched_core_account_forceidle(rq); +} + +extern void __sched_core_tick(struct rq *rq); + +static inline void sched_core_tick(struct rq *rq) +{ + if (sched_core_enabled(rq) && schedstat_enabled()) + __sched_core_tick(rq); +} + +#else + +static inline void sched_core_account_forceidle(struct rq *rq) {} + +static inline void sched_core_tick(struct rq *rq) {} + +#endif /* CONFIG_SCHED_CORE && CONFIG_SCHEDSTATS */ + #ifdef CONFIG_CGROUP_SCHED /* -- GitLab From cb0e52b7748737b2cf6481fdd9b920ce7e1ebbdf Mon Sep 17 00:00:00 2001 From: Brian Chen Date: Wed, 10 Nov 2021 21:33:12 +0000 Subject: [PATCH 0066/1112] psi: Fix PSI_MEM_FULL state when tasks are in memstall and doing reclaim We've noticed cases where tasks in a cgroup are stalled on memory but there is little memory FULL pressure since tasks stay on the runqueue in reclaim. A simple example involves a single threaded program that keeps leaking and touching large amounts of memory. It runs in a cgroup with swap enabled, memory.high set at 10M and cpu.max ratio set at 5%. Though there is significant CPU pressure and memory SOME, there is barely any memory FULL since the task enters reclaim and stays on the runqueue. However, this memory-bound task is effectively stalled on memory and we expect memory FULL to match memory SOME in this scenario. The code is confused about memstall && running, thinking there is a stalled task and a productive task when there's only one task: a reclaimer that's counted as both. To fix this, we redefine the condition for PSI_MEM_FULL to check that all running tasks are in an active memstall instead of checking that there are no running tasks. case PSI_MEM_FULL: - return unlikely(tasks[NR_MEMSTALL] && !tasks[NR_RUNNING]); + return unlikely(tasks[NR_MEMSTALL] && + tasks[NR_RUNNING] == tasks[NR_MEMSTALL_RUNNING]); This will capture reclaimers. It will also capture tasks that called psi_memstall_enter() and are about to sleep, but this should be negligible noise. Signed-off-by: Brian Chen Signed-off-by: Peter Zijlstra (Intel) Acked-by: Johannes Weiner Link: https://lore.kernel.org/r/20211110213312.310243-1-brianchen118@gmail.com --- include/linux/psi_types.h | 13 ++++++++++- kernel/sched/psi.c | 45 ++++++++++++++++++++++++--------------- kernel/sched/stats.h | 5 ++++- 3 files changed, 44 insertions(+), 19 deletions(-) diff --git a/include/linux/psi_types.h b/include/linux/psi_types.h index bf50068d5d4ba..516c0fe836fd5 100644 --- a/include/linux/psi_types.h +++ b/include/linux/psi_types.h @@ -22,7 +22,17 @@ enum psi_task_count { * don't have to special case any state tracking for it. */ NR_ONCPU, - NR_PSI_TASK_COUNTS = 4, + /* + * For IO and CPU stalls the presence of running/oncpu tasks + * in the domain means a partial rather than a full stall. + * For memory it's not so simple because of page reclaimers: + * they are running/oncpu while representing a stall. To tell + * whether a domain has productivity left or not, we need to + * distinguish between regular running (i.e. productive) + * threads and memstall ones. + */ + NR_MEMSTALL_RUNNING, + NR_PSI_TASK_COUNTS = 5, }; /* Task state bitmasks */ @@ -30,6 +40,7 @@ enum psi_task_count { #define TSK_MEMSTALL (1 << NR_MEMSTALL) #define TSK_RUNNING (1 << NR_RUNNING) #define TSK_ONCPU (1 << NR_ONCPU) +#define TSK_MEMSTALL_RUNNING (1 << NR_MEMSTALL_RUNNING) /* Resources that workloads could be stalled on */ enum psi_res { diff --git a/kernel/sched/psi.c b/kernel/sched/psi.c index 3397fa0011575..a679613a7cb74 100644 --- a/kernel/sched/psi.c +++ b/kernel/sched/psi.c @@ -35,13 +35,19 @@ * delayed on that resource such that nobody is advancing and the CPU * goes idle. This leaves both workload and CPU unproductive. * - * Naturally, the FULL state doesn't exist for the CPU resource at the - * system level, but exist at the cgroup level, means all non-idle tasks - * in a cgroup are delayed on the CPU resource which used by others outside - * of the cgroup or throttled by the cgroup cpu.max configuration. - * * SOME = nr_delayed_tasks != 0 - * FULL = nr_delayed_tasks != 0 && nr_running_tasks == 0 + * FULL = nr_delayed_tasks != 0 && nr_productive_tasks == 0 + * + * What it means for a task to be productive is defined differently + * for each resource. For IO, productive means a running task. For + * memory, productive means a running task that isn't a reclaimer. For + * CPU, productive means an oncpu task. + * + * Naturally, the FULL state doesn't exist for the CPU resource at the + * system level, but exist at the cgroup level. At the cgroup level, + * FULL means all non-idle tasks in the cgroup are delayed on the CPU + * resource which is being used by others outside of the cgroup or + * throttled by the cgroup cpu.max configuration. * * The percentage of wallclock time spent in those compound stall * states gives pressure numbers between 0 and 100 for each resource, @@ -82,13 +88,13 @@ * * threads = min(nr_nonidle_tasks, nr_cpus) * SOME = min(nr_delayed_tasks / threads, 1) - * FULL = (threads - min(nr_running_tasks, threads)) / threads + * FULL = (threads - min(nr_productive_tasks, threads)) / threads * * For the 257 number crunchers on 256 CPUs, this yields: * * threads = min(257, 256) * SOME = min(1 / 256, 1) = 0.4% - * FULL = (256 - min(257, 256)) / 256 = 0% + * FULL = (256 - min(256, 256)) / 256 = 0% * * For the 1 out of 4 memory-delayed tasks, this yields: * @@ -113,7 +119,7 @@ * For each runqueue, we track: * * tSOME[cpu] = time(nr_delayed_tasks[cpu] != 0) - * tFULL[cpu] = time(nr_delayed_tasks[cpu] && !nr_running_tasks[cpu]) + * tFULL[cpu] = time(nr_delayed_tasks[cpu] && !nr_productive_tasks[cpu]) * tNONIDLE[cpu] = time(nr_nonidle_tasks[cpu] != 0) * * and then periodically aggregate: @@ -234,7 +240,8 @@ static bool test_state(unsigned int *tasks, enum psi_states state) case PSI_MEM_SOME: return unlikely(tasks[NR_MEMSTALL]); case PSI_MEM_FULL: - return unlikely(tasks[NR_MEMSTALL] && !tasks[NR_RUNNING]); + return unlikely(tasks[NR_MEMSTALL] && + tasks[NR_RUNNING] == tasks[NR_MEMSTALL_RUNNING]); case PSI_CPU_SOME: return unlikely(tasks[NR_RUNNING] > tasks[NR_ONCPU]); case PSI_CPU_FULL: @@ -711,10 +718,11 @@ static void psi_group_change(struct psi_group *group, int cpu, if (groupc->tasks[t]) { groupc->tasks[t]--; } else if (!psi_bug) { - printk_deferred(KERN_ERR "psi: task underflow! cpu=%d t=%d tasks=[%u %u %u %u] clear=%x set=%x\n", + printk_deferred(KERN_ERR "psi: task underflow! cpu=%d t=%d tasks=[%u %u %u %u %u] clear=%x set=%x\n", cpu, t, groupc->tasks[0], groupc->tasks[1], groupc->tasks[2], - groupc->tasks[3], clear, set); + groupc->tasks[3], groupc->tasks[4], + clear, set); psi_bug = 1; } } @@ -854,12 +862,15 @@ void psi_task_switch(struct task_struct *prev, struct task_struct *next, int clear = TSK_ONCPU, set = 0; /* - * When we're going to sleep, psi_dequeue() lets us handle - * TSK_RUNNING and TSK_IOWAIT here, where we can combine it - * with TSK_ONCPU and save walking common ancestors twice. + * When we're going to sleep, psi_dequeue() lets us + * handle TSK_RUNNING, TSK_MEMSTALL_RUNNING and + * TSK_IOWAIT here, where we can combine it with + * TSK_ONCPU and save walking common ancestors twice. */ if (sleep) { clear |= TSK_RUNNING; + if (prev->in_memstall) + clear |= TSK_MEMSTALL_RUNNING; if (prev->in_iowait) set |= TSK_IOWAIT; } @@ -908,7 +919,7 @@ void psi_memstall_enter(unsigned long *flags) rq = this_rq_lock_irq(&rf); current->in_memstall = 1; - psi_task_change(current, 0, TSK_MEMSTALL); + psi_task_change(current, 0, TSK_MEMSTALL | TSK_MEMSTALL_RUNNING); rq_unlock_irq(rq, &rf); } @@ -937,7 +948,7 @@ void psi_memstall_leave(unsigned long *flags) rq = this_rq_lock_irq(&rf); current->in_memstall = 0; - psi_task_change(current, TSK_MEMSTALL, 0); + psi_task_change(current, TSK_MEMSTALL | TSK_MEMSTALL_RUNNING, 0); rq_unlock_irq(rq, &rf); } diff --git a/kernel/sched/stats.h b/kernel/sched/stats.h index cfb0893a83d45..3a3c826dd83a7 100644 --- a/kernel/sched/stats.h +++ b/kernel/sched/stats.h @@ -118,6 +118,9 @@ static inline void psi_enqueue(struct task_struct *p, bool wakeup) if (static_branch_likely(&psi_disabled)) return; + if (p->in_memstall) + set |= TSK_MEMSTALL_RUNNING; + if (!wakeup || p->sched_psi_wake_requeue) { if (p->in_memstall) set |= TSK_MEMSTALL; @@ -148,7 +151,7 @@ static inline void psi_dequeue(struct task_struct *p, bool sleep) return; if (p->in_memstall) - clear |= TSK_MEMSTALL; + clear |= (TSK_MEMSTALL | TSK_MEMSTALL_RUNNING); psi_task_change(p, clear, 0); } -- GitLab From 1b9beda83e27a0c2cd75d1cb743c297c7b36c844 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 17 Nov 2021 09:20:43 -0500 Subject: [PATCH 0067/1112] fs: dlm: fix build with CONFIG_IPV6 disabled This patch will surround the AF_INET6 case in sk_error_report() of dlm with a #if IS_ENABLED(CONFIG_IPV6). The field sk->sk_v6_daddr is not defined when CONFIG_IPV6 is disabled. If CONFIG_IPV6 is disabled, the socket creation with AF_INET6 should already fail because a runtime check if AF_INET6 is registered. However if there is the possibility that AF_INET6 is set as sk_family the sk_error_report() callback will print then an invalid family type error. Reported-by: kernel test robot Fixes: 4c3d90570bcc ("fs: dlm: don't call kernel_getpeername() in error_report()") Signed-off-by: Alexander Aring Signed-off-by: David Teigland --- fs/dlm/lowcomms.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 2034701890111..f7fc1ac76ce83 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -608,6 +608,7 @@ static void lowcomms_error_report(struct sock *sk) ntohs(inet->inet_dport), sk->sk_err, sk->sk_err_soft); break; +#if IS_ENABLED(CONFIG_IPV6) case AF_INET6: printk_ratelimited(KERN_ERR "dlm: node %d: socket error " "sending to node %d at %pI6c, " @@ -616,6 +617,7 @@ static void lowcomms_error_report(struct sock *sk) ntohs(inet->inet_dport), sk->sk_err, sk->sk_err_soft); break; +#endif default: printk_ratelimited(KERN_ERR "dlm: node %d: socket error " "invalid socket family %d set, " -- GitLab From a4585ba2050f460f749bbaf2b67bd56c41e30283 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 17 Nov 2021 00:02:33 +0100 Subject: [PATCH 0068/1112] power: supply: core: Use library interpolation The power supply core appears to contain two open coded linear interpolations. Use the kernel fixpoint arithmetic interpolation library function instead. Cc: Chunyan Zhang Signed-off-by: Linus Walleij Reviewed-by: Baolin Wang Signed-off-by: Sebastian Reichel --- drivers/power/supply/power_supply_core.c | 61 ++++++++++++------------ 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index fc12a4f407f43..2907b84ceea9e 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "power_supply.h" /* exported for the APM Power driver, APM emulation */ @@ -783,26 +784,25 @@ EXPORT_SYMBOL_GPL(power_supply_put_battery_info); int power_supply_temp2resist_simple(struct power_supply_resistance_temp_table *table, int table_len, int temp) { - int i, resist; + int i, high, low; - for (i = 0; i < table_len; i++) + /* Break loop at table_len - 1 because that is the highest index */ + for (i = 0; i < table_len - 1; i++) if (temp > table[i].temp) break; - if (i > 0 && i < table_len) { - int tmp; - - tmp = (table[i - 1].resistance - table[i].resistance) * - (temp - table[i].temp); - tmp /= table[i - 1].temp - table[i].temp; - resist = tmp + table[i].resistance; - } else if (i == 0) { - resist = table[0].resistance; - } else { - resist = table[table_len - 1].resistance; - } - - return resist; + /* The library function will deal with high == low */ + if ((i == 0) || (i == (table_len - 1))) + high = i; + else + high = i - 1; + low = i; + + return fixp_linear_interpolate(table[low].temp, + table[low].resistance, + table[high].temp, + table[high].resistance, + temp); } EXPORT_SYMBOL_GPL(power_supply_temp2resist_simple); @@ -821,24 +821,25 @@ EXPORT_SYMBOL_GPL(power_supply_temp2resist_simple); int power_supply_ocv2cap_simple(struct power_supply_battery_ocv_table *table, int table_len, int ocv) { - int i, cap, tmp; + int i, high, low; - for (i = 0; i < table_len; i++) + /* Break loop at table_len - 1 because that is the highest index */ + for (i = 0; i < table_len - 1; i++) if (ocv > table[i].ocv) break; - if (i > 0 && i < table_len) { - tmp = (table[i - 1].capacity - table[i].capacity) * - (ocv - table[i].ocv); - tmp /= table[i - 1].ocv - table[i].ocv; - cap = tmp + table[i].capacity; - } else if (i == 0) { - cap = table[0].capacity; - } else { - cap = table[table_len - 1].capacity; - } - - return cap; + /* The library function will deal with high == low */ + if ((i == 0) || (i == (table_len - 1))) + high = i - 1; + else + high = i; /* i.e. i == 0 */ + low = i; + + return fixp_linear_interpolate(table[low].ocv, + table[low].capacity, + table[high].ocv, + table[high].capacity, + ocv); } EXPORT_SYMBOL_GPL(power_supply_ocv2cap_simple); -- GitLab From e0dbd7b0ed021fb9250f7ba4d759325678efefb5 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 16 Nov 2021 23:44:28 +0100 Subject: [PATCH 0069/1112] power: supply: core: Add kerneldoc to battery struct This complements the struct power_supply_battery_info with extensive kerneldoc explaining the different semantics of the fields, including an overview of the CC/CV charging concepts implicit in some of the struct members. This is done to first establish semantics before I can add more charging methods by breaking out the CC/CV parameters to its own struct. Tested-by: Randy Dunlap Acked-by: Randy Dunlap Reviewed-by: Matti Vaittinen Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- include/linux/power_supply.h | 215 +++++++++++++++++++++++++++++++---- 1 file changed, 192 insertions(+), 23 deletions(-) diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 2d1318fe2455e..f6e94eae4f28f 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -343,37 +343,206 @@ struct power_supply_resistance_temp_table { #define POWER_SUPPLY_OCV_TEMP_MAX 20 -/* +/** + * struct power_supply_battery_info - information about batteries + * @technology: from the POWER_SUPPLY_TECHNOLOGY_* enum + * @energy_full_design_uwh: energy content when fully charged in microwatt + * hours + * @charge_full_design_uah: charge content when fully charged in microampere + * hours + * @voltage_min_design_uv: minimum voltage across the poles when the battery + * is at minimum voltage level in microvolts. If the voltage drops below this + * level the battery will need precharging when using CC/CV charging. + * @voltage_max_design_uv: voltage across the poles when the battery is fully + * charged in microvolts. This is the "nominal voltage" i.e. the voltage + * printed on the label of the battery. + * @tricklecharge_current_ua: the tricklecharge current used when trickle + * charging the battery in microamperes. This is the charging phase when the + * battery is completely empty and we need to carefully trickle in some + * charge until we reach the precharging voltage. + * @precharge_current_ua: current to use in the precharge phase in microamperes, + * the precharge rate is limited by limiting the current to this value. + * @precharge_voltage_max_uv: the maximum voltage allowed when precharging in + * microvolts. When we pass this voltage we will nominally switch over to the + * CC (constant current) charging phase defined by constant_charge_current_ua + * and constant_charge_voltage_max_uv. + * @charge_term_current_ua: when the current in the CV (constant voltage) + * charging phase drops below this value in microamperes the charging will + * terminate completely and not restart until the voltage over the battery + * poles reach charge_restart_voltage_uv unless we use maintenance charging. + * @charge_restart_voltage_uv: when the battery has been fully charged by + * CC/CV charging and charging has been disabled, and the voltage subsequently + * drops below this value in microvolts, the charging will be restarted + * (typically using CV charging). + * @overvoltage_limit_uv: If the voltage exceeds the nominal voltage + * voltage_max_design_uv and we reach this voltage level, all charging must + * stop and emergency procedures take place, such as shutting down the system + * in some cases. + * @constant_charge_current_max_ua: current in microamperes to use in the CC + * (constant current) charging phase. The charging rate is limited + * by this current. This is the main charging phase and as the current is + * constant into the battery the voltage slowly ascends to + * constant_charge_voltage_max_uv. + * @constant_charge_voltage_max_uv: voltage in microvolts signifying the end of + * the CC (constant current) charging phase and the beginning of the CV + * (constant voltage) charging phase. + * @factory_internal_resistance_uohm: the internal resistance of the battery + * at fabrication time, expressed in microohms. This resistance will vary + * depending on the lifetime and charge of the battery, so this is just a + * nominal ballpark figure. + * @ocv_temp: array indicating the open circuit voltage (OCV) capacity + * temperature indices. This is an array of temperatures in degrees Celsius + * indicating which capacity table to use for a certain temperature, since + * the capacity for reasons of chemistry will be different at different + * temperatures. Determining capacity is a multivariate problem and the + * temperature is the first variable we determine. + * @temp_ambient_alert_min: the battery will go outside of operating conditions + * when the ambient temperature goes below this temperature in degrees + * Celsius. + * @temp_ambient_alert_max: the battery will go outside of operating conditions + * when the ambient temperature goes above this temperature in degrees + * Celsius. + * @temp_alert_min: the battery should issue an alert if the internal + * temperature goes below this temperature in degrees Celsius. + * @temp_alert_max: the battery should issue an alert if the internal + * temperature goes above this temperature in degrees Celsius. + * @temp_min: the battery will go outside of operating conditions when + * the internal temperature goes below this temperature in degrees Celsius. + * Normally this means the system should shut down. + * @temp_max: the battery will go outside of operating conditions when + * the internal temperature goes above this temperature in degrees Celsius. + * Normally this means the system should shut down. + * @ocv_table: for each entry in ocv_temp there is a corresponding entry in + * ocv_table and a size for each entry in ocv_table_size. These arrays + * determine the capacity in percent in relation to the voltage in microvolts + * at the indexed temperature. + * @ocv_table_size: for each entry in ocv_temp this array is giving the size of + * each entry in the array of capacity arrays in ocv_table. + * @resist_table: this is a table that correlates a battery temperature to the + * expected internal resistance at this temperature. The resistance is given + * as a percentage of factory_internal_resistance_uohm. Knowing the + * resistance of the battery is usually necessary for calculating the open + * circuit voltage (OCV) that is then used with the ocv_table to calculate + * the capacity of the battery. The resist_table must be ordered descending + * by temperature: highest temperature with lowest resistance first, lowest + * temperature with highest resistance last. + * @resist_table_size: the number of items in the resist_table. + * * This is the recommended struct to manage static battery parameters, * populated by power_supply_get_battery_info(). Most platform drivers should * use these for consistency. + * * Its field names must correspond to elements in enum power_supply_property. * The default field value is -EINVAL. - * Power supply class itself doesn't use this. + * + * The charging parameters here assume a CC/CV charging scheme. This method + * is most common with Lithium Ion batteries (other methods are possible) and + * looks as follows: + * + * ^ Battery voltage + * | --- overvoltage_limit_uv + * | + * | ................................................... + * | .. constant_charge_voltage_max_uv + * | .. + * | . + * | . + * | . + * | . + * | . + * | .. precharge_voltage_max_uv + * | .. + * |. (trickle charging) + * +------------------------------------------------------------------> time + * + * ^ Current into the battery + * | + * | ............. constant_charge_current_max_ua + * | . . + * | . . + * | . . + * | . . + * | . .. + * | . .... + * | . ..... + * | ... precharge_current_ua ....... charge_term_current_ua + * | . . + * | . . + * |.... tricklecharge_current_ua . + * | . + * +-----------------------------------------------------------------> time + * + * These diagrams are synchronized on time and the voltage and current + * follow each other. + * + * With CC/CV charging commence over time like this for an empty battery: + * + * 1. When the battery is completely empty it may need to be charged with + * an especially small current so that electrons just "trickle in", + * this is the tricklecharge_current_ua. + * + * 2. Next a small initial pre-charge current (precharge_current_ua) + * is applied if the voltage is below precharge_voltage_max_uv until we + * reach precharge_voltage_max_uv. CAUTION: in some texts this is referred + * to as "trickle charging" but the use in the Linux kernel is different + * see below! + * + * 3. Then the main charging current is applied, which is called the constant + * current (CC) phase. A current regulator is set up to allow + * constant_charge_current_max_ua of current to flow into the battery. + * The chemical reaction in the battery will make the voltage go up as + * charge goes into the battery. This current is applied until we reach + * the constant_charge_voltage_max_uv voltage. + * + * 4. At this voltage we switch over to the constant voltage (CV) phase. This + * means we allow current to go into the battery, but we keep the voltage + * fixed. This current will continue to charge the battery while keeping + * the voltage the same. A chemical reaction in the battery goes on + * storing energy without affecting the voltage. Over time the current + * will slowly drop and when we reach charge_term_current_ua we will + * end the constant voltage phase. + * + * After this the battery is fully charged, and if we do not support maintenance + * charging, the charging will not restart until power dissipation makes the + * voltage fall so that we reach charge_restart_voltage_uv and at this point + * we restart charging at the appropriate phase, usually this will be inside + * the CV phase. + * + * If we support maintenance charging the voltage is however kept high after + * the CV phase with a very low current. This is meant to let the same charge + * go in for usage while the charger is still connected, mainly for + * dissipation for the power consuming entity while connected to the + * charger. + * + * All charging MUST terminate if the overvoltage_limit_uv is ever reached. + * Overcharging Lithium Ion cells can be DANGEROUS and lead to fire or + * explosions. + * + * The power supply class itself doesn't use this struct as of now. */ struct power_supply_battery_info { - unsigned int technology; /* from the enum above */ - int energy_full_design_uwh; /* microWatt-hours */ - int charge_full_design_uah; /* microAmp-hours */ - int voltage_min_design_uv; /* microVolts */ - int voltage_max_design_uv; /* microVolts */ - int tricklecharge_current_ua; /* microAmps */ - int precharge_current_ua; /* microAmps */ - int precharge_voltage_max_uv; /* microVolts */ - int charge_term_current_ua; /* microAmps */ - int charge_restart_voltage_uv; /* microVolts */ - int overvoltage_limit_uv; /* microVolts */ - int constant_charge_current_max_ua; /* microAmps */ - int constant_charge_voltage_max_uv; /* microVolts */ - int factory_internal_resistance_uohm; /* microOhms */ - int ocv_temp[POWER_SUPPLY_OCV_TEMP_MAX];/* celsius */ - int temp_ambient_alert_min; /* celsius */ - int temp_ambient_alert_max; /* celsius */ - int temp_alert_min; /* celsius */ - int temp_alert_max; /* celsius */ - int temp_min; /* celsius */ - int temp_max; /* celsius */ + unsigned int technology; + int energy_full_design_uwh; + int charge_full_design_uah; + int voltage_min_design_uv; + int voltage_max_design_uv; + int tricklecharge_current_ua; + int precharge_current_ua; + int precharge_voltage_max_uv; + int charge_term_current_ua; + int charge_restart_voltage_uv; + int overvoltage_limit_uv; + int constant_charge_current_max_ua; + int constant_charge_voltage_max_uv; + int factory_internal_resistance_uohm; + int ocv_temp[POWER_SUPPLY_OCV_TEMP_MAX]; + int temp_ambient_alert_min; + int temp_ambient_alert_max; + int temp_alert_min; + int temp_alert_max; + int temp_min; + int temp_max; struct power_supply_battery_ocv_table *ocv_table[POWER_SUPPLY_OCV_TEMP_MAX]; int ocv_table_size[POWER_SUPPLY_OCV_TEMP_MAX]; struct power_supply_resistance_temp_table *resist_table; -- GitLab From adca4b68713f3c2f9fc1b2b529296a5da6f1eb4b Mon Sep 17 00:00:00 2001 From: Mark Pearson Date: Wed, 17 Nov 2021 13:44:52 -0500 Subject: [PATCH 0070/1112] Documentation: syfs-class-firmware-attributes: Lenovo Opcode support Newer Lenovo BIOS's have an opcode GUID support interface which provides - improved password setting control - ability to set System, hard drive and NVMe passwords Add the support for these new passwords, and the ability to select user/master mode and the drive index. Signed-off-by: Mark Pearson Link: https://lore.kernel.org/r/20211117184453.2476-1-markpearson@lenovo.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- .../testing/sysfs-class-firmware-attributes | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-firmware-attributes b/Documentation/ABI/testing/sysfs-class-firmware-attributes index 90fdf935aa5ea..13e31c6a0e9c3 100644 --- a/Documentation/ABI/testing/sysfs-class-firmware-attributes +++ b/Documentation/ABI/testing/sysfs-class-firmware-attributes @@ -161,6 +161,15 @@ Description: power-on: Representing a password required to use the system + system-mgmt: + Representing System Management password. + See Lenovo extensions section for details + HDD: + Representing HDD password + See Lenovo extensions section for details + NVMe: + Representing NVMe password + See Lenovo extensions section for details mechanism: The means of authentication. This attribute is mandatory. @@ -207,6 +216,13 @@ Description: On Lenovo systems the following additional settings are available: + role: system-mgmt This gives the same authority as the bios-admin password to control + security related features. The authorities allocated can be set via + the BIOS menu SMP Access Control Policy + + role: HDD & NVMe This password is used to unlock access to the drive at boot. Note see + 'level' and 'index' extensions below. + lenovo_encoding: The encoding method that is used. This can be either "ascii" or "scancode". Default is set to "ascii" @@ -216,6 +232,22 @@ Description: two char code (e.g. "us", "fr", "gr") and may vary per platform. Default is set to "us" + level: + Available for HDD and NVMe authentication to set 'user' or 'master' + privilege level. + If only the user password is configured then this should be used to + unlock the drive at boot. If both master and user passwords are set + then either can be used. If a master password is set a user password + is required. + This attribute defaults to 'user' level + + index: + Used with HDD and NVME authentication to set the drive index + that is being referenced (e.g hdd0, hdd1 etc) + This attribute defaults to device 0. + + + What: /sys/class/firmware-attributes/*/attributes/pending_reboot Date: February 2021 KernelVersion: 5.11 -- GitLab From 640a5fa50a42b99bfa2a0ec51b4ea9591d9bd055 Mon Sep 17 00:00:00 2001 From: Mark Pearson Date: Wed, 17 Nov 2021 13:44:53 -0500 Subject: [PATCH 0071/1112] platform/x86: think-lmi: Opcode support Implement Opcode support. This is available on ThinkCenter and ThinkStations platforms and gives improved password setting capabilities Add options to configure System, HDD & NVMe passwords. HDD & NVMe passwords need a user level (user/master) along with drive index. Signed-off-by: Mark Pearson Link: https://lore.kernel.org/r/20211117184453.2476-2-markpearson@lenovo.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/think-lmi.c | 320 +++++++++++++++++++++++++++---- drivers/platform/x86/think-lmi.h | 28 ++- 2 files changed, 311 insertions(+), 37 deletions(-) diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c index c4d9c45350f7c..fee9e004161fd 100644 --- a/drivers/platform/x86/think-lmi.c +++ b/drivers/platform/x86/think-lmi.c @@ -128,8 +128,23 @@ MODULE_PARM_DESC(debug_support, "Enable debug command support"); */ #define LENOVO_DEBUG_CMD_GUID "7FF47003-3B6C-4E5E-A227-E979824A85D1" +/* + * Name: + * Lenovo_OpcodeIF + * Description: + * Opcode interface which provides the ability to set multiple + * parameters and then trigger an action with a final command. + * This is particularly useful for simplifying setting passwords. + * With this support comes the ability to set System, HDD and NVMe + * passwords. + * This is currently available on ThinkCenter and ThinkStations platforms + */ +#define LENOVO_OPCODE_IF_GUID "DFDDEF2C-57D4-48ce-B196-0FB787D90836" + #define TLMI_POP_PWD (1 << 0) #define TLMI_PAP_PWD (1 << 1) +#define TLMI_HDD_PWD (1 << 2) +#define TLMI_SYS_PWD (1 << 3) #define to_tlmi_pwd_setting(kobj) container_of(kobj, struct tlmi_pwd_setting, kobj) #define to_tlmi_attr_setting(kobj) container_of(kobj, struct tlmi_attr_setting, kobj) @@ -145,6 +160,10 @@ static const char * const encoding_options[] = { [TLMI_ENCODING_ASCII] = "ascii", [TLMI_ENCODING_SCANCODE] = "scancode", }; +static const char * const level_options[] = { + [TLMI_LEVEL_USER] = "user", + [TLMI_LEVEL_MASTER] = "master", +}; static struct think_lmi tlmi_priv; static struct class *fw_attr_class; @@ -233,6 +252,7 @@ static int tlmi_get_pwd_settings(struct tlmi_pwdcfg *pwdcfg) struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; const union acpi_object *obj; acpi_status status; + int copy_size; if (!tlmi_priv.can_get_password_settings) return -EOPNOTSUPP; @@ -253,14 +273,21 @@ static int tlmi_get_pwd_settings(struct tlmi_pwdcfg *pwdcfg) * The size of thinkpad_wmi_pcfg on ThinkStation is larger than ThinkPad. * To make the driver compatible on different brands, we permit it to get * the data in below case. + * Settings must have at minimum the core fields available */ - if (obj->buffer.length < sizeof(struct tlmi_pwdcfg)) { + if (obj->buffer.length < sizeof(struct tlmi_pwdcfg_core)) { pr_warn("Unknown pwdcfg buffer length %d\n", obj->buffer.length); kfree(obj); return -EIO; } - memcpy(pwdcfg, obj->buffer.pointer, sizeof(struct tlmi_pwdcfg)); + + copy_size = obj->buffer.length < sizeof(struct tlmi_pwdcfg) ? + obj->buffer.length : sizeof(struct tlmi_pwdcfg); + memcpy(pwdcfg, obj->buffer.pointer, copy_size); kfree(obj); + + if (WARN_ON(pwdcfg->core.max_length >= TLMI_PWD_BUFSIZE)) + pwdcfg->core.max_length = TLMI_PWD_BUFSIZE - 1; return 0; } @@ -270,6 +297,20 @@ static int tlmi_save_bios_settings(const char *password) password); } +static int tlmi_opcode_setting(char *setting, const char *value) +{ + char *opcode_str; + int ret; + + opcode_str = kasprintf(GFP_KERNEL, "%s:%s;", setting, value); + if (!opcode_str) + return -ENOMEM; + + ret = tlmi_simple_call(LENOVO_OPCODE_IF_GUID, opcode_str); + kfree(opcode_str); + return ret; +} + static int tlmi_setting(int item, char **value, const char *guid_string) { struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -370,16 +411,54 @@ static ssize_t new_password_store(struct kobject *kobj, goto out; } - /* Format: 'PasswordType,CurrentPw,NewPw,Encoding,KbdLang;' */ - auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s,%s,%s;", - setting->pwd_type, setting->password, new_pwd, - encoding_options[setting->encoding], setting->kbdlang); - if (!auth_str) { - ret = -ENOMEM; - goto out; + /* If opcode support is present use that interface */ + if (tlmi_priv.opcode_support) { + char pwd_type[8]; + + /* Special handling required for HDD and NVMe passwords */ + if (setting == tlmi_priv.pwd_hdd) { + if (setting->level == TLMI_LEVEL_USER) + sprintf(pwd_type, "uhdp%d", setting->index); + else + sprintf(pwd_type, "mhdp%d", setting->index); + } else if (setting == tlmi_priv.pwd_nvme) { + if (setting->level == TLMI_LEVEL_USER) + sprintf(pwd_type, "unvp%d", setting->index); + else + sprintf(pwd_type, "mnvp%d", setting->index); + } else { + sprintf(pwd_type, "%s", setting->pwd_type); + } + + ret = tlmi_opcode_setting("WmiOpcodePasswordType", pwd_type); + if (ret) + goto out; + + if (tlmi_priv.pwd_admin->valid) { + ret = tlmi_opcode_setting("WmiOpcodePasswordAdmin", + tlmi_priv.pwd_admin->password); + if (ret) + goto out; + } + ret = tlmi_opcode_setting("WmiOpcodePasswordCurrent01", setting->password); + if (ret) + goto out; + ret = tlmi_opcode_setting("WmiOpcodePasswordNew01", new_pwd); + if (ret) + goto out; + ret = tlmi_simple_call(LENOVO_OPCODE_IF_GUID, "WmiOpcodePasswordSetUpdate;"); + } else { + /* Format: 'PasswordType,CurrentPw,NewPw,Encoding,KbdLang;' */ + auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s,%s,%s;", + setting->pwd_type, setting->password, new_pwd, + encoding_options[setting->encoding], setting->kbdlang); + if (!auth_str) { + ret = -ENOMEM; + goto out; + } + ret = tlmi_simple_call(LENOVO_SET_BIOS_PASSWORD_GUID, auth_str); + kfree(auth_str); } - ret = tlmi_simple_call(LENOVO_SET_BIOS_PASSWORD_GUID, auth_str); - kfree(auth_str); out: kfree(new_pwd); return ret ?: count; @@ -475,6 +554,75 @@ static ssize_t role_show(struct kobject *kobj, struct kobj_attribute *attr, } static struct kobj_attribute auth_role = __ATTR_RO(role); +static ssize_t index_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj); + + return sysfs_emit(buf, "%d\n", setting->index); +} + +static ssize_t index_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj); + int err, val; + + err = kstrtoint(buf, 10, &val); + if (err < 0) + return err; + + if (val > TLMI_INDEX_MAX) + return -EINVAL; + + setting->index = val; + return count; +} + +static struct kobj_attribute auth_index = __ATTR_RW(index); + +static ssize_t level_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj); + + return sysfs_emit(buf, "%s\n", level_options[setting->level]); +} + +static ssize_t level_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj); + int i; + + /* Scan for a matching profile */ + i = sysfs_match_string(level_options, buf); + if (i < 0) + return -EINVAL; + + setting->level = i; + return count; +} + +static struct kobj_attribute auth_level = __ATTR_RW(level); + +static umode_t auth_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj); + + /*We only want to display level and index settings on HDD/NVMe */ + if ((attr == (struct attribute *)&auth_index) || + (attr == (struct attribute *)&auth_level)) { + if ((setting == tlmi_priv.pwd_hdd) || (setting == tlmi_priv.pwd_nvme)) + return attr->mode; + return 0; + } + return attr->mode; +} + static struct attribute *auth_attrs[] = { &auth_is_pass_set.attr, &auth_min_pass_length.attr, @@ -485,10 +633,13 @@ static struct attribute *auth_attrs[] = { &auth_mechanism.attr, &auth_encoding.attr, &auth_kbdlang.attr, + &auth_index.attr, + &auth_level.attr, NULL }; static const struct attribute_group auth_attr_group = { + .is_visible = auth_attr_is_visible, .attrs = auth_attrs, }; @@ -752,6 +903,16 @@ static void tlmi_release_attr(void) kobject_put(&tlmi_priv.pwd_admin->kobj); sysfs_remove_group(&tlmi_priv.pwd_power->kobj, &auth_attr_group); kobject_put(&tlmi_priv.pwd_power->kobj); + + if (tlmi_priv.opcode_support) { + sysfs_remove_group(&tlmi_priv.pwd_system->kobj, &auth_attr_group); + kobject_put(&tlmi_priv.pwd_system->kobj); + sysfs_remove_group(&tlmi_priv.pwd_hdd->kobj, &auth_attr_group); + kobject_put(&tlmi_priv.pwd_hdd->kobj); + sysfs_remove_group(&tlmi_priv.pwd_nvme->kobj, &auth_attr_group); + kobject_put(&tlmi_priv.pwd_nvme->kobj); + } + kset_unregister(tlmi_priv.authentication_kset); } @@ -831,7 +992,7 @@ static int tlmi_sysfs_init(void) goto fail_create_attr; tlmi_priv.pwd_power->kobj.kset = tlmi_priv.authentication_kset; - ret = kobject_add(&tlmi_priv.pwd_power->kobj, NULL, "%s", "System"); + ret = kobject_add(&tlmi_priv.pwd_power->kobj, NULL, "%s", "Power-on"); if (ret) goto fail_create_attr; @@ -839,6 +1000,35 @@ static int tlmi_sysfs_init(void) if (ret) goto fail_create_attr; + if (tlmi_priv.opcode_support) { + tlmi_priv.pwd_system->kobj.kset = tlmi_priv.authentication_kset; + ret = kobject_add(&tlmi_priv.pwd_system->kobj, NULL, "%s", "System"); + if (ret) + goto fail_create_attr; + + ret = sysfs_create_group(&tlmi_priv.pwd_system->kobj, &auth_attr_group); + if (ret) + goto fail_create_attr; + + tlmi_priv.pwd_hdd->kobj.kset = tlmi_priv.authentication_kset; + ret = kobject_add(&tlmi_priv.pwd_hdd->kobj, NULL, "%s", "HDD"); + if (ret) + goto fail_create_attr; + + ret = sysfs_create_group(&tlmi_priv.pwd_hdd->kobj, &auth_attr_group); + if (ret) + goto fail_create_attr; + + tlmi_priv.pwd_nvme->kobj.kset = tlmi_priv.authentication_kset; + ret = kobject_add(&tlmi_priv.pwd_nvme->kobj, NULL, "%s", "NVMe"); + if (ret) + goto fail_create_attr; + + ret = sysfs_create_group(&tlmi_priv.pwd_nvme->kobj, &auth_attr_group); + if (ret) + goto fail_create_attr; + } + return ret; fail_create_attr: @@ -851,9 +1041,27 @@ fail_class_created: } /* ---- Base Driver -------------------------------------------------------- */ +static struct tlmi_pwd_setting *tlmi_create_auth(const char *pwd_type, + const char *pwd_role) +{ + struct tlmi_pwd_setting *new_pwd; + + new_pwd = kzalloc(sizeof(struct tlmi_pwd_setting), GFP_KERNEL); + if (!new_pwd) + return NULL; + + strscpy(new_pwd->kbdlang, "us", TLMI_LANG_MAXLEN); + new_pwd->encoding = TLMI_ENCODING_ASCII; + new_pwd->pwd_type = pwd_type; + new_pwd->role = pwd_role; + new_pwd->minlen = tlmi_priv.pwdcfg.core.min_length; + new_pwd->maxlen = tlmi_priv.pwdcfg.core.max_length; + new_pwd->index = 0; + return new_pwd; +} + static int tlmi_analyze(void) { - struct tlmi_pwdcfg pwdcfg; acpi_status status; int i, ret; @@ -873,6 +1081,9 @@ static int tlmi_analyze(void) if (wmi_has_guid(LENOVO_DEBUG_CMD_GUID)) tlmi_priv.can_debug_cmd = true; + if (wmi_has_guid(LENOVO_OPCODE_IF_GUID)) + tlmi_priv.opcode_support = true; + /* * Try to find the number of valid settings of this machine * and use it to create sysfs attributes. @@ -923,49 +1134,81 @@ static int tlmi_analyze(void) } /* Create password setting structure */ - ret = tlmi_get_pwd_settings(&pwdcfg); + ret = tlmi_get_pwd_settings(&tlmi_priv.pwdcfg); if (ret) goto fail_clear_attr; - tlmi_priv.pwd_admin = kzalloc(sizeof(struct tlmi_pwd_setting), GFP_KERNEL); + tlmi_priv.pwd_admin = tlmi_create_auth("pap", "bios-admin"); if (!tlmi_priv.pwd_admin) { ret = -ENOMEM; goto fail_clear_attr; } - strscpy(tlmi_priv.pwd_admin->kbdlang, "us", TLMI_LANG_MAXLEN); - tlmi_priv.pwd_admin->encoding = TLMI_ENCODING_ASCII; - tlmi_priv.pwd_admin->pwd_type = "pap"; - tlmi_priv.pwd_admin->role = "bios-admin"; - tlmi_priv.pwd_admin->minlen = pwdcfg.min_length; - if (WARN_ON(pwdcfg.max_length >= TLMI_PWD_BUFSIZE)) - pwdcfg.max_length = TLMI_PWD_BUFSIZE - 1; - tlmi_priv.pwd_admin->maxlen = pwdcfg.max_length; - if (pwdcfg.password_state & TLMI_PAP_PWD) + if (tlmi_priv.pwdcfg.core.password_state & TLMI_PAP_PWD) tlmi_priv.pwd_admin->valid = true; kobject_init(&tlmi_priv.pwd_admin->kobj, &tlmi_pwd_setting_ktype); - tlmi_priv.pwd_power = kzalloc(sizeof(struct tlmi_pwd_setting), GFP_KERNEL); + tlmi_priv.pwd_power = tlmi_create_auth("pop", "power-on"); if (!tlmi_priv.pwd_power) { ret = -ENOMEM; - goto fail_free_pwd_admin; + goto fail_clear_attr; } - strscpy(tlmi_priv.pwd_power->kbdlang, "us", TLMI_LANG_MAXLEN); - tlmi_priv.pwd_power->encoding = TLMI_ENCODING_ASCII; - tlmi_priv.pwd_power->pwd_type = "pop"; - tlmi_priv.pwd_power->role = "power-on"; - tlmi_priv.pwd_power->minlen = pwdcfg.min_length; - tlmi_priv.pwd_power->maxlen = pwdcfg.max_length; - - if (pwdcfg.password_state & TLMI_POP_PWD) + if (tlmi_priv.pwdcfg.core.password_state & TLMI_POP_PWD) tlmi_priv.pwd_power->valid = true; kobject_init(&tlmi_priv.pwd_power->kobj, &tlmi_pwd_setting_ktype); + if (tlmi_priv.opcode_support) { + tlmi_priv.pwd_system = tlmi_create_auth("sys", "system"); + if (!tlmi_priv.pwd_system) { + ret = -ENOMEM; + goto fail_clear_attr; + } + if (tlmi_priv.pwdcfg.core.password_state & TLMI_SYS_PWD) + tlmi_priv.pwd_system->valid = true; + + kobject_init(&tlmi_priv.pwd_system->kobj, &tlmi_pwd_setting_ktype); + + tlmi_priv.pwd_hdd = tlmi_create_auth("hdd", "hdd"); + if (!tlmi_priv.pwd_hdd) { + ret = -ENOMEM; + goto fail_clear_attr; + } + kobject_init(&tlmi_priv.pwd_hdd->kobj, &tlmi_pwd_setting_ktype); + + tlmi_priv.pwd_nvme = tlmi_create_auth("nvm", "nvme"); + if (!tlmi_priv.pwd_nvme) { + ret = -ENOMEM; + goto fail_clear_attr; + } + kobject_init(&tlmi_priv.pwd_nvme->kobj, &tlmi_pwd_setting_ktype); + + if (tlmi_priv.pwdcfg.core.password_state & TLMI_HDD_PWD) { + /* Check if PWD is configured and set index to first drive found */ + if (tlmi_priv.pwdcfg.ext.hdd_user_password || + tlmi_priv.pwdcfg.ext.hdd_master_password) { + tlmi_priv.pwd_hdd->valid = true; + if (tlmi_priv.pwdcfg.ext.hdd_master_password) + tlmi_priv.pwd_hdd->index = + ffs(tlmi_priv.pwdcfg.ext.hdd_master_password) - 1; + else + tlmi_priv.pwd_hdd->index = + ffs(tlmi_priv.pwdcfg.ext.hdd_user_password) - 1; + } + if (tlmi_priv.pwdcfg.ext.nvme_user_password || + tlmi_priv.pwdcfg.ext.nvme_master_password) { + tlmi_priv.pwd_nvme->valid = true; + if (tlmi_priv.pwdcfg.ext.nvme_master_password) + tlmi_priv.pwd_nvme->index = + ffs(tlmi_priv.pwdcfg.ext.nvme_master_password) - 1; + else + tlmi_priv.pwd_nvme->index = + ffs(tlmi_priv.pwdcfg.ext.nvme_user_password) - 1; + } + } + } return 0; -fail_free_pwd_admin: - kfree(tlmi_priv.pwd_admin); fail_clear_attr: for (i = 0; i < TLMI_SETTINGS_COUNT; ++i) { if (tlmi_priv.setting[i]) { @@ -973,6 +1216,11 @@ fail_clear_attr: kfree(tlmi_priv.setting[i]); } } + kfree(tlmi_priv.pwd_admin); + kfree(tlmi_priv.pwd_power); + kfree(tlmi_priv.pwd_system); + kfree(tlmi_priv.pwd_hdd); + kfree(tlmi_priv.pwd_nvme); return ret; } diff --git a/drivers/platform/x86/think-lmi.h b/drivers/platform/x86/think-lmi.h index 2ce5086a5af27..e46c7f383353b 100644 --- a/drivers/platform/x86/think-lmi.h +++ b/drivers/platform/x86/think-lmi.h @@ -9,6 +9,7 @@ #define TLMI_SETTINGS_MAXLEN 512 #define TLMI_PWD_BUFSIZE 129 #define TLMI_LANG_MAXLEN 4 +#define TLMI_INDEX_MAX 32 /* Possible error values */ struct tlmi_err_codes { @@ -21,8 +22,13 @@ enum encoding_option { TLMI_ENCODING_SCANCODE, }; +enum level_option { + TLMI_LEVEL_USER, + TLMI_LEVEL_MASTER, +}; + /* password configuration details */ -struct tlmi_pwdcfg { +struct tlmi_pwdcfg_core { uint32_t password_mode; uint32_t password_state; uint32_t min_length; @@ -31,6 +37,18 @@ struct tlmi_pwdcfg { uint32_t supported_keyboard; }; +struct tlmi_pwdcfg_ext { + uint32_t hdd_user_password; + uint32_t hdd_master_password; + uint32_t nvme_user_password; + uint32_t nvme_master_password; +}; + +struct tlmi_pwdcfg { + struct tlmi_pwdcfg_core core; + struct tlmi_pwdcfg_ext ext; +}; + /* password setting details */ struct tlmi_pwd_setting { struct kobject kobj; @@ -42,6 +60,8 @@ struct tlmi_pwd_setting { int maxlen; enum encoding_option encoding; char kbdlang[TLMI_LANG_MAXLEN]; + int index; /*Used for HDD and NVME auth */ + enum level_option level; }; /* Attribute setting details */ @@ -61,13 +81,19 @@ struct think_lmi { bool can_get_password_settings; bool pending_changes; bool can_debug_cmd; + bool opcode_support; struct tlmi_attr_setting *setting[TLMI_SETTINGS_COUNT]; struct device *class_dev; struct kset *attribute_kset; struct kset *authentication_kset; + + struct tlmi_pwdcfg pwdcfg; struct tlmi_pwd_setting *pwd_admin; struct tlmi_pwd_setting *pwd_power; + struct tlmi_pwd_setting *pwd_system; + struct tlmi_pwd_setting *pwd_hdd; + struct tlmi_pwd_setting *pwd_nvme; }; #endif /* !_THINK_LMI_H_ */ -- GitLab From 8b6e88555971eac384b89fb0bd6c72ee4e1e6a6a Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Thu, 18 Nov 2021 13:48:47 +0200 Subject: [PATCH 0072/1112] regulator: rohm-regulator: add helper for restricted voltage setting Few ROHM PMICs have regulators where voltage setting can be done only when regulator is disabled. Add helper for those PMICs. Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/6f51871e9fea611d133b5dd2560f4a7ee1ede9cd.1637233864.git.matti.vaittinen@fi.rohmeurope.com Signed-off-by: Mark Brown --- drivers/regulator/rohm-regulator.c | 16 ++++++++++++++++ include/linux/mfd/rohm-generic.h | 7 +++++++ 2 files changed, 23 insertions(+) diff --git a/drivers/regulator/rohm-regulator.c b/drivers/regulator/rohm-regulator.c index 6e0d9c08ec1ca..f97a9a51ee765 100644 --- a/drivers/regulator/rohm-regulator.c +++ b/drivers/regulator/rohm-regulator.c @@ -112,6 +112,22 @@ int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs, } EXPORT_SYMBOL(rohm_regulator_set_dvs_levels); +/* + * Few ROHM PMIC ICs have constrains on voltage changing: + * BD71837 - only buck 1-4 voltages can be changed when they are enabled. + * Other bucks and all LDOs must be disabled when voltage is changed. + * BD96801 - LDO voltage levels can be changed when LDOs are disabled. + */ +int rohm_regulator_set_voltage_sel_restricted(struct regulator_dev *rdev, + unsigned int sel) +{ + if (rdev->desc->ops->is_enabled(rdev)) + return -EBUSY; + + return regulator_set_voltage_sel_regmap(rdev, sel); +} +EXPORT_SYMBOL_GPL(rohm_regulator_set_voltage_sel_restricted); + MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Matti Vaittinen "); MODULE_DESCRIPTION("Generic helpers for ROHM PMIC regulator drivers"); diff --git a/include/linux/mfd/rohm-generic.h b/include/linux/mfd/rohm-generic.h index 35b392a0d73a1..35c5866f48b7c 100644 --- a/include/linux/mfd/rohm-generic.h +++ b/include/linux/mfd/rohm-generic.h @@ -80,6 +80,8 @@ int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs, const struct regulator_desc *desc, struct regmap *regmap); +int rohm_regulator_set_voltage_sel_restricted(struct regulator_dev *rdev, + unsigned int sel); #else static inline int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs, struct device_node *np, @@ -88,6 +90,11 @@ static inline int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dv { return 0; } +static int rohm_regulator_set_voltage_sel_restricted(struct regulator_dev *rdev, + unsigned int sel) +{ + return 0; +} #endif #endif -- GitLab From e7543e199591c24175c4a06beec15611ce4b5a5b Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Thu, 18 Nov 2021 13:49:08 +0200 Subject: [PATCH 0073/1112] regulator: bd718x7: Use rohm generic restricted voltage setting Use common restricted voltage setting instead of implementing own. Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/5a0ee14852802690241568a29ed19ff9550b0b08.1637233864.git.matti.vaittinen@fi.rohmeurope.com Signed-off-by: Mark Brown --- drivers/regulator/bd718x7-regulator.c | 29 ++++----------------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/drivers/regulator/bd718x7-regulator.c b/drivers/regulator/bd718x7-regulator.c index d60fccedb250d..00efb18a836cd 100644 --- a/drivers/regulator/bd718x7-regulator.c +++ b/drivers/regulator/bd718x7-regulator.c @@ -125,27 +125,6 @@ static int bd71837_get_buck34_enable_hwctrl(struct regulator_dev *rdev) return !!(BD718XX_BUCK_RUN_ON & val); } -/* - * On BD71837 (not on BD71847, BD71850, ...) - * Bucks 1 to 4 support DVS. PWM mode is used when voltage is changed. - * Bucks 5 to 8 and LDOs can use PFM and must be disabled when voltage - * is changed. Hence we return -EBUSY for these if voltage is changed - * when BUCK/LDO is enabled. - * - * On BD71847, BD71850, ... The LDO voltage can be changed when LDO is - * enabled. But if voltage is increased the LDO power-good monitoring - * must be disabled for the duration of changing + 1mS to ensure voltage - * has reached the higher level before HW does next under voltage detection - * cycle. - */ -static int bd71837_set_voltage_sel_restricted(struct regulator_dev *rdev, - unsigned int sel) -{ - if (rdev->desc->ops->is_enabled(rdev)) - return -EBUSY; - - return regulator_set_voltage_sel_regmap(rdev, sel); -} static void voltage_change_done(struct regulator_dev *rdev, unsigned int sel, unsigned int *mask) @@ -642,22 +621,22 @@ BD718XX_OPS(bd71837_pickable_range_buck_ops, bd718x7_set_buck_ovp); BD718XX_OPS(bd71837_ldo_regulator_ops, regulator_list_voltage_linear_range, - NULL, bd71837_set_voltage_sel_restricted, + NULL, rohm_regulator_set_voltage_sel_restricted, regulator_get_voltage_sel_regmap, NULL, NULL, bd718x7_set_ldo_uvp, NULL); BD718XX_OPS(bd71837_ldo_regulator_nolinear_ops, regulator_list_voltage_table, - NULL, bd71837_set_voltage_sel_restricted, + NULL, rohm_regulator_set_voltage_sel_restricted, regulator_get_voltage_sel_regmap, NULL, NULL, bd718x7_set_ldo_uvp, NULL); BD718XX_OPS(bd71837_buck_regulator_ops, regulator_list_voltage_linear_range, - NULL, bd71837_set_voltage_sel_restricted, + NULL, rohm_regulator_set_voltage_sel_restricted, regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel, NULL, bd718x7_set_buck_uvp, bd718x7_set_buck_ovp); BD718XX_OPS(bd71837_buck_regulator_nolinear_ops, regulator_list_voltage_table, - regulator_map_voltage_ascend, bd71837_set_voltage_sel_restricted, + regulator_map_voltage_ascend, rohm_regulator_set_voltage_sel_restricted, regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel, NULL, bd718x7_set_buck_uvp, bd718x7_set_buck_ovp); /* -- GitLab From 92b1348277f8893671e5354adde64fe3cf462821 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Thu, 18 Nov 2021 13:49:30 +0200 Subject: [PATCH 0074/1112] regulator: Add units to limit documentation The documentation for limits used at protection level setting did not mention the units. Fix the units in documentation to match values passed in from device-tree (uV, uA, Kelvin) to avoid confusion. Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/111114aca991e41e49a32f89b74e95285f07c1e3.1637233864.git.matti.vaittinen@fi.rohmeurope.com Signed-off-by: Mark Brown --- include/linux/regulator/driver.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index bd7a73db2e66c..1cb8071fee343 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -101,11 +101,13 @@ enum regulator_detection_severity { * is requested. * @set_over_voltage_protection: Support enabling of and setting limits for over * voltage situation detection. Detection can be configured for same - * severities as over current protection. + * severities as over current protection. Units of uV. * @set_under_voltage_protection: Support enabling of and setting limits for - * under situation detection. + * under voltage situation detection. Detection can be configured for same + * severities as over current protection. Units of uV. * @set_thermal_protection: Support enabling of and setting limits for over - * temperature situation detection. + * temperature situation detection.Detection can be configured for same + * severities as over current protection. Units of degree Kelvin. * * @set_active_discharge: Set active discharge enable/disable of regulators. * -- GitLab From 5a8f8542e34b6469cd5c5a3d075fa5977d90775e Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Thu, 18 Nov 2021 03:10:39 +0000 Subject: [PATCH 0075/1112] spi: dt-bindings: renesas,rspi: Document RZ/G2L SoC Add RSPI binding documentation for Renesas RZ/G2L SoC. RSPI block is identical to one found on RZ/A, so no driver changes are required. The fallback compatible string "renesas,rspi-rz" will be used on RZ/G2L. Signed-off-by: Lad Prabhakar Reviewed-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20211118031041.2312-2-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/renesas,rspi.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/spi/renesas,rspi.yaml b/Documentation/devicetree/bindings/spi/renesas,rspi.yaml index 8397f60d80a2e..76e6d9e52fc72 100644 --- a/Documentation/devicetree/bindings/spi/renesas,rspi.yaml +++ b/Documentation/devicetree/bindings/spi/renesas,rspi.yaml @@ -21,7 +21,8 @@ properties: - enum: - renesas,rspi-r7s72100 # RZ/A1H - renesas,rspi-r7s9210 # RZ/A2 - - const: renesas,rspi-rz # RZ/A + - renesas,r9a07g044-rspi # RZ/G2{L,LC} + - const: renesas,rspi-rz # RZ/A and RZ/G2{L,LC} - items: - enum: @@ -122,6 +123,7 @@ allOf: contains: enum: - renesas,qspi + - renesas,r9a07g044-rspi then: required: - resets -- GitLab From aadbff4af5c90919cbe67e2c4d77c68cdefa454e Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Thu, 18 Nov 2021 03:10:40 +0000 Subject: [PATCH 0076/1112] spi: spi-rspi: Add support to deassert/assert reset line On RZ/G2L SoC we need to explicitly deassert the reset line for the device to work, use this opportunity to deassert/assert reset line in spi-rspi driver. This patch adds support to read the "resets" property (if available) from DT and perform deassert/assert when required. Signed-off-by: Lad Prabhakar Reviewed-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20211118031041.2312-3-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 41761f0d892ad..b7df49a57e5fc 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -1225,8 +1226,14 @@ static const struct of_device_id rspi_of_match[] = { MODULE_DEVICE_TABLE(of, rspi_of_match); +static void rspi_reset_control_assert(void *data) +{ + reset_control_assert(data); +} + static int rspi_parse_dt(struct device *dev, struct spi_controller *ctlr) { + struct reset_control *rstc; u32 num_cs; int error; @@ -1238,6 +1245,24 @@ static int rspi_parse_dt(struct device *dev, struct spi_controller *ctlr) } ctlr->num_chipselect = num_cs; + + rstc = devm_reset_control_get_optional_exclusive(dev, NULL); + if (IS_ERR(rstc)) + return dev_err_probe(dev, PTR_ERR(rstc), + "failed to get reset ctrl\n"); + + error = reset_control_deassert(rstc); + if (error) { + dev_err(dev, "failed to deassert reset %d\n", error); + return error; + } + + error = devm_add_action_or_reset(dev, rspi_reset_control_assert, rstc); + if (error) { + dev_err(dev, "failed to register assert devm action, %d\n", error); + return error; + } + return 0; } #else -- GitLab From 1d734f592e1a1d41af80e90001d109cec1c98fb4 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Thu, 18 Nov 2021 03:10:41 +0000 Subject: [PATCH 0077/1112] spi: spi-rspi: Drop redeclaring ret variable in qspi_transfer_in() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "ret" variable is already declared in qspi_transfer_in() at the beginning of function, drop redeclaring ret in the if block, fixing below: spi-rspi.c: In function ‘qspi_transfer_in’: spi-rspi.c:838:7: warning: declaration of ‘ret’ shadows a previous local 838 | int ret = rspi_dma_transfer(rspi, NULL, &xfer->rx_sg); | ^~~ spi-rspi.c:835:6: note: shadowed declaration is here 835 | int ret; Fixes: db30083813b55 ("spi: rspi: avoid uninitialized variable access") Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20211118031041.2312-4-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index b7df49a57e5fc..bd5708d7e5a15 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -835,7 +835,7 @@ static int qspi_transfer_in(struct rspi_data *rspi, struct spi_transfer *xfer) int ret; if (rspi->ctlr->can_dma && __rspi_can_dma(rspi, xfer)) { - int ret = rspi_dma_transfer(rspi, NULL, &xfer->rx_sg); + ret = rspi_dma_transfer(rspi, NULL, &xfer->rx_sg); if (ret != -EAGAIN) return ret; } -- GitLab From 61f6e38ae8b6cbe140cfd320b3003a52147edef0 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Wed, 17 Nov 2021 19:01:08 +0530 Subject: [PATCH 0078/1112] spi: qcom: geni: remove unused defines Commit b59c122484ec ("spi: spi-geni-qcom: Add support for GPI dma") added GPI support but also added unused defines, so remove them Signed-off-by: Vinod Koul Reviewed-by: Douglas Anderson Link: https://lore.kernel.org/r/20211117133110.2682631-1-vkoul@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-geni-qcom.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index e2affaee4e769..413fa1a7a9365 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -71,10 +71,6 @@ #define GSI_CPHA BIT(4) #define GSI_CPOL BIT(5) -#define MAX_TX_SG 3 -#define NUM_SPI_XFER 8 -#define SPI_XFER_TIMEOUT_MS 250 - struct spi_geni_master { struct geni_se se; struct device *dev; -- GitLab From d951ae1ce8033dea91c532810536809d0e691615 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Tue, 2 Nov 2021 11:40:25 -0700 Subject: [PATCH 0079/1112] HID: i2c-hid: Report wakeup events The i2c-hid driver generally supports wakeup, bit it currently doesn't report wakeup events to the PM subsystem. Change that. Signed-off-by: Matthias Kaehlcke Acked-by: Hans de Goede Signed-off-by: Jiri Kosina --- drivers/hid/i2c-hid/i2c-hid-core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 517141138b007..68d9a089e3e85 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -522,9 +522,12 @@ static void i2c_hid_get_input(struct i2c_hid *ihid) i2c_hid_dbg(ihid, "input: %*ph\n", ret_size, ihid->inbuf); - if (test_bit(I2C_HID_STARTED, &ihid->flags)) + if (test_bit(I2C_HID_STARTED, &ihid->flags)) { + pm_wakeup_event(&ihid->client->dev, 0); + hid_input_report(ihid->hid, HID_INPUT_REPORT, ihid->inbuf + 2, ret_size - 2, 1); + } return; } -- GitLab From 03dada294d0830f3bc994909f2e74ecaa3aa92a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Thu, 11 Nov 2021 16:44:11 +0000 Subject: [PATCH 0080/1112] HID: logitech: add myself as a reviewer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, I have to use a separate email address and maintain several filters to monitor changes to Logitech drivers, so that I can have an opportunity to review them. Since I am very interested in keeping up with the changes, as I have a lot of the hardware and maintain the main userspace stacks that depend on these drivers, I would like to mark myself as a reviewer. I would also be open to be marked as a maintainer if Benjamin thinks it makes sense. Signed-off-by: Filipe Laíns Signed-off-by: Jiri Kosina --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 74158b271cb74..5381b6f16cb35 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8436,6 +8436,12 @@ F: drivers/hid/ F: include/linux/hid* F: include/uapi/linux/hid* +HID LOGITECH DRIVERS +R: Filipe Laíns +L: linux-input@vger.kernel.org +S: Maintained +F: drivers/hid/hid-logitech-* + HID PLAYSTATION DRIVER M: Roderick Colenbrander L: linux-input@vger.kernel.org -- GitLab From 0b91b4e4dae63cd43871fc2012370b86ee588f91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Thu, 18 Nov 2021 17:52:08 +0100 Subject: [PATCH 0081/1112] HID: magicmouse: Report battery level over USB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When connected over USB, the Apple Magic Mouse 2 and the Apple Magic Trackpad 2 register multiple interfaces, one of them is used to report the battery level. However, unlike when connected over Bluetooth, the battery level is not reported automatically and it is required to fetch it manually. Fix the battery report descriptor and add a timer to fetch the battery level. Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-magicmouse.c | 94 +++++++++++++++++++++++++++++++++--- 1 file changed, 88 insertions(+), 6 deletions(-) diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index 686788ebf3e1e..167b6a5dd226a 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -57,6 +57,8 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie #define MOUSE_REPORT_ID 0x29 #define MOUSE2_REPORT_ID 0x12 #define DOUBLE_REPORT_ID 0xf7 +#define USB_BATTERY_TIMEOUT_MS 60000 + /* These definitions are not precise, but they're close enough. (Bits * 0x03 seem to indicate the aspect ratio of the touch, bits 0x70 seem * to be some kind of bit mask -- 0x20 may be a near-field reading, @@ -140,6 +142,7 @@ struct magicmouse_sc { struct hid_device *hdev; struct delayed_work work; + struct timer_list battery_timer; }; static int magicmouse_firm_touch(struct magicmouse_sc *msc) @@ -735,6 +738,44 @@ static void magicmouse_enable_mt_work(struct work_struct *work) hid_err(msc->hdev, "unable to request touch data (%d)\n", ret); } +static int magicmouse_fetch_battery(struct hid_device *hdev) +{ +#ifdef CONFIG_HID_BATTERY_STRENGTH + struct hid_report_enum *report_enum; + struct hid_report *report; + + if (!hdev->battery || hdev->vendor != USB_VENDOR_ID_APPLE || + (hdev->product != USB_DEVICE_ID_APPLE_MAGICMOUSE2 && + hdev->product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2)) + return -1; + + report_enum = &hdev->report_enum[hdev->battery_report_type]; + report = report_enum->report_id_hash[hdev->battery_report_id]; + + if (!report || report->maxfield < 1) + return -1; + + if (hdev->battery_capacity == hdev->battery_max) + return -1; + + hid_hw_request(hdev, report, HID_REQ_GET_REPORT); + return 0; +#else + return -1; +#endif +} + +static void magicmouse_battery_timer_tick(struct timer_list *t) +{ + struct magicmouse_sc *msc = from_timer(msc, t, battery_timer); + struct hid_device *hdev = msc->hdev; + + if (magicmouse_fetch_battery(hdev) == 0) { + mod_timer(&msc->battery_timer, + jiffies + msecs_to_jiffies(USB_BATTERY_TIMEOUT_MS)); + } +} + static int magicmouse_probe(struct hid_device *hdev, const struct hid_device_id *id) { @@ -742,11 +783,6 @@ static int magicmouse_probe(struct hid_device *hdev, struct hid_report *report; int ret; - if (id->vendor == USB_VENDOR_ID_APPLE && - id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 && - hdev->type != HID_TYPE_USBMOUSE) - return -ENODEV; - msc = devm_kzalloc(&hdev->dev, sizeof(*msc), GFP_KERNEL); if (msc == NULL) { hid_err(hdev, "can't alloc magicmouse descriptor\n"); @@ -772,6 +808,16 @@ static int magicmouse_probe(struct hid_device *hdev, return ret; } + timer_setup(&msc->battery_timer, magicmouse_battery_timer_tick, 0); + mod_timer(&msc->battery_timer, + jiffies + msecs_to_jiffies(USB_BATTERY_TIMEOUT_MS)); + magicmouse_fetch_battery(hdev); + + if (id->vendor == USB_VENDOR_ID_APPLE && + (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 || + (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 && hdev->type != HID_TYPE_USBMOUSE))) + return 0; + if (!msc->input) { hid_err(hdev, "magicmouse input not registered\n"); ret = -ENOMEM; @@ -832,17 +878,52 @@ static void magicmouse_remove(struct hid_device *hdev) { struct magicmouse_sc *msc = hid_get_drvdata(hdev); - if (msc) + if (msc) { cancel_delayed_work_sync(&msc->work); + del_timer_sync(&msc->battery_timer); + } hid_hw_stop(hdev); } +static __u8 *magicmouse_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + /* + * Change the usage from: + * 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 0 + * 0x09, 0x0b, // Usage (Vendor Usage 0x0b) 3 + * To: + * 0x05, 0x01, // Usage Page (Generic Desktop) 0 + * 0x09, 0x02, // Usage (Mouse) 2 + */ + if (hdev->vendor == USB_VENDOR_ID_APPLE && + (hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 || + hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) && + *rsize == 83 && rdesc[46] == 0x84 && rdesc[58] == 0x85) { + hid_info(hdev, + "fixing up magicmouse battery report descriptor\n"); + *rsize = *rsize - 1; + rdesc = kmemdup(rdesc + 1, *rsize, GFP_KERNEL); + if (!rdesc) + return NULL; + + rdesc[0] = 0x05; + rdesc[1] = 0x01; + rdesc[2] = 0x09; + rdesc[3] = 0x02; + } + + return rdesc; +} + static const struct hid_device_id magic_mice[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE), .driver_data = 0 }, { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE2), .driver_data = 0 }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, + USB_DEVICE_ID_APPLE_MAGICMOUSE2), .driver_data = 0 }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD), .driver_data = 0 }, { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, @@ -858,6 +939,7 @@ static struct hid_driver magicmouse_driver = { .id_table = magic_mice, .probe = magicmouse_probe, .remove = magicmouse_remove, + .report_fixup = magicmouse_report_fixup, .raw_event = magicmouse_raw_event, .event = magicmouse_event, .input_mapping = magicmouse_input_mapping, -- GitLab From a5fe7864d8ada170f19cc47d176bf8260ffb4263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Thu, 18 Nov 2021 08:29:53 +0100 Subject: [PATCH 0082/1112] HID: apple: Do not reset quirks when the Fn key is not found MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a keyboard without a function key is detected, instead of removing all quirks, remove only the APPLE_HAS_FN quirk. Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-apple.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 2c9c5faa74a97..a4ca5ed00e5f5 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -428,7 +428,7 @@ static int apple_input_configured(struct hid_device *hdev, if ((asc->quirks & APPLE_HAS_FN) && !asc->fn_found) { hid_info(hdev, "Fn key not found (Apple Wireless Keyboard clone?), disabling Fn key handling\n"); - asc->quirks = 0; + asc->quirks &= ~APPLE_HAS_FN; } return 0; -- GitLab From 7f52ece242e9714d94d3bab630ea1dd2236e7d54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Thu, 18 Nov 2021 08:29:54 +0100 Subject: [PATCH 0083/1112] HID: apple: Use BIT to define quirks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the existing quirk hardcoded values with the BIT macro in order to simplify including new quirks. Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-apple.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index a4ca5ed00e5f5..b34aeed292a28 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -21,15 +21,15 @@ #include "hid-ids.h" -#define APPLE_RDESC_JIS 0x0001 -#define APPLE_IGNORE_MOUSE 0x0002 -#define APPLE_HAS_FN 0x0004 -/* 0x0008 reserved, was: APPLE_HIDDEV */ -#define APPLE_ISO_TILDE_QUIRK 0x0010 -#define APPLE_MIGHTYMOUSE 0x0020 -#define APPLE_INVERT_HWHEEL 0x0040 -/* 0x0080 reserved, was: APPLE_IGNORE_HIDINPUT */ -#define APPLE_NUMLOCK_EMULATION 0x0100 +#define APPLE_RDESC_JIS BIT(0) +#define APPLE_IGNORE_MOUSE BIT(1) +#define APPLE_HAS_FN BIT(2) +/* BIT(3) reserved, was: APPLE_HIDDEV */ +#define APPLE_ISO_TILDE_QUIRK BIT(4) +#define APPLE_MIGHTYMOUSE BIT(5) +#define APPLE_INVERT_HWHEEL BIT(6) +/* BIT(7) reserved, was: APPLE_IGNORE_HIDINPUT */ +#define APPLE_NUMLOCK_EMULATION BIT(8) #define APPLE_FLAG_FKEY 0x01 -- GitLab From 6e143293e17a73c9313f91c5ca3aaacbaef030cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Thu, 18 Nov 2021 08:29:55 +0100 Subject: [PATCH 0084/1112] HID: apple: Report Magic Keyboard battery over USB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When connected over USB, the Apple Magic Keyboard 2015 registers 3 different interfaces. One of them is used to report the battery level. However, unlike when connected over Bluetooth, the battery level is not reported automatically and it is required to fetch it manually. Add a new quirk to fix the battery report descriptor and a timer to fetch the battery level. Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-apple.c | 87 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index b34aeed292a28..2bd8276411e07 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -16,8 +16,10 @@ #include #include +#include #include #include +#include #include "hid-ids.h" @@ -30,10 +32,12 @@ #define APPLE_INVERT_HWHEEL BIT(6) /* BIT(7) reserved, was: APPLE_IGNORE_HIDINPUT */ #define APPLE_NUMLOCK_EMULATION BIT(8) +#define APPLE_RDESC_BATTERY BIT(9) #define APPLE_FLAG_FKEY 0x01 #define HID_COUNTRY_INTERNATIONAL_ISO 13 +#define APPLE_BATTERY_TIMEOUT_MS 60000 static unsigned int fnmode = 1; module_param(fnmode, uint, 0644); @@ -58,10 +62,12 @@ MODULE_PARM_DESC(swap_fn_leftctrl, "Swap the Fn and left Control keys. " "[0] = as-is, Mac layout, 1 = swapped, PC layout)"); struct apple_sc { + struct hid_device *hdev; unsigned long quirks; unsigned int fn_on; unsigned int fn_found; DECLARE_BITMAP(pressed_numlock, KEY_CNT); + struct timer_list battery_timer; }; struct apple_key_translation { @@ -333,6 +339,43 @@ static int apple_event(struct hid_device *hdev, struct hid_field *field, return 0; } +static int apple_fetch_battery(struct hid_device *hdev) +{ +#ifdef CONFIG_HID_BATTERY_STRENGTH + struct apple_sc *asc = hid_get_drvdata(hdev); + struct hid_report_enum *report_enum; + struct hid_report *report; + + if (!(asc->quirks & APPLE_RDESC_BATTERY) || !hdev->battery) + return -1; + + report_enum = &hdev->report_enum[hdev->battery_report_type]; + report = report_enum->report_id_hash[hdev->battery_report_id]; + + if (!report || report->maxfield < 1) + return -1; + + if (hdev->battery_capacity == hdev->battery_max) + return -1; + + hid_hw_request(hdev, report, HID_REQ_GET_REPORT); + return 0; +#else + return -1; +#endif +} + +static void apple_battery_timer_tick(struct timer_list *t) +{ + struct apple_sc *asc = from_timer(asc, t, battery_timer); + struct hid_device *hdev = asc->hdev; + + if (apple_fetch_battery(hdev) == 0) { + mod_timer(&asc->battery_timer, + jiffies + msecs_to_jiffies(APPLE_BATTERY_TIMEOUT_MS)); + } +} + /* * MacBook JIS keyboard has wrong logical maximum * Magic Keyboard JIS has wrong logical maximum @@ -354,6 +397,30 @@ static __u8 *apple_report_fixup(struct hid_device *hdev, __u8 *rdesc, "fixing up MacBook JIS keyboard report descriptor\n"); rdesc[53] = rdesc[59] = 0xe7; } + + /* + * Change the usage from: + * 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 0 + * 0x09, 0x0b, // Usage (Vendor Usage 0x0b) 3 + * To: + * 0x05, 0x01, // Usage Page (Generic Desktop) 0 + * 0x09, 0x06, // Usage (Keyboard) 2 + */ + if ((asc->quirks & APPLE_RDESC_BATTERY) && *rsize == 83 && + rdesc[46] == 0x84 && rdesc[58] == 0x85) { + hid_info(hdev, + "fixing up Magic Keyboard battery report descriptor\n"); + *rsize = *rsize - 1; + rdesc = kmemdup(rdesc + 1, *rsize, GFP_KERNEL); + if (!rdesc) + return NULL; + + rdesc[0] = 0x05; + rdesc[1] = 0x01; + rdesc[2] = 0x09; + rdesc[3] = 0x06; + } + return rdesc; } @@ -447,6 +514,7 @@ static int apple_probe(struct hid_device *hdev, return -ENOMEM; } + asc->hdev = hdev; asc->quirks = quirks; hid_set_drvdata(hdev, asc); @@ -463,9 +531,23 @@ static int apple_probe(struct hid_device *hdev, return ret; } + timer_setup(&asc->battery_timer, apple_battery_timer_tick, 0); + mod_timer(&asc->battery_timer, + jiffies + msecs_to_jiffies(APPLE_BATTERY_TIMEOUT_MS)); + apple_fetch_battery(hdev); + return 0; } +static void apple_remove(struct hid_device *hdev) +{ + struct apple_sc *asc = hid_get_drvdata(hdev); + + del_timer_sync(&asc->battery_timer); + + hid_hw_stop(hdev); +} + static const struct hid_device_id apple_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE), .driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL }, @@ -540,11 +622,11 @@ static const struct hid_device_id apple_devices[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS), .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2015), - .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, + .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_RDESC_BATTERY }, { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2015), .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2015), - .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, + .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_RDESC_BATTERY }, { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2015), .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI), @@ -650,6 +732,7 @@ static struct hid_driver apple_driver = { .id_table = apple_devices, .report_fixup = apple_report_fixup, .probe = apple_probe, + .remove = apple_remove, .event = apple_event, .input_mapping = apple_input_mapping, .input_mapped = apple_input_mapped, -- GitLab From 71e89591502d737c10db2bd4d8fcfaa352552afb Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 16 Oct 2021 14:22:24 +0100 Subject: [PATCH 0085/1112] mtd: rawnand: davinci: Don't calculate ECC when reading page The function nand_davinci_read_page_hwecc_oob_first() does read the ECC data from the OOB area. Therefore it does not need to calculate the ECC as it is already available. Cc: # v5.2 Fixes: a0ac778eb82c ("mtd: rawnand: ingenic: Add support for the JZ4740") Signed-off-by: Paul Cercueil Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20211016132228.40254-1-paul@crapouillou.net --- drivers/mtd/nand/raw/davinci_nand.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c index 118da9944e3bc..89de24d3bb7a3 100644 --- a/drivers/mtd/nand/raw/davinci_nand.c +++ b/drivers/mtd/nand/raw/davinci_nand.c @@ -394,7 +394,6 @@ static int nand_davinci_read_page_hwecc_oob_first(struct nand_chip *chip, int eccsteps = chip->ecc.steps; uint8_t *p = buf; uint8_t *ecc_code = chip->ecc.code_buf; - uint8_t *ecc_calc = chip->ecc.calc_buf; unsigned int max_bitflips = 0; /* Read the OOB area first */ @@ -420,8 +419,6 @@ static int nand_davinci_read_page_hwecc_oob_first(struct nand_chip *chip, if (ret) return ret; - chip->ecc.calculate(chip, p, &ecc_calc[i]); - stat = chip->ecc.correct(chip, p, &ecc_code[i], NULL); if (stat == -EBADMSG && (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) { -- GitLab From 9c9d709965385de5a99f84b14bd5860e1541729e Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 16 Oct 2021 14:22:25 +0100 Subject: [PATCH 0086/1112] mtd: rawnand: davinci: Avoid duplicated page read The function nand_davinci_read_page_hwecc_oob_first() first reads the OOB data, extracts the ECC information, programs the ECC hardware before reading the actual data in a loop. Right after the OOB data was read, it called nand_read_page_op() to reset the read cursor to the beginning of the page. This caused the first page to be read twice: in that call, and later in the loop. Address that issue by changing the call to nand_read_page_op() to nand_change_read_column_op(), which will only reset the read cursor. Cc: # v5.2 Fixes: a0ac778eb82c ("mtd: rawnand: ingenic: Add support for the JZ4740") Signed-off-by: Paul Cercueil Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20211016132228.40254-2-paul@crapouillou.net --- drivers/mtd/nand/raw/davinci_nand.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c index 89de24d3bb7a3..2e6a0c1671bea 100644 --- a/drivers/mtd/nand/raw/davinci_nand.c +++ b/drivers/mtd/nand/raw/davinci_nand.c @@ -401,7 +401,8 @@ static int nand_davinci_read_page_hwecc_oob_first(struct nand_chip *chip, if (ret) return ret; - ret = nand_read_page_op(chip, page, 0, NULL, 0); + /* Move read cursor to start of page */ + ret = nand_change_read_column_op(chip, 0, NULL, 0, false); if (ret) return ret; -- GitLab From 0697f8441faad552fbeb02d74454b5e7bcc956a2 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 16 Oct 2021 14:22:26 +0100 Subject: [PATCH 0087/1112] mtd: rawnand: davinci: Rewrite function description The original comment that describes the function nand_davinci_read_page_hwecc_oob_first() is very obscure and it is hard to understand what it is for. Cc: # v5.2 Fixes: a0ac778eb82c ("mtd: rawnand: ingenic: Add support for the JZ4740") Signed-off-by: Paul Cercueil Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20211016132228.40254-3-paul@crapouillou.net --- drivers/mtd/nand/raw/davinci_nand.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c index 2e6a0c1671bea..fe2511cdcae37 100644 --- a/drivers/mtd/nand/raw/davinci_nand.c +++ b/drivers/mtd/nand/raw/davinci_nand.c @@ -372,17 +372,15 @@ correct: } /** - * nand_read_page_hwecc_oob_first - hw ecc, read oob first + * nand_davinci_read_page_hwecc_oob_first - Hardware ECC page read with ECC + * data read from OOB area * @chip: nand chip info structure * @buf: buffer to store read data * @oob_required: caller requires OOB data read to chip->oob_poi * @page: page number to read * - * Hardware ECC for large page chips, require OOB to be read first. For this - * ECC mode, the write_page method is re-used from ECC_HW. These methods - * read/write ECC from the OOB area, unlike the ECC_HW_SYNDROME support with - * multiple ECC steps, follows the "infix ECC" scheme and reads/writes ECC from - * the data area, by overwriting the NAND manufacturer bad block markings. + * Hardware ECC for large page chips, which requires the ECC data to be + * extracted from the OOB before the actual data is read. */ static int nand_davinci_read_page_hwecc_oob_first(struct nand_chip *chip, uint8_t *buf, -- GitLab From d8466f73010faf71effb21228ae1cbf577dab130 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 16 Oct 2021 14:22:27 +0100 Subject: [PATCH 0088/1112] mtd: rawnand: Export nand_read_page_hwecc_oob_first() Move the function nand_read_page_hwecc_oob_first() (previously nand_davinci_read_page_hwecc_oob_first()) to nand_base.c, and export it as a GPL symbol, so that it can be used by more modules. Cc: # v5.2 Fixes: a0ac778eb82c ("mtd: rawnand: ingenic: Add support for the JZ4740") Signed-off-by: Paul Cercueil Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20211016132228.40254-4-paul@crapouillou.net --- drivers/mtd/nand/raw/davinci_nand.c | 69 +---------------------------- drivers/mtd/nand/raw/nand_base.c | 67 ++++++++++++++++++++++++++++ include/linux/mtd/rawnand.h | 2 + 3 files changed, 70 insertions(+), 68 deletions(-) diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c index fe2511cdcae37..45fec8c192aba 100644 --- a/drivers/mtd/nand/raw/davinci_nand.c +++ b/drivers/mtd/nand/raw/davinci_nand.c @@ -371,73 +371,6 @@ correct: return corrected; } -/** - * nand_davinci_read_page_hwecc_oob_first - Hardware ECC page read with ECC - * data read from OOB area - * @chip: nand chip info structure - * @buf: buffer to store read data - * @oob_required: caller requires OOB data read to chip->oob_poi - * @page: page number to read - * - * Hardware ECC for large page chips, which requires the ECC data to be - * extracted from the OOB before the actual data is read. - */ -static int nand_davinci_read_page_hwecc_oob_first(struct nand_chip *chip, - uint8_t *buf, - int oob_required, int page) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - int i, eccsize = chip->ecc.size, ret; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - uint8_t *p = buf; - uint8_t *ecc_code = chip->ecc.code_buf; - unsigned int max_bitflips = 0; - - /* Read the OOB area first */ - ret = nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize); - if (ret) - return ret; - - /* Move read cursor to start of page */ - ret = nand_change_read_column_op(chip, 0, NULL, 0, false); - if (ret) - return ret; - - ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0, - chip->ecc.total); - if (ret) - return ret; - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - int stat; - - chip->ecc.hwctl(chip, NAND_ECC_READ); - - ret = nand_read_data_op(chip, p, eccsize, false, false); - if (ret) - return ret; - - stat = chip->ecc.correct(chip, p, &ecc_code[i], NULL); - if (stat == -EBADMSG && - (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) { - /* check for empty pages with bitflips */ - stat = nand_check_erased_ecc_chunk(p, eccsize, - &ecc_code[i], - eccbytes, NULL, 0, - chip->ecc.strength); - } - - if (stat < 0) { - mtd->ecc_stats.failed++; - } else { - mtd->ecc_stats.corrected += stat; - max_bitflips = max_t(unsigned int, max_bitflips, stat); - } - } - return max_bitflips; -} - /*----------------------------------------------------------------------*/ /* An ECC layout for using 4-bit ECC with small-page flash, storing @@ -647,7 +580,7 @@ static int davinci_nand_attach_chip(struct nand_chip *chip) } else if (chunks == 4 || chunks == 8) { mtd_set_ooblayout(mtd, nand_get_large_page_ooblayout()); - chip->ecc.read_page = nand_davinci_read_page_hwecc_oob_first; + chip->ecc.read_page = nand_read_page_hwecc_oob_first; } else { return -EIO; } diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 3d6c6e8805207..113a2e9f43b1b 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -3160,6 +3160,73 @@ static int nand_read_page_hwecc(struct nand_chip *chip, uint8_t *buf, return max_bitflips; } +/** + * nand_read_page_hwecc_oob_first - Hardware ECC page read with ECC + * data read from OOB area + * @chip: nand chip info structure + * @buf: buffer to store read data + * @oob_required: caller requires OOB data read to chip->oob_poi + * @page: page number to read + * + * Hardware ECC for large page chips, which requires the ECC data to be + * extracted from the OOB before the actual data is read. + */ +int nand_read_page_hwecc_oob_first(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + int i, eccsize = chip->ecc.size, ret; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + uint8_t *p = buf; + uint8_t *ecc_code = chip->ecc.code_buf; + unsigned int max_bitflips = 0; + + /* Read the OOB area first */ + ret = nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize); + if (ret) + return ret; + + /* Move read cursor to start of page */ + ret = nand_change_read_column_op(chip, 0, NULL, 0, false); + if (ret) + return ret; + + ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0, + chip->ecc.total); + if (ret) + return ret; + + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + int stat; + + chip->ecc.hwctl(chip, NAND_ECC_READ); + + ret = nand_read_data_op(chip, p, eccsize, false, false); + if (ret) + return ret; + + stat = chip->ecc.correct(chip, p, &ecc_code[i], NULL); + if (stat == -EBADMSG && + (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) { + /* check for empty pages with bitflips */ + stat = nand_check_erased_ecc_chunk(p, eccsize, + &ecc_code[i], + eccbytes, NULL, 0, + chip->ecc.strength); + } + + if (stat < 0) { + mtd->ecc_stats.failed++; + } else { + mtd->ecc_stats.corrected += stat; + max_bitflips = max_t(unsigned int, max_bitflips, stat); + } + } + return max_bitflips; +} +EXPORT_SYMBOL_GPL(nand_read_page_hwecc_oob_first); + /** * nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read * @chip: nand chip info structure diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index b2f9dd3cbd695..5b88cd51fadb5 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1539,6 +1539,8 @@ int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len, bool force_8bit, bool check_only); int nand_write_data_op(struct nand_chip *chip, const void *buf, unsigned int len, bool force_8bit); +int nand_read_page_hwecc_oob_first(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page); /* Scan and identify a NAND device */ int nand_scan_with_ids(struct nand_chip *chip, unsigned int max_chips, -- GitLab From 0171480007d64f663aae9226303f1b1e4621229e Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 16 Oct 2021 14:22:28 +0100 Subject: [PATCH 0089/1112] mtd: rawnand: ingenic: JZ4740 needs 'oob_first' read page function The ECC engine on the JZ4740 SoC requires the ECC data to be read before the page; using the default page reading function does not work. Indeed, the old JZ4740 NAND driver (removed in 5.4) did use the 'OOB first' flag that existed back then. Use the newly created nand_read_page_hwecc_oob_first() to address this issue. This issue was not found when the new ingenic-nand driver was developed, most likely because the Device Tree used had the nand-ecc-mode set to "hw_oob_first", which seems to not be supported anymore. Cc: # v5.2 Fixes: a0ac778eb82c ("mtd: rawnand: ingenic: Add support for the JZ4740") Signed-off-by: Paul Cercueil Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20211016132228.40254-5-paul@crapouillou.net --- drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c b/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c index 0e9d426fe4f2b..b18861bdcdc88 100644 --- a/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c +++ b/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c @@ -32,6 +32,7 @@ struct jz_soc_info { unsigned long addr_offset; unsigned long cmd_offset; const struct mtd_ooblayout_ops *oob_layout; + bool oob_first; }; struct ingenic_nand_cs { @@ -240,6 +241,9 @@ static int ingenic_nand_attach_chip(struct nand_chip *chip) if (chip->bbt_options & NAND_BBT_USE_FLASH) chip->bbt_options |= NAND_BBT_NO_OOB; + if (nfc->soc_info->oob_first) + chip->ecc.read_page = nand_read_page_hwecc_oob_first; + /* For legacy reasons we use a different layout on the qi,lb60 board. */ if (of_machine_is_compatible("qi,lb60")) mtd_set_ooblayout(mtd, &qi_lb60_ooblayout_ops); @@ -534,6 +538,7 @@ static const struct jz_soc_info jz4740_soc_info = { .data_offset = 0x00000000, .cmd_offset = 0x00008000, .addr_offset = 0x00010000, + .oob_first = true, }; static const struct jz_soc_info jz4725b_soc_info = { -- GitLab From aa1baa0e6c1aa4872e481dce4fc7fd6f3dd8496b Mon Sep 17 00:00:00 2001 From: Stefan Riedmueller Date: Tue, 2 Nov 2021 21:20:21 +0100 Subject: [PATCH 0090/1112] mtd: rawnand: gpmi: Remove explicit default gpmi clock setting for i.MX6 There is no need to explicitly set the default gpmi clock rate during boot for the i.MX 6 since this is done during nand_detect anyway. Signed-off-by: Stefan Riedmueller Cc: stable@vger.kernel.org Acked-by: Han Xu Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20211102202022.15551-1-ceggers@arri.de --- drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c index 10cc71829dcb6..66239f129a4d2 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -1032,15 +1032,6 @@ static int gpmi_get_clks(struct gpmi_nand_data *this) r->clock[i] = clk; } - if (GPMI_IS_MX6(this)) - /* - * Set the default value for the gpmi clock. - * - * If you want to use the ONFI nand which is in the - * Synchronous Mode, you should change the clock as you need. - */ - clk_set_rate(r->clock[0], 22000000); - return 0; err_clock: -- GitLab From f53d4c109a666bf1a4883b45d546fba079258717 Mon Sep 17 00:00:00 2001 From: Christian Eggers Date: Tue, 2 Nov 2021 21:20:22 +0100 Subject: [PATCH 0091/1112] mtd: rawnand: gpmi: Add ERR007117 protection for nfc_apply_timings gpmi_io clock needs to be gated off when changing the parent/dividers of enfc_clk_root (i.MX6Q/i.MX6UL) respectively qspi2_clk_root (i.MX6SX). Otherwise this rate change can lead to an unresponsive GPMI core which results in DMA timeouts and failed driver probe: [ 4.072318] gpmi-nand 112000.gpmi-nand: DMA timeout, last DMA ... [ 4.370355] gpmi-nand 112000.gpmi-nand: Chip: 0, Error -110 ... [ 4.375988] gpmi-nand 112000.gpmi-nand: Chip: 0, Error -22 [ 4.381524] gpmi-nand 112000.gpmi-nand: Error in ECC-based read: -22 [ 4.387988] gpmi-nand 112000.gpmi-nand: Chip: 0, Error -22 [ 4.393535] gpmi-nand 112000.gpmi-nand: Chip: 0, Error -22 ... Other than stated in i.MX 6 erratum ERR007117, it should be sufficient to gate only gpmi_io because all other bch/nand clocks are derived from different clock roots. The i.MX6 reference manuals state that changing clock muxers can cause glitches but are silent about changing dividers. But tests showed that these glitches can definitely happen on i.MX6ULL. For i.MX7D/8MM in turn, the manual guarantees that no glitches can happen when changing dividers. Co-developed-by: Stefan Riedmueller Signed-off-by: Stefan Riedmueller Signed-off-by: Christian Eggers Cc: stable@vger.kernel.org Acked-by: Han Xu Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20211102202022.15551-2-ceggers@arri.de --- drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | 28 +++++++++++++++++++--- 1 file changed, 25 insertions(+), 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 66239f129a4d2..65bcd1c548d2e 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -713,14 +713,32 @@ static void gpmi_nfc_compute_timings(struct gpmi_nand_data *this, (use_half_period ? BM_GPMI_CTRL1_HALF_PERIOD : 0); } -static void gpmi_nfc_apply_timings(struct gpmi_nand_data *this) +static int gpmi_nfc_apply_timings(struct gpmi_nand_data *this) { struct gpmi_nfc_hardware_timing *hw = &this->hw; struct resources *r = &this->resources; void __iomem *gpmi_regs = r->gpmi_regs; unsigned int dll_wait_time_us; + int ret; + + /* Clock dividers do NOT guarantee a clean clock signal on its output + * during the change of the divide factor on i.MX6Q/UL/SX. On i.MX7/8, + * all clock dividers provide these guarantee. + */ + if (GPMI_IS_MX6Q(this) || GPMI_IS_MX6SX(this)) + clk_disable_unprepare(r->clock[0]); + + ret = clk_set_rate(r->clock[0], hw->clk_rate); + if (ret) { + dev_err(this->dev, "cannot set clock rate to %lu Hz: %d\n", hw->clk_rate, ret); + return ret; + } - clk_set_rate(r->clock[0], hw->clk_rate); + if (GPMI_IS_MX6Q(this) || GPMI_IS_MX6SX(this)) { + ret = clk_prepare_enable(r->clock[0]); + if (ret) + return ret; + } writel(hw->timing0, gpmi_regs + HW_GPMI_TIMING0); writel(hw->timing1, gpmi_regs + HW_GPMI_TIMING1); @@ -739,6 +757,8 @@ static void gpmi_nfc_apply_timings(struct gpmi_nand_data *this) /* Wait for the DLL to settle. */ udelay(dll_wait_time_us); + + return 0; } static int gpmi_setup_interface(struct nand_chip *chip, int chipnr, @@ -2269,7 +2289,9 @@ static int gpmi_nfc_exec_op(struct nand_chip *chip, */ if (this->hw.must_apply_timings) { this->hw.must_apply_timings = false; - gpmi_nfc_apply_timings(this); + ret = gpmi_nfc_apply_timings(this); + if (ret) + return ret; } dev_dbg(this->dev, "%s: %d instructions\n", __func__, op->ninstrs); -- GitLab From 6d48de655917a9d782953eba65de4e3db593ddf0 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Wed, 27 Oct 2021 16:30:01 +0300 Subject: [PATCH 0092/1112] crypto: atmel-aes - Reestablish the correct tfm context at dequeue In case there were more requests from different tfms in the crypto queue, only the context of the last initialized tfm was considered. Fixes: ec2088b66f7a ("crypto: atmel-aes - Allocate aes dev at tfm init time") Reported-by: Wolfgang Ocker Signed-off-by: Tudor Ambarus Signed-off-by: Herbert Xu --- drivers/crypto/atmel-aes.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c index 9391ccc03382d..fe05584031914 100644 --- a/drivers/crypto/atmel-aes.c +++ b/drivers/crypto/atmel-aes.c @@ -960,6 +960,7 @@ static int atmel_aes_handle_queue(struct atmel_aes_dev *dd, ctx = crypto_tfm_ctx(areq->tfm); dd->areq = areq; + dd->ctx = ctx; start_async = (areq != new_areq); dd->is_async = start_async; @@ -1274,7 +1275,6 @@ static int atmel_aes_init_tfm(struct crypto_skcipher *tfm) crypto_skcipher_set_reqsize(tfm, sizeof(struct atmel_aes_reqctx)); ctx->base.dd = dd; - ctx->base.dd->ctx = &ctx->base; ctx->base.start = atmel_aes_start; return 0; @@ -1291,7 +1291,6 @@ static int atmel_aes_ctr_init_tfm(struct crypto_skcipher *tfm) crypto_skcipher_set_reqsize(tfm, sizeof(struct atmel_aes_reqctx)); ctx->base.dd = dd; - ctx->base.dd->ctx = &ctx->base; ctx->base.start = atmel_aes_ctr_start; return 0; @@ -1783,7 +1782,6 @@ static int atmel_aes_gcm_init(struct crypto_aead *tfm) crypto_aead_set_reqsize(tfm, sizeof(struct atmel_aes_reqctx)); ctx->base.dd = dd; - ctx->base.dd->ctx = &ctx->base; ctx->base.start = atmel_aes_gcm_start; return 0; @@ -1927,7 +1925,6 @@ static int atmel_aes_xts_init_tfm(struct crypto_skcipher *tfm) crypto_skcipher_set_reqsize(tfm, sizeof(struct atmel_aes_reqctx) + crypto_skcipher_reqsize(ctx->fallback_tfm)); ctx->base.dd = dd; - ctx->base.dd->ctx = &ctx->base; ctx->base.start = atmel_aes_xts_start; return 0; @@ -2154,7 +2151,6 @@ static int atmel_aes_authenc_init_tfm(struct crypto_aead *tfm, crypto_aead_set_reqsize(tfm, (sizeof(struct atmel_aes_authenc_reqctx) + auth_reqsize)); ctx->base.dd = dd; - ctx->base.dd->ctx = &ctx->base; ctx->base.start = atmel_aes_authenc_start; return 0; -- GitLab From 680efb33546be8960ccbb2f4e0e43034d9c93b30 Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Fri, 29 Oct 2021 22:49:59 +0530 Subject: [PATCH 0093/1112] hwrng: cavium - Check health status while reading random data This RNG device is present on Marvell OcteonTx2 silicons as well and also provides entropy health status. HW continuously checks health condition of entropy and reports faults. Fault is in terms of co-processor cycles since last fault detected. This doesn't get cleared and only updated when new fault is detected. Also there are chances of detecting false positives. So to detect a entropy failure SW has to check if failures are persistent ie cycles elapsed is frequently updated by HW. This patch adds support to detect health failures using below algo. 1. Consider any fault detected before 10ms as a false positive and ignore. 10ms is chosen randomly, no significance. 2. Upon first failure detection make a note of cycles elapsed and when this error happened in realtime (cntvct). 3. Upon subsequent failure, check if this is new or a old one by comparing current cycles with the ones since last failure. cycles or time since last failure is calculated using cycles and time info captured at (2). HEALTH_CHECK status register is not available to VF, hence had to map PF registers. Also since cycles are in terms of co-processor cycles, had to retrieve co-processor clock rate from RST device. Signed-off-by: Sunil Goutham Signed-off-by: Herbert Xu --- drivers/char/hw_random/Kconfig | 2 +- drivers/char/hw_random/cavium-rng-vf.c | 194 +++++++++++++++++++++++-- drivers/char/hw_random/cavium-rng.c | 11 +- 3 files changed, 190 insertions(+), 17 deletions(-) diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 814b3d0ca7b77..1da64771ee2e4 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -414,7 +414,7 @@ config HW_RANDOM_MESON config HW_RANDOM_CAVIUM tristate "Cavium ThunderX Random Number Generator support" - depends on HW_RANDOM && PCI && (ARM64 || (COMPILE_TEST && 64BIT)) + depends on HW_RANDOM && PCI && ARM64 default HW_RANDOM help This driver provides kernel-side support for the Random Number diff --git a/drivers/char/hw_random/cavium-rng-vf.c b/drivers/char/hw_random/cavium-rng-vf.c index 3de4a6a443ef9..6f66919652bf5 100644 --- a/drivers/char/hw_random/cavium-rng-vf.c +++ b/drivers/char/hw_random/cavium-rng-vf.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Hardware Random Number Generator support for Cavium, Inc. - * Thunder processor family. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. + * Hardware Random Number Generator support. + * Cavium Thunder, Marvell OcteonTx/Tx2 processor families. * * Copyright (C) 2016 Cavium, Inc. */ @@ -15,16 +12,146 @@ #include #include +#include + +/* PCI device IDs */ +#define PCI_DEVID_CAVIUM_RNG_PF 0xA018 +#define PCI_DEVID_CAVIUM_RNG_VF 0xA033 + +#define HEALTH_STATUS_REG 0x38 + +/* RST device info */ +#define PCI_DEVICE_ID_RST_OTX2 0xA085 +#define RST_BOOT_REG 0x1600ULL +#define CLOCK_BASE_RATE 50000000ULL +#define MSEC_TO_NSEC(x) (x * 1000000) + struct cavium_rng { struct hwrng ops; void __iomem *result; + void __iomem *pf_regbase; + struct pci_dev *pdev; + u64 clock_rate; + u64 prev_error; + u64 prev_time; }; +static inline bool is_octeontx(struct pci_dev *pdev) +{ + if (midr_is_cpu_model_range(read_cpuid_id(), MIDR_THUNDERX_83XX, + MIDR_CPU_VAR_REV(0, 0), + MIDR_CPU_VAR_REV(3, 0)) || + midr_is_cpu_model_range(read_cpuid_id(), MIDR_THUNDERX_81XX, + MIDR_CPU_VAR_REV(0, 0), + MIDR_CPU_VAR_REV(3, 0)) || + midr_is_cpu_model_range(read_cpuid_id(), MIDR_THUNDERX, + MIDR_CPU_VAR_REV(0, 0), + MIDR_CPU_VAR_REV(3, 0))) + return true; + + return false; +} + +static u64 rng_get_coprocessor_clkrate(void) +{ + u64 ret = CLOCK_BASE_RATE * 16; /* Assume 800Mhz as default */ + struct pci_dev *pdev; + void __iomem *base; + + pdev = pci_get_device(PCI_VENDOR_ID_CAVIUM, + PCI_DEVICE_ID_RST_OTX2, NULL); + if (!pdev) + goto error; + + base = pci_ioremap_bar(pdev, 0); + if (!base) + goto error_put_pdev; + + /* RST: PNR_MUL * 50Mhz gives clockrate */ + ret = CLOCK_BASE_RATE * ((readq(base + RST_BOOT_REG) >> 33) & 0x3F); + + iounmap(base); + +error_put_pdev: + pci_dev_put(pdev); + +error: + return ret; +} + +static int check_rng_health(struct cavium_rng *rng) +{ + u64 cur_err, cur_time; + u64 status, cycles; + u64 time_elapsed; + + + /* Skip checking health for OcteonTx */ + if (!rng->pf_regbase) + return 0; + + status = readq(rng->pf_regbase + HEALTH_STATUS_REG); + if (status & BIT_ULL(0)) { + dev_err(&rng->pdev->dev, "HWRNG: Startup health test failed\n"); + return -EIO; + } + + cycles = status >> 1; + if (!cycles) + return 0; + + cur_time = arch_timer_read_counter(); + + /* RNM_HEALTH_STATUS[CYCLES_SINCE_HEALTH_FAILURE] + * Number of coprocessor cycles times 2 since the last failure. + * This field doesn't get cleared/updated until another failure. + */ + cycles = cycles / 2; + cur_err = (cycles * 1000000000) / rng->clock_rate; /* In nanosec */ + + /* Ignore errors that happenned a long time ago, these + * are most likely false positive errors. + */ + if (cur_err > MSEC_TO_NSEC(10)) { + rng->prev_error = 0; + rng->prev_time = 0; + return 0; + } + + if (rng->prev_error) { + /* Calculate time elapsed since last error + * '1' tick of CNTVCT is 10ns, since it runs at 100Mhz. + */ + time_elapsed = (cur_time - rng->prev_time) * 10; + time_elapsed += rng->prev_error; + + /* Check if current error is a new one or the old one itself. + * If error is a new one then consider there is a persistent + * issue with entropy, declare hardware failure. + */ + if (cur_err < time_elapsed) { + dev_err(&rng->pdev->dev, "HWRNG failure detected\n"); + rng->prev_error = cur_err; + rng->prev_time = cur_time; + return -EIO; + } + } + + rng->prev_error = cur_err; + rng->prev_time = cur_time; + return 0; +} + /* Read data from the RNG unit */ static int cavium_rng_read(struct hwrng *rng, void *dat, size_t max, bool wait) { struct cavium_rng *p = container_of(rng, struct cavium_rng, ops); unsigned int size = max; + int err = 0; + + err = check_rng_health(p); + if (err) + return err; while (size >= 8) { *((u64 *)dat) = readq(p->result); @@ -39,6 +166,39 @@ static int cavium_rng_read(struct hwrng *rng, void *dat, size_t max, bool wait) return max; } +static int cavium_map_pf_regs(struct cavium_rng *rng) +{ + struct pci_dev *pdev; + + /* Health status is not supported on 83xx, skip mapping PF CSRs */ + if (is_octeontx(rng->pdev)) { + rng->pf_regbase = NULL; + return 0; + } + + pdev = pci_get_device(PCI_VENDOR_ID_CAVIUM, + PCI_DEVID_CAVIUM_RNG_PF, NULL); + if (!pdev) { + dev_err(&pdev->dev, "Cannot find RNG PF device\n"); + return -EIO; + } + + rng->pf_regbase = ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (!rng->pf_regbase) { + dev_err(&pdev->dev, "Failed to map PF CSR region\n"); + pci_dev_put(pdev); + return -ENOMEM; + } + + pci_dev_put(pdev); + + /* Get co-processor clock rate */ + rng->clock_rate = rng_get_coprocessor_clkrate(); + + return 0; +} + /* Map Cavium RNG to an HWRNG object */ static int cavium_rng_probe_vf(struct pci_dev *pdev, const struct pci_device_id *id) @@ -50,6 +210,8 @@ static int cavium_rng_probe_vf(struct pci_dev *pdev, if (!rng) return -ENOMEM; + rng->pdev = pdev; + /* Map the RNG result */ rng->result = pcim_iomap(pdev, 0, 0); if (!rng->result) { @@ -67,6 +229,11 @@ static int cavium_rng_probe_vf(struct pci_dev *pdev, pci_set_drvdata(pdev, rng); + /* Health status is available only at PF, hence map PF registers. */ + ret = cavium_map_pf_regs(rng); + if (ret) + return ret; + ret = devm_hwrng_register(&pdev->dev, &rng->ops); if (ret) { dev_err(&pdev->dev, "Error registering device as HWRNG.\n"); @@ -76,10 +243,18 @@ static int cavium_rng_probe_vf(struct pci_dev *pdev, return 0; } +/* Remove the VF */ +static void cavium_rng_remove_vf(struct pci_dev *pdev) +{ + struct cavium_rng *rng; + + rng = pci_get_drvdata(pdev); + iounmap(rng->pf_regbase); +} static const struct pci_device_id cavium_rng_vf_id_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xa033), 0, 0, 0}, - {0,}, + { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CAVIUM_RNG_VF) }, + { 0, } }; MODULE_DEVICE_TABLE(pci, cavium_rng_vf_id_table); @@ -87,8 +262,9 @@ static struct pci_driver cavium_rng_vf_driver = { .name = "cavium_rng_vf", .id_table = cavium_rng_vf_id_table, .probe = cavium_rng_probe_vf, + .remove = cavium_rng_remove_vf, }; module_pci_driver(cavium_rng_vf_driver); MODULE_AUTHOR("Omer Khaliq "); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/char/hw_random/cavium-rng.c b/drivers/char/hw_random/cavium-rng.c index 63d6e68c24d2f..b96579222408b 100644 --- a/drivers/char/hw_random/cavium-rng.c +++ b/drivers/char/hw_random/cavium-rng.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Hardware Random Number Generator support for Cavium Inc. - * Thunder processor family. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. + * Hardware Random Number Generator support. + * Cavium Thunder, Marvell OcteonTx/Tx2 processor families. * * Copyright (C) 2016 Cavium, Inc. */ @@ -91,4 +88,4 @@ static struct pci_driver cavium_rng_pf_driver = { module_pci_driver(cavium_rng_pf_driver); MODULE_AUTHOR("Omer Khaliq "); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); -- GitLab From efd21e10fc3bf4c6da122470a5ae89ec4ed8d180 Mon Sep 17 00:00:00 2001 From: Meng Li Date: Mon, 1 Nov 2021 11:13:53 +0800 Subject: [PATCH 0094/1112] crypto: caam - replace this_cpu_ptr with raw_cpu_ptr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When enable the kernel debug config, there is below calltrace detected: BUG: using smp_processor_id() in preemptible [00000000] code: cryptomgr_test/339 caller is debug_smp_processor_id+0x20/0x30 CPU: 9 PID: 339 Comm: cryptomgr_test Not tainted 5.10.63-yocto-standard #1 Hardware name: NXP Layerscape LX2160ARDB (DT) Call trace: dump_backtrace+0x0/0x1a0 show_stack+0x24/0x30 dump_stack+0xf0/0x13c check_preemption_disabled+0x100/0x110 debug_smp_processor_id+0x20/0x30 dpaa2_caam_enqueue+0x10c/0x25c ...... cryptomgr_test+0x38/0x60 kthread+0x158/0x164 ret_from_fork+0x10/0x38 According to the comment in commit ac5d15b4519f("crypto: caam/qi2 - use affine DPIOs "), because preemption is no longer disabled while trying to enqueue an FQID, it might be possible to run the enqueue on a different CPU(due to migration, when in process context), however this wouldn't be a functionality issue. But there will be above calltrace when enable kernel debug config. So, replace this_cpu_ptr with raw_cpu_ptr to avoid above call trace. Fixes: ac5d15b4519f ("crypto: caam/qi2 - use affine DPIOs") Cc: stable@vger.kernel.org Signed-off-by: Meng Li Reviewed-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg_qi2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c index 8b8ed77d8715d..6753f0e6e55d1 100644 --- a/drivers/crypto/caam/caamalg_qi2.c +++ b/drivers/crypto/caam/caamalg_qi2.c @@ -5470,7 +5470,7 @@ int dpaa2_caam_enqueue(struct device *dev, struct caam_request *req) dpaa2_fd_set_len(&fd, dpaa2_fl_get_len(&req->fd_flt[1])); dpaa2_fd_set_flc(&fd, req->flc_dma); - ppriv = this_cpu_ptr(priv->ppriv); + ppriv = raw_cpu_ptr(priv->ppriv); for (i = 0; i < (priv->dpseci_attr.num_tx_queues << 1); i++) { err = dpaa2_io_service_enqueue_fq(ppriv->dpio, ppriv->req_fqid, &fd); -- GitLab From 94ad2d19a97efdb603a21fcad0625f466f1cdd0f Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 1 Nov 2021 14:02:33 +0000 Subject: [PATCH 0095/1112] crypto: keembay-ocs-ecc - Fix error return code in kmb_ocs_ecc_probe() Fix to return negative error code -ENOMEM from the error handling case instead of 0, as done elsewhere in this function. Fixes: c9f608c38009 ("crypto: keembay-ocs-ecc - Add Keem Bay OCS ECC Driver") Reported-by: Hulk Robot Signed-off-by: Wei Yongjun Reviewed-by: Daniele Alessandrelli Signed-off-by: Herbert Xu --- drivers/crypto/keembay/keembay-ocs-ecc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/crypto/keembay/keembay-ocs-ecc.c b/drivers/crypto/keembay/keembay-ocs-ecc.c index 679e6ae295e0b..5d0785d3f1b55 100644 --- a/drivers/crypto/keembay/keembay-ocs-ecc.c +++ b/drivers/crypto/keembay/keembay-ocs-ecc.c @@ -930,6 +930,7 @@ static int kmb_ocs_ecc_probe(struct platform_device *pdev) ecc_dev->engine = crypto_engine_alloc_init(dev, 1); if (!ecc_dev->engine) { dev_err(dev, "Could not allocate crypto engine\n"); + rc = -ENOMEM; goto list_del; } -- GitLab From 7875506f7a755cdafe231ca310c8fbca793d262f Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Wed, 3 Nov 2021 10:47:11 +0100 Subject: [PATCH 0096/1112] MAINTAINERS: rectify entry for INTEL KEEM BAY OCS ECC CRYPTO DRIVER Commit c9f608c38009 ("crypto: keembay-ocs-ecc - Add Keem Bay OCS ECC Driver") only adds drivers/crypto/keembay/keembay-ocs-ecc.c, but adds a file entry drivers/crypto/keembay/ocs-ecc-curve-defs.h in MAINTAINERS. Hence, ./scripts/get_maintainer.pl --self-test=patterns warns: warning: no file matches F: drivers/crypto/keembay/ocs-ecc-curve-defs.h Assuming that this header is obsolete and will not be included in the repository, remove the unneeded file entry from MAINTAINERS. Signed-off-by: Lukas Bulwahn Reviewed-by: Daniele Alessandrelli Signed-off-by: Herbert Xu --- MAINTAINERS | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 7a2345ce85213..00475646e3e33 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9673,7 +9673,6 @@ F: Documentation/devicetree/bindings/crypto/intel,keembay-ocs-ecc.yaml F: drivers/crypto/keembay/Kconfig F: drivers/crypto/keembay/Makefile F: drivers/crypto/keembay/keembay-ocs-ecc.c -F: drivers/crypto/keembay/ocs-ecc-curve-defs.h INTEL KEEM BAY OCS HCU CRYPTO DRIVER M: Daniele Alessandrelli -- GitLab From 574c833ef3a60dc5dff6c9e885a30ba13e88971e Mon Sep 17 00:00:00 2001 From: Yang Guang Date: Thu, 4 Nov 2021 14:19:10 +0800 Subject: [PATCH 0097/1112] crypto: hisilicon/hpre - use swap() to make code cleaner Use the macro 'swap()' defined in 'include/linux/minmax.h' to avoid opencoding it. Reported-by: Zeal Robot Signed-off-by: Yang Guang Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/hpre/hpre_crypto.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/crypto/hisilicon/hpre/hpre_crypto.c b/drivers/crypto/hisilicon/hpre/hpre_crypto.c index a032c192ef1d6..0f1724d355b81 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_crypto.c +++ b/drivers/crypto/hisilicon/hpre/hpre_crypto.c @@ -1177,13 +1177,10 @@ static void hpre_rsa_exit_tfm(struct crypto_akcipher *tfm) static void hpre_key_to_big_end(u8 *data, int len) { int i, j; - u8 tmp; for (i = 0; i < len / 2; i++) { j = len - i - 1; - tmp = data[j]; - data[j] = data[i]; - data[i] = tmp; + swap(data[j], data[i]); } } -- GitLab From 4a9dbd021970ffe1b92521328377b699acba7c52 Mon Sep 17 00:00:00 2001 From: Chengfeng Ye Date: Thu, 4 Nov 2021 06:28:07 -0700 Subject: [PATCH 0098/1112] crypto: qce - fix uaf on qce_aead_register_one Pointer alg points to sub field of tmpl, it is dereferenced after tmpl is freed. Fix this by accessing alg before free tmpl. Fixes: 9363efb4 ("crypto: qce - Add support for AEAD algorithms") Signed-off-by: Chengfeng Ye Acked-by: Thara Gopinath Signed-off-by: Herbert Xu --- drivers/crypto/qce/aead.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/qce/aead.c b/drivers/crypto/qce/aead.c index 290e2446a2f35..97a530171f07a 100644 --- a/drivers/crypto/qce/aead.c +++ b/drivers/crypto/qce/aead.c @@ -802,8 +802,8 @@ static int qce_aead_register_one(const struct qce_aead_def *def, struct qce_devi ret = crypto_register_aead(alg); if (ret) { - kfree(tmpl); dev_err(qce->dev, "%s registration failed\n", alg->base.cra_name); + kfree(tmpl); return ret; } -- GitLab From b4cb4d31631912842eb7dce02b4350cbb7562d5e Mon Sep 17 00:00:00 2001 From: Chengfeng Ye Date: Thu, 4 Nov 2021 06:38:31 -0700 Subject: [PATCH 0099/1112] crypto: qce - fix uaf on qce_ahash_register_one Pointer base points to sub field of tmpl, it is dereferenced after tmpl is freed. Fix this by accessing base before free tmpl. Fixes: ec8f5d8f ("crypto: qce - Qualcomm crypto engine driver") Signed-off-by: Chengfeng Ye Acked-by: Thara Gopinath Signed-off-by: Herbert Xu --- drivers/crypto/qce/sha.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/qce/sha.c b/drivers/crypto/qce/sha.c index 8e6fcf2c21cc0..59159f5e64e52 100644 --- a/drivers/crypto/qce/sha.c +++ b/drivers/crypto/qce/sha.c @@ -498,8 +498,8 @@ static int qce_ahash_register_one(const struct qce_ahash_def *def, ret = crypto_register_ahash(alg); if (ret) { - kfree(tmpl); dev_err(qce->dev, "%s registration failed\n", base->cra_name); + kfree(tmpl); return ret; } -- GitLab From e9c195aaeed1b45c9012adbe29dedb6031e85aa8 Mon Sep 17 00:00:00 2001 From: Chengfeng Ye Date: Thu, 4 Nov 2021 06:46:42 -0700 Subject: [PATCH 0100/1112] crypto: qce - fix uaf on qce_skcipher_register_one Pointer alg points to sub field of tmpl, it is dereferenced after tmpl is freed. Fix this by accessing alg before free tmpl. Fixes: ec8f5d8f ("crypto: qce - Qualcomm crypto engine driver") Signed-off-by: Chengfeng Ye Acked-by: Thara Gopinath Signed-off-by: Herbert Xu --- drivers/crypto/qce/skcipher.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/qce/skcipher.c b/drivers/crypto/qce/skcipher.c index 8ff10928f581d..3d27cd5210ef5 100644 --- a/drivers/crypto/qce/skcipher.c +++ b/drivers/crypto/qce/skcipher.c @@ -484,8 +484,8 @@ static int qce_skcipher_register_one(const struct qce_skcipher_def *def, ret = crypto_register_skcipher(alg); if (ret) { - kfree(tmpl); dev_err(qce->dev, "%s registration failed\n", alg->base.cra_name); + kfree(tmpl); return ret; } -- GitLab From a9887010ed2da3fddaff83ceec80e2b71be8a966 Mon Sep 17 00:00:00 2001 From: Lei He Date: Fri, 5 Nov 2021 20:25:31 +0800 Subject: [PATCH 0101/1112] crypto: testmgr - Fix wrong test case of RSA According to the BER encoding rules, integer value should be encoded as two's complement, and if the highest bit of a positive integer is 1, should add a leading zero-octet. The kernel's built-in RSA algorithm cannot recognize negative numbers when parsing keys, so it can pass this test case. Export the key to file and run the following command to verify the fix result: openssl asn1parse -inform DER -in /path/to/key/file Signed-off-by: Lei He Signed-off-by: Herbert Xu --- crypto/testmgr.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crypto/testmgr.h b/crypto/testmgr.h index 779720bf9364b..a253d66ba1c1a 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -257,9 +257,9 @@ static const struct akcipher_testvec rsa_tv_template[] = { }, { #endif .key = - "\x30\x82\x02\x1F" /* sequence of 543 bytes */ + "\x30\x82\x02\x20" /* sequence of 544 bytes */ "\x02\x01\x01" /* version - integer of 1 byte */ - "\x02\x82\x01\x00" /* modulus - integer of 256 bytes */ + "\x02\x82\x01\x01\x00" /* modulus - integer of 256 bytes */ "\xDB\x10\x1A\xC2\xA3\xF1\xDC\xFF\x13\x6B\xED\x44\xDF\xF0\x02\x6D" "\x13\xC7\x88\xDA\x70\x6B\x54\xF1\xE8\x27\xDC\xC3\x0F\x99\x6A\xFA" "\xC6\x67\xFF\x1D\x1E\x3C\x1D\xC1\xB5\x5F\x6C\xC0\xB2\x07\x3A\x6D" @@ -299,7 +299,7 @@ static const struct akcipher_testvec rsa_tv_template[] = { "\x02\x01\x00" /* exponent1 - integer of 1 byte */ "\x02\x01\x00" /* exponent2 - integer of 1 byte */ "\x02\x01\x00", /* coefficient - integer of 1 byte */ - .key_len = 547, + .key_len = 548, .m = "\x54\x85\x9b\x34\x2c\x49\xea\x2a", .c = "\xb2\x97\x76\xb4\xae\x3e\x38\x3c\x7e\x64\x1f\xcc\xa2\x7f\xf6\xbe" -- GitLab From 3121d5d1181885d9e01436fbdac78646617fb42f Mon Sep 17 00:00:00 2001 From: chiminghao Date: Tue, 9 Nov 2021 08:35:03 +0000 Subject: [PATCH 0102/1112] crypto: octeontx2 - use swap() to make code cleaner Fix the following coccicheck REVIEW: ./drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c:1688:16-17 use swap() to make code cleaner Reported-by: Zeal Robot Signed-off-by: chiminghao Signed-off-by: Herbert Xu --- drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c b/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c index 877a948469bd1..2748a3327e391 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c @@ -1682,11 +1682,8 @@ static void swap_func(void *lptr, void *rptr, int size) { struct cpt_device_desc *ldesc = lptr; struct cpt_device_desc *rdesc = rptr; - struct cpt_device_desc desc; - desc = *ldesc; - *ldesc = *rdesc; - *rdesc = desc; + swap(*ldesc, *rdesc); } int otx2_cpt_crypto_init(struct pci_dev *pdev, struct module *mod, -- GitLab From 882ed23e103f2cc8222eb3d280ddf1af167fa9ea Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Fri, 12 Nov 2021 17:49:23 +0100 Subject: [PATCH 0103/1112] crypto: ccree - remove redundant 'flush_workqueue()' calls 'destroy_workqueue()' already drains the queue before destroying it, so there is no need to flush it explicitly. Remove the redundant 'flush_workqueue()' calls. This was generated with coccinelle: @@ expression E; @@ - flush_workqueue(E); destroy_workqueue(E); Signed-off-by: Christophe JAILLET Reviewed-by: Cristian Marussi Acked-by: Gilad Ben-Yossef Signed-off-by: Herbert Xu --- drivers/crypto/ccree/cc_request_mgr.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/crypto/ccree/cc_request_mgr.c b/drivers/crypto/ccree/cc_request_mgr.c index 33fb27745d522..887162df50f96 100644 --- a/drivers/crypto/ccree/cc_request_mgr.c +++ b/drivers/crypto/ccree/cc_request_mgr.c @@ -101,7 +101,6 @@ void cc_req_mgr_fini(struct cc_drvdata *drvdata) dev_dbg(dev, "max_used_sw_slots=%d\n", req_mgr_h->max_used_sw_slots); #ifdef COMP_IN_WQ - flush_workqueue(req_mgr_h->workq); destroy_workqueue(req_mgr_h->workq); #else /* Kill tasklet */ -- GitLab From 370a40ee228340b5141e5d89dee3186452d9f5fb Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Sat, 13 Nov 2021 14:30:23 +0800 Subject: [PATCH 0104/1112] crypto: ccp - no need to initialise statics to 0 Static variables do not need to be initialized to 0. Signed-off-by: Jason Wang Signed-off-by: Herbert Xu --- drivers/crypto/ccp/ccp-dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/ccp/ccp-dev.c b/drivers/crypto/ccp/ccp-dev.c index 9ce4b68e9c483..c531d13d971f3 100644 --- a/drivers/crypto/ccp/ccp-dev.c +++ b/drivers/crypto/ccp/ccp-dev.c @@ -31,7 +31,7 @@ #define MAX_CCPS 32 /* Limit CCP use to a specifed number of queues per device */ -static unsigned int nqueues = 0; +static unsigned int nqueues; module_param(nqueues, uint, 0444); MODULE_PARM_DESC(nqueues, "Number of queues per CCP (minimum 1; default: all available)"); -- GitLab From baaf965f94308301d2dc554d72a87d7432cd5ce6 Mon Sep 17 00:00:00 2001 From: "George G. Davis" Date: Fri, 16 Jul 2021 16:49:35 -0400 Subject: [PATCH 0105/1112] mtd: hyperbus: rpc-if: fix bug in rpcif_hb_remove The following KASAN BUG is observed when testing the rpc-if driver on rcar-gen3: root@rcar-gen3:~# modprobe -r rpc-if [ 101.930146] ================================================================== [ 101.937408] BUG: KASAN: slab-out-of-bounds in __lock_acquire+0x518/0x25d0 [ 101.944240] Read of size 8 at addr ffff0004c5be2750 by task modprobe/664 [ 101.950959] [ 101.952466] CPU: 2 PID: 664 Comm: modprobe Not tainted 5.14.0-rc1-00342-g1a1464d7aa31 #1 [ 101.960578] Hardware name: Renesas H3ULCB board based on r8a77951 (DT) [ 101.967120] Call trace: [ 101.969580] dump_backtrace+0x0/0x2c0 [ 101.973275] show_stack+0x1c/0x30 [ 101.976616] dump_stack_lvl+0x9c/0xd8 [ 101.980301] print_address_description.constprop.0+0x74/0x2b8 [ 101.986071] kasan_report+0x1f4/0x26c [ 101.989757] __asan_load8+0x98/0xd4 [ 101.993266] __lock_acquire+0x518/0x25d0 [ 101.997215] lock_acquire.part.0+0x18c/0x360 [ 102.001506] lock_acquire+0x74/0x90 [ 102.005013] _raw_spin_lock_irq+0x98/0x130 [ 102.009131] __pm_runtime_disable+0x30/0x210 [ 102.013427] rpcif_hb_remove+0x5c/0x70 [rpc_if] [ 102.018001] platform_remove+0x40/0x80 [ 102.021771] __device_release_driver+0x234/0x350 [ 102.026412] driver_detach+0x158/0x20c [ 102.030179] bus_remove_driver+0xa0/0x140 [ 102.034212] driver_unregister+0x48/0x80 [ 102.038153] platform_driver_unregister+0x18/0x24 [ 102.042879] rpcif_platform_driver_exit+0x1c/0x34 [rpc_if] [ 102.048400] __arm64_sys_delete_module+0x210/0x310 [ 102.053212] invoke_syscall+0x60/0x190 [ 102.056986] el0_svc_common+0x12c/0x144 [ 102.060844] do_el0_svc+0x88/0xac [ 102.064181] el0_svc+0x24/0x3c [ 102.067257] el0t_64_sync_handler+0x1a8/0x1b0 [ 102.071634] el0t_64_sync+0x198/0x19c [ 102.075315] [ 102.076815] Allocated by task 628: [ 102.080781] [ 102.082280] Last potentially related work creation: [ 102.087524] [ 102.089022] The buggy address belongs to the object at ffff0004c5be2000 [ 102.089022] which belongs to the cache kmalloc-2k of size 2048 [ 102.101555] The buggy address is located 1872 bytes inside of [ 102.101555] 2048-byte region [ffff0004c5be2000, ffff0004c5be2800) [ 102.113486] The buggy address belongs to the page: [ 102.118409] [ 102.119908] Memory state around the buggy address: [ 102.124711] ffff0004c5be2600: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 102.131947] ffff0004c5be2680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 102.139181] >ffff0004c5be2700: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 102.146412] ^ [ 102.152257] ffff0004c5be2780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 102.159491] ffff0004c5be2800: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 102.166723] ================================================================== The above bug is caused by use of the wrong pointer in the rpcif_disable_rpm() call. Fix the bug by using the correct pointer. Fixes: 5de15b610f78 ("mtd: hyperbus: add Renesas RPC-IF driver") Signed-off-by: George G. Davis Signed-off-by: Vignesh Raghavendra Link: https://lore.kernel.org/r/20210716204935.25859-1-george_davis@mentor.com --- drivers/mtd/hyperbus/rpc-if.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/hyperbus/rpc-if.c b/drivers/mtd/hyperbus/rpc-if.c index 367b0d72bf622..dc164c18f8429 100644 --- a/drivers/mtd/hyperbus/rpc-if.c +++ b/drivers/mtd/hyperbus/rpc-if.c @@ -152,9 +152,9 @@ static int rpcif_hb_remove(struct platform_device *pdev) { struct rpcif_hyperbus *hyperbus = platform_get_drvdata(pdev); int error = hyperbus_unregister_device(&hyperbus->hbdev); - struct rpcif *rpc = dev_get_drvdata(pdev->dev.parent); - rpcif_disable_rpm(rpc); + rpcif_disable_rpm(&hyperbus->rpc); + return error; } -- GitLab From f65b8132092699e4f672111836f3f51c00c354f2 Mon Sep 17 00:00:00 2001 From: Elyes HAOUAS Date: Thu, 28 Oct 2021 23:05:17 +0200 Subject: [PATCH 0106/1112] include/linux/efi.h: Remove unneeded whitespaces before tabs Signed-off-by: Elyes HAOUAS Signed-off-by: Ard Biesheuvel --- include/linux/efi.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/linux/efi.h b/include/linux/efi.h index dbd39b20e0345..de36fb5476025 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -570,8 +570,8 @@ extern struct efi { unsigned long flags; } efi; -#define EFI_RT_SUPPORTED_GET_TIME 0x0001 -#define EFI_RT_SUPPORTED_SET_TIME 0x0002 +#define EFI_RT_SUPPORTED_GET_TIME 0x0001 +#define EFI_RT_SUPPORTED_SET_TIME 0x0002 #define EFI_RT_SUPPORTED_GET_WAKEUP_TIME 0x0004 #define EFI_RT_SUPPORTED_SET_WAKEUP_TIME 0x0008 #define EFI_RT_SUPPORTED_GET_VARIABLE 0x0010 @@ -838,7 +838,7 @@ extern int efi_status_to_err(efi_status_t status); #define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x0000000000000020 #define EFI_VARIABLE_APPEND_WRITE 0x0000000000000040 -#define EFI_VARIABLE_MASK (EFI_VARIABLE_NON_VOLATILE | \ +#define EFI_VARIABLE_MASK (EFI_VARIABLE_NON_VOLATILE | \ EFI_VARIABLE_BOOTSERVICE_ACCESS | \ EFI_VARIABLE_RUNTIME_ACCESS | \ EFI_VARIABLE_HARDWARE_ERROR_RECORD | \ -- GitLab From 4da87c51705815fe1fbd41cc61640bb80da5bc54 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 19 Nov 2021 13:47:42 +0200 Subject: [PATCH 0107/1112] efi/libstub: add prototype of efi_tcg2_protocol::hash_log_extend_event() Define the right prototype for efi_tcg2_protocol::hash_log_extend_event() and add the required structs so we can start using it to measure the initrd into the TPM if it was loaded by the EFI stub itself. Signed-off-by: Ard Biesheuvel Signed-off-by: Ilias Apalodimas Link: https://lore.kernel.org/r/20211119114745.1560453-2-ilias.apalodimas@linaro.org Signed-off-by: Ard Biesheuvel --- arch/x86/include/asm/efi.h | 4 ++++ drivers/firmware/efi/libstub/efistub.h | 29 +++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 4d0b126835b8a..85f156f8ef810 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -308,6 +308,10 @@ static inline u32 efi64_convert_status(efi_status_t status) #define __efi64_argmap_query_mode(gop, mode, size, info) \ ((gop), (mode), efi64_zero_upper(size), efi64_zero_upper(info)) +/* TCG2 protocol */ +#define __efi64_argmap_hash_log_extend_event(prot, fl, addr, size, ev) \ + ((prot), (fl), 0ULL, (u64)(addr), 0ULL, (u64)(size), 0ULL, ev) + /* * The macros below handle the plumbing for the argument mapping. To add a * mapping for a specific EFI method, simply define a macro diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index cde0a2ef507d9..a2825c4351580 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -667,6 +667,29 @@ union apple_properties_protocol { typedef u32 efi_tcg2_event_log_format; +#define INITRD_EVENT_TAG_ID 0x8F3B22ECU +#define EV_EVENT_TAG 0x00000006U +#define EFI_TCG2_EVENT_HEADER_VERSION 0x1 + +struct efi_tcg2_event { + u32 event_size; + struct { + u32 header_size; + u16 header_version; + u32 pcr_index; + u32 event_type; + } __packed event_header; + /* u8[] event follows here */ +} __packed; + +struct efi_tcg2_tagged_event { + u32 tagged_event_id; + u32 tagged_event_data_size; + /* u8 tagged event data follows here */ +} __packed; + +typedef struct efi_tcg2_event efi_tcg2_event_t; +typedef struct efi_tcg2_tagged_event efi_tcg2_tagged_event_t; typedef union efi_tcg2_protocol efi_tcg2_protocol_t; union efi_tcg2_protocol { @@ -677,7 +700,11 @@ union efi_tcg2_protocol { efi_physical_addr_t *, efi_physical_addr_t *, efi_bool_t *); - void *hash_log_extend_event; + efi_status_t (__efiapi *hash_log_extend_event)(efi_tcg2_protocol_t *, + u64, + efi_physical_addr_t, + u64, + const efi_tcg2_event_t *); void *submit_command; void *get_active_pcr_banks; void *set_active_pcr_banks; -- GitLab From 44f155b4b07b8293472c9797d5b39839b91041ca Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 19 Nov 2021 13:47:43 +0200 Subject: [PATCH 0108/1112] efi/libstub: x86/mixed: increase supported argument count Increase the number of arguments supported by mixed mode calls, so that we will be able to call into the TCG2 protocol to measure the initrd and extend the associated PCR. This involves the TCG2 protocol's hash_log_extend_event() method, which takes five arguments, three of which are u64 and need to be split, producing a total of 8 outgoing Signed-off-by: Ard Biesheuvel Signed-off-by: Ilias Apalodimas Link: https://lore.kernel.org/r/20211119114745.1560453-3-ilias.apalodimas@linaro.org Signed-off-by: Ard Biesheuvel --- arch/x86/boot/compressed/efi_thunk_64.S | 14 +++++++++++--- arch/x86/include/asm/efi.h | 10 ++++++---- arch/x86/platform/efi/efi_thunk_64.S | 14 ++++++++++++-- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/arch/x86/boot/compressed/efi_thunk_64.S b/arch/x86/boot/compressed/efi_thunk_64.S index 8bb92e9f4e973..d05f781d54f26 100644 --- a/arch/x86/boot/compressed/efi_thunk_64.S +++ b/arch/x86/boot/compressed/efi_thunk_64.S @@ -26,8 +26,6 @@ SYM_FUNC_START(__efi64_thunk) push %rbp push %rbx - leaq 1f(%rip), %rbp - movl %ds, %eax push %rax movl %es, %eax @@ -35,6 +33,11 @@ SYM_FUNC_START(__efi64_thunk) movl %ss, %eax push %rax + /* Copy args passed on stack */ + movq 0x30(%rsp), %rbp + movq 0x38(%rsp), %rbx + movq 0x40(%rsp), %rax + /* * Convert x86-64 ABI params to i386 ABI */ @@ -44,13 +47,18 @@ SYM_FUNC_START(__efi64_thunk) movl %ecx, 0x8(%rsp) movl %r8d, 0xc(%rsp) movl %r9d, 0x10(%rsp) + movl %ebp, 0x14(%rsp) + movl %ebx, 0x18(%rsp) + movl %eax, 0x1c(%rsp) - leaq 0x14(%rsp), %rbx + leaq 0x20(%rsp), %rbx sgdt (%rbx) addq $16, %rbx sidt (%rbx) + leaq 1f(%rip), %rbp + /* * Switch to IDT and GDT with 32-bit segments. This is the firmware GDT * and IDT that was installed when the kernel started executing. The diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 85f156f8ef810..a323dbac91829 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -46,13 +46,14 @@ extern unsigned long efi_mixed_mode_stack_pa; #define __efi_nargs(...) __efi_nargs_(__VA_ARGS__) #define __efi_nargs_(...) __efi_nargs__(0, ##__VA_ARGS__, \ + __efi_arg_sentinel(9), __efi_arg_sentinel(8), \ __efi_arg_sentinel(7), __efi_arg_sentinel(6), \ __efi_arg_sentinel(5), __efi_arg_sentinel(4), \ __efi_arg_sentinel(3), __efi_arg_sentinel(2), \ __efi_arg_sentinel(1), __efi_arg_sentinel(0)) -#define __efi_nargs__(_0, _1, _2, _3, _4, _5, _6, _7, n, ...) \ +#define __efi_nargs__(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, n, ...) \ __take_second_arg(n, \ - ({ BUILD_BUG_ON_MSG(1, "__efi_nargs limit exceeded"); 8; })) + ({ BUILD_BUG_ON_MSG(1, "__efi_nargs limit exceeded"); 10; })) #define __efi_arg_sentinel(n) , n /* @@ -176,8 +177,9 @@ extern u64 efi_setup; extern efi_status_t __efi64_thunk(u32, ...); #define efi64_thunk(...) ({ \ - __efi_nargs_check(efi64_thunk, 6, __VA_ARGS__); \ - __efi64_thunk(__VA_ARGS__); \ + u64 __pad[3]; /* must have space for 3 args on the stack */ \ + __efi_nargs_check(efi64_thunk, 9, __VA_ARGS__); \ + __efi64_thunk(__VA_ARGS__, __pad); \ }) static inline bool efi_is_mixed(void) diff --git a/arch/x86/platform/efi/efi_thunk_64.S b/arch/x86/platform/efi/efi_thunk_64.S index fd3dd1708eba5..5b7c6e09954ec 100644 --- a/arch/x86/platform/efi/efi_thunk_64.S +++ b/arch/x86/platform/efi/efi_thunk_64.S @@ -36,6 +36,17 @@ SYM_CODE_START(__efi64_thunk) movq efi_mixed_mode_stack_pa(%rip), %rsp push %rax + /* + * Copy args passed via the stack + */ + subq $0x24, %rsp + movq 0x18(%rax), %rbp + movq 0x20(%rax), %rbx + movq 0x28(%rax), %rax + movl %ebp, 0x18(%rsp) + movl %ebx, 0x1c(%rsp) + movl %eax, 0x20(%rsp) + /* * Calculate the physical address of the kernel text. */ @@ -47,7 +58,6 @@ SYM_CODE_START(__efi64_thunk) subq %rax, %rbp subq %rax, %rbx - subq $28, %rsp movl %ebx, 0x0(%rsp) /* return address */ movl %esi, 0x4(%rsp) movl %edx, 0x8(%rsp) @@ -60,7 +70,7 @@ SYM_CODE_START(__efi64_thunk) pushq %rdi /* EFI runtime service address */ lretq -1: movq 24(%rsp), %rsp +1: movq 0x20(%rsp), %rsp pop %rbx pop %rbp retq -- GitLab From 20287d56f52dab0790acb05f44cd2011bac0a431 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 19 Nov 2021 13:47:44 +0200 Subject: [PATCH 0109/1112] efi/libstub: consolidate initrd handling across architectures Before adding TPM measurement of the initrd contents, refactor the initrd handling slightly to be more self-contained and consistent. Signed-off-by: Ard Biesheuvel Signed-off-by: Ilias Apalodimas Link: https://lore.kernel.org/r/20211119114745.1560453-4-ilias.apalodimas@linaro.org Signed-off-by: Ard Biesheuvel --- .../firmware/efi/libstub/efi-stub-helper.c | 13 +++++++--- drivers/firmware/efi/libstub/efi-stub.c | 10 ++----- drivers/firmware/efi/libstub/efistub.h | 1 - drivers/firmware/efi/libstub/x86-stub.c | 26 +++++++------------ 4 files changed, 21 insertions(+), 29 deletions(-) diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index d489bdc645fe1..01677181453d4 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -20,10 +20,10 @@ bool efi_nochunk; bool efi_nokaslr = !IS_ENABLED(CONFIG_RANDOMIZE_BASE); -bool efi_noinitrd; int efi_loglevel = CONSOLE_LOGLEVEL_DEFAULT; bool efi_novamap; +static bool efi_noinitrd; static bool efi_nosoftreserve; static bool efi_disable_pci_dma = IS_ENABLED(CONFIG_EFI_DISABLE_PCI_DMA); @@ -643,8 +643,10 @@ efi_status_t efi_load_initrd(efi_loaded_image_t *image, { efi_status_t status; - if (!load_addr || !load_size) - return EFI_INVALID_PARAMETER; + if (efi_noinitrd) { + *load_addr = *load_size = 0; + return EFI_SUCCESS; + } status = efi_load_initrd_dev_path(load_addr, load_size, hard_limit); if (status == EFI_SUCCESS) { @@ -655,7 +657,10 @@ efi_status_t efi_load_initrd(efi_loaded_image_t *image, if (status == EFI_SUCCESS && *load_size > 0) efi_info("Loaded initrd from command line option\n"); } - + if (status != EFI_SUCCESS) { + efi_err("Failed to load initrd: 0x%lx\n", status); + *load_addr = *load_size = 0; + } return status; } diff --git a/drivers/firmware/efi/libstub/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c index 26e69788f27a4..e87e7f1b1a33a 100644 --- a/drivers/firmware/efi/libstub/efi-stub.c +++ b/drivers/firmware/efi/libstub/efi-stub.c @@ -134,7 +134,6 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, enum efi_secureboot_mode secure_boot; struct screen_info *si; efi_properties_table_t *prop_tbl; - unsigned long max_addr; efi_system_table = sys_table_arg; @@ -240,13 +239,8 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, if (!fdt_addr) efi_info("Generating empty DTB\n"); - if (!efi_noinitrd) { - max_addr = efi_get_max_initrd_addr(image_addr); - status = efi_load_initrd(image, &initrd_addr, &initrd_size, - ULONG_MAX, max_addr); - if (status != EFI_SUCCESS) - efi_err("Failed to load initrd!\n"); - } + efi_load_initrd(image, &initrd_addr, &initrd_size, ULONG_MAX, + efi_get_max_initrd_addr(image_addr)); efi_random_get_seed(); diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index a2825c4351580..edb77b0621ea3 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -31,7 +31,6 @@ extern bool efi_nochunk; extern bool efi_nokaslr; -extern bool efi_noinitrd; extern int efi_loglevel; extern bool efi_novamap; diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c index f14c4ff5839f9..01ddd4502e28a 100644 --- a/drivers/firmware/efi/libstub/x86-stub.c +++ b/drivers/firmware/efi/libstub/x86-stub.c @@ -673,6 +673,7 @@ unsigned long efi_main(efi_handle_t handle, unsigned long bzimage_addr = (unsigned long)startup_32; unsigned long buffer_start, buffer_end; struct setup_header *hdr = &boot_params->hdr; + unsigned long addr, size; efi_status_t status; efi_system_table = sys_table_arg; @@ -761,22 +762,15 @@ unsigned long efi_main(efi_handle_t handle, * arguments will be processed only if image is not NULL, which will be * the case only if we were loaded via the PE entry point. */ - if (!efi_noinitrd) { - unsigned long addr, size; - - status = efi_load_initrd(image, &addr, &size, - hdr->initrd_addr_max, ULONG_MAX); - - if (status != EFI_SUCCESS) { - efi_err("Failed to load initrd!\n"); - goto fail; - } - if (size > 0) { - efi_set_u64_split(addr, &hdr->ramdisk_image, - &boot_params->ext_ramdisk_image); - efi_set_u64_split(size, &hdr->ramdisk_size, - &boot_params->ext_ramdisk_size); - } + status = efi_load_initrd(image, &addr, &size, hdr->initrd_addr_max, + ULONG_MAX); + if (status != EFI_SUCCESS) + goto fail; + if (size > 0) { + efi_set_u64_split(addr, &hdr->ramdisk_image, + &boot_params->ext_ramdisk_image); + efi_set_u64_split(size, &hdr->ramdisk_size, + &boot_params->ext_ramdisk_size); } /* -- GitLab From 01df1385ec4ec699ad6a63007e7f1081089e83a0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 18 Nov 2021 12:41:49 +0100 Subject: [PATCH 0110/1112] platform/x86: think-lmi: Move kobject_init() call into tlmi_create_auth() All callers of tlmi_create_auth() also call kobject_init(&pwd_setting->kobj, &tlmi_pwd_setting_ktype) on the returned tlmi_pwd_setting struct. Move this into tlmi_create_auth(). Tested-by: Mark Pearson Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20211118114150.271274-1-hdegoede@redhat.com --- drivers/platform/x86/think-lmi.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c index fee9e004161fd..6eba69334fa60 100644 --- a/drivers/platform/x86/think-lmi.c +++ b/drivers/platform/x86/think-lmi.c @@ -1057,6 +1057,9 @@ static struct tlmi_pwd_setting *tlmi_create_auth(const char *pwd_type, new_pwd->minlen = tlmi_priv.pwdcfg.core.min_length; new_pwd->maxlen = tlmi_priv.pwdcfg.core.max_length; new_pwd->index = 0; + + kobject_init(&new_pwd->kobj, &tlmi_pwd_setting_ktype); + return new_pwd; } @@ -1146,8 +1149,6 @@ static int tlmi_analyze(void) if (tlmi_priv.pwdcfg.core.password_state & TLMI_PAP_PWD) tlmi_priv.pwd_admin->valid = true; - kobject_init(&tlmi_priv.pwd_admin->kobj, &tlmi_pwd_setting_ktype); - tlmi_priv.pwd_power = tlmi_create_auth("pop", "power-on"); if (!tlmi_priv.pwd_power) { ret = -ENOMEM; @@ -1156,8 +1157,6 @@ static int tlmi_analyze(void) if (tlmi_priv.pwdcfg.core.password_state & TLMI_POP_PWD) tlmi_priv.pwd_power->valid = true; - kobject_init(&tlmi_priv.pwd_power->kobj, &tlmi_pwd_setting_ktype); - if (tlmi_priv.opcode_support) { tlmi_priv.pwd_system = tlmi_create_auth("sys", "system"); if (!tlmi_priv.pwd_system) { @@ -1167,21 +1166,17 @@ static int tlmi_analyze(void) if (tlmi_priv.pwdcfg.core.password_state & TLMI_SYS_PWD) tlmi_priv.pwd_system->valid = true; - kobject_init(&tlmi_priv.pwd_system->kobj, &tlmi_pwd_setting_ktype); - tlmi_priv.pwd_hdd = tlmi_create_auth("hdd", "hdd"); if (!tlmi_priv.pwd_hdd) { ret = -ENOMEM; goto fail_clear_attr; } - kobject_init(&tlmi_priv.pwd_hdd->kobj, &tlmi_pwd_setting_ktype); tlmi_priv.pwd_nvme = tlmi_create_auth("nvm", "nvme"); if (!tlmi_priv.pwd_nvme) { ret = -ENOMEM; goto fail_clear_attr; } - kobject_init(&tlmi_priv.pwd_nvme->kobj, &tlmi_pwd_setting_ktype); if (tlmi_priv.pwdcfg.core.password_state & TLMI_HDD_PWD) { /* Check if PWD is configured and set index to first drive found */ -- GitLab From ff448bbaacfb6f216ae101c1f16d8c5142c16fdf Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 18 Nov 2021 12:41:50 +0100 Subject: [PATCH 0111/1112] platform/x86: think-lmi: Simplify tlmi_analyze() error handling a bit Creating the tlmi_pwd_setting structs can only fail with -ENOMEM, set ret to this once and simplify the error handling a bit. Tested-by: Mark Pearson Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20211118114150.271274-2-hdegoede@redhat.com --- drivers/platform/x86/think-lmi.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c index 6eba69334fa60..27ab8e4e5b836 100644 --- a/drivers/platform/x86/think-lmi.c +++ b/drivers/platform/x86/think-lmi.c @@ -1141,42 +1141,38 @@ static int tlmi_analyze(void) if (ret) goto fail_clear_attr; + /* All failures below boil down to kmalloc failures */ + ret = -ENOMEM; + tlmi_priv.pwd_admin = tlmi_create_auth("pap", "bios-admin"); - if (!tlmi_priv.pwd_admin) { - ret = -ENOMEM; + if (!tlmi_priv.pwd_admin) goto fail_clear_attr; - } + if (tlmi_priv.pwdcfg.core.password_state & TLMI_PAP_PWD) tlmi_priv.pwd_admin->valid = true; tlmi_priv.pwd_power = tlmi_create_auth("pop", "power-on"); - if (!tlmi_priv.pwd_power) { - ret = -ENOMEM; + if (!tlmi_priv.pwd_power) goto fail_clear_attr; - } + if (tlmi_priv.pwdcfg.core.password_state & TLMI_POP_PWD) tlmi_priv.pwd_power->valid = true; if (tlmi_priv.opcode_support) { tlmi_priv.pwd_system = tlmi_create_auth("sys", "system"); - if (!tlmi_priv.pwd_system) { - ret = -ENOMEM; + if (!tlmi_priv.pwd_system) goto fail_clear_attr; - } + if (tlmi_priv.pwdcfg.core.password_state & TLMI_SYS_PWD) tlmi_priv.pwd_system->valid = true; tlmi_priv.pwd_hdd = tlmi_create_auth("hdd", "hdd"); - if (!tlmi_priv.pwd_hdd) { - ret = -ENOMEM; + if (!tlmi_priv.pwd_hdd) goto fail_clear_attr; - } tlmi_priv.pwd_nvme = tlmi_create_auth("nvm", "nvme"); - if (!tlmi_priv.pwd_nvme) { - ret = -ENOMEM; + if (!tlmi_priv.pwd_nvme) goto fail_clear_attr; - } if (tlmi_priv.pwdcfg.core.password_state & TLMI_HDD_PWD) { /* Check if PWD is configured and set index to first drive found */ -- GitLab From c15f86856bec5bbf9a5ea909ce5ccc5b05744eb1 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 21 Nov 2021 20:11:23 +0100 Subject: [PATCH 0112/1112] platform/x86: thinkpad_acpi: Accept ibm_init_struct.init() returning -ENODEV Commit 79f960e29cfc ("platform/x86: thinkpad_acpi: Convert platform driver to use dev_groups") accidentally modified tpacpi_kbdlang_init() causing it to return -ENODEV instead of 0 on machines without kbdlang support (which are most of them). ibm_init() sees this -ENODEV as an error causing the entire module to not load, not good. Note that technically tpacpi_kbdlang_init() was already buggy before, it should have returned 1 instead of 0 if the feature is not present. Rather then fixing tpacpi_kbdlang_init() though, IMHO it is bettter to just make ibm_init() treat -ENODEV as 1 to fix the issue; and then in a followup commit also change all the existing "return 1"s from ibm_init_struct.init() callbacks to "return -ENODEV" as -ENODEV clearly states what it going on where as a magic return of "1" requires a deep dive into the code to figure out what is going on. This will also allow removing some extra ifs to translate -ENODEV to return 1 in a couple of init() callbacks. Fixes: 79f960e29cfc ("platform/x86: thinkpad_acpi: Convert platform driver to use dev_groups") Cc: Len Baker Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20211121191129.256713-2-hdegoede@redhat.com --- drivers/platform/x86/thinkpad_acpi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 37aadc64d4e00..9e296b436bea3 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -10685,8 +10685,8 @@ static int __init ibm_init(struct ibm_init_struct *iibm) if (iibm->init) { ret = iibm->init(iibm); - if (ret > 0) - return 0; /* probe failed */ + if (ret > 0 || ret == -ENODEV) + return 0; /* subdriver functionality not available */ if (ret) return ret; -- GitLab From f6f6a6320eeeb3e80e1393f727f898f8ca976bfd Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 19 Nov 2021 13:11:39 +0100 Subject: [PATCH 0113/1112] spi: docs: improve the SPI userspace API documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This doc is fairly outdated and only uses legacy device instantiation terminology. Let us update it and also mention the OF and ACPI device tables, to make easier for users to figure out how should be defined. Also, mention that devices bind could be done in user-space now using the "driver_override" sysfs entry. Suggested-by: Ralph Siemsen Signed-off-by: Javier Martinez Canillas Acked-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20211119121139.2412761-1-javierm@redhat.com Signed-off-by: Mark Brown --- Documentation/spi/spidev.rst | 58 ++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/Documentation/spi/spidev.rst b/Documentation/spi/spidev.rst index f05dbc5ccdbc6..369c657ba4358 100644 --- a/Documentation/spi/spidev.rst +++ b/Documentation/spi/spidev.rst @@ -29,21 +29,49 @@ of the driver stack) that are not accessible to userspace. DEVICE CREATION, DRIVER BINDING =============================== -The simplest way to arrange to use this driver is to just list it in the -spi_board_info for a device as the driver it should use: the "modalias" -entry is "spidev", matching the name of the driver exposing this API. -Set up the other device characteristics (bits per word, SPI clocking, -chipselect polarity, etc) as usual, so you won't always need to override -them later. - -(Sysfs also supports userspace driven binding/unbinding of drivers to -devices. That mechanism might be supported here in the future.) - -When you do that, the sysfs node for the SPI device will include a child -device node with a "dev" attribute that will be understood by udev or mdev. -(Larger systems will have "udev". Smaller ones may configure "mdev" into -busybox; it's less featureful, but often enough.) For a SPI device with -chipselect C on bus B, you should see: + +The spidev driver contains lists of SPI devices that are supported for +the different hardware topology representations. + +The following are the SPI device tables supported by the spidev driver: + + - struct spi_device_id spidev_spi_ids[]: list of devices that can be + bound when these are defined using a struct spi_board_info with a + .modalias field matching one of the entries in the table. + + - struct of_device_id spidev_dt_ids[]: list of devices that can be + bound when these are defined using a Device Tree node that has a + compatible string matching one of the entries in the table. + + - struct acpi_device_id spidev_acpi_ids[]: list of devices that can + be bound when these are defined using a ACPI device object with a + _HID matching one of the entries in the table. + +You are encouraged to add an entry for your SPI device name to relevant +tables, if these don't already have an entry for the device. To do that, +post a patch for spidev to the linux-spi@vger.kernel.org mailing list. + +It used to be supported to define an SPI device using the "spidev" name. +For example, as .modalias = "spidev" or compatible = "spidev". But this +is no longer supported by the Linux kernel and instead a real SPI device +name as listed in one of the tables must be used. + +Not having a real SPI device name will lead to an error being printed and +the spidev driver failing to probe. + +Sysfs also supports userspace driven binding/unbinding of drivers to +devices that do not bind automatically using one of the tables above. +To make the spidev driver bind to such a device, use the following: + + echo spidev > /sys/bus/spi/devices/spiB.C/driver_override + echo spiB.C > /sys/bus/spi/drivers/spidev/bind + +When the spidev driver is bound to a SPI device, the sysfs node for the +device will include a child device node with a "dev" attribute that will +be understood by udev or mdev (udev replacement from BusyBox; it's less +featureful, but often enough). + +For a SPI device with chipselect C on bus B, you should see: /dev/spidevB.C ... character special device, major number 153 with -- GitLab From d94758b344e3b6f16d31cb5b51b93e3e5a4c3567 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 02:17:15 +0100 Subject: [PATCH 0114/1112] spi: Add resets to the PL022 bindings Some PL022 implementations provide a reset line to the silicon IP block, add a device tree property for this. Cc: devicetree@vger.kernel.org Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20211120011715.2630873-1-linus.walleij@linaro.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-pl022.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/spi/spi-pl022.yaml b/Documentation/devicetree/bindings/spi/spi-pl022.yaml index a91d868e40c5e..6d633728fc2be 100644 --- a/Documentation/devicetree/bindings/spi/spi-pl022.yaml +++ b/Documentation/devicetree/bindings/spi/spi-pl022.yaml @@ -72,6 +72,9 @@ properties: - const: rx - const: tx + resets: + maxItems: 1 + patternProperties: "^[a-zA-Z][a-zA-Z0-9,+\\-._]{0,63}@[0-9a-f]+$": type: object -- GitLab From 3f07657506df363709a37f99db04e9e0d0b1bce7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 19 Nov 2021 19:37:17 +0200 Subject: [PATCH 0115/1112] spi: deduplicate spi_match_id() in __spi_register_driver() The same logic is used in spi_match_id() and in the __spi_register_driver(). By switching the former from taking struct spi_device * to const char * as the second parameter we may deduplicate the code. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211119173718.52938-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index fdd530b150a7a..9d19d9bae2537 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -315,11 +315,10 @@ static void spi_statistics_add_transfer_stats(struct spi_statistics *stats, * and the sysfs version makes coldplug work too. */ -static const struct spi_device_id *spi_match_id(const struct spi_device_id *id, - const struct spi_device *sdev) +static const struct spi_device_id *spi_match_id(const struct spi_device_id *id, const char *name) { while (id->name[0]) { - if (!strcmp(sdev->modalias, id->name)) + if (!strcmp(name, id->name)) return id; id++; } @@ -330,7 +329,7 @@ const struct spi_device_id *spi_get_device_id(const struct spi_device *sdev) { const struct spi_driver *sdrv = to_spi_driver(sdev->dev.driver); - return spi_match_id(sdrv->id_table, sdev); + return spi_match_id(sdrv->id_table, sdev->modalias); } EXPORT_SYMBOL_GPL(spi_get_device_id); @@ -352,7 +351,7 @@ static int spi_match_device(struct device *dev, struct device_driver *drv) return 1; if (sdrv->id_table) - return !!spi_match_id(sdrv->id_table, spi); + return !!spi_match_id(sdrv->id_table, spi->modalias); return strcmp(spi->modalias, drv->name) == 0; } @@ -474,12 +473,8 @@ int __spi_register_driver(struct module *owner, struct spi_driver *sdrv) if (sdrv->id_table) { const struct spi_device_id *spi_id; - for (spi_id = sdrv->id_table; spi_id->name[0]; - spi_id++) - if (strcmp(spi_id->name, of_name) == 0) - break; - - if (spi_id->name[0]) + spi_id = spi_match_id(sdrv->id_table, of_name); + if (!spi_id) continue; } else { if (strcmp(sdrv->driver.name, of_name) == 0) -- GitLab From 49cd1eb37b487036f51bd57b591f7b5760a10e02 Mon Sep 17 00:00:00 2001 From: Jacky Bai Date: Sat, 20 Nov 2021 19:34:49 +0800 Subject: [PATCH 0116/1112] spi: fsl-lpspi: Add imx8ulp compatible string The lpspi on i.MX8ULP is derived from i.MX7ULP, it uses two compatible strings, so update the comaptible string for i.MX8ULP. Signed-off-by: Jacky Bai Reviewed-by: Dong Aisheng Acked-by: Rob Herring Link: https://lore.kernel.org/r/20211120113454.785997-4-peng.fan@oss.nxp.com Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi-fsl-lpspi.yaml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/spi-fsl-lpspi.yaml b/Documentation/devicetree/bindings/spi/spi-fsl-lpspi.yaml index 312d8fee9dbb8..1d46877fe46a8 100644 --- a/Documentation/devicetree/bindings/spi/spi-fsl-lpspi.yaml +++ b/Documentation/devicetree/bindings/spi/spi-fsl-lpspi.yaml @@ -14,10 +14,13 @@ allOf: properties: compatible: - enum: - - fsl,imx7ulp-spi - - fsl,imx8qxp-spi - + oneOf: + - enum: + - fsl,imx7ulp-spi + - fsl,imx8qxp-spi + - items: + - const: fsl,imx8ulp-spi + - const: fsl,imx7ulp-spi reg: maxItems: 1 -- GitLab From 59f1b854706d4d6830a3ed0f6b535a2ba5d425a6 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:11 +0100 Subject: [PATCH 0117/1112] power: supply: ab8500: Use core battery parser This deploys the core battery DT parser to read the basic properties of the battery. We only use very little of it as we start out, but we will improve as we go along. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 3 +-- drivers/power/supply/ab8500_bmdata.c | 31 +++++++++++---------------- drivers/power/supply/ab8500_charger.c | 16 +++++++++----- 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index d11405b7ee1aa..33c7e15f5d96e 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -570,8 +570,7 @@ int ab8500_fg_inst_curr_start(struct ab8500_fg *di); int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res); int ab8500_fg_inst_curr_started(struct ab8500_fg *di); int ab8500_fg_inst_curr_done(struct ab8500_fg *di); -int ab8500_bm_of_probe(struct device *dev, - struct device_node *np, +int ab8500_bm_of_probe(struct power_supply *psy, struct ab8500_bm_data *bm); extern struct platform_driver ab8500_fg_driver; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index bfc1245d79123..a515dfad4c3fd 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -488,29 +488,22 @@ struct ab8500_bm_data ab8500_bm_data = { .n_chg_in_curr = ARRAY_SIZE(ab8500_charge_input_curr_map), }; -int ab8500_bm_of_probe(struct device *dev, - struct device_node *np, +int ab8500_bm_of_probe(struct power_supply *psy, struct ab8500_bm_data *bm) { const struct batres_vs_temp *tmp_batres_tbl; - struct device_node *battery_node; - const char *btech; + struct power_supply_battery_info info; + struct device *dev = &psy->dev; + int ret; int i; - battery_node = of_parse_phandle(np, "monitored-battery", 0); - if (!battery_node) { - dev_err(dev, "battery node or reference missing\n"); - return -EINVAL; + ret = power_supply_get_battery_info(psy, &info); + if (ret) { + dev_err(dev, "cannot retrieve battery info\n"); + return ret; } - btech = of_get_property(battery_node, "stericsson,battery-type", NULL); - if (!btech) { - dev_warn(dev, "missing property battery-name/type\n"); - of_node_put(battery_node); - return -EINVAL; - } - - if (strncmp(btech, "LION", 4) == 0) { + if (info.technology == POWER_SUPPLY_TECHNOLOGY_LION) { bm->no_maintenance = true; bm->chg_unknown_bat = true; bm->bat_type[BATTERY_UNKNOWN].charge_full_design = 2600; @@ -520,8 +513,8 @@ int ab8500_bm_of_probe(struct device *dev, bm->bat_type[BATTERY_UNKNOWN].normal_vol_lvl = 4200; } - if (of_property_read_bool(battery_node, "thermistor-on-batctrl")) { - if (strncmp(btech, "LION", 4) == 0) + if (of_property_read_bool(psy->of_node, "thermistor-on-batctrl")) { + if (info.technology == POWER_SUPPLY_TECHNOLOGY_LION) tmp_batres_tbl = temp_to_batres_tbl_9100; else tmp_batres_tbl = temp_to_batres_tbl_thermistor; @@ -536,7 +529,7 @@ int ab8500_bm_of_probe(struct device *dev, for (i = 0; i < bm->n_btypes; ++i) bm->bat_type[i].batres_tbl = tmp_batres_tbl; - of_node_put(battery_node); + power_supply_put_battery_info(psy, &info); return 0; } diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c index 15eadaf46f144..59ca9c0b8012f 100644 --- a/drivers/power/supply/ab8500_charger.c +++ b/drivers/power/supply/ab8500_charger.c @@ -3413,11 +3413,6 @@ static int ab8500_charger_probe(struct platform_device *pdev) di->bm = &ab8500_bm_data; - ret = ab8500_bm_of_probe(dev, np, di->bm); - if (ret) { - dev_err(dev, "failed to get battery information\n"); - return ret; - } di->autopower_cfg = of_property_read_bool(np, "autopower_cfg"); /* get parent data */ @@ -3490,9 +3485,11 @@ static int ab8500_charger_probe(struct platform_device *pdev) di->invalid_charger_detect_state = 0; /* AC and USB supply config */ + ac_psy_cfg.of_node = np; ac_psy_cfg.supplied_to = supply_interface; ac_psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface); ac_psy_cfg.drv_data = &di->ac_chg; + usb_psy_cfg.of_node = np; usb_psy_cfg.supplied_to = supply_interface; usb_psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface); usb_psy_cfg.drv_data = &di->usb_chg; @@ -3610,6 +3607,15 @@ static int ab8500_charger_probe(struct platform_device *pdev) return PTR_ERR(di->usb_chg.psy); } + /* + * Check what battery we have, since we always have the USB + * psy, use that as a handle. + */ + ret = ab8500_bm_of_probe(di->usb_chg.psy, di->bm); + if (ret) + return dev_err_probe(dev, ret, + "failed to get battery information\n"); + /* Identify the connected charger types during startup */ charger_status = ab8500_charger_detect_chargers(di, true); if (charger_status & AC_PW_CONN) { -- GitLab From 3aca6ecdab44b30e812001ab4de19b79001a3fbd Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:12 +0100 Subject: [PATCH 0118/1112] power: supply: ab8500: Sink current tables into charger code The two tables for input and output current translation from register values does not need to be passed around from the battery manager data. Just push it down into the charger code where it is used, like other tables in that code. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 8 ------ drivers/power/supply/ab8500_bmdata.c | 22 ---------------- drivers/power/supply/ab8500_charger.c | 38 ++++++++++++++++++--------- 3 files changed, 25 insertions(+), 43 deletions(-) diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index 33c7e15f5d96e..bcb0548102901 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -484,10 +484,6 @@ struct ab8500_bm_charger_parameters { * @interval_not_charging charge alg cycle period time when not charging (sec) * @temp_hysteresis temperature hysteresis * @gnd_lift_resistance Battery ground to phone ground resistance (mOhm) - * @n_chg_out_curr number of elements in array chg_output_curr - * @n_chg_in_curr number of elements in array chg_input_curr - * @chg_output_curr charger output current level map - * @chg_input_curr charger input current level map * @maxi maximization parameters * @cap_levels capacity in percent for the different capacity levels * @bat_type table of supported battery types @@ -519,10 +515,6 @@ struct ab8500_bm_data { int interval_not_charging; int temp_hysteresis; int gnd_lift_resistance; - int n_chg_out_curr; - int n_chg_in_curr; - int *chg_output_curr; - int *chg_input_curr; const struct ab8500_maxim_parameters *maxi; const struct ab8500_bm_capacity_levels *cap_levels; struct ab8500_battery_type *bat_type; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index a515dfad4c3fd..6f6865c46926f 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -436,24 +436,6 @@ static const struct ab8500_bm_charger_parameters chg = { .ac_curr_max = 1500, }; -/* - * This array maps the raw hex value to charger output current used by the - * AB8500 values - */ -static int ab8500_charge_output_curr_map[] = { - 100, 200, 300, 400, 500, 600, 700, 800, - 900, 1000, 1100, 1200, 1300, 1400, 1500, 1500, -}; - -/* - * This array maps the raw hex value to charger input current used by the - * AB8500 values - */ -static int ab8500_charge_input_curr_map[] = { - 50, 98, 193, 290, 380, 450, 500, 600, - 700, 800, 900, 1000, 1100, 1300, 1400, 1500, -}; - struct ab8500_bm_data ab8500_bm_data = { .temp_under = 3, .temp_low = 8, @@ -479,13 +461,9 @@ struct ab8500_bm_data ab8500_bm_data = { .interval_not_charging = 120, .temp_hysteresis = 3, .gnd_lift_resistance = 34, - .chg_output_curr = ab8500_charge_output_curr_map, - .n_chg_out_curr = ARRAY_SIZE(ab8500_charge_output_curr_map), .maxi = &ab8500_maxi_params, .chg_params = &chg, .fg_params = &fg, - .chg_input_curr = ab8500_charge_input_curr_map, - .n_chg_in_curr = ARRAY_SIZE(ab8500_charge_input_curr_map), }; int ab8500_bm_of_probe(struct power_supply *psy, diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c index 59ca9c0b8012f..32c2046ea6bbf 100644 --- a/drivers/power/supply/ab8500_charger.c +++ b/drivers/power/supply/ab8500_charger.c @@ -1025,21 +1025,33 @@ static int ab8500_voltage_to_regval(int voltage) return -1; } +/* This array maps the raw register value to charger input current */ +static int ab8500_charge_input_curr_map[] = { + 50, 98, 193, 290, 380, 450, 500, 600, + 700, 800, 900, 1000, 1100, 1300, 1400, 1500, +}; + +/* This array maps the raw register value to charger output current */ +static int ab8500_charge_output_curr_map[] = { + 100, 200, 300, 400, 500, 600, 700, 800, + 900, 1000, 1100, 1200, 1300, 1400, 1500, 1500, +}; + static int ab8500_current_to_regval(struct ab8500_charger *di, int curr) { int i; - if (curr < di->bm->chg_output_curr[0]) + if (curr < ab8500_charge_output_curr_map[0]) return 0; - for (i = 0; i < di->bm->n_chg_out_curr; i++) { - if (curr < di->bm->chg_output_curr[i]) + for (i = 0; i < ARRAY_SIZE(ab8500_charge_output_curr_map); i++) { + if (curr < ab8500_charge_output_curr_map[i]) return i - 1; } /* If not last element, return error */ - i = di->bm->n_chg_out_curr - 1; - if (curr == di->bm->chg_output_curr[i]) + i = ARRAY_SIZE(ab8500_charge_output_curr_map) - 1; + if (curr == ab8500_charge_output_curr_map[i]) return i; else return -1; @@ -1049,17 +1061,17 @@ static int ab8500_vbus_in_curr_to_regval(struct ab8500_charger *di, int curr) { int i; - if (curr < di->bm->chg_input_curr[0]) + if (curr < ab8500_charge_input_curr_map[0]) return 0; - for (i = 0; i < di->bm->n_chg_in_curr; i++) { - if (curr < di->bm->chg_input_curr[i]) + for (i = 0; i < ARRAY_SIZE(ab8500_charge_input_curr_map); i++) { + if (curr < ab8500_charge_input_curr_map[i]) return i - 1; } /* If not last element, return error */ - i = di->bm->n_chg_in_curr - 1; - if (curr == di->bm->chg_input_curr[i]) + i = ARRAY_SIZE(ab8500_charge_input_curr_map) - 1; + if (curr == ab8500_charge_input_curr_map[i]) return i; else return -1; @@ -2673,7 +2685,7 @@ static void ab8500_charger_vbus_drop_end_work(struct work_struct *work) return; } - curr = di->bm->chg_input_curr[ + curr = ab8500_charge_input_curr_map[ reg_value >> AUTO_VBUS_IN_CURR_LIM_SHIFT]; if (di->max_usb_in_curr.calculated_max != curr) { @@ -3503,7 +3515,7 @@ static int ab8500_charger_probe(struct platform_device *pdev) di->ac_chg.max_out_volt = ab8500_charger_voltage_map[ ARRAY_SIZE(ab8500_charger_voltage_map) - 1]; di->ac_chg.max_out_curr = - di->bm->chg_output_curr[di->bm->n_chg_out_curr - 1]; + ab8500_charge_output_curr_map[ARRAY_SIZE(ab8500_charge_output_curr_map) - 1]; di->ac_chg.wdt_refresh = CHG_WD_INTERVAL; /* * The AB8505 only supports USB charging. If we are not the @@ -3524,7 +3536,7 @@ static int ab8500_charger_probe(struct platform_device *pdev) di->usb_chg.max_out_volt = ab8500_charger_voltage_map[ ARRAY_SIZE(ab8500_charger_voltage_map) - 1]; di->usb_chg.max_out_curr = - di->bm->chg_output_curr[di->bm->n_chg_out_curr - 1]; + ab8500_charge_output_curr_map[ARRAY_SIZE(ab8500_charge_output_curr_map) - 1]; di->usb_chg.wdt_refresh = CHG_WD_INTERVAL; di->usb_chg.external = false; di->usb_state.usb_current = -1; -- GitLab From 6252c706cdb003da0046ced1a088b9f31af1fd9b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:13 +0100 Subject: [PATCH 0119/1112] power: supply: ab8500: Standardize operating temperature Instead of storing the temperature limits in our custom struct struct ab8500_bm_data, make struct power_supply_battery_info a member of this and store the min and max temperatures inside that struct as the temp_min/temp_max and temp_alert_min/temp_alert_max respectively. The values can be assigned from the device tree, but if not present will be set to the same defaults as are currently in the code. This way we start to move over to using struct power_supply_battery_info and make it possible to move the data over to the device tree and we will move piece by piece toward using the standard info struct. Temperature hysteresis is currently not supported by the standard struct but we move the assignment here as well so that we have all parameterization in one spot. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 12 +++---- drivers/power/supply/ab8500_bmdata.c | 43 +++++++++++++++++++------- drivers/power/supply/ab8500_chargalg.c | 20 ++++++------ drivers/power/supply/ab8500_charger.c | 1 + 4 files changed, 48 insertions(+), 28 deletions(-) diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index bcb0548102901..fe783610bc544 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -460,10 +460,7 @@ struct ab8500_bm_charger_parameters { /** * struct ab8500_bm_data - ab8500 battery management data - * @temp_under under this temp, charging is stopped - * @temp_low between this temp and temp_under charging is reduced - * @temp_high between this temp and temp_over charging is reduced - * @temp_over over this temp, charging is stopped + * @bi battery info from device tree * @temp_now present battery temperature * @temp_interval_chg temperature measurement interval in s when charging * @temp_interval_nochg temperature measurement interval in s when not charging @@ -491,10 +488,7 @@ struct ab8500_bm_charger_parameters { * @fg_params fuel gauge parameters */ struct ab8500_bm_data { - int temp_under; - int temp_low; - int temp_high; - int temp_over; + struct power_supply_battery_info bi; int temp_now; int temp_interval_chg; int temp_interval_nochg; @@ -564,6 +558,8 @@ int ab8500_fg_inst_curr_started(struct ab8500_fg *di); int ab8500_fg_inst_curr_done(struct ab8500_fg *di); int ab8500_bm_of_probe(struct power_supply *psy, struct ab8500_bm_data *bm); +void ab8500_bm_of_remove(struct power_supply *psy, + struct ab8500_bm_data *bm); extern struct platform_driver ab8500_fg_driver; extern struct platform_driver ab8500_btemp_driver; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index 6f6865c46926f..41561b6adfd38 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -5,6 +5,17 @@ #include "ab8500-bm.h" +/* Default: under this temperature, charging is stopped */ +#define AB8500_TEMP_UNDER 3 +/* Default: between this temp and AB8500_TEMP_UNDER charging is reduced */ +#define AB8500_TEMP_LOW 8 +/* Default: between this temp and AB8500_TEMP_OVER charging is reduced */ +#define AB8500_TEMP_HIGH 43 +/* Default: over this temp, charging is stopped */ +#define AB8500_TEMP_OVER 48 +/* Default: temperature hysteresis */ +#define AB8500_TEMP_HYSTERESIS 3 + /* * These are the defined batteries that uses a NTC and ID resistor placed * inside of the battery pack. @@ -437,10 +448,6 @@ static const struct ab8500_bm_charger_parameters chg = { }; struct ab8500_bm_data ab8500_bm_data = { - .temp_under = 3, - .temp_low = 8, - .temp_high = 43, - .temp_over = 48, .main_safety_tmr_h = 4, .temp_interval_chg = 20, .temp_interval_nochg = 120, @@ -459,7 +466,6 @@ struct ab8500_bm_data ab8500_bm_data = { .batt_id = 0, .interval_charging = 5, .interval_not_charging = 120, - .temp_hysteresis = 3, .gnd_lift_resistance = 34, .maxi = &ab8500_maxi_params, .chg_params = &chg, @@ -470,18 +476,29 @@ int ab8500_bm_of_probe(struct power_supply *psy, struct ab8500_bm_data *bm) { const struct batres_vs_temp *tmp_batres_tbl; - struct power_supply_battery_info info; + struct power_supply_battery_info *bi = &bm->bi; struct device *dev = &psy->dev; int ret; int i; - ret = power_supply_get_battery_info(psy, &info); + ret = power_supply_get_battery_info(psy, bi); if (ret) { dev_err(dev, "cannot retrieve battery info\n"); return ret; } - if (info.technology == POWER_SUPPLY_TECHNOLOGY_LION) { + if (bi->temp_min == INT_MIN) + bi->temp_min = AB8500_TEMP_UNDER; + if (bi->temp_max == INT_MAX) + bi->temp_max = AB8500_TEMP_OVER; + if (bi->temp_alert_min == INT_MIN) + bi->temp_alert_min = AB8500_TEMP_LOW; + if (bi->temp_alert_max == INT_MAX) + bi->temp_alert_max = AB8500_TEMP_HIGH; + bm->temp_hysteresis = AB8500_TEMP_HYSTERESIS; + + + if (bi->technology == POWER_SUPPLY_TECHNOLOGY_LION) { bm->no_maintenance = true; bm->chg_unknown_bat = true; bm->bat_type[BATTERY_UNKNOWN].charge_full_design = 2600; @@ -492,7 +509,7 @@ int ab8500_bm_of_probe(struct power_supply *psy, } if (of_property_read_bool(psy->of_node, "thermistor-on-batctrl")) { - if (info.technology == POWER_SUPPLY_TECHNOLOGY_LION) + if (bi->technology == POWER_SUPPLY_TECHNOLOGY_LION) tmp_batres_tbl = temp_to_batres_tbl_9100; else tmp_batres_tbl = temp_to_batres_tbl_thermistor; @@ -507,7 +524,11 @@ int ab8500_bm_of_probe(struct power_supply *psy, for (i = 0; i < bm->n_btypes; ++i) bm->bat_type[i].batres_tbl = tmp_batres_tbl; - power_supply_put_battery_info(psy, &info); - return 0; } + +void ab8500_bm_of_remove(struct power_supply *psy, + struct ab8500_bm_data *bm) +{ + power_supply_put_battery_info(psy, &bm->bi); +} diff --git a/drivers/power/supply/ab8500_chargalg.c b/drivers/power/supply/ab8500_chargalg.c index ff4b26b1cecae..9196434393e80 100644 --- a/drivers/power/supply/ab8500_chargalg.c +++ b/drivers/power/supply/ab8500_chargalg.c @@ -722,27 +722,29 @@ static void ab8500_chargalg_start_charging(struct ab8500_chargalg *di, */ static void ab8500_chargalg_check_temp(struct ab8500_chargalg *di) { - if (di->batt_data.temp > (di->bm->temp_low + di->t_hyst_norm) && - di->batt_data.temp < (di->bm->temp_high - di->t_hyst_norm)) { + struct power_supply_battery_info *bi = &di->bm->bi; + + if (di->batt_data.temp > (bi->temp_alert_min + di->t_hyst_norm) && + di->batt_data.temp < (bi->temp_alert_max - di->t_hyst_norm)) { /* Temp OK! */ di->events.btemp_underover = false; di->events.btemp_lowhigh = false; di->t_hyst_norm = 0; di->t_hyst_lowhigh = 0; } else { - if (((di->batt_data.temp >= di->bm->temp_high) && + if (((di->batt_data.temp >= bi->temp_alert_max) && (di->batt_data.temp < - (di->bm->temp_over - di->t_hyst_lowhigh))) || + (bi->temp_max - di->t_hyst_lowhigh))) || ((di->batt_data.temp > - (di->bm->temp_under + di->t_hyst_lowhigh)) && - (di->batt_data.temp <= di->bm->temp_low))) { + (bi->temp_min + di->t_hyst_lowhigh)) && + (di->batt_data.temp <= bi->temp_alert_min))) { /* TEMP minor!!!!! */ di->events.btemp_underover = false; di->events.btemp_lowhigh = true; di->t_hyst_norm = di->bm->temp_hysteresis; di->t_hyst_lowhigh = 0; - } else if (di->batt_data.temp <= di->bm->temp_under || - di->batt_data.temp >= di->bm->temp_over) { + } else if (di->batt_data.temp <= bi->temp_min || + di->batt_data.temp >= bi->temp_max) { /* TEMP major!!!!! */ di->events.btemp_underover = true; di->events.btemp_lowhigh = false; @@ -1722,7 +1724,7 @@ static int ab8500_chargalg_get_property(struct power_supply *psy, if (di->events.batt_ovv) { val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; } else if (di->events.btemp_underover) { - if (di->batt_data.temp <= di->bm->temp_under) + if (di->batt_data.temp <= di->bm->bi.temp_min) val->intval = POWER_SUPPLY_HEALTH_COLD; else val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c index 32c2046ea6bbf..7a151cd97399c 100644 --- a/drivers/power/supply/ab8500_charger.c +++ b/drivers/power/supply/ab8500_charger.c @@ -3709,6 +3709,7 @@ static int ab8500_charger_remove(struct platform_device *pdev) component_master_del(&pdev->dev, &ab8500_charger_comp_ops); usb_unregister_notifier(di->usb_phy, &di->nb); + ab8500_bm_of_remove(di->usb_chg.psy, di->bm); usb_put_phy(di->usb_phy); if (!di->ac_chg.enabled) blocking_notifier_chain_unregister( -- GitLab From d8d26ac12e182f2e7f2697b09fabe817b4238c2c Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:14 +0100 Subject: [PATCH 0120/1112] power: supply: ab8500: Drop unused battery types The code tries to detect a lot of battery variants on the reference designs, but we are not using the reference designs in practice, we are using real products such as Samsung Phones. The reference design with no battery plugged in will be detected as a LIPO battery with a thermistor on the batctrl pin so we will assume this and later on we can support other types through the device tree if we want, just like the products do. Drop the tables for external thermistor, only keep the internal thermistor tables that we will use as default. We can delete the assignment of the temperature to resistance table since the default will be the only and correct option. Also get rid of some unused variables and unused exports. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500_bmdata.c | 180 +-------------------------- 1 file changed, 1 insertion(+), 179 deletions(-) diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index 41561b6adfd38..8235c984e724a 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -39,10 +39,6 @@ const struct ab8500_res_to_temp ab8500_temp_tbl_a_thermistor[] = { {60, 13437}, {65, 12500}, }; -EXPORT_SYMBOL(ab8500_temp_tbl_a_thermistor); - -const int ab8500_temp_tbl_a_size = ARRAY_SIZE(ab8500_temp_tbl_a_thermistor); -EXPORT_SYMBOL(ab8500_temp_tbl_a_size); const struct ab8500_res_to_temp ab8500_temp_tbl_b_thermistor[] = { {-5, 200000}, @@ -61,10 +57,6 @@ const struct ab8500_res_to_temp ab8500_temp_tbl_b_thermistor[] = { {60, 85461}, {65, 82869}, }; -EXPORT_SYMBOL(ab8500_temp_tbl_b_thermistor); - -const int ab8500_temp_tbl_b_size = ARRAY_SIZE(ab8500_temp_tbl_b_thermistor); -EXPORT_SYMBOL(ab8500_temp_tbl_b_size); static const struct ab8500_v_to_cap cap_tbl_a_thermistor[] = { {4171, 100}, @@ -175,31 +167,6 @@ static const struct batres_vs_temp temp_to_batres_tbl_thermistor[] = { {-20, 595}, }; -/* - * Note that the batres_vs_temp table must be strictly sorted by falling - * temperature values to work. - */ -static const struct batres_vs_temp temp_to_batres_tbl_ext_thermistor[] = { - { 60, 300}, - { 30, 300}, - { 20, 300}, - { 10, 300}, - { 00, 300}, - {-10, 300}, - {-20, 300}, -}; - -/* battery resistance table for LI ION 9100 battery */ -static const struct batres_vs_temp temp_to_batres_tbl_9100[] = { - { 60, 180}, - { 30, 180}, - { 20, 180}, - { 10, 180}, - { 00, 180}, - {-10, 180}, - {-20, 180}, -}; - static struct ab8500_battery_type bat_type_thermistor[] = { [BATTERY_UNKNOWN] = { /* First element always represent the UNKNOWN battery */ @@ -286,123 +253,6 @@ static struct ab8500_battery_type bat_type_thermistor[] = { }, }; -static struct ab8500_battery_type bat_type_ext_thermistor[] = { - [BATTERY_UNKNOWN] = { - /* First element always represent the UNKNOWN battery */ - .name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN, - .resis_high = 0, - .resis_low = 0, - .battery_resistance = 300, - .charge_full_design = 612, - .nominal_voltage = 3700, - .termination_vol = 4050, - .termination_curr = 200, - .recharge_cap = 95, - .normal_cur_lvl = 400, - .normal_vol_lvl = 4100, - .maint_a_cur_lvl = 400, - .maint_a_vol_lvl = 4050, - .maint_a_chg_timer_h = 60, - .maint_b_cur_lvl = 400, - .maint_b_vol_lvl = 4000, - .maint_b_chg_timer_h = 200, - .low_high_cur_lvl = 300, - .low_high_vol_lvl = 4000, - .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl), - .r_to_t_tbl = temp_tbl, - .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl), - .v_to_cap_tbl = cap_tbl, - .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor), - .batres_tbl = temp_to_batres_tbl_thermistor, - }, -/* - * These are the batteries that doesn't have an internal NTC resistor to measure - * its temperature. The temperature in this case is measure with a NTC placed - * near the battery but on the PCB. - */ - { - .name = POWER_SUPPLY_TECHNOLOGY_LIPO, - .resis_high = 76000, - .resis_low = 53000, - .battery_resistance = 300, - .charge_full_design = 900, - .nominal_voltage = 3700, - .termination_vol = 4150, - .termination_curr = 100, - .recharge_cap = 95, - .normal_cur_lvl = 700, - .normal_vol_lvl = 4200, - .maint_a_cur_lvl = 600, - .maint_a_vol_lvl = 4150, - .maint_a_chg_timer_h = 60, - .maint_b_cur_lvl = 600, - .maint_b_vol_lvl = 4100, - .maint_b_chg_timer_h = 200, - .low_high_cur_lvl = 300, - .low_high_vol_lvl = 4000, - .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl), - .r_to_t_tbl = temp_tbl, - .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl), - .v_to_cap_tbl = cap_tbl, - .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor), - .batres_tbl = temp_to_batres_tbl_thermistor, - }, - { - .name = POWER_SUPPLY_TECHNOLOGY_LION, - .resis_high = 30000, - .resis_low = 10000, - .battery_resistance = 300, - .charge_full_design = 950, - .nominal_voltage = 3700, - .termination_vol = 4150, - .termination_curr = 100, - .recharge_cap = 95, - .normal_cur_lvl = 700, - .normal_vol_lvl = 4200, - .maint_a_cur_lvl = 600, - .maint_a_vol_lvl = 4150, - .maint_a_chg_timer_h = 60, - .maint_b_cur_lvl = 600, - .maint_b_vol_lvl = 4100, - .maint_b_chg_timer_h = 200, - .low_high_cur_lvl = 300, - .low_high_vol_lvl = 4000, - .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl), - .r_to_t_tbl = temp_tbl, - .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl), - .v_to_cap_tbl = cap_tbl, - .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor), - .batres_tbl = temp_to_batres_tbl_thermistor, - }, - { - .name = POWER_SUPPLY_TECHNOLOGY_LION, - .resis_high = 95000, - .resis_low = 76001, - .battery_resistance = 300, - .charge_full_design = 950, - .nominal_voltage = 3700, - .termination_vol = 4150, - .termination_curr = 100, - .recharge_cap = 95, - .normal_cur_lvl = 700, - .normal_vol_lvl = 4200, - .maint_a_cur_lvl = 600, - .maint_a_vol_lvl = 4150, - .maint_a_chg_timer_h = 60, - .maint_b_cur_lvl = 600, - .maint_b_vol_lvl = 4100, - .maint_b_chg_timer_h = 200, - .low_high_cur_lvl = 300, - .low_high_vol_lvl = 4000, - .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl), - .r_to_t_tbl = temp_tbl, - .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl), - .v_to_cap_tbl = cap_tbl, - .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor), - .batres_tbl = temp_to_batres_tbl_thermistor, - }, -}; - static const struct ab8500_bm_capacity_levels cap_levels = { .critical = 2, .low = 10, @@ -447,6 +297,7 @@ static const struct ab8500_bm_charger_parameters chg = { .ac_curr_max = 1500, }; +/* This is referenced directly in the charger code */ struct ab8500_bm_data ab8500_bm_data = { .main_safety_tmr_h = 4, .temp_interval_chg = 20, @@ -475,11 +326,9 @@ struct ab8500_bm_data ab8500_bm_data = { int ab8500_bm_of_probe(struct power_supply *psy, struct ab8500_bm_data *bm) { - const struct batres_vs_temp *tmp_batres_tbl; struct power_supply_battery_info *bi = &bm->bi; struct device *dev = &psy->dev; int ret; - int i; ret = power_supply_get_battery_info(psy, bi); if (ret) { @@ -497,33 +346,6 @@ int ab8500_bm_of_probe(struct power_supply *psy, bi->temp_alert_max = AB8500_TEMP_HIGH; bm->temp_hysteresis = AB8500_TEMP_HYSTERESIS; - - if (bi->technology == POWER_SUPPLY_TECHNOLOGY_LION) { - bm->no_maintenance = true; - bm->chg_unknown_bat = true; - bm->bat_type[BATTERY_UNKNOWN].charge_full_design = 2600; - bm->bat_type[BATTERY_UNKNOWN].termination_vol = 4150; - bm->bat_type[BATTERY_UNKNOWN].recharge_cap = 95; - bm->bat_type[BATTERY_UNKNOWN].normal_cur_lvl = 520; - bm->bat_type[BATTERY_UNKNOWN].normal_vol_lvl = 4200; - } - - if (of_property_read_bool(psy->of_node, "thermistor-on-batctrl")) { - if (bi->technology == POWER_SUPPLY_TECHNOLOGY_LION) - tmp_batres_tbl = temp_to_batres_tbl_9100; - else - tmp_batres_tbl = temp_to_batres_tbl_thermistor; - } else { - bm->n_btypes = 4; - bm->bat_type = bat_type_ext_thermistor; - bm->adc_therm = AB8500_ADC_THERM_BATTEMP; - tmp_batres_tbl = temp_to_batres_tbl_ext_thermistor; - } - - /* select the battery resolution table */ - for (i = 0; i < bm->n_btypes; ++i) - bm->bat_type[i].batres_tbl = tmp_batres_tbl; - return 0; } -- GitLab From e5dff305ab5c539320f1e30db44604e9977c3504 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:15 +0100 Subject: [PATCH 0121/1112] power: supply: ab8500: Use only one battery type The code was going through hoops and loops to detect what battery is connected and check the resistance for this battery etc. Skip this trouble: we will support one battery (currently "unknown") then we will find the connected battery in the device tree using a compatible string. The battery resistance may be used to double-check that the right battery is connected. Convert the array of battery types into one battery type so we can next move over the properties of this one type into the standard struct power_supply_battery_info. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 4 - drivers/power/supply/ab8500_bmdata.c | 203 ++++--------------------- drivers/power/supply/ab8500_btemp.c | 61 ++++---- drivers/power/supply/ab8500_chargalg.c | 51 +++---- drivers/power/supply/ab8500_fg.c | 17 ++- 5 files changed, 85 insertions(+), 251 deletions(-) diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index fe783610bc544..99ada7f08ec77 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -475,8 +475,6 @@ struct ab8500_bm_charger_parameters { * @enable_overshoot flag to enable VBAT overshoot control * @auto_trig flag to enable auto adc trigger * @fg_res resistance of FG resistor in 0.1mOhm - * @n_btypes number of elements in array bat_type - * @batt_id index of the identified battery in array bat_type * @interval_charging charge alg cycle period time when charging (sec) * @interval_not_charging charge alg cycle period time when not charging (sec) * @temp_hysteresis temperature hysteresis @@ -503,8 +501,6 @@ struct ab8500_bm_data { bool auto_trig; enum ab8500_adc_therm adc_therm; int fg_res; - int n_btypes; - int batt_id; int interval_charging; int interval_not_charging; int temp_hysteresis; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index 8235c984e724a..5db13b026d812 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -16,94 +16,6 @@ /* Default: temperature hysteresis */ #define AB8500_TEMP_HYSTERESIS 3 -/* - * These are the defined batteries that uses a NTC and ID resistor placed - * inside of the battery pack. - * Note that the res_to_temp table must be strictly sorted by falling resistance - * values to work. - */ -const struct ab8500_res_to_temp ab8500_temp_tbl_a_thermistor[] = { - {-5, 53407}, - { 0, 48594}, - { 5, 43804}, - {10, 39188}, - {15, 34870}, - {20, 30933}, - {25, 27422}, - {30, 24347}, - {35, 21694}, - {40, 19431}, - {45, 17517}, - {50, 15908}, - {55, 14561}, - {60, 13437}, - {65, 12500}, -}; - -const struct ab8500_res_to_temp ab8500_temp_tbl_b_thermistor[] = { - {-5, 200000}, - { 0, 159024}, - { 5, 151921}, - {10, 144300}, - {15, 136424}, - {20, 128565}, - {25, 120978}, - {30, 113875}, - {35, 107397}, - {40, 101629}, - {45, 96592}, - {50, 92253}, - {55, 88569}, - {60, 85461}, - {65, 82869}, -}; - -static const struct ab8500_v_to_cap cap_tbl_a_thermistor[] = { - {4171, 100}, - {4114, 95}, - {4009, 83}, - {3947, 74}, - {3907, 67}, - {3863, 59}, - {3830, 56}, - {3813, 53}, - {3791, 46}, - {3771, 33}, - {3754, 25}, - {3735, 20}, - {3717, 17}, - {3681, 13}, - {3664, 8}, - {3651, 6}, - {3635, 5}, - {3560, 3}, - {3408, 1}, - {3247, 0}, -}; - -static const struct ab8500_v_to_cap cap_tbl_b_thermistor[] = { - {4161, 100}, - {4124, 98}, - {4044, 90}, - {4003, 85}, - {3966, 80}, - {3933, 75}, - {3888, 67}, - {3849, 60}, - {3813, 55}, - {3787, 47}, - {3772, 30}, - {3751, 25}, - {3718, 20}, - {3681, 16}, - {3660, 14}, - {3589, 10}, - {3546, 7}, - {3495, 4}, - {3404, 2}, - {3250, 0}, -}; - static const struct ab8500_v_to_cap cap_tbl[] = { {4186, 100}, {4163, 99}, @@ -167,90 +79,33 @@ static const struct batres_vs_temp temp_to_batres_tbl_thermistor[] = { {-20, 595}, }; -static struct ab8500_battery_type bat_type_thermistor[] = { - [BATTERY_UNKNOWN] = { - /* First element always represent the UNKNOWN battery */ - .name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN, - .resis_high = 0, - .resis_low = 0, - .battery_resistance = 300, - .charge_full_design = 612, - .nominal_voltage = 3700, - .termination_vol = 4050, - .termination_curr = 200, - .recharge_cap = 95, - .normal_cur_lvl = 400, - .normal_vol_lvl = 4100, - .maint_a_cur_lvl = 400, - .maint_a_vol_lvl = 4050, - .maint_a_chg_timer_h = 60, - .maint_b_cur_lvl = 400, - .maint_b_vol_lvl = 4000, - .maint_b_chg_timer_h = 200, - .low_high_cur_lvl = 300, - .low_high_vol_lvl = 4000, - .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl), - .r_to_t_tbl = temp_tbl, - .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl), - .v_to_cap_tbl = cap_tbl, - .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor), - .batres_tbl = temp_to_batres_tbl_thermistor, - }, - { - .name = POWER_SUPPLY_TECHNOLOGY_LIPO, - .resis_high = 53407, - .resis_low = 12500, - .battery_resistance = 300, - .charge_full_design = 900, - .nominal_voltage = 3600, - .termination_vol = 4150, - .termination_curr = 80, - .recharge_cap = 95, - .normal_cur_lvl = 700, - .normal_vol_lvl = 4200, - .maint_a_cur_lvl = 600, - .maint_a_vol_lvl = 4150, - .maint_a_chg_timer_h = 60, - .maint_b_cur_lvl = 600, - .maint_b_vol_lvl = 4100, - .maint_b_chg_timer_h = 200, - .low_high_cur_lvl = 300, - .low_high_vol_lvl = 4000, - .n_temp_tbl_elements = ARRAY_SIZE(ab8500_temp_tbl_a_thermistor), - .r_to_t_tbl = ab8500_temp_tbl_a_thermistor, - .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_a_thermistor), - .v_to_cap_tbl = cap_tbl_a_thermistor, - .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor), - .batres_tbl = temp_to_batres_tbl_thermistor, - - }, - { - .name = POWER_SUPPLY_TECHNOLOGY_LIPO, - .resis_high = 200000, - .resis_low = 82869, - .battery_resistance = 300, - .charge_full_design = 900, - .nominal_voltage = 3600, - .termination_vol = 4150, - .termination_curr = 80, - .recharge_cap = 95, - .normal_cur_lvl = 700, - .normal_vol_lvl = 4200, - .maint_a_cur_lvl = 600, - .maint_a_vol_lvl = 4150, - .maint_a_chg_timer_h = 60, - .maint_b_cur_lvl = 600, - .maint_b_vol_lvl = 4100, - .maint_b_chg_timer_h = 200, - .low_high_cur_lvl = 300, - .low_high_vol_lvl = 4000, - .n_temp_tbl_elements = ARRAY_SIZE(ab8500_temp_tbl_b_thermistor), - .r_to_t_tbl = ab8500_temp_tbl_b_thermistor, - .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_b_thermistor), - .v_to_cap_tbl = cap_tbl_b_thermistor, - .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor), - .batres_tbl = temp_to_batres_tbl_thermistor, - }, +/* Default battery type for reference designs is the unknown type */ +static struct ab8500_battery_type bat_type_thermistor_unknown = { + .name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN, + .resis_high = 0, + .resis_low = 0, + .battery_resistance = 300, + .charge_full_design = 612, + .nominal_voltage = 3700, + .termination_vol = 4050, + .termination_curr = 200, + .recharge_cap = 95, + .normal_cur_lvl = 400, + .normal_vol_lvl = 4100, + .maint_a_cur_lvl = 400, + .maint_a_vol_lvl = 4050, + .maint_a_chg_timer_h = 60, + .maint_b_cur_lvl = 400, + .maint_b_vol_lvl = 4000, + .maint_b_chg_timer_h = 200, + .low_high_cur_lvl = 300, + .low_high_vol_lvl = 4000, + .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl), + .r_to_t_tbl = temp_tbl, + .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl), + .v_to_cap_tbl = cap_tbl, + .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor), + .batres_tbl = temp_to_batres_tbl_thermistor, }; static const struct ab8500_bm_capacity_levels cap_levels = { @@ -312,9 +167,7 @@ struct ab8500_bm_data ab8500_bm_data = { .enable_overshoot = false, .fg_res = 100, .cap_levels = &cap_levels, - .bat_type = bat_type_thermistor, - .n_btypes = ARRAY_SIZE(bat_type_thermistor), - .batt_id = 0, + .bat_type = &bat_type_thermistor_unknown, .interval_charging = 5, .interval_not_charging = 120, .gnd_lift_resistance = 34, diff --git a/drivers/power/supply/ab8500_btemp.c b/drivers/power/supply/ab8500_btemp.c index b6c9111d77d7d..fbb58074efab9 100644 --- a/drivers/power/supply/ab8500_btemp.c +++ b/drivers/power/supply/ab8500_btemp.c @@ -454,12 +454,9 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) int temp, ret; static int prev; int rbat, rntc, vntc; - u8 id; - id = di->bm->batt_id; - - if (di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL && - id != BATTERY_UNKNOWN) { + if ((di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL) && + (di->bm->bat_type->name == POWER_SUPPLY_TECHNOLOGY_UNKNOWN)) { rbat = ab8500_btemp_get_batctrl_res(di); if (rbat < 0) { @@ -473,8 +470,8 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) } temp = ab8500_btemp_res_to_temp(di, - di->bm->bat_type[id].r_to_t_tbl, - di->bm->bat_type[id].n_temp_tbl_elements, rbat); + di->bm->bat_type->r_to_t_tbl, + di->bm->bat_type->n_temp_tbl_elements, rbat); } else { ret = iio_read_channel_processed(di->btemp_ball, &vntc); if (ret < 0) { @@ -490,8 +487,8 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) rntc = 230000 * vntc / (VTVOUT_V - vntc); temp = ab8500_btemp_res_to_temp(di, - di->bm->bat_type[id].r_to_t_tbl, - di->bm->bat_type[id].n_temp_tbl_elements, rntc); + di->bm->bat_type->r_to_t_tbl, + di->bm->bat_type->n_temp_tbl_elements, rntc); prev = temp; } dev_dbg(di->dev, "Battery temperature is %d\n", temp); @@ -512,7 +509,6 @@ static int ab8500_btemp_id(struct ab8500_btemp *di) u8 i; di->curr_source = BTEMP_BATCTRL_CURR_SRC_7UA; - di->bm->batt_id = BATTERY_UNKNOWN; res = ab8500_btemp_get_batctrl_res(di); if (res < 0) { @@ -520,40 +516,37 @@ static int ab8500_btemp_id(struct ab8500_btemp *di) return -ENXIO; } - /* BATTERY_UNKNOWN is defined on position 0, skip it! */ - for (i = BATTERY_UNKNOWN + 1; i < di->bm->n_btypes; i++) { - if ((res <= di->bm->bat_type[i].resis_high) && - (res >= di->bm->bat_type[i].resis_low)) { - dev_dbg(di->dev, "Battery detected on %s" - " low %d < res %d < high: %d" - " index: %d\n", - di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL ? - "BATCTRL" : "BATTEMP", - di->bm->bat_type[i].resis_low, res, - di->bm->bat_type[i].resis_high, i); - - di->bm->batt_id = i; - break; - } - } - - if (di->bm->batt_id == BATTERY_UNKNOWN) { + if ((res <= di->bm->bat_type->resis_high) && + (res >= di->bm->bat_type->resis_low)) { + dev_info(di->dev, "Battery detected on %s" + " low %d < res %d < high: %d" + " index: %d\n", + di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL ? + "BATCTRL" : "BATTEMP", + di->bm->bat_type->resis_low, res, + di->bm->bat_type->resis_high, i); + } else { dev_warn(di->dev, "Battery identified as unknown" - ", resistance %d Ohm\n", res); + ", resistance %d Ohm\n", res); return -ENXIO; } /* * We only have to change current source if the - * detected type is Type 1. + * detected type is Type 1 (LIPO) resis_high = 53407, resis_low = 12500 + * if someone hacks this in. + * + * FIXME: make sure this is done automatically for the batteries + * that need it. */ - if (di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL && - di->bm->batt_id == 1) { + if ((di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL) && + (di->bm->bat_type->name == POWER_SUPPLY_TECHNOLOGY_LIPO) && + (res <= 53407) && (res >= 12500)) { dev_dbg(di->dev, "Set BATCTRL current source to 20uA\n"); di->curr_source = BTEMP_BATCTRL_CURR_SRC_20UA; } - return di->bm->batt_id; + return 0; } /** @@ -814,7 +807,7 @@ static int ab8500_btemp_get_property(struct power_supply *psy, val->intval = 1; break; case POWER_SUPPLY_PROP_TECHNOLOGY: - val->intval = di->bm->bat_type[di->bm->batt_id].name; + val->intval = di->bm->bat_type->name; break; case POWER_SUPPLY_PROP_TEMP: val->intval = ab8500_btemp_get_temp(di); diff --git a/drivers/power/supply/ab8500_chargalg.c b/drivers/power/supply/ab8500_chargalg.c index 9196434393e80..a5ccfb0aa9f4d 100644 --- a/drivers/power/supply/ab8500_chargalg.c +++ b/drivers/power/supply/ab8500_chargalg.c @@ -356,13 +356,13 @@ static int ab8500_chargalg_check_charger_enable(struct ab8500_chargalg *di) if (di->chg_info.charger_type & USB_CHG) { return di->usb_chg->ops.check_enable(di->usb_chg, - di->bm->bat_type[di->bm->batt_id].normal_vol_lvl, - di->bm->bat_type[di->bm->batt_id].normal_cur_lvl); + di->bm->bat_type->normal_vol_lvl, + di->bm->bat_type->normal_cur_lvl); } else if ((di->chg_info.charger_type & AC_CHG) && !(di->ac_chg->external)) { return di->ac_chg->ops.check_enable(di->ac_chg, - di->bm->bat_type[di->bm->batt_id].normal_vol_lvl, - di->bm->bat_type[di->bm->batt_id].normal_cur_lvl); + di->bm->bat_type->normal_vol_lvl, + di->bm->bat_type->normal_cur_lvl); } return 0; } @@ -793,10 +793,10 @@ static void ab8500_chargalg_end_of_charge(struct ab8500_chargalg *di) if (di->charge_status == POWER_SUPPLY_STATUS_CHARGING && di->charge_state == STATE_NORMAL && !di->maintenance_chg && (di->batt_data.volt >= - di->bm->bat_type[di->bm->batt_id].termination_vol || + di->bm->bat_type->termination_vol || di->events.usb_cv_active || di->events.ac_cv_active) && di->batt_data.avg_curr < - di->bm->bat_type[di->bm->batt_id].termination_curr && + di->bm->bat_type->termination_curr && di->batt_data.avg_curr > 0) { if (++di->eoc_cnt >= EOC_COND_CNT) { di->eoc_cnt = 0; @@ -819,9 +819,9 @@ static void ab8500_chargalg_end_of_charge(struct ab8500_chargalg *di) static void init_maxim_chg_curr(struct ab8500_chargalg *di) { di->ccm.original_iset = - di->bm->bat_type[di->bm->batt_id].normal_cur_lvl; + di->bm->bat_type->normal_cur_lvl; di->ccm.current_iset = - di->bm->bat_type[di->bm->batt_id].normal_cur_lvl; + di->bm->bat_type->normal_cur_lvl; di->ccm.test_delta_i = di->bm->maxi->charger_curr_step; di->ccm.max_current = di->bm->maxi->chg_curr; di->ccm.condition_cnt = di->bm->maxi->wait_cycles; @@ -924,7 +924,7 @@ static void handle_maxim_chg_curr(struct ab8500_chargalg *di) break; case MAXIM_RET_IBAT_TOO_HIGH: result = ab8500_chargalg_update_chg_curr(di, - di->bm->bat_type[di->bm->batt_id].normal_cur_lvl); + di->bm->bat_type->normal_cur_lvl); if (result) dev_err(di->dev, "failed to set chg curr\n"); break; @@ -1505,13 +1505,12 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) if (di->curr_status.curr_step == CHARGALG_CURR_STEP_LOW) ab8500_chargalg_stop_charging(di); else { - curr_step_lvl = di->bm->bat_type[ - di->bm->batt_id].normal_cur_lvl + curr_step_lvl = di->bm->bat_type->normal_cur_lvl * di->curr_status.curr_step / CHARGALG_CURR_STEP_HIGH; ab8500_chargalg_start_charging(di, - di->bm->bat_type[di->bm->batt_id] - .normal_vol_lvl, curr_step_lvl); + di->bm->bat_type->normal_vol_lvl, + curr_step_lvl); } ab8500_chargalg_state_to(di, STATE_NORMAL); @@ -1546,20 +1545,17 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) case STATE_WAIT_FOR_RECHARGE: if (di->batt_data.percent <= - di->bm->bat_type[di->bm->batt_id].recharge_cap) + di->bm->bat_type->recharge_cap) ab8500_chargalg_state_to(di, STATE_NORMAL_INIT); break; case STATE_MAINTENANCE_A_INIT: ab8500_chargalg_stop_safety_timer(di); ab8500_chargalg_start_maintenance_timer(di, - di->bm->bat_type[ - di->bm->batt_id].maint_a_chg_timer_h); + di->bm->bat_type->maint_a_chg_timer_h); ab8500_chargalg_start_charging(di, - di->bm->bat_type[ - di->bm->batt_id].maint_a_vol_lvl, - di->bm->bat_type[ - di->bm->batt_id].maint_a_cur_lvl); + di->bm->bat_type->maint_a_vol_lvl, + di->bm->bat_type->maint_a_cur_lvl); ab8500_chargalg_state_to(di, STATE_MAINTENANCE_A); power_supply_changed(di->chargalg_psy); fallthrough; @@ -1573,13 +1569,10 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) case STATE_MAINTENANCE_B_INIT: ab8500_chargalg_start_maintenance_timer(di, - di->bm->bat_type[ - di->bm->batt_id].maint_b_chg_timer_h); + di->bm->bat_type->maint_b_chg_timer_h); ab8500_chargalg_start_charging(di, - di->bm->bat_type[ - di->bm->batt_id].maint_b_vol_lvl, - di->bm->bat_type[ - di->bm->batt_id].maint_b_cur_lvl); + di->bm->bat_type->maint_b_vol_lvl, + di->bm->bat_type->maint_b_cur_lvl); ab8500_chargalg_state_to(di, STATE_MAINTENANCE_B); power_supply_changed(di->chargalg_psy); fallthrough; @@ -1593,10 +1586,8 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) case STATE_TEMP_LOWHIGH_INIT: ab8500_chargalg_start_charging(di, - di->bm->bat_type[ - di->bm->batt_id].low_high_vol_lvl, - di->bm->bat_type[ - di->bm->batt_id].low_high_cur_lvl); + di->bm->bat_type->low_high_vol_lvl, + di->bm->bat_type->low_high_cur_lvl); ab8500_chargalg_stop_maintenance_timer(di); di->charge_status = POWER_SUPPLY_STATUS_CHARGING; ab8500_chargalg_state_to(di, STATE_TEMP_LOWHIGH); diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index 05fe9724ba508..2013db0118ee3 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -857,8 +857,8 @@ static int ab8500_fg_volt_to_capacity(struct ab8500_fg *di, int voltage) const struct ab8500_v_to_cap *tbl; int cap = 0; - tbl = di->bm->bat_type[di->bm->batt_id].v_to_cap_tbl; - tbl_size = di->bm->bat_type[di->bm->batt_id].n_v_cap_tbl_elements; + tbl = di->bm->bat_type->v_to_cap_tbl; + tbl_size = di->bm->bat_type->n_v_cap_tbl_elements; for (i = 0; i < tbl_size; ++i) { if (voltage > tbl[i].voltage) @@ -910,8 +910,8 @@ static int ab8500_fg_battery_resistance(struct ab8500_fg *di) const struct batres_vs_temp *tbl; int resist = 0; - tbl = di->bm->bat_type[di->bm->batt_id].batres_tbl; - tbl_size = di->bm->bat_type[di->bm->batt_id].n_batres_tbl_elements; + tbl = di->bm->bat_type->batres_tbl; + tbl_size = di->bm->bat_type->n_batres_tbl_elements; for (i = 0; i < tbl_size; ++i) { if (di->bat_temp / 10 > tbl[i].temp) @@ -2234,10 +2234,11 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data) switch (ext->desc->type) { case POWER_SUPPLY_TYPE_BATTERY: if (!di->flags.batt_id_received && - di->bm->batt_id != BATTERY_UNKNOWN) { + (di->bm->bat_type->name != + POWER_SUPPLY_TECHNOLOGY_UNKNOWN)) { const struct ab8500_battery_type *b; - b = &(di->bm->bat_type[di->bm->batt_id]); + b = di->bm->bat_type; di->flags.batt_id_received = true; @@ -3078,11 +3079,11 @@ static int ab8500_fg_probe(struct platform_device *pdev) psy_cfg.drv_data = di; di->bat_cap.max_mah_design = MILLI_TO_MICRO * - di->bm->bat_type[di->bm->batt_id].charge_full_design; + di->bm->bat_type->charge_full_design; di->bat_cap.max_mah = di->bat_cap.max_mah_design; - di->vbat_nom = di->bm->bat_type[di->bm->batt_id].nominal_voltage; + di->vbat_nom = di->bm->bat_type->nominal_voltage; di->init_capacity = true; -- GitLab From 22be8d77c80dca59af004d4595699b2092670499 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:16 +0100 Subject: [PATCH 0122/1112] power: supply: ab8500: Standardize design capacity Now that we know that we have only one battery type to deal with we can proceed to transfer properties to struct power_supply_battery_info. The designed capacity for the battery was in a custom field of the custom battery type in mAh, transfer this to the standard charge_full_design_uah property in struct power_supply_battery_info and augment the code accordingly. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 2 -- drivers/power/supply/ab8500_bmdata.c | 5 ++++- drivers/power/supply/ab8500_fg.c | 8 ++------ 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index 99ada7f08ec77..a5cae92882749 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -375,7 +375,6 @@ struct ab8500_maxim_parameters { * @name: battery technology * @resis_high: battery upper resistance limit * @resis_low: battery lower resistance limit - * @charge_full_design: Maximum battery capacity in mAh * @nominal_voltage: Nominal voltage of the battery in mV * @termination_vol: max voltage upto which battery can be charged * @termination_curr battery charging termination current in mA @@ -404,7 +403,6 @@ struct ab8500_battery_type { int name; int resis_high; int resis_low; - int charge_full_design; int nominal_voltage; int termination_vol; int termination_curr; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index 5db13b026d812..2d328d3007a94 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -85,7 +85,6 @@ static struct ab8500_battery_type bat_type_thermistor_unknown = { .resis_high = 0, .resis_low = 0, .battery_resistance = 300, - .charge_full_design = 612, .nominal_voltage = 3700, .termination_vol = 4050, .termination_curr = 200, @@ -189,6 +188,10 @@ int ab8500_bm_of_probe(struct power_supply *psy, return ret; } + /* Fill in defaults for any data missing from the device tree */ + if (bi->charge_full_design_uah < 0) + /* The default capacity is 612 mAh for unknown batteries */ + bi->charge_full_design_uah = 612000; if (bi->temp_min == INT_MIN) bi->temp_min = AB8500_TEMP_UNDER; if (bi->temp_max == INT_MAX) diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index 2013db0118ee3..4f8b3a76c5652 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -38,7 +38,6 @@ #include "ab8500-bm.h" -#define MILLI_TO_MICRO 1000 #define FG_LSB_IN_MA 1627 #define QLSB_NANO_AMP_HOURS_X10 1071 #define INS_CURR_TIMEOUT (3 * HZ) @@ -2243,8 +2242,7 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data) di->flags.batt_id_received = true; di->bat_cap.max_mah_design = - MILLI_TO_MICRO * - b->charge_full_design; + di->bm->bi.charge_full_design_uah; di->bat_cap.max_mah = di->bat_cap.max_mah_design; @@ -3078,9 +3076,7 @@ static int ab8500_fg_probe(struct platform_device *pdev) psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface); psy_cfg.drv_data = di; - di->bat_cap.max_mah_design = MILLI_TO_MICRO * - di->bm->bat_type->charge_full_design; - + di->bat_cap.max_mah_design = di->bm->bi.charge_full_design_uah; di->bat_cap.max_mah = di->bat_cap.max_mah_design; di->vbat_nom = di->bm->bat_type->nominal_voltage; -- GitLab From 2d3559a50ad6d21552ed2434889bc568acfa2a83 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:17 +0100 Subject: [PATCH 0123/1112] power: supply: ab8500: Standardize technology The AB8500 custom battery type can be replaced by the corresponding struct power_supply_battery_info field. Remove the struct member and amend the code to use the standard property. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 2 -- drivers/power/supply/ab8500_bmdata.c | 1 - drivers/power/supply/ab8500_btemp.c | 6 +++--- drivers/power/supply/ab8500_fg.c | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index a5cae92882749..750d1a962f39f 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -372,7 +372,6 @@ struct ab8500_maxim_parameters { /** * struct ab8500_battery_type - different batteries supported - * @name: battery technology * @resis_high: battery upper resistance limit * @resis_low: battery lower resistance limit * @nominal_voltage: Nominal voltage of the battery in mV @@ -400,7 +399,6 @@ struct ab8500_maxim_parameters { * @batres_tbl battery internal resistance vs temperature table */ struct ab8500_battery_type { - int name; int resis_high; int resis_low; int nominal_voltage; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index 2d328d3007a94..44d7c568949f3 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -81,7 +81,6 @@ static const struct batres_vs_temp temp_to_batres_tbl_thermistor[] = { /* Default battery type for reference designs is the unknown type */ static struct ab8500_battery_type bat_type_thermistor_unknown = { - .name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN, .resis_high = 0, .resis_low = 0, .battery_resistance = 300, diff --git a/drivers/power/supply/ab8500_btemp.c b/drivers/power/supply/ab8500_btemp.c index fbb58074efab9..20253b8a7fe9f 100644 --- a/drivers/power/supply/ab8500_btemp.c +++ b/drivers/power/supply/ab8500_btemp.c @@ -456,7 +456,7 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) int rbat, rntc, vntc; if ((di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL) && - (di->bm->bat_type->name == POWER_SUPPLY_TECHNOLOGY_UNKNOWN)) { + (di->bm->bi.technology == POWER_SUPPLY_TECHNOLOGY_UNKNOWN)) { rbat = ab8500_btemp_get_batctrl_res(di); if (rbat < 0) { @@ -540,7 +540,7 @@ static int ab8500_btemp_id(struct ab8500_btemp *di) * that need it. */ if ((di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL) && - (di->bm->bat_type->name == POWER_SUPPLY_TECHNOLOGY_LIPO) && + (di->bm->bi.technology == POWER_SUPPLY_TECHNOLOGY_LIPO) && (res <= 53407) && (res >= 12500)) { dev_dbg(di->dev, "Set BATCTRL current source to 20uA\n"); di->curr_source = BTEMP_BATCTRL_CURR_SRC_20UA; @@ -807,7 +807,7 @@ static int ab8500_btemp_get_property(struct power_supply *psy, val->intval = 1; break; case POWER_SUPPLY_PROP_TECHNOLOGY: - val->intval = di->bm->bat_type->name; + val->intval = di->bm->bi.technology; break; case POWER_SUPPLY_PROP_TEMP: val->intval = ab8500_btemp_get_temp(di); diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index 4f8b3a76c5652..c6237c4f4721c 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -2233,7 +2233,7 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data) switch (ext->desc->type) { case POWER_SUPPLY_TYPE_BATTERY: if (!di->flags.batt_id_received && - (di->bm->bat_type->name != + (di->bm->bi.technology != POWER_SUPPLY_TECHNOLOGY_UNKNOWN)) { const struct ab8500_battery_type *b; -- GitLab From 2a5f41830aadc2d7f4145eae49381133da5df2a3 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:18 +0100 Subject: [PATCH 0124/1112] power: supply: ab8500: Standardize voltages The nominal voltage in this charge driver corresponds to both the voltage_min_design_uv and voltage_max_design_uv of struct power_supply_battery_info so assign both if this is undefined. The overcharge max voltage (when the charger should cut off) is migrated at the same time so we move both voltages to struct power_supply_battery_info. Adjust the code to deal directly with the microvolt values instead of converting them to millivolts. Add *_uv suffixes for clarity and to make sure we have changed all code sites using this member. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 4 ---- drivers/power/supply/ab8500_bmdata.c | 17 +++++++++++++++-- drivers/power/supply/ab8500_chargalg.c | 10 +++++----- drivers/power/supply/ab8500_fg.c | 21 +++++++++++++-------- 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index 750d1a962f39f..b21d3a99471f5 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -374,8 +374,6 @@ struct ab8500_maxim_parameters { * struct ab8500_battery_type - different batteries supported * @resis_high: battery upper resistance limit * @resis_low: battery lower resistance limit - * @nominal_voltage: Nominal voltage of the battery in mV - * @termination_vol: max voltage upto which battery can be charged * @termination_curr battery charging termination current in mA * @recharge_cap battery capacity limit that will trigger a new * full charging cycle in the case where maintenan- @@ -401,8 +399,6 @@ struct ab8500_maxim_parameters { struct ab8500_battery_type { int resis_high; int resis_low; - int nominal_voltage; - int termination_vol; int termination_curr; int recharge_cap; int normal_cur_lvl; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index 44d7c568949f3..684cefccebd10 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -84,8 +84,6 @@ static struct ab8500_battery_type bat_type_thermistor_unknown = { .resis_high = 0, .resis_low = 0, .battery_resistance = 300, - .nominal_voltage = 3700, - .termination_vol = 4050, .termination_curr = 200, .recharge_cap = 95, .normal_cur_lvl = 400, @@ -191,6 +189,21 @@ int ab8500_bm_of_probe(struct power_supply *psy, if (bi->charge_full_design_uah < 0) /* The default capacity is 612 mAh for unknown batteries */ bi->charge_full_design_uah = 612000; + + /* + * All of these voltages need to be specified or we will simply + * fall back to safe defaults. + */ + if ((bi->voltage_min_design_uv < 0) || + (bi->voltage_max_design_uv < 0) || + (bi->overvoltage_limit_uv < 0)) { + /* Nominal voltage is 3.7V for unknown batteries */ + bi->voltage_min_design_uv = 3700000; + bi->voltage_max_design_uv = 3700000; + /* Termination voltage (overcharge limit) 4.05V */ + bi->overvoltage_limit_uv = 4050000; + } + if (bi->temp_min == INT_MIN) bi->temp_min = AB8500_TEMP_UNDER; if (bi->temp_max == INT_MAX) diff --git a/drivers/power/supply/ab8500_chargalg.c b/drivers/power/supply/ab8500_chargalg.c index a5ccfb0aa9f4d..dd9cad63e37ea 100644 --- a/drivers/power/supply/ab8500_chargalg.c +++ b/drivers/power/supply/ab8500_chargalg.c @@ -86,7 +86,7 @@ struct ab8500_chargalg_current_step_status { struct ab8500_chargalg_battery_data { int temp; - int volt; + int volt_uv; int avg_curr; int inst_curr; int percent; @@ -792,8 +792,8 @@ static void ab8500_chargalg_end_of_charge(struct ab8500_chargalg *di) { if (di->charge_status == POWER_SUPPLY_STATUS_CHARGING && di->charge_state == STATE_NORMAL && - !di->maintenance_chg && (di->batt_data.volt >= - di->bm->bat_type->termination_vol || + !di->maintenance_chg && (di->batt_data.volt_uv >= + di->bm->bi.overvoltage_limit_uv || di->events.usb_cv_active || di->events.ac_cv_active) && di->batt_data.avg_curr < di->bm->bat_type->termination_curr && @@ -1160,7 +1160,7 @@ static int ab8500_chargalg_get_ext_psy_data(struct device *dev, void *data) case POWER_SUPPLY_PROP_VOLTAGE_NOW: switch (ext->desc->type) { case POWER_SUPPLY_TYPE_BATTERY: - di->batt_data.volt = ret.intval / 1000; + di->batt_data.volt_uv = ret.intval; break; case POWER_SUPPLY_TYPE_MAINS: di->chg_info.ac_volt = ret.intval / 1000; @@ -1397,7 +1397,7 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) "State %s Active_chg %d Chg_status %d AC %d USB %d " "AC_online %d USB_online %d AC_CV %d USB_CV %d AC_I %d " "USB_I %d AC_Vset %d AC_Iset %d USB_Vset %d USB_Iset %d\n", - di->batt_data.volt, + di->batt_data.volt_uv, di->batt_data.avg_curr, di->batt_data.inst_curr, di->batt_data.temp, diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index c6237c4f4721c..ab6141faa798b 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -157,7 +157,7 @@ struct inst_curr_result_list { * @node: a list of AB8500 FGs, hence prepared for reentrance * @irq holds the CCEOC interrupt number * @vbat: Battery voltage in mV - * @vbat_nom: Nominal battery voltage in mV + * @vbat_nom_uv: Nominal battery voltage in uV * @inst_curr: Instantenous battery current in mA * @avg_curr: Average battery current in mA * @bat_temp battery temperature @@ -199,7 +199,7 @@ struct ab8500_fg { struct list_head node; int irq; int vbat; - int vbat_nom; + int vbat_nom_uv; int inst_curr; int avg_curr; int bat_temp; @@ -1013,11 +1013,16 @@ static int ab8500_fg_convert_mah_to_uwh(struct ab8500_fg *di, int cap_mah) u64 div_res; u32 div_rem; - div_res = ((u64) cap_mah) * ((u64) di->vbat_nom); - div_rem = do_div(div_res, 1000); + /* + * Capacity is in milli ampere hours (10^-3)Ah + * Nominal voltage is in microvolts (10^-6)V + * divide by 1000000 after multiplication to get to mWh + */ + div_res = ((u64) cap_mah) * ((u64) di->vbat_nom_uv); + div_rem = do_div(div_res, 1000000); /* Make sure to round upwards if necessary */ - if (div_rem >= 1000 / 2) + if (div_rem >= 1000000 / 2) div_res++; return (int) div_res; @@ -2247,7 +2252,8 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data) di->bat_cap.max_mah = di->bat_cap.max_mah_design; - di->vbat_nom = b->nominal_voltage; + di->vbat_nom_uv = + di->bm->bi.voltage_max_design_uv; } if (ret.intval) @@ -3078,8 +3084,7 @@ static int ab8500_fg_probe(struct platform_device *pdev) di->bat_cap.max_mah_design = di->bm->bi.charge_full_design_uah; di->bat_cap.max_mah = di->bat_cap.max_mah_design; - - di->vbat_nom = di->bm->bat_type->nominal_voltage; + di->vbat_nom_uv = di->bm->bi.voltage_max_design_uv; di->init_capacity = true; -- GitLab From fc81c435a8a67c72939b44e851111b2991d5ac51 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:19 +0100 Subject: [PATCH 0125/1112] power: supply: ab8500_fg: Init battery data in bind() We were assigning some battery data state in probe() but this is insecure as it depends on the proper probe order between the components: the charger must probe first so that the battery data is populated. Move the init to the bind() call which is certain to happen after the probe of the master and all components has happened. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500_fg.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index ab6141faa798b..daa008138b059 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -3023,6 +3023,10 @@ static int ab8500_fg_bind(struct device *dev, struct device *master, return -ENOMEM; } + di->bat_cap.max_mah_design = di->bm->bi.charge_full_design_uah; + di->bat_cap.max_mah = di->bat_cap.max_mah_design; + di->vbat_nom_uv = di->bm->bi.voltage_max_design_uv; + /* Start the coulomb counter */ ab8500_fg_coulomb_counter(di, true); /* Run the FG algorithm */ @@ -3082,10 +3086,6 @@ static int ab8500_fg_probe(struct platform_device *pdev) psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface); psy_cfg.drv_data = di; - di->bat_cap.max_mah_design = di->bm->bi.charge_full_design_uah; - di->bat_cap.max_mah = di->bat_cap.max_mah_design; - di->vbat_nom_uv = di->bm->bi.voltage_max_design_uv; - di->init_capacity = true; ab8500_fg_charge_state_to(di, AB8500_FG_CHARGE_INIT); -- GitLab From 50425ccf2467db9f4134a60a95ef6b6a580222cb Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:20 +0100 Subject: [PATCH 0126/1112] power: supply: ab8500: Standardize internal resistance The nominal internal resistance isn't used by the AB8500 charging code, instead this resistance is measured continuously, but we anyways migrate this to the standard property in struct power_supply_battery_info. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 2 -- drivers/power/supply/ab8500_bmdata.c | 4 +++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index b21d3a99471f5..7e00f480756b6 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -388,7 +388,6 @@ struct ab8500_maxim_parameters { * @maint_b_chg_timer_h: charge time in maintenance B state * @low_high_cur_lvl: charger current in temp low/high state in mA * @low_high_vol_lvl: charger voltage in temp low/high state in mV' - * @battery_resistance: battery inner resistance in mOhm. * @n_r_t_tbl_elements: number of elements in r_to_t_tbl * @r_to_t_tbl: table containing resistance to temp points * @n_v_cap_tbl_elements: number of elements in v_to_cap_tbl @@ -411,7 +410,6 @@ struct ab8500_battery_type { int maint_b_chg_timer_h; int low_high_cur_lvl; int low_high_vol_lvl; - int battery_resistance; int n_temp_tbl_elements; const struct ab8500_res_to_temp *r_to_t_tbl; int n_v_cap_tbl_elements; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index 684cefccebd10..981003105af69 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -83,7 +83,6 @@ static const struct batres_vs_temp temp_to_batres_tbl_thermistor[] = { static struct ab8500_battery_type bat_type_thermistor_unknown = { .resis_high = 0, .resis_low = 0, - .battery_resistance = 300, .termination_curr = 200, .recharge_cap = 95, .normal_cur_lvl = 400, @@ -204,6 +203,9 @@ int ab8500_bm_of_probe(struct power_supply *psy, bi->overvoltage_limit_uv = 4050000; } + if (bi->factory_internal_resistance_uohm < 0) + bi->factory_internal_resistance_uohm = 300000; + if (bi->temp_min == INT_MIN) bi->temp_min = AB8500_TEMP_UNDER; if (bi->temp_max == INT_MAX) -- GitLab From 9c20899da46b85ed00e6f3b935b4bd9c9b34a571 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:21 +0100 Subject: [PATCH 0127/1112] power: supply: ab8500: Standardize termination current The AB8500 custom termination current can be replaced by the corresponding struct power_supply_battery_info field. Remove the struct member and amend the code to use the standard property. Add *_ua suffix for clarity and to make sure we have changed all code sites using this member. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 2 -- drivers/power/supply/ab8500_bmdata.c | 5 ++++- drivers/power/supply/ab8500_chargalg.c | 12 ++++++------ 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index 7e00f480756b6..4bc932109f639 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -374,7 +374,6 @@ struct ab8500_maxim_parameters { * struct ab8500_battery_type - different batteries supported * @resis_high: battery upper resistance limit * @resis_low: battery lower resistance limit - * @termination_curr battery charging termination current in mA * @recharge_cap battery capacity limit that will trigger a new * full charging cycle in the case where maintenan- * -ce charging has been disabled @@ -398,7 +397,6 @@ struct ab8500_maxim_parameters { struct ab8500_battery_type { int resis_high; int resis_low; - int termination_curr; int recharge_cap; int normal_cur_lvl; int normal_vol_lvl; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index 981003105af69..cd1fc288314eb 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -83,7 +83,6 @@ static const struct batres_vs_temp temp_to_batres_tbl_thermistor[] = { static struct ab8500_battery_type bat_type_thermistor_unknown = { .resis_high = 0, .resis_low = 0, - .termination_curr = 200, .recharge_cap = 95, .normal_cur_lvl = 400, .normal_vol_lvl = 4100, @@ -203,6 +202,10 @@ int ab8500_bm_of_probe(struct power_supply *psy, bi->overvoltage_limit_uv = 4050000; } + if (bi->charge_term_current_ua) + /* Charging stops when we drop below this current */ + bi->charge_term_current_ua = 200000; + if (bi->factory_internal_resistance_uohm < 0) bi->factory_internal_resistance_uohm = 300000; diff --git a/drivers/power/supply/ab8500_chargalg.c b/drivers/power/supply/ab8500_chargalg.c index dd9cad63e37ea..49e7167d03623 100644 --- a/drivers/power/supply/ab8500_chargalg.c +++ b/drivers/power/supply/ab8500_chargalg.c @@ -87,7 +87,7 @@ struct ab8500_chargalg_current_step_status { struct ab8500_chargalg_battery_data { int temp; int volt_uv; - int avg_curr; + int avg_curr_ua; int inst_curr; int percent; }; @@ -795,9 +795,9 @@ static void ab8500_chargalg_end_of_charge(struct ab8500_chargalg *di) !di->maintenance_chg && (di->batt_data.volt_uv >= di->bm->bi.overvoltage_limit_uv || di->events.usb_cv_active || di->events.ac_cv_active) && - di->batt_data.avg_curr < - di->bm->bat_type->termination_curr && - di->batt_data.avg_curr > 0) { + di->batt_data.avg_curr_ua < + di->bm->bi.charge_term_current_ua && + di->batt_data.avg_curr_ua > 0) { if (++di->eoc_cnt >= EOC_COND_CNT) { di->eoc_cnt = 0; di->charge_status = POWER_SUPPLY_STATUS_FULL; @@ -1237,7 +1237,7 @@ static int ab8500_chargalg_get_ext_psy_data(struct device *dev, void *data) case POWER_SUPPLY_PROP_CURRENT_AVG: switch (ext->desc->type) { case POWER_SUPPLY_TYPE_BATTERY: - di->batt_data.avg_curr = ret.intval / 1000; + di->batt_data.avg_curr_ua = ret.intval; break; case POWER_SUPPLY_TYPE_USB: if (ret.intval) @@ -1398,7 +1398,7 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) "AC_online %d USB_online %d AC_CV %d USB_CV %d AC_I %d " "USB_I %d AC_Vset %d AC_Iset %d USB_Vset %d USB_Iset %d\n", di->batt_data.volt_uv, - di->batt_data.avg_curr, + di->batt_data.avg_curr_ua, di->batt_data.inst_curr, di->batt_data.temp, di->batt_data.percent, -- GitLab From 1091ed7db0d2957e015a5650ed17ff7537c2b3f3 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:22 +0100 Subject: [PATCH 0128/1112] power: supply: ab8500: Make recharge capacity a constant The recharge capacity is the hysteresis level for a charger to restart when a battery does not support maintenance charging. All products using the AB8500 have batteries supporting maintenace charging and all code has always set this to 95%. Turn it into a constant. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 4 ---- drivers/power/supply/ab8500_bmdata.c | 1 - drivers/power/supply/ab8500_chargalg.c | 10 ++++++++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index 4bc932109f639..58e4cb9010763 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -374,9 +374,6 @@ struct ab8500_maxim_parameters { * struct ab8500_battery_type - different batteries supported * @resis_high: battery upper resistance limit * @resis_low: battery lower resistance limit - * @recharge_cap battery capacity limit that will trigger a new - * full charging cycle in the case where maintenan- - * -ce charging has been disabled * @normal_cur_lvl: charger current in normal state in mA * @normal_vol_lvl: charger voltage in normal state in mV * @maint_a_cur_lvl: charger current in maintenance A state in mA @@ -397,7 +394,6 @@ struct ab8500_maxim_parameters { struct ab8500_battery_type { int resis_high; int resis_low; - int recharge_cap; int normal_cur_lvl; int normal_vol_lvl; int maint_a_cur_lvl; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index cd1fc288314eb..78182a396de7e 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -83,7 +83,6 @@ static const struct batres_vs_temp temp_to_batres_tbl_thermistor[] = { static struct ab8500_battery_type bat_type_thermistor_unknown = { .resis_high = 0, .resis_low = 0, - .recharge_cap = 95, .normal_cur_lvl = 400, .normal_vol_lvl = 4100, .maint_a_cur_lvl = 400, diff --git a/drivers/power/supply/ab8500_chargalg.c b/drivers/power/supply/ab8500_chargalg.c index 49e7167d03623..90974a8887cd1 100644 --- a/drivers/power/supply/ab8500_chargalg.c +++ b/drivers/power/supply/ab8500_chargalg.c @@ -49,6 +49,13 @@ #define CHARGALG_CURR_STEP_LOW 0 #define CHARGALG_CURR_STEP_HIGH 100 +/* + * This is the battery capacity limit that will trigger a new + * full charging cycle in the case where maintenance charging + * has been disabled + */ +#define AB8500_RECHARGE_CAP 95 + enum ab8500_chargers { NO_CHG, AC_CHG, @@ -1544,8 +1551,7 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) fallthrough; case STATE_WAIT_FOR_RECHARGE: - if (di->batt_data.percent <= - di->bm->bat_type->recharge_cap) + if (di->batt_data.percent <= AB8500_RECHARGE_CAP) ab8500_chargalg_state_to(di, STATE_NORMAL_INIT); break; -- GitLab From 83e5aa77d1120fd38101f757c4aeb985e9305700 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:23 +0100 Subject: [PATCH 0129/1112] power: supply: ab8500: Standardize CC current The current used in the constant current phase of the charging exist in struct power_supply_battery_info as constant_charge_current_max_ua. Switch the custom property max_out_curr to this and consequentally change everything that relates to this value over to using microamperes rather than milliamperes so we align internal representation of current with the power core. Prefix every variable we change with *_ua to indicate the unit everywhere but also to make sure we do not miss any outlier. Drop some duplicate unused defines in a header. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 25 +- drivers/power/supply/ab8500-chargalg.h | 4 +- drivers/power/supply/ab8500_bmdata.c | 12 +- drivers/power/supply/ab8500_chargalg.c | 194 ++++++++-------- drivers/power/supply/ab8500_charger.c | 301 +++++++++++++------------ 5 files changed, 270 insertions(+), 266 deletions(-) diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index 58e4cb9010763..c8841567dfee5 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -160,13 +160,6 @@ #define BTEMP_HIGH_TH_57_1 0x02 #define BTEMP_HIGH_TH_62 0x03 -/* current is mA */ -#define USB_0P1A 100 -#define USB_0P2A 200 -#define USB_0P3A 300 -#define USB_0P4A 400 -#define USB_0P5A 500 - #define LOW_BAT_3P1V 0x20 #define LOW_BAT_2P3V 0x00 #define LOW_BAT_RESET 0x01 @@ -359,22 +352,21 @@ struct ab8500_fg_parameters { /** * struct ab8500_charger_maximization - struct used by the board config. * @use_maxi: Enable maximization for this battery type - * @maxi_chg_curr: Maximum charger current allowed + * @maxi_chg_curr_ua: Maximum charger current allowed in microampere * @maxi_wait_cycles: cycles to wait before setting charger current - * @charger_curr_step delta between two charger current settings (mA) + * @charger_curr_step_ua: delta between two charger current settings (uA) */ struct ab8500_maxim_parameters { bool ena_maxi; - int chg_curr; + int chg_curr_ua; int wait_cycles; - int charger_curr_step; + int charger_curr_step_ua; }; /** * struct ab8500_battery_type - different batteries supported * @resis_high: battery upper resistance limit * @resis_low: battery lower resistance limit - * @normal_cur_lvl: charger current in normal state in mA * @normal_vol_lvl: charger voltage in normal state in mV * @maint_a_cur_lvl: charger current in maintenance A state in mA * @maint_a_vol_lvl: charger voltage in maintenance A state in mV @@ -394,7 +386,6 @@ struct ab8500_maxim_parameters { struct ab8500_battery_type { int resis_high; int resis_low; - int normal_cur_lvl; int normal_vol_lvl; int maint_a_cur_lvl; int maint_a_vol_lvl; @@ -431,15 +422,15 @@ struct ab8500_bm_capacity_levels { /** * struct ab8500_bm_charger_parameters - Charger specific parameters * @usb_volt_max: maximum allowed USB charger voltage in mV - * @usb_curr_max: maximum allowed USB charger current in mA + * @usb_curr_max_ua: maximum allowed USB charger current in uA * @ac_volt_max: maximum allowed AC charger voltage in mV - * @ac_curr_max: maximum allowed AC charger current in mA + * @ac_curr_max_ua: maximum allowed AC charger current in uA */ struct ab8500_bm_charger_parameters { int usb_volt_max; - int usb_curr_max; + int usb_curr_max_ua; int ac_volt_max; - int ac_curr_max; + int ac_curr_max_ua; }; /** diff --git a/drivers/power/supply/ab8500-chargalg.h b/drivers/power/supply/ab8500-chargalg.h index 07e6ff50084f0..8094a3c2bd3a7 100644 --- a/drivers/power/supply/ab8500-chargalg.h +++ b/drivers/power/supply/ab8500-chargalg.h @@ -32,7 +32,7 @@ struct ux500_charger_ops { * @psy power supply base class * @ops ux500 charger operations * @max_out_volt maximum output charger voltage in mV - * @max_out_curr maximum output charger current in mA + * @max_out_curr_ua maximum output charger current in uA * @enabled indicates if this charger is used or not * @external external charger unit (pm2xxx) */ @@ -40,7 +40,7 @@ struct ux500_charger { struct power_supply *psy; struct ux500_charger_ops ops; int max_out_volt; - int max_out_curr; + int max_out_curr_ua; int wdt_refresh; bool enabled; bool external; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index 78182a396de7e..e9bbb7517e045 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -83,7 +83,6 @@ static const struct batres_vs_temp temp_to_batres_tbl_thermistor[] = { static struct ab8500_battery_type bat_type_thermistor_unknown = { .resis_high = 0, .resis_low = 0, - .normal_cur_lvl = 400, .normal_vol_lvl = 4100, .maint_a_cur_lvl = 400, .maint_a_vol_lvl = 4050, @@ -133,16 +132,16 @@ static const struct ab8500_fg_parameters fg = { static const struct ab8500_maxim_parameters ab8500_maxi_params = { .ena_maxi = true, - .chg_curr = 910, + .chg_curr_ua = 910000, .wait_cycles = 10, - .charger_curr_step = 100, + .charger_curr_step_ua = 100000, }; static const struct ab8500_bm_charger_parameters chg = { .usb_volt_max = 5500, - .usb_curr_max = 1500, + .usb_curr_max_ua = 1500000, .ac_volt_max = 7500, - .ac_curr_max = 1500, + .ac_curr_max_ua = 1500000, }; /* This is referenced directly in the charger code */ @@ -201,6 +200,9 @@ int ab8500_bm_of_probe(struct power_supply *psy, bi->overvoltage_limit_uv = 4050000; } + if (bi->constant_charge_current_max_ua < 0) + bi->constant_charge_current_max_ua = 400000; + if (bi->charge_term_current_ua) /* Charging stops when we drop below this current */ bi->charge_term_current_ua = 200000; diff --git a/drivers/power/supply/ab8500_chargalg.c b/drivers/power/supply/ab8500_chargalg.c index 90974a8887cd1..8ad3924ee4969 100644 --- a/drivers/power/supply/ab8500_chargalg.c +++ b/drivers/power/supply/ab8500_chargalg.c @@ -46,8 +46,8 @@ /* Five minutes expressed in seconds */ #define FIVE_MINUTES_IN_SECONDS 300 -#define CHARGALG_CURR_STEP_LOW 0 -#define CHARGALG_CURR_STEP_HIGH 100 +#define CHARGALG_CURR_STEP_LOW_UA 0 +#define CHARGALG_CURR_STEP_HIGH_UA 100000 /* * This is the battery capacity limit that will trigger a new @@ -71,13 +71,13 @@ struct ab8500_chargalg_charger_info { bool usb_chg_ok; bool ac_chg_ok; int usb_volt; - int usb_curr; + int usb_curr_ua; int ac_volt; - int ac_curr; + int ac_curr_ua; int usb_vset; - int usb_iset; + int usb_iset_ua; int ac_vset; - int ac_iset; + int ac_iset_ua; }; struct ab8500_chargalg_suspension_status { @@ -88,14 +88,14 @@ struct ab8500_chargalg_suspension_status { struct ab8500_chargalg_current_step_status { bool curr_step_change; - int curr_step; + int curr_step_ua; }; struct ab8500_chargalg_battery_data { int temp; int volt_uv; int avg_curr_ua; - int inst_curr; + int inst_curr_ua; int percent; }; @@ -184,13 +184,13 @@ struct ab8500_chargalg_events { /** * struct ab8500_charge_curr_maximization - Charger maximization parameters - * @original_iset: the non optimized/maximised charger current - * @current_iset: the charging current used at this moment - * @test_delta_i: the delta between the current we want to charge and the + * @original_iset_ua: the non optimized/maximised charger current + * @current_iset_ua: the charging current used at this moment + * @test_delta_i_ua: the delta between the current we want to charge and the current that is really going into the battery * @condition_cnt: number of iterations needed before a new charger current is set - * @max_current: maximum charger current + * @max_current_ua: maximum charger current * @wait_cnt: to avoid too fast current step down in case of charger * voltage collapse, we insert this delay between step * down @@ -198,11 +198,11 @@ struct ab8500_chargalg_events { increased */ struct ab8500_charge_curr_maximization { - int original_iset; - int current_iset; - int test_delta_i; + int original_iset_ua; + int current_iset_ua; + int test_delta_i_ua; int condition_cnt; - int max_current; + int max_current_ua; int wait_cnt; u8 level; }; @@ -352,6 +352,8 @@ static void ab8500_chargalg_state_to(struct ab8500_chargalg *di, static int ab8500_chargalg_check_charger_enable(struct ab8500_chargalg *di) { + struct power_supply_battery_info *bi = &di->bm->bi; + switch (di->charge_state) { case STATE_NORMAL: case STATE_MAINTENANCE_A: @@ -364,12 +366,12 @@ static int ab8500_chargalg_check_charger_enable(struct ab8500_chargalg *di) if (di->chg_info.charger_type & USB_CHG) { return di->usb_chg->ops.check_enable(di->usb_chg, di->bm->bat_type->normal_vol_lvl, - di->bm->bat_type->normal_cur_lvl); + bi->constant_charge_current_max_ua); } else if ((di->chg_info.charger_type & AC_CHG) && !(di->ac_chg->external)) { return di->ac_chg->ops.check_enable(di->ac_chg, di->bm->bat_type->normal_vol_lvl, - di->bm->bat_type->normal_cur_lvl); + bi->constant_charge_current_max_ua); } return 0; } @@ -545,13 +547,13 @@ static int ab8500_chargalg_kick_watchdog(struct ab8500_chargalg *di) * @di: pointer to the ab8500_chargalg structure * @enable: charger on/off * @vset: requested charger output voltage - * @iset: requested charger output current + * @iset_ua: requested charger output current in microampere * * The AC charger will be turned on/off with the requested charge voltage and * current */ static int ab8500_chargalg_ac_en(struct ab8500_chargalg *di, int enable, - int vset, int iset) + int vset, int iset_ua) { static int ab8500_chargalg_ex_ac_enable_toggle; @@ -561,10 +563,10 @@ static int ab8500_chargalg_ac_en(struct ab8500_chargalg *di, int enable, /* Select maximum of what both the charger and the battery supports */ if (di->ac_chg->max_out_volt) vset = min(vset, di->ac_chg->max_out_volt); - if (di->ac_chg->max_out_curr) - iset = min(iset, di->ac_chg->max_out_curr); + if (di->ac_chg->max_out_curr_ua) + iset_ua = min(iset_ua, di->ac_chg->max_out_curr_ua); - di->chg_info.ac_iset = iset; + di->chg_info.ac_iset_ua = iset_ua; di->chg_info.ac_vset = vset; /* Enable external charger */ @@ -575,7 +577,7 @@ static int ab8500_chargalg_ac_en(struct ab8500_chargalg *di, int enable, ab8500_chargalg_ex_ac_enable_toggle++; } - return di->ac_chg->ops.enable(di->ac_chg, enable, vset, iset); + return di->ac_chg->ops.enable(di->ac_chg, enable, vset, iset_ua); } /** @@ -583,13 +585,13 @@ static int ab8500_chargalg_ac_en(struct ab8500_chargalg *di, int enable, * @di: pointer to the ab8500_chargalg structure * @enable: charger on/off * @vset: requested charger output voltage - * @iset: requested charger output current + * @iset_ua: requested charger output current in microampere * * The USB charger will be turned on/off with the requested charge voltage and * current */ static int ab8500_chargalg_usb_en(struct ab8500_chargalg *di, int enable, - int vset, int iset) + int vset, int iset_ua) { if (!di->usb_chg || !di->usb_chg->ops.enable) return -ENXIO; @@ -597,25 +599,25 @@ static int ab8500_chargalg_usb_en(struct ab8500_chargalg *di, int enable, /* Select maximum of what both the charger and the battery supports */ if (di->usb_chg->max_out_volt) vset = min(vset, di->usb_chg->max_out_volt); - if (di->usb_chg->max_out_curr) - iset = min(iset, di->usb_chg->max_out_curr); + if (di->usb_chg->max_out_curr_ua) + iset_ua = min(iset_ua, di->usb_chg->max_out_curr_ua); - di->chg_info.usb_iset = iset; + di->chg_info.usb_iset_ua = iset_ua; di->chg_info.usb_vset = vset; - return di->usb_chg->ops.enable(di->usb_chg, enable, vset, iset); + return di->usb_chg->ops.enable(di->usb_chg, enable, vset, iset_ua); } /** * ab8500_chargalg_update_chg_curr() - Update charger current * @di: pointer to the ab8500_chargalg structure - * @iset: requested charger output current + * @iset_ua: requested charger output current in microampere * * The charger output current will be updated for the charger * that is currently in use */ static int ab8500_chargalg_update_chg_curr(struct ab8500_chargalg *di, - int iset) + int iset_ua) { /* Check if charger exists and update current if charging */ if (di->ac_chg && di->ac_chg->ops.update_curr && @@ -624,24 +626,24 @@ static int ab8500_chargalg_update_chg_curr(struct ab8500_chargalg *di, * Select maximum of what both the charger * and the battery supports */ - if (di->ac_chg->max_out_curr) - iset = min(iset, di->ac_chg->max_out_curr); + if (di->ac_chg->max_out_curr_ua) + iset_ua = min(iset_ua, di->ac_chg->max_out_curr_ua); - di->chg_info.ac_iset = iset; + di->chg_info.ac_iset_ua = iset_ua; - return di->ac_chg->ops.update_curr(di->ac_chg, iset); + return di->ac_chg->ops.update_curr(di->ac_chg, iset_ua); } else if (di->usb_chg && di->usb_chg->ops.update_curr && di->chg_info.charger_type & USB_CHG) { /* * Select maximum of what both the charger * and the battery supports */ - if (di->usb_chg->max_out_curr) - iset = min(iset, di->usb_chg->max_out_curr); + if (di->usb_chg->max_out_curr_ua) + iset_ua = min(iset_ua, di->usb_chg->max_out_curr_ua); - di->chg_info.usb_iset = iset; + di->chg_info.usb_iset_ua = iset_ua; - return di->usb_chg->ops.update_curr(di->usb_chg, iset); + return di->usb_chg->ops.update_curr(di->usb_chg, iset_ua); } return -ENXIO; @@ -691,27 +693,27 @@ static void ab8500_chargalg_hold_charging(struct ab8500_chargalg *di) * ab8500_chargalg_start_charging() - Start the charger * @di: pointer to the ab8500_chargalg structure * @vset: requested charger output voltage - * @iset: requested charger output current + * @iset_ua: requested charger output current in microampere * * A charger will be enabled depending on the requested charger type that was * detected previously. */ static void ab8500_chargalg_start_charging(struct ab8500_chargalg *di, - int vset, int iset) + int vset, int iset_ua) { switch (di->chg_info.charger_type) { case AC_CHG: dev_dbg(di->dev, - "AC parameters: Vset %d, Ich %d\n", vset, iset); + "AC parameters: Vset %d, Ich %d\n", vset, iset_ua); ab8500_chargalg_usb_en(di, false, 0, 0); - ab8500_chargalg_ac_en(di, true, vset, iset); + ab8500_chargalg_ac_en(di, true, vset, iset_ua); break; case USB_CHG: dev_dbg(di->dev, - "USB parameters: Vset %d, Ich %d\n", vset, iset); + "USB parameters: Vset %d, Ich %d\n", vset, iset_ua); ab8500_chargalg_ac_en(di, false, 0, 0); - ab8500_chargalg_usb_en(di, true, vset, iset); + ab8500_chargalg_usb_en(di, true, vset, iset_ua); break; default: @@ -825,12 +827,12 @@ static void ab8500_chargalg_end_of_charge(struct ab8500_chargalg *di) static void init_maxim_chg_curr(struct ab8500_chargalg *di) { - di->ccm.original_iset = - di->bm->bat_type->normal_cur_lvl; - di->ccm.current_iset = - di->bm->bat_type->normal_cur_lvl; - di->ccm.test_delta_i = di->bm->maxi->charger_curr_step; - di->ccm.max_current = di->bm->maxi->chg_curr; + struct power_supply_battery_info *bi = &di->bm->bi; + + di->ccm.original_iset_ua = bi->constant_charge_current_max_ua; + di->ccm.current_iset_ua = bi->constant_charge_current_max_ua; + di->ccm.test_delta_i_ua = di->bm->maxi->charger_curr_step_ua; + di->ccm.max_current_ua = di->bm->maxi->chg_curr_ua; di->ccm.condition_cnt = di->bm->maxi->wait_cycles; di->ccm.level = 0; } @@ -846,12 +848,12 @@ static void init_maxim_chg_curr(struct ab8500_chargalg *di) */ static enum maxim_ret ab8500_chargalg_chg_curr_maxim(struct ab8500_chargalg *di) { - int delta_i; + int delta_i_ua; if (!di->bm->maxi->ena_maxi) return MAXIM_RET_NOACTION; - delta_i = di->ccm.original_iset - di->batt_data.inst_curr; + delta_i_ua = di->ccm.original_iset_ua - di->batt_data.inst_curr_ua; if (di->events.vbus_collapsed) { dev_dbg(di->dev, "Charger voltage has collapsed %d\n", @@ -860,9 +862,9 @@ static enum maxim_ret ab8500_chargalg_chg_curr_maxim(struct ab8500_chargalg *di) dev_dbg(di->dev, "lowering current\n"); di->ccm.wait_cnt++; di->ccm.condition_cnt = di->bm->maxi->wait_cycles; - di->ccm.max_current = - di->ccm.current_iset - di->ccm.test_delta_i; - di->ccm.current_iset = di->ccm.max_current; + di->ccm.max_current_ua = + di->ccm.current_iset_ua - di->ccm.test_delta_i_ua; + di->ccm.current_iset_ua = di->ccm.max_current_ua; di->ccm.level--; return MAXIM_RET_CHANGE; } else { @@ -875,36 +877,36 @@ static enum maxim_ret ab8500_chargalg_chg_curr_maxim(struct ab8500_chargalg *di) di->ccm.wait_cnt = 0; - if (di->batt_data.inst_curr > di->ccm.original_iset) { - dev_dbg(di->dev, " Maximization Ibat (%dmA) too high" - " (limit %dmA) (current iset: %dmA)!\n", - di->batt_data.inst_curr, di->ccm.original_iset, - di->ccm.current_iset); + if (di->batt_data.inst_curr_ua > di->ccm.original_iset_ua) { + dev_dbg(di->dev, " Maximization Ibat (%duA) too high" + " (limit %duA) (current iset: %duA)!\n", + di->batt_data.inst_curr_ua, di->ccm.original_iset_ua, + di->ccm.current_iset_ua); - if (di->ccm.current_iset == di->ccm.original_iset) + if (di->ccm.current_iset_ua == di->ccm.original_iset_ua) return MAXIM_RET_NOACTION; di->ccm.condition_cnt = di->bm->maxi->wait_cycles; - di->ccm.current_iset = di->ccm.original_iset; + di->ccm.current_iset_ua = di->ccm.original_iset_ua; di->ccm.level = 0; return MAXIM_RET_IBAT_TOO_HIGH; } - if (delta_i > di->ccm.test_delta_i && - (di->ccm.current_iset + di->ccm.test_delta_i) < - di->ccm.max_current) { + if (delta_i_ua > di->ccm.test_delta_i_ua && + (di->ccm.current_iset_ua + di->ccm.test_delta_i_ua) < + di->ccm.max_current_ua) { if (di->ccm.condition_cnt-- == 0) { /* Increse the iset with cco.test_delta_i */ di->ccm.condition_cnt = di->bm->maxi->wait_cycles; - di->ccm.current_iset += di->ccm.test_delta_i; + di->ccm.current_iset_ua += di->ccm.test_delta_i_ua; di->ccm.level++; dev_dbg(di->dev, " Maximization needed, increase" - " with %d mA to %dmA (Optimal ibat: %d)" + " with %d uA to %duA (Optimal ibat: %d uA)" " Level %d\n", - di->ccm.test_delta_i, - di->ccm.current_iset, - di->ccm.original_iset, + di->ccm.test_delta_i_ua, + di->ccm.current_iset_ua, + di->ccm.original_iset_ua, di->ccm.level); return MAXIM_RET_CHANGE; } else { @@ -918,6 +920,7 @@ static enum maxim_ret ab8500_chargalg_chg_curr_maxim(struct ab8500_chargalg *di) static void handle_maxim_chg_curr(struct ab8500_chargalg *di) { + struct power_supply_battery_info *bi = &di->bm->bi; enum maxim_ret ret; int result; @@ -925,13 +928,13 @@ static void handle_maxim_chg_curr(struct ab8500_chargalg *di) switch (ret) { case MAXIM_RET_CHANGE: result = ab8500_chargalg_update_chg_curr(di, - di->ccm.current_iset); + di->ccm.current_iset_ua); if (result) dev_err(di->dev, "failed to set chg curr\n"); break; case MAXIM_RET_IBAT_TOO_HIGH: result = ab8500_chargalg_update_chg_curr(di, - di->bm->bat_type->normal_cur_lvl); + bi->constant_charge_current_max_ua); if (result) dev_err(di->dev, "failed to set chg curr\n"); break; @@ -1226,15 +1229,13 @@ static int ab8500_chargalg_get_ext_psy_data(struct device *dev, void *data) case POWER_SUPPLY_PROP_CURRENT_NOW: switch (ext->desc->type) { case POWER_SUPPLY_TYPE_MAINS: - di->chg_info.ac_curr = - ret.intval / 1000; - break; + di->chg_info.ac_curr_ua = ret.intval; + break; case POWER_SUPPLY_TYPE_USB: - di->chg_info.usb_curr = - ret.intval / 1000; + di->chg_info.usb_curr_ua = ret.intval; break; case POWER_SUPPLY_TYPE_BATTERY: - di->batt_data.inst_curr = ret.intval / 1000; + di->batt_data.inst_curr_ua = ret.intval; break; default: break; @@ -1298,9 +1299,10 @@ static void ab8500_chargalg_external_power_changed(struct power_supply *psy) */ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) { + struct power_supply_battery_info *bi = &di->bm->bi; int charger_status; int ret; - int curr_step_lvl; + int curr_step_lvl_ua; /* Collect data from all power_supply class devices */ class_for_each_device(power_supply_class, NULL, @@ -1406,7 +1408,7 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) "USB_I %d AC_Vset %d AC_Iset %d USB_Vset %d USB_Iset %d\n", di->batt_data.volt_uv, di->batt_data.avg_curr_ua, - di->batt_data.inst_curr, + di->batt_data.inst_curr_ua, di->batt_data.temp, di->batt_data.percent, di->maintenance_chg, @@ -1419,12 +1421,12 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) di->chg_info.online_chg & USB_CHG, di->events.ac_cv_active, di->events.usb_cv_active, - di->chg_info.ac_curr, - di->chg_info.usb_curr, + di->chg_info.ac_curr_ua, + di->chg_info.usb_curr_ua, di->chg_info.ac_vset, - di->chg_info.ac_iset, + di->chg_info.ac_iset_ua, di->chg_info.usb_vset, - di->chg_info.usb_iset); + di->chg_info.usb_iset_ua); switch (di->charge_state) { case STATE_HANDHELD_INIT: @@ -1509,15 +1511,15 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) break; case STATE_NORMAL_INIT: - if (di->curr_status.curr_step == CHARGALG_CURR_STEP_LOW) + if (di->curr_status.curr_step_ua == CHARGALG_CURR_STEP_LOW_UA) ab8500_chargalg_stop_charging(di); else { - curr_step_lvl = di->bm->bat_type->normal_cur_lvl - * di->curr_status.curr_step - / CHARGALG_CURR_STEP_HIGH; + curr_step_lvl_ua = bi->constant_charge_current_max_ua + * di->curr_status.curr_step_ua + / CHARGALG_CURR_STEP_HIGH_UA; ab8500_chargalg_start_charging(di, di->bm->bat_type->normal_vol_lvl, - curr_step_lvl); + curr_step_lvl_ua); } ab8500_chargalg_state_to(di, STATE_NORMAL); @@ -1743,7 +1745,7 @@ static int ab8500_chargalg_get_property(struct power_supply *psy, static ssize_t ab8500_chargalg_curr_step_show(struct ab8500_chargalg *di, char *buf) { - return sprintf(buf, "%d\n", di->curr_status.curr_step); + return sprintf(buf, "%d\n", di->curr_status.curr_step_ua); } static ssize_t ab8500_chargalg_curr_step_store(struct ab8500_chargalg *di, @@ -1756,9 +1758,9 @@ static ssize_t ab8500_chargalg_curr_step_store(struct ab8500_chargalg *di, if (ret < 0) return ret; - di->curr_status.curr_step = param; - if (di->curr_status.curr_step >= CHARGALG_CURR_STEP_LOW && - di->curr_status.curr_step <= CHARGALG_CURR_STEP_HIGH) { + di->curr_status.curr_step_ua = param; + if (di->curr_status.curr_step_ua >= CHARGALG_CURR_STEP_LOW_UA && + di->curr_status.curr_step_ua <= CHARGALG_CURR_STEP_HIGH_UA) { di->curr_status.curr_step_change = true; queue_work(di->chargalg_wq, &di->chargalg_work); } else @@ -2055,7 +2057,7 @@ static int ab8500_chargalg_probe(struct platform_device *pdev) dev_err(di->dev, "failed to create sysfs entry\n"); return ret; } - di->curr_status.curr_step = CHARGALG_CURR_STEP_HIGH; + di->curr_status.curr_step_ua = CHARGALG_CURR_STEP_HIGH_UA; dev_info(di->dev, "probe success\n"); return component_add(dev, &ab8500_chargalg_component_ops); diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c index 7a151cd97399c..e66091f3f6064 100644 --- a/drivers/power/supply/ab8500_charger.c +++ b/drivers/power/supply/ab8500_charger.c @@ -145,23 +145,23 @@ enum ab8500_usb_state { AB8500_BM_USB_STATE_MAX, }; -/* VBUS input current limits supported in AB8500 in mA */ -#define USB_CH_IP_CUR_LVL_0P05 50 -#define USB_CH_IP_CUR_LVL_0P09 98 -#define USB_CH_IP_CUR_LVL_0P19 193 -#define USB_CH_IP_CUR_LVL_0P29 290 -#define USB_CH_IP_CUR_LVL_0P38 380 -#define USB_CH_IP_CUR_LVL_0P45 450 -#define USB_CH_IP_CUR_LVL_0P5 500 -#define USB_CH_IP_CUR_LVL_0P6 600 -#define USB_CH_IP_CUR_LVL_0P7 700 -#define USB_CH_IP_CUR_LVL_0P8 800 -#define USB_CH_IP_CUR_LVL_0P9 900 -#define USB_CH_IP_CUR_LVL_1P0 1000 -#define USB_CH_IP_CUR_LVL_1P1 1100 -#define USB_CH_IP_CUR_LVL_1P3 1300 -#define USB_CH_IP_CUR_LVL_1P4 1400 -#define USB_CH_IP_CUR_LVL_1P5 1500 +/* VBUS input current limits supported in AB8500 in uA */ +#define USB_CH_IP_CUR_LVL_0P05 50000 +#define USB_CH_IP_CUR_LVL_0P09 98000 +#define USB_CH_IP_CUR_LVL_0P19 193000 +#define USB_CH_IP_CUR_LVL_0P29 290000 +#define USB_CH_IP_CUR_LVL_0P38 380000 +#define USB_CH_IP_CUR_LVL_0P45 450000 +#define USB_CH_IP_CUR_LVL_0P5 500000 +#define USB_CH_IP_CUR_LVL_0P6 600000 +#define USB_CH_IP_CUR_LVL_0P7 700000 +#define USB_CH_IP_CUR_LVL_0P8 800000 +#define USB_CH_IP_CUR_LVL_0P9 900000 +#define USB_CH_IP_CUR_LVL_1P0 1000000 +#define USB_CH_IP_CUR_LVL_1P1 1100000 +#define USB_CH_IP_CUR_LVL_1P3 1300000 +#define USB_CH_IP_CUR_LVL_1P4 1400000 +#define USB_CH_IP_CUR_LVL_1P5 1500000 #define VBAT_TRESH_IP_CUR_RED 3800 @@ -186,7 +186,7 @@ struct ab8500_charger_info { int charger_voltage; int cv_active; bool wd_expired; - int charger_current; + int charger_current_ua; }; struct ab8500_charger_event_flags { @@ -201,17 +201,17 @@ struct ab8500_charger_event_flags { }; struct ab8500_charger_usb_state { - int usb_current; - int usb_current_tmp; + int usb_current_ua; + int usb_current_tmp_ua; enum ab8500_usb_state state; enum ab8500_usb_state state_tmp; spinlock_t usb_lock; }; struct ab8500_charger_max_usb_in_curr { - int usb_type_max; - int set_max; - int calculated_max; + int usb_type_max_ua; + int set_max_ua; + int calculated_max_ua; }; /** @@ -552,7 +552,7 @@ static int ab8500_charger_get_vbus_voltage(struct ab8500_charger *di) * @di: pointer to the ab8500_charger structure * * This function returns the usb charger current. - * Returns usb current (on success) and error code on failure + * Returns usb current in microamperes (on success) and error code on failure */ static int ab8500_charger_get_usb_current(struct ab8500_charger *di) { @@ -566,7 +566,8 @@ static int ab8500_charger_get_usb_current(struct ab8500_charger *di) } else { ich = 0; } - return ich; + /* Return microamperes */ + return ich * 1000; } /** @@ -574,7 +575,7 @@ static int ab8500_charger_get_usb_current(struct ab8500_charger *di) * @di: pointer to the ab8500_charger structure * * This function returns the ac charger current. - * Returns ac current (on success) and error code on failure. + * Returns ac current in microamperes (on success) and error code on failure. */ static int ab8500_charger_get_ac_current(struct ab8500_charger *di) { @@ -588,7 +589,8 @@ static int ab8500_charger_get_ac_current(struct ab8500_charger *di) } else { ich = 0; } - return ich; + /* Return microamperes */ + return ich * 1000; } /** @@ -711,19 +713,19 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, case USB_STAT_STD_HOST_C_S: dev_dbg(di->dev, "USB Type - Standard host is " "detected through USB driver\n"); - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5; di->is_aca_rid = 0; break; case USB_STAT_HOST_CHG_HS_CHIRP: - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5; di->is_aca_rid = 0; break; case USB_STAT_HOST_CHG_HS: - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5; di->is_aca_rid = 0; break; case USB_STAT_ACA_RID_C_HS: - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P9; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P9; di->is_aca_rid = 0; break; case USB_STAT_ACA_RID_A: @@ -732,7 +734,7 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, * can consume (900mA). Closest level is 500mA */ dev_dbg(di->dev, "USB_STAT_ACA_RID_A detected\n"); - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5; di->is_aca_rid = 1; break; case USB_STAT_ACA_RID_B: @@ -740,36 +742,36 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, * Dedicated charger level minus 120mA (20mA for ACA and * 100mA for potential accessory). Closest level is 1300mA */ - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_1P3; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_1P3; dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status, - di->max_usb_in_curr.usb_type_max); + di->max_usb_in_curr.usb_type_max_ua); di->is_aca_rid = 1; break; case USB_STAT_HOST_CHG_NM: - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5; di->is_aca_rid = 0; break; case USB_STAT_DEDICATED_CHG: - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_1P5; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_1P5; di->is_aca_rid = 0; break; case USB_STAT_ACA_RID_C_HS_CHIRP: case USB_STAT_ACA_RID_C_NM: - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_1P5; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_1P5; di->is_aca_rid = 1; break; case USB_STAT_NOT_CONFIGURED: if (di->vbus_detected) { di->usb_device_is_unrecognised = true; dev_dbg(di->dev, "USB Type - Legacy charger.\n"); - di->max_usb_in_curr.usb_type_max = + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_1P5; break; } fallthrough; case USB_STAT_HM_IDGND: dev_err(di->dev, "USB Type - Charging not allowed\n"); - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P05; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P05; ret = -ENXIO; break; case USB_STAT_RESERVED: @@ -781,11 +783,11 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, break; } else { dev_dbg(di->dev, "USB Type - Charging not allowed\n"); - di->max_usb_in_curr.usb_type_max = + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P05; dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status, - di->max_usb_in_curr.usb_type_max); + di->max_usb_in_curr.usb_type_max_ua); ret = -ENXIO; break; } @@ -793,25 +795,25 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, case USB_STAT_CARKIT_2: case USB_STAT_ACA_DOCK_CHARGER: case USB_STAT_CHARGER_LINE_1: - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5; dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status, - di->max_usb_in_curr.usb_type_max); + di->max_usb_in_curr.usb_type_max_ua); break; case USB_STAT_NOT_VALID_LINK: dev_err(di->dev, "USB Type invalid - try charging anyway\n"); - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5; break; default: dev_err(di->dev, "USB Type - Unknown\n"); - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P05; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P05; ret = -ENXIO; break; } - di->max_usb_in_curr.set_max = di->max_usb_in_curr.usb_type_max; + di->max_usb_in_curr.set_max_ua = di->max_usb_in_curr.usb_type_max_ua; dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", - link_status, di->max_usb_in_curr.set_max); + link_status, di->max_usb_in_curr.set_max_ua); return ret; } @@ -1027,51 +1029,51 @@ static int ab8500_voltage_to_regval(int voltage) /* This array maps the raw register value to charger input current */ static int ab8500_charge_input_curr_map[] = { - 50, 98, 193, 290, 380, 450, 500, 600, - 700, 800, 900, 1000, 1100, 1300, 1400, 1500, + 50000, 98000, 193000, 290000, 380000, 450000, 500000, 600000, + 700000, 800000, 900000, 1000000, 1100000, 1300000, 1400000, 1500000, }; /* This array maps the raw register value to charger output current */ static int ab8500_charge_output_curr_map[] = { - 100, 200, 300, 400, 500, 600, 700, 800, - 900, 1000, 1100, 1200, 1300, 1400, 1500, 1500, + 100000, 200000, 300000, 400000, 500000, 600000, 700000, 800000, + 900000, 1000000, 1100000, 1200000, 1300000, 1400000, 1500000, 1500000, }; -static int ab8500_current_to_regval(struct ab8500_charger *di, int curr) +static int ab8500_current_to_regval(struct ab8500_charger *di, int curr_ua) { int i; - if (curr < ab8500_charge_output_curr_map[0]) + if (curr_ua < ab8500_charge_output_curr_map[0]) return 0; for (i = 0; i < ARRAY_SIZE(ab8500_charge_output_curr_map); i++) { - if (curr < ab8500_charge_output_curr_map[i]) + if (curr_ua < ab8500_charge_output_curr_map[i]) return i - 1; } /* If not last element, return error */ i = ARRAY_SIZE(ab8500_charge_output_curr_map) - 1; - if (curr == ab8500_charge_output_curr_map[i]) + if (curr_ua == ab8500_charge_output_curr_map[i]) return i; else return -1; } -static int ab8500_vbus_in_curr_to_regval(struct ab8500_charger *di, int curr) +static int ab8500_vbus_in_curr_to_regval(struct ab8500_charger *di, int curr_ua) { int i; - if (curr < ab8500_charge_input_curr_map[0]) + if (curr_ua < ab8500_charge_input_curr_map[0]) return 0; for (i = 0; i < ARRAY_SIZE(ab8500_charge_input_curr_map); i++) { - if (curr < ab8500_charge_input_curr_map[i]) + if (curr_ua < ab8500_charge_input_curr_map[i]) return i - 1; } /* If not last element, return error */ i = ARRAY_SIZE(ab8500_charge_input_curr_map) - 1; - if (curr == ab8500_charge_input_curr_map[i]) + if (curr_ua == ab8500_charge_input_curr_map[i]) return i; else return -1; @@ -1082,35 +1084,35 @@ static int ab8500_vbus_in_curr_to_regval(struct ab8500_charger *di, int curr) * @di: pointer to the ab8500_charger structre * * The usb stack provides the maximum current that can be drawn from - * the standard usb host. This will be in mA. - * This function converts current in mA to a value that can be written + * the standard usb host. This will be in uA. + * This function converts current in uA to a value that can be written * to the register. Returns -1 if charging is not allowed */ static int ab8500_charger_get_usb_cur(struct ab8500_charger *di) { int ret = 0; - switch (di->usb_state.usb_current) { - case 100: - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P09; + switch (di->usb_state.usb_current_ua) { + case 100000: + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P09; break; - case 200: - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P19; + case 200000: + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P19; break; - case 300: - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P29; + case 300000: + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P29; break; - case 400: - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P38; + case 400000: + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P38; break; - case 500: - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; + case 500000: + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P5; break; default: - di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P05; + di->max_usb_in_curr.usb_type_max_ua = USB_CH_IP_CUR_LVL_0P05; ret = -EPERM; break; } - di->max_usb_in_curr.set_max = di->max_usb_in_curr.usb_type_max; + di->max_usb_in_curr.set_max_ua = di->max_usb_in_curr.usb_type_max_ua; return ret; } @@ -1135,7 +1137,7 @@ static bool ab8500_charger_check_continue_stepping(struct ab8500_charger *di, /** * ab8500_charger_set_current() - set charger current * @di: pointer to the ab8500_charger structure - * @ich: charger current, in mA + * @ich_ua: charger current, in uA * @reg: select what charger register to set * * Set charger current. @@ -1146,7 +1148,7 @@ static bool ab8500_charger_check_continue_stepping(struct ab8500_charger *di, * Returns error code in case of failure else 0(on success) */ static int ab8500_charger_set_current(struct ab8500_charger *di, - int ich, int reg) + int ich_ua, int reg) { int ret = 0; int curr_index, prev_curr_index, shift_value, i; @@ -1167,7 +1169,7 @@ static int ab8500_charger_set_current(struct ab8500_charger *di, case AB8500_MCH_IPT_CURLVL_REG: shift_value = MAIN_CH_INPUT_CURR_SHIFT; prev_curr_index = (reg_value >> shift_value); - curr_index = ab8500_current_to_regval(di, ich); + curr_index = ab8500_current_to_regval(di, ich_ua); step_udelay = STEP_UDELAY; if (!di->ac.charger_connected) no_stepping = true; @@ -1175,7 +1177,7 @@ static int ab8500_charger_set_current(struct ab8500_charger *di, case AB8500_USBCH_IPT_CRNTLVL_REG: shift_value = VBUS_IN_CURR_LIM_SHIFT; prev_curr_index = (reg_value >> shift_value); - curr_index = ab8500_vbus_in_curr_to_regval(di, ich); + curr_index = ab8500_vbus_in_curr_to_regval(di, ich_ua); step_udelay = STEP_UDELAY * 100; if (!di->usb.charger_connected) @@ -1184,7 +1186,7 @@ static int ab8500_charger_set_current(struct ab8500_charger *di, case AB8500_CH_OPT_CRNTLVL_REG: shift_value = 0; prev_curr_index = (reg_value >> shift_value); - curr_index = ab8500_current_to_regval(di, ich); + curr_index = ab8500_current_to_regval(di, ich_ua); step_udelay = STEP_UDELAY; if (curr_index && (curr_index - prev_curr_index) > 1) step_udelay *= 100; @@ -1213,8 +1215,8 @@ static int ab8500_charger_set_current(struct ab8500_charger *di, goto exit_set_current; } - dev_dbg(di->dev, "%s set charger current: %d mA for reg: 0x%02x\n", - __func__, ich, reg); + dev_dbg(di->dev, "%s set charger current: %d uA for reg: 0x%02x\n", + __func__, ich_ua, reg); if (no_stepping) { ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, @@ -1261,31 +1263,31 @@ exit_set_current: /** * ab8500_charger_set_vbus_in_curr() - set VBUS input current limit * @di: pointer to the ab8500_charger structure - * @ich_in: charger input current limit + * @ich_in_ua: charger input current limit in microampere * * Sets the current that can be drawn from the USB host * Returns error code in case of failure else 0(on success) */ static int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di, - int ich_in) + int ich_in_ua) { int min_value; int ret; /* We should always use to lowest current limit */ - min_value = min(di->bm->chg_params->usb_curr_max, ich_in); - if (di->max_usb_in_curr.set_max > 0) - min_value = min(di->max_usb_in_curr.set_max, min_value); + min_value = min(di->bm->chg_params->usb_curr_max_ua, ich_in_ua); + if (di->max_usb_in_curr.set_max_ua > 0) + min_value = min(di->max_usb_in_curr.set_max_ua, min_value); - if (di->usb_state.usb_current >= 0) - min_value = min(di->usb_state.usb_current, min_value); + if (di->usb_state.usb_current_ua >= 0) + min_value = min(di->usb_state.usb_current_ua, min_value); switch (min_value) { - case 100: + case 100000: if (di->vbat < VBAT_TRESH_IP_CUR_RED) min_value = USB_CH_IP_CUR_LVL_0P05; break; - case 500: + case 500000: if (di->vbat < VBAT_TRESH_IP_CUR_RED) min_value = USB_CH_IP_CUR_LVL_0P45; break; @@ -1293,7 +1295,7 @@ static int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di, break; } - dev_info(di->dev, "VBUS input current limit set to %d mA\n", min_value); + dev_info(di->dev, "VBUS input current limit set to %d uA\n", min_value); mutex_lock(&di->usb_ipt_crnt_lock); ret = ab8500_charger_set_current(di, min_value, @@ -1306,30 +1308,30 @@ static int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di, /** * ab8500_charger_set_main_in_curr() - set main charger input current * @di: pointer to the ab8500_charger structure - * @ich_in: input charger current, in mA + * @ich_in_ua: input charger current, in uA * * Set main charger input current. * Returns error code in case of failure else 0(on success) */ static int ab8500_charger_set_main_in_curr(struct ab8500_charger *di, - int ich_in) + int ich_in_ua) { - return ab8500_charger_set_current(di, ich_in, + return ab8500_charger_set_current(di, ich_in_ua, AB8500_MCH_IPT_CURLVL_REG); } /** * ab8500_charger_set_output_curr() - set charger output current * @di: pointer to the ab8500_charger structure - * @ich_out: output charger current, in mA + * @ich_out_ua: output charger current, in uA * * Set charger output current. * Returns error code in case of failure else 0(on success) */ static int ab8500_charger_set_output_curr(struct ab8500_charger *di, - int ich_out) + int ich_out_ua) { - return ab8500_charger_set_current(di, ich_out, + return ab8500_charger_set_current(di, ich_out_ua, AB8500_CH_OPT_CRNTLVL_REG); } @@ -1381,13 +1383,13 @@ static int ab8500_charger_led_en(struct ab8500_charger *di, int on) * @di: pointer to the ab8500_charger structure * @enable: enable/disable flag * @vset: charging voltage - * @iset: charging current + * @iset_ua: charging current in microampere * * Enable/Disable AC/Mains charging and turns on/off the charging led * respectively. **/ static int ab8500_charger_ac_en(struct ux500_charger *charger, - int enable, int vset, int iset) + int enable, int vset, int iset_ua) { int ret; int volt_index; @@ -1405,7 +1407,7 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, } /* Enable AC charging */ - dev_dbg(di->dev, "Enable AC: %dmV %dmA\n", vset, iset); + dev_dbg(di->dev, "Enable AC: %dmV %duA\n", vset, iset_ua); /* * Due to a bug in AB8500, BTEMP_HIGH/LOW interrupts @@ -1428,9 +1430,9 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, /* Check if the requested voltage or current is valid */ volt_index = ab8500_voltage_to_regval(vset); - curr_index = ab8500_current_to_regval(di, iset); + curr_index = ab8500_current_to_regval(di, iset_ua); input_curr_index = ab8500_current_to_regval(di, - di->bm->chg_params->ac_curr_max); + di->bm->chg_params->ac_curr_max_ua); if (volt_index < 0 || curr_index < 0 || input_curr_index < 0) { dev_err(di->dev, "Charger voltage or current too high, " @@ -1447,14 +1449,14 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, } /* MainChInputCurr: current that can be drawn from the charger*/ ret = ab8500_charger_set_main_in_curr(di, - di->bm->chg_params->ac_curr_max); + di->bm->chg_params->ac_curr_max_ua); if (ret) { dev_err(di->dev, "%s Failed to set MainChInputCurr\n", __func__); return ret; } /* ChOutputCurentLevel: protected output current */ - ret = ab8500_charger_set_output_curr(di, iset); + ret = ab8500_charger_set_output_curr(di, iset_ua); if (ret) { dev_err(di->dev, "%s " "Failed to set ChOutputCurentLevel\n", @@ -1558,13 +1560,13 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, * @di: pointer to the ab8500_charger structure * @enable: enable/disable flag * @vset: charging voltage - * @ich_out: charger output current + * @ich_out_ua: charger output current in microampere * * Enable/Disable USB charging and turns on/off the charging led respectively. * Returns error code in case of failure else 0(on success) */ static int ab8500_charger_usb_en(struct ux500_charger *charger, - int enable, int vset, int ich_out) + int enable, int vset, int ich_out_ua) { int ret; int volt_index; @@ -1600,11 +1602,11 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger, } /* Enable USB charging */ - dev_dbg(di->dev, "Enable USB: %dmV %dmA\n", vset, ich_out); + dev_dbg(di->dev, "Enable USB: %d mV %d uA\n", vset, ich_out_ua); /* Check if the requested voltage or current is valid */ volt_index = ab8500_voltage_to_regval(vset); - curr_index = ab8500_current_to_regval(di, ich_out); + curr_index = ab8500_current_to_regval(di, ich_out_ua); if (volt_index < 0 || curr_index < 0) { dev_err(di->dev, "Charger voltage or current too high, " @@ -1645,14 +1647,14 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger, /* USBChInputCurr: current that can be drawn from the usb */ ret = ab8500_charger_set_vbus_in_curr(di, - di->max_usb_in_curr.usb_type_max); + di->max_usb_in_curr.usb_type_max_ua); if (ret) { dev_err(di->dev, "setting USBChInputCurr failed\n"); return ret; } /* ChOutputCurentLevel: protected output current */ - ret = ab8500_charger_set_output_curr(di, ich_out); + ret = ab8500_charger_set_output_curr(di, ich_out_ua); if (ret) { dev_err(di->dev, "%s " "Failed to set ChOutputCurentLevel\n", @@ -1739,13 +1741,13 @@ out: * ab8500_charger_usb_check_enable() - enable usb charging * @charger: pointer to the ux500_charger structure * @vset: charging voltage - * @iset: charger output current + * @iset_ua: charger output current in microampere * * Check if the VBUS charger has been disconnected and reconnected without * AB8500 rising an interrupt. Returns 0 on success. */ static int ab8500_charger_usb_check_enable(struct ux500_charger *charger, - int vset, int iset) + int vset, int iset_ua) { u8 usbch_ctrl1 = 0; int ret = 0; @@ -1774,7 +1776,7 @@ static int ab8500_charger_usb_check_enable(struct ux500_charger *charger, return ret; } - ret = ab8500_charger_usb_en(&di->usb_chg, true, vset, iset); + ret = ab8500_charger_usb_en(&di->usb_chg, true, vset, iset_ua); if (ret < 0) { dev_err(di->dev, "Failed to enable VBUS charger %d\n", __LINE__); @@ -1788,13 +1790,13 @@ static int ab8500_charger_usb_check_enable(struct ux500_charger *charger, * ab8500_charger_ac_check_enable() - enable usb charging * @charger: pointer to the ux500_charger structure * @vset: charging voltage - * @iset: charger output current + * @iset_ua: charger output current in micrompere * * Check if the AC charger has been disconnected and reconnected without * AB8500 rising an interrupt. Returns 0 on success. */ static int ab8500_charger_ac_check_enable(struct ux500_charger *charger, - int vset, int iset) + int vset, int iset_ua) { u8 mainch_ctrl1 = 0; int ret = 0; @@ -1824,7 +1826,7 @@ static int ab8500_charger_ac_check_enable(struct ux500_charger *charger, return ret; } - ret = ab8500_charger_ac_en(&di->usb_chg, true, vset, iset); + ret = ab8500_charger_ac_en(&di->usb_chg, true, vset, iset_ua); if (ret < 0) { dev_err(di->dev, "failed to enable AC charger %d\n", __LINE__); @@ -1863,13 +1865,14 @@ static int ab8500_charger_watchdog_kick(struct ux500_charger *charger) /** * ab8500_charger_update_charger_current() - update charger current - * @di: pointer to the ab8500_charger structure + * @charger: pointer to the ab8500_charger structure + * @ich_out_ua: desired output current in microampere * * Update the charger output current for the specified charger * Returns error code in case of failure else 0(on success) */ static int ab8500_charger_update_charger_current(struct ux500_charger *charger, - int ich_out) + int ich_out_ua) { int ret; struct ab8500_charger *di; @@ -1881,7 +1884,7 @@ static int ab8500_charger_update_charger_current(struct ux500_charger *charger, else return -ENXIO; - ret = ab8500_charger_set_output_curr(di, ich_out); + ret = ab8500_charger_set_output_curr(di, ich_out_ua); if (ret) { dev_err(di->dev, "%s " "Failed to set ChOutputCurentLevel\n", @@ -1973,10 +1976,10 @@ static void ab8500_charger_check_vbat_work(struct work_struct *work) di->vbat > VBAT_TRESH_IP_CUR_RED))) { dev_dbg(di->dev, "Vbat did cross threshold, curr: %d, new: %d," - " old: %d\n", di->max_usb_in_curr.usb_type_max, + " old: %d\n", di->max_usb_in_curr.usb_type_max_ua, di->vbat, di->old_vbat); ab8500_charger_set_vbus_in_curr(di, - di->max_usb_in_curr.usb_type_max); + di->max_usb_in_curr.usb_type_max_ua); power_supply_changed(di->usb_chg.psy); } @@ -2257,7 +2260,7 @@ static void ab8500_charger_usb_link_attach_work(struct work_struct *work) /* Update maximum input current if USB enumeration is not detected */ if (!di->usb.charger_online) { ret = ab8500_charger_set_vbus_in_curr(di, - di->max_usb_in_curr.usb_type_max); + di->max_usb_in_curr.usb_type_max_ua); if (ret) return; } @@ -2419,11 +2422,11 @@ static void ab8500_charger_usb_state_changed_work(struct work_struct *work) spin_lock_irqsave(&di->usb_state.usb_lock, flags); di->usb_state.state = di->usb_state.state_tmp; - di->usb_state.usb_current = di->usb_state.usb_current_tmp; + di->usb_state.usb_current_ua = di->usb_state.usb_current_tmp_ua; spin_unlock_irqrestore(&di->usb_state.usb_lock, flags); - dev_dbg(di->dev, "%s USB state: 0x%02x mA: %d\n", - __func__, di->usb_state.state, di->usb_state.usb_current); + dev_dbg(di->dev, "%s USB state: 0x%02x uA: %d\n", + __func__, di->usb_state.state, di->usb_state.usb_current_ua); switch (di->usb_state.state) { case AB8500_BM_USB_STATE_RESET_HS: @@ -2449,7 +2452,7 @@ static void ab8500_charger_usb_state_changed_work(struct work_struct *work) if (!ab8500_charger_get_usb_cur(di)) { /* Update maximum input current */ ret = ab8500_charger_set_vbus_in_curr(di, - di->max_usb_in_curr.usb_type_max); + di->max_usb_in_curr.usb_type_max_ua); if (ret) return; @@ -2669,7 +2672,7 @@ static void ab8500_charger_vbus_drop_end_work(struct work_struct *work) { struct ab8500_charger *di = container_of(work, struct ab8500_charger, vbus_drop_end_work.work); - int ret, curr; + int ret, curr_ua; u8 reg_value; di->flags.vbus_drop_end = false; @@ -2685,30 +2688,30 @@ static void ab8500_charger_vbus_drop_end_work(struct work_struct *work) return; } - curr = ab8500_charge_input_curr_map[ + curr_ua = ab8500_charge_input_curr_map[ reg_value >> AUTO_VBUS_IN_CURR_LIM_SHIFT]; - if (di->max_usb_in_curr.calculated_max != curr) { + if (di->max_usb_in_curr.calculated_max_ua != curr_ua) { /* USB source is collapsing */ - di->max_usb_in_curr.calculated_max = curr; + di->max_usb_in_curr.calculated_max_ua = curr_ua; dev_dbg(di->dev, - "VBUS input current limiting to %d mA\n", - di->max_usb_in_curr.calculated_max); + "VBUS input current limiting to %d uA\n", + di->max_usb_in_curr.calculated_max_ua); } else { /* * USB source can not give more than this amount. * Taking more will collapse the source. */ - di->max_usb_in_curr.set_max = - di->max_usb_in_curr.calculated_max; + di->max_usb_in_curr.set_max_ua = + di->max_usb_in_curr.calculated_max_ua; dev_dbg(di->dev, - "VBUS input current limited to %d mA\n", - di->max_usb_in_curr.set_max); + "VBUS input current limited to %d uA\n", + di->max_usb_in_curr.set_max_ua); } if (di->usb.charger_connected) ab8500_charger_set_vbus_in_curr(di, - di->max_usb_in_curr.usb_type_max); + di->max_usb_in_curr.usb_type_max_ua); } /** @@ -2953,8 +2956,8 @@ static int ab8500_charger_ac_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CURRENT_NOW: ret = ab8500_charger_get_ac_current(di); if (ret >= 0) - di->ac.charger_current = ret; - val->intval = di->ac.charger_current * 1000; + di->ac.charger_current_ua = ret; + val->intval = di->ac.charger_current_ua; break; default: return -EINVAL; @@ -3021,8 +3024,8 @@ static int ab8500_charger_usb_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CURRENT_NOW: ret = ab8500_charger_get_usb_current(di); if (ret >= 0) - di->usb.charger_current = ret; - val->intval = di->usb.charger_current * 1000; + di->usb.charger_current_ua = ret; + val->intval = di->usb.charger_current_ua; break; case POWER_SUPPLY_PROP_CURRENT_AVG: /* @@ -3198,6 +3201,11 @@ static int ab8500_charger_usb_notifier_call(struct notifier_block *nb, struct ab8500_charger *di = container_of(nb, struct ab8500_charger, nb); enum ab8500_usb_state bm_usb_state; + /* + * FIXME: it appears the AB8500 PHY never sends what it should here. + * Fix the PHY driver to properly notify the desired current. + * Also broadcast microampere and not milliampere. + */ unsigned mA = *((unsigned *)power); if (event != USB_EVENT_VBUS) { @@ -3208,7 +3216,7 @@ static int ab8500_charger_usb_notifier_call(struct notifier_block *nb, /* TODO: State is fabricate here. See if charger really needs USB * state or if mA is enough */ - if ((di->usb_state.usb_current == 2) && (mA > 2)) + if ((di->usb_state.usb_current_ua == 2000) && (mA > 2)) bm_usb_state = AB8500_BM_USB_STATE_RESUME; else if (mA == 0) bm_usb_state = AB8500_BM_USB_STATE_RESET_HS; @@ -3224,7 +3232,8 @@ static int ab8500_charger_usb_notifier_call(struct notifier_block *nb, spin_lock(&di->usb_state.usb_lock); di->usb_state.state_tmp = bm_usb_state; - di->usb_state.usb_current_tmp = mA; + /* FIXME: broadcast ua instead, see above */ + di->usb_state.usb_current_tmp_ua = mA * 1000; spin_unlock(&di->usb_state.usb_lock); /* @@ -3514,7 +3523,7 @@ static int ab8500_charger_probe(struct platform_device *pdev) di->ac_chg.ops.update_curr = &ab8500_charger_update_charger_current; di->ac_chg.max_out_volt = ab8500_charger_voltage_map[ ARRAY_SIZE(ab8500_charger_voltage_map) - 1]; - di->ac_chg.max_out_curr = + di->ac_chg.max_out_curr_ua = ab8500_charge_output_curr_map[ARRAY_SIZE(ab8500_charge_output_curr_map) - 1]; di->ac_chg.wdt_refresh = CHG_WD_INTERVAL; /* @@ -3535,11 +3544,11 @@ static int ab8500_charger_probe(struct platform_device *pdev) di->usb_chg.ops.update_curr = &ab8500_charger_update_charger_current; di->usb_chg.max_out_volt = ab8500_charger_voltage_map[ ARRAY_SIZE(ab8500_charger_voltage_map) - 1]; - di->usb_chg.max_out_curr = + di->usb_chg.max_out_curr_ua = ab8500_charge_output_curr_map[ARRAY_SIZE(ab8500_charge_output_curr_map) - 1]; di->usb_chg.wdt_refresh = CHG_WD_INTERVAL; di->usb_chg.external = false; - di->usb_state.usb_current = -1; + di->usb_state.usb_current_ua = -1; mutex_init(&di->charger_attached_mutex); -- GitLab From bc6e0287140216011b99392fdf687a92707675ad Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:24 +0100 Subject: [PATCH 0130/1112] power: supply: ab8500: Standardize CV voltage The voltage used in the constant voltage phase of the charging exist in struct power_supply_battery_info as constant_charge_voltage_max_uv. Switch the custom property normal_vol_lvl to this and consequentially change everything that relates to this value over to using microvolts rather than millivolts so we align internal representation of current with the power core. Prefix every variable we change with *_uv to indicate the unit everywhere but also to make sure we do not miss any outlier. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 10 +- drivers/power/supply/ab8500-chargalg.h | 4 +- drivers/power/supply/ab8500_bmdata.c | 8 +- drivers/power/supply/ab8500_chargalg.c | 62 +++---- drivers/power/supply/ab8500_charger.c | 218 +++++++++++++------------ 5 files changed, 152 insertions(+), 150 deletions(-) diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index c8841567dfee5..febf2dea853b2 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -367,7 +367,6 @@ struct ab8500_maxim_parameters { * struct ab8500_battery_type - different batteries supported * @resis_high: battery upper resistance limit * @resis_low: battery lower resistance limit - * @normal_vol_lvl: charger voltage in normal state in mV * @maint_a_cur_lvl: charger current in maintenance A state in mA * @maint_a_vol_lvl: charger voltage in maintenance A state in mV * @maint_a_chg_timer_h: charge time in maintenance A state @@ -386,7 +385,6 @@ struct ab8500_maxim_parameters { struct ab8500_battery_type { int resis_high; int resis_low; - int normal_vol_lvl; int maint_a_cur_lvl; int maint_a_vol_lvl; int maint_a_chg_timer_h; @@ -421,15 +419,15 @@ struct ab8500_bm_capacity_levels { /** * struct ab8500_bm_charger_parameters - Charger specific parameters - * @usb_volt_max: maximum allowed USB charger voltage in mV + * @usb_volt_max_uv: maximum allowed USB charger voltage in uV * @usb_curr_max_ua: maximum allowed USB charger current in uA - * @ac_volt_max: maximum allowed AC charger voltage in mV + * @ac_volt_max_uv: maximum allowed AC charger voltage in uV * @ac_curr_max_ua: maximum allowed AC charger current in uA */ struct ab8500_bm_charger_parameters { - int usb_volt_max; + int usb_volt_max_uv; int usb_curr_max_ua; - int ac_volt_max; + int ac_volt_max_uv; int ac_curr_max_ua; }; diff --git a/drivers/power/supply/ab8500-chargalg.h b/drivers/power/supply/ab8500-chargalg.h index 8094a3c2bd3a7..f47a0061c36a2 100644 --- a/drivers/power/supply/ab8500-chargalg.h +++ b/drivers/power/supply/ab8500-chargalg.h @@ -31,7 +31,7 @@ struct ux500_charger_ops { * struct ux500_charger - power supply ux500 charger sub class * @psy power supply base class * @ops ux500 charger operations - * @max_out_volt maximum output charger voltage in mV + * @max_out_volt_uv maximum output charger voltage in uV * @max_out_curr_ua maximum output charger current in uA * @enabled indicates if this charger is used or not * @external external charger unit (pm2xxx) @@ -39,7 +39,7 @@ struct ux500_charger_ops { struct ux500_charger { struct power_supply *psy; struct ux500_charger_ops ops; - int max_out_volt; + int max_out_volt_uv; int max_out_curr_ua; int wdt_refresh; bool enabled; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index e9bbb7517e045..ce0a5fcb31773 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -83,7 +83,6 @@ static const struct batres_vs_temp temp_to_batres_tbl_thermistor[] = { static struct ab8500_battery_type bat_type_thermistor_unknown = { .resis_high = 0, .resis_low = 0, - .normal_vol_lvl = 4100, .maint_a_cur_lvl = 400, .maint_a_vol_lvl = 4050, .maint_a_chg_timer_h = 60, @@ -138,9 +137,9 @@ static const struct ab8500_maxim_parameters ab8500_maxi_params = { }; static const struct ab8500_bm_charger_parameters chg = { - .usb_volt_max = 5500, + .usb_volt_max_uv = 5500000, .usb_curr_max_ua = 1500000, - .ac_volt_max = 7500, + .ac_volt_max_uv = 7500000, .ac_curr_max_ua = 1500000, }; @@ -203,6 +202,9 @@ int ab8500_bm_of_probe(struct power_supply *psy, if (bi->constant_charge_current_max_ua < 0) bi->constant_charge_current_max_ua = 400000; + if (bi->constant_charge_voltage_max_uv < 0) + bi->constant_charge_voltage_max_uv = 4100000; + if (bi->charge_term_current_ua) /* Charging stops when we drop below this current */ bi->charge_term_current_ua = 200000; diff --git a/drivers/power/supply/ab8500_chargalg.c b/drivers/power/supply/ab8500_chargalg.c index 8ad3924ee4969..86d740ce3a638 100644 --- a/drivers/power/supply/ab8500_chargalg.c +++ b/drivers/power/supply/ab8500_chargalg.c @@ -70,13 +70,13 @@ struct ab8500_chargalg_charger_info { enum ab8500_chargers charger_type; bool usb_chg_ok; bool ac_chg_ok; - int usb_volt; + int usb_volt_uv; int usb_curr_ua; - int ac_volt; + int ac_volt_uv; int ac_curr_ua; - int usb_vset; + int usb_vset_uv; int usb_iset_ua; - int ac_vset; + int ac_vset_uv; int ac_iset_ua; }; @@ -365,12 +365,12 @@ static int ab8500_chargalg_check_charger_enable(struct ab8500_chargalg *di) if (di->chg_info.charger_type & USB_CHG) { return di->usb_chg->ops.check_enable(di->usb_chg, - di->bm->bat_type->normal_vol_lvl, + bi->constant_charge_voltage_max_uv, bi->constant_charge_current_max_ua); } else if ((di->chg_info.charger_type & AC_CHG) && !(di->ac_chg->external)) { return di->ac_chg->ops.check_enable(di->ac_chg, - di->bm->bat_type->normal_vol_lvl, + bi->constant_charge_voltage_max_uv, bi->constant_charge_current_max_ua); } return 0; @@ -546,14 +546,14 @@ static int ab8500_chargalg_kick_watchdog(struct ab8500_chargalg *di) * ab8500_chargalg_ac_en() - Turn on/off the AC charger * @di: pointer to the ab8500_chargalg structure * @enable: charger on/off - * @vset: requested charger output voltage + * @vset_uv: requested charger output voltage in microvolt * @iset_ua: requested charger output current in microampere * * The AC charger will be turned on/off with the requested charge voltage and * current */ static int ab8500_chargalg_ac_en(struct ab8500_chargalg *di, int enable, - int vset, int iset_ua) + int vset_uv, int iset_ua) { static int ab8500_chargalg_ex_ac_enable_toggle; @@ -561,13 +561,13 @@ static int ab8500_chargalg_ac_en(struct ab8500_chargalg *di, int enable, return -ENXIO; /* Select maximum of what both the charger and the battery supports */ - if (di->ac_chg->max_out_volt) - vset = min(vset, di->ac_chg->max_out_volt); + if (di->ac_chg->max_out_volt_uv) + vset_uv = min(vset_uv, di->ac_chg->max_out_volt_uv); if (di->ac_chg->max_out_curr_ua) iset_ua = min(iset_ua, di->ac_chg->max_out_curr_ua); di->chg_info.ac_iset_ua = iset_ua; - di->chg_info.ac_vset = vset; + di->chg_info.ac_vset_uv = vset_uv; /* Enable external charger */ if (enable && di->ac_chg->external && @@ -577,35 +577,35 @@ static int ab8500_chargalg_ac_en(struct ab8500_chargalg *di, int enable, ab8500_chargalg_ex_ac_enable_toggle++; } - return di->ac_chg->ops.enable(di->ac_chg, enable, vset, iset_ua); + return di->ac_chg->ops.enable(di->ac_chg, enable, vset_uv, iset_ua); } /** * ab8500_chargalg_usb_en() - Turn on/off the USB charger * @di: pointer to the ab8500_chargalg structure * @enable: charger on/off - * @vset: requested charger output voltage + * @vset_uv: requested charger output voltage in microvolt * @iset_ua: requested charger output current in microampere * * The USB charger will be turned on/off with the requested charge voltage and * current */ static int ab8500_chargalg_usb_en(struct ab8500_chargalg *di, int enable, - int vset, int iset_ua) + int vset_uv, int iset_ua) { if (!di->usb_chg || !di->usb_chg->ops.enable) return -ENXIO; /* Select maximum of what both the charger and the battery supports */ - if (di->usb_chg->max_out_volt) - vset = min(vset, di->usb_chg->max_out_volt); + if (di->usb_chg->max_out_volt_uv) + vset_uv = min(vset_uv, di->usb_chg->max_out_volt_uv); if (di->usb_chg->max_out_curr_ua) iset_ua = min(iset_ua, di->usb_chg->max_out_curr_ua); di->chg_info.usb_iset_ua = iset_ua; - di->chg_info.usb_vset = vset; + di->chg_info.usb_vset_uv = vset_uv; - return di->usb_chg->ops.enable(di->usb_chg, enable, vset, iset_ua); + return di->usb_chg->ops.enable(di->usb_chg, enable, vset_uv, iset_ua); } /** @@ -692,28 +692,28 @@ static void ab8500_chargalg_hold_charging(struct ab8500_chargalg *di) /** * ab8500_chargalg_start_charging() - Start the charger * @di: pointer to the ab8500_chargalg structure - * @vset: requested charger output voltage + * @vset_uv: requested charger output voltage in microvolt * @iset_ua: requested charger output current in microampere * * A charger will be enabled depending on the requested charger type that was * detected previously. */ static void ab8500_chargalg_start_charging(struct ab8500_chargalg *di, - int vset, int iset_ua) + int vset_uv, int iset_ua) { switch (di->chg_info.charger_type) { case AC_CHG: dev_dbg(di->dev, - "AC parameters: Vset %d, Ich %d\n", vset, iset_ua); + "AC parameters: Vset %d, Ich %d\n", vset_uv, iset_ua); ab8500_chargalg_usb_en(di, false, 0, 0); - ab8500_chargalg_ac_en(di, true, vset, iset_ua); + ab8500_chargalg_ac_en(di, true, vset_uv, iset_ua); break; case USB_CHG: dev_dbg(di->dev, - "USB parameters: Vset %d, Ich %d\n", vset, iset_ua); + "USB parameters: Vset %d, Ich %d\n", vset_uv, iset_ua); ab8500_chargalg_ac_en(di, false, 0, 0); - ab8500_chargalg_usb_en(di, true, vset, iset_ua); + ab8500_chargalg_usb_en(di, true, vset_uv, iset_ua); break; default: @@ -777,12 +777,12 @@ static void ab8500_chargalg_check_temp(struct ab8500_chargalg *di) */ static void ab8500_chargalg_check_charger_voltage(struct ab8500_chargalg *di) { - if (di->chg_info.usb_volt > di->bm->chg_params->usb_volt_max) + if (di->chg_info.usb_volt_uv > di->bm->chg_params->usb_volt_max_uv) di->chg_info.usb_chg_ok = false; else di->chg_info.usb_chg_ok = true; - if (di->chg_info.ac_volt > di->bm->chg_params->ac_volt_max) + if (di->chg_info.ac_volt_uv > di->bm->chg_params->ac_volt_max_uv) di->chg_info.ac_chg_ok = false; else di->chg_info.ac_chg_ok = true; @@ -1173,10 +1173,10 @@ static int ab8500_chargalg_get_ext_psy_data(struct device *dev, void *data) di->batt_data.volt_uv = ret.intval; break; case POWER_SUPPLY_TYPE_MAINS: - di->chg_info.ac_volt = ret.intval / 1000; + di->chg_info.ac_volt_uv = ret.intval; break; case POWER_SUPPLY_TYPE_USB: - di->chg_info.usb_volt = ret.intval / 1000; + di->chg_info.usb_volt_uv = ret.intval; break; default: break; @@ -1423,9 +1423,9 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) di->events.usb_cv_active, di->chg_info.ac_curr_ua, di->chg_info.usb_curr_ua, - di->chg_info.ac_vset, + di->chg_info.ac_vset_uv, di->chg_info.ac_iset_ua, - di->chg_info.usb_vset, + di->chg_info.usb_vset_uv, di->chg_info.usb_iset_ua); switch (di->charge_state) { @@ -1518,7 +1518,7 @@ static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) * di->curr_status.curr_step_ua / CHARGALG_CURR_STEP_HIGH_UA; ab8500_chargalg_start_charging(di, - di->bm->bat_type->normal_vol_lvl, + bi->constant_charge_voltage_max_uv, curr_step_lvl_ua); } diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c index e66091f3f6064..db7457064a179 100644 --- a/drivers/power/supply/ab8500_charger.c +++ b/drivers/power/supply/ab8500_charger.c @@ -183,7 +183,7 @@ struct ab8500_charger_interrupts { struct ab8500_charger_info { int charger_connected; int charger_online; - int charger_voltage; + int charger_voltage_uv; int cv_active; bool wd_expired; int charger_current_ua; @@ -479,7 +479,7 @@ static void ab8500_charger_set_usb_connected(struct ab8500_charger *di, * ab8500_charger_get_ac_voltage() - get ac charger voltage * @di: pointer to the ab8500_charger structure * - * Returns ac charger voltage (on success) + * Returns ac charger voltage in microvolt (on success) */ static int ab8500_charger_get_ac_voltage(struct ab8500_charger *di) { @@ -493,7 +493,8 @@ static int ab8500_charger_get_ac_voltage(struct ab8500_charger *di) } else { vch = 0; } - return vch; + /* Convert to microvolt, IIO returns millivolt */ + return vch * 1000; } /** @@ -530,7 +531,7 @@ static int ab8500_charger_ac_cv(struct ab8500_charger *di) * @di: pointer to the ab8500_charger structure * * This function returns the vbus voltage. - * Returns vbus voltage (on success) + * Returns vbus voltage in microvolt (on success) */ static int ab8500_charger_get_vbus_voltage(struct ab8500_charger *di) { @@ -544,7 +545,8 @@ static int ab8500_charger_get_vbus_voltage(struct ab8500_charger *di) } else { vch = 0; } - return vch; + /* Convert to microvolt, IIO returns millivolt */ + return vch * 1000; } /** @@ -923,105 +925,105 @@ static int ab8500_charger_detect_usb_type(struct ab8500_charger *di) /* * This array maps the raw hex value to charger voltage used by the AB8500 - * Values taken from the UM0836 + * Values taken from the UM0836, in microvolt. */ static int ab8500_charger_voltage_map[] = { - 3500 , - 3525 , - 3550 , - 3575 , - 3600 , - 3625 , - 3650 , - 3675 , - 3700 , - 3725 , - 3750 , - 3775 , - 3800 , - 3825 , - 3850 , - 3875 , - 3900 , - 3925 , - 3950 , - 3975 , - 4000 , - 4025 , - 4050 , - 4060 , - 4070 , - 4080 , - 4090 , - 4100 , - 4110 , - 4120 , - 4130 , - 4140 , - 4150 , - 4160 , - 4170 , - 4180 , - 4190 , - 4200 , - 4210 , - 4220 , - 4230 , - 4240 , - 4250 , - 4260 , - 4270 , - 4280 , - 4290 , - 4300 , - 4310 , - 4320 , - 4330 , - 4340 , - 4350 , - 4360 , - 4370 , - 4380 , - 4390 , - 4400 , - 4410 , - 4420 , - 4430 , - 4440 , - 4450 , - 4460 , - 4470 , - 4480 , - 4490 , - 4500 , - 4510 , - 4520 , - 4530 , - 4540 , - 4550 , - 4560 , - 4570 , - 4580 , - 4590 , - 4600 , + 3500000, + 3525000, + 3550000, + 3575000, + 3600000, + 3625000, + 3650000, + 3675000, + 3700000, + 3725000, + 3750000, + 3775000, + 3800000, + 3825000, + 3850000, + 3875000, + 3900000, + 3925000, + 3950000, + 3975000, + 4000000, + 4025000, + 4050000, + 4060000, + 4070000, + 4080000, + 4090000, + 4100000, + 4110000, + 4120000, + 4130000, + 4140000, + 4150000, + 4160000, + 4170000, + 4180000, + 4190000, + 4200000, + 4210000, + 4220000, + 4230000, + 4240000, + 4250000, + 4260000, + 4270000, + 4280000, + 4290000, + 4300000, + 4310000, + 4320000, + 4330000, + 4340000, + 4350000, + 4360000, + 4370000, + 4380000, + 4390000, + 4400000, + 4410000, + 4420000, + 4430000, + 4440000, + 4450000, + 4460000, + 4470000, + 4480000, + 4490000, + 4500000, + 4510000, + 4520000, + 4530000, + 4540000, + 4550000, + 4560000, + 4570000, + 4580000, + 4590000, + 4600000, }; -static int ab8500_voltage_to_regval(int voltage) +static int ab8500_voltage_to_regval(int voltage_uv) { int i; /* Special case for voltage below 3.5V */ - if (voltage < ab8500_charger_voltage_map[0]) + if (voltage_uv < ab8500_charger_voltage_map[0]) return LOW_VOLT_REG; for (i = 1; i < ARRAY_SIZE(ab8500_charger_voltage_map); i++) { - if (voltage < ab8500_charger_voltage_map[i]) + if (voltage_uv < ab8500_charger_voltage_map[i]) return i - 1; } /* If not last element, return error */ i = ARRAY_SIZE(ab8500_charger_voltage_map) - 1; - if (voltage == ab8500_charger_voltage_map[i]) + if (voltage_uv == ab8500_charger_voltage_map[i]) return i; else return -1; @@ -1382,14 +1384,14 @@ static int ab8500_charger_led_en(struct ab8500_charger *di, int on) * ab8500_charger_ac_en() - enable or disable ac charging * @di: pointer to the ab8500_charger structure * @enable: enable/disable flag - * @vset: charging voltage + * @vset_uv: charging voltage in microvolt * @iset_ua: charging current in microampere * * Enable/Disable AC/Mains charging and turns on/off the charging led * respectively. **/ static int ab8500_charger_ac_en(struct ux500_charger *charger, - int enable, int vset, int iset_ua) + int enable, int vset_uv, int iset_ua) { int ret; int volt_index; @@ -1407,7 +1409,7 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, } /* Enable AC charging */ - dev_dbg(di->dev, "Enable AC: %dmV %duA\n", vset, iset_ua); + dev_dbg(di->dev, "Enable AC: %duV %duA\n", vset_uv, iset_ua); /* * Due to a bug in AB8500, BTEMP_HIGH/LOW interrupts @@ -1429,7 +1431,7 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, } /* Check if the requested voltage or current is valid */ - volt_index = ab8500_voltage_to_regval(vset); + volt_index = ab8500_voltage_to_regval(vset_uv); curr_index = ab8500_current_to_regval(di, iset_ua); input_curr_index = ab8500_current_to_regval(di, di->bm->chg_params->ac_curr_max_ua); @@ -1559,14 +1561,14 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, * ab8500_charger_usb_en() - enable usb charging * @di: pointer to the ab8500_charger structure * @enable: enable/disable flag - * @vset: charging voltage + * @vset_uv: charging voltage in microvolt * @ich_out_ua: charger output current in microampere * * Enable/Disable USB charging and turns on/off the charging led respectively. * Returns error code in case of failure else 0(on success) */ static int ab8500_charger_usb_en(struct ux500_charger *charger, - int enable, int vset, int ich_out_ua) + int enable, int vset_uv, int ich_out_ua) { int ret; int volt_index; @@ -1602,10 +1604,10 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger, } /* Enable USB charging */ - dev_dbg(di->dev, "Enable USB: %d mV %d uA\n", vset, ich_out_ua); + dev_dbg(di->dev, "Enable USB: %d uV %d uA\n", vset_uv, ich_out_ua); /* Check if the requested voltage or current is valid */ - volt_index = ab8500_voltage_to_regval(vset); + volt_index = ab8500_voltage_to_regval(vset_uv); curr_index = ab8500_current_to_regval(di, ich_out_ua); if (volt_index < 0 || curr_index < 0) { dev_err(di->dev, @@ -1740,14 +1742,14 @@ out: /** * ab8500_charger_usb_check_enable() - enable usb charging * @charger: pointer to the ux500_charger structure - * @vset: charging voltage + * @vset_uv: charging voltage in microvolt * @iset_ua: charger output current in microampere * * Check if the VBUS charger has been disconnected and reconnected without * AB8500 rising an interrupt. Returns 0 on success. */ static int ab8500_charger_usb_check_enable(struct ux500_charger *charger, - int vset, int iset_ua) + int vset_uv, int iset_ua) { u8 usbch_ctrl1 = 0; int ret = 0; @@ -1776,7 +1778,7 @@ static int ab8500_charger_usb_check_enable(struct ux500_charger *charger, return ret; } - ret = ab8500_charger_usb_en(&di->usb_chg, true, vset, iset_ua); + ret = ab8500_charger_usb_en(&di->usb_chg, true, vset_uv, iset_ua); if (ret < 0) { dev_err(di->dev, "Failed to enable VBUS charger %d\n", __LINE__); @@ -1789,14 +1791,14 @@ static int ab8500_charger_usb_check_enable(struct ux500_charger *charger, /** * ab8500_charger_ac_check_enable() - enable usb charging * @charger: pointer to the ux500_charger structure - * @vset: charging voltage + * @vset_uv: charging voltage in microvolt * @iset_ua: charger output current in micrompere * * Check if the AC charger has been disconnected and reconnected without * AB8500 rising an interrupt. Returns 0 on success. */ static int ab8500_charger_ac_check_enable(struct ux500_charger *charger, - int vset, int iset_ua) + int vset_uv, int iset_ua) { u8 mainch_ctrl1 = 0; int ret = 0; @@ -1826,7 +1828,7 @@ static int ab8500_charger_ac_check_enable(struct ux500_charger *charger, return ret; } - ret = ab8500_charger_ac_en(&di->usb_chg, true, vset, iset_ua); + ret = ab8500_charger_ac_en(&di->usb_chg, true, vset_uv, iset_ua); if (ret < 0) { dev_err(di->dev, "failed to enable AC charger %d\n", __LINE__); @@ -2941,9 +2943,9 @@ static int ab8500_charger_ac_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_VOLTAGE_NOW: ret = ab8500_charger_get_ac_voltage(di); if (ret >= 0) - di->ac.charger_voltage = ret; + di->ac.charger_voltage_uv = ret; /* On error, use previous value */ - val->intval = di->ac.charger_voltage * 1000; + val->intval = di->ac.charger_voltage_uv; break; case POWER_SUPPLY_PROP_VOLTAGE_AVG: /* @@ -3010,8 +3012,8 @@ static int ab8500_charger_usb_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_VOLTAGE_NOW: ret = ab8500_charger_get_vbus_voltage(di); if (ret >= 0) - di->usb.charger_voltage = ret; - val->intval = di->usb.charger_voltage * 1000; + di->usb.charger_voltage_uv = ret; + val->intval = di->usb.charger_voltage_uv; break; case POWER_SUPPLY_PROP_VOLTAGE_AVG: /* @@ -3521,7 +3523,7 @@ static int ab8500_charger_probe(struct platform_device *pdev) di->ac_chg.ops.check_enable = &ab8500_charger_ac_check_enable; di->ac_chg.ops.kick_wd = &ab8500_charger_watchdog_kick; di->ac_chg.ops.update_curr = &ab8500_charger_update_charger_current; - di->ac_chg.max_out_volt = ab8500_charger_voltage_map[ + di->ac_chg.max_out_volt_uv = ab8500_charger_voltage_map[ ARRAY_SIZE(ab8500_charger_voltage_map) - 1]; di->ac_chg.max_out_curr_ua = ab8500_charge_output_curr_map[ARRAY_SIZE(ab8500_charge_output_curr_map) - 1]; @@ -3542,7 +3544,7 @@ static int ab8500_charger_probe(struct platform_device *pdev) di->usb_chg.ops.check_enable = &ab8500_charger_usb_check_enable; di->usb_chg.ops.kick_wd = &ab8500_charger_watchdog_kick; di->usb_chg.ops.update_curr = &ab8500_charger_update_charger_current; - di->usb_chg.max_out_volt = ab8500_charger_voltage_map[ + di->usb_chg.max_out_volt_uv = ab8500_charger_voltage_map[ ARRAY_SIZE(ab8500_charger_voltage_map) - 1]; di->usb_chg.max_out_curr_ua = ab8500_charge_output_curr_map[ARRAY_SIZE(ab8500_charge_output_curr_map) - 1]; -- GitLab From 67acb291f3b6636cc52a3f859c91c05688992a15 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:25 +0100 Subject: [PATCH 0131/1112] power: supply: ab8500: Standardize temp res lookup The lookup from battery temperature to internal resistance was using its own format. Rewrite this to use the table inside struct power_supply_battery_info:s resist_table. The supplied resistance table has to be rewritten to express the resistance in percent of the factory resistance as a side effect. We can then rely on the library function power_supply_temp2resist_simple() to interpolate the internal resistance percent from the temperature. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 15 --------- drivers/power/supply/ab8500_bmdata.c | 31 +++++++++++------- drivers/power/supply/ab8500_fg.c | 47 +++++++++++----------------- 3 files changed, 38 insertions(+), 55 deletions(-) diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index febf2dea853b2..af52539a7a7b9 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -379,8 +379,6 @@ struct ab8500_maxim_parameters { * @r_to_t_tbl: table containing resistance to temp points * @n_v_cap_tbl_elements: number of elements in v_to_cap_tbl * @v_to_cap_tbl: Voltage to capacity (in %) table - * @n_batres_tbl_elements number of elements in the batres_tbl - * @batres_tbl battery internal resistance vs temperature table */ struct ab8500_battery_type { int resis_high; @@ -397,8 +395,6 @@ struct ab8500_battery_type { const struct ab8500_res_to_temp *r_to_t_tbl; int n_v_cap_tbl_elements; const struct ab8500_v_to_cap *v_to_cap_tbl; - int n_batres_tbl_elements; - const struct batres_vs_temp *batres_tbl; }; /** @@ -502,17 +498,6 @@ struct res_to_temp { int resist; }; -/** - * struct batres_vs_temp - defines one point in a temp vs battery internal - * resistance curve. - * @temp: battery pack temperature in Celsius - * @resist: battery internal reistance in mOhm - */ -struct batres_vs_temp { - int temp; - int resist; -}; - /* Forward declaration */ struct ab8500_fg; diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index ce0a5fcb31773..1175532fe017d 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -67,16 +67,17 @@ static const struct ab8500_res_to_temp temp_tbl[] = { /* * Note that the batres_vs_temp table must be strictly sorted by falling - * temperature values to work. + * temperature values to work. Factory resistance is 300 mOhm and the + * resistance values to the right are percentages of 300 mOhm. */ -static const struct batres_vs_temp temp_to_batres_tbl_thermistor[] = { - { 40, 120}, - { 30, 135}, - { 20, 165}, - { 10, 230}, - { 00, 325}, - {-10, 445}, - {-20, 595}, +static struct power_supply_resistance_temp_table temp_to_batres_tbl_thermistor[] = { + { .temp = 40, .resistance = 40 /* 120 mOhm */ }, + { .temp = 30, .resistance = 45 /* 135 mOhm */ }, + { .temp = 20, .resistance = 55 /* 165 mOhm */ }, + { .temp = 10, .resistance = 77 /* 230 mOhm */ }, + { .temp = 00, .resistance = 108 /* 325 mOhm */ }, + { .temp = -10, .resistance = 158 /* 445 mOhm */ }, + { .temp = -20, .resistance = 198 /* 595 mOhm */ }, }; /* Default battery type for reference designs is the unknown type */ @@ -95,8 +96,6 @@ static struct ab8500_battery_type bat_type_thermistor_unknown = { .r_to_t_tbl = temp_tbl, .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl), .v_to_cap_tbl = cap_tbl, - .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor), - .batres_tbl = temp_to_batres_tbl_thermistor, }; static const struct ab8500_bm_capacity_levels cap_levels = { @@ -209,8 +208,16 @@ int ab8500_bm_of_probe(struct power_supply *psy, /* Charging stops when we drop below this current */ bi->charge_term_current_ua = 200000; - if (bi->factory_internal_resistance_uohm < 0) + /* + * Internal resistance and factory resistance are tightly coupled + * so both MUST be defined or we fall back to defaults. + */ + if ((bi->factory_internal_resistance_uohm < 0) || + !bi->resist_table) { bi->factory_internal_resistance_uohm = 300000; + bi->resist_table = temp_to_batres_tbl_thermistor; + bi->resist_table_size = ARRAY_SIZE(temp_to_batres_tbl_thermistor); + } if (bi->temp_min == INT_MIN) bi->temp_min = AB8500_TEMP_UNDER; diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index daa008138b059..96bb81e539f0b 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -901,44 +901,35 @@ static int ab8500_fg_uncomp_volt_to_capacity(struct ab8500_fg *di) * @di: pointer to the ab8500_fg structure * * Returns battery inner resistance added with the fuel gauge resistor value - * to get the total resistance in the whole link from gnd to bat+ node. + * to get the total resistance in the whole link from gnd to bat+ node + * in milliohm. */ static int ab8500_fg_battery_resistance(struct ab8500_fg *di) { - int i, tbl_size; - const struct batres_vs_temp *tbl; - int resist = 0; - - tbl = di->bm->bat_type->batres_tbl; - tbl_size = di->bm->bat_type->n_batres_tbl_elements; - - for (i = 0; i < tbl_size; ++i) { - if (di->bat_temp / 10 > tbl[i].temp) - break; - } + struct power_supply_battery_info *bi = &di->bm->bi; + int resistance_percent = 0; + int resistance; - if ((i > 0) && (i < tbl_size)) { - resist = fixp_linear_interpolate( - tbl[i].temp, - tbl[i].resist, - tbl[i-1].temp, - tbl[i-1].resist, - di->bat_temp / 10); - } else if (i == 0) { - resist = tbl[0].resist; - } else { - resist = tbl[tbl_size - 1].resist; - } + resistance_percent = power_supply_temp2resist_simple(bi->resist_table, + bi->resist_table_size, + di->bat_temp / 10); + /* + * We get a percentage of factory resistance here so first get + * the factory resistance in milliohms then calculate how much + * resistance we have at this temperature. + */ + resistance = (bi->factory_internal_resistance_uohm / 1000); + resistance = resistance * resistance_percent / 100; dev_dbg(di->dev, "%s Temp: %d battery internal resistance: %d" " fg resistance %d, total: %d (mOhm)\n", - __func__, di->bat_temp, resist, di->bm->fg_res / 10, - (di->bm->fg_res / 10) + resist); + __func__, di->bat_temp, resistance, di->bm->fg_res / 10, + (di->bm->fg_res / 10) + resistance); /* fg_res variable is in 0.1mOhm */ - resist += di->bm->fg_res / 10; + resistance += di->bm->fg_res / 10; - return resist; + return resistance; } /** -- GitLab From 0525f34d02758b801619d5e7093003e66a7efe3c Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 20 Nov 2021 16:53:26 +0100 Subject: [PATCH 0132/1112] power: supply: ab8500: Standardize capacity lookup The AB8500 charger only has one capacity table with unspecified temperature, so we assume this capacity is given for 20 degrees Celsius. Convert this table to use the OCV (open circuit voltage) tables in struct power_supply_battery_ocv_table. In the process, convert the fuel gauge driver to use microvolts and microamperes so we can use the same internals as the power supply subsystem without having to multiply and divide with 1000 in a few places. Also convert high_curr_threshold and lowbat_threshold to use microamperes and microvolts as these are closely related to these changes. Drop the unused overbat_threshold member in the custom struct ab8500_fg_parameters. Signed-off-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500-bm.h | 30 +-- drivers/power/supply/ab8500_bmdata.c | 63 +++--- drivers/power/supply/ab8500_fg.c | 286 +++++++++++++-------------- 3 files changed, 173 insertions(+), 206 deletions(-) diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index af52539a7a7b9..57e1a8e27e51a 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -196,8 +196,8 @@ enum bup_vch_sel { #define BATT_OVV_TH_3P7 0x00 #define BATT_OVV_TH_4P75 0x01 -/* A value to indicate over voltage */ -#define BATT_OVV_VALUE 4750 +/* A value to indicate over voltage (microvolts) */ +#define BATT_OVV_VALUE 4750000 /* VBUS OVV constants */ #define VBUS_OVV_SELECT_MASK 0x78 @@ -284,16 +284,6 @@ struct ab8500_res_to_temp { int resist; }; -/** - * struct ab8500_v_to_cap - Table for translating voltage to capacity - * @voltage: Voltage in mV - * @capacity: Capacity in percent - */ -struct ab8500_v_to_cap { - int voltage; - int capacity; -}; - /* Forward declaration */ struct ab8500_fg; @@ -307,10 +297,9 @@ struct ab8500_fg; * @init_total_time: Total init time during startup * @high_curr_time: Time current has to be high to go to recovery * @accu_charging: FG accumulation time while charging - * @accu_high_curr: FG accumulation time in high current mode - * @high_curr_threshold: High current threshold, in mA - * @lowbat_threshold: Low battery threshold, in mV - * @overbat_threshold: Over battery threshold, in mV + * @accu_high_curr_ua: FG accumulation time in high current mode + * @high_curr_threshold_ua: High current threshold, in uA + * @lowbat_threshold_uv: Low battery threshold, in uV * @battok_falling_th_sel0 Threshold in mV for battOk signal sel0 * Resolution in 50 mV step. * @battok_raising_th_sel1 Threshold in mV for battOk signal sel1 @@ -335,9 +324,8 @@ struct ab8500_fg_parameters { int high_curr_time; int accu_charging; int accu_high_curr; - int high_curr_threshold; - int lowbat_threshold; - int overbat_threshold; + int high_curr_threshold_ua; + int lowbat_threshold_uv; int battok_falling_th_sel0; int battok_raising_th_sel1; int user_cap_limit; @@ -377,8 +365,6 @@ struct ab8500_maxim_parameters { * @low_high_vol_lvl: charger voltage in temp low/high state in mV' * @n_r_t_tbl_elements: number of elements in r_to_t_tbl * @r_to_t_tbl: table containing resistance to temp points - * @n_v_cap_tbl_elements: number of elements in v_to_cap_tbl - * @v_to_cap_tbl: Voltage to capacity (in %) table */ struct ab8500_battery_type { int resis_high; @@ -393,8 +379,6 @@ struct ab8500_battery_type { int low_high_vol_lvl; int n_temp_tbl_elements; const struct ab8500_res_to_temp *r_to_t_tbl; - int n_v_cap_tbl_elements; - const struct ab8500_v_to_cap *v_to_cap_tbl; }; /** diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index 1175532fe017d..62953f9cb85a8 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -16,31 +16,31 @@ /* Default: temperature hysteresis */ #define AB8500_TEMP_HYSTERESIS 3 -static const struct ab8500_v_to_cap cap_tbl[] = { - {4186, 100}, - {4163, 99}, - {4114, 95}, - {4068, 90}, - {3990, 80}, - {3926, 70}, - {3898, 65}, - {3866, 60}, - {3833, 55}, - {3812, 50}, - {3787, 40}, - {3768, 30}, - {3747, 25}, - {3730, 20}, - {3705, 15}, - {3699, 14}, - {3684, 12}, - {3672, 9}, - {3657, 7}, - {3638, 6}, - {3556, 4}, - {3424, 2}, - {3317, 1}, - {3094, 0}, +static struct power_supply_battery_ocv_table ocv_cap_tbl[] = { + { .ocv = 4186000, .capacity = 100}, + { .ocv = 4163000, .capacity = 99}, + { .ocv = 4114000, .capacity = 95}, + { .ocv = 4068000, .capacity = 90}, + { .ocv = 3990000, .capacity = 80}, + { .ocv = 3926000, .capacity = 70}, + { .ocv = 3898000, .capacity = 65}, + { .ocv = 3866000, .capacity = 60}, + { .ocv = 3833000, .capacity = 55}, + { .ocv = 3812000, .capacity = 50}, + { .ocv = 3787000, .capacity = 40}, + { .ocv = 3768000, .capacity = 30}, + { .ocv = 3747000, .capacity = 25}, + { .ocv = 3730000, .capacity = 20}, + { .ocv = 3705000, .capacity = 15}, + { .ocv = 3699000, .capacity = 14}, + { .ocv = 3684000, .capacity = 12}, + { .ocv = 3672000, .capacity = 9}, + { .ocv = 3657000, .capacity = 7}, + { .ocv = 3638000, .capacity = 6}, + { .ocv = 3556000, .capacity = 4}, + { .ocv = 3424000, .capacity = 2}, + { .ocv = 3317000, .capacity = 1}, + { .ocv = 3094000, .capacity = 0}, }; /* @@ -94,8 +94,6 @@ static struct ab8500_battery_type bat_type_thermistor_unknown = { .low_high_vol_lvl = 4000, .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl), .r_to_t_tbl = temp_tbl, - .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl), - .v_to_cap_tbl = cap_tbl, }; static const struct ab8500_bm_capacity_levels cap_levels = { @@ -115,8 +113,8 @@ static const struct ab8500_fg_parameters fg = { .high_curr_time = 60, .accu_charging = 30, .accu_high_curr = 30, - .high_curr_threshold = 50, - .lowbat_threshold = 3100, + .high_curr_threshold_ua = 50000, + .lowbat_threshold_uv = 3100000, .battok_falling_th_sel0 = 2860, .battok_raising_th_sel1 = 2860, .maint_thres = 95, @@ -219,6 +217,13 @@ int ab8500_bm_of_probe(struct power_supply *psy, bi->resist_table_size = ARRAY_SIZE(temp_to_batres_tbl_thermistor); } + if (!bi->ocv_table[0]) { + /* Default capacity table at say 25 degrees Celsius */ + bi->ocv_temp[0] = 25; + bi->ocv_table[0] = ocv_cap_tbl; + bi->ocv_table_size[0] = ARRAY_SIZE(ocv_cap_tbl); + } + if (bi->temp_min == INT_MIN) bi->temp_min = AB8500_TEMP_UNDER; if (bi->temp_max == INT_MAX) diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index 96bb81e539f0b..eb3e5c4ca44fd 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -156,10 +156,10 @@ struct inst_curr_result_list { * @dev: Pointer to the structure device * @node: a list of AB8500 FGs, hence prepared for reentrance * @irq holds the CCEOC interrupt number - * @vbat: Battery voltage in mV + * @vbat_uv: Battery voltage in uV * @vbat_nom_uv: Nominal battery voltage in uV - * @inst_curr: Instantenous battery current in mA - * @avg_curr: Average battery current in mA + * @inst_curr_ua: Instantenous battery current in uA + * @avg_curr_ua: Average battery current in uA * @bat_temp battery temperature * @fg_samples: Number of samples used in the FG accumulation * @accu_charge: Accumulated charge from the last conversion @@ -198,10 +198,10 @@ struct ab8500_fg { struct device *dev; struct list_head node; int irq; - int vbat; + int vbat_uv; int vbat_nom_uv; - int inst_curr; - int avg_curr; + int inst_curr_ua; + int avg_curr_ua; int bat_temp; int fg_samples; int accu_charge; @@ -265,84 +265,84 @@ static enum power_supply_property ab8500_fg_props[] = { /* * This array maps the raw hex value to lowbat voltage used by the AB8500 - * Values taken from the UM0836 + * Values taken from the UM0836, in microvolts. */ static int ab8500_fg_lowbat_voltage_map[] = { - 2300 , - 2325 , - 2350 , - 2375 , - 2400 , - 2425 , - 2450 , - 2475 , - 2500 , - 2525 , - 2550 , - 2575 , - 2600 , - 2625 , - 2650 , - 2675 , - 2700 , - 2725 , - 2750 , - 2775 , - 2800 , - 2825 , - 2850 , - 2875 , - 2900 , - 2925 , - 2950 , - 2975 , - 3000 , - 3025 , - 3050 , - 3075 , - 3100 , - 3125 , - 3150 , - 3175 , - 3200 , - 3225 , - 3250 , - 3275 , - 3300 , - 3325 , - 3350 , - 3375 , - 3400 , - 3425 , - 3450 , - 3475 , - 3500 , - 3525 , - 3550 , - 3575 , - 3600 , - 3625 , - 3650 , - 3675 , - 3700 , - 3725 , - 3750 , - 3775 , - 3800 , - 3825 , - 3850 , - 3850 , + 2300000, + 2325000, + 2350000, + 2375000, + 2400000, + 2425000, + 2450000, + 2475000, + 2500000, + 2525000, + 2550000, + 2575000, + 2600000, + 2625000, + 2650000, + 2675000, + 2700000, + 2725000, + 2750000, + 2775000, + 2800000, + 2825000, + 2850000, + 2875000, + 2900000, + 2925000, + 2950000, + 2975000, + 3000000, + 3025000, + 3050000, + 3075000, + 3100000, + 3125000, + 3150000, + 3175000, + 3200000, + 3225000, + 3250000, + 3275000, + 3300000, + 3325000, + 3350000, + 3375000, + 3400000, + 3425000, + 3450000, + 3475000, + 3500000, + 3525000, + 3550000, + 3575000, + 3600000, + 3625000, + 3650000, + 3675000, + 3700000, + 3725000, + 3750000, + 3775000, + 3800000, + 3825000, + 3850000, + 3850000, }; -static u8 ab8500_volt_to_regval(int voltage) +static u8 ab8500_volt_to_regval(int voltage_uv) { int i; - if (voltage < ab8500_fg_lowbat_voltage_map[0]) + if (voltage_uv < ab8500_fg_lowbat_voltage_map[0]) return 0; for (i = 0; i < ARRAY_SIZE(ab8500_fg_lowbat_voltage_map); i++) { - if (voltage < ab8500_fg_lowbat_voltage_map[i]) + if (voltage_uv < ab8500_fg_lowbat_voltage_map[i]) return (u8) i - 1; } @@ -353,16 +353,16 @@ static u8 ab8500_volt_to_regval(int voltage) /** * ab8500_fg_is_low_curr() - Low or high current mode * @di: pointer to the ab8500_fg structure - * @curr: the current to base or our decision on + * @curr_ua: the current to base or our decision on in microampere * * Low current mode if the current consumption is below a certain threshold */ -static int ab8500_fg_is_low_curr(struct ab8500_fg *di, int curr) +static int ab8500_fg_is_low_curr(struct ab8500_fg *di, int curr_ua) { /* * We want to know if we're in low current mode */ - if (curr > -di->bm->fg_params->high_curr_threshold) + if (curr_ua > -di->bm->fg_params->high_curr_threshold_ua) return true; else return false; @@ -600,13 +600,13 @@ int ab8500_fg_inst_curr_done(struct ab8500_fg *di) /** * ab8500_fg_inst_curr_finalize() - battery instantaneous current * @di: pointer to the ab8500_fg structure - * @res: battery instantenous current(on success) + * @curr_ua: battery instantenous current in microampere (on success) * * Returns 0 or an error code * Note: This is part "two" and has to be called at earliest 250 ms * after ab8500_fg_inst_curr_start() */ -int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res) +int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *curr_ua) { u8 low, high; int val; @@ -662,14 +662,13 @@ int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res) /* * Convert to unit value in mA * Full scale input voltage is - * 63.160mV => LSB = 63.160mV/(4096*res) = 1.542mA + * 63.160mV => LSB = 63.160mV/(4096*res) = 1.542.000 uA * Given a 250ms conversion cycle time the LSB corresponds * to 107.1 nAh. Convert to current by dividing by the conversion * time in hours (250ms = 1 / (3600 * 4)h) * 107.1nAh assumes 10mOhm, but fg_res is in 0.1mOhm */ - val = (val * QLSB_NANO_AMP_HOURS_X10 * 36 * 4) / - (1000 * di->bm->fg_res); + val = (val * QLSB_NANO_AMP_HOURS_X10 * 36 * 4) / di->bm->fg_res; if (di->turn_off_fg) { dev_dbg(di->dev, "%s Disable FG\n", __func__); @@ -687,7 +686,7 @@ int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res) goto fail; } mutex_unlock(&di->cc_lock); - (*res) = val; + *curr_ua = val; return 0; fail: @@ -698,15 +697,15 @@ fail: /** * ab8500_fg_inst_curr_blocking() - battery instantaneous current * @di: pointer to the ab8500_fg structure - * @res: battery instantenous current(on success) * - * Returns 0 else error code + * Returns battery instantenous current in microampere (on success) + * else error code */ int ab8500_fg_inst_curr_blocking(struct ab8500_fg *di) { int ret; unsigned long timeout; - int res = 0; + int curr_ua = 0; ret = ab8500_fg_inst_curr_start(di); if (ret) { @@ -729,14 +728,14 @@ int ab8500_fg_inst_curr_blocking(struct ab8500_fg *di) } } - ret = ab8500_fg_inst_curr_finalize(di, &res); + ret = ab8500_fg_inst_curr_finalize(di, &curr_ua); if (ret) { dev_err(di->dev, "Failed to finalize fg_inst\n"); return 0; } - dev_dbg(di->dev, "%s instant current: %d", __func__, res); - return res; + dev_dbg(di->dev, "%s instant current: %d uA", __func__, curr_ua); + return curr_ua; fail: disable_irq(di->irq); mutex_unlock(&di->cc_lock); @@ -796,13 +795,12 @@ static void ab8500_fg_acc_cur_work(struct work_struct *work) (100 * di->bm->fg_res); /* - * Convert to unit value in mA + * Convert to unit value in uA * by dividing by the conversion * time in hours (= samples / (3600 * 4)h) - * and multiply with 1000 */ - di->avg_curr = (val * QLSB_NANO_AMP_HOURS_X10 * 36) / - (1000 * di->bm->fg_res * (di->fg_samples / 4)); + di->avg_curr_ua = (val * QLSB_NANO_AMP_HOURS_X10 * 36) / + (di->bm->fg_res * (di->fg_samples / 4)); di->flags.conv_done = true; @@ -824,7 +822,7 @@ exit: * ab8500_fg_bat_voltage() - get battery voltage * @di: pointer to the ab8500_fg structure * - * Returns battery voltage(on success) else error code + * Returns battery voltage in microvolts (on success) else error code */ static int ab8500_fg_bat_voltage(struct ab8500_fg *di) { @@ -839,6 +837,8 @@ static int ab8500_fg_bat_voltage(struct ab8500_fg *di) return prev; } + /* IIO returns millivolts but we want microvolts */ + vbat *= 1000; prev = vbat; return vbat; } @@ -846,41 +846,16 @@ static int ab8500_fg_bat_voltage(struct ab8500_fg *di) /** * ab8500_fg_volt_to_capacity() - Voltage based capacity * @di: pointer to the ab8500_fg structure - * @voltage: The voltage to convert to a capacity + * @voltage_uv: The voltage to convert to a capacity in microvolt * * Returns battery capacity in per mille based on voltage */ -static int ab8500_fg_volt_to_capacity(struct ab8500_fg *di, int voltage) +static int ab8500_fg_volt_to_capacity(struct ab8500_fg *di, int voltage_uv) { - int i, tbl_size; - const struct ab8500_v_to_cap *tbl; - int cap = 0; - - tbl = di->bm->bat_type->v_to_cap_tbl; - tbl_size = di->bm->bat_type->n_v_cap_tbl_elements; - - for (i = 0; i < tbl_size; ++i) { - if (voltage > tbl[i].voltage) - break; - } - - if ((i > 0) && (i < tbl_size)) { - cap = fixp_linear_interpolate( - tbl[i].voltage, - tbl[i].capacity * 10, - tbl[i-1].voltage, - tbl[i-1].capacity * 10, - voltage); - } else if (i == 0) { - cap = 1000; - } else { - cap = 0; - } - - dev_dbg(di->dev, "%s Vbat: %d, Cap: %d per mille", - __func__, voltage, cap); + struct power_supply_battery_info *bi = &di->bm->bi; - return cap; + /* Multiply by 10 because the capacity is tracked in per mille */ + return power_supply_batinfo_ocv2cap(bi, voltage_uv, di->bat_temp) * 10; } /** @@ -892,8 +867,8 @@ static int ab8500_fg_volt_to_capacity(struct ab8500_fg *di, int voltage) */ static int ab8500_fg_uncomp_volt_to_capacity(struct ab8500_fg *di) { - di->vbat = ab8500_fg_bat_voltage(di); - return ab8500_fg_volt_to_capacity(di, di->vbat); + di->vbat_uv = ab8500_fg_bat_voltage(di); + return ab8500_fg_volt_to_capacity(di, di->vbat_uv); } /** @@ -941,31 +916,34 @@ static int ab8500_fg_battery_resistance(struct ab8500_fg *di) */ static int ab8500_fg_load_comp_volt_to_capacity(struct ab8500_fg *di) { - int vbat_comp, res; + int vbat_comp_uv, res; int i = 0; - int vbat = 0; + int vbat_uv = 0; ab8500_fg_inst_curr_start(di); do { - vbat += ab8500_fg_bat_voltage(di); + vbat_uv += ab8500_fg_bat_voltage(di); i++; usleep_range(5000, 6000); } while (!ab8500_fg_inst_curr_done(di)); - ab8500_fg_inst_curr_finalize(di, &di->inst_curr); + ab8500_fg_inst_curr_finalize(di, &di->inst_curr_ua); - di->vbat = vbat / i; + di->vbat_uv = vbat_uv / i; res = ab8500_fg_battery_resistance(di); - /* Use Ohms law to get the load compensated voltage */ - vbat_comp = di->vbat - (di->inst_curr * res) / 1000; + /* + * Use Ohms law to get the load compensated voltage. + * Divide by 1000 to get from milliohms to ohms. + */ + vbat_comp_uv = di->vbat_uv - (di->inst_curr_ua * res) / 1000; - dev_dbg(di->dev, "%s Measured Vbat: %dmV,Compensated Vbat %dmV, " - "R: %dmOhm, Current: %dmA Vbat Samples: %d\n", - __func__, di->vbat, vbat_comp, res, di->inst_curr, i); + dev_dbg(di->dev, "%s Measured Vbat: %d uV,Compensated Vbat %d uV, " + "R: %d mOhm, Current: %d uA Vbat Samples: %d\n", + __func__, di->vbat_uv, vbat_comp_uv, res, di->inst_curr_ua, i); - return ab8500_fg_volt_to_capacity(di, vbat_comp); + return ab8500_fg_volt_to_capacity(di, vbat_comp_uv); } /** @@ -1052,8 +1030,8 @@ static int ab8500_fg_calc_cap_charging(struct ab8500_fg *di) ab8500_fg_convert_mah_to_permille(di, di->bat_cap.mah); /* We need to update battery voltage and inst current when charging */ - di->vbat = ab8500_fg_bat_voltage(di); - di->inst_curr = ab8500_fg_inst_curr_blocking(di); + di->vbat_uv = ab8500_fg_bat_voltage(di); + di->inst_curr_ua = ab8500_fg_inst_curr_blocking(di); return di->bat_cap.mah; } @@ -1580,9 +1558,9 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di) * RECOVERY_SLEEP if time left. * If high, go to READOUT */ - di->inst_curr = ab8500_fg_inst_curr_blocking(di); + di->inst_curr_ua = ab8500_fg_inst_curr_blocking(di); - if (ab8500_fg_is_low_curr(di, di->inst_curr)) { + if (ab8500_fg_is_low_curr(di, di->inst_curr_ua)) { if (di->recovery_cnt > di->bm->fg_params->recovery_total_time) { di->fg_samples = SEC_TO_SAMPLE( @@ -1615,9 +1593,9 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di) break; case AB8500_FG_DISCHARGE_READOUT: - di->inst_curr = ab8500_fg_inst_curr_blocking(di); + di->inst_curr_ua = ab8500_fg_inst_curr_blocking(di); - if (ab8500_fg_is_low_curr(di, di->inst_curr)) { + if (ab8500_fg_is_low_curr(di, di->inst_curr_ua)) { /* Detect mode change */ if (di->high_curr_mode) { di->high_curr_mode = false; @@ -1763,9 +1741,9 @@ static void ab8500_fg_algorithm(struct ab8500_fg *di) di->bat_cap.prev_mah, di->bat_cap.prev_percent, di->bat_cap.prev_level, - di->vbat, - di->inst_curr, - di->avg_curr, + di->vbat_uv, + di->inst_curr_ua, + di->avg_curr_ua, di->accu_charge, di->flags.charging, di->charge_state, @@ -1858,15 +1836,15 @@ static void ab8500_fg_check_hw_failure_work(struct work_struct *work) */ static void ab8500_fg_low_bat_work(struct work_struct *work) { - int vbat; + int vbat_uv; struct ab8500_fg *di = container_of(work, struct ab8500_fg, fg_low_bat_work.work); - vbat = ab8500_fg_bat_voltage(di); + vbat_uv = ab8500_fg_bat_voltage(di); /* Check if LOW_BAT still fulfilled */ - if (vbat < di->bm->fg_params->lowbat_threshold) { + if (vbat_uv < di->bm->fg_params->lowbat_threshold_uv) { /* Is it time to shut down? */ if (di->low_bat_cnt < 1) { di->flags.low_bat = true; @@ -2096,15 +2074,15 @@ static int ab8500_fg_get_property(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_VOLTAGE_NOW: if (di->flags.bat_ovv) - val->intval = BATT_OVV_VALUE * 1000; + val->intval = BATT_OVV_VALUE; else - val->intval = di->vbat * 1000; + val->intval = di->vbat_uv; break; case POWER_SUPPLY_PROP_CURRENT_NOW: - val->intval = di->inst_curr * 1000; + val->intval = di->inst_curr_ua; break; case POWER_SUPPLY_PROP_CURRENT_AVG: - val->intval = di->avg_curr * 1000; + val->intval = di->avg_curr_ua; break; case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: val->intval = ab8500_fg_convert_mah_to_uwh(di, @@ -2310,7 +2288,7 @@ static int ab8500_fg_init_hw_registers(struct ab8500_fg *di) AB8500_SYS_CTRL2_BLOCK, AB8500_LOW_BAT_REG, ab8500_volt_to_regval( - di->bm->fg_params->lowbat_threshold) << 1 | + di->bm->fg_params->lowbat_threshold_uv) << 1 | LOW_BAT_ENABLE); if (ret) { dev_err(di->dev, "%s write failed\n", __func__); -- GitLab From 6326948f940dc3f77066d5cdc44ba6afe67830c0 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Wed, 29 Sep 2021 11:01:21 -0400 Subject: [PATCH 0133/1112] lsm: security_task_getsecid_subj() -> security_current_getsecid_subj() The security_task_getsecid_subj() LSM hook invites misuse by allowing callers to specify a task even though the hook is only safe when the current task is referenced. Fix this by removing the task_struct argument to the hook, requiring LSM implementations to use the current task. While we are changing the hook declaration we also rename the function to security_current_getsecid_subj() in an effort to reinforce that the hook captures the subjective credentials of the current task and not an arbitrary task on the system. Reviewed-by: Serge Hallyn Reviewed-by: Casey Schaufler Signed-off-by: Paul Moore --- include/linux/lsm_hook_defs.h | 3 +-- include/linux/lsm_hooks.h | 8 +++----- include/linux/security.h | 4 ++-- kernel/audit.c | 4 ++-- kernel/auditfilter.c | 3 +-- kernel/auditsc.c | 11 ++++++++++- net/netlabel/netlabel_unlabeled.c | 2 +- net/netlabel/netlabel_user.h | 2 +- security/apparmor/lsm.c | 13 ++++++++++--- security/integrity/ima/ima_appraise.c | 2 +- security/integrity/ima/ima_main.c | 14 +++++++------- security/security.c | 6 +++--- security/selinux/hooks.c | 19 +++---------------- security/smack/smack.h | 16 ---------------- security/smack/smack_lsm.c | 9 ++++----- 15 files changed, 49 insertions(+), 67 deletions(-) diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index df8de62f4710f..ae2228f0711dd 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -206,8 +206,7 @@ LSM_HOOK(int, 0, task_fix_setgid, struct cred *new, const struct cred * old, LSM_HOOK(int, 0, task_setpgid, struct task_struct *p, pid_t pgid) LSM_HOOK(int, 0, task_getpgid, struct task_struct *p) LSM_HOOK(int, 0, task_getsid, struct task_struct *p) -LSM_HOOK(void, LSM_RET_VOID, task_getsecid_subj, - struct task_struct *p, u32 *secid) +LSM_HOOK(void, LSM_RET_VOID, current_getsecid_subj, u32 *secid) LSM_HOOK(void, LSM_RET_VOID, task_getsecid_obj, struct task_struct *p, u32 *secid) LSM_HOOK(int, 0, task_setnice, struct task_struct *p, int nice) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index d45b6f6e27fda..52c1990644b98 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -719,11 +719,9 @@ * @p. * @p contains the task_struct for the process. * Return 0 if permission is granted. - * @task_getsecid_subj: - * Retrieve the subjective security identifier of the task_struct in @p - * and return it in @secid. Special care must be taken to ensure that @p - * is the either the "current" task, or the caller has exclusive access - * to @p. + * @current_getsecid_subj: + * Retrieve the subjective security identifier of the current task and + * return it in @secid. * In case of failure, @secid will be set to zero. * @task_getsecid_obj: * Retrieve the objective security identifier of the task_struct in @p diff --git a/include/linux/security.h b/include/linux/security.h index bbf44a4668326..bb301963e3339 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -418,7 +418,7 @@ int security_task_fix_setgid(struct cred *new, const struct cred *old, int security_task_setpgid(struct task_struct *p, pid_t pgid); int security_task_getpgid(struct task_struct *p); int security_task_getsid(struct task_struct *p); -void security_task_getsecid_subj(struct task_struct *p, u32 *secid); +void security_current_getsecid_subj(u32 *secid); void security_task_getsecid_obj(struct task_struct *p, u32 *secid); int security_task_setnice(struct task_struct *p, int nice); int security_task_setioprio(struct task_struct *p, int ioprio); @@ -1119,7 +1119,7 @@ static inline int security_task_getsid(struct task_struct *p) return 0; } -static inline void security_task_getsecid_subj(struct task_struct *p, u32 *secid) +static inline void security_current_getsecid_subj(u32 *secid) { *secid = 0; } diff --git a/kernel/audit.c b/kernel/audit.c index 121d37e700a62..d4084751cfe69 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -2132,7 +2132,7 @@ int audit_log_task_context(struct audit_buffer *ab) int error; u32 sid; - security_task_getsecid_subj(current, &sid); + security_current_getsecid_subj(&sid); if (!sid) return 0; @@ -2353,7 +2353,7 @@ int audit_signal_info(int sig, struct task_struct *t) audit_sig_uid = auid; else audit_sig_uid = uid; - security_task_getsecid_subj(current, &audit_sig_sid); + security_current_getsecid_subj(&audit_sig_sid); } return audit_signal_info_syscall(t); diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index d75acb014ccdc..4173e771650c8 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -1368,8 +1368,7 @@ int audit_filter(int msgtype, unsigned int listtype) case AUDIT_SUBJ_SEN: case AUDIT_SUBJ_CLR: if (f->lsm_rule) { - security_task_getsecid_subj(current, - &sid); + security_current_getsecid_subj(&sid); result = security_audit_rule_match(sid, f->type, f->op, f->lsm_rule); } diff --git a/kernel/auditsc.c b/kernel/auditsc.c index b517947bfa48d..fce5d43a933f0 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -666,7 +666,16 @@ static int audit_filter_rules(struct task_struct *tsk, logged upon error */ if (f->lsm_rule) { if (need_sid) { - security_task_getsecid_subj(tsk, &sid); + /* @tsk should always be equal to + * @current with the exception of + * fork()/copy_process() in which case + * the new @tsk creds are still a dup + * of @current's creds so we can still + * use security_current_getsecid_subj() + * here even though it always refs + * @current's creds + */ + security_current_getsecid_subj(&sid); need_sid = 0; } result = security_audit_rule_match(sid, f->type, diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index 566ba4397ee40..8490e46359ae0 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -1537,7 +1537,7 @@ int __init netlbl_unlabel_defconf(void) /* Only the kernel is allowed to call this function and the only time * it is called is at bootup before the audit subsystem is reporting * messages so don't worry to much about these values. */ - security_task_getsecid_subj(current, &audit_info.secid); + security_current_getsecid_subj(&audit_info.secid); audit_info.loginuid = GLOBAL_ROOT_UID; audit_info.sessionid = 0; diff --git a/net/netlabel/netlabel_user.h b/net/netlabel/netlabel_user.h index 6190cbf94bf0d..d6c5b31eb4eb8 100644 --- a/net/netlabel/netlabel_user.h +++ b/net/netlabel/netlabel_user.h @@ -32,7 +32,7 @@ */ static inline void netlbl_netlink_auditinfo(struct netlbl_audit *audit_info) { - security_task_getsecid_subj(current, &audit_info->secid); + security_current_getsecid_subj(&audit_info->secid); audit_info->loginuid = audit_get_loginuid(current); audit_info->sessionid = audit_get_sessionid(current); } diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 0d6585056f3df..4f0eecb67dde0 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -728,7 +728,14 @@ static void apparmor_bprm_committed_creds(struct linux_binprm *bprm) return; } -static void apparmor_task_getsecid(struct task_struct *p, u32 *secid) +static void apparmor_current_getsecid_subj(u32 *secid) +{ + struct aa_label *label = aa_get_current_label(); + *secid = label->secid; + aa_put_label(label); +} + +static void apparmor_task_getsecid_obj(struct task_struct *p, u32 *secid) { struct aa_label *label = aa_get_task_label(p); *secid = label->secid; @@ -1252,8 +1259,8 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(task_free, apparmor_task_free), LSM_HOOK_INIT(task_alloc, apparmor_task_alloc), - LSM_HOOK_INIT(task_getsecid_subj, apparmor_task_getsecid), - LSM_HOOK_INIT(task_getsecid_obj, apparmor_task_getsecid), + LSM_HOOK_INIT(current_getsecid_subj, apparmor_current_getsecid_subj), + LSM_HOOK_INIT(task_getsecid_obj, apparmor_task_getsecid_obj), LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit), LSM_HOOK_INIT(task_kill, apparmor_task_kill), diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index dbba51583e7c1..17232bbfb9f96 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -76,7 +76,7 @@ int ima_must_appraise(struct user_namespace *mnt_userns, struct inode *inode, if (!ima_appraise) return 0; - security_task_getsecid_subj(current, &secid); + security_current_getsecid_subj(&secid); return ima_match_policy(mnt_userns, inode, current_cred(), secid, func, mask, IMA_APPRAISE | IMA_HASH, NULL, NULL, NULL, NULL); diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 465865412100b..8c6e4514d4944 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -408,7 +408,7 @@ int ima_file_mmap(struct file *file, unsigned long prot) u32 secid; if (file && (prot & PROT_EXEC)) { - security_task_getsecid_subj(current, &secid); + security_current_getsecid_subj(&secid); return process_measurement(file, current_cred(), secid, NULL, 0, MAY_EXEC, MMAP_CHECK); } @@ -446,7 +446,7 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot) !(prot & PROT_EXEC) || (vma->vm_flags & VM_EXEC)) return 0; - security_task_getsecid_subj(current, &secid); + security_current_getsecid_subj(&secid); inode = file_inode(vma->vm_file); action = ima_get_action(file_mnt_user_ns(vma->vm_file), inode, current_cred(), secid, MAY_EXEC, MMAP_CHECK, @@ -487,7 +487,7 @@ int ima_bprm_check(struct linux_binprm *bprm) int ret; u32 secid; - security_task_getsecid_subj(current, &secid); + security_current_getsecid_subj(&secid); ret = process_measurement(bprm->file, current_cred(), secid, NULL, 0, MAY_EXEC, BPRM_CHECK); if (ret) @@ -512,7 +512,7 @@ int ima_file_check(struct file *file, int mask) { u32 secid; - security_task_getsecid_subj(current, &secid); + security_current_getsecid_subj(&secid); return process_measurement(file, current_cred(), secid, NULL, 0, mask & (MAY_READ | MAY_WRITE | MAY_EXEC | MAY_APPEND), FILE_CHECK); @@ -709,7 +709,7 @@ int ima_read_file(struct file *file, enum kernel_read_file_id read_id, /* Read entire file for all partial reads. */ func = read_idmap[read_id] ?: FILE_CHECK; - security_task_getsecid_subj(current, &secid); + security_current_getsecid_subj(&secid); return process_measurement(file, current_cred(), secid, NULL, 0, MAY_READ, func); } @@ -752,7 +752,7 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size, } func = read_idmap[read_id] ?: FILE_CHECK; - security_task_getsecid_subj(current, &secid); + security_current_getsecid_subj(&secid); return process_measurement(file, current_cred(), secid, buf, size, MAY_READ, func); } @@ -905,7 +905,7 @@ int process_buffer_measurement(struct user_namespace *mnt_userns, * buffer measurements. */ if (func) { - security_task_getsecid_subj(current, &secid); + security_current_getsecid_subj(&secid); action = ima_get_action(mnt_userns, inode, current_cred(), secid, 0, func, &pcr, &template, func_data, NULL); diff --git a/security/security.c b/security/security.c index c88167a414b41..edb922b8bf4a0 100644 --- a/security/security.c +++ b/security/security.c @@ -1808,12 +1808,12 @@ int security_task_getsid(struct task_struct *p) return call_int_hook(task_getsid, 0, p); } -void security_task_getsecid_subj(struct task_struct *p, u32 *secid) +void security_current_getsecid_subj(u32 *secid) { *secid = 0; - call_void_hook(task_getsecid_subj, p, secid); + call_void_hook(current_getsecid_subj, secid); } -EXPORT_SYMBOL(security_task_getsecid_subj); +EXPORT_SYMBOL(security_current_getsecid_subj); void security_task_getsecid_obj(struct task_struct *p, u32 *secid) { diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 62d30c0a30c29..726175254f60d 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -229,19 +229,6 @@ static inline u32 cred_sid(const struct cred *cred) return tsec->sid; } -/* - * get the subjective security ID of a task - */ -static inline u32 task_sid_subj(const struct task_struct *task) -{ - u32 sid; - - rcu_read_lock(); - sid = cred_sid(rcu_dereference(task->cred)); - rcu_read_unlock(); - return sid; -} - /* * get the objective security ID of a task */ @@ -4205,9 +4192,9 @@ static int selinux_task_getsid(struct task_struct *p) PROCESS__GETSESSION, NULL); } -static void selinux_task_getsecid_subj(struct task_struct *p, u32 *secid) +static void selinux_current_getsecid_subj(u32 *secid) { - *secid = task_sid_subj(p); + *secid = current_sid(); } static void selinux_task_getsecid_obj(struct task_struct *p, u32 *secid) @@ -7159,7 +7146,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(task_setpgid, selinux_task_setpgid), LSM_HOOK_INIT(task_getpgid, selinux_task_getpgid), LSM_HOOK_INIT(task_getsid, selinux_task_getsid), - LSM_HOOK_INIT(task_getsecid_subj, selinux_task_getsecid_subj), + LSM_HOOK_INIT(current_getsecid_subj, selinux_current_getsecid_subj), LSM_HOOK_INIT(task_getsecid_obj, selinux_task_getsecid_obj), LSM_HOOK_INIT(task_setnice, selinux_task_setnice), LSM_HOOK_INIT(task_setioprio, selinux_task_setioprio), diff --git a/security/smack/smack.h b/security/smack/smack.h index 99c3422596ab9..fc837dcebf96e 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -389,22 +389,6 @@ static inline struct smack_known *smk_of_task(const struct task_smack *tsp) return tsp->smk_task; } -static inline struct smack_known *smk_of_task_struct_subj( - const struct task_struct *t) -{ - struct smack_known *skp; - const struct cred *cred; - - rcu_read_lock(); - - cred = rcu_dereference(t->cred); - skp = smk_of_task(smack_cred(cred)); - - rcu_read_unlock(); - - return skp; -} - static inline struct smack_known *smk_of_task_struct_obj( const struct task_struct *t) { diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index efd35b07c7f88..14b279cc75c96 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -2067,15 +2067,14 @@ static int smack_task_getsid(struct task_struct *p) } /** - * smack_task_getsecid_subj - get the subjective secid of the task - * @p: the task + * smack_current_getsecid_subj - get the subjective secid of the current task * @secid: where to put the result * * Sets the secid to contain a u32 version of the task's subjective smack label. */ -static void smack_task_getsecid_subj(struct task_struct *p, u32 *secid) +static void smack_current_getsecid_subj(u32 *secid) { - struct smack_known *skp = smk_of_task_struct_subj(p); + struct smack_known *skp = smk_of_current(); *secid = skp->smk_secid; } @@ -4807,7 +4806,7 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(task_setpgid, smack_task_setpgid), LSM_HOOK_INIT(task_getpgid, smack_task_getpgid), LSM_HOOK_INIT(task_getsid, smack_task_getsid), - LSM_HOOK_INIT(task_getsecid_subj, smack_task_getsecid_subj), + LSM_HOOK_INIT(current_getsecid_subj, smack_current_getsecid_subj), LSM_HOOK_INIT(task_getsecid_obj, smack_task_getsecid_obj), LSM_HOOK_INIT(task_setnice, smack_task_setnice), LSM_HOOK_INIT(task_setioprio, smack_task_setioprio), -- GitLab From 9731698ecb9c851f353ce2496292ff9fcea39dff Mon Sep 17 00:00:00 2001 From: Andrey Ryabinin Date: Mon, 15 Nov 2021 19:46:04 +0300 Subject: [PATCH 0134/1112] cputime, cpuacct: Include guest time in user time in cpuacct.stat cpuacct.stat in no-root cgroups shows user time without guest time included int it. This doesn't match with user time shown in root cpuacct.stat and /proc//stat. This also affects cgroup2's cpu.stat in the same way. Make account_guest_time() to add user time to cgroup's cpustat to fix this. Fixes: ef12fefabf94 ("cpuacct: add per-cgroup utime/stime statistics") Signed-off-by: Andrey Ryabinin Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Daniel Jordan Acked-by: Tejun Heo Cc: Link: https://lore.kernel.org/r/20211115164607.23784-1-arbn@yandex-team.com --- kernel/sched/cputime.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index 872e481d5098c..042a6dbce8f32 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -148,10 +148,10 @@ void account_guest_time(struct task_struct *p, u64 cputime) /* Add guest time to cpustat. */ if (task_nice(p) > 0) { - cpustat[CPUTIME_NICE] += cputime; + task_group_account_field(p, CPUTIME_NICE, cputime); cpustat[CPUTIME_GUEST_NICE] += cputime; } else { - cpustat[CPUTIME_USER] += cputime; + task_group_account_field(p, CPUTIME_USER, cputime); cpustat[CPUTIME_GUEST] += cputime; } } -- GitLab From c7ccbf4b6174e32c130892570db06d0f496cfef0 Mon Sep 17 00:00:00 2001 From: Andrey Ryabinin Date: Mon, 15 Nov 2021 19:46:05 +0300 Subject: [PATCH 0135/1112] cpuacct: Convert BUG_ON() to WARN_ON_ONCE() Replace fatal BUG_ON() with more safe WARN_ON_ONCE() in cpuacct_cpuusage_read(). Signed-off-by: Andrey Ryabinin Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Daniel Jordan Acked-by: Tejun Heo Link: https://lore.kernel.org/r/20211115164607.23784-2-arbn@yandex-team.com --- kernel/sched/cpuacct.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/sched/cpuacct.c b/kernel/sched/cpuacct.c index 893eece65bfda..f347cf9e46345 100644 --- a/kernel/sched/cpuacct.c +++ b/kernel/sched/cpuacct.c @@ -106,7 +106,8 @@ static u64 cpuacct_cpuusage_read(struct cpuacct *ca, int cpu, * We allow index == CPUACCT_STAT_NSTATS here to read * the sum of usages. */ - BUG_ON(index > CPUACCT_STAT_NSTATS); + if (WARN_ON_ONCE(index > CPUACCT_STAT_NSTATS)) + return 0; #ifndef CONFIG_64BIT /* -- GitLab From dd02d4234c9a2214a81c57a16484304a1a51872a Mon Sep 17 00:00:00 2001 From: Andrey Ryabinin Date: Mon, 15 Nov 2021 19:46:06 +0300 Subject: [PATCH 0136/1112] sched/cpuacct: Fix user/system in shown cpuacct.usage* cpuacct has 2 different ways of accounting and showing user and system times. The first one uses cpuacct_account_field() to account times and cpuacct.stat file to expose them. And this one seems to work ok. The second one is uses cpuacct_charge() function for accounting and set of cpuacct.usage* files to show times. Despite some attempts to fix it in the past it still doesn't work. Sometimes while running KVM guest the cpuacct_charge() accounts most of the guest time as system time. This doesn't match with user&system times shown in cpuacct.stat or proc//stat. Demonstration: # git clone https://github.com/aryabinin/kvmsample # make # mkdir /sys/fs/cgroup/cpuacct/test # echo $$ > /sys/fs/cgroup/cpuacct/test/tasks # ./kvmsample & # for i in {1..5}; do cat /sys/fs/cgroup/cpuacct/test/cpuacct.usage_sys; sleep 1; done 1976535645 2979839428 3979832704 4983603153 5983604157 Use cpustats accounted in cpuacct_account_field() as the source of user/sys times for cpuacct.usage* files. Make cpuacct_charge() to account only summary execution time. Fixes: d740037fac70 ("sched/cpuacct: Split usage accounting into user_usage and sys_usage") Signed-off-by: Andrey Ryabinin Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Daniel Jordan Acked-by: Tejun Heo Cc: Link: https://lore.kernel.org/r/20211115164607.23784-3-arbn@yandex-team.com --- kernel/sched/cpuacct.c | 79 +++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 47 deletions(-) diff --git a/kernel/sched/cpuacct.c b/kernel/sched/cpuacct.c index f347cf9e46345..9de7dd51beb0e 100644 --- a/kernel/sched/cpuacct.c +++ b/kernel/sched/cpuacct.c @@ -21,15 +21,11 @@ static const char * const cpuacct_stat_desc[] = { [CPUACCT_STAT_SYSTEM] = "system", }; -struct cpuacct_usage { - u64 usages[CPUACCT_STAT_NSTATS]; -}; - /* track CPU usage of a group of tasks and its child groups */ struct cpuacct { struct cgroup_subsys_state css; /* cpuusage holds pointer to a u64-type object on every CPU */ - struct cpuacct_usage __percpu *cpuusage; + u64 __percpu *cpuusage; struct kernel_cpustat __percpu *cpustat; }; @@ -49,7 +45,7 @@ static inline struct cpuacct *parent_ca(struct cpuacct *ca) return css_ca(ca->css.parent); } -static DEFINE_PER_CPU(struct cpuacct_usage, root_cpuacct_cpuusage); +static DEFINE_PER_CPU(u64, root_cpuacct_cpuusage); static struct cpuacct root_cpuacct = { .cpustat = &kernel_cpustat, .cpuusage = &root_cpuacct_cpuusage, @@ -68,7 +64,7 @@ cpuacct_css_alloc(struct cgroup_subsys_state *parent_css) if (!ca) goto out; - ca->cpuusage = alloc_percpu(struct cpuacct_usage); + ca->cpuusage = alloc_percpu(u64); if (!ca->cpuusage) goto out_free_ca; @@ -99,7 +95,8 @@ static void cpuacct_css_free(struct cgroup_subsys_state *css) static u64 cpuacct_cpuusage_read(struct cpuacct *ca, int cpu, enum cpuacct_stat_index index) { - struct cpuacct_usage *cpuusage = per_cpu_ptr(ca->cpuusage, cpu); + u64 *cpuusage = per_cpu_ptr(ca->cpuusage, cpu); + u64 *cpustat = per_cpu_ptr(ca->cpustat, cpu)->cpustat; u64 data; /* @@ -116,14 +113,17 @@ static u64 cpuacct_cpuusage_read(struct cpuacct *ca, int cpu, raw_spin_rq_lock_irq(cpu_rq(cpu)); #endif - if (index == CPUACCT_STAT_NSTATS) { - int i = 0; - - data = 0; - for (i = 0; i < CPUACCT_STAT_NSTATS; i++) - data += cpuusage->usages[i]; - } else { - data = cpuusage->usages[index]; + switch (index) { + case CPUACCT_STAT_USER: + data = cpustat[CPUTIME_USER] + cpustat[CPUTIME_NICE]; + break; + case CPUACCT_STAT_SYSTEM: + data = cpustat[CPUTIME_SYSTEM] + cpustat[CPUTIME_IRQ] + + cpustat[CPUTIME_SOFTIRQ]; + break; + case CPUACCT_STAT_NSTATS: + data = *cpuusage; + break; } #ifndef CONFIG_64BIT @@ -133,10 +133,14 @@ static u64 cpuacct_cpuusage_read(struct cpuacct *ca, int cpu, return data; } -static void cpuacct_cpuusage_write(struct cpuacct *ca, int cpu, u64 val) +static void cpuacct_cpuusage_write(struct cpuacct *ca, int cpu) { - struct cpuacct_usage *cpuusage = per_cpu_ptr(ca->cpuusage, cpu); - int i; + u64 *cpuusage = per_cpu_ptr(ca->cpuusage, cpu); + u64 *cpustat = per_cpu_ptr(ca->cpustat, cpu)->cpustat; + + /* Don't allow to reset global kernel_cpustat */ + if (ca == &root_cpuacct) + return; #ifndef CONFIG_64BIT /* @@ -144,9 +148,10 @@ static void cpuacct_cpuusage_write(struct cpuacct *ca, int cpu, u64 val) */ raw_spin_rq_lock_irq(cpu_rq(cpu)); #endif - - for (i = 0; i < CPUACCT_STAT_NSTATS; i++) - cpuusage->usages[i] = val; + *cpuusage = 0; + cpustat[CPUTIME_USER] = cpustat[CPUTIME_NICE] = 0; + cpustat[CPUTIME_SYSTEM] = cpustat[CPUTIME_IRQ] = 0; + cpustat[CPUTIME_SOFTIRQ] = 0; #ifndef CONFIG_64BIT raw_spin_rq_unlock_irq(cpu_rq(cpu)); @@ -197,7 +202,7 @@ static int cpuusage_write(struct cgroup_subsys_state *css, struct cftype *cft, return -EINVAL; for_each_possible_cpu(cpu) - cpuacct_cpuusage_write(ca, cpu, 0); + cpuacct_cpuusage_write(ca, cpu); return 0; } @@ -244,25 +249,10 @@ static int cpuacct_all_seq_show(struct seq_file *m, void *V) seq_puts(m, "\n"); for_each_possible_cpu(cpu) { - struct cpuacct_usage *cpuusage = per_cpu_ptr(ca->cpuusage, cpu); - seq_printf(m, "%d", cpu); - - for (index = 0; index < CPUACCT_STAT_NSTATS; index++) { -#ifndef CONFIG_64BIT - /* - * Take rq->lock to make 64-bit read safe on 32-bit - * platforms. - */ - raw_spin_rq_lock_irq(cpu_rq(cpu)); -#endif - - seq_printf(m, " %llu", cpuusage->usages[index]); - -#ifndef CONFIG_64BIT - raw_spin_rq_unlock_irq(cpu_rq(cpu)); -#endif - } + for (index = 0; index < CPUACCT_STAT_NSTATS; index++) + seq_printf(m, " %llu", + cpuacct_cpuusage_read(ca, cpu, index)); seq_puts(m, "\n"); } return 0; @@ -340,16 +330,11 @@ static struct cftype files[] = { void cpuacct_charge(struct task_struct *tsk, u64 cputime) { struct cpuacct *ca; - int index = CPUACCT_STAT_SYSTEM; - struct pt_regs *regs = get_irq_regs() ? : task_pt_regs(tsk); - - if (regs && user_mode(regs)) - index = CPUACCT_STAT_USER; rcu_read_lock(); for (ca = task_ca(tsk); ca; ca = parent_ca(ca)) - __this_cpu_add(ca->cpuusage->usages[index], cputime); + __this_cpu_add(*ca->cpuusage, cputime); rcu_read_unlock(); } -- GitLab From 8c92606ab81086db00cbb73347d124b4eb169b7e Mon Sep 17 00:00:00 2001 From: Andrey Ryabinin Date: Mon, 15 Nov 2021 19:46:07 +0300 Subject: [PATCH 0137/1112] sched/cpuacct: Make user/system times in cpuacct.stat more precise cpuacct.stat shows user time based on raw random precision tick based counters. Use cputime_addjust() to scale these values against the total runtime accounted by the scheduler, like we already do for user/system times in /proc//stat. Signed-off-by: Andrey Ryabinin Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Daniel Jordan Acked-by: Tejun Heo Link: https://lore.kernel.org/r/20211115164607.23784-4-arbn@yandex-team.com --- kernel/sched/cpuacct.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/kernel/sched/cpuacct.c b/kernel/sched/cpuacct.c index 9de7dd51beb0e..3d06c5e4220d4 100644 --- a/kernel/sched/cpuacct.c +++ b/kernel/sched/cpuacct.c @@ -261,25 +261,30 @@ static int cpuacct_all_seq_show(struct seq_file *m, void *V) static int cpuacct_stats_show(struct seq_file *sf, void *v) { struct cpuacct *ca = css_ca(seq_css(sf)); - s64 val[CPUACCT_STAT_NSTATS]; + struct task_cputime cputime; + u64 val[CPUACCT_STAT_NSTATS]; int cpu; int stat; - memset(val, 0, sizeof(val)); + memset(&cputime, 0, sizeof(cputime)); for_each_possible_cpu(cpu) { u64 *cpustat = per_cpu_ptr(ca->cpustat, cpu)->cpustat; - val[CPUACCT_STAT_USER] += cpustat[CPUTIME_USER]; - val[CPUACCT_STAT_USER] += cpustat[CPUTIME_NICE]; - val[CPUACCT_STAT_SYSTEM] += cpustat[CPUTIME_SYSTEM]; - val[CPUACCT_STAT_SYSTEM] += cpustat[CPUTIME_IRQ]; - val[CPUACCT_STAT_SYSTEM] += cpustat[CPUTIME_SOFTIRQ]; + cputime.utime += cpustat[CPUTIME_USER]; + cputime.utime += cpustat[CPUTIME_NICE]; + cputime.stime += cpustat[CPUTIME_SYSTEM]; + cputime.stime += cpustat[CPUTIME_IRQ]; + cputime.stime += cpustat[CPUTIME_SOFTIRQ]; + + cputime.sum_exec_runtime += *per_cpu_ptr(ca->cpuusage, cpu); } + cputime_adjust(&cputime, &seq_css(sf)->cgroup->prev_cputime, + &val[CPUACCT_STAT_USER], &val[CPUACCT_STAT_SYSTEM]); + for (stat = 0; stat < CPUACCT_STAT_NSTATS; stat++) { - seq_printf(sf, "%s %lld\n", - cpuacct_stat_desc[stat], - (long long)nsec_to_clock_t(val[stat])); + seq_printf(sf, "%s %llu\n", cpuacct_stat_desc[stat], + nsec_to_clock_t(val[stat])); } return 0; -- GitLab From cff6f593251cdf5398dc3c57f7032b8e9dcb633e Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Tue, 23 Nov 2021 12:36:47 +0200 Subject: [PATCH 0138/1112] regulator: rohm-generic: iniline stub function The function rohm_regulator_set_voltage_sel_restricted() has a stub implementation. Linux-next testing spot following: include/linux/mfd/rohm-generic.h:93:12: error: 'rohm_regulator_set_voltage_sel_restricted' defined but not used Fix this by inlining the stub. Fixes: 8b6e88555971 ("regulator: rohm-regulator: add helper for restricted voltage setting") Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/YZzEP3S7U15bTDAI@fedora Signed-off-by: Mark Brown --- include/linux/mfd/rohm-generic.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linux/mfd/rohm-generic.h b/include/linux/mfd/rohm-generic.h index 35c5866f48b7c..080d60adcd5f5 100644 --- a/include/linux/mfd/rohm-generic.h +++ b/include/linux/mfd/rohm-generic.h @@ -90,7 +90,8 @@ static inline int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dv { return 0; } -static int rohm_regulator_set_voltage_sel_restricted(struct regulator_dev *rdev, + +static inline int rohm_regulator_set_voltage_sel_restricted(struct regulator_dev *rdev, unsigned int sel) { return 0; -- GitLab From b00bab9d48bbb6446a5cf366f5f8e501a16031a1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 22 Nov 2021 19:17:20 +0200 Subject: [PATCH 0139/1112] spi: Replace memset() with __GFP_ZERO krealloc() as any other kernel memory allocation calls accepts GFP flags, one of which is __GFP_ZERO. Hence, no need to call memset() explicitly on the reallocated buffer. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211122171721.61553-2-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 9d19d9bae2537..3b9010a673975 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1222,11 +1222,10 @@ static int spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg) if (max_tx) { tmp = krealloc(ctlr->dummy_tx, max_tx, - GFP_KERNEL | GFP_DMA); + GFP_KERNEL | GFP_DMA | __GFP_ZERO); if (!tmp) return -ENOMEM; ctlr->dummy_tx = tmp; - memset(tmp, 0, max_tx); } if (max_rx) { -- GitLab From 350de7ce26caba5c7ec0dd4ef1802c9a50a5d85d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 22 Nov 2021 19:17:21 +0200 Subject: [PATCH 0140/1112] spi: Fix multi-line comment style /* * Fix multi-line comment style as in this short example. Pay attention * to the capitalization, period and starting line of the text. */ While at it, split the (supposedly short) description of couple of functions to summary (short description) and (long) description. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211122171721.61553-3-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 160 ++++++++++++++++++++++++++-------------------- 1 file changed, 89 insertions(+), 71 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 3b9010a673975..5bf680fcb1709 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -311,10 +311,10 @@ static void spi_statistics_add_transfer_stats(struct spi_statistics *stats, spin_unlock_irqrestore(&stats->lock, flags); } -/* modalias support makes "modprobe $MODALIAS" new-style hotplug work, +/* + * modalias support makes "modprobe $MODALIAS" new-style hotplug work, * and the sysfs version makes coldplug work too. */ - static const struct spi_device_id *spi_match_id(const struct spi_device_id *id, const char *name) { while (id->name[0]) { @@ -492,7 +492,8 @@ EXPORT_SYMBOL_GPL(__spi_register_driver); /*-------------------------------------------------------------------------*/ -/* SPI devices should normally not be created by SPI device drivers; that +/* + * SPI devices should normally not be created by SPI device drivers; that * would make them board-specific. Similarly with SPI controller drivers. * Device registration normally goes into like arch/.../mach.../board-YYY.c * with other readonly (flashable) information about mainboard devices. @@ -508,8 +509,8 @@ static LIST_HEAD(spi_controller_list); /* * Used to protect add/del operation for board_info list and - * spi_controller list, and their matching process - * also used to protect object of type struct idr + * spi_controller list, and their matching process also used + * to protect object of type struct idr. */ static DEFINE_MUTEX(board_lock); @@ -616,7 +617,8 @@ static int __spi_add_device(struct spi_device *spi) else if (ctlr->cs_gpios) spi->cs_gpio = ctlr->cs_gpios[spi->chip_select]; - /* Drivers may modify this initial i/o setup, but will + /* + * Drivers may modify this initial i/o setup, but will * normally rely on the device being setup. Devices * using SPI_CS_HIGH can't coexist well otherwise... */ @@ -710,7 +712,8 @@ struct spi_device *spi_new_device(struct spi_controller *ctlr, struct spi_device *proxy; int status; - /* NOTE: caller did any chip->bus_num checks necessary. + /* + * NOTE: caller did any chip->bus_num checks necessary. * * Also, unless we change the return value convention to use * error-or-pointer (not NULL-or-pointer), troubleshootability @@ -878,7 +881,6 @@ static void *spi_res_alloc(struct spi_device *spi, spi_res_release_t release, /** * spi_res_free - free an spi resource * @res: pointer to the custom data of a resource - * */ static void spi_res_free(void *res) { @@ -973,7 +975,7 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force) gpiod_set_value_cansleep(spi->cs_gpiod, activate); } else { /* - * invert the enable line, as active low is + * Invert the enable line, as active low is * default for SPI. */ gpio_set_value_cansleep(spi->cs_gpio, !enable); @@ -1711,16 +1713,7 @@ static void spi_pump_messages(struct kthread_work *work) } /** - * spi_take_timestamp_pre - helper for drivers to collect the beginning of the - * TX timestamp for the requested byte from the SPI - * transfer. The frequency with which this function - * must be called (once per word, once for the whole - * transfer, once per batch of words etc) is arbitrary - * as long as the @tx buffer offset is greater than or - * equal to the requested byte at the time of the - * call. The timestamp is only taken once, at the - * first such call. It is assumed that the driver - * advances its @tx buffer pointer monotonically. + * spi_take_timestamp_pre - helper to collect the beginning of the TX timestamp * @ctlr: Pointer to the spi_controller structure of the driver * @xfer: Pointer to the transfer being timestamped * @progress: How many words (not bytes) have been transferred so far @@ -1730,6 +1723,14 @@ static void spi_pump_messages(struct kthread_work *work) * spi_take_timestamp_post or otherwise system will crash. * WARNING: for fully predictable results, the CPU frequency must * also be under control (governor). + * + * This is a helper for drivers to collect the beginning of the TX timestamp + * for the requested byte from the SPI transfer. The frequency with which this + * function must be called (once per word, once for the whole transfer, once + * per batch of words etc) is arbitrary as long as the @tx buffer offset is + * greater than or equal to the requested byte at the time of the call. The + * timestamp is only taken once, at the first such call. It is assumed that + * the driver advances its @tx buffer pointer monotonically. */ void spi_take_timestamp_pre(struct spi_controller *ctlr, struct spi_transfer *xfer, @@ -1757,16 +1758,16 @@ void spi_take_timestamp_pre(struct spi_controller *ctlr, EXPORT_SYMBOL_GPL(spi_take_timestamp_pre); /** - * spi_take_timestamp_post - helper for drivers to collect the end of the - * TX timestamp for the requested byte from the SPI - * transfer. Can be called with an arbitrary - * frequency: only the first call where @tx exceeds - * or is equal to the requested word will be - * timestamped. + * spi_take_timestamp_post - helper to collect the end of the TX timestamp * @ctlr: Pointer to the spi_controller structure of the driver * @xfer: Pointer to the transfer being timestamped * @progress: How many words (not bytes) have been transferred so far * @irqs_off: If true, will re-enable IRQs and preemption for the local CPU. + * + * This is a helper for drivers to collect the end of the TX timestamp for + * the requested byte from the SPI transfer. Can be called with an arbitrary + * frequency: only the first call where @tx exceeds or is equal to the + * requested word will be timestamped. */ void spi_take_timestamp_post(struct spi_controller *ctlr, struct spi_transfer *xfer, @@ -1899,10 +1900,12 @@ void spi_finalize_current_message(struct spi_controller *ctlr) spi_unmap_msg(ctlr, mesg); - /* In the prepare_messages callback the spi bus has the opportunity to - * split a transfer to smaller chunks. - * Release splited transfers here since spi_map_msg is done on the - * splited transfers. + /* + * In the prepare_messages callback the SPI bus has the opportunity + * to split a transfer to smaller chunks. + * + * Release the split transfers here since spi_map_msg() is done on + * the split transfers. */ spi_res_release(ctlr, mesg); @@ -2944,8 +2947,9 @@ int spi_register_controller(struct spi_controller *ctlr) if (!ctlr->max_dma_len) ctlr->max_dma_len = INT_MAX; - /* register the device, then userspace will see it. - * registration fails if the bus ID is in use. + /* + * Register the device, then userspace will see it. + * Registration fails if the bus ID is in use. */ dev_set_name(&ctlr->dev, "spi%u", ctlr->bus_num); @@ -3211,16 +3215,18 @@ static struct spi_replaced_transfers *spi_replace_transfers( /* init the replaced_transfers list */ INIT_LIST_HEAD(&rxfer->replaced_transfers); - /* assign the list_entry after which we should reinsert + /* + * Assign the list_entry after which we should reinsert * the @replaced_transfers - it may be spi_message.messages! */ rxfer->replaced_after = xfer_first->transfer_list.prev; /* remove the requested number of transfers */ for (i = 0; i < remove; i++) { - /* if the entry after replaced_after it is msg->transfers + /* + * If the entry after replaced_after it is msg->transfers * then we have been requested to remove more transfers - * than are in the list + * than are in the list. */ if (rxfer->replaced_after->next == &msg->transfers) { dev_err(&msg->spi->dev, @@ -3236,15 +3242,17 @@ static struct spi_replaced_transfers *spi_replace_transfers( return ERR_PTR(-EINVAL); } - /* remove the entry after replaced_after from list of - * transfers and add it to list of replaced_transfers + /* + * Remove the entry after replaced_after from list of + * transfers and add it to list of replaced_transfers. */ list_move_tail(rxfer->replaced_after->next, &rxfer->replaced_transfers); } - /* create copy of the given xfer with identical settings - * based on the first transfer to get removed + /* + * Create copy of the given xfer with identical settings + * based on the first transfer to get removed. */ for (i = 0; i < insert; i++) { /* we need to run in reverse order */ @@ -3292,18 +3300,20 @@ static int __spi_split_transfer_maxsize(struct spi_controller *ctlr, return PTR_ERR(srt); xfers = srt->inserted_transfers; - /* now handle each of those newly inserted spi_transfers - * note that the replacements spi_transfers all are preset + /* + * Now handle each of those newly inserted spi_transfers. + * Note that the replacements spi_transfers all are preset * to the same values as *xferp, so tx_buf, rx_buf and len * are all identical (as well as most others) * so we just have to fix up len and the pointers. * - * this also includes support for the depreciated - * spi_message.is_dma_mapped interface + * This also includes support for the depreciated + * spi_message.is_dma_mapped interface. */ - /* the first transfer just needs the length modified, so we - * run it outside the loop + /* + * The first transfer just needs the length modified, so we + * run it outside the loop. */ xfers[0].len = min_t(size_t, maxsize, xfer[0].len); @@ -3323,8 +3333,9 @@ static int __spi_split_transfer_maxsize(struct spi_controller *ctlr, xfers[i].len = min(maxsize, xfers[i].len - offset); } - /* we set up xferp to the last entry we have inserted, - * so that we skip those already split transfers + /* + * We set up xferp to the last entry we have inserted, + * so that we skip those already split transfers. */ *xferp = &xfers[count - 1]; @@ -3356,11 +3367,12 @@ int spi_split_transfers_maxsize(struct spi_controller *ctlr, struct spi_transfer *xfer; int ret; - /* iterate over the transfer_list, + /* + * Iterate over the transfer_list, * but note that xfer is advanced to the last transfer inserted * to avoid checking sizes again unnecessarily (also xfer does - * potentiall belong to a different list by the time the - * replacement has happened + * potentially belong to a different list by the time the + * replacement has happened). */ list_for_each_entry(xfer, &msg->transfers, transfer_list) { if (xfer->len > maxsize) { @@ -3421,8 +3433,8 @@ int spi_setup(struct spi_device *spi) int status; /* - * check mode to prevent that any two of DUAL, QUAD and NO_MOSI/MISO - * are set at the same time + * Check mode to prevent that any two of DUAL, QUAD and NO_MOSI/MISO + * are set at the same time. */ if ((hweight_long(spi->mode & (SPI_TX_DUAL | SPI_TX_QUAD | SPI_NO_TX)) > 1) || @@ -3432,20 +3444,21 @@ int spi_setup(struct spi_device *spi) "setup: can not select any two of dual, quad and no-rx/tx at the same time\n"); return -EINVAL; } - /* if it is SPI_3WIRE mode, DUAL and QUAD should be forbidden - */ + /* If it is SPI_3WIRE mode, DUAL and QUAD should be forbidden */ if ((spi->mode & SPI_3WIRE) && (spi->mode & (SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL | SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL))) return -EINVAL; - /* help drivers fail *cleanly* when they need options - * that aren't supported with their current controller + /* + * Help drivers fail *cleanly* when they need options + * that aren't supported with their current controller. * SPI_CS_WORD has a fallback software implementation, * so it is ignored here. */ bad_bits = spi->mode & ~(spi->controller->mode_bits | SPI_CS_WORD | SPI_NO_TX | SPI_NO_RX); - /* nothing prevents from working with active-high CS in case if it + /* + * Nothing prevents from working with active-high CS in case if it * is driven by GPIO. */ if (gpio_is_valid(spi->cs_gpio)) @@ -3567,7 +3580,8 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) if (list_empty(&message->transfers)) return -EINVAL; - /* If an SPI controller does not support toggling the CS line on each + /* + * If an SPI controller does not support toggling the CS line on each * transfer (indicated by the SPI_CS_WORD flag) or we are using a GPIO * for the CS line, we can emulate the CS-per-word hardware function by * splitting transfers into one-word transfers and ensuring that @@ -3597,7 +3611,8 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) } } - /* Half-duplex links include original MicroWire, and ones with + /* + * Half-duplex links include original MicroWire, and ones with * only one data pin like SPI_3WIRE (switches direction) or where * either MOSI or MISO is missing. They can also be caused by * software limitations. @@ -3616,7 +3631,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) } } - /** + /* * Set transfer bits_per_word and max speed as spi device default if * it is not set for this transfer. * Set transfer tx_nbits and rx_nbits as single transfer default @@ -3642,7 +3657,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) /* * SPI transfer length should be multiple of SPI word size - * where SPI word size should be power-of-two multiple + * where SPI word size should be power-of-two multiple. */ if (xfer->bits_per_word <= 8) w_size = 1; @@ -3663,7 +3678,8 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) xfer->tx_nbits = SPI_NBITS_SINGLE; if (xfer->rx_buf && !xfer->rx_nbits) xfer->rx_nbits = SPI_NBITS_SINGLE; - /* check transfer tx/rx_nbits: + /* + * Check transfer tx/rx_nbits: * 1. check the value matches one of single, dual and quad * 2. check tx/rx_nbits match the mode in spi_device */ @@ -3842,7 +3858,8 @@ static int spi_async_locked(struct spi_device *spi, struct spi_message *message) /*-------------------------------------------------------------------------*/ -/* Utility methods for SPI protocol drivers, layered on +/* + * Utility methods for SPI protocol drivers, layered on * top of the core. Some other utility methods are defined as * inline functions. */ @@ -3870,7 +3887,8 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message) SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics, spi_sync); SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_sync); - /* If we're not using the legacy transfer method then we will + /* + * If we're not using the legacy transfer method then we will * try to transfer in the calling context so special case. * This code would be less tricky if we could remove the * support for driver implemented message queues. @@ -3888,9 +3906,7 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message) } if (status == 0) { - /* Push out the messages in the calling context if we - * can. - */ + /* Push out the messages in the calling context if we can */ if (ctlr->transfer == spi_queued_transfer) { SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics, spi_sync_immediate); @@ -4051,7 +4067,8 @@ int spi_write_then_read(struct spi_device *spi, struct spi_transfer x[2]; u8 *local_buf; - /* Use preallocated DMA-safe buffer if we can. We can't avoid + /* + * Use preallocated DMA-safe buffer if we can. We can't avoid * copying here, (as a pure convenience thing), but we can * keep heap costs out of the hot path unless someone else is * using the pre-allocated buffer or the transfer is too large. @@ -4287,11 +4304,12 @@ err0: return status; } -/* board_info is normally registered in arch_initcall(), - * but even essential drivers wait till later +/* + * A board_info is normally registered in arch_initcall(), + * but even essential drivers wait till later. * - * REVISIT only boardinfo really needs static linking. the rest (device and - * driver registration) _could_ be dynamically linked (modular) ... costs + * REVISIT only boardinfo really needs static linking. The rest (device and + * driver registration) _could_ be dynamically linked (modular) ... Costs * include needing to have boardinfo data structures be much more public. */ postcore_initcall(spi_init); -- GitLab From dd06a0c6b6f64f6610c0bb8f7651df3ebfb0f990 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 22 Nov 2021 19:52:45 +0200 Subject: [PATCH 0141/1112] spi: spidev: Use SPI_MODE_USER_MASK instead of casting Currently the 16-bit mode is what being used in user space. However assuming that is not fully correct. Instead we should use the respective mask, i.e. SPI_MODE_USER_MASK, which precisely defines what bits are available for user space apps. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211122175245.84691-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spidev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 1bd73e322b7bb..968dab2f5e3de 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -415,7 +415,7 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) tmp |= SPI_CS_HIGH; tmp |= spi->mode & ~SPI_MODE_MASK; - spi->mode = (u16)tmp; + spi->mode = tmp & SPI_MODE_USER_MASK; retval = spi_setup(spi); if (retval < 0) spi->mode = save; -- GitLab From 44ec41b7f7831f91c79a06de5e45f2d7ce6e4fbd Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 22 Nov 2021 22:06:22 +0200 Subject: [PATCH 0142/1112] spi: pxa2xx: Remove redundant ->read() and ->write() in struct chip_data Since the commit 196b0e2cf237 ("spi: pxa2xx: Remove if statement that is always true in pump_transfers()") the ->read() and ->write() methods in the struct driver_data are reconfigured for each transfer. Hence no need to keep the intermediate state in the struct chip_data. The same applies to n_bytes member of the same data structure. Get rid of unneeded storage for good. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211122200622.43305-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 35 ++++++----------------------------- drivers/spi/spi-pxa2xx.h | 4 ---- 2 files changed, 6 insertions(+), 33 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 1573f6d8eb48a..ee3297dd532e3 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -994,13 +994,10 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller, dev_err(&spi->dev, "Flush failed\n"); return -EIO; } - drv_data->n_bytes = chip->n_bytes; drv_data->tx = (void *)transfer->tx_buf; drv_data->tx_end = drv_data->tx + transfer->len; drv_data->rx = transfer->rx_buf; drv_data->rx_end = drv_data->rx + transfer->len; - drv_data->write = drv_data->tx ? chip->write : null_writer; - drv_data->read = drv_data->rx ? chip->read : null_reader; /* Change speed and bit per word on a per transfer */ bits = transfer->bits_per_word; @@ -1010,22 +1007,16 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller, if (bits <= 8) { drv_data->n_bytes = 1; - drv_data->read = drv_data->read != null_reader ? - u8_reader : null_reader; - drv_data->write = drv_data->write != null_writer ? - u8_writer : null_writer; + drv_data->read = drv_data->rx ? u8_reader : null_reader; + drv_data->write = drv_data->tx ? u8_writer : null_writer; } else if (bits <= 16) { drv_data->n_bytes = 2; - drv_data->read = drv_data->read != null_reader ? - u16_reader : null_reader; - drv_data->write = drv_data->write != null_writer ? - u16_writer : null_writer; + drv_data->read = drv_data->rx ? u16_reader : null_reader; + drv_data->write = drv_data->tx ? u16_writer : null_writer; } else if (bits <= 32) { drv_data->n_bytes = 4; - drv_data->read = drv_data->read != null_reader ? - u32_reader : null_reader; - drv_data->write = drv_data->write != null_writer ? - u32_writer : null_writer; + drv_data->read = drv_data->rx ? u32_reader : null_reader; + drv_data->write = drv_data->tx ? u32_writer : null_writer; } /* * If bits per word is changed in DMA mode, then must check @@ -1391,20 +1382,6 @@ static int setup(struct spi_device *spi) if (spi->mode & SPI_LOOP) chip->cr1 |= SSCR1_LBM; - if (spi->bits_per_word <= 8) { - chip->n_bytes = 1; - chip->read = u8_reader; - chip->write = u8_writer; - } else if (spi->bits_per_word <= 16) { - chip->n_bytes = 2; - chip->read = u16_reader; - chip->write = u16_writer; - } else if (spi->bits_per_word <= 32) { - chip->n_bytes = 4; - chip->read = u32_reader; - chip->write = u32_writer; - } - spi_set_ctldata(spi, chip); if (drv_data->ssp_type == CE4100_SSP) diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index 9a20fb88e50f4..4d77f4de6eda2 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -61,7 +61,6 @@ struct chip_data { u32 cr1; u32 dds_rate; u32 timeout; - u8 n_bytes; u8 enable_dma; u32 dma_burst_size; u32 dma_threshold; @@ -69,9 +68,6 @@ struct chip_data { u16 lpss_rx_threshold; u16 lpss_tx_threshold; - int (*write)(struct driver_data *drv_data); - int (*read)(struct driver_data *drv_data); - void (*cs_control)(u32 command); }; -- GitLab From 1b6ed6bf32fb22ef8e3572fc9c0f6454adf1ca40 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Wed, 24 Nov 2021 09:17:37 +0200 Subject: [PATCH 0143/1112] regulator: Drop unnecessary struct member The irq_flags from the regulator IRQ helper description struct was never used. The IRQ flags are passed as parameters to helper registration instead. Remove the unnecessary struct field. Fixes: 7111c6d1b31b ("regulator: IRQ based event/error notification helpers") Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/5f6371e178453fa2b165da50452f7db4e986debb.1637736436.git.matti.vaittinen@fi.rohmeurope.com Signed-off-by: Mark Brown --- include/linux/regulator/driver.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 1cb8071fee343..53b25cd7ead0c 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -554,7 +554,6 @@ struct regulator_irq_data { */ struct regulator_irq_desc { const char *name; - int irq_flags; int fatal_cnt; int reread_ms; int irq_off_ms; -- GitLab From 6fadec4c5561e2fbe1dfa8a7da9bc58d094a8f04 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Wed, 24 Nov 2021 09:16:45 +0200 Subject: [PATCH 0144/1112] regulator: Add regulator_err2notif() helper Help drivers avoid storing both supported notification and supported error flags by supporting conversion from regulator error to notification. This may help saving some bytes. Add helper for finding the regulator notification corresponding to a regulator error. Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/eb1755ac0569ff07ffa466cf8912c6fd50e7c7c6.1637736436.git.matti.vaittinen@fi.rohmeurope.com Signed-off-by: Mark Brown --- include/linux/regulator/driver.h | 34 ++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 53b25cd7ead0c..6c6ec9658c303 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -645,6 +645,40 @@ struct regulator_dev { spinlock_t err_lock; }; +/* + * Convert error flags to corresponding notifications. + * + * Can be used by drivers which use the notification helpers to + * find out correct notification flags based on the error flags. Drivers + * can avoid storing both supported notification and error flags which + * may save few bytes. + */ +static inline int regulator_err2notif(int err) +{ + switch (err) { + case REGULATOR_ERROR_UNDER_VOLTAGE: + return REGULATOR_EVENT_UNDER_VOLTAGE; + case REGULATOR_ERROR_OVER_CURRENT: + return REGULATOR_EVENT_OVER_CURRENT; + case REGULATOR_ERROR_REGULATION_OUT: + return REGULATOR_EVENT_REGULATION_OUT; + case REGULATOR_ERROR_FAIL: + return REGULATOR_EVENT_FAIL; + case REGULATOR_ERROR_OVER_TEMP: + return REGULATOR_EVENT_OVER_TEMP; + case REGULATOR_ERROR_UNDER_VOLTAGE_WARN: + return REGULATOR_EVENT_UNDER_VOLTAGE_WARN; + case REGULATOR_ERROR_OVER_CURRENT_WARN: + return REGULATOR_EVENT_OVER_CURRENT_WARN; + case REGULATOR_ERROR_OVER_VOLTAGE_WARN: + return REGULATOR_EVENT_OVER_VOLTAGE_WARN; + case REGULATOR_ERROR_OVER_TEMP_WARN: + return REGULATOR_EVENT_OVER_TEMP_WARN; + } + return 0; +} + + struct regulator_dev * regulator_register(const struct regulator_desc *regulator_desc, const struct regulator_config *config); -- GitLab From a764ff77d697a4a13e69b3379cc613f7409c6b9a Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Wed, 24 Nov 2021 09:17:13 +0200 Subject: [PATCH 0145/1112] regulator: irq_helper: Provide helper for trivial IRQ notifications Provide a generic map_event helper for regulators which have a notification IRQ with single, well defined purpose. Eg, IRQ always indicates exactly one event for exactly one regulator device. For such IRQs the mapping is trivial. Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/603b7ed1938013a00371c1e7ccc63dfb16982b87.1637736436.git.matti.vaittinen@fi.rohmeurope.com Signed-off-by: Mark Brown --- drivers/regulator/irq_helpers.c | 41 +++++++++++++++++++++++++++++++- include/linux/regulator/driver.h | 2 ++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/drivers/regulator/irq_helpers.c b/drivers/regulator/irq_helpers.c index 5227644355750..fe7ae0f3f46af 100644 --- a/drivers/regulator/irq_helpers.c +++ b/drivers/regulator/irq_helpers.c @@ -320,7 +320,9 @@ static void init_rdev_errors(struct regulator_irq *h) * IRQF_ONESHOT when requesting the (threaded) irq. * @common_errs: Errors which can be flagged by this IRQ for all rdevs. * When IRQ is re-enabled these errors will be cleared - * from all associated regulators + * from all associated regulators. Use this instead of the + * per_rdev_errs if you use + * regulator_irq_map_event_simple() for event mapping. * @per_rdev_errs: Optional error flag array describing errors specific * for only some of the regulators. These errors will be * or'ed with common errors. If this is given the array @@ -395,3 +397,40 @@ void regulator_irq_helper_cancel(void **handle) } } EXPORT_SYMBOL_GPL(regulator_irq_helper_cancel); + +/** + * regulator_irq_map_event_simple - regulator IRQ notification for trivial IRQs + * + * @irq: Number of IRQ that occurred + * @rid: Information about the event IRQ indicates + * @dev_mask: mask indicating the regulator originating the IRQ + * + * Regulators whose IRQ has single, well defined purpose (always indicate + * exactly one event, and are relevant to exactly one regulator device) can + * use this function as their map_event callbac for their regulator IRQ + * notification helperk. Exactly one rdev and exactly one error (in + * "common_errs"-field) can be given at IRQ helper registration for + * regulator_irq_map_event_simple() to be viable. + */ +int regulator_irq_map_event_simple(int irq, struct regulator_irq_data *rid, + unsigned long *dev_mask) +{ + int err = rid->states[0].possible_errs; + + *dev_mask = 1; + /* + * This helper should only be used in a situation where the IRQ + * can indicate only one type of problem for one specific rdev. + * Something fishy is going on if we are having multiple rdevs or ERROR + * flags here. + */ + if (WARN_ON(rid->num_states != 1 || hweight32(err) != 1)) + return 0; + + rid->states[0].errors = err; + rid->states[0].notifs = regulator_err2notif(err); + + return 0; +} +EXPORT_SYMBOL_GPL(regulator_irq_map_event_simple); + diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 6c6ec9658c303..4078c77764532 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -700,6 +700,8 @@ void *regulator_irq_helper(struct device *dev, int irq_flags, int common_errs, int *per_rdev_errs, struct regulator_dev **rdev, int rdev_amount); void regulator_irq_helper_cancel(void **handle); +int regulator_irq_map_event_simple(int irq, struct regulator_irq_data *rid, + unsigned long *dev_mask); void *rdev_get_drvdata(struct regulator_dev *rdev); struct device *rdev_get_dev(struct regulator_dev *rdev); -- GitLab From 432dd1fc134ef902b049b26839edfd3fdc1f8dc0 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Wed, 24 Nov 2021 07:57:49 +0200 Subject: [PATCH 0146/1112] regulator: rohm-generic: remove unused dummies Function rohm_regulator_set_voltage_sel_restricted() and rohm_regulator_set_dvs_levels() had inlined dummy implementations for cases when the real implementation was not configured in. All of the drivers who issue the call to these functions do SELECT the real implementation from the Kconfig. There should be no cases where the real implementation was not selected by the drivers using these functions - such a situation is likely to be an error which deserves to be noticed at compile-time. These dummies could in theory be used for compile-testing the drivers only (without the generic rohm regulator pieces). However, for such compile testing we should manually drop the selection from KConfig - and I guess that if it does not work out-of-the-box, then it is not going to happen. Especially when there should be no reason to omit compile-testing the generic rohm_regulator part. Crash test dummies. Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/YZ3UXXrk/Efe7Scj@fedora Signed-off-by: Mark Brown --- include/linux/mfd/rohm-generic.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/include/linux/mfd/rohm-generic.h b/include/linux/mfd/rohm-generic.h index 080d60adcd5f5..5ed97a1d0908d 100644 --- a/include/linux/mfd/rohm-generic.h +++ b/include/linux/mfd/rohm-generic.h @@ -82,20 +82,6 @@ int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs, int rohm_regulator_set_voltage_sel_restricted(struct regulator_dev *rdev, unsigned int sel); -#else -static inline int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs, - struct device_node *np, - const struct regulator_desc *desc, - struct regmap *regmap) -{ - return 0; -} - -static inline int rohm_regulator_set_voltage_sel_restricted(struct regulator_dev *rdev, - unsigned int sel) -{ - return 0; -} #endif #endif -- GitLab From fffc84fd87d963a2ea77a125b8a6f5a3c9f3192d Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 9 Nov 2021 23:59:20 +0100 Subject: [PATCH 0147/1112] spi: spidev: Make probe to fail early if a spidev compatible is used Some Device Trees don't use a real device name in the compatible string for SPI devices nodes, abusing the fact that the spidev driver name is used to match as a fallback when a SPI device ID table is not defined. But since commit 6840615f85f6 ("spi: spidev: Add SPI ID table") a table for SPI device IDs was added to the driver breaking the assumption that these DTs were relying on. There has been a warning message for some time since commit 956b200a846e ("spi: spidev: Warn loudly if instantiated from DT as "spidev""), making quite clear that this case is not really supported by the spidev driver. Since these devices won't match anyways after the mentioned commit, there is no point to continue if an spidev compatible is used. Let's just make the driver probe to fail early. Signed-off-by: Javier Martinez Canillas Link: https://lore.kernel.org/r/20211109225920.1158920-1-javierm@redhat.com Signed-off-by: Mark Brown --- drivers/spi/spidev.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 968dab2f5e3de..a5cceca8b82b6 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -751,9 +751,10 @@ static int spidev_probe(struct spi_device *spi) * compatible string, it is a Linux implementation thing * rather than a description of the hardware. */ - WARN(spi->dev.of_node && - of_device_is_compatible(spi->dev.of_node, "spidev"), - "%pOF: buggy DT: spidev listed directly in DT\n", spi->dev.of_node); + if (spi->dev.of_node && of_device_is_compatible(spi->dev.of_node, "spidev")) { + dev_err(&spi->dev, "spidev listed directly in DT is not supported\n"); + return -EINVAL; + } spidev_probe_acpi(spi); -- GitLab From b79332ef9d61513d0ccda74a5161bb7c31851e9c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 23 Nov 2021 19:00:32 +0200 Subject: [PATCH 0148/1112] spi: Fix condition in the __spi_register_driver() The recent commit 3f07657506df ("spi: deduplicate spi_match_id() in __spi_register_driver()") inadvertently inverted a condition that provokes a (harmless) warning: WARNING KERN SPI driver mtd_dataflash has no spi_device_id for atmel,at45 Restore logic to avoid such warning to be issued. Fixes: 3f07657506df ("spi: deduplicate spi_match_id() in __spi_register_driver()") Reported-by: Jon Hunter Signed-off-by: Andy Shevchenko Tested-by: Jon Hunter Link: https://lore.kernel.org/r/20211123170034.41253-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 5bf680fcb1709..8726309b3eaf2 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -474,7 +474,7 @@ int __spi_register_driver(struct module *owner, struct spi_driver *sdrv) const struct spi_device_id *spi_id; spi_id = spi_match_id(sdrv->id_table, of_name); - if (!spi_id) + if (spi_id) continue; } else { if (strcmp(sdrv->driver.name, of_name) == 0) -- GitLab From 3f2bedabb62c6210df63b604dc988d2f7f56f947 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 26 Oct 2021 12:03:47 +0200 Subject: [PATCH 0149/1112] futex: Ensure futex_atomic_cmpxchg_inatomic() is present The boot-time detection of futex_atomic_cmpxchg_inatomic() has a bug on some 32-bit arm builds, and Thomas Gleixner suggested that setting CONFIG_HAVE_FUTEX_CMPXCHG would avoid the problem, as it is always present anyway. Looking into which other architectures could do the same showed that almost all architectures have it, the exceptions being: - some old 32-bit MIPS uniprocessor cores without ll/sc - one xtensa variant with no SMP - 32-bit SPARC when built for SMP Fix MIPS And Xtensa by rearranging the generic code to let it be used as a fallback. For SPARC, the SMP definition just ends up turning off futex anyway, so this can be done at Kconfig time instead. Note that sparc32 glibc requires the CASA instruction for its mutexes anyway, which is only available when running on SPARCv9 or LEON CPUs, but needs to be implemented in the sparc32 kernel for those. Signed-off-by: Arnd Bergmann Signed-off-by: Thomas Gleixner Acked-by: Max Filippov Acked-by: Geert Uytterhoeven Acked-by: Rich Felker Link: https://lore.kernel.org/r/20211026100432.1730393-1-arnd@kernel.org --- arch/mips/include/asm/futex.h | 29 ++++++++++++++++++----------- arch/xtensa/include/asm/futex.h | 8 ++++++-- include/asm-generic/futex.h | 31 +++++++++++-------------------- init/Kconfig | 1 + 4 files changed, 36 insertions(+), 33 deletions(-) diff --git a/arch/mips/include/asm/futex.h b/arch/mips/include/asm/futex.h index d85248404c52c..9287110cb06d9 100644 --- a/arch/mips/include/asm/futex.h +++ b/arch/mips/include/asm/futex.h @@ -19,7 +19,11 @@ #include #include -#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ +#define arch_futex_atomic_op_inuser arch_futex_atomic_op_inuser +#define futex_atomic_cmpxchg_inatomic futex_atomic_cmpxchg_inatomic +#include + +#define __futex_atomic_op(op, insn, ret, oldval, uaddr, oparg) \ { \ if (cpu_has_llsc && IS_ENABLED(CONFIG_WAR_R10000_LLSC)) { \ __asm__ __volatile__( \ @@ -80,9 +84,11 @@ : "0" (0), GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oparg), \ "i" (-EFAULT) \ : "memory"); \ - } else \ - ret = -ENOSYS; \ -} + } else { \ + /* fallback for non-SMP */ \ + ret = arch_futex_atomic_op_inuser_local(op, oparg, oval,\ + uaddr); \ + } static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) @@ -94,23 +100,23 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) switch (op) { case FUTEX_OP_SET: - __futex_atomic_op("move $1, %z5", ret, oldval, uaddr, oparg); + __futex_atomic_op(op, "move $1, %z5", ret, oldval, uaddr, oparg); break; case FUTEX_OP_ADD: - __futex_atomic_op("addu $1, %1, %z5", + __futex_atomic_op(op, "addu $1, %1, %z5", ret, oldval, uaddr, oparg); break; case FUTEX_OP_OR: - __futex_atomic_op("or $1, %1, %z5", + __futex_atomic_op(op, "or $1, %1, %z5", ret, oldval, uaddr, oparg); break; case FUTEX_OP_ANDN: - __futex_atomic_op("and $1, %1, %z5", + __futex_atomic_op(op, "and $1, %1, %z5", ret, oldval, uaddr, ~oparg); break; case FUTEX_OP_XOR: - __futex_atomic_op("xor $1, %1, %z5", + __futex_atomic_op(op, "xor $1, %1, %z5", ret, oldval, uaddr, oparg); break; default: @@ -193,8 +199,9 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, : GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT) : "memory"); - } else - return -ENOSYS; + } else { + return futex_atomic_cmpxchg_inatomic_local(uval, uaddr, oldval, newval); + } *uval = val; return ret; diff --git a/arch/xtensa/include/asm/futex.h b/arch/xtensa/include/asm/futex.h index a1a27b2ea4608..fe8f31575ab17 100644 --- a/arch/xtensa/include/asm/futex.h +++ b/arch/xtensa/include/asm/futex.h @@ -16,6 +16,10 @@ #include #include +#define arch_futex_atomic_op_inuser arch_futex_atomic_op_inuser +#define futex_atomic_cmpxchg_inatomic futex_atomic_cmpxchg_inatomic +#include + #if XCHAL_HAVE_EXCLUSIVE #define __futex_atomic_op(insn, ret, old, uaddr, arg) \ __asm__ __volatile( \ @@ -105,7 +109,7 @@ static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, return ret; #else - return -ENOSYS; + return arch_futex_atomic_op_inuser_local(op, oparg, oval, uaddr); #endif } @@ -156,7 +160,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, return ret; #else - return -ENOSYS; + return futex_atomic_cmpxchg_inatomic_local(uval, uaddr, oldval, newval); #endif } diff --git a/include/asm-generic/futex.h b/include/asm-generic/futex.h index f4c3470480c73..30e7fa63b5dfe 100644 --- a/include/asm-generic/futex.h +++ b/include/asm-generic/futex.h @@ -6,15 +6,22 @@ #include #include +#ifndef futex_atomic_cmpxchg_inatomic #ifndef CONFIG_SMP /* * The following implementation only for uniprocessor machines. * It relies on preempt_disable() ensuring mutual exclusion. * */ +#define futex_atomic_cmpxchg_inatomic(uval, uaddr, oldval, newval) \ + futex_atomic_cmpxchg_inatomic_local_generic(uval, uaddr, oldval, newval) +#define arch_futex_atomic_op_inuser(op, oparg, oval, uaddr) \ + arch_futex_atomic_op_inuser_local_generic(op, oparg, oval, uaddr) +#endif /* CONFIG_SMP */ +#endif /** - * arch_futex_atomic_op_inuser() - Atomic arithmetic operation with constant + * arch_futex_atomic_op_inuser_local() - Atomic arithmetic operation with constant * argument and comparison of the previous * futex value with another constant. * @@ -28,7 +35,7 @@ * -ENOSYS - Operation not supported */ static inline int -arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr) +futex_atomic_op_inuser_local(int op, u32 oparg, int *oval, u32 __user *uaddr) { int oldval, ret; u32 tmp; @@ -75,7 +82,7 @@ out_pagefault_enable: } /** - * futex_atomic_cmpxchg_inatomic() - Compare and exchange the content of the + * futex_atomic_cmpxchg_inatomic_local() - Compare and exchange the content of the * uaddr with newval if the current value is * oldval. * @uval: pointer to store content of @uaddr @@ -87,10 +94,9 @@ out_pagefault_enable: * 0 - On success * -EFAULT - User access resulted in a page fault * -EAGAIN - Atomic operation was unable to complete due to contention - * -ENOSYS - Function not implemented (only if !HAVE_FUTEX_CMPXCHG) */ static inline int -futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, +futex_atomic_cmpxchg_inatomic_local(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval) { u32 val; @@ -112,19 +118,4 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, return 0; } -#else -static inline int -arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr) -{ - return -ENOSYS; -} - -static inline int -futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, - u32 oldval, u32 newval) -{ - return -ENOSYS; -} - -#endif /* CONFIG_SMP */ #endif diff --git a/init/Kconfig b/init/Kconfig index 036b750e8d8a8..3f5aa5063f555 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1579,6 +1579,7 @@ config BASE_FULL config FUTEX bool "Enable futex support" if EXPERT + depends on !(SPARC32 && SMP) default y imply RT_MUTEXES help -- GitLab From 3297481d688a5cc2973ea58bd78e66b8639748b1 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 26 Oct 2021 12:03:48 +0200 Subject: [PATCH 0150/1112] futex: Remove futex_cmpxchg detection Now that all architectures have a working futex implementation in any configuration, remove the runtime detection code. Signed-off-by: Arnd Bergmann Signed-off-by: Thomas Gleixner Reviewed-by: Russell King (Oracle) Acked-by: Vineet Gupta Acked-by: Max Filippov Acked-by: Christian Borntraeger Link: https://lore.kernel.org/r/20211026100432.1730393-2-arnd@kernel.org --- arch/arc/Kconfig | 1 - arch/arm/Kconfig | 1 - arch/arm64/Kconfig | 1 - arch/csky/Kconfig | 1 - arch/m68k/Kconfig | 1 - arch/riscv/Kconfig | 1 - arch/s390/Kconfig | 1 - arch/sh/Kconfig | 1 - arch/um/Kconfig | 1 - arch/um/kernel/skas/uaccess.c | 1 - arch/xtensa/Kconfig | 1 - init/Kconfig | 8 -------- kernel/futex/core.c | 35 ----------------------------------- kernel/futex/futex.h | 6 ------ kernel/futex/syscalls.c | 22 ---------------------- 15 files changed, 82 deletions(-) diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index b4ae6058902af..f74d9860a4420 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -32,7 +32,6 @@ config ARC select HAVE_ARCH_TRANSPARENT_HUGEPAGE if ARC_MMU_V4 select HAVE_DEBUG_STACKOVERFLOW select HAVE_DEBUG_KMEMLEAK - select HAVE_FUTEX_CMPXCHG if FUTEX select HAVE_IOREMAP_PROT select HAVE_KERNEL_GZIP select HAVE_KERNEL_LZMA diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index f0f9e8bec83ac..2948487346dc9 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -92,7 +92,6 @@ config ARM select HAVE_FTRACE_MCOUNT_RECORD if !XIP_KERNEL select HAVE_FUNCTION_GRAPH_TRACER if !THUMB2_KERNEL && !CC_IS_CLANG select HAVE_FUNCTION_TRACER if !XIP_KERNEL && !(THUMB2_KERNEL && CC_IS_CLANG) - select HAVE_FUTEX_CMPXCHG if FUTEX select HAVE_GCC_PLUGINS select HAVE_HW_BREAKPOINT if PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7) select HAVE_IRQ_TIME_ACCOUNTING diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index c4207cf9bb17f..5e2dfef78956a 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -194,7 +194,6 @@ config ARM64 select HAVE_REGS_AND_STACK_ACCESS_API select HAVE_POSIX_CPU_TIMERS_TASK_WORK select HAVE_FUNCTION_ARG_ACCESS_API - select HAVE_FUTEX_CMPXCHG if FUTEX select MMU_GATHER_RCU_TABLE_FREE select HAVE_RSEQ select HAVE_STACKPROTECTOR diff --git a/arch/csky/Kconfig b/arch/csky/Kconfig index aed2b3e734ee0..132f43f12dd85 100644 --- a/arch/csky/Kconfig +++ b/arch/csky/Kconfig @@ -52,7 +52,6 @@ config CSKY select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FUNCTION_ERROR_INJECTION - select HAVE_FUTEX_CMPXCHG if FUTEX && SMP select HAVE_FTRACE_MCOUNT_RECORD select HAVE_KERNEL_GZIP select HAVE_KERNEL_LZO diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index 0b50da08a9c56..15a793c5b2dc4 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig @@ -20,7 +20,6 @@ config M68K select HAVE_ASM_MODVERSIONS select HAVE_DEBUG_BUGVERBOSE select HAVE_EFFICIENT_UNALIGNED_ACCESS if !CPU_HAS_NO_UNALIGNED - select HAVE_FUTEX_CMPXCHG if MMU && FUTEX select HAVE_MOD_ARCH_SPECIFIC select HAVE_UID16 select MMU_GATHER_NO_RANGE if MMU diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 821252b65f890..09abf62ae0ad4 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -83,7 +83,6 @@ config RISCV select HAVE_DMA_CONTIGUOUS if MMU select HAVE_EBPF_JIT if MMU select HAVE_FUNCTION_ERROR_INJECTION - select HAVE_FUTEX_CMPXCHG if FUTEX select HAVE_GCC_PLUGINS select HAVE_GENERIC_VDSO if MMU && 64BIT select HAVE_IRQ_TIME_ACCOUNTING diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 8857ec3b97eb8..f614562d74f05 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -165,7 +165,6 @@ config S390 select HAVE_FUNCTION_ERROR_INJECTION select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FUNCTION_TRACER - select HAVE_FUTEX_CMPXCHG if FUTEX select HAVE_GCC_PLUGINS select HAVE_GENERIC_VDSO select HAVE_IOREMAP_PROT if PCI diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 70afb30e0b321..2474a04ceac43 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -34,7 +34,6 @@ config SUPERH select HAVE_FAST_GUP if MMU select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FUNCTION_TRACER - select HAVE_FUTEX_CMPXCHG if FUTEX select HAVE_FTRACE_MCOUNT_RECORD select HAVE_HW_BREAKPOINT select HAVE_IOREMAP_PROT if MMU && !X2TLB diff --git a/arch/um/Kconfig b/arch/um/Kconfig index c18b45f75d41f..c906250d49706 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -14,7 +14,6 @@ config UML select HAVE_ARCH_SECCOMP_FILTER select HAVE_ASM_MODVERSIONS select HAVE_UID16 - select HAVE_FUTEX_CMPXCHG if FUTEX select HAVE_DEBUG_KMEMLEAK select HAVE_DEBUG_BUGVERBOSE select NO_DMA if !UML_DMA_EMULATION diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c index a509be9110260..9e37a7c05990d 100644 --- a/arch/um/kernel/skas/uaccess.c +++ b/arch/um/kernel/skas/uaccess.c @@ -348,7 +348,6 @@ EXPORT_SYMBOL(arch_futex_atomic_op_inuser); * 0 - On success * -EFAULT - User access resulted in a page fault * -EAGAIN - Atomic operation was unable to complete due to contention - * -ENOSYS - Function not implemented (only if !HAVE_FUTEX_CMPXCHG) */ int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 0e56bad058fae..8ac599aa6d994 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -31,7 +31,6 @@ config XTENSA select HAVE_DMA_CONTIGUOUS select HAVE_EXIT_THREAD select HAVE_FUNCTION_TRACER - select HAVE_FUTEX_CMPXCHG if !MMU && FUTEX select HAVE_HW_BREAKPOINT if PERF_EVENTS select HAVE_IRQ_TIME_ACCOUNTING select HAVE_PCI diff --git a/init/Kconfig b/init/Kconfig index 3f5aa5063f555..76d89db5657be 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1592,14 +1592,6 @@ config FUTEX_PI depends on FUTEX && RT_MUTEXES default y -config HAVE_FUTEX_CMPXCHG - bool - depends on FUTEX - help - Architectures should select this if futex_atomic_cmpxchg_inatomic() - is implemented and always working. This removes a couple of runtime - checks. - config EPOLL bool "Enable eventpoll support" if EXPERT default y diff --git a/kernel/futex/core.c b/kernel/futex/core.c index 25d8a88b32e5b..926c2bb752bc8 100644 --- a/kernel/futex/core.c +++ b/kernel/futex/core.c @@ -41,11 +41,6 @@ #include "futex.h" #include "../locking/rtmutex_common.h" -#ifndef CONFIG_HAVE_FUTEX_CMPXCHG -int __read_mostly futex_cmpxchg_enabled; -#endif - - /* * The base of the bucket array and its size are always used together * (after initialization only in futex_hash()), so ensure that they @@ -776,9 +771,6 @@ static void exit_robust_list(struct task_struct *curr) unsigned long futex_offset; int rc; - if (!futex_cmpxchg_enabled) - return; - /* * Fetch the list head (which was registered earlier, via * sys_set_robust_list()): @@ -874,9 +866,6 @@ static void compat_exit_robust_list(struct task_struct *curr) compat_long_t futex_offset; int rc; - if (!futex_cmpxchg_enabled) - return; - /* * Fetch the list head (which was registered earlier, via * sys_set_robust_list()): @@ -950,8 +939,6 @@ static void exit_pi_state_list(struct task_struct *curr) struct futex_hash_bucket *hb; union futex_key key = FUTEX_KEY_INIT; - if (!futex_cmpxchg_enabled) - return; /* * We are a ZOMBIE and nobody can enqueue itself on * pi_state_list anymore, but we have to be careful @@ -1125,26 +1112,6 @@ void futex_exit_release(struct task_struct *tsk) futex_cleanup_end(tsk, FUTEX_STATE_DEAD); } -static void __init futex_detect_cmpxchg(void) -{ -#ifndef CONFIG_HAVE_FUTEX_CMPXCHG - u32 curval; - - /* - * This will fail and we want it. Some arch implementations do - * runtime detection of the futex_atomic_cmpxchg_inatomic() - * functionality. We want to know that before we call in any - * of the complex code paths. Also we want to prevent - * registration of robust lists in that case. NULL is - * guaranteed to fault and we get -EFAULT on functional - * implementation, the non-functional ones will return - * -ENOSYS. - */ - if (futex_cmpxchg_value_locked(&curval, NULL, 0, 0) == -EFAULT) - futex_cmpxchg_enabled = 1; -#endif -} - static int __init futex_init(void) { unsigned int futex_shift; @@ -1163,8 +1130,6 @@ static int __init futex_init(void) futex_hashsize, futex_hashsize); futex_hashsize = 1UL << futex_shift; - futex_detect_cmpxchg(); - for (i = 0; i < futex_hashsize; i++) { atomic_set(&futex_queues[i].waiters, 0); plist_head_init(&futex_queues[i].chain); diff --git a/kernel/futex/futex.h b/kernel/futex/futex.h index 040ae4277cb0c..c264cbeab71c6 100644 --- a/kernel/futex/futex.h +++ b/kernel/futex/futex.h @@ -27,12 +27,6 @@ #define FLAGS_CLOCKRT 0x02 #define FLAGS_HAS_TIMEOUT 0x04 -#ifdef CONFIG_HAVE_FUTEX_CMPXCHG -#define futex_cmpxchg_enabled 1 -#else -extern int __read_mostly futex_cmpxchg_enabled; -#endif - #ifdef CONFIG_FAIL_FUTEX extern bool should_fail_futex(bool fshared); #else diff --git a/kernel/futex/syscalls.c b/kernel/futex/syscalls.c index 6f91a07a6a836..086a22d1adb78 100644 --- a/kernel/futex/syscalls.c +++ b/kernel/futex/syscalls.c @@ -29,8 +29,6 @@ SYSCALL_DEFINE2(set_robust_list, struct robust_list_head __user *, head, size_t, len) { - if (!futex_cmpxchg_enabled) - return -ENOSYS; /* * The kernel knows only one size for now: */ @@ -56,9 +54,6 @@ SYSCALL_DEFINE3(get_robust_list, int, pid, unsigned long ret; struct task_struct *p; - if (!futex_cmpxchg_enabled) - return -ENOSYS; - rcu_read_lock(); ret = -ESRCH; @@ -103,17 +98,6 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout, return -ENOSYS; } - switch (cmd) { - case FUTEX_LOCK_PI: - case FUTEX_LOCK_PI2: - case FUTEX_UNLOCK_PI: - case FUTEX_TRYLOCK_PI: - case FUTEX_WAIT_REQUEUE_PI: - case FUTEX_CMP_REQUEUE_PI: - if (!futex_cmpxchg_enabled) - return -ENOSYS; - } - switch (cmd) { case FUTEX_WAIT: val3 = FUTEX_BITSET_MATCH_ANY; @@ -323,9 +307,6 @@ COMPAT_SYSCALL_DEFINE2(set_robust_list, struct compat_robust_list_head __user *, head, compat_size_t, len) { - if (!futex_cmpxchg_enabled) - return -ENOSYS; - if (unlikely(len != sizeof(*head))) return -EINVAL; @@ -342,9 +323,6 @@ COMPAT_SYSCALL_DEFINE3(get_robust_list, int, pid, unsigned long ret; struct task_struct *p; - if (!futex_cmpxchg_enabled) - return -ENOSYS; - rcu_read_lock(); ret = -ESRCH; -- GitLab From c74526f947ab946273939757c72499c0a5b09826 Mon Sep 17 00:00:00 2001 From: Kamal Dasu Date: Wed, 24 Nov 2021 14:33:52 -0500 Subject: [PATCH 0151/1112] spi: bcm-qspi: choose sysclk setting based on requested speed Check requested speed for a given transfer before setting 27MHz or 108Mhz sysclk on SoCs that support both. This way for baud rates below 212Khz we can use 27Mhz clock. Signed-off-by: Kamal Dasu Link: https://lore.kernel.org/r/20211124193353.32311-2-kdasu.kdev@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-bcm-qspi.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c index f3de3305d0f59..38e6e2cb62cad 100644 --- a/drivers/spi/spi-bcm-qspi.c +++ b/drivers/spi/spi-bcm-qspi.c @@ -287,6 +287,18 @@ static inline int bcm_qspi_spbr_min(struct bcm_qspi *qspi) return 8; } +static u32 bcm_qspi_calc_spbr(u32 clk_speed_hz, + const struct bcm_qspi_parms *xp) +{ + u32 spbr = 0; + + /* SPBR = System Clock/(2 * SCK Baud Rate) */ + if (xp->speed_hz) + spbr = clk_speed_hz / (xp->speed_hz * 2); + + return spbr; +} + /* Read qspi controller register*/ static inline u32 bcm_qspi_read(struct bcm_qspi *qspi, enum base_type type, unsigned int offset) @@ -621,9 +633,17 @@ static void bcm_qspi_hw_set_parms(struct bcm_qspi *qspi, spcr |= MSPI_SPCR3_HALFDUPLEX | MSPI_SPCR3_HDOUTTYPE; if (bcm_qspi_has_sysclk_108(qspi)) { - /* SYSCLK_108 */ - spcr |= MSPI_SPCR3_SYSCLKSEL_108; - qspi->base_clk = MSPI_BASE_FREQ * 4; + /* check requested baud rate before moving to 108Mhz */ + spbr = bcm_qspi_calc_spbr(MSPI_BASE_FREQ * 4, xp); + if (spbr > QSPI_SPBR_MAX) { + /* use SYSCLK_27Mhz for slower baud rates */ + spcr &= ~MSPI_SPCR3_SYSCLKSEL_MASK; + qspi->base_clk = MSPI_BASE_FREQ; + } else { + /* SYSCLK_108Mhz */ + spcr |= MSPI_SPCR3_SYSCLKSEL_108; + qspi->base_clk = MSPI_BASE_FREQ * 4; + } } if (xp->bits_per_word > 16) { @@ -649,9 +669,9 @@ static void bcm_qspi_hw_set_parms(struct bcm_qspi *qspi, bcm_qspi_write(qspi, MSPI, MSPI_SPCR3, spcr); } - if (xp->speed_hz) - spbr = qspi->base_clk / (2 * xp->speed_hz); - + /* SCK Baud Rate = System Clock/(2 * SPBR) */ + qspi->max_speed_hz = qspi->base_clk / (bcm_qspi_spbr_min(qspi) * 2); + spbr = bcm_qspi_calc_spbr(qspi->base_clk, xp); spbr = clamp_val(spbr, bcm_qspi_spbr_min(qspi), QSPI_SPBR_MAX); bcm_qspi_write(qspi, MSPI, MSPI_SPCR0_LSB, spbr); -- GitLab From e10a6bb5f52de70c7798b720d16632d4042d2552 Mon Sep 17 00:00:00 2001 From: Kamal Dasu Date: Wed, 24 Nov 2021 14:33:53 -0500 Subject: [PATCH 0152/1112] spi: bcm-qspi: set transfer parameter only if they change Check if the transfer parameters have changed from previous settings before applying new parameters. Signed-off-by: Kamal Dasu Link: https://lore.kernel.org/r/20211124193353.32311-3-kdasu.kdev@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-bcm-qspi.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c index 38e6e2cb62cad..c9a769b8594b7 100644 --- a/drivers/spi/spi-bcm-qspi.c +++ b/drivers/spi/spi-bcm-qspi.c @@ -598,12 +598,24 @@ static void bcm_qspi_chip_select(struct bcm_qspi *qspi, int cs) qspi->curr_cs = cs; } +static bool bcmspi_parms_did_change(const struct bcm_qspi_parms * const cur, + const struct bcm_qspi_parms * const prev) +{ + return (cur->speed_hz != prev->speed_hz) || + (cur->mode != prev->mode) || + (cur->bits_per_word != prev->bits_per_word); +} + + /* MSPI helpers */ static void bcm_qspi_hw_set_parms(struct bcm_qspi *qspi, const struct bcm_qspi_parms *xp) { u32 spcr, spbr = 0; + if (!bcmspi_parms_did_change(xp, &qspi->last_parms)) + return; + if (!qspi->mspi_maj_rev) /* legacy controller */ spcr = MSPI_MASTER_BIT; -- GitLab From c7e1c782f2432cd4dc6c6ea930d99d93997a0edb Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 21 Nov 2021 20:11:24 +0100 Subject: [PATCH 0153/1112] platform/x86: thinkpad_acpi: Make *_init() functions return -ENODEV instead of 1 Make ibm_init_struct.init() callbacks return -ENODEV instead of 1 when the subdevice / function is not available. Using -ENODEV clearly states what it going on where as a magic return of "1" requires a deep dive into the code to figure out what is going on. This also allows for some cleanups, avoiding the need to translate an -ENODEV return into "return 1" (which often mistakenly was "return 0"). Reviewed-by: Andy Shevchenko Tested-by: Mark Pearson Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20211121191129.256713-3-hdegoede@redhat.com --- drivers/platform/x86/thinkpad_acpi.c | 85 +++++++++++----------------- 1 file changed, 34 insertions(+), 51 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 9e296b436bea3..c5613399453ae 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -3377,7 +3377,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) str_supported(tp_features.hotkey)); if (!tp_features.hotkey) - return 1; + return -ENODEV; quirks = tpacpi_check_quirks(tpacpi_hotkey_qtable, ARRAY_SIZE(tpacpi_hotkey_qtable)); @@ -3584,7 +3584,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) return 0; err_exit: - return (res < 0) ? res : 1; + return (res < 0) ? res : -ENODEV; } /* Thinkpad X1 Carbon support 5 modes including Home mode, Web browser @@ -4451,7 +4451,7 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) } if (!tp_features.bluetooth) - return 1; + return -ENODEV; res = tpacpi_new_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID, &bluetooth_tprfk_ops, @@ -4631,7 +4631,7 @@ static int __init wan_init(struct ibm_init_struct *iibm) } if (!tp_features.wan) - return 1; + return -ENODEV; res = tpacpi_new_rfkill(TPACPI_RFK_WWAN_SW_ID, &wan_tprfk_ops, @@ -4760,7 +4760,7 @@ static int __init uwb_init(struct ibm_init_struct *iibm) } if (!tp_features.uwb) - return 1; + return -ENODEV; res = tpacpi_new_rfkill(TPACPI_RFK_UWB_SW_ID, &uwb_tprfk_ops, @@ -4853,7 +4853,7 @@ static int __init video_init(struct ibm_init_struct *iibm) str_supported(video_supported != TPACPI_VIDEO_NONE), video_supported); - return (video_supported != TPACPI_VIDEO_NONE) ? 0 : 1; + return (video_supported != TPACPI_VIDEO_NONE) ? 0 : -ENODEV; } static void video_exit(void) @@ -5261,7 +5261,7 @@ static int __init kbdlight_init(struct ibm_init_struct *iibm) if (!kbdlight_is_supported()) { tp_features.kbdlight = 0; vdbg_printk(TPACPI_DBG_INIT, "kbdlight is unsupported\n"); - return 1; + return -ENODEV; } kbdlight_brightness = kbdlight_sysfs_get(NULL); @@ -5451,7 +5451,7 @@ static int __init light_init(struct ibm_init_struct *iibm) str_supported(tp_features.light_status)); if (!tp_features.light) - return 1; + return -ENODEV; rc = led_classdev_register(&tpacpi_pdev->dev, &tpacpi_led_thinklight.led_classdev); @@ -5567,7 +5567,7 @@ static int __init cmos_init(struct ibm_init_struct *iibm) vdbg_printk(TPACPI_DBG_INIT, "cmos commands are %s\n", str_supported(cmos_handle != NULL)); - return cmos_handle ? 0 : 1; + return cmos_handle ? 0 : -ENODEV; } static int cmos_read(struct seq_file *m) @@ -5912,7 +5912,7 @@ static int __init led_init(struct ibm_init_struct *iibm) str_supported(led_supported), led_supported); if (led_supported == TPACPI_LED_NONE) - return 1; + return -ENODEV; tpacpi_leds = kcalloc(TPACPI_LED_NUMLEDS, sizeof(*tpacpi_leds), GFP_KERNEL); @@ -6041,7 +6041,7 @@ static int __init beep_init(struct ibm_init_struct *iibm) tp_features.beep_needs_two_args = !!(quirks & TPACPI_BEEP_Q1); - return (beep_handle) ? 0 : 1; + return (beep_handle) ? 0 : -ENODEV; } static int beep_read(struct seq_file *m) @@ -6425,7 +6425,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm) str_supported(thermal_read_mode != TPACPI_THERMAL_NONE), thermal_read_mode); - return thermal_read_mode == TPACPI_THERMAL_NONE ? 1 : 0; + return thermal_read_mode != TPACPI_THERMAL_NONE ? 0 : -ENODEV; } static int thermal_read(struct seq_file *m) @@ -6836,25 +6836,25 @@ static int __init brightness_init(struct ibm_init_struct *iibm) /* if it is unknown, we don't handle it: it wouldn't be safe */ if (tp_features.bright_unkfw) - return 1; + return -ENODEV; if (!brightness_enable) { dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT, "brightness support disabled by module parameter\n"); - return 1; + return -ENODEV; } if (acpi_video_get_backlight_type() != acpi_backlight_vendor) { if (brightness_enable > 1) { pr_info("Standard ACPI backlight interface available, not loading native one\n"); - return 1; + return -ENODEV; } else if (brightness_enable == 1) { pr_warn("Cannot enable backlight brightness support, ACPI is already handling it. Refer to the acpi_backlight kernel parameter.\n"); - return 1; + return -ENODEV; } } else if (!tp_features.bright_acpimode) { pr_notice("ACPI backlight interface not available\n"); - return 1; + return -ENODEV; } pr_notice("ACPI native brightness control enabled\n"); @@ -6887,7 +6887,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm) return -EINVAL; if (tpacpi_brightness_get_raw(&b) < 0) - return 1; + return -ENODEV; memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_PLATFORM; @@ -7477,7 +7477,7 @@ static int __init volume_create_alsa_mixer(void) sizeof(struct tpacpi_alsa_data), &card); if (rc < 0 || !card) { pr_err("Failed to create ALSA card structures: %d\n", rc); - return 1; + return -ENODEV; } BUG_ON(!card->private_data); @@ -7536,7 +7536,7 @@ static int __init volume_create_alsa_mixer(void) err_exit: snd_card_free(card); - return 1; + return -ENODEV; } #define TPACPI_VOL_Q_MUTEONLY 0x0001 /* Mute-only control available */ @@ -7585,7 +7585,7 @@ static int __init volume_init(struct ibm_init_struct *iibm) if (volume_mode == TPACPI_VOL_MODE_UCMS_STEP) { pr_err("UCMS step volume mode not implemented, please contact %s\n", TPACPI_MAIL); - return 1; + return -ENODEV; } if (volume_capabilities >= TPACPI_VOL_CAP_MAX) @@ -7598,7 +7598,7 @@ static int __init volume_init(struct ibm_init_struct *iibm) if (!alsa_enable) { vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER, "ALSA mixer disabled by parameter, not loading volume subdriver...\n"); - return 1; + return -ENODEV; } quirks = tpacpi_check_quirks(volume_quirk_table, @@ -7611,7 +7611,7 @@ static int __init volume_init(struct ibm_init_struct *iibm) else if (quirks & TPACPI_VOL_Q_LEVEL) tp_features.mixer_no_level_control = 0; else - return 1; /* no mixer */ + return -ENODEV; /* no mixer */ break; case TPACPI_VOL_CAP_VOLMUTE: tp_features.mixer_no_level_control = 0; @@ -7620,7 +7620,7 @@ static int __init volume_init(struct ibm_init_struct *iibm) tp_features.mixer_no_level_control = 1; break; default: - return 1; + return -ENODEV; } if (volume_capabilities != TPACPI_VOL_CAP_AUTO) @@ -7792,7 +7792,7 @@ static int __init volume_init(struct ibm_init_struct *iibm) { pr_info("volume: disabled as there is no ALSA support in this kernel\n"); - return 1; + return -ENODEV; } static struct ibm_struct volume_driver_data = { @@ -8729,7 +8729,7 @@ static int __init fan_init(struct ibm_init_struct *iibm) } } else { pr_err("ThinkPad ACPI EC access misbehaving, fan status and control unavailable\n"); - return 1; + return -ENODEV; } } @@ -8778,11 +8778,11 @@ static int __init fan_init(struct ibm_init_struct *iibm) if (fan_status_access_mode != TPACPI_FAN_NONE) fan_get_status_safe(NULL); - if (fan_status_access_mode != TPACPI_FAN_NONE || - fan_control_access_mode != TPACPI_FAN_WR_NONE) - return 0; + if (fan_status_access_mode == TPACPI_FAN_NONE && + fan_control_access_mode == TPACPI_FAN_WR_NONE) + return -ENODEV; - return 1; + return 0; } static void fan_exit(void) @@ -9886,12 +9886,9 @@ static int tpacpi_proxsensor_init(struct ibm_init_struct *iibm) palm_err = palmsensor_get(&has_palmsensor, &palm_state); lap_err = lapsensor_get(&has_lapsensor, &lap_state); - /* - * If support isn't available (ENODEV) for both devices then quit, but - * don't return an error. - */ + /* If support isn't available for both devices return -ENODEV */ if ((palm_err == -ENODEV) && (lap_err == -ENODEV)) - return 0; + return -ENODEV; /* Otherwise, if there was an error return it */ if (palm_err && (palm_err != -ENODEV)) return palm_err; @@ -10127,13 +10124,6 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm) dytc_profile_available = false; err = dytc_command(DYTC_CMD_QUERY, &output); - /* - * If support isn't available (ENODEV) then don't return an error - * and don't create the sysfs group - */ - if (err == -ENODEV) - return 0; - /* For all other errors we can flag the failure */ if (err) return err; @@ -10436,16 +10426,9 @@ static const struct attribute_group dprc_attr_group = { static int tpacpi_dprc_init(struct ibm_init_struct *iibm) { - int err = get_wwan_antenna(&wwan_antennatype); - - /* - * If support isn't available (ENODEV) then quit, but don't - * return an error. - */ - if (err == -ENODEV) - return 0; + int err; - /* If there was an error return it */ + err = get_wwan_antenna(&wwan_antennatype); if (err) return err; -- GitLab From 5a47ac0041678d3d610b3ac724bca8c4bda2ddff Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 21 Nov 2021 20:11:25 +0100 Subject: [PATCH 0154/1112] platform/x86: thinkpad_acpi: Simplify dytc_version handling The only reason the proxysensor code needs dytc_version handling is for proxsensor_attr_is_visible() and that will only ever get called after all the subdrv init() callbacks have run. tpacpi_dytc_profile_init() already calls DYTC_CMD_QUERY and is the primary consumer of dytc_version, so simply let tpacpi_dytc_profile_init() set dytc_version and remove the now no longer necessary dytc_get_version() helper and its calls. Reviewed-by: Andy Shevchenko Tested-by: Mark Pearson Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20211121191129.256713-4-hdegoede@redhat.com --- drivers/platform/x86/thinkpad_acpi.c | 47 +++------------------------- 1 file changed, 5 insertions(+), 42 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index c5613399453ae..724a0e966c58b 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -9742,33 +9742,6 @@ static int dytc_command(int command, int *output) return 0; } -static int dytc_get_version(void) -{ - int err, output; - - /* Check if we've been called before - and just return cached value */ - if (dytc_version) - return dytc_version; - - /* Otherwise query DYTC and extract version information */ - err = dytc_command(DYTC_CMD_QUERY, &output); - /* - * If support isn't available (ENODEV) then don't return an error - * and don't create the sysfs group - */ - if (err == -ENODEV) - return 0; - /* For all other errors we can flag the failure */ - if (err) - return err; - - /* Check DYTC is enabled and supports mode setting */ - if (output & BIT(DYTC_QUERY_ENABLE_BIT)) - dytc_version = (output >> DYTC_QUERY_REV_BIT) & 0xF; - - return 0; -} - static int lapsensor_get(bool *present, bool *state) { int output, err; @@ -9865,7 +9838,7 @@ static umode_t proxsensor_attr_is_visible(struct kobject *kobj, * Platforms before DYTC version 5 claim to have a lap sensor, * but it doesn't work, so we ignore them. */ - if (!has_lapsensor || dytc_version < 5) + if (!has_lapsensor || dytc_version < 5) return 0; } else if (attr == &dev_attr_palmsensor.attr) { if (!has_palmsensor) @@ -9882,7 +9855,7 @@ static const struct attribute_group proxsensor_attr_group = { static int tpacpi_proxsensor_init(struct ibm_init_struct *iibm) { - int palm_err, lap_err, err; + int palm_err, lap_err; palm_err = palmsensor_get(&has_palmsensor, &palm_state); lap_err = lapsensor_get(&has_lapsensor, &lap_state); @@ -9895,13 +9868,6 @@ static int tpacpi_proxsensor_init(struct ibm_init_struct *iibm) if (lap_err && (lap_err != -ENODEV)) return lap_err; - /* Check if we know the DYTC version, if we don't then get it */ - if (!dytc_version) { - err = dytc_get_version(); - if (err) - return err; - } - return 0; } @@ -10127,12 +10093,9 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm) if (err) return err; - /* Check if we know the DYTC version, if we don't then get it */ - if (!dytc_version) { - err = dytc_get_version(); - if (err) - return err; - } + if (output & BIT(DYTC_QUERY_ENABLE_BIT)) + dytc_version = (output >> DYTC_QUERY_REV_BIT) & 0xF; + /* Check DYTC is enabled and supports mode setting */ if (dytc_version >= 5) { dbg_printk(TPACPI_DBG_INIT, -- GitLab From 0b0d2fba4f3302b601c429c9286e66b3af2d29cb Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 21 Nov 2021 20:11:26 +0100 Subject: [PATCH 0155/1112] platform/x86: thinkpad_acpi: Cleanup dytc_profile_available Remove the dytc_profile_available check from dytc_profile_set(), that function only gets called if the platform_profile_handler was registered, so the check is not necessary. Make tpacpi_dytc_profile_init() return -ENODEV when it does not register the platform_profile() handler this will cause dytc_profile_driver_data.flags.init to not get set, which in turn will cause the dytc_profile_exit() call to get skipped. Together this avoids the need to have the dytc_profile_available variable at all, since the information is now duplicated in the dytc_profile_driver_data.flags.init flag. Note this leaves a weirdly indented code-block behind, this is deliberately done to make what actually changes in this commit clear. This will be fixed-up in the next commit. Reviewed-by: Andy Shevchenko Tested-by: Mark Pearson Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20211121191129.256713-5-hdegoede@redhat.com --- drivers/platform/x86/thinkpad_acpi.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 724a0e966c58b..7b7667b1a6fb9 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -9911,7 +9911,6 @@ static struct ibm_struct proxsensor_driver_data = { #define DYTC_ENABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_BALANCE, 1) -static bool dytc_profile_available; static enum platform_profile_option dytc_current_profile; static atomic_t dytc_ignore_event = ATOMIC_INIT(0); static DEFINE_MUTEX(dytc_mutex); @@ -10015,9 +10014,6 @@ static int dytc_profile_set(struct platform_profile_handler *pprof, int output; int err; - if (!dytc_profile_available) - return -ENODEV; - err = mutex_lock_interruptible(&dytc_mutex); if (err) return err; @@ -10088,7 +10084,6 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm) set_bit(PLATFORM_PROFILE_BALANCED, dytc_profile.choices); set_bit(PLATFORM_PROFILE_PERFORMANCE, dytc_profile.choices); - dytc_profile_available = false; err = dytc_command(DYTC_CMD_QUERY, &output); if (err) return err; @@ -10097,7 +10092,10 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm) dytc_version = (output >> DYTC_QUERY_REV_BIT) & 0xF; /* Check DYTC is enabled and supports mode setting */ - if (dytc_version >= 5) { + if (dytc_version < 5) + return -ENODEV; + + { dbg_printk(TPACPI_DBG_INIT, "DYTC version %d: thermal mode available\n", dytc_version); /* @@ -10117,9 +10115,8 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm) * don't quit terminally. */ if (err) - return 0; + return -ENODEV; - dytc_profile_available = true; /* Ensure initial values are correct */ dytc_profile_refresh(); } @@ -10128,10 +10125,7 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm) static void dytc_profile_exit(void) { - if (dytc_profile_available) { - dytc_profile_available = false; - platform_profile_remove(); - } + platform_profile_remove(); } static struct ibm_struct dytc_profile_driver_data = { -- GitLab From 798682e236893a20e5674de02ede474373dd342d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 21 Nov 2021 20:11:27 +0100 Subject: [PATCH 0156/1112] platform/x86: thinkpad_acpi: Properly indent code in tpacpi_dytc_profile_init() The previous refactoring of some code in tpacpi_dytc_profile_init() left a weirdly indented code-block behind. Remove the unnecessary '{}' and reduce the indent level one step, other then changing the indentation the code is completely unchanged. Reviewed-by: Andy Shevchenko Tested-by: Mark Pearson Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20211121191129.256713-6-hdegoede@redhat.com --- drivers/platform/x86/thinkpad_acpi.c | 47 ++++++++++++++-------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 7b7667b1a6fb9..ca86e6c2b546b 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -10095,31 +10095,30 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm) if (dytc_version < 5) return -ENODEV; - { - dbg_printk(TPACPI_DBG_INIT, - "DYTC version %d: thermal mode available\n", dytc_version); - /* - * Check if MMC_GET functionality available - * Version > 6 and return success from MMC_GET command - */ - dytc_mmc_get_available = false; - if (dytc_version >= 6) { - err = dytc_command(DYTC_CMD_MMC_GET, &output); - if (!err && ((output & DYTC_ERR_MASK) == DYTC_ERR_SUCCESS)) - dytc_mmc_get_available = true; - } - /* Create platform_profile structure and register */ - err = platform_profile_register(&dytc_profile); - /* - * If for some reason platform_profiles aren't enabled - * don't quit terminally. - */ - if (err) - return -ENODEV; - - /* Ensure initial values are correct */ - dytc_profile_refresh(); + dbg_printk(TPACPI_DBG_INIT, + "DYTC version %d: thermal mode available\n", dytc_version); + /* + * Check if MMC_GET functionality available + * Version > 6 and return success from MMC_GET command + */ + dytc_mmc_get_available = false; + if (dytc_version >= 6) { + err = dytc_command(DYTC_CMD_MMC_GET, &output); + if (!err && ((output & DYTC_ERR_MASK) == DYTC_ERR_SUCCESS)) + dytc_mmc_get_available = true; } + /* Create platform_profile structure and register */ + err = platform_profile_register(&dytc_profile); + /* + * If for some reason platform_profiles aren't enabled + * don't quit terminally. + */ + if (err) + return -ENODEV; + + /* Ensure initial values are correct */ + dytc_profile_refresh(); + return 0; } -- GitLab From cb97f5f01d383ff166d50e356d07ac38d6033ac8 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 21 Nov 2021 20:11:28 +0100 Subject: [PATCH 0157/1112] platform/x86: thinkpad_acpi: Remove "goto err_exit" from hotkey_init() The err_exit label just does a: return (res < 0) ? res : -ENODEV; And res is always < 0 when we go there (hotkey_mask_get() returns either 0 or -EIO), so the goto-s can simply be replaced with "return res". Reviewed-by: Andy Shevchenko Tested-by: Mark Pearson Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20211121191129.256713-7-hdegoede@redhat.com --- drivers/platform/x86/thinkpad_acpi.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index ca86e6c2b546b..45b68042e1fbd 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -3464,7 +3464,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) * the first hotkey_mask_get to return hotkey_orig_mask */ res = hotkey_mask_get(); if (res) - goto err_exit; + return res; hotkey_orig_mask = hotkey_acpi_mask; } else { @@ -3500,8 +3500,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) TPACPI_HOTKEY_MAP_SIZE, GFP_KERNEL); if (!hotkey_keycode_map) { pr_err("failed to allocate memory for key map\n"); - res = -ENOMEM; - goto err_exit; + return -ENOMEM; } input_set_capability(tpacpi_inputdev, EV_MSC, MSC_SCAN); @@ -3582,9 +3581,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) hotkey_poll_setup_safe(true); return 0; - -err_exit: - return (res < 0) ? res : -ENODEV; } /* Thinkpad X1 Carbon support 5 modes including Home mode, Web browser -- GitLab From 3a0abea60c6a39f5362db6d78cba7a932850fec2 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 21 Nov 2021 20:11:29 +0100 Subject: [PATCH 0158/1112] platform/x86: thinkpad_acpi: Fix thermal_temp_input_attr sorting Fix thermal_temp_input_attr sorting. Now that we use is_visible, rather then registering only part of the thermal_temp_input_attr array, putting attr 0-7 last is no longer needed. Reviewed-by: Andy Shevchenko Tested-by: Mark Pearson Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20211121191129.256713-8-hdegoede@redhat.com --- drivers/platform/x86/thinkpad_acpi.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 45b68042e1fbd..59a75ac4bca8b 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -6267,14 +6267,6 @@ static struct sensor_device_attribute sensor_dev_attr_thermal_temp_input[] = { &sensor_dev_attr_thermal_temp_input[X].dev_attr.attr static struct attribute *thermal_temp_input_attr[] = { - THERMAL_ATTRS(8), - THERMAL_ATTRS(9), - THERMAL_ATTRS(10), - THERMAL_ATTRS(11), - THERMAL_ATTRS(12), - THERMAL_ATTRS(13), - THERMAL_ATTRS(14), - THERMAL_ATTRS(15), THERMAL_ATTRS(0), THERMAL_ATTRS(1), THERMAL_ATTRS(2), @@ -6283,6 +6275,14 @@ static struct attribute *thermal_temp_input_attr[] = { THERMAL_ATTRS(5), THERMAL_ATTRS(6), THERMAL_ATTRS(7), + THERMAL_ATTRS(8), + THERMAL_ATTRS(9), + THERMAL_ATTRS(10), + THERMAL_ATTRS(11), + THERMAL_ATTRS(12), + THERMAL_ATTRS(13), + THERMAL_ATTRS(14), + THERMAL_ATTRS(15), NULL }; -- GitLab From 910524004383863bb1d2888e510dd61fd00119d0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 23 Nov 2021 22:04:19 +0100 Subject: [PATCH 0159/1112] platform/x86: thinkpad_acpi: Restore missing hotkey_tablet_mode and hotkey_radio_sw sysfs-attr Commit c99ca78d67a6 ("platform/x86: thinkpad_acpi: Switch to common use of attributes") removed the conditional adding of the hotkey_tablet_mode and hotkey_radio_sw sysfs-attributes, replacing this with a hotkey_attr_is_visible() callback which hides them when the feature is not present. But this commit forgot to add these 2 attributes to the default hotkey_attributes[] set, so they would now never get added at all. Add the 2 attributes to the default hotkey_attributes[] set so that they are available on systems with these features once more. Fixes: c99ca78d67a6 ("platform/x86: thinkpad_acpi: Switch to common use of attributes") Cc: Len Baker Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20211123210424.266607-2-hdegoede@redhat.com --- drivers/platform/x86/thinkpad_acpi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 59a75ac4bca8b..5c2572abd98e4 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -2960,6 +2960,8 @@ static struct attribute *hotkey_attributes[] = { &dev_attr_hotkey_all_mask.attr, &dev_attr_hotkey_adaptive_all_mask.attr, &dev_attr_hotkey_recommended_mask.attr, + &dev_attr_hotkey_tablet_mode.attr, + &dev_attr_hotkey_radio_sw.attr, #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL &dev_attr_hotkey_source_mask.attr, &dev_attr_hotkey_poll_freq.attr, -- GitLab From 2f5ad08f3eec8d4376b62f3fe708102f6aaea056 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 23 Nov 2021 22:04:20 +0100 Subject: [PATCH 0160/1112] platform/x86: thinkpad_acpi: Register tpacpi_pdriver after subdriver init Commit 79f960e29cfc ("platform/x86: thinkpad_acpi: Convert platform driver to use dev_groups") introduces the use of driver.dev_groups + attribute_group.is_visible callbacks replacing the conditional calling of driver_create_file() for optional attributes. The is_visible callbacks rely on various tp_features.has_foo flags, which get set by the subdriver init functions. But before this fix, thinkpad_acpi_module_init() would call the subdriver init functions after registering the platform_device and the tpacpi_pdriver. Which would cause the is_visible callbacks to get called before the subdriver init functions, which in turn would cause optional attributes to not get registered at all, even when the feature is actually present. Fix this by moving the platform_driver_register(&tpacpi_pdriver) to after the subdriver init calls; and do the same for the tpacpi_hmon_pdriver. Fixes: 79f960e29cfc ("platform/x86: thinkpad_acpi: Convert platform driver to use dev_groups") Cc: Len Baker Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20211123210424.266607-3-hdegoede@redhat.com --- drivers/platform/x86/thinkpad_acpi.c | 41 ++++++++++++++-------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 5c2572abd98e4..1aa292e6cc961 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -11113,6 +11113,11 @@ static void thinkpad_acpi_module_exit(void) tpacpi_lifecycle = TPACPI_LIFE_EXITING; + if (tp_features.sensors_pdrv_registered) + platform_driver_unregister(&tpacpi_hwmon_pdriver); + if (tp_features.platform_drv_registered) + platform_driver_unregister(&tpacpi_pdriver); + list_for_each_entry_safe_reverse(ibm, itmp, &tpacpi_all_drivers, all_drivers) { @@ -11135,10 +11140,6 @@ static void thinkpad_acpi_module_exit(void) platform_device_unregister(tpacpi_sensors_pdev); if (tpacpi_pdev) platform_device_unregister(tpacpi_pdev); - if (tp_features.sensors_pdrv_registered) - platform_driver_unregister(&tpacpi_hwmon_pdriver); - if (tp_features.platform_drv_registered) - platform_driver_unregister(&tpacpi_pdriver); if (proc_dir) remove_proc_entry(TPACPI_PROC_DIR, acpi_root_dir); if (tpacpi_wq) @@ -11192,22 +11193,6 @@ static int __init thinkpad_acpi_module_init(void) return -ENODEV; } - ret = platform_driver_register(&tpacpi_pdriver); - if (ret) { - pr_err("unable to register main platform driver\n"); - thinkpad_acpi_module_exit(); - return ret; - } - tp_features.platform_drv_registered = 1; - - ret = platform_driver_register(&tpacpi_hwmon_pdriver); - if (ret) { - pr_err("unable to register hwmon platform driver\n"); - thinkpad_acpi_module_exit(); - return ret; - } - tp_features.sensors_pdrv_registered = 1; - /* Device initialization */ tpacpi_pdev = platform_device_register_simple(TPACPI_DRVR_NAME, -1, NULL, 0); @@ -11271,6 +11256,22 @@ static int __init thinkpad_acpi_module_init(void) tpacpi_lifecycle = TPACPI_LIFE_RUNNING; + ret = platform_driver_register(&tpacpi_pdriver); + if (ret) { + pr_err("unable to register main platform driver\n"); + thinkpad_acpi_module_exit(); + return ret; + } + tp_features.platform_drv_registered = 1; + + ret = platform_driver_register(&tpacpi_hwmon_pdriver); + if (ret) { + pr_err("unable to register hwmon platform driver\n"); + thinkpad_acpi_module_exit(); + return ret; + } + tp_features.sensors_pdrv_registered = 1; + ret = input_register_device(tpacpi_inputdev); if (ret < 0) { pr_err("unable to register input device\n"); -- GitLab From 5cd689683eb0507c67f825f1c29b17bb80612468 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 23 Nov 2021 22:04:21 +0100 Subject: [PATCH 0161/1112] platform/x86: thinkpad_acpi: tpacpi_attr_group contains driver attributes not device attrs Commit 79f960e29cfc ("platform/x86: thinkpad_acpi: Convert platform driver to use dev_groups") put the debug_level, interface_version, version and the THINKPAD_ACPI_DEBUGFACILITIES attributes in a new tpacpi_attr_group and added those to the tpacpi_groups groups-array which is used to initialize the driver.dev_groups member. But before this commit these attributes were registered with driver_create_file(), so they should be part of the groups-array which is used to initialize the driver.groups member instead. And also make the same change for the fan_watchdog hwmon driver attribute. Fixes: 79f960e29cfc ("platform/x86: thinkpad_acpi: Convert platform driver to use dev_groups") Cc: Len Baker Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20211123210424.266607-4-hdegoede@redhat.com --- drivers/platform/x86/thinkpad_acpi.c | 30 +++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 1aa292e6cc961..93c1c925b6551 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -8630,7 +8630,6 @@ static struct attribute *fan_attributes[] = { &dev_attr_pwm1.attr, &dev_attr_fan1_input.attr, &dev_attr_fan2_input.attr, - &driver_attr_fan_watchdog.attr, NULL }; @@ -8654,6 +8653,16 @@ static const struct attribute_group fan_attr_group = { .attrs = fan_attributes, }; +static struct attribute *fan_driver_attributes[] = { + &driver_attr_fan_watchdog.attr, + NULL +}; + +static const struct attribute_group fan_driver_attr_group = { + .is_visible = fan_attr_is_visible, + .attrs = fan_driver_attributes, +}; + #define TPACPI_FAN_Q1 0x0001 /* Unitialized HFSP */ #define TPACPI_FAN_2FAN 0x0002 /* EC 0x31 bit 0 selects fan2 */ #define TPACPI_FAN_2CTL 0x0004 /* selects fan2 control */ @@ -10396,7 +10405,7 @@ static struct ibm_struct dprc_driver_data = { /* --------------------------------------------------------------------- */ -static struct attribute *tpacpi_attributes[] = { +static struct attribute *tpacpi_driver_attributes[] = { &driver_attr_debug_level.attr, &driver_attr_version.attr, &driver_attr_interface_version.attr, @@ -10431,11 +10440,16 @@ static umode_t tpacpi_attr_is_visible(struct kobject *kobj, } #endif -static const struct attribute_group tpacpi_attr_group = { +static const struct attribute_group tpacpi_driver_attr_group = { #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES .is_visible = tpacpi_attr_is_visible, #endif - .attrs = tpacpi_attributes, + .attrs = tpacpi_driver_attributes, +}; + +static const struct attribute_group *tpacpi_driver_groups[] = { + &tpacpi_driver_attr_group, + NULL, }; static const struct attribute_group *tpacpi_groups[] = { @@ -10447,7 +10461,6 @@ static const struct attribute_group *tpacpi_groups[] = { &proxsensor_attr_group, &kbdlang_attr_group, &dprc_attr_group, - &tpacpi_attr_group, NULL, }; @@ -10458,6 +10471,11 @@ static const struct attribute_group *tpacpi_hwmon_groups[] = { NULL, }; +static const struct attribute_group *tpacpi_hwmon_driver_groups[] = { + &fan_driver_attr_group, + NULL, +}; + /**************************************************************************** **************************************************************************** * @@ -10470,6 +10488,7 @@ static struct platform_driver tpacpi_pdriver = { .driver = { .name = TPACPI_DRVR_NAME, .pm = &tpacpi_pm, + .groups = tpacpi_driver_groups, .dev_groups = tpacpi_groups, }, .shutdown = tpacpi_shutdown_handler, @@ -10478,6 +10497,7 @@ static struct platform_driver tpacpi_pdriver = { static struct platform_driver tpacpi_hwmon_pdriver = { .driver = { .name = TPACPI_HWMON_DRVR_NAME, + .groups = tpacpi_hwmon_driver_groups, .dev_groups = tpacpi_hwmon_groups, }, }; -- GitLab From 526ac103dbc67291a071fc57aab0f85ad7298ef3 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 23 Nov 2021 22:04:22 +0100 Subject: [PATCH 0162/1112] platform/x86: thinkpad_acpi: Fix the hwmon sysfs-attr showing up in the wrong place The hwmon sysfs-attr should show up under the hwmon-classdev, not under the tpacpi_sensors_pdev. Pass the tpacpi_hwmon_groups attr-groups array to hwmon_device_register_with_groups() instead of setting tpacpi_hwmon_pdriver.driver.dev_groups to it to fix this. This also requires moving the hwmon_device_register_with_groups() call to after the subdriver init functions have run so that the is_visible() calls will work properly. Fixes: 79f960e29cfc ("platform/x86: thinkpad_acpi: Convert platform driver to use dev_groups") Cc: Len Baker Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20211123210424.266607-5-hdegoede@redhat.com --- drivers/platform/x86/thinkpad_acpi.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 93c1c925b6551..63cb71c915305 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -10498,7 +10498,6 @@ static struct platform_driver tpacpi_hwmon_pdriver = { .driver = { .name = TPACPI_HWMON_DRVR_NAME, .groups = tpacpi_hwmon_driver_groups, - .dev_groups = tpacpi_hwmon_groups, }, }; @@ -11133,6 +11132,8 @@ static void thinkpad_acpi_module_exit(void) tpacpi_lifecycle = TPACPI_LIFE_EXITING; + if (tpacpi_hwmon) + hwmon_device_unregister(tpacpi_hwmon); if (tp_features.sensors_pdrv_registered) platform_driver_unregister(&tpacpi_hwmon_pdriver); if (tp_features.platform_drv_registered) @@ -11154,8 +11155,6 @@ static void thinkpad_acpi_module_exit(void) kfree(hotkey_keycode_map); } - if (tpacpi_hwmon) - hwmon_device_unregister(tpacpi_hwmon); if (tpacpi_sensors_pdev) platform_device_unregister(tpacpi_sensors_pdev); if (tpacpi_pdev) @@ -11234,16 +11233,7 @@ static int __init thinkpad_acpi_module_init(void) return ret; } tp_features.sensors_pdev_attrs_registered = 1; - tpacpi_hwmon = hwmon_device_register_with_groups( - &tpacpi_sensors_pdev->dev, TPACPI_NAME, NULL, NULL); - if (IS_ERR(tpacpi_hwmon)) { - ret = PTR_ERR(tpacpi_hwmon); - tpacpi_hwmon = NULL; - pr_err("unable to register hwmon device\n"); - thinkpad_acpi_module_exit(); - return ret; - } mutex_init(&tpacpi_inputdev_send_mutex); tpacpi_inputdev = input_allocate_device(); if (!tpacpi_inputdev) { @@ -11292,6 +11282,16 @@ static int __init thinkpad_acpi_module_init(void) } tp_features.sensors_pdrv_registered = 1; + tpacpi_hwmon = hwmon_device_register_with_groups( + &tpacpi_sensors_pdev->dev, TPACPI_NAME, NULL, tpacpi_hwmon_groups); + if (IS_ERR(tpacpi_hwmon)) { + ret = PTR_ERR(tpacpi_hwmon); + tpacpi_hwmon = NULL; + pr_err("unable to register hwmon device\n"); + thinkpad_acpi_module_exit(); + return ret; + } + ret = input_register_device(tpacpi_inputdev); if (ret < 0) { pr_err("unable to register input device\n"); -- GitLab From f3dc3009c2edb1512e0fe6964f387045a36b2ff4 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 23 Nov 2021 22:04:23 +0100 Subject: [PATCH 0163/1112] platform/x86: thinkpad_acpi: Remove unused sensors_pdev_attrs_registered flag After the recent sysfs-attributes registration cleanups, the tp_features.sensors_pdev_attrs_registered flag only ever gets set and never gets read, remove it. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20211123210424.266607-6-hdegoede@redhat.com --- drivers/platform/x86/thinkpad_acpi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 63cb71c915305..c198acc6f53b7 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -333,7 +333,6 @@ static struct { u32 input_device_registered:1; u32 platform_drv_registered:1; u32 sensors_pdrv_registered:1; - u32 sensors_pdev_attrs_registered:1; u32 hotkey_poll_active:1; u32 has_adaptive_kbd:1; u32 kbd_lang:1; @@ -11232,7 +11231,6 @@ static int __init thinkpad_acpi_module_init(void) thinkpad_acpi_module_exit(); return ret; } - tp_features.sensors_pdev_attrs_registered = 1; mutex_init(&tpacpi_inputdev_send_mutex); tpacpi_inputdev = input_allocate_device(); -- GitLab From bdfd6ab8fdccd8b138837efff66f4a1911496378 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 25 Nov 2021 21:30:10 +0100 Subject: [PATCH 0164/1112] gpiolib: acpi: Do not set the IRQ type if the IRQ is already in use If the IRQ is already in use, then acpi_dev_gpio_irq_get_by() really should not change the type underneath the current owner. I specifically hit an issue with this an a Chuwi Hi8 Super (CWI509) Bay Trail tablet, when the Boot OS selection in the BIOS is set to Android. In this case _STA for a MAX17047 ACPI I2C device wrongly returns 0xf and the _CRS resources for this device include a GpioInt pointing to a GPIO already in use by an _AEI handler, with a different type then specified in the _CRS for the MAX17047 device. Leading to the acpi_dev_gpio_irq_get() call done by the i2c-core-acpi.c code changing the type breaking the _AEI handler. Now this clearly is a bug in the DSDT of this tablet (in Android mode), but in general calling irq_set_irq_type() on an IRQ which already is in use seems like a bad idea. Signed-off-by: Hans de Goede Signed-off-by: Andy Shevchenko --- drivers/gpio/gpiolib-acpi.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 7dd0484b89c60..02b06e69b50b4 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -1044,10 +1044,17 @@ int acpi_dev_gpio_irq_get_by(struct acpi_device *adev, const char *name, int ind irq_flags = acpi_dev_get_irq_type(info.triggering, info.polarity); - /* Set type if specified and different than the current one */ - if (irq_flags != IRQ_TYPE_NONE && - irq_flags != irq_get_trigger_type(irq)) - irq_set_irq_type(irq, irq_flags); + /* + * If the IRQ is not already in use then set type + * if specified and different than the current one. + */ + if (can_request_irq(irq, irq_flags)) { + if (irq_flags != IRQ_TYPE_NONE && + irq_flags != irq_get_trigger_type(irq)) + irq_set_irq_type(irq, irq_flags); + } else { + dev_dbg(&adev->dev, "IRQ %d already in use\n", irq); + } return irq; } -- GitLab From be3dc15ffe644d1b8bfae4a05eae3dc413a7c5e7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 23 Nov 2021 12:18:37 +0200 Subject: [PATCH 0165/1112] gpiolib: acpi: Unify debug and other messages format When ACPI device pointer available use it, otherwise take parent of GPIO chip. Signed-off-by: Andy Shevchenko --- drivers/gpio/gpiolib-acpi.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 02b06e69b50b4..c7a0e56593e77 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -219,14 +219,13 @@ EXPORT_SYMBOL_GPL(acpi_gpio_get_io_resource); static void acpi_gpiochip_request_irq(struct acpi_gpio_chip *acpi_gpio, struct acpi_gpio_event *event) { + struct device *parent = acpi_gpio->chip->parent; int ret, value; ret = request_threaded_irq(event->irq, NULL, event->handler, event->irqflags | IRQF_ONESHOT, "ACPI:Event", event); if (ret) { - dev_err(acpi_gpio->chip->parent, - "Failed to setup interrupt handler for %d\n", - event->irq); + dev_err(parent, "Failed to setup interrupt handler for %d\n", event->irq); return; } @@ -347,8 +346,7 @@ static bool acpi_gpio_in_ignore_list(const char *controller_in, int pin_in) return false; err: - pr_err_once("Error invalid value for gpiolib_acpi.ignore_wake: %s\n", - ignore_wake); + pr_err_once("Error: Invalid value for gpiolib_acpi.ignore_wake: %s\n", ignore_wake); return false; } @@ -929,7 +927,7 @@ struct gpio_desc *acpi_find_gpio(struct device *dev, if (info.gpioint && (*dflags == GPIOD_OUT_LOW || *dflags == GPIOD_OUT_HIGH)) { - dev_dbg(dev, "refusing GpioInt() entry when doing GPIOD_OUT_* lookup\n"); + dev_dbg(&adev->dev, "refusing GpioInt() entry when doing GPIOD_OUT_* lookup\n"); return ERR_PTR(-ENOENT); } -- GitLab From a1ee1c08fcd5af03187dcd41dcab12fd5b379555 Mon Sep 17 00:00:00 2001 From: Chengfeng Ye Date: Fri, 5 Nov 2021 06:45:07 -0700 Subject: [PATCH 0166/1112] HSI: core: Fix return freed object in hsi_new_client cl is freed on error of calling device_register, but this object is return later, which will cause uaf issue. Fix it by return NULL on error. Signed-off-by: Chengfeng Ye Signed-off-by: Sebastian Reichel --- drivers/hsi/hsi_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hsi/hsi_core.c b/drivers/hsi/hsi_core.c index ec90713564e32..884066109699c 100644 --- a/drivers/hsi/hsi_core.c +++ b/drivers/hsi/hsi_core.c @@ -102,6 +102,7 @@ struct hsi_client *hsi_new_client(struct hsi_port *port, if (device_register(&cl->device) < 0) { pr_err("hsi: failed to register client: %s\n", info->name); put_device(&cl->device); + goto err; } return cl; -- GitLab From ce8ce31b2c5c8b18667784b8c515650c65d57b4e Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Mon, 15 Nov 2021 15:18:04 +0100 Subject: [PATCH 0167/1112] crypto: drbg - prepare for more fine-grained tracking of seeding state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are two different randomness sources the DRBGs are getting seeded from, namely the jitterentropy source (if enabled) and get_random_bytes(). At initial DRBG seeding time during boot, the latter might not have collected sufficient entropy for seeding itself yet and thus, the DRBG implementation schedules a reseed work from a random_ready_callback once that has happened. This is particularly important for the !->pr DRBG instances, for which (almost) no further reseeds are getting triggered during their lifetime. Because collecting data from the jitterentropy source is a rather expensive operation, the aforementioned asynchronously scheduled reseed work restricts itself to get_random_bytes() only. That is, it in some sense amends the initial DRBG seed derived from jitterentropy output at full (estimated) entropy with fresh randomness obtained from get_random_bytes() once that has been seeded with sufficient entropy itself. With the advent of rng_is_initialized(), there is no real need for doing the reseed operation from an asynchronously scheduled work anymore and a subsequent patch will make it synchronous by moving it next to related logic already present in drbg_generate(). However, for tracking whether a full reseed including the jitterentropy source is required or a "partial" reseed involving only get_random_bytes() would be sufficient already, the boolean struct drbg_state's ->seeded member must become a tristate value. Prepare for this by introducing the new enum drbg_seed_state and change struct drbg_state's ->seeded member's type from bool to that type. For facilitating review, enum drbg_seed_state is made to only contain two members corresponding to the former ->seeded values of false and true resp. at this point: DRBG_SEED_STATE_UNSEEDED and DRBG_SEED_STATE_FULL. A third one for tracking the intermediate state of "seeded from jitterentropy only" will be introduced with a subsequent patch. There is no change in behaviour at this point. Signed-off-by: Nicolai Stange Reviewed-by: Stephan Müller Signed-off-by: Herbert Xu --- crypto/drbg.c | 19 ++++++++++--------- include/crypto/drbg.h | 7 ++++++- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index f72f340a13210..6329c70e5bbbf 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -1043,7 +1043,7 @@ static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed, if (ret) return ret; - drbg->seeded = true; + drbg->seeded = DRBG_SEED_STATE_FULL; /* 10.1.1.2 / 10.1.1.3 step 5 */ drbg->reseed_ctr = 1; @@ -1088,14 +1088,14 @@ static void drbg_async_seed(struct work_struct *work) if (ret) goto unlock; - /* Set seeded to false so that if __drbg_seed fails the - * next generate call will trigger a reseed. + /* Reset ->seeded so that if __drbg_seed fails the next + * generate call will trigger a reseed. */ - drbg->seeded = false; + drbg->seeded = DRBG_SEED_STATE_UNSEEDED; __drbg_seed(drbg, &seedlist, true); - if (drbg->seeded) + if (drbg->seeded == DRBG_SEED_STATE_FULL) drbg->reseed_threshold = drbg_max_requests(drbg); unlock: @@ -1386,13 +1386,14 @@ static int drbg_generate(struct drbg_state *drbg, * here. The spec is a bit convoluted here, we make it simpler. */ if (drbg->reseed_threshold < drbg->reseed_ctr) - drbg->seeded = false; + drbg->seeded = DRBG_SEED_STATE_UNSEEDED; - if (drbg->pr || !drbg->seeded) { + if (drbg->pr || drbg->seeded == DRBG_SEED_STATE_UNSEEDED) { pr_devel("DRBG: reseeding before generation (prediction " "resistance: %s, state %s)\n", drbg->pr ? "true" : "false", - drbg->seeded ? "seeded" : "unseeded"); + (drbg->seeded == DRBG_SEED_STATE_FULL ? + "seeded" : "unseeded")); /* 9.3.1 steps 7.1 through 7.3 */ len = drbg_seed(drbg, addtl, true); if (len) @@ -1578,7 +1579,7 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers, if (!drbg->core) { drbg->core = &drbg_cores[coreref]; drbg->pr = pr; - drbg->seeded = false; + drbg->seeded = DRBG_SEED_STATE_UNSEEDED; drbg->reseed_threshold = drbg_max_requests(drbg); ret = drbg_alloc_state(drbg); diff --git a/include/crypto/drbg.h b/include/crypto/drbg.h index c4165126937e4..92a87b23ad2f9 100644 --- a/include/crypto/drbg.h +++ b/include/crypto/drbg.h @@ -105,6 +105,11 @@ struct drbg_test_data { struct drbg_string *testentropy; /* TEST PARAMETER: test entropy */ }; +enum drbg_seed_state { + DRBG_SEED_STATE_UNSEEDED, + DRBG_SEED_STATE_FULL, +}; + struct drbg_state { struct mutex drbg_mutex; /* lock around DRBG */ unsigned char *V; /* internal state 10.1.1.1 1a) */ @@ -127,7 +132,7 @@ struct drbg_state { struct crypto_wait ctr_wait; /* CTR mode async wait obj */ struct scatterlist sg_in, sg_out; /* CTR mode SGLs */ - bool seeded; /* DRBG fully seeded? */ + enum drbg_seed_state seeded; /* DRBG fully seeded? */ bool pr; /* Prediction resistance enabled? */ bool fips_primed; /* Continuous test primed? */ unsigned char *prev; /* FIPS 140-2 continuous test value */ -- GitLab From 2bcd25443868aa8863779a6ebc6c9319633025d2 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Mon, 15 Nov 2021 15:18:05 +0100 Subject: [PATCH 0168/1112] crypto: drbg - track whether DRBG was seeded with !rng_is_initialized() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, the DRBG implementation schedules asynchronous works from random_ready_callbacks for reseeding the DRBG instances with output from get_random_bytes() once the latter has sufficient entropy available. However, as the get_random_bytes() initialization state can get queried by means of rng_is_initialized() now, there is no real need for this asynchronous reseeding logic anymore and it's better to keep things simple by doing it synchronously when needed instead, i.e. from drbg_generate() once rng_is_initialized() has flipped to true. Of course, for this to work, drbg_generate() would need some means by which it can tell whether or not rng_is_initialized() has flipped to true since the last seeding from get_random_bytes(). Or equivalently, whether or not the last seed from get_random_bytes() has happened when rng_is_initialized() was still evaluating to false. As it currently stands, enum drbg_seed_state allows for the representation of two different DRBG seeding states: DRBG_SEED_STATE_UNSEEDED and DRBG_SEED_STATE_FULL. The former makes drbg_generate() to invoke a full reseeding operation involving both, the rather expensive jitterentropy as well as the get_random_bytes() randomness sources. The DRBG_SEED_STATE_FULL state on the other hand implies that no reseeding at all is required for a !->pr DRBG variant. Introduce the new DRBG_SEED_STATE_PARTIAL state to enum drbg_seed_state for representing the condition that a DRBG was being seeded when rng_is_initialized() had still been false. In particular, this new state implies that - the given DRBG instance has been fully seeded from the jitterentropy source (if enabled) - and drbg_generate() is supposed to reseed from get_random_bytes() *only* once rng_is_initialized() turns to true. Up to now, the __drbg_seed() helper used to set the given DRBG instance's ->seeded state to constant DRBG_SEED_STATE_FULL. Introduce a new argument allowing for the specification of the to be written ->seeded value instead. Make the first of its two callers, drbg_seed(), determine the appropriate value based on rng_is_initialized(). The remaining caller, drbg_async_seed(), is known to get invoked only once rng_is_initialized() is true, hence let it pass constant DRBG_SEED_STATE_FULL for the new argument to __drbg_seed(). There is no change in behaviour, except for that the pr_devel() in drbg_generate() would now report "unseeded" for ->pr DRBG instances which had last been seeded when rng_is_initialized() was still evaluating to false. Signed-off-by: Nicolai Stange Reviewed-by: Stephan Müller Signed-off-by: Herbert Xu --- crypto/drbg.c | 12 ++++++++---- include/crypto/drbg.h | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index 6329c70e5bbbf..d71c704d0cd2d 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -1036,14 +1036,14 @@ static const struct drbg_state_ops drbg_hash_ops = { ******************************************************************/ static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed, - int reseed) + int reseed, enum drbg_seed_state new_seed_state) { int ret = drbg->d_ops->update(drbg, seed, reseed); if (ret) return ret; - drbg->seeded = DRBG_SEED_STATE_FULL; + drbg->seeded = new_seed_state; /* 10.1.1.2 / 10.1.1.3 step 5 */ drbg->reseed_ctr = 1; @@ -1093,7 +1093,7 @@ static void drbg_async_seed(struct work_struct *work) */ drbg->seeded = DRBG_SEED_STATE_UNSEEDED; - __drbg_seed(drbg, &seedlist, true); + __drbg_seed(drbg, &seedlist, true, DRBG_SEED_STATE_FULL); if (drbg->seeded == DRBG_SEED_STATE_FULL) drbg->reseed_threshold = drbg_max_requests(drbg); @@ -1123,6 +1123,7 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers, unsigned int entropylen = drbg_sec_strength(drbg->core->flags); struct drbg_string data1; LIST_HEAD(seedlist); + enum drbg_seed_state new_seed_state = DRBG_SEED_STATE_FULL; /* 9.1 / 9.2 / 9.3.1 step 3 */ if (pers && pers->len > (drbg_max_addtl(drbg))) { @@ -1150,6 +1151,9 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers, BUG_ON((entropylen * 2) > sizeof(entropy)); /* Get seed from in-kernel /dev/urandom */ + if (!rng_is_initialized()) + new_seed_state = DRBG_SEED_STATE_PARTIAL; + ret = drbg_get_random_bytes(drbg, entropy, entropylen); if (ret) goto out; @@ -1206,7 +1210,7 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers, memset(drbg->C, 0, drbg_statelen(drbg)); } - ret = __drbg_seed(drbg, &seedlist, reseed); + ret = __drbg_seed(drbg, &seedlist, reseed, new_seed_state); out: memzero_explicit(entropy, entropylen * 2); diff --git a/include/crypto/drbg.h b/include/crypto/drbg.h index 92a87b23ad2f9..3ebdb1effe74e 100644 --- a/include/crypto/drbg.h +++ b/include/crypto/drbg.h @@ -107,6 +107,7 @@ struct drbg_test_data { enum drbg_seed_state { DRBG_SEED_STATE_UNSEEDED, + DRBG_SEED_STATE_PARTIAL, /* Seeded with !rng_is_initialized() */ DRBG_SEED_STATE_FULL, }; -- GitLab From 262d83a4290c331cd4f617a457408bdb82fbb738 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Mon, 15 Nov 2021 15:18:06 +0100 Subject: [PATCH 0169/1112] crypto: drbg - move dynamic ->reseed_threshold adjustments to __drbg_seed() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 42ea507fae1a ("crypto: drbg - reseed often if seedsource is degraded"), the maximum seed lifetime represented by ->reseed_threshold gets temporarily lowered if the get_random_bytes() source cannot provide sufficient entropy yet, as is common during boot, and restored back to the original value again once that has changed. More specifically, if the add_random_ready_callback() invoked from drbg_prepare_hrng() in the course of DRBG instantiation does not return -EALREADY, that is, if get_random_bytes() has not been fully initialized at this point yet, drbg_prepare_hrng() will lower ->reseed_threshold to a value of 50. The drbg_async_seed() scheduled from said random_ready_callback will eventually restore the original value. A future patch will replace the random_ready_callback based notification mechanism and thus, there will be no add_random_ready_callback() return value anymore which could get compared to -EALREADY. However, there's __drbg_seed() which gets invoked in the course of both, the DRBG instantiation as well as the eventual reseeding from get_random_bytes() in aforementioned drbg_async_seed(), if any. Moreover, it knows about the get_random_bytes() initialization state by the time the seed data had been obtained from it: the new_seed_state argument introduced with the previous patch would get set to DRBG_SEED_STATE_PARTIAL in case get_random_bytes() had not been fully initialized yet and to DRBG_SEED_STATE_FULL otherwise. Thus, __drbg_seed() provides a convenient alternative for managing that ->reseed_threshold lowering and restoring at a central place. Move all ->reseed_threshold adjustment code from drbg_prepare_hrng() and drbg_async_seed() respectively to __drbg_seed(). Make __drbg_seed() lower the ->reseed_threshold to 50 in case its new_seed_state argument equals DRBG_SEED_STATE_PARTIAL and let it restore the original value otherwise. There is no change in behaviour. Signed-off-by: Nicolai Stange Reviewed-by: Stephan Müller Signed-off-by: Herbert Xu --- crypto/drbg.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index d71c704d0cd2d..9b233e86a5f0c 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -1047,6 +1047,27 @@ static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed, /* 10.1.1.2 / 10.1.1.3 step 5 */ drbg->reseed_ctr = 1; + switch (drbg->seeded) { + case DRBG_SEED_STATE_UNSEEDED: + /* Impossible, but handle it to silence compiler warnings. */ + fallthrough; + case DRBG_SEED_STATE_PARTIAL: + /* + * Require frequent reseeds until the seed source is + * fully initialized. + */ + drbg->reseed_threshold = 50; + break; + + case DRBG_SEED_STATE_FULL: + /* + * Seed source has become fully initialized, frequent + * reseeds no longer required. + */ + drbg->reseed_threshold = drbg_max_requests(drbg); + break; + } + return ret; } @@ -1095,9 +1116,6 @@ static void drbg_async_seed(struct work_struct *work) __drbg_seed(drbg, &seedlist, true, DRBG_SEED_STATE_FULL); - if (drbg->seeded == DRBG_SEED_STATE_FULL) - drbg->reseed_threshold = drbg_max_requests(drbg); - unlock: mutex_unlock(&drbg->drbg_mutex); @@ -1534,12 +1552,6 @@ static int drbg_prepare_hrng(struct drbg_state *drbg) return err; } - /* - * Require frequent reseeds until the seed source is fully - * initialized. - */ - drbg->reseed_threshold = 50; - return err; } -- GitLab From 074bcd4000e0d812bc253f86fedc40f81ed59ccc Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Mon, 15 Nov 2021 15:18:07 +0100 Subject: [PATCH 0170/1112] crypto: drbg - make reseeding from get_random_bytes() synchronous get_random_bytes() usually hasn't full entropy available by the time DRBG instances are first getting seeded from it during boot. Thus, the DRBG implementation registers random_ready_callbacks which would in turn schedule some work for reseeding the DRBGs once get_random_bytes() has sufficient entropy available. For reference, the relevant history around handling DRBG (re)seeding in the context of a not yet fully seeded get_random_bytes() is: commit 16b369a91d0d ("random: Blocking API for accessing nonblocking_pool") commit 4c7879907edd ("crypto: drbg - add async seeding operation") commit 205a525c3342 ("random: Add callback API for random pool readiness") commit 57225e679788 ("crypto: drbg - Use callback API for random readiness") commit c2719503f5e1 ("random: Remove kernel blocking API") However, some time later, the initialization state of get_random_bytes() has been made queryable via rng_is_initialized() introduced with commit 9a47249d444d ("random: Make crng state queryable"). This primitive now allows for streamlining the DRBG reseeding from get_random_bytes() by replacing that aforementioned asynchronous work scheduling from random_ready_callbacks with some simpler, synchronous code in drbg_generate() next to the related logic already present therein. Apart from improving overall code readability, this change will also enable DRBG users to rely on wait_for_random_bytes() for ensuring that the initial seeding has completed, if desired. The previous patches already laid the grounds by making drbg_seed() to record at each DRBG instance whether it was being seeded at a time when rng_is_initialized() still had been false as indicated by ->seeded == DRBG_SEED_STATE_PARTIAL. All that remains to be done now is to make drbg_generate() check for this condition, determine whether rng_is_initialized() has flipped to true in the meanwhile and invoke a reseed from get_random_bytes() if so. Make this move: - rename the former drbg_async_seed() work handler, i.e. the one in charge of reseeding a DRBG instance from get_random_bytes(), to "drbg_seed_from_random()", - change its signature as appropriate, i.e. make it take a struct drbg_state rather than a work_struct and change its return type from "void" to "int" in order to allow for passing error information from e.g. its __drbg_seed() invocation onwards to callers, - make drbg_generate() invoke this drbg_seed_from_random() once it encounters a DRBG instance with ->seeded == DRBG_SEED_STATE_PARTIAL by the time rng_is_initialized() has flipped to true and - prune everything related to the former, random_ready_callback based mechanism. As drbg_seed_from_random() is now getting invoked from drbg_generate() with the ->drbg_mutex being held, it must not attempt to recursively grab it once again. Remove the corresponding mutex operations from what is now drbg_seed_from_random(). Furthermore, as drbg_seed_from_random() can now report errors directly to its caller, there's no need for it to temporarily switch the DRBG's ->seeded state to DRBG_SEED_STATE_UNSEEDED so that a failure of the subsequently invoked __drbg_seed() will get signaled to drbg_generate(). Don't do it then. Signed-off-by: Nicolai Stange Signed-off-by: Herbert Xu --- crypto/drbg.c | 62 ++++++++----------------------------------- include/crypto/drbg.h | 2 -- 2 files changed, 11 insertions(+), 53 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index 9b233e86a5f0c..2b03a05a9e99b 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -1087,12 +1087,10 @@ static inline int drbg_get_random_bytes(struct drbg_state *drbg, return 0; } -static void drbg_async_seed(struct work_struct *work) +static int drbg_seed_from_random(struct drbg_state *drbg) { struct drbg_string data; LIST_HEAD(seedlist); - struct drbg_state *drbg = container_of(work, struct drbg_state, - seed_work); unsigned int entropylen = drbg_sec_strength(drbg->core->flags); unsigned char entropy[32]; int ret; @@ -1103,23 +1101,15 @@ static void drbg_async_seed(struct work_struct *work) drbg_string_fill(&data, entropy, entropylen); list_add_tail(&data.list, &seedlist); - mutex_lock(&drbg->drbg_mutex); - ret = drbg_get_random_bytes(drbg, entropy, entropylen); if (ret) - goto unlock; - - /* Reset ->seeded so that if __drbg_seed fails the next - * generate call will trigger a reseed. - */ - drbg->seeded = DRBG_SEED_STATE_UNSEEDED; - - __drbg_seed(drbg, &seedlist, true, DRBG_SEED_STATE_FULL); + goto out; -unlock: - mutex_unlock(&drbg->drbg_mutex); + ret = __drbg_seed(drbg, &seedlist, true, DRBG_SEED_STATE_FULL); +out: memzero_explicit(entropy, entropylen); + return ret; } /* @@ -1422,6 +1412,11 @@ static int drbg_generate(struct drbg_state *drbg, goto err; /* 9.3.1 step 7.4 */ addtl = NULL; + } else if (rng_is_initialized() && + drbg->seeded == DRBG_SEED_STATE_PARTIAL) { + len = drbg_seed_from_random(drbg); + if (len) + goto err; } if (addtl && 0 < addtl->len) @@ -1514,45 +1509,15 @@ static int drbg_generate_long(struct drbg_state *drbg, return 0; } -static void drbg_schedule_async_seed(struct random_ready_callback *rdy) -{ - struct drbg_state *drbg = container_of(rdy, struct drbg_state, - random_ready); - - schedule_work(&drbg->seed_work); -} - static int drbg_prepare_hrng(struct drbg_state *drbg) { - int err; - /* We do not need an HRNG in test mode. */ if (list_empty(&drbg->test_data.list)) return 0; drbg->jent = crypto_alloc_rng("jitterentropy_rng", 0, 0); - INIT_WORK(&drbg->seed_work, drbg_async_seed); - - drbg->random_ready.owner = THIS_MODULE; - drbg->random_ready.func = drbg_schedule_async_seed; - - err = add_random_ready_callback(&drbg->random_ready); - - switch (err) { - case 0: - break; - - case -EALREADY: - err = 0; - fallthrough; - - default: - drbg->random_ready.func = NULL; - return err; - } - - return err; + return 0; } /* @@ -1646,11 +1611,6 @@ free_everything: */ static int drbg_uninstantiate(struct drbg_state *drbg) { - if (drbg->random_ready.func) { - del_random_ready_callback(&drbg->random_ready); - cancel_work_sync(&drbg->seed_work); - } - if (!IS_ERR_OR_NULL(drbg->jent)) crypto_free_rng(drbg->jent); drbg->jent = NULL; diff --git a/include/crypto/drbg.h b/include/crypto/drbg.h index 3ebdb1effe74e..a6c3b8e7deb64 100644 --- a/include/crypto/drbg.h +++ b/include/crypto/drbg.h @@ -137,12 +137,10 @@ struct drbg_state { bool pr; /* Prediction resistance enabled? */ bool fips_primed; /* Continuous test primed? */ unsigned char *prev; /* FIPS 140-2 continuous test value */ - struct work_struct seed_work; /* asynchronous seeding support */ struct crypto_rng *jent; const struct drbg_state_ops *d_ops; const struct drbg_core *core; struct drbg_string test_data; - struct random_ready_callback random_ready; }; static inline __u8 drbg_statelen(struct drbg_state *drbg) -- GitLab From 559edd47cce4cc407d606b4d7f376822816fd4b8 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Mon, 15 Nov 2021 15:18:08 +0100 Subject: [PATCH 0171/1112] crypto: drbg - make drbg_prepare_hrng() handle jent instantiation errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that drbg_prepare_hrng() doesn't do anything but to instantiate a jitterentropy crypto_rng instance, it looks a little odd to have the related error handling at its only caller, drbg_instantiate(). Move the handling of jitterentropy allocation failures from drbg_instantiate() close to the allocation itself in drbg_prepare_hrng(). There is no change in behaviour. Signed-off-by: Nicolai Stange Reviewed-by: Stephan Müller Signed-off-by: Herbert Xu --- crypto/drbg.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index 2b03a05a9e99b..9f6485962ecce 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -1516,6 +1516,14 @@ static int drbg_prepare_hrng(struct drbg_state *drbg) return 0; drbg->jent = crypto_alloc_rng("jitterentropy_rng", 0, 0); + if (IS_ERR(drbg->jent)) { + const int err = PTR_ERR(drbg->jent); + + drbg->jent = NULL; + if (fips_enabled || err != -ENOENT) + return err; + pr_info("DRBG: Continuing without Jitter RNG\n"); + } return 0; } @@ -1571,14 +1579,6 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers, if (ret) goto free_everything; - if (IS_ERR(drbg->jent)) { - ret = PTR_ERR(drbg->jent); - drbg->jent = NULL; - if (fips_enabled || ret != -ENOENT) - goto free_everything; - pr_info("DRBG: Continuing without Jitter RNG\n"); - } - reseed = false; } -- GitLab From 8ea5ee00beb925d2aa0fed0eb3faf04715a3f2bd Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Mon, 15 Nov 2021 15:18:09 +0100 Subject: [PATCH 0172/1112] crypto: drbg - reseed 'nopr' drbgs periodically from get_random_bytes() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In contrast to the fully prediction resistant 'pr' DRBGs, the 'nopr' variants get seeded once at boot and reseeded only rarely thereafter, namely only after 2^20 requests have been served each. AFAICT, this reseeding based on the number of requests served is primarily motivated by information theoretic considerations, c.f. NIST SP800-90Ar1, sec. 8.6.8 ("Reseeding"). However, given the relatively large seed lifetime of 2^20 requests, the 'nopr' DRBGs can hardly be considered to provide any prediction resistance whatsoever, i.e. to protect against threats like side channel leaks of the internal DRBG state (think e.g. leaked VM snapshots). This is expected and completely in line with the 'nopr' naming, but as e.g. the "drbg_nopr_hmac_sha512" implementation is potentially being used for providing the "stdrng" and thus, the crypto_default_rng serving the in-kernel crypto, it would certainly be desirable to achieve at least the same level of prediction resistance as get_random_bytes() does. Note that the chacha20 rngs underlying get_random_bytes() get reseeded every CRNG_RESEED_INTERVAL == 5min: the secondary, per-NUMA node rngs from the primary one and the primary rng in turn from the entropy pool, provided sufficient entropy is available. The 'nopr' DRBGs do draw randomness from get_random_bytes() for their initial seed already, so making them to reseed themselves periodically from get_random_bytes() in order to let them benefit from the latter's prediction resistance is not such a big change conceptually. In principle, it would have been also possible to make the 'nopr' DRBGs to periodically invoke a full reseeding operation, i.e. to also consider the jitterentropy source (if enabled) in addition to get_random_bytes() for the seed value. However, get_random_bytes() is relatively lightweight as compared to the jitterentropy generation process and thus, even though the 'nopr' reseeding is supposed to get invoked infrequently, it's IMO still worthwhile to avoid occasional latency spikes for drbg_generate() and stick to get_random_bytes() only. As an additional remark, note that drawing randomness from the non-SP800-90B-conforming get_random_bytes() only won't adversely affect SP800-90A conformance either: the very same is being done during boot via drbg_seed_from_random() already once rng_is_initialized() flips to true and it follows that if the DRBG implementation does conform to SP800-90A now, it will continue to do so. Make the 'nopr' DRBGs to reseed themselves periodically from get_random_bytes() every CRNG_RESEED_INTERVAL == 5min. More specifically, introduce a new member ->last_seed_time to struct drbg_state for recording in units of jiffies when the last seeding operation had taken place. Make __drbg_seed() maintain it and let drbg_generate() invoke a reseed from get_random_bytes() via drbg_seed_from_random() if more than 5min have passed by since the last seeding operation. Be careful to not to reseed if in testing mode though, or otherwise the drbg related tests in crypto/testmgr.c would fail to reproduce the expected output. In order to keep the formatting clean in drbg_generate() wrap the logic for deciding whether or not a reseed is due in a new helper, drbg_nopr_reseed_interval_elapsed(). Signed-off-by: Nicolai Stange Reviewed-by: Stephan Müller Signed-off-by: Herbert Xu --- crypto/drbg.c | 26 +++++++++++++++++++++++++- include/crypto/drbg.h | 1 + 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/crypto/drbg.c b/crypto/drbg.c index 9f6485962ecce..5977a72afb034 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -100,6 +100,7 @@ #include #include #include +#include /*************************************************************** * Backend cipher definitions available to DRBG @@ -1044,6 +1045,7 @@ static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed, return ret; drbg->seeded = new_seed_state; + drbg->last_seed_time = jiffies; /* 10.1.1.2 / 10.1.1.3 step 5 */ drbg->reseed_ctr = 1; @@ -1112,6 +1114,26 @@ out: return ret; } +static bool drbg_nopr_reseed_interval_elapsed(struct drbg_state *drbg) +{ + unsigned long next_reseed; + + /* Don't ever reseed from get_random_bytes() in test mode. */ + if (list_empty(&drbg->test_data.list)) + return false; + + /* + * Obtain fresh entropy for the nopr DRBGs after 300s have + * elapsed in order to still achieve sort of partial + * prediction resistance over the time domain at least. Note + * that the period of 300s has been chosen to match the + * CRNG_RESEED_INTERVAL of the get_random_bytes()' chacha + * rngs. + */ + next_reseed = drbg->last_seed_time + 300 * HZ; + return time_after(jiffies, next_reseed); +} + /* * Seeding or reseeding of the DRBG * @@ -1413,7 +1435,8 @@ static int drbg_generate(struct drbg_state *drbg, /* 9.3.1 step 7.4 */ addtl = NULL; } else if (rng_is_initialized() && - drbg->seeded == DRBG_SEED_STATE_PARTIAL) { + (drbg->seeded == DRBG_SEED_STATE_PARTIAL || + drbg_nopr_reseed_interval_elapsed(drbg))) { len = drbg_seed_from_random(drbg); if (len) goto err; @@ -1569,6 +1592,7 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers, drbg->core = &drbg_cores[coreref]; drbg->pr = pr; drbg->seeded = DRBG_SEED_STATE_UNSEEDED; + drbg->last_seed_time = 0; drbg->reseed_threshold = drbg_max_requests(drbg); ret = drbg_alloc_state(drbg); diff --git a/include/crypto/drbg.h b/include/crypto/drbg.h index a6c3b8e7deb64..af5ad51d3eef8 100644 --- a/include/crypto/drbg.h +++ b/include/crypto/drbg.h @@ -134,6 +134,7 @@ struct drbg_state { struct scatterlist sg_in, sg_out; /* CTR mode SGLs */ enum drbg_seed_state seeded; /* DRBG fully seeded? */ + unsigned long last_seed_time; bool pr; /* Prediction resistance enabled? */ bool fips_primed; /* Continuous test primed? */ unsigned char *prev; /* FIPS 140-2 continuous test value */ -- GitLab From c79391c696da0151c6ec8cb8a31edfa8bbe68f24 Mon Sep 17 00:00:00 2001 From: Giovanni Cabiddu Date: Wed, 17 Nov 2021 14:30:34 +0000 Subject: [PATCH 0173/1112] crypto: qat - do not handle PFVF sources for qat_4xxx The QAT driver does not have support for PFVF interrupts for GEN4 devices, therefore report the vf2pf sources as 0. This prevents a NULL pointer dereference in the function adf_msix_isr_ae() if the device triggers a spurious interrupt. Fixes: 993161d36ab5 ("crypto: qat - fix handling of VF to PF interrupts") Reported-by: Adam Guerin Signed-off-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c b/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c index fa768f10635fd..fd29861526d6b 100644 --- a/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c +++ b/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c @@ -211,6 +211,12 @@ static u32 uof_get_ae_mask(u32 obj_num) return adf_4xxx_fw_config[obj_num].ae_mask; } +static u32 get_vf2pf_sources(void __iomem *pmisc_addr) +{ + /* For the moment do not report vf2pf sources */ + return 0; +} + void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data) { hw_data->dev_class = &adf_4xxx_class; @@ -254,6 +260,7 @@ void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data) hw_data->set_msix_rttable = set_msix_default_rttable; hw_data->set_ssm_wdtimer = adf_gen4_set_ssm_wdtimer; hw_data->enable_pfvf_comms = pfvf_comms_disabled; + hw_data->get_vf2pf_sources = get_vf2pf_sources; hw_data->disable_iov = adf_disable_sriov; hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION; -- GitLab From 5002200b4fedd7e90e4fbc2e5c42a4b3351df814 Mon Sep 17 00:00:00 2001 From: Giovanni Cabiddu Date: Wed, 17 Nov 2021 14:30:35 +0000 Subject: [PATCH 0174/1112] crypto: qat - fix undetected PFVF timeout in ACK loop If the remote function did not ACK the reception of a message, the function __adf_iov_putmsg() could detect it as a collision. This was due to the fact that the collision and the timeout checks after the ACK loop were in the wrong order. The timeout must be checked at the end of the loop, so fix by swapping the order of the two checks. Fixes: 9b768e8a3909 ("crypto: qat - detect PFVF collision after ACK") Signed-off-by: Giovanni Cabiddu Co-developed-by: Marco Chiappero Signed-off-by: Marco Chiappero Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_pf2vf_msg.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c index 59860bdaedb69..99ee17c3d06bf 100644 --- a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c +++ b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c @@ -107,6 +107,12 @@ static int __adf_iov_putmsg(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr) val = ADF_CSR_RD(pmisc_bar_addr, pf2vf_offset); } while ((val & int_bit) && (count++ < ADF_PFVF_MSG_ACK_MAX_RETRY)); + if (val & int_bit) { + dev_dbg(&GET_DEV(accel_dev), "ACK not received from remote\n"); + val &= ~int_bit; + ret = -EIO; + } + if (val != msg) { dev_dbg(&GET_DEV(accel_dev), "Collision - PFVF CSR overwritten by remote function\n"); @@ -114,12 +120,6 @@ static int __adf_iov_putmsg(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr) goto out; } - if (val & int_bit) { - dev_dbg(&GET_DEV(accel_dev), "ACK not received from remote\n"); - val &= ~int_bit; - ret = -EIO; - } - /* Finished with the PFVF CSR; relinquish it and leave msg in CSR */ ADF_CSR_WR(pmisc_bar_addr, pf2vf_offset, val & ~local_in_use_mask); out: -- GitLab From 95b4d40ed256c5d36b1dee979b65c04c3edd2b23 Mon Sep 17 00:00:00 2001 From: Marco Chiappero Date: Wed, 17 Nov 2021 14:30:36 +0000 Subject: [PATCH 0175/1112] crypto: qat - refactor PF top half for PFVF Move logic associated to handling VF2PF interrupt to its own function. This will simplify the handling of multiple interrupt sources in the function adf_msix_isr_ae() in the future. Signed-off-by: Marco Chiappero Co-developed-by: Giovanni Cabiddu Signed-off-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_isr.c | 84 +++++++++++++------------ 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/drivers/crypto/qat/qat_common/adf_isr.c b/drivers/crypto/qat/qat_common/adf_isr.c index 40593c9449a20..5dfc534f1bf01 100644 --- a/drivers/crypto/qat/qat_common/adf_isr.c +++ b/drivers/crypto/qat/qat_common/adf_isr.c @@ -54,52 +54,56 @@ static irqreturn_t adf_msix_isr_bundle(int irq, void *bank_ptr) return IRQ_HANDLED; } +#ifdef CONFIG_PCI_IOV +static bool adf_handle_vf2pf_int(struct adf_accel_dev *accel_dev) +{ + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + int bar_id = hw_data->get_misc_bar_id(hw_data); + struct adf_bar *pmisc = &GET_BARS(accel_dev)[bar_id]; + void __iomem *pmisc_addr = pmisc->virt_addr; + bool irq_handled = false; + unsigned long vf_mask; + + /* Get the interrupt sources triggered by VFs */ + vf_mask = hw_data->get_vf2pf_sources(pmisc_addr); + + if (vf_mask) { + struct adf_accel_vf_info *vf_info; + int i; + + /* Disable VF2PF interrupts for VFs with pending ints */ + adf_disable_vf2pf_interrupts_irq(accel_dev, vf_mask); + + /* + * Handle VF2PF interrupt unless the VF is malicious and + * is attempting to flood the host OS with VF2PF interrupts. + */ + for_each_set_bit(i, &vf_mask, ADF_MAX_NUM_VFS) { + vf_info = accel_dev->pf.vf_info + i; + + if (!__ratelimit(&vf_info->vf2pf_ratelimit)) { + dev_info(&GET_DEV(accel_dev), + "Too many ints from VF%d\n", + vf_info->vf_nr + 1); + continue; + } + + adf_schedule_vf2pf_handler(vf_info); + irq_handled = true; + } + } + return irq_handled; +} +#endif /* CONFIG_PCI_IOV */ + static irqreturn_t adf_msix_isr_ae(int irq, void *dev_ptr) { struct adf_accel_dev *accel_dev = dev_ptr; #ifdef CONFIG_PCI_IOV /* If SR-IOV is enabled (vf_info is non-NULL), check for VF->PF ints */ - if (accel_dev->pf.vf_info) { - struct adf_hw_device_data *hw_data = accel_dev->hw_device; - struct adf_bar *pmisc = - &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)]; - void __iomem *pmisc_addr = pmisc->virt_addr; - unsigned long vf_mask; - - /* Get the interrupt sources triggered by VFs */ - vf_mask = hw_data->get_vf2pf_sources(pmisc_addr); - - if (vf_mask) { - struct adf_accel_vf_info *vf_info; - bool irq_handled = false; - int i; - - /* Disable VF2PF interrupts for VFs with pending ints */ - adf_disable_vf2pf_interrupts_irq(accel_dev, vf_mask); - - /* - * Handle VF2PF interrupt unless the VF is malicious and - * is attempting to flood the host OS with VF2PF interrupts. - */ - for_each_set_bit(i, &vf_mask, ADF_MAX_NUM_VFS) { - vf_info = accel_dev->pf.vf_info + i; - - if (!__ratelimit(&vf_info->vf2pf_ratelimit)) { - dev_info(&GET_DEV(accel_dev), - "Too many ints from VF%d\n", - vf_info->vf_nr + 1); - continue; - } - - adf_schedule_vf2pf_handler(vf_info); - irq_handled = true; - } - - if (irq_handled) - return IRQ_HANDLED; - } - } + if (accel_dev->pf.vf_info && adf_handle_vf2pf_int(accel_dev)) + return IRQ_HANDLED; #endif /* CONFIG_PCI_IOV */ dev_dbg(&GET_DEV(accel_dev), "qat_dev%d spurious AE interrupt\n", -- GitLab From 08ea97f48883a5d3178e09433b449bafc5f2a314 Mon Sep 17 00:00:00 2001 From: Giovanni Cabiddu Date: Wed, 17 Nov 2021 14:30:37 +0000 Subject: [PATCH 0176/1112] crypto: qat - move vf2pf interrupt helpers Move vf2pf interrupt enable and disable functions from adf_pf2vf_msg.c to adf_isr.c This it to separate the interrupt related code from the PFVF protocol logic. With this change, the function adf_disable_vf2pf_interrupts_irq() is only called from adf_isr.c and it has been marked as static. Signed-off-by: Giovanni Cabiddu Reviewed-by: Marco Chiappero Signed-off-by: Herbert Xu --- .../crypto/qat/qat_common/adf_common_drv.h | 2 - drivers/crypto/qat/qat_common/adf_isr.c | 39 +++++++++++++++++++ drivers/crypto/qat/qat_common/adf_pf2vf_msg.c | 39 ------------------- 3 files changed, 39 insertions(+), 41 deletions(-) diff --git a/drivers/crypto/qat/qat_common/adf_common_drv.h b/drivers/crypto/qat/qat_common/adf_common_drv.h index de94b76a6d2ce..4f9f94db16e52 100644 --- a/drivers/crypto/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/qat/qat_common/adf_common_drv.h @@ -193,8 +193,6 @@ int adf_sriov_configure(struct pci_dev *pdev, int numvfs); void adf_disable_sriov(struct adf_accel_dev *accel_dev); void adf_disable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask); -void adf_disable_vf2pf_interrupts_irq(struct adf_accel_dev *accel_dev, - u32 vf_mask); void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask); int adf_enable_pf2vf_comms(struct adf_accel_dev *accel_dev); diff --git a/drivers/crypto/qat/qat_common/adf_isr.c b/drivers/crypto/qat/qat_common/adf_isr.c index 5dfc534f1bf01..2b4900c913083 100644 --- a/drivers/crypto/qat/qat_common/adf_isr.c +++ b/drivers/crypto/qat/qat_common/adf_isr.c @@ -55,6 +55,45 @@ static irqreturn_t adf_msix_isr_bundle(int irq, void *bank_ptr) } #ifdef CONFIG_PCI_IOV +void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask) +{ + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + u32 misc_bar_id = hw_data->get_misc_bar_id(hw_data); + struct adf_bar *pmisc = &GET_BARS(accel_dev)[misc_bar_id]; + void __iomem *pmisc_addr = pmisc->virt_addr; + unsigned long flags; + + spin_lock_irqsave(&accel_dev->pf.vf2pf_ints_lock, flags); + hw_data->enable_vf2pf_interrupts(pmisc_addr, vf_mask); + spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags); +} + +void adf_disable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask) +{ + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + u32 misc_bar_id = hw_data->get_misc_bar_id(hw_data); + struct adf_bar *pmisc = &GET_BARS(accel_dev)[misc_bar_id]; + void __iomem *pmisc_addr = pmisc->virt_addr; + unsigned long flags; + + spin_lock_irqsave(&accel_dev->pf.vf2pf_ints_lock, flags); + hw_data->disable_vf2pf_interrupts(pmisc_addr, vf_mask); + spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags); +} + +static void adf_disable_vf2pf_interrupts_irq(struct adf_accel_dev *accel_dev, + u32 vf_mask) +{ + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + u32 misc_bar_id = hw_data->get_misc_bar_id(hw_data); + struct adf_bar *pmisc = &GET_BARS(accel_dev)[misc_bar_id]; + void __iomem *pmisc_addr = pmisc->virt_addr; + + spin_lock(&accel_dev->pf.vf2pf_ints_lock); + hw_data->disable_vf2pf_interrupts(pmisc_addr, vf_mask); + spin_unlock(&accel_dev->pf.vf2pf_ints_lock); +} + static bool adf_handle_vf2pf_int(struct adf_accel_dev *accel_dev) { struct adf_hw_device_data *hw_data = accel_dev->hw_device; diff --git a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c index 99ee17c3d06bf..d0492530c84ab 100644 --- a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c +++ b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c @@ -14,45 +14,6 @@ ADF_PFVF_MSG_ACK_MAX_RETRY + \ ADF_PFVF_MSG_COLLISION_DETECT_DELAY) -void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask) -{ - struct adf_hw_device_data *hw_data = accel_dev->hw_device; - u32 misc_bar_id = hw_data->get_misc_bar_id(hw_data); - struct adf_bar *pmisc = &GET_BARS(accel_dev)[misc_bar_id]; - void __iomem *pmisc_addr = pmisc->virt_addr; - unsigned long flags; - - spin_lock_irqsave(&accel_dev->pf.vf2pf_ints_lock, flags); - hw_data->enable_vf2pf_interrupts(pmisc_addr, vf_mask); - spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags); -} - -void adf_disable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask) -{ - struct adf_hw_device_data *hw_data = accel_dev->hw_device; - u32 misc_bar_id = hw_data->get_misc_bar_id(hw_data); - struct adf_bar *pmisc = &GET_BARS(accel_dev)[misc_bar_id]; - void __iomem *pmisc_addr = pmisc->virt_addr; - unsigned long flags; - - spin_lock_irqsave(&accel_dev->pf.vf2pf_ints_lock, flags); - hw_data->disable_vf2pf_interrupts(pmisc_addr, vf_mask); - spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags); -} - -void adf_disable_vf2pf_interrupts_irq(struct adf_accel_dev *accel_dev, - u32 vf_mask) -{ - struct adf_hw_device_data *hw_data = accel_dev->hw_device; - u32 misc_bar_id = hw_data->get_misc_bar_id(hw_data); - struct adf_bar *pmisc = &GET_BARS(accel_dev)[misc_bar_id]; - void __iomem *pmisc_addr = pmisc->virt_addr; - - spin_lock(&accel_dev->pf.vf2pf_ints_lock); - hw_data->disable_vf2pf_interrupts(pmisc_addr, vf_mask); - spin_unlock(&accel_dev->pf.vf2pf_ints_lock); -} - static int __adf_iov_putmsg(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr) { struct adf_accel_pci *pci_info = &accel_dev->accel_pci_dev; -- GitLab From b7c13ee46cebfd106e7065cf5fee191b324d0ca9 Mon Sep 17 00:00:00 2001 From: Marco Chiappero Date: Wed, 17 Nov 2021 14:30:38 +0000 Subject: [PATCH 0177/1112] crypto: qat - move VF message handler to adf_vf2pf_msg.c Move the reading and parsing of a PF2VF message from the bottom half function in adf_vf_isr.c, adf_pf2vf_bh_handler(), to the PFVF protocol file adf_vf2pf_msg.c, for better code organization. The receive and handle logic has been moved to a new function called adf_recv_and_handle_pf2vf_msg() which returns a boolean indicating if interrupts need to be re-enabled or not. A slight refactoring has been done to avoid calculating the PF2VF CSR offset twice and repeating the clearing of the PF2VFINT bit. The "PF restarting" logic, now defined in the function adf_pf2vf_handle_pf_restaring(), has been kept in adf_vf_isr.c due to the dependencies with the adf_vf_stop_wq workqueue. Signed-off-by: Marco Chiappero Co-developed-by: Giovanni Cabiddu Signed-off-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- .../crypto/qat/qat_common/adf_common_drv.h | 2 + drivers/crypto/qat/qat_common/adf_vf2pf_msg.c | 59 ++++++++++++ drivers/crypto/qat/qat_common/adf_vf_isr.c | 91 +++++-------------- 3 files changed, 86 insertions(+), 66 deletions(-) diff --git a/drivers/crypto/qat/qat_common/adf_common_drv.h b/drivers/crypto/qat/qat_common/adf_common_drv.h index 4f9f94db16e52..56ee2d5a6b370 100644 --- a/drivers/crypto/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/qat/qat_common/adf_common_drv.h @@ -195,6 +195,8 @@ void adf_disable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask); void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask); +bool adf_recv_and_handle_pf2vf_msg(struct adf_accel_dev *accel_dev); +int adf_pf2vf_handle_pf_restarting(struct adf_accel_dev *accel_dev); int adf_enable_pf2vf_comms(struct adf_accel_dev *accel_dev); void adf_enable_pf2vf_interrupts(struct adf_accel_dev *accel_dev); void adf_disable_pf2vf_interrupts(struct adf_accel_dev *accel_dev); diff --git a/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c b/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c index 8d11bb24cea00..064477fcb5fb6 100644 --- a/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c +++ b/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c @@ -46,3 +46,62 @@ void adf_vf2pf_notify_shutdown(struct adf_accel_dev *accel_dev) "Failed to send Shutdown event to PF\n"); } EXPORT_SYMBOL_GPL(adf_vf2pf_notify_shutdown); + +bool adf_recv_and_handle_pf2vf_msg(struct adf_accel_dev *accel_dev) +{ + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + struct adf_bar *pmisc = + &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)]; + void __iomem *pmisc_bar_addr = pmisc->virt_addr; + u32 offset = hw_data->get_pf2vf_offset(0); + bool ret; + u32 msg; + + /* Read the message from PF */ + msg = ADF_CSR_RD(pmisc_bar_addr, offset); + if (!(msg & ADF_PF2VF_INT)) { + dev_info(&GET_DEV(accel_dev), + "Spurious PF2VF interrupt, msg %X. Ignored\n", msg); + return true; + } + + if (!(msg & ADF_PF2VF_MSGORIGIN_SYSTEM)) + /* Ignore legacy non-system (non-kernel) PF2VF messages */ + goto err; + + switch ((msg & ADF_PF2VF_MSGTYPE_MASK) >> ADF_PF2VF_MSGTYPE_SHIFT) { + case ADF_PF2VF_MSGTYPE_RESTARTING: + dev_dbg(&GET_DEV(accel_dev), + "Restarting msg received from PF 0x%x\n", msg); + + adf_pf2vf_handle_pf_restarting(accel_dev); + ret = false; + break; + case ADF_PF2VF_MSGTYPE_VERSION_RESP: + dev_dbg(&GET_DEV(accel_dev), + "Version resp received from PF 0x%x\n", msg); + accel_dev->vf.pf_version = + (msg & ADF_PF2VF_VERSION_RESP_VERS_MASK) >> + ADF_PF2VF_VERSION_RESP_VERS_SHIFT; + accel_dev->vf.compatible = + (msg & ADF_PF2VF_VERSION_RESP_RESULT_MASK) >> + ADF_PF2VF_VERSION_RESP_RESULT_SHIFT; + complete(&accel_dev->vf.iov_msg_completion); + ret = true; + break; + default: + goto err; + } + + /* To ack, clear the PF2VFINT bit */ + msg &= ~ADF_PF2VF_INT; + ADF_CSR_WR(pmisc_bar_addr, offset, msg); + return ret; + +err: + dev_err(&GET_DEV(accel_dev), + "Unknown message from PF (0x%x); leaving PF2VF ints disabled\n", + msg); + + return false; +} diff --git a/drivers/crypto/qat/qat_common/adf_vf_isr.c b/drivers/crypto/qat/qat_common/adf_vf_isr.c index db5e7abbe5f33..b17040b8a4b9f 100644 --- a/drivers/crypto/qat/qat_common/adf_vf_isr.c +++ b/drivers/crypto/qat/qat_common/adf_vf_isr.c @@ -85,78 +85,37 @@ static void adf_dev_stop_async(struct work_struct *work) kfree(stop_data); } -static void adf_pf2vf_bh_handler(void *data) +int adf_pf2vf_handle_pf_restarting(struct adf_accel_dev *accel_dev) { - struct adf_accel_dev *accel_dev = data; - struct adf_hw_device_data *hw_data = accel_dev->hw_device; - struct adf_bar *pmisc = - &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)]; - void __iomem *pmisc_bar_addr = pmisc->virt_addr; - u32 msg; - - /* Read the message from PF */ - msg = ADF_CSR_RD(pmisc_bar_addr, hw_data->get_pf2vf_offset(0)); - if (!(msg & ADF_PF2VF_INT)) { - dev_info(&GET_DEV(accel_dev), - "Spurious PF2VF interrupt, msg %X. Ignored\n", msg); - goto out; - } + struct adf_vf_stop_data *stop_data; - if (!(msg & ADF_PF2VF_MSGORIGIN_SYSTEM)) - /* Ignore legacy non-system (non-kernel) PF2VF messages */ - goto err; - - switch ((msg & ADF_PF2VF_MSGTYPE_MASK) >> ADF_PF2VF_MSGTYPE_SHIFT) { - case ADF_PF2VF_MSGTYPE_RESTARTING: { - struct adf_vf_stop_data *stop_data; - - dev_dbg(&GET_DEV(accel_dev), - "Restarting msg received from PF 0x%x\n", msg); - - clear_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status); - - stop_data = kzalloc(sizeof(*stop_data), GFP_ATOMIC); - if (!stop_data) { - dev_err(&GET_DEV(accel_dev), - "Couldn't schedule stop for vf_%d\n", - accel_dev->accel_id); - return; - } - stop_data->accel_dev = accel_dev; - INIT_WORK(&stop_data->work, adf_dev_stop_async); - queue_work(adf_vf_stop_wq, &stop_data->work); - /* To ack, clear the PF2VFINT bit */ - msg &= ~ADF_PF2VF_INT; - ADF_CSR_WR(pmisc_bar_addr, hw_data->get_pf2vf_offset(0), msg); - return; - } - case ADF_PF2VF_MSGTYPE_VERSION_RESP: - dev_dbg(&GET_DEV(accel_dev), - "Version resp received from PF 0x%x\n", msg); - accel_dev->vf.pf_version = - (msg & ADF_PF2VF_VERSION_RESP_VERS_MASK) >> - ADF_PF2VF_VERSION_RESP_VERS_SHIFT; - accel_dev->vf.compatible = - (msg & ADF_PF2VF_VERSION_RESP_RESULT_MASK) >> - ADF_PF2VF_VERSION_RESP_RESULT_SHIFT; - complete(&accel_dev->vf.iov_msg_completion); - break; - default: - goto err; + clear_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status); + stop_data = kzalloc(sizeof(*stop_data), GFP_ATOMIC); + if (!stop_data) { + dev_err(&GET_DEV(accel_dev), + "Couldn't schedule stop for vf_%d\n", + accel_dev->accel_id); + return -ENOMEM; } + stop_data->accel_dev = accel_dev; + INIT_WORK(&stop_data->work, adf_dev_stop_async); + queue_work(adf_vf_stop_wq, &stop_data->work); - /* To ack, clear the PF2VFINT bit */ - msg &= ~ADF_PF2VF_INT; - ADF_CSR_WR(pmisc_bar_addr, hw_data->get_pf2vf_offset(0), msg); + return 0; +} + +static void adf_pf2vf_bh_handler(void *data) +{ + struct adf_accel_dev *accel_dev = data; + bool ret; + + ret = adf_recv_and_handle_pf2vf_msg(accel_dev); + if (ret) + /* Re-enable PF2VF interrupts */ + adf_enable_pf2vf_interrupts(accel_dev); -out: - /* Re-enable PF2VF interrupts */ - adf_enable_pf2vf_interrupts(accel_dev); return; -err: - dev_err(&GET_DEV(accel_dev), - "Unknown message from PF (0x%x); leaving PF2VF ints disabled\n", - msg); + } static int adf_setup_pf2vf_bh(struct adf_accel_dev *accel_dev) -- GitLab From 720aa72a77f402a8d33ad1ddef72a4bf6e973fdd Mon Sep 17 00:00:00 2001 From: Marco Chiappero Date: Wed, 17 Nov 2021 14:30:39 +0000 Subject: [PATCH 0178/1112] crypto: qat - move interrupt code out of the PFVF handler Move the interrupt handling call from the PF specific protocol file, adf_pf2vf_msg.c, to adf_sriov.c to maintain the PFVF files focused on the protocol handling. The function adf_vf2pf_req_hndl() has been renamed as adf_recv_and_handle_vf2pf_msg() to reflect its actual purpose and maintain consistency with the VF side. This function now returns a boolean indicating to the caller if interrupts need to be re-enabled or not. Signed-off-by: Marco Chiappero Co-developed-by: Giovanni Cabiddu Signed-off-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_common_drv.h | 2 +- drivers/crypto/qat/qat_common/adf_pf2vf_msg.c | 15 ++++++--------- drivers/crypto/qat/qat_common/adf_sriov.c | 10 +++++++++- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/crypto/qat/qat_common/adf_common_drv.h b/drivers/crypto/qat/qat_common/adf_common_drv.h index 56ee2d5a6b370..db9d045e6a062 100644 --- a/drivers/crypto/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/qat/qat_common/adf_common_drv.h @@ -64,7 +64,6 @@ void adf_dev_shutdown(struct adf_accel_dev *accel_dev); void adf_pf2vf_notify_restarting(struct adf_accel_dev *accel_dev); int adf_enable_vf2pf_comms(struct adf_accel_dev *accel_dev); -void adf_vf2pf_req_hndl(struct adf_accel_vf_info *vf_info); void adf_devmgr_update_class_index(struct adf_hw_device_data *hw_data); void adf_clean_vf_map(bool); @@ -196,6 +195,7 @@ void adf_disable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask); bool adf_recv_and_handle_pf2vf_msg(struct adf_accel_dev *accel_dev); +bool adf_recv_and_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr); int adf_pf2vf_handle_pf_restarting(struct adf_accel_dev *accel_dev); int adf_enable_pf2vf_comms(struct adf_accel_dev *accel_dev); void adf_enable_pf2vf_interrupts(struct adf_accel_dev *accel_dev); diff --git a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c index d0492530c84ab..796301e9fe5bc 100644 --- a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c +++ b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c @@ -178,21 +178,21 @@ static int adf_send_vf2pf_req(struct adf_accel_dev *accel_dev, u32 msg) return 0; } -void adf_vf2pf_req_hndl(struct adf_accel_vf_info *vf_info) +bool adf_recv_and_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr) { - struct adf_accel_dev *accel_dev = vf_info->accel_dev; + struct adf_accel_vf_info *vf_info = &accel_dev->pf.vf_info[vf_nr]; struct adf_hw_device_data *hw_data = accel_dev->hw_device; int bar_id = hw_data->get_misc_bar_id(hw_data); struct adf_bar *pmisc = &GET_BARS(accel_dev)[bar_id]; void __iomem *pmisc_addr = pmisc->virt_addr; - u32 msg, resp = 0, vf_nr = vf_info->vf_nr; + u32 msg, resp = 0; /* Read message from the VF */ msg = ADF_CSR_RD(pmisc_addr, hw_data->get_pf2vf_offset(vf_nr)); if (!(msg & ADF_VF2PF_INT)) { dev_info(&GET_DEV(accel_dev), "Spurious VF2PF interrupt, msg %X. Ignored\n", msg); - goto out; + return true; } /* To ACK, clear the VF2PFINT bit */ @@ -277,14 +277,11 @@ void adf_vf2pf_req_hndl(struct adf_accel_vf_info *vf_info) if (resp && adf_send_pf2vf_msg(accel_dev, vf_nr, resp)) dev_err(&GET_DEV(accel_dev), "Failed to send response to VF\n"); -out: - /* re-enable interrupt on PF from this VF */ - adf_enable_vf2pf_interrupts(accel_dev, (1 << vf_nr)); - - return; + return true; err: dev_dbg(&GET_DEV(accel_dev), "Unknown message from VF%d (0x%x);\n", vf_nr + 1, msg); + return false; } void adf_pf2vf_notify_restarting(struct adf_accel_dev *accel_dev) diff --git a/drivers/crypto/qat/qat_common/adf_sriov.c b/drivers/crypto/qat/qat_common/adf_sriov.c index 90ec057f9183d..b1a814ac1d679 100644 --- a/drivers/crypto/qat/qat_common/adf_sriov.c +++ b/drivers/crypto/qat/qat_common/adf_sriov.c @@ -19,8 +19,16 @@ static void adf_iov_send_resp(struct work_struct *work) { struct adf_pf2vf_resp *pf2vf_resp = container_of(work, struct adf_pf2vf_resp, pf2vf_resp_work); + struct adf_accel_vf_info *vf_info = pf2vf_resp->vf_info; + struct adf_accel_dev *accel_dev = vf_info->accel_dev; + u32 vf_nr = vf_info->vf_nr; + bool ret; + + ret = adf_recv_and_handle_vf2pf_msg(accel_dev, vf_nr); + if (ret) + /* re-enable interrupt on PF from this VF */ + adf_enable_vf2pf_interrupts(accel_dev, 1 << vf_nr); - adf_vf2pf_req_hndl(pf2vf_resp->vf_info); kfree(pf2vf_resp); } -- GitLab From 956125e21f460ef94660019b6ec9de3f835f93ab Mon Sep 17 00:00:00 2001 From: Giovanni Cabiddu Date: Wed, 17 Nov 2021 14:30:40 +0000 Subject: [PATCH 0179/1112] crypto: qat - change PFVF ACK behaviour Change the PFVF receipt flow on the VF side to read, ack and handle the message instead of read, handle and ack. This is done for (1) consistency with the PF side, see the function adf_recv_and_handle_vf2pf_msg() in adf_pf2vf_msg.c, and (2) performance reasons, to avoid keeping the CSR busy while parsing the message. In addition, do not ACK PFVF legacy messages, as this driver is not capable of handling PFVF legacy messages. If a PFVF message with MSGORIGIN not set is received, do nothing. Signed-off-by: Giovanni Cabiddu Reviewed-by: Marco Chiappero Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_pf2vf_msg.c | 8 ++++---- drivers/crypto/qat/qat_common/adf_vf2pf_msg.c | 7 ++++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c index 796301e9fe5bc..4922ee2a2a081 100644 --- a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c +++ b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c @@ -195,14 +195,14 @@ bool adf_recv_and_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr) return true; } - /* To ACK, clear the VF2PFINT bit */ - msg &= ~ADF_VF2PF_INT; - ADF_CSR_WR(pmisc_addr, hw_data->get_pf2vf_offset(vf_nr), msg); - if (!(msg & ADF_VF2PF_MSGORIGIN_SYSTEM)) /* Ignore legacy non-system (non-kernel) VF2PF messages */ goto err; + /* To ACK, clear the VF2PFINT bit */ + msg &= ~ADF_VF2PF_INT; + ADF_CSR_WR(pmisc_addr, hw_data->get_pf2vf_offset(vf_nr), msg); + switch ((msg & ADF_VF2PF_MSGTYPE_MASK) >> ADF_VF2PF_MSGTYPE_SHIFT) { case ADF_VF2PF_MSGTYPE_COMPAT_VER_REQ: { diff --git a/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c b/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c index 064477fcb5fb6..a6eaf93d5462b 100644 --- a/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c +++ b/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c @@ -69,6 +69,10 @@ bool adf_recv_and_handle_pf2vf_msg(struct adf_accel_dev *accel_dev) /* Ignore legacy non-system (non-kernel) PF2VF messages */ goto err; + /* To ack, clear the PF2VFINT bit */ + msg &= ~ADF_PF2VF_INT; + ADF_CSR_WR(pmisc_bar_addr, offset, msg); + switch ((msg & ADF_PF2VF_MSGTYPE_MASK) >> ADF_PF2VF_MSGTYPE_SHIFT) { case ADF_PF2VF_MSGTYPE_RESTARTING: dev_dbg(&GET_DEV(accel_dev), @@ -93,9 +97,6 @@ bool adf_recv_and_handle_pf2vf_msg(struct adf_accel_dev *accel_dev) goto err; } - /* To ack, clear the PF2VFINT bit */ - msg &= ~ADF_PF2VF_INT; - ADF_CSR_WR(pmisc_bar_addr, offset, msg); return ret; err: -- GitLab From 04cf47872c7edde7a11c634aef04b1dbcf9c26fa Mon Sep 17 00:00:00 2001 From: Giovanni Cabiddu Date: Wed, 17 Nov 2021 14:30:41 +0000 Subject: [PATCH 0180/1112] crypto: qat - re-enable interrupts for legacy PFVF messages If a PFVF message with MSGORIGIN_SYSTEM not set is received, re-enable interrupts allowing the processing of new messages. This is to simplify the refactoring of the recv function in a subsequent patch. Signed-off-by: Giovanni Cabiddu Reviewed-by: Marco Chiappero Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_pf2vf_msg.c | 2 +- drivers/crypto/qat/qat_common/adf_vf2pf_msg.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c index 4922ee2a2a081..296f54805e332 100644 --- a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c +++ b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c @@ -197,7 +197,7 @@ bool adf_recv_and_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr) if (!(msg & ADF_VF2PF_MSGORIGIN_SYSTEM)) /* Ignore legacy non-system (non-kernel) VF2PF messages */ - goto err; + return true; /* To ACK, clear the VF2PFINT bit */ msg &= ~ADF_VF2PF_INT; diff --git a/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c b/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c index a6eaf93d5462b..e383232b06856 100644 --- a/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c +++ b/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c @@ -67,7 +67,7 @@ bool adf_recv_and_handle_pf2vf_msg(struct adf_accel_dev *accel_dev) if (!(msg & ADF_PF2VF_MSGORIGIN_SYSTEM)) /* Ignore legacy non-system (non-kernel) PF2VF messages */ - goto err; + return true; /* To ack, clear the PF2VFINT bit */ msg &= ~ADF_PF2VF_INT; -- GitLab From bd59b769ddac0db24d2d43ca5e40b29a58d7b205 Mon Sep 17 00:00:00 2001 From: Marco Chiappero Date: Wed, 17 Nov 2021 14:30:42 +0000 Subject: [PATCH 0181/1112] crypto: qat - split PFVF message decoding from handling Refactor the receive and handle logic to separate the parsing and handling of the PFVF message from the initial retrieval and ACK. This is to allow the intoduction of the recv function in a subsequent patch. Signed-off-by: Marco Chiappero Co-developed-by: Giovanni Cabiddu Signed-off-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_pf2vf_msg.c | 68 ++++++++++++------- drivers/crypto/qat/qat_common/adf_vf2pf_msg.c | 62 ++++++++--------- 2 files changed, 71 insertions(+), 59 deletions(-) diff --git a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c index 296f54805e332..201744825e23a 100644 --- a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c +++ b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c @@ -178,30 +178,12 @@ static int adf_send_vf2pf_req(struct adf_accel_dev *accel_dev, u32 msg) return 0; } -bool adf_recv_and_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr) +static int adf_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr, + u32 msg, u32 *response) { struct adf_accel_vf_info *vf_info = &accel_dev->pf.vf_info[vf_nr]; struct adf_hw_device_data *hw_data = accel_dev->hw_device; - int bar_id = hw_data->get_misc_bar_id(hw_data); - struct adf_bar *pmisc = &GET_BARS(accel_dev)[bar_id]; - void __iomem *pmisc_addr = pmisc->virt_addr; - u32 msg, resp = 0; - - /* Read message from the VF */ - msg = ADF_CSR_RD(pmisc_addr, hw_data->get_pf2vf_offset(vf_nr)); - if (!(msg & ADF_VF2PF_INT)) { - dev_info(&GET_DEV(accel_dev), - "Spurious VF2PF interrupt, msg %X. Ignored\n", msg); - return true; - } - - if (!(msg & ADF_VF2PF_MSGORIGIN_SYSTEM)) - /* Ignore legacy non-system (non-kernel) VF2PF messages */ - return true; - - /* To ACK, clear the VF2PFINT bit */ - msg &= ~ADF_VF2PF_INT; - ADF_CSR_WR(pmisc_addr, hw_data->get_pf2vf_offset(vf_nr), msg); + u32 resp = 0; switch ((msg & ADF_VF2PF_MSGTYPE_MASK) >> ADF_VF2PF_MSGTYPE_SHIFT) { case ADF_VF2PF_MSGTYPE_COMPAT_VER_REQ: @@ -271,17 +253,51 @@ bool adf_recv_and_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr) } break; default: - goto err; + dev_dbg(&GET_DEV(accel_dev), "Unknown message from VF%d (0x%x)\n", + vf_nr + 1, msg); + return -ENOMSG; + } + + *response = resp; + + return 0; +} + +bool adf_recv_and_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr) +{ + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + int bar_id = hw_data->get_misc_bar_id(hw_data); + struct adf_bar *pmisc = &GET_BARS(accel_dev)[bar_id]; + void __iomem *pmisc_addr = pmisc->virt_addr; + u32 msg, resp = 0; + + /* Read message from the VF */ + msg = ADF_CSR_RD(pmisc_addr, hw_data->get_pf2vf_offset(vf_nr)); + if (!(msg & ADF_VF2PF_INT)) { + dev_info(&GET_DEV(accel_dev), + "Spurious VF2PF interrupt, msg %X. Ignored\n", msg); + return true; + } + + /* Ignore legacy non-system (non-kernel) VF2PF messages */ + if (!(msg & ADF_VF2PF_MSGORIGIN_SYSTEM)) { + dev_dbg(&GET_DEV(accel_dev), + "Ignored non-system message from VF%d (0x%x);\n", + vf_nr + 1, msg); + return true; } + /* To ACK, clear the VF2PFINT bit */ + msg &= ~ADF_VF2PF_INT; + ADF_CSR_WR(pmisc_addr, hw_data->get_pf2vf_offset(vf_nr), msg); + + if (adf_handle_vf2pf_msg(accel_dev, vf_nr, msg, &resp)) + return false; + if (resp && adf_send_pf2vf_msg(accel_dev, vf_nr, resp)) dev_err(&GET_DEV(accel_dev), "Failed to send response to VF\n"); return true; -err: - dev_dbg(&GET_DEV(accel_dev), "Unknown message from VF%d (0x%x);\n", - vf_nr + 1, msg); - return false; } void adf_pf2vf_notify_restarting(struct adf_accel_dev *accel_dev) diff --git a/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c b/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c index e383232b06856..01a6e68f256b6 100644 --- a/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c +++ b/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c @@ -47,6 +47,34 @@ void adf_vf2pf_notify_shutdown(struct adf_accel_dev *accel_dev) } EXPORT_SYMBOL_GPL(adf_vf2pf_notify_shutdown); +static bool adf_handle_pf2vf_msg(struct adf_accel_dev *accel_dev, u32 msg) +{ + switch ((msg & ADF_PF2VF_MSGTYPE_MASK) >> ADF_PF2VF_MSGTYPE_SHIFT) { + case ADF_PF2VF_MSGTYPE_RESTARTING: + dev_dbg(&GET_DEV(accel_dev), + "Restarting msg received from PF 0x%x\n", msg); + + adf_pf2vf_handle_pf_restarting(accel_dev); + return false; + case ADF_PF2VF_MSGTYPE_VERSION_RESP: + dev_dbg(&GET_DEV(accel_dev), + "Version resp received from PF 0x%x\n", msg); + accel_dev->vf.pf_version = + (msg & ADF_PF2VF_VERSION_RESP_VERS_MASK) >> + ADF_PF2VF_VERSION_RESP_VERS_SHIFT; + accel_dev->vf.compatible = + (msg & ADF_PF2VF_VERSION_RESP_RESULT_MASK) >> + ADF_PF2VF_VERSION_RESP_RESULT_SHIFT; + complete(&accel_dev->vf.iov_msg_completion); + return true; + default: + dev_err(&GET_DEV(accel_dev), + "Unknown PF2VF message(0x%x)\n", msg); + } + + return false; +} + bool adf_recv_and_handle_pf2vf_msg(struct adf_accel_dev *accel_dev) { struct adf_hw_device_data *hw_data = accel_dev->hw_device; @@ -54,7 +82,6 @@ bool adf_recv_and_handle_pf2vf_msg(struct adf_accel_dev *accel_dev) &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)]; void __iomem *pmisc_bar_addr = pmisc->virt_addr; u32 offset = hw_data->get_pf2vf_offset(0); - bool ret; u32 msg; /* Read the message from PF */ @@ -73,36 +100,5 @@ bool adf_recv_and_handle_pf2vf_msg(struct adf_accel_dev *accel_dev) msg &= ~ADF_PF2VF_INT; ADF_CSR_WR(pmisc_bar_addr, offset, msg); - switch ((msg & ADF_PF2VF_MSGTYPE_MASK) >> ADF_PF2VF_MSGTYPE_SHIFT) { - case ADF_PF2VF_MSGTYPE_RESTARTING: - dev_dbg(&GET_DEV(accel_dev), - "Restarting msg received from PF 0x%x\n", msg); - - adf_pf2vf_handle_pf_restarting(accel_dev); - ret = false; - break; - case ADF_PF2VF_MSGTYPE_VERSION_RESP: - dev_dbg(&GET_DEV(accel_dev), - "Version resp received from PF 0x%x\n", msg); - accel_dev->vf.pf_version = - (msg & ADF_PF2VF_VERSION_RESP_VERS_MASK) >> - ADF_PF2VF_VERSION_RESP_VERS_SHIFT; - accel_dev->vf.compatible = - (msg & ADF_PF2VF_VERSION_RESP_RESULT_MASK) >> - ADF_PF2VF_VERSION_RESP_RESULT_SHIFT; - complete(&accel_dev->vf.iov_msg_completion); - ret = true; - break; - default: - goto err; - } - - return ret; - -err: - dev_err(&GET_DEV(accel_dev), - "Unknown message from PF (0x%x); leaving PF2VF ints disabled\n", - msg); - - return false; + return adf_handle_pf2vf_msg(accel_dev, msg); } -- GitLab From 1d6133123fb2626499e0e0a9d62e39bcdc5e593b Mon Sep 17 00:00:00 2001 From: Marco Chiappero Date: Wed, 17 Nov 2021 14:30:43 +0000 Subject: [PATCH 0182/1112] crypto: qat - handle retries due to collisions in adf_iov_putmsg() Rework __adf_iov_putmsg() to handle retries due to collisions internally, removing the need for an external retry loop. The functions __adf_iov_putmsg() and adf_iov_putmsg() have been merged together maintaining the adf_iov_putmsg() name. This will allow to use this function only for GEN2 devices, since collision are peculiar of this generation and therefore should be confined to the actual implementation of the transport/medium access. Note that now adf_iov_putmsg() will retry to send a message only in case of collisions and will now fail if an ACK is not received from the remote function. Signed-off-by: Marco Chiappero Co-developed-by: Giovanni Cabiddu Signed-off-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_pf2vf_msg.c | 52 +++++++------------ 1 file changed, 19 insertions(+), 33 deletions(-) diff --git a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c index 201744825e23a..d98e3639c9d28 100644 --- a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c +++ b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c @@ -14,7 +14,7 @@ ADF_PFVF_MSG_ACK_MAX_RETRY + \ ADF_PFVF_MSG_COLLISION_DETECT_DELAY) -static int __adf_iov_putmsg(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr) +static int adf_iov_putmsg(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr) { struct adf_accel_pci *pci_info = &accel_dev->accel_pci_dev; struct adf_hw_device_data *hw_data = accel_dev->hw_device; @@ -24,8 +24,9 @@ static int __adf_iov_putmsg(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr) u32 local_in_use_mask, local_in_use_pattern; u32 remote_in_use_mask, remote_in_use_pattern; struct mutex *lock; /* lock preventing concurrent acces of CSR */ + unsigned int retries = ADF_PFVF_MSG_MAX_RETRIES; u32 int_bit; - int ret = 0; + int ret; if (accel_dev->is_vf) { pf2vf_offset = hw_data->get_pf2vf_offset(0); @@ -45,20 +46,22 @@ static int __adf_iov_putmsg(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr) int_bit = ADF_PF2VF_INT; } + msg &= ~local_in_use_mask; + msg |= local_in_use_pattern; + mutex_lock(lock); +start: + ret = 0; + /* Check if the PFVF CSR is in use by remote function */ val = ADF_CSR_RD(pmisc_bar_addr, pf2vf_offset); if ((val & remote_in_use_mask) == remote_in_use_pattern) { dev_dbg(&GET_DEV(accel_dev), "PFVF CSR in use by remote function\n"); - ret = -EBUSY; - goto out; + goto retry; } - msg &= ~local_in_use_mask; - msg |= local_in_use_pattern; - /* Attempt to get ownership of the PFVF CSR */ ADF_CSR_WR(pmisc_bar_addr, pf2vf_offset, msg | int_bit); @@ -77,8 +80,7 @@ static int __adf_iov_putmsg(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr) if (val != msg) { dev_dbg(&GET_DEV(accel_dev), "Collision - PFVF CSR overwritten by remote function\n"); - ret = -EIO; - goto out; + goto retry; } /* Finished with the PFVF CSR; relinquish it and leave msg in CSR */ @@ -86,31 +88,15 @@ static int __adf_iov_putmsg(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr) out: mutex_unlock(lock); return ret; -} -/** - * adf_iov_putmsg() - send PFVF message - * @accel_dev: Pointer to acceleration device. - * @msg: Message to send - * @vf_nr: VF number to which the message will be sent if on PF, ignored - * otherwise - * - * Function sends a message through the PFVF channel - * - * Return: 0 on success, error code otherwise. - */ -static int adf_iov_putmsg(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr) -{ - u32 count = 0; - int ret; - - do { - ret = __adf_iov_putmsg(accel_dev, msg, vf_nr); - if (ret) - msleep(ADF_PFVF_MSG_RETRY_DELAY); - } while (ret && (count++ < ADF_PFVF_MSG_MAX_RETRIES)); - - return ret; +retry: + if (--retries) { + msleep(ADF_PFVF_MSG_RETRY_DELAY); + goto start; + } else { + ret = -EBUSY; + goto out; + } } /** -- GitLab From b85bd9457dc302749411a9b43f78fd493499f3ef Mon Sep 17 00:00:00 2001 From: Marco Chiappero Date: Wed, 17 Nov 2021 14:30:44 +0000 Subject: [PATCH 0183/1112] crypto: qat - relocate PFVF PF related logic Move device specific PFVF logic related to the PF to the newly created adf_gen2_pfvf.c. This refactory is done to isolate the GEN2 PFVF code into its own file in preparation for the introduction of support for PFVF for GEN4 devices. In addition the PFVF PF logic for dh895xcc has been isolated to adf_dh895xcc_hw_data.c. Signed-off-by: Marco Chiappero Co-developed-by: Giovanni Cabiddu Signed-off-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- .../crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c | 1 + .../crypto/qat/qat_c62x/adf_c62x_hw_data.c | 1 + drivers/crypto/qat/qat_common/Makefile | 3 +- .../crypto/qat/qat_common/adf_gen2_hw_data.c | 48 ---------------- .../crypto/qat/qat_common/adf_gen2_hw_data.h | 13 ----- drivers/crypto/qat/qat_common/adf_gen2_pfvf.c | 57 +++++++++++++++++++ drivers/crypto/qat/qat_common/adf_gen2_pfvf.h | 19 +++++++ .../qat/qat_dh895xcc/adf_dh895xcc_hw_data.c | 28 ++++++--- .../qat/qat_dh895xcc/adf_dh895xcc_hw_data.h | 2 + 9 files changed, 103 insertions(+), 69 deletions(-) create mode 100644 drivers/crypto/qat/qat_common/adf_gen2_pfvf.c create mode 100644 drivers/crypto/qat/qat_common/adf_gen2_pfvf.h diff --git a/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c b/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c index 1fa690219d925..0bc528004f79d 100644 --- a/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c +++ b/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "adf_c3xxx_hw_data.h" #include "icp_qat_hw.h" diff --git a/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c b/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c index 0613db0776896..9303f2dbcaf9e 100644 --- a/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c +++ b/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "adf_c62x_hw_data.h" #include "icp_qat_hw.h" diff --git a/drivers/crypto/qat/qat_common/Makefile b/drivers/crypto/qat/qat_common/Makefile index 9c57abdf56b78..3874e427d1f7e 100644 --- a/drivers/crypto/qat/qat_common/Makefile +++ b/drivers/crypto/qat/qat_common/Makefile @@ -16,7 +16,8 @@ intel_qat-objs := adf_cfg.o \ qat_algs.o \ qat_asym_algs.o \ qat_uclo.o \ - qat_hal.o + qat_hal.o \ + adf_gen2_pfvf.o intel_qat-$(CONFIG_DEBUG_FS) += adf_transport_debug.o intel_qat-$(CONFIG_PCI_IOV) += adf_sriov.o adf_pf2vf_msg.o \ diff --git a/drivers/crypto/qat/qat_common/adf_gen2_hw_data.c b/drivers/crypto/qat/qat_common/adf_gen2_hw_data.c index 262bdc05dab4e..3b48fdaaff6d5 100644 --- a/drivers/crypto/qat/qat_common/adf_gen2_hw_data.c +++ b/drivers/crypto/qat/qat_common/adf_gen2_hw_data.c @@ -4,54 +4,6 @@ #include "icp_qat_hw.h" #include -#define ADF_GEN2_PF2VF_OFFSET(i) (0x3A000 + 0x280 + ((i) * 0x04)) - -u32 adf_gen2_get_pf2vf_offset(u32 i) -{ - return ADF_GEN2_PF2VF_OFFSET(i); -} -EXPORT_SYMBOL_GPL(adf_gen2_get_pf2vf_offset); - -u32 adf_gen2_get_vf2pf_sources(void __iomem *pmisc_addr) -{ - u32 errsou3, errmsk3, vf_int_mask; - - /* Get the interrupt sources triggered by VFs */ - errsou3 = ADF_CSR_RD(pmisc_addr, ADF_GEN2_ERRSOU3); - vf_int_mask = ADF_GEN2_ERR_REG_VF2PF(errsou3); - - /* To avoid adding duplicate entries to work queue, clear - * vf_int_mask_sets bits that are already masked in ERRMSK register. - */ - errmsk3 = ADF_CSR_RD(pmisc_addr, ADF_GEN2_ERRMSK3); - vf_int_mask &= ~ADF_GEN2_ERR_REG_VF2PF(errmsk3); - - return vf_int_mask; -} -EXPORT_SYMBOL_GPL(adf_gen2_get_vf2pf_sources); - -void adf_gen2_enable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask) -{ - /* Enable VF2PF Messaging Ints - VFs 0 through 15 per vf_mask[15:0] */ - if (vf_mask & 0xFFFF) { - u32 val = ADF_CSR_RD(pmisc_addr, ADF_GEN2_ERRMSK3) - & ~ADF_GEN2_ERR_MSK_VF2PF(vf_mask); - ADF_CSR_WR(pmisc_addr, ADF_GEN2_ERRMSK3, val); - } -} -EXPORT_SYMBOL_GPL(adf_gen2_enable_vf2pf_interrupts); - -void adf_gen2_disable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask) -{ - /* Disable VF2PF interrupts for VFs 0 through 15 per vf_mask[15:0] */ - if (vf_mask & 0xFFFF) { - u32 val = ADF_CSR_RD(pmisc_addr, ADF_GEN2_ERRMSK3) - | ADF_GEN2_ERR_MSK_VF2PF(vf_mask); - ADF_CSR_WR(pmisc_addr, ADF_GEN2_ERRMSK3, val); - } -} -EXPORT_SYMBOL_GPL(adf_gen2_disable_vf2pf_interrupts); - u32 adf_gen2_get_num_accels(struct adf_hw_device_data *self) { if (!self || !self->accel_mask) diff --git a/drivers/crypto/qat/qat_common/adf_gen2_hw_data.h b/drivers/crypto/qat/qat_common/adf_gen2_hw_data.h index c169d704097de..448c97f740e7c 100644 --- a/drivers/crypto/qat/qat_common/adf_gen2_hw_data.h +++ b/drivers/crypto/qat/qat_common/adf_gen2_hw_data.h @@ -136,19 +136,6 @@ do { \ #define ADF_GEN2_CERRSSMSH(i) ((i) * 0x4000 + 0x10) #define ADF_GEN2_ERRSSMSH_EN BIT(3) - /* VF2PF interrupts */ -#define ADF_GEN2_ERRSOU3 (0x3A000 + 0x0C) -#define ADF_GEN2_ERRSOU5 (0x3A000 + 0xD8) -#define ADF_GEN2_ERRMSK3 (0x3A000 + 0x1C) -#define ADF_GEN2_ERRMSK5 (0x3A000 + 0xDC) -#define ADF_GEN2_ERR_REG_VF2PF(vf_src) (((vf_src) & 0x01FFFE00) >> 9) -#define ADF_GEN2_ERR_MSK_VF2PF(vf_mask) (((vf_mask) & 0xFFFF) << 9) - -u32 adf_gen2_get_pf2vf_offset(u32 i); -u32 adf_gen2_get_vf2pf_sources(void __iomem *pmisc_bar); -void adf_gen2_enable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask); -void adf_gen2_disable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask); - u32 adf_gen2_get_num_accels(struct adf_hw_device_data *self); u32 adf_gen2_get_num_aes(struct adf_hw_device_data *self); void adf_gen2_enable_error_correction(struct adf_accel_dev *accel_dev); diff --git a/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c b/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c new file mode 100644 index 0000000000000..d4d79419daaa4 --- /dev/null +++ b/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) +/* Copyright(c) 2021 Intel Corporation */ +#include +#include "adf_accel_devices.h" +#include "adf_gen2_pfvf.h" + + /* VF2PF interrupts */ +#define ADF_GEN2_ERR_REG_VF2PF(vf_src) (((vf_src) & 0x01FFFE00) >> 9) +#define ADF_GEN2_ERR_MSK_VF2PF(vf_mask) (((vf_mask) & 0xFFFF) << 9) + +#define ADF_GEN2_PF2VF_OFFSET(i) (0x3A000 + 0x280 + ((i) * 0x04)) + +u32 adf_gen2_get_pf2vf_offset(u32 i) +{ + return ADF_GEN2_PF2VF_OFFSET(i); +} +EXPORT_SYMBOL_GPL(adf_gen2_get_pf2vf_offset); + +u32 adf_gen2_get_vf2pf_sources(void __iomem *pmisc_addr) +{ + u32 errsou3, errmsk3, vf_int_mask; + + /* Get the interrupt sources triggered by VFs */ + errsou3 = ADF_CSR_RD(pmisc_addr, ADF_GEN2_ERRSOU3); + vf_int_mask = ADF_GEN2_ERR_REG_VF2PF(errsou3); + + /* To avoid adding duplicate entries to work queue, clear + * vf_int_mask_sets bits that are already masked in ERRMSK register. + */ + errmsk3 = ADF_CSR_RD(pmisc_addr, ADF_GEN2_ERRMSK3); + vf_int_mask &= ~ADF_GEN2_ERR_REG_VF2PF(errmsk3); + + return vf_int_mask; +} +EXPORT_SYMBOL_GPL(adf_gen2_get_vf2pf_sources); + +void adf_gen2_enable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask) +{ + /* Enable VF2PF Messaging Ints - VFs 0 through 15 per vf_mask[15:0] */ + if (vf_mask & 0xFFFF) { + u32 val = ADF_CSR_RD(pmisc_addr, ADF_GEN2_ERRMSK3) + & ~ADF_GEN2_ERR_MSK_VF2PF(vf_mask); + ADF_CSR_WR(pmisc_addr, ADF_GEN2_ERRMSK3, val); + } +} +EXPORT_SYMBOL_GPL(adf_gen2_enable_vf2pf_interrupts); + +void adf_gen2_disable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask) +{ + /* Disable VF2PF interrupts for VFs 0 through 15 per vf_mask[15:0] */ + if (vf_mask & 0xFFFF) { + u32 val = ADF_CSR_RD(pmisc_addr, ADF_GEN2_ERRMSK3) + | ADF_GEN2_ERR_MSK_VF2PF(vf_mask); + ADF_CSR_WR(pmisc_addr, ADF_GEN2_ERRMSK3, val); + } +} +EXPORT_SYMBOL_GPL(adf_gen2_disable_vf2pf_interrupts); diff --git a/drivers/crypto/qat/qat_common/adf_gen2_pfvf.h b/drivers/crypto/qat/qat_common/adf_gen2_pfvf.h new file mode 100644 index 0000000000000..0987e254e86b3 --- /dev/null +++ b/drivers/crypto/qat/qat_common/adf_gen2_pfvf.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) */ +/* Copyright(c) 2021 Intel Corporation */ +#ifndef ADF_GEN2_PFVF_H +#define ADF_GEN2_PFVF_H + +#include +#include "adf_accel_devices.h" + +#define ADF_GEN2_ERRSOU3 (0x3A000 + 0x0C) +#define ADF_GEN2_ERRSOU5 (0x3A000 + 0xD8) +#define ADF_GEN2_ERRMSK3 (0x3A000 + 0x1C) +#define ADF_GEN2_ERRMSK5 (0x3A000 + 0xDC) + +u32 adf_gen2_get_pf2vf_offset(u32 i); +u32 adf_gen2_get_vf2pf_sources(void __iomem *pmisc_bar); +void adf_gen2_enable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask); +void adf_gen2_disable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask); + +#endif /* ADF_GEN2_PFVF_H */ diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c index 8e2e1554dcf6a..e134385b76a8c 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c +++ b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "adf_dh895xcc_hw_data.h" #include "icp_qat_hw.h" @@ -114,14 +115,19 @@ static void adf_enable_ints(struct adf_accel_dev *accel_dev) static u32 get_vf2pf_sources(void __iomem *pmisc_bar) { - u32 errsou5, errmsk5, vf_int_mask; + u32 errsou3, errmsk3, errsou5, errmsk5, vf_int_mask; - vf_int_mask = adf_gen2_get_vf2pf_sources(pmisc_bar); + /* Get the interrupt sources triggered by VFs */ + errsou3 = ADF_CSR_RD(pmisc_bar, ADF_GEN2_ERRSOU3); + vf_int_mask = ADF_DH895XCC_ERR_REG_VF2PF_L(errsou3); - /* Get the interrupt sources triggered by VFs, but to avoid duplicates - * in the work queue, clear vf_int_mask_sets bits that are already - * masked in ERRMSK register. + /* To avoid adding duplicate entries to work queue, clear + * vf_int_mask_sets bits that are already masked in ERRMSK register. */ + errmsk3 = ADF_CSR_RD(pmisc_bar, ADF_GEN2_ERRMSK3); + vf_int_mask &= ~ADF_DH895XCC_ERR_REG_VF2PF_L(errmsk3); + + /* Do the same for ERRSOU5 */ errsou5 = ADF_CSR_RD(pmisc_bar, ADF_GEN2_ERRSOU5); errmsk5 = ADF_CSR_RD(pmisc_bar, ADF_GEN2_ERRMSK5); vf_int_mask |= ADF_DH895XCC_ERR_REG_VF2PF_U(errsou5); @@ -133,7 +139,11 @@ static u32 get_vf2pf_sources(void __iomem *pmisc_bar) static void enable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask) { /* Enable VF2PF Messaging Ints - VFs 0 through 15 per vf_mask[15:0] */ - adf_gen2_enable_vf2pf_interrupts(pmisc_addr, vf_mask); + if (vf_mask & 0xFFFF) { + u32 val = ADF_CSR_RD(pmisc_addr, ADF_GEN2_ERRMSK3) + & ~ADF_DH895XCC_ERR_MSK_VF2PF_L(vf_mask); + ADF_CSR_WR(pmisc_addr, ADF_GEN2_ERRMSK3, val); + } /* Enable VF2PF Messaging Ints - VFs 16 through 31 per vf_mask[31:16] */ if (vf_mask >> 16) { @@ -147,7 +157,11 @@ static void enable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask) static void disable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask) { /* Disable VF2PF interrupts for VFs 0 through 15 per vf_mask[15:0] */ - adf_gen2_disable_vf2pf_interrupts(pmisc_addr, vf_mask); + if (vf_mask & 0xFFFF) { + u32 val = ADF_CSR_RD(pmisc_addr, ADF_GEN2_ERRMSK3) + | ADF_DH895XCC_ERR_MSK_VF2PF_L(vf_mask); + ADF_CSR_WR(pmisc_addr, ADF_GEN2_ERRMSK3, val); + } /* Disable VF2PF interrupts for VFs 16 through 31 per vf_mask[31:16] */ if (vf_mask >> 16) { diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h index 0af34dd8708ac..aa17272a1507b 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h +++ b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h @@ -25,6 +25,8 @@ #define ADF_DH895XCC_SMIA1_MASK 0x1 /* Masks for VF2PF interrupts */ +#define ADF_DH895XCC_ERR_REG_VF2PF_L(vf_src) (((vf_src) & 0x01FFFE00) >> 9) +#define ADF_DH895XCC_ERR_MSK_VF2PF_L(vf_mask) (((vf_mask) & 0xFFFF) << 9) #define ADF_DH895XCC_ERR_REG_VF2PF_U(vf_src) (((vf_src) & 0x0000FFFF) << 16) #define ADF_DH895XCC_ERR_MSK_VF2PF_U(vf_mask) ((vf_mask) >> 16) -- GitLab From 7e00fb3f162cfb27d8ac72910d7132612f07ec9c Mon Sep 17 00:00:00 2001 From: Marco Chiappero Date: Wed, 17 Nov 2021 14:30:45 +0000 Subject: [PATCH 0184/1112] crypto: qat - relocate PFVF VF related logic Move device specific PFVF logic related to the VF to the newly created adf_gen2_pfvf.c. This refactory is done to isolate the GEN2 PFVF code into its own file in preparation for the introduction of support for PFVF for GEN4 devices. Signed-off-by: Marco Chiappero Reviewed-by: Giovanni Cabiddu Signed-off-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c | 2 +- .../crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c | 8 ++------ .../crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.h | 1 - drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c | 2 +- .../crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c | 8 ++------ .../crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.h | 1 - drivers/crypto/qat/qat_common/adf_gen2_pfvf.c | 15 +++++++++++---- drivers/crypto/qat/qat_common/adf_gen2_pfvf.h | 3 ++- .../qat/qat_dh895xcc/adf_dh895xcc_hw_data.c | 2 +- .../qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c | 8 ++------ .../qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.h | 1 - 11 files changed, 22 insertions(+), 29 deletions(-) diff --git a/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c b/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c index 0bc528004f79d..aaf8e65887b88 100644 --- a/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c +++ b/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c @@ -136,7 +136,7 @@ void adf_init_hw_data_c3xxx(struct adf_hw_device_data *hw_data) hw_data->enable_ints = adf_enable_ints; hw_data->reset_device = adf_reset_flr; hw_data->set_ssm_wdtimer = adf_gen2_set_ssm_wdtimer; - hw_data->get_pf2vf_offset = adf_gen2_get_pf2vf_offset; + hw_data->get_pf2vf_offset = adf_gen2_pf_get_pf2vf_offset; hw_data->get_vf2pf_sources = adf_gen2_get_vf2pf_sources; hw_data->enable_vf2pf_interrupts = adf_gen2_enable_vf2pf_interrupts; hw_data->disable_vf2pf_interrupts = adf_gen2_disable_vf2pf_interrupts; diff --git a/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c b/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c index 3e69b520e82fa..ee61f69a8077e 100644 --- a/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c +++ b/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "adf_c3xxxvf_hw_data.h" static struct adf_hw_device_class c3xxxiov_class = { @@ -47,11 +48,6 @@ static enum dev_sku_info get_sku(struct adf_hw_device_data *self) return DEV_SKU_VF; } -static u32 get_pf2vf_offset(u32 i) -{ - return ADF_C3XXXIOV_PF2VF_OFFSET; -} - static int adf_vf_int_noop(struct adf_accel_dev *accel_dev) { return 0; @@ -86,7 +82,7 @@ void adf_init_hw_data_c3xxxiov(struct adf_hw_device_data *hw_data) hw_data->get_num_aes = get_num_aes; hw_data->get_etr_bar_id = get_etr_bar_id; hw_data->get_misc_bar_id = get_misc_bar_id; - hw_data->get_pf2vf_offset = get_pf2vf_offset; + hw_data->get_pf2vf_offset = adf_gen2_vf_get_pf2vf_offset; hw_data->get_sku = get_sku; hw_data->enable_ints = adf_vf_void_noop; hw_data->enable_pfvf_comms = adf_enable_vf2pf_comms; diff --git a/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.h b/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.h index f5de4ce660148..6b4bf181d15bd 100644 --- a/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.h +++ b/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.h @@ -12,7 +12,6 @@ #define ADF_C3XXXIOV_TX_RINGS_MASK 0xFF #define ADF_C3XXXIOV_ETR_BAR 0 #define ADF_C3XXXIOV_ETR_MAX_BANKS 1 -#define ADF_C3XXXIOV_PF2VF_OFFSET 0x200 void adf_init_hw_data_c3xxxiov(struct adf_hw_device_data *hw_data); void adf_clean_hw_data_c3xxxiov(struct adf_hw_device_data *hw_data); diff --git a/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c b/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c index 9303f2dbcaf9e..0d694c7137975 100644 --- a/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c +++ b/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c @@ -138,7 +138,7 @@ void adf_init_hw_data_c62x(struct adf_hw_device_data *hw_data) hw_data->enable_ints = adf_enable_ints; hw_data->reset_device = adf_reset_flr; hw_data->set_ssm_wdtimer = adf_gen2_set_ssm_wdtimer; - hw_data->get_pf2vf_offset = adf_gen2_get_pf2vf_offset; + hw_data->get_pf2vf_offset = adf_gen2_pf_get_pf2vf_offset; hw_data->get_vf2pf_sources = adf_gen2_get_vf2pf_sources; hw_data->enable_vf2pf_interrupts = adf_gen2_enable_vf2pf_interrupts; hw_data->disable_vf2pf_interrupts = adf_gen2_disable_vf2pf_interrupts; diff --git a/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c b/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c index 3bee3e4673636..407f3beee43c0 100644 --- a/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c +++ b/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "adf_c62xvf_hw_data.h" static struct adf_hw_device_class c62xiov_class = { @@ -47,11 +48,6 @@ static enum dev_sku_info get_sku(struct adf_hw_device_data *self) return DEV_SKU_VF; } -static u32 get_pf2vf_offset(u32 i) -{ - return ADF_C62XIOV_PF2VF_OFFSET; -} - static int adf_vf_int_noop(struct adf_accel_dev *accel_dev) { return 0; @@ -86,7 +82,7 @@ void adf_init_hw_data_c62xiov(struct adf_hw_device_data *hw_data) hw_data->get_num_aes = get_num_aes; hw_data->get_etr_bar_id = get_etr_bar_id; hw_data->get_misc_bar_id = get_misc_bar_id; - hw_data->get_pf2vf_offset = get_pf2vf_offset; + hw_data->get_pf2vf_offset = adf_gen2_vf_get_pf2vf_offset; hw_data->get_sku = get_sku; hw_data->enable_ints = adf_vf_void_noop; hw_data->enable_pfvf_comms = adf_enable_vf2pf_comms; diff --git a/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.h b/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.h index 794778c486782..a1a62c003ebf1 100644 --- a/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.h +++ b/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.h @@ -12,7 +12,6 @@ #define ADF_C62XIOV_TX_RINGS_MASK 0xFF #define ADF_C62XIOV_ETR_BAR 0 #define ADF_C62XIOV_ETR_MAX_BANKS 1 -#define ADF_C62XIOV_PF2VF_OFFSET 0x200 void adf_init_hw_data_c62xiov(struct adf_hw_device_data *hw_data); void adf_clean_hw_data_c62xiov(struct adf_hw_device_data *hw_data); diff --git a/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c b/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c index d4d79419daaa4..ea8d34922374b 100644 --- a/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c +++ b/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c @@ -8,13 +8,20 @@ #define ADF_GEN2_ERR_REG_VF2PF(vf_src) (((vf_src) & 0x01FFFE00) >> 9) #define ADF_GEN2_ERR_MSK_VF2PF(vf_mask) (((vf_mask) & 0xFFFF) << 9) -#define ADF_GEN2_PF2VF_OFFSET(i) (0x3A000 + 0x280 + ((i) * 0x04)) +#define ADF_GEN2_PF_PF2VF_OFFSET(i) (0x3A000 + 0x280 + ((i) * 0x04)) +#define ADF_GEN2_VF_PF2VF_OFFSET 0x200 -u32 adf_gen2_get_pf2vf_offset(u32 i) +u32 adf_gen2_pf_get_pf2vf_offset(u32 i) { - return ADF_GEN2_PF2VF_OFFSET(i); + return ADF_GEN2_PF_PF2VF_OFFSET(i); } -EXPORT_SYMBOL_GPL(adf_gen2_get_pf2vf_offset); +EXPORT_SYMBOL_GPL(adf_gen2_pf_get_pf2vf_offset); + +u32 adf_gen2_vf_get_pf2vf_offset(u32 i) +{ + return ADF_GEN2_VF_PF2VF_OFFSET; +} +EXPORT_SYMBOL_GPL(adf_gen2_vf_get_pf2vf_offset); u32 adf_gen2_get_vf2pf_sources(void __iomem *pmisc_addr) { diff --git a/drivers/crypto/qat/qat_common/adf_gen2_pfvf.h b/drivers/crypto/qat/qat_common/adf_gen2_pfvf.h index 0987e254e86b3..a21787e3e5508 100644 --- a/drivers/crypto/qat/qat_common/adf_gen2_pfvf.h +++ b/drivers/crypto/qat/qat_common/adf_gen2_pfvf.h @@ -11,7 +11,8 @@ #define ADF_GEN2_ERRMSK3 (0x3A000 + 0x1C) #define ADF_GEN2_ERRMSK5 (0x3A000 + 0xDC) -u32 adf_gen2_get_pf2vf_offset(u32 i); +u32 adf_gen2_pf_get_pf2vf_offset(u32 i); +u32 adf_gen2_vf_get_pf2vf_offset(u32 i); u32 adf_gen2_get_vf2pf_sources(void __iomem *pmisc_bar); void adf_gen2_enable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask); void adf_gen2_disable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask); diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c index e134385b76a8c..5fc2e5a7f10b6 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c +++ b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c @@ -215,7 +215,7 @@ void adf_init_hw_data_dh895xcc(struct adf_hw_device_data *hw_data) hw_data->get_arb_mapping = adf_get_arbiter_mapping; hw_data->enable_ints = adf_enable_ints; hw_data->reset_device = adf_reset_sbr; - hw_data->get_pf2vf_offset = adf_gen2_get_pf2vf_offset; + hw_data->get_pf2vf_offset = adf_gen2_pf_get_pf2vf_offset; hw_data->get_vf2pf_sources = get_vf2pf_sources; hw_data->enable_vf2pf_interrupts = enable_vf2pf_interrupts; hw_data->disable_vf2pf_interrupts = disable_vf2pf_interrupts; diff --git a/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c b/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c index 7c6ed6bc8abf2..30d862226026e 100644 --- a/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c +++ b/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "adf_dh895xccvf_hw_data.h" static struct adf_hw_device_class dh895xcciov_class = { @@ -47,11 +48,6 @@ static enum dev_sku_info get_sku(struct adf_hw_device_data *self) return DEV_SKU_VF; } -static u32 get_pf2vf_offset(u32 i) -{ - return ADF_DH895XCCIOV_PF2VF_OFFSET; -} - static int adf_vf_int_noop(struct adf_accel_dev *accel_dev) { return 0; @@ -86,7 +82,7 @@ void adf_init_hw_data_dh895xcciov(struct adf_hw_device_data *hw_data) hw_data->get_num_aes = get_num_aes; hw_data->get_etr_bar_id = get_etr_bar_id; hw_data->get_misc_bar_id = get_misc_bar_id; - hw_data->get_pf2vf_offset = get_pf2vf_offset; + hw_data->get_pf2vf_offset = adf_gen2_vf_get_pf2vf_offset; hw_data->get_sku = get_sku; hw_data->enable_ints = adf_vf_void_noop; hw_data->enable_pfvf_comms = adf_enable_vf2pf_comms; diff --git a/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.h b/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.h index 306ebb71a408b..6973fa967bc8e 100644 --- a/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.h +++ b/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.h @@ -12,7 +12,6 @@ #define ADF_DH895XCCIOV_TX_RINGS_MASK 0xFF #define ADF_DH895XCCIOV_ETR_BAR 0 #define ADF_DH895XCCIOV_ETR_MAX_BANKS 1 -#define ADF_DH895XCCIOV_PF2VF_OFFSET 0x200 void adf_init_hw_data_dh895xcciov(struct adf_hw_device_data *hw_data); void adf_clean_hw_data_dh895xcciov(struct adf_hw_device_data *hw_data); -- GitLab From 6f2e28015bacfa8793902eb39a1fb20feb19a011 Mon Sep 17 00:00:00 2001 From: Giovanni Cabiddu Date: Wed, 17 Nov 2021 14:30:46 +0000 Subject: [PATCH 0185/1112] crypto: qat - relocate PFVF disabled function Move the function pfvf_comms_disabled() from the qat_4xxx module to intel_qat as it will be used by other components to keep the PFVF feature disabled. Signed-off-by: Giovanni Cabiddu Reviewed-by: Marco Chiappero Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c | 7 +------ drivers/crypto/qat/qat_common/adf_common_drv.h | 2 ++ drivers/crypto/qat/qat_common/adf_gen4_hw_data.c | 7 +++++++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c b/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c index fd29861526d6b..f4521eeeebedf 100644 --- a/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c +++ b/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c @@ -191,11 +191,6 @@ static int adf_init_device(struct adf_accel_dev *accel_dev) return ret; } -static int pfvf_comms_disabled(struct adf_accel_dev *accel_dev) -{ - return 0; -} - static u32 uof_get_num_objs(void) { return ARRAY_SIZE(adf_4xxx_fw_config); @@ -259,7 +254,7 @@ void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data) hw_data->uof_get_ae_mask = uof_get_ae_mask; hw_data->set_msix_rttable = set_msix_default_rttable; hw_data->set_ssm_wdtimer = adf_gen4_set_ssm_wdtimer; - hw_data->enable_pfvf_comms = pfvf_comms_disabled; + hw_data->enable_pfvf_comms = adf_pfvf_comms_disabled; hw_data->get_vf2pf_sources = get_vf2pf_sources; hw_data->disable_iov = adf_disable_sriov; hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION; diff --git a/drivers/crypto/qat/qat_common/adf_common_drv.h b/drivers/crypto/qat/qat_common/adf_common_drv.h index db9d045e6a062..c0699e4535027 100644 --- a/drivers/crypto/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/qat/qat_common/adf_common_drv.h @@ -130,6 +130,8 @@ void adf_isr_resource_free(struct adf_accel_dev *accel_dev); int adf_vf_isr_resource_alloc(struct adf_accel_dev *accel_dev); void adf_vf_isr_resource_free(struct adf_accel_dev *accel_dev); +int adf_pfvf_comms_disabled(struct adf_accel_dev *accel_dev); + int qat_hal_init(struct adf_accel_dev *accel_dev); void qat_hal_deinit(struct icp_qat_fw_loader_handle *handle); int qat_hal_start(struct icp_qat_fw_loader_handle *handle); diff --git a/drivers/crypto/qat/qat_common/adf_gen4_hw_data.c b/drivers/crypto/qat/qat_common/adf_gen4_hw_data.c index 000528327b296..e3157df8a653f 100644 --- a/drivers/crypto/qat/qat_common/adf_gen4_hw_data.c +++ b/drivers/crypto/qat/qat_common/adf_gen4_hw_data.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) /* Copyright(c) 2020 Intel Corporation */ #include "adf_accel_devices.h" +#include "adf_common_drv.h" #include "adf_gen4_hw_data.h" static u64 build_csr_ring_base_addr(dma_addr_t addr, u32 size) @@ -139,3 +140,9 @@ void adf_gen4_set_ssm_wdtimer(struct adf_accel_dev *accel_dev) ADF_CSR_WR(pmisc_addr, ADF_SSMWDTPKEH_OFFSET, ssm_wdt_pke_high); } EXPORT_SYMBOL_GPL(adf_gen4_set_ssm_wdtimer); + +int adf_pfvf_comms_disabled(struct adf_accel_dev *accel_dev) +{ + return 0; +} +EXPORT_SYMBOL_GPL(adf_pfvf_comms_disabled); -- GitLab From bc63dabe525402b91320192ff1758f0d05b159c6 Mon Sep 17 00:00:00 2001 From: Marco Chiappero Date: Wed, 17 Nov 2021 14:30:47 +0000 Subject: [PATCH 0186/1112] crypto: qat - add pfvf_ops Add pfvf_ops structure to isolate PFVF related functions inside the adf_hw_device_data structure. For GEN2, the structure is populated using one of the two helper functions, adf_gen2_init_pf_pfvf_ops() or adf_gen2_init_vf_pfvf_ops(), for the PF and VF driver respectively. For the DH895XCC PF driver, the structure is populated using adf_gen2_init_pf_pfvf_ops() but some of the functions are then overwritten. Signed-off-by: Marco Chiappero Co-developed-by: Giovanni Cabiddu Signed-off-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- .../crypto/qat/qat_4xxx/adf_4xxx_hw_data.c | 4 +-- .../crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c | 6 +--- .../qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c | 3 +- .../crypto/qat/qat_c62x/adf_c62x_hw_data.c | 6 +--- .../qat/qat_c62xvf/adf_c62xvf_hw_data.c | 3 +- drivers/crypto/qat/qat_common/Makefile | 6 ++-- .../crypto/qat/qat_common/adf_accel_devices.h | 17 +++++---- drivers/crypto/qat/qat_common/adf_gen2_pfvf.c | 35 +++++++++++++------ drivers/crypto/qat/qat_common/adf_gen2_pfvf.h | 19 +++++++--- drivers/crypto/qat/qat_common/adf_init.c | 2 +- drivers/crypto/qat/qat_common/adf_isr.c | 8 ++--- drivers/crypto/qat/qat_common/adf_pf2vf_msg.c | 8 ++--- drivers/crypto/qat/qat_common/adf_sriov.c | 6 ++-- drivers/crypto/qat/qat_common/adf_vf2pf_msg.c | 2 +- .../qat/qat_dh895xcc/adf_dh895xcc_hw_data.c | 9 +++-- .../qat_dh895xccvf/adf_dh895xccvf_hw_data.c | 3 +- 16 files changed, 76 insertions(+), 61 deletions(-) diff --git a/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c b/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c index f4521eeeebedf..ec57a2e2d1fcb 100644 --- a/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c +++ b/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c @@ -254,8 +254,8 @@ void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data) hw_data->uof_get_ae_mask = uof_get_ae_mask; hw_data->set_msix_rttable = set_msix_default_rttable; hw_data->set_ssm_wdtimer = adf_gen4_set_ssm_wdtimer; - hw_data->enable_pfvf_comms = adf_pfvf_comms_disabled; - hw_data->get_vf2pf_sources = get_vf2pf_sources; + hw_data->pfvf_ops.enable_comms = adf_pfvf_comms_disabled; + hw_data->pfvf_ops.get_vf2pf_sources = get_vf2pf_sources; hw_data->disable_iov = adf_disable_sriov; hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION; diff --git a/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c b/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c index aaf8e65887b88..d25f78660b8cb 100644 --- a/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c +++ b/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c @@ -136,14 +136,10 @@ void adf_init_hw_data_c3xxx(struct adf_hw_device_data *hw_data) hw_data->enable_ints = adf_enable_ints; hw_data->reset_device = adf_reset_flr; hw_data->set_ssm_wdtimer = adf_gen2_set_ssm_wdtimer; - hw_data->get_pf2vf_offset = adf_gen2_pf_get_pf2vf_offset; - hw_data->get_vf2pf_sources = adf_gen2_get_vf2pf_sources; - hw_data->enable_vf2pf_interrupts = adf_gen2_enable_vf2pf_interrupts; - hw_data->disable_vf2pf_interrupts = adf_gen2_disable_vf2pf_interrupts; - hw_data->enable_pfvf_comms = adf_enable_pf2vf_comms; hw_data->disable_iov = adf_disable_sriov; hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION; + adf_gen2_init_pf_pfvf_ops(&hw_data->pfvf_ops); adf_gen2_init_hw_csr_ops(&hw_data->csr_ops); } diff --git a/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c b/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c index ee61f69a8077e..c39733320063a 100644 --- a/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c +++ b/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c @@ -82,13 +82,12 @@ void adf_init_hw_data_c3xxxiov(struct adf_hw_device_data *hw_data) hw_data->get_num_aes = get_num_aes; hw_data->get_etr_bar_id = get_etr_bar_id; hw_data->get_misc_bar_id = get_misc_bar_id; - hw_data->get_pf2vf_offset = adf_gen2_vf_get_pf2vf_offset; hw_data->get_sku = get_sku; hw_data->enable_ints = adf_vf_void_noop; - hw_data->enable_pfvf_comms = adf_enable_vf2pf_comms; hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION; hw_data->dev_class->instances++; adf_devmgr_update_class_index(hw_data); + adf_gen2_init_vf_pfvf_ops(&hw_data->pfvf_ops); adf_gen2_init_hw_csr_ops(&hw_data->csr_ops); } diff --git a/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c b/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c index 0d694c7137975..f24a01e1bc1a1 100644 --- a/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c +++ b/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c @@ -138,14 +138,10 @@ void adf_init_hw_data_c62x(struct adf_hw_device_data *hw_data) hw_data->enable_ints = adf_enable_ints; hw_data->reset_device = adf_reset_flr; hw_data->set_ssm_wdtimer = adf_gen2_set_ssm_wdtimer; - hw_data->get_pf2vf_offset = adf_gen2_pf_get_pf2vf_offset; - hw_data->get_vf2pf_sources = adf_gen2_get_vf2pf_sources; - hw_data->enable_vf2pf_interrupts = adf_gen2_enable_vf2pf_interrupts; - hw_data->disable_vf2pf_interrupts = adf_gen2_disable_vf2pf_interrupts; - hw_data->enable_pfvf_comms = adf_enable_pf2vf_comms; hw_data->disable_iov = adf_disable_sriov; hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION; + adf_gen2_init_pf_pfvf_ops(&hw_data->pfvf_ops); adf_gen2_init_hw_csr_ops(&hw_data->csr_ops); } diff --git a/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c b/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c index 407f3beee43c0..03097bbe600a2 100644 --- a/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c +++ b/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c @@ -82,13 +82,12 @@ void adf_init_hw_data_c62xiov(struct adf_hw_device_data *hw_data) hw_data->get_num_aes = get_num_aes; hw_data->get_etr_bar_id = get_etr_bar_id; hw_data->get_misc_bar_id = get_misc_bar_id; - hw_data->get_pf2vf_offset = adf_gen2_vf_get_pf2vf_offset; hw_data->get_sku = get_sku; hw_data->enable_ints = adf_vf_void_noop; - hw_data->enable_pfvf_comms = adf_enable_vf2pf_comms; hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION; hw_data->dev_class->instances++; adf_devmgr_update_class_index(hw_data); + adf_gen2_init_vf_pfvf_ops(&hw_data->pfvf_ops); adf_gen2_init_hw_csr_ops(&hw_data->csr_ops); } diff --git a/drivers/crypto/qat/qat_common/Makefile b/drivers/crypto/qat/qat_common/Makefile index 3874e427d1f7e..676aef6533e0f 100644 --- a/drivers/crypto/qat/qat_common/Makefile +++ b/drivers/crypto/qat/qat_common/Makefile @@ -16,9 +16,9 @@ intel_qat-objs := adf_cfg.o \ qat_algs.o \ qat_asym_algs.o \ qat_uclo.o \ - qat_hal.o \ - adf_gen2_pfvf.o + qat_hal.o intel_qat-$(CONFIG_DEBUG_FS) += adf_transport_debug.o intel_qat-$(CONFIG_PCI_IOV) += adf_sriov.o adf_pf2vf_msg.o \ - adf_vf2pf_msg.o adf_vf_isr.o + adf_vf2pf_msg.o adf_vf_isr.o \ + adf_gen2_pfvf.o diff --git a/drivers/crypto/qat/qat_common/adf_accel_devices.h b/drivers/crypto/qat/qat_common/adf_accel_devices.h index 57d9ca08e6115..a1baa65bd0342 100644 --- a/drivers/crypto/qat/qat_common/adf_accel_devices.h +++ b/drivers/crypto/qat/qat_common/adf_accel_devices.h @@ -147,6 +147,14 @@ struct adf_accel_dev; struct adf_etr_data; struct adf_etr_ring_data; +struct adf_pfvf_ops { + int (*enable_comms)(struct adf_accel_dev *accel_dev); + u32 (*get_pf2vf_offset)(u32 i); + u32 (*get_vf2pf_sources)(void __iomem *pmisc_addr); + void (*enable_vf2pf_interrupts)(void __iomem *pmisc_addr, u32 vf_mask); + void (*disable_vf2pf_interrupts)(void __iomem *pmisc_addr, u32 vf_mask); +}; + struct adf_hw_device_data { struct adf_hw_device_class *dev_class; u32 (*get_accel_mask)(struct adf_hw_device_data *self); @@ -157,7 +165,6 @@ struct adf_hw_device_data { u32 (*get_etr_bar_id)(struct adf_hw_device_data *self); u32 (*get_num_aes)(struct adf_hw_device_data *self); u32 (*get_num_accels)(struct adf_hw_device_data *self); - u32 (*get_pf2vf_offset)(u32 i); void (*get_arb_info)(struct arb_info *arb_csrs_info); void (*get_admin_info)(struct admin_info *admin_csrs_info); enum dev_sku_info (*get_sku)(struct adf_hw_device_data *self); @@ -176,17 +183,12 @@ struct adf_hw_device_data { bool enable); void (*enable_ints)(struct adf_accel_dev *accel_dev); void (*set_ssm_wdtimer)(struct adf_accel_dev *accel_dev); - int (*enable_pfvf_comms)(struct adf_accel_dev *accel_dev); - u32 (*get_vf2pf_sources)(void __iomem *pmisc_addr); - void (*enable_vf2pf_interrupts)(void __iomem *pmisc_bar_addr, - u32 vf_mask); - void (*disable_vf2pf_interrupts)(void __iomem *pmisc_bar_addr, - u32 vf_mask); void (*reset_device)(struct adf_accel_dev *accel_dev); void (*set_msix_rttable)(struct adf_accel_dev *accel_dev); char *(*uof_get_name)(u32 obj_num); u32 (*uof_get_num_objs)(void); u32 (*uof_get_ae_mask)(u32 obj_num); + struct adf_pfvf_ops pfvf_ops; struct adf_hw_csr_ops csr_ops; const char *fw_name; const char *fw_mmp_name; @@ -222,6 +224,7 @@ struct adf_hw_device_data { GET_HW_DATA(accel_dev)->num_rings_per_bank #define GET_MAX_ACCELENGINES(accel_dev) (GET_HW_DATA(accel_dev)->num_engines) #define GET_CSR_OPS(accel_dev) (&(accel_dev)->hw_device->csr_ops) +#define GET_PFVF_OPS(accel_dev) (&(accel_dev)->hw_device->pfvf_ops) #define accel_to_pci_dev(accel_ptr) accel_ptr->accel_pci_dev.pci_dev struct adf_admin_comms; diff --git a/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c b/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c index ea8d34922374b..36c8ff0096612 100644 --- a/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c +++ b/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c @@ -2,6 +2,7 @@ /* Copyright(c) 2021 Intel Corporation */ #include #include "adf_accel_devices.h" +#include "adf_common_drv.h" #include "adf_gen2_pfvf.h" /* VF2PF interrupts */ @@ -11,19 +12,17 @@ #define ADF_GEN2_PF_PF2VF_OFFSET(i) (0x3A000 + 0x280 + ((i) * 0x04)) #define ADF_GEN2_VF_PF2VF_OFFSET 0x200 -u32 adf_gen2_pf_get_pf2vf_offset(u32 i) +static u32 adf_gen2_pf_get_pf2vf_offset(u32 i) { return ADF_GEN2_PF_PF2VF_OFFSET(i); } -EXPORT_SYMBOL_GPL(adf_gen2_pf_get_pf2vf_offset); -u32 adf_gen2_vf_get_pf2vf_offset(u32 i) +static u32 adf_gen2_vf_get_pf2vf_offset(u32 i) { return ADF_GEN2_VF_PF2VF_OFFSET; } -EXPORT_SYMBOL_GPL(adf_gen2_vf_get_pf2vf_offset); -u32 adf_gen2_get_vf2pf_sources(void __iomem *pmisc_addr) +static u32 adf_gen2_get_vf2pf_sources(void __iomem *pmisc_addr) { u32 errsou3, errmsk3, vf_int_mask; @@ -39,9 +38,9 @@ u32 adf_gen2_get_vf2pf_sources(void __iomem *pmisc_addr) return vf_int_mask; } -EXPORT_SYMBOL_GPL(adf_gen2_get_vf2pf_sources); -void adf_gen2_enable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask) +static void adf_gen2_enable_vf2pf_interrupts(void __iomem *pmisc_addr, + u32 vf_mask) { /* Enable VF2PF Messaging Ints - VFs 0 through 15 per vf_mask[15:0] */ if (vf_mask & 0xFFFF) { @@ -50,9 +49,9 @@ void adf_gen2_enable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask) ADF_CSR_WR(pmisc_addr, ADF_GEN2_ERRMSK3, val); } } -EXPORT_SYMBOL_GPL(adf_gen2_enable_vf2pf_interrupts); -void adf_gen2_disable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask) +static void adf_gen2_disable_vf2pf_interrupts(void __iomem *pmisc_addr, + u32 vf_mask) { /* Disable VF2PF interrupts for VFs 0 through 15 per vf_mask[15:0] */ if (vf_mask & 0xFFFF) { @@ -61,4 +60,20 @@ void adf_gen2_disable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask) ADF_CSR_WR(pmisc_addr, ADF_GEN2_ERRMSK3, val); } } -EXPORT_SYMBOL_GPL(adf_gen2_disable_vf2pf_interrupts); + +void adf_gen2_init_pf_pfvf_ops(struct adf_pfvf_ops *pfvf_ops) +{ + pfvf_ops->enable_comms = adf_enable_pf2vf_comms; + pfvf_ops->get_pf2vf_offset = adf_gen2_pf_get_pf2vf_offset; + pfvf_ops->get_vf2pf_sources = adf_gen2_get_vf2pf_sources; + pfvf_ops->enable_vf2pf_interrupts = adf_gen2_enable_vf2pf_interrupts; + pfvf_ops->disable_vf2pf_interrupts = adf_gen2_disable_vf2pf_interrupts; +} +EXPORT_SYMBOL_GPL(adf_gen2_init_pf_pfvf_ops); + +void adf_gen2_init_vf_pfvf_ops(struct adf_pfvf_ops *pfvf_ops) +{ + pfvf_ops->enable_comms = adf_enable_vf2pf_comms; + pfvf_ops->get_pf2vf_offset = adf_gen2_vf_get_pf2vf_offset; +} +EXPORT_SYMBOL_GPL(adf_gen2_init_vf_pfvf_ops); diff --git a/drivers/crypto/qat/qat_common/adf_gen2_pfvf.h b/drivers/crypto/qat/qat_common/adf_gen2_pfvf.h index a21787e3e5508..a716545a764ca 100644 --- a/drivers/crypto/qat/qat_common/adf_gen2_pfvf.h +++ b/drivers/crypto/qat/qat_common/adf_gen2_pfvf.h @@ -11,10 +11,19 @@ #define ADF_GEN2_ERRMSK3 (0x3A000 + 0x1C) #define ADF_GEN2_ERRMSK5 (0x3A000 + 0xDC) -u32 adf_gen2_pf_get_pf2vf_offset(u32 i); -u32 adf_gen2_vf_get_pf2vf_offset(u32 i); -u32 adf_gen2_get_vf2pf_sources(void __iomem *pmisc_bar); -void adf_gen2_enable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask); -void adf_gen2_disable_vf2pf_interrupts(void __iomem *pmisc_addr, u32 vf_mask); +#if defined(CONFIG_PCI_IOV) +void adf_gen2_init_pf_pfvf_ops(struct adf_pfvf_ops *pfvf_ops); +void adf_gen2_init_vf_pfvf_ops(struct adf_pfvf_ops *pfvf_ops); +#else +static inline void adf_gen2_init_pf_pfvf_ops(struct adf_pfvf_ops *pfvf_ops) +{ + pfvf_ops->enable_comms = adf_pfvf_comms_disabled; +} + +static inline void adf_gen2_init_vf_pfvf_ops(struct adf_pfvf_ops *pfvf_ops) +{ + pfvf_ops->enable_comms = adf_pfvf_comms_disabled; +} +#endif #endif /* ADF_GEN2_PFVF_H */ diff --git a/drivers/crypto/qat/qat_common/adf_init.c b/drivers/crypto/qat/qat_common/adf_init.c index e3749e5817d94..391d82a64a936 100644 --- a/drivers/crypto/qat/qat_common/adf_init.c +++ b/drivers/crypto/qat/qat_common/adf_init.c @@ -117,7 +117,7 @@ int adf_dev_init(struct adf_accel_dev *accel_dev) hw_data->enable_ints(accel_dev); hw_data->enable_error_correction(accel_dev); - ret = hw_data->enable_pfvf_comms(accel_dev); + ret = hw_data->pfvf_ops.enable_comms(accel_dev); if (ret) return ret; diff --git a/drivers/crypto/qat/qat_common/adf_isr.c b/drivers/crypto/qat/qat_common/adf_isr.c index 2b4900c913083..358200c0d5981 100644 --- a/drivers/crypto/qat/qat_common/adf_isr.c +++ b/drivers/crypto/qat/qat_common/adf_isr.c @@ -64,7 +64,7 @@ void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask) unsigned long flags; spin_lock_irqsave(&accel_dev->pf.vf2pf_ints_lock, flags); - hw_data->enable_vf2pf_interrupts(pmisc_addr, vf_mask); + hw_data->pfvf_ops.enable_vf2pf_interrupts(pmisc_addr, vf_mask); spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags); } @@ -77,7 +77,7 @@ void adf_disable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask) unsigned long flags; spin_lock_irqsave(&accel_dev->pf.vf2pf_ints_lock, flags); - hw_data->disable_vf2pf_interrupts(pmisc_addr, vf_mask); + hw_data->pfvf_ops.disable_vf2pf_interrupts(pmisc_addr, vf_mask); spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags); } @@ -90,7 +90,7 @@ static void adf_disable_vf2pf_interrupts_irq(struct adf_accel_dev *accel_dev, void __iomem *pmisc_addr = pmisc->virt_addr; spin_lock(&accel_dev->pf.vf2pf_ints_lock); - hw_data->disable_vf2pf_interrupts(pmisc_addr, vf_mask); + hw_data->pfvf_ops.disable_vf2pf_interrupts(pmisc_addr, vf_mask); spin_unlock(&accel_dev->pf.vf2pf_ints_lock); } @@ -104,7 +104,7 @@ static bool adf_handle_vf2pf_int(struct adf_accel_dev *accel_dev) unsigned long vf_mask; /* Get the interrupt sources triggered by VFs */ - vf_mask = hw_data->get_vf2pf_sources(pmisc_addr); + vf_mask = hw_data->pfvf_ops.get_vf2pf_sources(pmisc_addr); if (vf_mask) { struct adf_accel_vf_info *vf_info; diff --git a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c index d98e3639c9d28..78dc8aea48667 100644 --- a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c +++ b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c @@ -29,7 +29,7 @@ static int adf_iov_putmsg(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr) int ret; if (accel_dev->is_vf) { - pf2vf_offset = hw_data->get_pf2vf_offset(0); + pf2vf_offset = hw_data->pfvf_ops.get_pf2vf_offset(0); lock = &accel_dev->vf.vf2pf_lock; local_in_use_mask = ADF_VF2PF_IN_USE_BY_VF_MASK; local_in_use_pattern = ADF_VF2PF_IN_USE_BY_VF; @@ -37,7 +37,7 @@ static int adf_iov_putmsg(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr) remote_in_use_pattern = ADF_PF2VF_IN_USE_BY_PF; int_bit = ADF_VF2PF_INT; } else { - pf2vf_offset = hw_data->get_pf2vf_offset(vf_nr); + pf2vf_offset = hw_data->pfvf_ops.get_pf2vf_offset(vf_nr); lock = &accel_dev->pf.vf_info[vf_nr].pf2vf_lock; local_in_use_mask = ADF_PF2VF_IN_USE_BY_PF_MASK; local_in_use_pattern = ADF_PF2VF_IN_USE_BY_PF; @@ -258,7 +258,7 @@ bool adf_recv_and_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr) u32 msg, resp = 0; /* Read message from the VF */ - msg = ADF_CSR_RD(pmisc_addr, hw_data->get_pf2vf_offset(vf_nr)); + msg = ADF_CSR_RD(pmisc_addr, hw_data->pfvf_ops.get_pf2vf_offset(vf_nr)); if (!(msg & ADF_VF2PF_INT)) { dev_info(&GET_DEV(accel_dev), "Spurious VF2PF interrupt, msg %X. Ignored\n", msg); @@ -275,7 +275,7 @@ bool adf_recv_and_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr) /* To ACK, clear the VF2PFINT bit */ msg &= ~ADF_VF2PF_INT; - ADF_CSR_WR(pmisc_addr, hw_data->get_pf2vf_offset(vf_nr), msg); + ADF_CSR_WR(pmisc_addr, hw_data->pfvf_ops.get_pf2vf_offset(vf_nr), msg); if (adf_handle_vf2pf_msg(accel_dev, vf_nr, msg, &resp)) return false; diff --git a/drivers/crypto/qat/qat_common/adf_sriov.c b/drivers/crypto/qat/qat_common/adf_sriov.c index b1a814ac1d679..342063406c196 100644 --- a/drivers/crypto/qat/qat_common/adf_sriov.c +++ b/drivers/crypto/qat/qat_common/adf_sriov.c @@ -70,7 +70,7 @@ static int adf_enable_sriov(struct adf_accel_dev *accel_dev) hw_data->configure_iov_threads(accel_dev, true); /* Enable VF to PF interrupts for all VFs */ - if (hw_data->get_pf2vf_offset) + if (hw_data->pfvf_ops.get_pf2vf_offset) adf_enable_vf2pf_interrupts(accel_dev, BIT_ULL(totalvfs) - 1); /* @@ -100,13 +100,13 @@ void adf_disable_sriov(struct adf_accel_dev *accel_dev) if (!accel_dev->pf.vf_info) return; - if (hw_data->get_pf2vf_offset) + if (hw_data->pfvf_ops.get_pf2vf_offset) adf_pf2vf_notify_restarting(accel_dev); pci_disable_sriov(accel_to_pci_dev(accel_dev)); /* Disable VF to PF interrupts */ - if (hw_data->get_pf2vf_offset) + if (hw_data->pfvf_ops.get_pf2vf_offset) adf_disable_vf2pf_interrupts(accel_dev, GENMASK(31, 0)); /* Clear Valid bits in AE Thread to PCIe Function Mapping */ diff --git a/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c b/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c index 01a6e68f256b6..d11eb60b3e867 100644 --- a/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c +++ b/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c @@ -81,7 +81,7 @@ bool adf_recv_and_handle_pf2vf_msg(struct adf_accel_dev *accel_dev) struct adf_bar *pmisc = &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)]; void __iomem *pmisc_bar_addr = pmisc->virt_addr; - u32 offset = hw_data->get_pf2vf_offset(0); + u32 offset = hw_data->pfvf_ops.get_pf2vf_offset(0); u32 msg; /* Read the message from PF */ diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c index 5fc2e5a7f10b6..aa42373a7118d 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c +++ b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c @@ -215,14 +215,13 @@ void adf_init_hw_data_dh895xcc(struct adf_hw_device_data *hw_data) hw_data->get_arb_mapping = adf_get_arbiter_mapping; hw_data->enable_ints = adf_enable_ints; hw_data->reset_device = adf_reset_sbr; - hw_data->get_pf2vf_offset = adf_gen2_pf_get_pf2vf_offset; - hw_data->get_vf2pf_sources = get_vf2pf_sources; - hw_data->enable_vf2pf_interrupts = enable_vf2pf_interrupts; - hw_data->disable_vf2pf_interrupts = disable_vf2pf_interrupts; - hw_data->enable_pfvf_comms = adf_enable_pf2vf_comms; hw_data->disable_iov = adf_disable_sriov; hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION; + adf_gen2_init_pf_pfvf_ops(&hw_data->pfvf_ops); + hw_data->pfvf_ops.get_vf2pf_sources = get_vf2pf_sources; + hw_data->pfvf_ops.enable_vf2pf_interrupts = enable_vf2pf_interrupts; + hw_data->pfvf_ops.disable_vf2pf_interrupts = disable_vf2pf_interrupts; adf_gen2_init_hw_csr_ops(&hw_data->csr_ops); } diff --git a/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c b/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c index 30d862226026e..2e2ef6b5bd2a2 100644 --- a/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c +++ b/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c @@ -82,13 +82,12 @@ void adf_init_hw_data_dh895xcciov(struct adf_hw_device_data *hw_data) hw_data->get_num_aes = get_num_aes; hw_data->get_etr_bar_id = get_etr_bar_id; hw_data->get_misc_bar_id = get_misc_bar_id; - hw_data->get_pf2vf_offset = adf_gen2_vf_get_pf2vf_offset; hw_data->get_sku = get_sku; hw_data->enable_ints = adf_vf_void_noop; - hw_data->enable_pfvf_comms = adf_enable_vf2pf_comms; hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION; hw_data->dev_class->instances++; adf_devmgr_update_class_index(hw_data); + adf_gen2_init_vf_pfvf_ops(&hw_data->pfvf_ops); adf_gen2_init_hw_csr_ops(&hw_data->csr_ops); } -- GitLab From 9baf2de7ee4eeaca5cf95d1a399182ab83aa42b8 Mon Sep 17 00:00:00 2001 From: Marco Chiappero Date: Wed, 17 Nov 2021 14:30:48 +0000 Subject: [PATCH 0187/1112] crypto: qat - differentiate between pf2vf and vf2pf offset Add the function get_vf2pf_offset() to adf_pfvf_ops to differentiate the CSRs used for pf2vf and vf2pf. Offsets may or may not be direction specific depending on QAT generation. Since in QAT GEN2 the CSR is not direction specific, i.e. there is a single mailbox register shared for pf2vf and vf2pf, both get_vf2pf_offset() and get_vf2pf_offset() will return the same offset. This change is to make the direction explicit, so it is easier to understand and debug and also in preparation for the introduction of PFVF support in the qat_4xxx driver since QAT GEN4 devices have a separate CSR for pf2vf and vf2pf communications. Signed-off-by: Marco Chiappero Reviewed-by: Giovanni Cabiddu Signed-off-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_accel_devices.h | 1 + drivers/crypto/qat/qat_common/adf_gen2_pfvf.c | 10 ++++++---- drivers/crypto/qat/qat_common/adf_pf2vf_msg.c | 6 +++--- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/crypto/qat/qat_common/adf_accel_devices.h b/drivers/crypto/qat/qat_common/adf_accel_devices.h index a1baa65bd0342..d9b2cc935b616 100644 --- a/drivers/crypto/qat/qat_common/adf_accel_devices.h +++ b/drivers/crypto/qat/qat_common/adf_accel_devices.h @@ -150,6 +150,7 @@ struct adf_etr_ring_data; struct adf_pfvf_ops { int (*enable_comms)(struct adf_accel_dev *accel_dev); u32 (*get_pf2vf_offset)(u32 i); + u32 (*get_vf2pf_offset)(u32 i); u32 (*get_vf2pf_sources)(void __iomem *pmisc_addr); void (*enable_vf2pf_interrupts)(void __iomem *pmisc_addr, u32 vf_mask); void (*disable_vf2pf_interrupts)(void __iomem *pmisc_addr, u32 vf_mask); diff --git a/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c b/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c index 36c8ff0096612..2f27146bb7c6e 100644 --- a/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c +++ b/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c @@ -12,12 +12,12 @@ #define ADF_GEN2_PF_PF2VF_OFFSET(i) (0x3A000 + 0x280 + ((i) * 0x04)) #define ADF_GEN2_VF_PF2VF_OFFSET 0x200 -static u32 adf_gen2_pf_get_pf2vf_offset(u32 i) +static u32 adf_gen2_pf_get_pfvf_offset(u32 i) { return ADF_GEN2_PF_PF2VF_OFFSET(i); } -static u32 adf_gen2_vf_get_pf2vf_offset(u32 i) +static u32 adf_gen2_vf_get_pfvf_offset(u32 i) { return ADF_GEN2_VF_PF2VF_OFFSET; } @@ -64,7 +64,8 @@ static void adf_gen2_disable_vf2pf_interrupts(void __iomem *pmisc_addr, void adf_gen2_init_pf_pfvf_ops(struct adf_pfvf_ops *pfvf_ops) { pfvf_ops->enable_comms = adf_enable_pf2vf_comms; - pfvf_ops->get_pf2vf_offset = adf_gen2_pf_get_pf2vf_offset; + pfvf_ops->get_pf2vf_offset = adf_gen2_pf_get_pfvf_offset; + pfvf_ops->get_vf2pf_offset = adf_gen2_pf_get_pfvf_offset; pfvf_ops->get_vf2pf_sources = adf_gen2_get_vf2pf_sources; pfvf_ops->enable_vf2pf_interrupts = adf_gen2_enable_vf2pf_interrupts; pfvf_ops->disable_vf2pf_interrupts = adf_gen2_disable_vf2pf_interrupts; @@ -74,6 +75,7 @@ EXPORT_SYMBOL_GPL(adf_gen2_init_pf_pfvf_ops); void adf_gen2_init_vf_pfvf_ops(struct adf_pfvf_ops *pfvf_ops) { pfvf_ops->enable_comms = adf_enable_vf2pf_comms; - pfvf_ops->get_pf2vf_offset = adf_gen2_vf_get_pf2vf_offset; + pfvf_ops->get_pf2vf_offset = adf_gen2_vf_get_pfvf_offset; + pfvf_ops->get_vf2pf_offset = adf_gen2_vf_get_pfvf_offset; } EXPORT_SYMBOL_GPL(adf_gen2_init_vf_pfvf_ops); diff --git a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c index 78dc8aea48667..c420ec03081b4 100644 --- a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c +++ b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c @@ -29,7 +29,7 @@ static int adf_iov_putmsg(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr) int ret; if (accel_dev->is_vf) { - pf2vf_offset = hw_data->pfvf_ops.get_pf2vf_offset(0); + pf2vf_offset = hw_data->pfvf_ops.get_vf2pf_offset(0); lock = &accel_dev->vf.vf2pf_lock; local_in_use_mask = ADF_VF2PF_IN_USE_BY_VF_MASK; local_in_use_pattern = ADF_VF2PF_IN_USE_BY_VF; @@ -258,7 +258,7 @@ bool adf_recv_and_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr) u32 msg, resp = 0; /* Read message from the VF */ - msg = ADF_CSR_RD(pmisc_addr, hw_data->pfvf_ops.get_pf2vf_offset(vf_nr)); + msg = ADF_CSR_RD(pmisc_addr, hw_data->pfvf_ops.get_vf2pf_offset(vf_nr)); if (!(msg & ADF_VF2PF_INT)) { dev_info(&GET_DEV(accel_dev), "Spurious VF2PF interrupt, msg %X. Ignored\n", msg); @@ -275,7 +275,7 @@ bool adf_recv_and_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr) /* To ACK, clear the VF2PFINT bit */ msg &= ~ADF_VF2PF_INT; - ADF_CSR_WR(pmisc_addr, hw_data->pfvf_ops.get_pf2vf_offset(vf_nr), msg); + ADF_CSR_WR(pmisc_addr, hw_data->pfvf_ops.get_vf2pf_offset(vf_nr), msg); if (adf_handle_vf2pf_msg(accel_dev, vf_nr, msg, &resp)) return false; -- GitLab From 49c43538ce05115e3fe12752dc77aa1deed3b0d2 Mon Sep 17 00:00:00 2001 From: Marco Chiappero Date: Wed, 17 Nov 2021 14:30:49 +0000 Subject: [PATCH 0188/1112] crypto: qat - abstract PFVF send function Make the PFVF send function device specific. This is in preparation for the introduction of PFVF support in the qat_4xxx driver since the send logic differs between QAT GEN2 and QAT GEN4 devices. Signed-off-by: Marco Chiappero Co-developed-by: Giovanni Cabiddu Signed-off-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- .../crypto/qat/qat_common/adf_accel_devices.h | 1 + drivers/crypto/qat/qat_common/adf_gen2_pfvf.c | 97 +++++++++++++++++++ drivers/crypto/qat/qat_common/adf_pf2vf_msg.c | 92 +----------------- drivers/crypto/qat/qat_common/adf_pf2vf_msg.h | 3 +- 4 files changed, 102 insertions(+), 91 deletions(-) diff --git a/drivers/crypto/qat/qat_common/adf_accel_devices.h b/drivers/crypto/qat/qat_common/adf_accel_devices.h index d9b2cc935b616..8938149590833 100644 --- a/drivers/crypto/qat/qat_common/adf_accel_devices.h +++ b/drivers/crypto/qat/qat_common/adf_accel_devices.h @@ -154,6 +154,7 @@ struct adf_pfvf_ops { u32 (*get_vf2pf_sources)(void __iomem *pmisc_addr); void (*enable_vf2pf_interrupts)(void __iomem *pmisc_addr, u32 vf_mask); void (*disable_vf2pf_interrupts)(void __iomem *pmisc_addr, u32 vf_mask); + int (*send_msg)(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr); }; struct adf_hw_device_data { diff --git a/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c b/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c index 2f27146bb7c6e..5eba042d453b7 100644 --- a/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c +++ b/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c @@ -1,9 +1,12 @@ // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) /* Copyright(c) 2021 Intel Corporation */ +#include +#include #include #include "adf_accel_devices.h" #include "adf_common_drv.h" #include "adf_gen2_pfvf.h" +#include "adf_pf2vf_msg.h" /* VF2PF interrupts */ #define ADF_GEN2_ERR_REG_VF2PF(vf_src) (((vf_src) & 0x01FFFE00) >> 9) @@ -12,6 +15,12 @@ #define ADF_GEN2_PF_PF2VF_OFFSET(i) (0x3A000 + 0x280 + ((i) * 0x04)) #define ADF_GEN2_VF_PF2VF_OFFSET 0x200 +#define ADF_PFVF_MSG_ACK_DELAY 2 +#define ADF_PFVF_MSG_ACK_MAX_RETRY 100 + +#define ADF_PFVF_MSG_RETRY_DELAY 5 +#define ADF_PFVF_MSG_MAX_RETRIES 3 + static u32 adf_gen2_pf_get_pfvf_offset(u32 i) { return ADF_GEN2_PF_PF2VF_OFFSET(i); @@ -61,6 +70,92 @@ static void adf_gen2_disable_vf2pf_interrupts(void __iomem *pmisc_addr, } } +static int adf_gen2_pfvf_send(struct adf_accel_dev *accel_dev, u32 msg, + u8 vf_nr) +{ + struct adf_accel_pci *pci_info = &accel_dev->accel_pci_dev; + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + void __iomem *pmisc_bar_addr = + pci_info->pci_bars[hw_data->get_misc_bar_id(hw_data)].virt_addr; + u32 val, pfvf_offset, count = 0; + u32 local_in_use_mask, local_in_use_pattern; + u32 remote_in_use_mask, remote_in_use_pattern; + struct mutex *lock; /* lock preventing concurrent acces of CSR */ + unsigned int retries = ADF_PFVF_MSG_MAX_RETRIES; + u32 int_bit; + int ret; + + if (accel_dev->is_vf) { + pfvf_offset = GET_PFVF_OPS(accel_dev)->get_vf2pf_offset(0); + lock = &accel_dev->vf.vf2pf_lock; + local_in_use_mask = ADF_VF2PF_IN_USE_BY_VF_MASK; + local_in_use_pattern = ADF_VF2PF_IN_USE_BY_VF; + remote_in_use_mask = ADF_PF2VF_IN_USE_BY_PF_MASK; + remote_in_use_pattern = ADF_PF2VF_IN_USE_BY_PF; + int_bit = ADF_VF2PF_INT; + } else { + pfvf_offset = GET_PFVF_OPS(accel_dev)->get_pf2vf_offset(vf_nr); + lock = &accel_dev->pf.vf_info[vf_nr].pf2vf_lock; + local_in_use_mask = ADF_PF2VF_IN_USE_BY_PF_MASK; + local_in_use_pattern = ADF_PF2VF_IN_USE_BY_PF; + remote_in_use_mask = ADF_VF2PF_IN_USE_BY_VF_MASK; + remote_in_use_pattern = ADF_VF2PF_IN_USE_BY_VF; + int_bit = ADF_PF2VF_INT; + } + + msg &= ~local_in_use_mask; + msg |= local_in_use_pattern; + + mutex_lock(lock); + +start: + ret = 0; + + /* Check if the PFVF CSR is in use by remote function */ + val = ADF_CSR_RD(pmisc_bar_addr, pfvf_offset); + if ((val & remote_in_use_mask) == remote_in_use_pattern) { + dev_dbg(&GET_DEV(accel_dev), + "PFVF CSR in use by remote function\n"); + goto retry; + } + + /* Attempt to get ownership of the PFVF CSR */ + ADF_CSR_WR(pmisc_bar_addr, pfvf_offset, msg | int_bit); + + /* Wait for confirmation from remote func it received the message */ + do { + msleep(ADF_PFVF_MSG_ACK_DELAY); + val = ADF_CSR_RD(pmisc_bar_addr, pfvf_offset); + } while ((val & int_bit) && (count++ < ADF_PFVF_MSG_ACK_MAX_RETRY)); + + if (val & int_bit) { + dev_dbg(&GET_DEV(accel_dev), "ACK not received from remote\n"); + val &= ~int_bit; + ret = -EIO; + } + + if (val != msg) { + dev_dbg(&GET_DEV(accel_dev), + "Collision - PFVF CSR overwritten by remote function\n"); + goto retry; + } + + /* Finished with the PFVF CSR; relinquish it and leave msg in CSR */ + ADF_CSR_WR(pmisc_bar_addr, pfvf_offset, val & ~local_in_use_mask); +out: + mutex_unlock(lock); + return ret; + +retry: + if (--retries) { + msleep(ADF_PFVF_MSG_RETRY_DELAY); + goto start; + } else { + ret = -EBUSY; + goto out; + } +} + void adf_gen2_init_pf_pfvf_ops(struct adf_pfvf_ops *pfvf_ops) { pfvf_ops->enable_comms = adf_enable_pf2vf_comms; @@ -69,6 +164,7 @@ void adf_gen2_init_pf_pfvf_ops(struct adf_pfvf_ops *pfvf_ops) pfvf_ops->get_vf2pf_sources = adf_gen2_get_vf2pf_sources; pfvf_ops->enable_vf2pf_interrupts = adf_gen2_enable_vf2pf_interrupts; pfvf_ops->disable_vf2pf_interrupts = adf_gen2_disable_vf2pf_interrupts; + pfvf_ops->send_msg = adf_gen2_pfvf_send; } EXPORT_SYMBOL_GPL(adf_gen2_init_pf_pfvf_ops); @@ -77,5 +173,6 @@ void adf_gen2_init_vf_pfvf_ops(struct adf_pfvf_ops *pfvf_ops) pfvf_ops->enable_comms = adf_enable_vf2pf_comms; pfvf_ops->get_pf2vf_offset = adf_gen2_vf_get_pfvf_offset; pfvf_ops->get_vf2pf_offset = adf_gen2_vf_get_pfvf_offset; + pfvf_ops->send_msg = adf_gen2_pfvf_send; } EXPORT_SYMBOL_GPL(adf_gen2_init_vf_pfvf_ops); diff --git a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c index c420ec03081b4..074e521ed9e88 100644 --- a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c +++ b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) /* Copyright(c) 2015 - 2020 Intel Corporation */ -#include #include "adf_accel_devices.h" #include "adf_common_drv.h" #include "adf_pf2vf_msg.h" @@ -8,97 +7,10 @@ #define ADF_PFVF_MSG_COLLISION_DETECT_DELAY 10 #define ADF_PFVF_MSG_ACK_DELAY 2 #define ADF_PFVF_MSG_ACK_MAX_RETRY 100 -#define ADF_PFVF_MSG_RETRY_DELAY 5 -#define ADF_PFVF_MSG_MAX_RETRIES 3 #define ADF_PFVF_MSG_RESP_TIMEOUT (ADF_PFVF_MSG_ACK_DELAY * \ ADF_PFVF_MSG_ACK_MAX_RETRY + \ ADF_PFVF_MSG_COLLISION_DETECT_DELAY) -static int adf_iov_putmsg(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr) -{ - struct adf_accel_pci *pci_info = &accel_dev->accel_pci_dev; - struct adf_hw_device_data *hw_data = accel_dev->hw_device; - void __iomem *pmisc_bar_addr = - pci_info->pci_bars[hw_data->get_misc_bar_id(hw_data)].virt_addr; - u32 val, pf2vf_offset, count = 0; - u32 local_in_use_mask, local_in_use_pattern; - u32 remote_in_use_mask, remote_in_use_pattern; - struct mutex *lock; /* lock preventing concurrent acces of CSR */ - unsigned int retries = ADF_PFVF_MSG_MAX_RETRIES; - u32 int_bit; - int ret; - - if (accel_dev->is_vf) { - pf2vf_offset = hw_data->pfvf_ops.get_vf2pf_offset(0); - lock = &accel_dev->vf.vf2pf_lock; - local_in_use_mask = ADF_VF2PF_IN_USE_BY_VF_MASK; - local_in_use_pattern = ADF_VF2PF_IN_USE_BY_VF; - remote_in_use_mask = ADF_PF2VF_IN_USE_BY_PF_MASK; - remote_in_use_pattern = ADF_PF2VF_IN_USE_BY_PF; - int_bit = ADF_VF2PF_INT; - } else { - pf2vf_offset = hw_data->pfvf_ops.get_pf2vf_offset(vf_nr); - lock = &accel_dev->pf.vf_info[vf_nr].pf2vf_lock; - local_in_use_mask = ADF_PF2VF_IN_USE_BY_PF_MASK; - local_in_use_pattern = ADF_PF2VF_IN_USE_BY_PF; - remote_in_use_mask = ADF_VF2PF_IN_USE_BY_VF_MASK; - remote_in_use_pattern = ADF_VF2PF_IN_USE_BY_VF; - int_bit = ADF_PF2VF_INT; - } - - msg &= ~local_in_use_mask; - msg |= local_in_use_pattern; - - mutex_lock(lock); - -start: - ret = 0; - - /* Check if the PFVF CSR is in use by remote function */ - val = ADF_CSR_RD(pmisc_bar_addr, pf2vf_offset); - if ((val & remote_in_use_mask) == remote_in_use_pattern) { - dev_dbg(&GET_DEV(accel_dev), - "PFVF CSR in use by remote function\n"); - goto retry; - } - - /* Attempt to get ownership of the PFVF CSR */ - ADF_CSR_WR(pmisc_bar_addr, pf2vf_offset, msg | int_bit); - - /* Wait for confirmation from remote func it received the message */ - do { - msleep(ADF_PFVF_MSG_ACK_DELAY); - val = ADF_CSR_RD(pmisc_bar_addr, pf2vf_offset); - } while ((val & int_bit) && (count++ < ADF_PFVF_MSG_ACK_MAX_RETRY)); - - if (val & int_bit) { - dev_dbg(&GET_DEV(accel_dev), "ACK not received from remote\n"); - val &= ~int_bit; - ret = -EIO; - } - - if (val != msg) { - dev_dbg(&GET_DEV(accel_dev), - "Collision - PFVF CSR overwritten by remote function\n"); - goto retry; - } - - /* Finished with the PFVF CSR; relinquish it and leave msg in CSR */ - ADF_CSR_WR(pmisc_bar_addr, pf2vf_offset, val & ~local_in_use_mask); -out: - mutex_unlock(lock); - return ret; - -retry: - if (--retries) { - msleep(ADF_PFVF_MSG_RETRY_DELAY); - goto start; - } else { - ret = -EBUSY; - goto out; - } -} - /** * adf_send_pf2vf_msg() - send PF to VF message * @accel_dev: Pointer to acceleration device @@ -111,7 +23,7 @@ retry: */ static int adf_send_pf2vf_msg(struct adf_accel_dev *accel_dev, u8 vf_nr, u32 msg) { - return adf_iov_putmsg(accel_dev, msg, vf_nr); + return GET_PFVF_OPS(accel_dev)->send_msg(accel_dev, msg, vf_nr); } /** @@ -125,7 +37,7 @@ static int adf_send_pf2vf_msg(struct adf_accel_dev *accel_dev, u8 vf_nr, u32 msg */ int adf_send_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 msg) { - return adf_iov_putmsg(accel_dev, msg, 0); + return GET_PFVF_OPS(accel_dev)->send_msg(accel_dev, msg, 0); } /** diff --git a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.h b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.h index a7d8f83673453..73eb8f13ad095 100644 --- a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.h +++ b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.h @@ -49,7 +49,8 @@ * * When a PF or VF attempts to send a message in the lower or upper 16 bits, * respectively, the other 16 bits are written to first with a defined - * IN_USE_BY pattern as part of a collision control scheme (see adf_iov_putmsg). + * IN_USE_BY pattern as part of a collision control scheme (see function + * adf_gen2_pfvf_send() in adf_pf2vf_msg.c). */ #define ADF_PFVF_COMPAT_THIS_VERSION 0x1 /* PF<->VF compat */ -- GitLab From 1ea7c2beca5b200240f6480d36ebd6ca775a5fca Mon Sep 17 00:00:00 2001 From: Giovanni Cabiddu Date: Wed, 17 Nov 2021 14:30:50 +0000 Subject: [PATCH 0189/1112] crypto: qat - abstract PFVF receive logic Refactor the PFVF receive logic so it is common between PF and VF and make it device specific. This is in preparation for the introduction of PFVF support in the qat_4xxx driver since the receive logic differs between QAT GEN2 and QAT GEN4 devices. Signed-off-by: Giovanni Cabiddu Co-developed-by: Marco Chiappero Signed-off-by: Marco Chiappero Signed-off-by: Herbert Xu --- .../crypto/qat/qat_common/adf_accel_devices.h | 1 + drivers/crypto/qat/qat_common/adf_gen2_pfvf.c | 45 +++++++++++++++++++ drivers/crypto/qat/qat_common/adf_pf2vf_msg.c | 41 ++++++++--------- drivers/crypto/qat/qat_common/adf_vf2pf_msg.c | 38 +++++++--------- 4 files changed, 81 insertions(+), 44 deletions(-) diff --git a/drivers/crypto/qat/qat_common/adf_accel_devices.h b/drivers/crypto/qat/qat_common/adf_accel_devices.h index 8938149590833..35e62a73f9fa8 100644 --- a/drivers/crypto/qat/qat_common/adf_accel_devices.h +++ b/drivers/crypto/qat/qat_common/adf_accel_devices.h @@ -155,6 +155,7 @@ struct adf_pfvf_ops { void (*enable_vf2pf_interrupts)(void __iomem *pmisc_addr, u32 vf_mask); void (*disable_vf2pf_interrupts)(void __iomem *pmisc_addr, u32 vf_mask); int (*send_msg)(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr); + u32 (*recv_msg)(struct adf_accel_dev *accel_dev, u8 vf_nr); }; struct adf_hw_device_data { diff --git a/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c b/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c index 5eba042d453b7..f79c3ca28283a 100644 --- a/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c +++ b/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c @@ -156,6 +156,49 @@ retry: } } +static u32 adf_gen2_pfvf_recv(struct adf_accel_dev *accel_dev, u8 vf_nr) +{ + struct adf_accel_pci *pci_info = &accel_dev->accel_pci_dev; + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + void __iomem *pmisc_addr = + pci_info->pci_bars[hw_data->get_misc_bar_id(hw_data)].virt_addr; + u32 pfvf_offset; + u32 msg_origin; + u32 int_bit; + u32 msg; + + if (accel_dev->is_vf) { + pfvf_offset = GET_PFVF_OPS(accel_dev)->get_pf2vf_offset(0); + int_bit = ADF_PF2VF_INT; + msg_origin = ADF_PF2VF_MSGORIGIN_SYSTEM; + } else { + pfvf_offset = GET_PFVF_OPS(accel_dev)->get_vf2pf_offset(vf_nr); + int_bit = ADF_VF2PF_INT; + msg_origin = ADF_VF2PF_MSGORIGIN_SYSTEM; + } + + /* Read message */ + msg = ADF_CSR_RD(pmisc_addr, pfvf_offset); + if (!(msg & int_bit)) { + dev_info(&GET_DEV(accel_dev), + "Spurious PFVF interrupt, msg %X. Ignored\n", msg); + return 0; + } + + /* Ignore legacy non-system (non-kernel) VF2PF messages */ + if (!(msg & msg_origin)) { + dev_dbg(&GET_DEV(accel_dev), + "Ignored non-system message (0x%x);\n", msg); + return 0; + } + + /* To ACK, clear the INT bit */ + msg &= ~int_bit; + ADF_CSR_WR(pmisc_addr, pfvf_offset, msg); + + return msg; +} + void adf_gen2_init_pf_pfvf_ops(struct adf_pfvf_ops *pfvf_ops) { pfvf_ops->enable_comms = adf_enable_pf2vf_comms; @@ -165,6 +208,7 @@ void adf_gen2_init_pf_pfvf_ops(struct adf_pfvf_ops *pfvf_ops) pfvf_ops->enable_vf2pf_interrupts = adf_gen2_enable_vf2pf_interrupts; pfvf_ops->disable_vf2pf_interrupts = adf_gen2_disable_vf2pf_interrupts; pfvf_ops->send_msg = adf_gen2_pfvf_send; + pfvf_ops->recv_msg = adf_gen2_pfvf_recv; } EXPORT_SYMBOL_GPL(adf_gen2_init_pf_pfvf_ops); @@ -174,5 +218,6 @@ void adf_gen2_init_vf_pfvf_ops(struct adf_pfvf_ops *pfvf_ops) pfvf_ops->get_pf2vf_offset = adf_gen2_vf_get_pfvf_offset; pfvf_ops->get_vf2pf_offset = adf_gen2_vf_get_pfvf_offset; pfvf_ops->send_msg = adf_gen2_pfvf_send; + pfvf_ops->recv_msg = adf_gen2_pfvf_recv; } EXPORT_SYMBOL_GPL(adf_gen2_init_vf_pfvf_ops); diff --git a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c index 074e521ed9e88..c064e8bab50dd 100644 --- a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c +++ b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c @@ -40,6 +40,20 @@ int adf_send_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 msg) return GET_PFVF_OPS(accel_dev)->send_msg(accel_dev, msg, 0); } +/** + * adf_recv_vf2pf_msg() - receive a VF to PF message + * @accel_dev: Pointer to acceleration device + * @vf_nr: Number of the VF from where the message will be received + * + * This function allows the PF to receive a message from a specific VF. + * + * Return: a valid message on success, zero otherwise. + */ +static u32 adf_recv_vf2pf_msg(struct adf_accel_dev *accel_dev, u8 vf_nr) +{ + return GET_PFVF_OPS(accel_dev)->recv_msg(accel_dev, vf_nr); +} + /** * adf_send_vf2pf_req() - send VF2PF request message * @accel_dev: Pointer to acceleration device. @@ -163,31 +177,12 @@ static int adf_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr, bool adf_recv_and_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr) { - struct adf_hw_device_data *hw_data = accel_dev->hw_device; - int bar_id = hw_data->get_misc_bar_id(hw_data); - struct adf_bar *pmisc = &GET_BARS(accel_dev)[bar_id]; - void __iomem *pmisc_addr = pmisc->virt_addr; - u32 msg, resp = 0; - - /* Read message from the VF */ - msg = ADF_CSR_RD(pmisc_addr, hw_data->pfvf_ops.get_vf2pf_offset(vf_nr)); - if (!(msg & ADF_VF2PF_INT)) { - dev_info(&GET_DEV(accel_dev), - "Spurious VF2PF interrupt, msg %X. Ignored\n", msg); - return true; - } + u32 resp = 0; + u32 msg; - /* Ignore legacy non-system (non-kernel) VF2PF messages */ - if (!(msg & ADF_VF2PF_MSGORIGIN_SYSTEM)) { - dev_dbg(&GET_DEV(accel_dev), - "Ignored non-system message from VF%d (0x%x);\n", - vf_nr + 1, msg); + msg = adf_recv_vf2pf_msg(accel_dev, vf_nr); + if (!msg) return true; - } - - /* To ACK, clear the VF2PFINT bit */ - msg &= ~ADF_VF2PF_INT; - ADF_CSR_WR(pmisc_addr, hw_data->pfvf_ops.get_vf2pf_offset(vf_nr), msg); if (adf_handle_vf2pf_msg(accel_dev, vf_nr, msg, &resp)) return false; diff --git a/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c b/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c index d11eb60b3e867..f3660981ad6aa 100644 --- a/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c +++ b/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c @@ -47,6 +47,19 @@ void adf_vf2pf_notify_shutdown(struct adf_accel_dev *accel_dev) } EXPORT_SYMBOL_GPL(adf_vf2pf_notify_shutdown); +/** + * adf_recv_pf2vf_msg() - receive a PF to VF message + * @accel_dev: Pointer to acceleration device + * + * This function allows the VF to receive a message from the PF. + * + * Return: a valid message on success, zero otherwise. + */ +static u32 adf_recv_pf2vf_msg(struct adf_accel_dev *accel_dev) +{ + return GET_PFVF_OPS(accel_dev)->recv_msg(accel_dev, 0); +} + static bool adf_handle_pf2vf_msg(struct adf_accel_dev *accel_dev, u32 msg) { switch ((msg & ADF_PF2VF_MSGTYPE_MASK) >> ADF_PF2VF_MSGTYPE_SHIFT) { @@ -77,28 +90,11 @@ static bool adf_handle_pf2vf_msg(struct adf_accel_dev *accel_dev, u32 msg) bool adf_recv_and_handle_pf2vf_msg(struct adf_accel_dev *accel_dev) { - struct adf_hw_device_data *hw_data = accel_dev->hw_device; - struct adf_bar *pmisc = - &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)]; - void __iomem *pmisc_bar_addr = pmisc->virt_addr; - u32 offset = hw_data->pfvf_ops.get_pf2vf_offset(0); u32 msg; - /* Read the message from PF */ - msg = ADF_CSR_RD(pmisc_bar_addr, offset); - if (!(msg & ADF_PF2VF_INT)) { - dev_info(&GET_DEV(accel_dev), - "Spurious PF2VF interrupt, msg %X. Ignored\n", msg); - return true; - } - - if (!(msg & ADF_PF2VF_MSGORIGIN_SYSTEM)) - /* Ignore legacy non-system (non-kernel) PF2VF messages */ - return true; - - /* To ack, clear the PF2VFINT bit */ - msg &= ~ADF_PF2VF_INT; - ADF_CSR_WR(pmisc_bar_addr, offset, msg); + msg = adf_recv_pf2vf_msg(accel_dev); + if (msg) + return adf_handle_pf2vf_msg(accel_dev, msg); - return adf_handle_pf2vf_msg(accel_dev, msg); + return true; } -- GitLab From 09ce899a592f7a8ee19857ad0ef394e31be83c1d Mon Sep 17 00:00:00 2001 From: Marco Chiappero Date: Wed, 17 Nov 2021 14:30:51 +0000 Subject: [PATCH 0190/1112] crypto: qat - reorganize PFVF code Reorganize the structure of the PFVF code by moving the content of adf_pf2vf_msg.c and adf_vf2pf_msg.c. The logic that handles high level messages has been moved to adf_pfvf_pf_msg.c and adf_pfvf_vf_msg.c. The implementation of low level communication primitives and the protocol is now included in adf_pfvf_pf_proto.c and adf_pfvf_vf_proto.c. In addition, the file adf_pf2vf_msg.h has been renamed in adf_pfvf_msg.h since it common to PF and VF and the copyright date for the touched files has been updated. Signed-off-by: Marco Chiappero Co-developed-by: Giovanni Cabiddu Signed-off-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- .../crypto/qat/qat_4xxx/adf_4xxx_hw_data.c | 4 +- .../crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c | 4 +- .../qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c | 5 +- .../crypto/qat/qat_c62x/adf_c62x_hw_data.c | 4 +- .../qat/qat_c62xvf/adf_c62xvf_hw_data.c | 5 +- drivers/crypto/qat/qat_common/Makefile | 5 +- .../crypto/qat/qat_common/adf_common_drv.h | 22 +-- drivers/crypto/qat/qat_common/adf_gen2_pfvf.c | 4 +- .../{adf_pf2vf_msg.h => adf_pfvf_msg.h} | 8 +- .../crypto/qat/qat_common/adf_pfvf_pf_msg.c | 21 +++ .../crypto/qat/qat_common/adf_pfvf_pf_msg.h | 10 ++ .../{adf_pf2vf_msg.c => adf_pfvf_pf_proto.c} | 137 +----------------- .../crypto/qat/qat_common/adf_pfvf_pf_proto.h | 13 ++ .../crypto/qat/qat_common/adf_pfvf_vf_msg.c | 93 ++++++++++++ .../crypto/qat/qat_common/adf_pfvf_vf_msg.h | 21 +++ .../crypto/qat/qat_common/adf_pfvf_vf_proto.c | 133 +++++++++++++++++ .../crypto/qat/qat_common/adf_pfvf_vf_proto.h | 14 ++ drivers/crypto/qat/qat_common/adf_sriov.c | 4 +- drivers/crypto/qat/qat_common/adf_vf2pf_msg.c | 100 ------------- drivers/crypto/qat/qat_common/adf_vf_isr.c | 1 - .../qat/qat_dh895xcc/adf_dh895xcc_hw_data.c | 4 +- .../qat_dh895xccvf/adf_dh895xccvf_hw_data.c | 5 +- 22 files changed, 341 insertions(+), 276 deletions(-) rename drivers/crypto/qat/qat_common/{adf_pf2vf_msg.h => adf_pfvf_msg.h} (96%) create mode 100644 drivers/crypto/qat/qat_common/adf_pfvf_pf_msg.c create mode 100644 drivers/crypto/qat/qat_common/adf_pfvf_pf_msg.h rename drivers/crypto/qat/qat_common/{adf_pf2vf_msg.c => adf_pfvf_pf_proto.c} (53%) create mode 100644 drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.h create mode 100644 drivers/crypto/qat/qat_common/adf_pfvf_vf_msg.c create mode 100644 drivers/crypto/qat/qat_common/adf_pfvf_vf_msg.h create mode 100644 drivers/crypto/qat/qat_common/adf_pfvf_vf_proto.c create mode 100644 drivers/crypto/qat/qat_common/adf_pfvf_vf_proto.h delete mode 100644 drivers/crypto/qat/qat_common/adf_vf2pf_msg.c diff --git a/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c b/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c index ec57a2e2d1fcb..2a878d98f81aa 100644 --- a/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c +++ b/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c @@ -1,10 +1,10 @@ // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) -/* Copyright(c) 2020 Intel Corporation */ +/* Copyright(c) 2020 - 2021 Intel Corporation */ #include #include #include -#include #include +#include #include "adf_4xxx_hw_data.h" #include "icp_qat_hw.h" diff --git a/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c b/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c index d25f78660b8cb..94a11e72edae1 100644 --- a/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c +++ b/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c @@ -1,10 +1,10 @@ // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) -/* Copyright(c) 2014 - 2020 Intel Corporation */ +/* Copyright(c) 2014 - 2021 Intel Corporation */ #include #include -#include #include #include +#include #include "adf_c3xxx_hw_data.h" #include "icp_qat_hw.h" diff --git a/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c b/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c index c39733320063a..4c43a0d93fa60 100644 --- a/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c +++ b/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c @@ -1,10 +1,11 @@ // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) -/* Copyright(c) 2015 - 2020 Intel Corporation */ +/* Copyright(c) 2015 - 2021 Intel Corporation */ #include -#include #include #include #include +#include +#include #include "adf_c3xxxvf_hw_data.h" static struct adf_hw_device_class c3xxxiov_class = { diff --git a/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c b/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c index f24a01e1bc1a1..3cb1a88d97aec 100644 --- a/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c +++ b/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c @@ -1,10 +1,10 @@ // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) -/* Copyright(c) 2014 - 2020 Intel Corporation */ +/* Copyright(c) 2014 - 2021 Intel Corporation */ #include #include -#include #include #include +#include #include "adf_c62x_hw_data.h" #include "icp_qat_hw.h" diff --git a/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c b/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c index 03097bbe600a2..c4b23e2cd5796 100644 --- a/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c +++ b/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c @@ -1,10 +1,11 @@ // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) -/* Copyright(c) 2015 - 2020 Intel Corporation */ +/* Copyright(c) 2015 - 2021 Intel Corporation */ #include -#include #include #include #include +#include +#include #include "adf_c62xvf_hw_data.h" static struct adf_hw_device_class c62xiov_class = { diff --git a/drivers/crypto/qat/qat_common/Makefile b/drivers/crypto/qat/qat_common/Makefile index 676aef6533e0f..1376504d16ff7 100644 --- a/drivers/crypto/qat/qat_common/Makefile +++ b/drivers/crypto/qat/qat_common/Makefile @@ -19,6 +19,7 @@ intel_qat-objs := adf_cfg.o \ qat_hal.o intel_qat-$(CONFIG_DEBUG_FS) += adf_transport_debug.o -intel_qat-$(CONFIG_PCI_IOV) += adf_sriov.o adf_pf2vf_msg.o \ - adf_vf2pf_msg.o adf_vf_isr.o \ +intel_qat-$(CONFIG_PCI_IOV) += adf_sriov.o adf_vf_isr.o \ + adf_pfvf_pf_msg.o adf_pfvf_pf_proto.o \ + adf_pfvf_vf_msg.o adf_pfvf_vf_proto.o \ adf_gen2_pfvf.o diff --git a/drivers/crypto/qat/qat_common/adf_common_drv.h b/drivers/crypto/qat/qat_common/adf_common_drv.h index c0699e4535027..2d8b720855054 100644 --- a/drivers/crypto/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/qat/qat_common/adf_common_drv.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) */ -/* Copyright(c) 2014 - 2020 Intel Corporation */ +/* Copyright(c) 2014 - 2021 Intel Corporation */ #ifndef ADF_DRV_H #define ADF_DRV_H @@ -62,8 +62,6 @@ int adf_dev_start(struct adf_accel_dev *accel_dev); void adf_dev_stop(struct adf_accel_dev *accel_dev); void adf_dev_shutdown(struct adf_accel_dev *accel_dev); -void adf_pf2vf_notify_restarting(struct adf_accel_dev *accel_dev); -int adf_enable_vf2pf_comms(struct adf_accel_dev *accel_dev); void adf_devmgr_update_class_index(struct adf_hw_device_data *hw_data); void adf_clean_vf_map(bool); @@ -199,13 +197,9 @@ void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, bool adf_recv_and_handle_pf2vf_msg(struct adf_accel_dev *accel_dev); bool adf_recv_and_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr); int adf_pf2vf_handle_pf_restarting(struct adf_accel_dev *accel_dev); -int adf_enable_pf2vf_comms(struct adf_accel_dev *accel_dev); void adf_enable_pf2vf_interrupts(struct adf_accel_dev *accel_dev); void adf_disable_pf2vf_interrupts(struct adf_accel_dev *accel_dev); void adf_schedule_vf2pf_handler(struct adf_accel_vf_info *vf_info); -int adf_send_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 msg); -int adf_vf2pf_notify_init(struct adf_accel_dev *accel_dev); -void adf_vf2pf_notify_shutdown(struct adf_accel_dev *accel_dev); int adf_init_pf_wq(void); void adf_exit_pf_wq(void); int adf_init_vf_wq(void); @@ -214,11 +208,6 @@ void adf_flush_vf_wq(struct adf_accel_dev *accel_dev); #else #define adf_sriov_configure NULL -static inline int adf_enable_pf2vf_comms(struct adf_accel_dev *accel_dev) -{ - return 0; -} - static inline void adf_disable_sriov(struct adf_accel_dev *accel_dev) { } @@ -231,15 +220,6 @@ static inline void adf_disable_pf2vf_interrupts(struct adf_accel_dev *accel_dev) { } -static inline int adf_vf2pf_notify_init(struct adf_accel_dev *accel_dev) -{ - return 0; -} - -static inline void adf_vf2pf_notify_shutdown(struct adf_accel_dev *accel_dev) -{ -} - static inline int adf_init_pf_wq(void) { return 0; diff --git a/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c b/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c index f79c3ca28283a..f3a0a9d651e0d 100644 --- a/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c +++ b/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c @@ -6,7 +6,9 @@ #include "adf_accel_devices.h" #include "adf_common_drv.h" #include "adf_gen2_pfvf.h" -#include "adf_pf2vf_msg.h" +#include "adf_pfvf_msg.h" +#include "adf_pfvf_pf_proto.h" +#include "adf_pfvf_vf_proto.h" /* VF2PF interrupts */ #define ADF_GEN2_ERR_REG_VF2PF(vf_src) (((vf_src) & 0x01FFFE00) >> 9) diff --git a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.h b/drivers/crypto/qat/qat_common/adf_pfvf_msg.h similarity index 96% rename from drivers/crypto/qat/qat_common/adf_pf2vf_msg.h rename to drivers/crypto/qat/qat_common/adf_pfvf_msg.h index 73eb8f13ad095..0520466563fd6 100644 --- a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.h +++ b/drivers/crypto/qat/qat_common/adf_pfvf_msg.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) */ -/* Copyright(c) 2015 - 2020 Intel Corporation */ -#ifndef ADF_PF2VF_MSG_H -#define ADF_PF2VF_MSG_H +/* Copyright(c) 2015 - 2021 Intel Corporation */ +#ifndef ADF_PFVF_MSG_H +#define ADF_PFVF_MSG_H /* * PF<->VF Messaging @@ -91,4 +91,4 @@ /* VF->PF Compatible Version Request */ #define ADF_VF2PF_COMPAT_VER_REQ_SHIFT 22 -#endif /* ADF_IOV_MSG_H */ +#endif /* ADF_PFVF_MSG_H */ diff --git a/drivers/crypto/qat/qat_common/adf_pfvf_pf_msg.c b/drivers/crypto/qat/qat_common/adf_pfvf_pf_msg.c new file mode 100644 index 0000000000000..647b82e6c4baf --- /dev/null +++ b/drivers/crypto/qat/qat_common/adf_pfvf_pf_msg.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) +/* Copyright(c) 2015 - 2021 Intel Corporation */ +#include +#include "adf_accel_devices.h" +#include "adf_pfvf_msg.h" +#include "adf_pfvf_pf_msg.h" +#include "adf_pfvf_pf_proto.h" + +void adf_pf2vf_notify_restarting(struct adf_accel_dev *accel_dev) +{ + struct adf_accel_vf_info *vf; + u32 msg = (ADF_PF2VF_MSGORIGIN_SYSTEM | + (ADF_PF2VF_MSGTYPE_RESTARTING << ADF_PF2VF_MSGTYPE_SHIFT)); + int i, num_vfs = pci_num_vf(accel_to_pci_dev(accel_dev)); + + for (i = 0, vf = accel_dev->pf.vf_info; i < num_vfs; i++, vf++) { + if (vf->init && adf_send_pf2vf_msg(accel_dev, i, msg)) + dev_err(&GET_DEV(accel_dev), + "Failed to send restarting msg to VF%d\n", i); + } +} diff --git a/drivers/crypto/qat/qat_common/adf_pfvf_pf_msg.h b/drivers/crypto/qat/qat_common/adf_pfvf_pf_msg.h new file mode 100644 index 0000000000000..187807b1ff880 --- /dev/null +++ b/drivers/crypto/qat/qat_common/adf_pfvf_pf_msg.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) */ +/* Copyright(c) 2021 Intel Corporation */ +#ifndef ADF_PFVF_PF_MSG_H +#define ADF_PFVF_PF_MSG_H + +#include "adf_accel_devices.h" + +void adf_pf2vf_notify_restarting(struct adf_accel_dev *accel_dev); + +#endif /* ADF_PFVF_PF_MSG_H */ diff --git a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c b/drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.c similarity index 53% rename from drivers/crypto/qat/qat_common/adf_pf2vf_msg.c rename to drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.c index c064e8bab50dd..ac6a54cf17f6d 100644 --- a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c +++ b/drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.c @@ -1,15 +1,11 @@ // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) -/* Copyright(c) 2015 - 2020 Intel Corporation */ +/* Copyright(c) 2015 - 2021 Intel Corporation */ +#include +#include #include "adf_accel_devices.h" #include "adf_common_drv.h" -#include "adf_pf2vf_msg.h" - -#define ADF_PFVF_MSG_COLLISION_DETECT_DELAY 10 -#define ADF_PFVF_MSG_ACK_DELAY 2 -#define ADF_PFVF_MSG_ACK_MAX_RETRY 100 -#define ADF_PFVF_MSG_RESP_TIMEOUT (ADF_PFVF_MSG_ACK_DELAY * \ - ADF_PFVF_MSG_ACK_MAX_RETRY + \ - ADF_PFVF_MSG_COLLISION_DETECT_DELAY) +#include "adf_pfvf_msg.h" +#include "adf_pfvf_pf_proto.h" /** * adf_send_pf2vf_msg() - send PF to VF message @@ -21,25 +17,11 @@ * * Return: 0 on success, error code otherwise. */ -static int adf_send_pf2vf_msg(struct adf_accel_dev *accel_dev, u8 vf_nr, u32 msg) +int adf_send_pf2vf_msg(struct adf_accel_dev *accel_dev, u8 vf_nr, u32 msg) { return GET_PFVF_OPS(accel_dev)->send_msg(accel_dev, msg, vf_nr); } -/** - * adf_send_vf2pf_msg() - send VF to PF message - * @accel_dev: Pointer to acceleration device - * @msg: Message to send - * - * This function allows the VF to send a message to the PF. - * - * Return: 0 on success, error code otherwise. - */ -int adf_send_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 msg) -{ - return GET_PFVF_OPS(accel_dev)->send_msg(accel_dev, msg, 0); -} - /** * adf_recv_vf2pf_msg() - receive a VF to PF message * @accel_dev: Pointer to acceleration device @@ -54,42 +36,6 @@ static u32 adf_recv_vf2pf_msg(struct adf_accel_dev *accel_dev, u8 vf_nr) return GET_PFVF_OPS(accel_dev)->recv_msg(accel_dev, vf_nr); } -/** - * adf_send_vf2pf_req() - send VF2PF request message - * @accel_dev: Pointer to acceleration device. - * @msg: Request message to send - * - * This function sends a message that requires a response from the VF to the PF - * and waits for a reply. - * - * Return: 0 on success, error code otherwise. - */ -static int adf_send_vf2pf_req(struct adf_accel_dev *accel_dev, u32 msg) -{ - unsigned long timeout = msecs_to_jiffies(ADF_PFVF_MSG_RESP_TIMEOUT); - int ret; - - reinit_completion(&accel_dev->vf.iov_msg_completion); - - /* Send request from VF to PF */ - ret = adf_send_vf2pf_msg(accel_dev, msg); - if (ret) { - dev_err(&GET_DEV(accel_dev), - "Failed to send request msg to PF\n"); - return ret; - } - - /* Wait for response */ - if (!wait_for_completion_timeout(&accel_dev->vf.iov_msg_completion, - timeout)) { - dev_err(&GET_DEV(accel_dev), - "PFVF request/response message timeout expired\n"); - return -EIO; - } - - return 0; -} - static int adf_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr, u32 msg, u32 *response) { @@ -193,77 +139,6 @@ bool adf_recv_and_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr) return true; } -void adf_pf2vf_notify_restarting(struct adf_accel_dev *accel_dev) -{ - struct adf_accel_vf_info *vf; - u32 msg = (ADF_PF2VF_MSGORIGIN_SYSTEM | - (ADF_PF2VF_MSGTYPE_RESTARTING << ADF_PF2VF_MSGTYPE_SHIFT)); - int i, num_vfs = pci_num_vf(accel_to_pci_dev(accel_dev)); - - for (i = 0, vf = accel_dev->pf.vf_info; i < num_vfs; i++, vf++) { - if (vf->init && adf_send_pf2vf_msg(accel_dev, i, msg)) - dev_err(&GET_DEV(accel_dev), - "Failed to send restarting msg to VF%d\n", i); - } -} - -static int adf_vf2pf_request_version(struct adf_accel_dev *accel_dev) -{ - struct adf_hw_device_data *hw_data = accel_dev->hw_device; - u32 msg = 0; - int ret; - - msg = ADF_VF2PF_MSGORIGIN_SYSTEM; - msg |= ADF_VF2PF_MSGTYPE_COMPAT_VER_REQ << ADF_VF2PF_MSGTYPE_SHIFT; - msg |= ADF_PFVF_COMPAT_THIS_VERSION << ADF_VF2PF_COMPAT_VER_REQ_SHIFT; - BUILD_BUG_ON(ADF_PFVF_COMPAT_THIS_VERSION > 255); - - ret = adf_send_vf2pf_req(accel_dev, msg); - if (ret) { - dev_err(&GET_DEV(accel_dev), - "Failed to send Compatibility Version Request.\n"); - return ret; - } - - /* Response from PF received, check compatibility */ - switch (accel_dev->vf.compatible) { - case ADF_PF2VF_VF_COMPATIBLE: - break; - case ADF_PF2VF_VF_COMPAT_UNKNOWN: - /* VF is newer than PF and decides whether it is compatible */ - if (accel_dev->vf.pf_version >= hw_data->min_iov_compat_ver) { - accel_dev->vf.compatible = ADF_PF2VF_VF_COMPATIBLE; - break; - } - fallthrough; - case ADF_PF2VF_VF_INCOMPATIBLE: - dev_err(&GET_DEV(accel_dev), - "PF (vers %d) and VF (vers %d) are not compatible\n", - accel_dev->vf.pf_version, - ADF_PFVF_COMPAT_THIS_VERSION); - return -EINVAL; - default: - dev_err(&GET_DEV(accel_dev), - "Invalid response from PF; assume not compatible\n"); - return -EINVAL; - } - return ret; -} - -/** - * adf_enable_vf2pf_comms() - Function enables communication from vf to pf - * - * @accel_dev: Pointer to acceleration device virtual function. - * - * Return: 0 on success, error code otherwise. - */ -int adf_enable_vf2pf_comms(struct adf_accel_dev *accel_dev) -{ - adf_enable_pf2vf_interrupts(accel_dev); - return adf_vf2pf_request_version(accel_dev); -} -EXPORT_SYMBOL_GPL(adf_enable_vf2pf_comms); - /** * adf_enable_pf2vf_comms() - Function enables communication from pf to vf * diff --git a/drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.h b/drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.h new file mode 100644 index 0000000000000..63245407bfb6f --- /dev/null +++ b/drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) */ +/* Copyright(c) 2021 Intel Corporation */ +#ifndef ADF_PFVF_PF_PROTO_H +#define ADF_PFVF_PF_PROTO_H + +#include +#include "adf_accel_devices.h" + +int adf_send_pf2vf_msg(struct adf_accel_dev *accel_dev, u8 vf_nr, u32 msg); + +int adf_enable_pf2vf_comms(struct adf_accel_dev *accel_dev); + +#endif /* ADF_PFVF_PF_PROTO_H */ diff --git a/drivers/crypto/qat/qat_common/adf_pfvf_vf_msg.c b/drivers/crypto/qat/qat_common/adf_pfvf_vf_msg.c new file mode 100644 index 0000000000000..7969a644e24b7 --- /dev/null +++ b/drivers/crypto/qat/qat_common/adf_pfvf_vf_msg.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) +/* Copyright(c) 2015 - 2021 Intel Corporation */ +#include "adf_accel_devices.h" +#include "adf_common_drv.h" +#include "adf_pfvf_msg.h" +#include "adf_pfvf_vf_msg.h" +#include "adf_pfvf_vf_proto.h" + +/** + * adf_vf2pf_notify_init() - send init msg to PF + * @accel_dev: Pointer to acceleration VF device. + * + * Function sends an init message from the VF to a PF + * + * Return: 0 on success, error code otherwise. + */ +int adf_vf2pf_notify_init(struct adf_accel_dev *accel_dev) +{ + u32 msg = (ADF_VF2PF_MSGORIGIN_SYSTEM | + (ADF_VF2PF_MSGTYPE_INIT << ADF_VF2PF_MSGTYPE_SHIFT)); + + if (adf_send_vf2pf_msg(accel_dev, msg)) { + dev_err(&GET_DEV(accel_dev), + "Failed to send Init event to PF\n"); + return -EFAULT; + } + set_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status); + return 0; +} +EXPORT_SYMBOL_GPL(adf_vf2pf_notify_init); + +/** + * adf_vf2pf_notify_shutdown() - send shutdown msg to PF + * @accel_dev: Pointer to acceleration VF device. + * + * Function sends a shutdown message from the VF to a PF + * + * Return: void + */ +void adf_vf2pf_notify_shutdown(struct adf_accel_dev *accel_dev) +{ + u32 msg = (ADF_VF2PF_MSGORIGIN_SYSTEM | + (ADF_VF2PF_MSGTYPE_SHUTDOWN << ADF_VF2PF_MSGTYPE_SHIFT)); + + if (test_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status)) + if (adf_send_vf2pf_msg(accel_dev, msg)) + dev_err(&GET_DEV(accel_dev), + "Failed to send Shutdown event to PF\n"); +} +EXPORT_SYMBOL_GPL(adf_vf2pf_notify_shutdown); + +int adf_vf2pf_request_version(struct adf_accel_dev *accel_dev) +{ + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + u32 msg = 0; + int ret; + + msg = ADF_VF2PF_MSGORIGIN_SYSTEM; + msg |= ADF_VF2PF_MSGTYPE_COMPAT_VER_REQ << ADF_VF2PF_MSGTYPE_SHIFT; + msg |= ADF_PFVF_COMPAT_THIS_VERSION << ADF_VF2PF_COMPAT_VER_REQ_SHIFT; + BUILD_BUG_ON(ADF_PFVF_COMPAT_THIS_VERSION > 255); + + ret = adf_send_vf2pf_req(accel_dev, msg); + if (ret) { + dev_err(&GET_DEV(accel_dev), + "Failed to send Compatibility Version Request.\n"); + return ret; + } + + /* Response from PF received, check compatibility */ + switch (accel_dev->vf.compatible) { + case ADF_PF2VF_VF_COMPATIBLE: + break; + case ADF_PF2VF_VF_COMPAT_UNKNOWN: + /* VF is newer than PF and decides whether it is compatible */ + if (accel_dev->vf.pf_version >= hw_data->min_iov_compat_ver) { + accel_dev->vf.compatible = ADF_PF2VF_VF_COMPATIBLE; + break; + } + fallthrough; + case ADF_PF2VF_VF_INCOMPATIBLE: + dev_err(&GET_DEV(accel_dev), + "PF (vers %d) and VF (vers %d) are not compatible\n", + accel_dev->vf.pf_version, + ADF_PFVF_COMPAT_THIS_VERSION); + return -EINVAL; + default: + dev_err(&GET_DEV(accel_dev), + "Invalid response from PF; assume not compatible\n"); + return -EINVAL; + } + return ret; +} diff --git a/drivers/crypto/qat/qat_common/adf_pfvf_vf_msg.h b/drivers/crypto/qat/qat_common/adf_pfvf_vf_msg.h new file mode 100644 index 0000000000000..5091b5b2fd8f3 --- /dev/null +++ b/drivers/crypto/qat/qat_common/adf_pfvf_vf_msg.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) */ +/* Copyright(c) 2021 Intel Corporation */ +#ifndef ADF_PFVF_VF_MSG_H +#define ADF_PFVF_VF_MSG_H + +#if defined(CONFIG_PCI_IOV) +int adf_vf2pf_notify_init(struct adf_accel_dev *accel_dev); +void adf_vf2pf_notify_shutdown(struct adf_accel_dev *accel_dev); +int adf_vf2pf_request_version(struct adf_accel_dev *accel_dev); +#else +static inline int adf_vf2pf_notify_init(struct adf_accel_dev *accel_dev) +{ + return 0; +} + +static inline void adf_vf2pf_notify_shutdown(struct adf_accel_dev *accel_dev) +{ +} +#endif + +#endif /* ADF_PFVF_VF_MSG_H */ diff --git a/drivers/crypto/qat/qat_common/adf_pfvf_vf_proto.c b/drivers/crypto/qat/qat_common/adf_pfvf_vf_proto.c new file mode 100644 index 0000000000000..62817bcec121e --- /dev/null +++ b/drivers/crypto/qat/qat_common/adf_pfvf_vf_proto.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) +/* Copyright(c) 2015 - 2021 Intel Corporation */ +#include +#include +#include "adf_accel_devices.h" +#include "adf_common_drv.h" +#include "adf_pfvf_msg.h" +#include "adf_pfvf_vf_msg.h" +#include "adf_pfvf_vf_proto.h" + +#define ADF_PFVF_MSG_COLLISION_DETECT_DELAY 10 +#define ADF_PFVF_MSG_ACK_DELAY 2 +#define ADF_PFVF_MSG_ACK_MAX_RETRY 100 + +#define ADF_PFVF_MSG_RESP_TIMEOUT (ADF_PFVF_MSG_ACK_DELAY * \ + ADF_PFVF_MSG_ACK_MAX_RETRY + \ + ADF_PFVF_MSG_COLLISION_DETECT_DELAY) + +/** + * adf_send_vf2pf_msg() - send VF to PF message + * @accel_dev: Pointer to acceleration device + * @msg: Message to send + * + * This function allows the VF to send a message to the PF. + * + * Return: 0 on success, error code otherwise. + */ +int adf_send_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 msg) +{ + return GET_PFVF_OPS(accel_dev)->send_msg(accel_dev, msg, 0); +} + +/** + * adf_recv_pf2vf_msg() - receive a PF to VF message + * @accel_dev: Pointer to acceleration device + * + * This function allows the VF to receive a message from the PF. + * + * Return: a valid message on success, zero otherwise. + */ +static u32 adf_recv_pf2vf_msg(struct adf_accel_dev *accel_dev) +{ + return GET_PFVF_OPS(accel_dev)->recv_msg(accel_dev, 0); +} + +/** + * adf_send_vf2pf_req() - send VF2PF request message + * @accel_dev: Pointer to acceleration device. + * @msg: Request message to send + * + * This function sends a message that requires a response from the VF to the PF + * and waits for a reply. + * + * Return: 0 on success, error code otherwise. + */ +int adf_send_vf2pf_req(struct adf_accel_dev *accel_dev, u32 msg) +{ + unsigned long timeout = msecs_to_jiffies(ADF_PFVF_MSG_RESP_TIMEOUT); + int ret; + + reinit_completion(&accel_dev->vf.iov_msg_completion); + + /* Send request from VF to PF */ + ret = adf_send_vf2pf_msg(accel_dev, msg); + if (ret) { + dev_err(&GET_DEV(accel_dev), + "Failed to send request msg to PF\n"); + return ret; + } + + /* Wait for response */ + if (!wait_for_completion_timeout(&accel_dev->vf.iov_msg_completion, + timeout)) { + dev_err(&GET_DEV(accel_dev), + "PFVF request/response message timeout expired\n"); + return -EIO; + } + + return 0; +} + +static bool adf_handle_pf2vf_msg(struct adf_accel_dev *accel_dev, u32 msg) +{ + switch ((msg & ADF_PF2VF_MSGTYPE_MASK) >> ADF_PF2VF_MSGTYPE_SHIFT) { + case ADF_PF2VF_MSGTYPE_RESTARTING: + dev_dbg(&GET_DEV(accel_dev), + "Restarting msg received from PF 0x%x\n", msg); + + adf_pf2vf_handle_pf_restarting(accel_dev); + return false; + case ADF_PF2VF_MSGTYPE_VERSION_RESP: + dev_dbg(&GET_DEV(accel_dev), + "Version resp received from PF 0x%x\n", msg); + accel_dev->vf.pf_version = + (msg & ADF_PF2VF_VERSION_RESP_VERS_MASK) >> + ADF_PF2VF_VERSION_RESP_VERS_SHIFT; + accel_dev->vf.compatible = + (msg & ADF_PF2VF_VERSION_RESP_RESULT_MASK) >> + ADF_PF2VF_VERSION_RESP_RESULT_SHIFT; + complete(&accel_dev->vf.iov_msg_completion); + return true; + default: + dev_err(&GET_DEV(accel_dev), + "Unknown PF2VF message(0x%x)\n", msg); + } + + return false; +} + +bool adf_recv_and_handle_pf2vf_msg(struct adf_accel_dev *accel_dev) +{ + u32 msg; + + msg = adf_recv_pf2vf_msg(accel_dev); + if (msg) + return adf_handle_pf2vf_msg(accel_dev, msg); + + return true; +} + +/** + * adf_enable_vf2pf_comms() - Function enables communication from vf to pf + * + * @accel_dev: Pointer to acceleration device virtual function. + * + * Return: 0 on success, error code otherwise. + */ +int adf_enable_vf2pf_comms(struct adf_accel_dev *accel_dev) +{ + adf_enable_pf2vf_interrupts(accel_dev); + return adf_vf2pf_request_version(accel_dev); +} +EXPORT_SYMBOL_GPL(adf_enable_vf2pf_comms); diff --git a/drivers/crypto/qat/qat_common/adf_pfvf_vf_proto.h b/drivers/crypto/qat/qat_common/adf_pfvf_vf_proto.h new file mode 100644 index 0000000000000..a3ab24c7d18bd --- /dev/null +++ b/drivers/crypto/qat/qat_common/adf_pfvf_vf_proto.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) */ +/* Copyright(c) 2021 Intel Corporation */ +#ifndef ADF_PFVF_VF_PROTO_H +#define ADF_PFVF_VF_PROTO_H + +#include +#include "adf_accel_devices.h" + +int adf_send_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 msg); +int adf_send_vf2pf_req(struct adf_accel_dev *accel_dev, u32 msg); + +int adf_enable_vf2pf_comms(struct adf_accel_dev *accel_dev); + +#endif /* ADF_PFVF_VF_PROTO_H */ diff --git a/drivers/crypto/qat/qat_common/adf_sriov.c b/drivers/crypto/qat/qat_common/adf_sriov.c index 342063406c196..429990c5e0f34 100644 --- a/drivers/crypto/qat/qat_common/adf_sriov.c +++ b/drivers/crypto/qat/qat_common/adf_sriov.c @@ -1,12 +1,12 @@ // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) -/* Copyright(c) 2015 - 2020 Intel Corporation */ +/* Copyright(c) 2015 - 2021 Intel Corporation */ #include #include #include #include #include "adf_common_drv.h" #include "adf_cfg.h" -#include "adf_pf2vf_msg.h" +#include "adf_pfvf_pf_msg.h" static struct workqueue_struct *pf2vf_resp_wq; diff --git a/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c b/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c deleted file mode 100644 index f3660981ad6aa..0000000000000 --- a/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c +++ /dev/null @@ -1,100 +0,0 @@ -// SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) -/* Copyright(c) 2015 - 2020 Intel Corporation */ -#include "adf_accel_devices.h" -#include "adf_common_drv.h" -#include "adf_pf2vf_msg.h" - -/** - * adf_vf2pf_notify_init() - send init msg to PF - * @accel_dev: Pointer to acceleration VF device. - * - * Function sends an init message from the VF to a PF - * - * Return: 0 on success, error code otherwise. - */ -int adf_vf2pf_notify_init(struct adf_accel_dev *accel_dev) -{ - u32 msg = (ADF_VF2PF_MSGORIGIN_SYSTEM | - (ADF_VF2PF_MSGTYPE_INIT << ADF_VF2PF_MSGTYPE_SHIFT)); - - if (adf_send_vf2pf_msg(accel_dev, msg)) { - dev_err(&GET_DEV(accel_dev), - "Failed to send Init event to PF\n"); - return -EFAULT; - } - set_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status); - return 0; -} -EXPORT_SYMBOL_GPL(adf_vf2pf_notify_init); - -/** - * adf_vf2pf_notify_shutdown() - send shutdown msg to PF - * @accel_dev: Pointer to acceleration VF device. - * - * Function sends a shutdown message from the VF to a PF - * - * Return: void - */ -void adf_vf2pf_notify_shutdown(struct adf_accel_dev *accel_dev) -{ - u32 msg = (ADF_VF2PF_MSGORIGIN_SYSTEM | - (ADF_VF2PF_MSGTYPE_SHUTDOWN << ADF_VF2PF_MSGTYPE_SHIFT)); - - if (test_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status)) - if (adf_send_vf2pf_msg(accel_dev, msg)) - dev_err(&GET_DEV(accel_dev), - "Failed to send Shutdown event to PF\n"); -} -EXPORT_SYMBOL_GPL(adf_vf2pf_notify_shutdown); - -/** - * adf_recv_pf2vf_msg() - receive a PF to VF message - * @accel_dev: Pointer to acceleration device - * - * This function allows the VF to receive a message from the PF. - * - * Return: a valid message on success, zero otherwise. - */ -static u32 adf_recv_pf2vf_msg(struct adf_accel_dev *accel_dev) -{ - return GET_PFVF_OPS(accel_dev)->recv_msg(accel_dev, 0); -} - -static bool adf_handle_pf2vf_msg(struct adf_accel_dev *accel_dev, u32 msg) -{ - switch ((msg & ADF_PF2VF_MSGTYPE_MASK) >> ADF_PF2VF_MSGTYPE_SHIFT) { - case ADF_PF2VF_MSGTYPE_RESTARTING: - dev_dbg(&GET_DEV(accel_dev), - "Restarting msg received from PF 0x%x\n", msg); - - adf_pf2vf_handle_pf_restarting(accel_dev); - return false; - case ADF_PF2VF_MSGTYPE_VERSION_RESP: - dev_dbg(&GET_DEV(accel_dev), - "Version resp received from PF 0x%x\n", msg); - accel_dev->vf.pf_version = - (msg & ADF_PF2VF_VERSION_RESP_VERS_MASK) >> - ADF_PF2VF_VERSION_RESP_VERS_SHIFT; - accel_dev->vf.compatible = - (msg & ADF_PF2VF_VERSION_RESP_RESULT_MASK) >> - ADF_PF2VF_VERSION_RESP_RESULT_SHIFT; - complete(&accel_dev->vf.iov_msg_completion); - return true; - default: - dev_err(&GET_DEV(accel_dev), - "Unknown PF2VF message(0x%x)\n", msg); - } - - return false; -} - -bool adf_recv_and_handle_pf2vf_msg(struct adf_accel_dev *accel_dev) -{ - u32 msg; - - msg = adf_recv_pf2vf_msg(accel_dev); - if (msg) - return adf_handle_pf2vf_msg(accel_dev, msg); - - return true; -} diff --git a/drivers/crypto/qat/qat_common/adf_vf_isr.c b/drivers/crypto/qat/qat_common/adf_vf_isr.c index b17040b8a4b9f..fe094178f065e 100644 --- a/drivers/crypto/qat/qat_common/adf_vf_isr.c +++ b/drivers/crypto/qat/qat_common/adf_vf_isr.c @@ -15,7 +15,6 @@ #include "adf_cfg_common.h" #include "adf_transport_access_macros.h" #include "adf_transport_internal.h" -#include "adf_pf2vf_msg.h" #define ADF_VINTSOU_OFFSET 0x204 #define ADF_VINTMSK_OFFSET 0x208 diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c index aa42373a7118d..37f43b8c29eb7 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c +++ b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c @@ -1,10 +1,10 @@ // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) -/* Copyright(c) 2014 - 2020 Intel Corporation */ +/* Copyright(c) 2014 - 2021 Intel Corporation */ #include -#include #include #include #include +#include #include "adf_dh895xcc_hw_data.h" #include "icp_qat_hw.h" diff --git a/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c b/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c index 2e2ef6b5bd2a2..d3795bab37255 100644 --- a/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c +++ b/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c @@ -1,10 +1,11 @@ // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) -/* Copyright(c) 2015 - 2020 Intel Corporation */ +/* Copyright(c) 2015 - 2021 Intel Corporation */ #include -#include #include #include #include +#include +#include #include "adf_dh895xccvf_hw_data.h" static struct adf_hw_device_class dh895xcciov_class = { -- GitLab From f6aff914989e9770ed96474e24570d6cab665162 Mon Sep 17 00:00:00 2001 From: Marco Chiappero Date: Wed, 17 Nov 2021 14:30:52 +0000 Subject: [PATCH 0191/1112] crypto: qat - reorganize PFVF protocol definitions Organize PFVF protocol definitions by type rather than direction, by keeping related fields close. Also, make sure the order is consistent for both PF and VF definitions. Signed-off-by: Marco Chiappero Reviewed-by: Giovanni Cabiddu Signed-off-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_pfvf_msg.h | 36 +++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/drivers/crypto/qat/qat_common/adf_pfvf_msg.h b/drivers/crypto/qat/qat_common/adf_pfvf_msg.h index 0520466563fd6..23f4c4b35dace 100644 --- a/drivers/crypto/qat/qat_common/adf_pfvf_msg.h +++ b/drivers/crypto/qat/qat_common/adf_pfvf_msg.h @@ -53,34 +53,21 @@ * adf_gen2_pfvf_send() in adf_pf2vf_msg.c). */ -#define ADF_PFVF_COMPAT_THIS_VERSION 0x1 /* PF<->VF compat */ - /* PF->VF messages */ #define ADF_PF2VF_INT BIT(0) #define ADF_PF2VF_MSGORIGIN_SYSTEM BIT(1) +#define ADF_PF2VF_IN_USE_BY_PF 0x6AC20000 +#define ADF_PF2VF_IN_USE_BY_PF_MASK 0xFFFE0000 #define ADF_PF2VF_MSGTYPE_MASK 0x0000003C #define ADF_PF2VF_MSGTYPE_SHIFT 2 #define ADF_PF2VF_MSGTYPE_RESTARTING 0x01 #define ADF_PF2VF_MSGTYPE_VERSION_RESP 0x02 -#define ADF_PF2VF_IN_USE_BY_PF 0x6AC20000 -#define ADF_PF2VF_IN_USE_BY_PF_MASK 0xFFFE0000 - -/* PF->VF Version Response */ -#define ADF_PF2VF_VERSION_RESP_VERS_MASK 0x00003FC0 -#define ADF_PF2VF_VERSION_RESP_VERS_SHIFT 6 -#define ADF_PF2VF_VERSION_RESP_RESULT_MASK 0x0000C000 -#define ADF_PF2VF_VERSION_RESP_RESULT_SHIFT 14 -#define ADF_PF2VF_MINORVERSION_SHIFT 6 -#define ADF_PF2VF_MAJORVERSION_SHIFT 10 -#define ADF_PF2VF_VF_COMPATIBLE 1 -#define ADF_PF2VF_VF_INCOMPATIBLE 2 -#define ADF_PF2VF_VF_COMPAT_UNKNOWN 3 /* VF->PF messages */ -#define ADF_VF2PF_IN_USE_BY_VF 0x00006AC2 -#define ADF_VF2PF_IN_USE_BY_VF_MASK 0x0000FFFE #define ADF_VF2PF_INT BIT(16) #define ADF_VF2PF_MSGORIGIN_SYSTEM BIT(17) +#define ADF_VF2PF_IN_USE_BY_VF 0x00006AC2 +#define ADF_VF2PF_IN_USE_BY_VF_MASK 0x0000FFFE #define ADF_VF2PF_MSGTYPE_MASK 0x003C0000 #define ADF_VF2PF_MSGTYPE_SHIFT 18 #define ADF_VF2PF_MSGTYPE_INIT 0x3 @@ -88,6 +75,21 @@ #define ADF_VF2PF_MSGTYPE_VERSION_REQ 0x5 #define ADF_VF2PF_MSGTYPE_COMPAT_VER_REQ 0x6 +/* VF/PF compatibility version. */ +/* Reference to the current version */ +#define ADF_PFVF_COMPAT_THIS_VERSION 1 /* PF<->VF compat */ + +/* PF->VF Version Response */ +#define ADF_PF2VF_MINORVERSION_SHIFT 6 +#define ADF_PF2VF_MAJORVERSION_SHIFT 10 +#define ADF_PF2VF_VERSION_RESP_VERS_MASK 0x00003FC0 +#define ADF_PF2VF_VERSION_RESP_VERS_SHIFT 6 +#define ADF_PF2VF_VERSION_RESP_RESULT_MASK 0x0000C000 +#define ADF_PF2VF_VERSION_RESP_RESULT_SHIFT 14 +#define ADF_PF2VF_VF_COMPATIBLE 1 +#define ADF_PF2VF_VF_INCOMPATIBLE 2 +#define ADF_PF2VF_VF_COMPAT_UNKNOWN 3 + /* VF->PF Compatible Version Request */ #define ADF_VF2PF_COMPAT_VER_REQ_SHIFT 22 -- GitLab From 1d4fde6c4e805f4cb5ecb54fb39c93686d3e5924 Mon Sep 17 00:00:00 2001 From: Marco Chiappero Date: Wed, 17 Nov 2021 14:30:53 +0000 Subject: [PATCH 0192/1112] crypto: qat - use enums for PFVF protocol codes Replace PFVF constants with enumerations for valid protocol codes. Signed-off-by: Marco Chiappero Reviewed-by: Giovanni Cabiddu Signed-off-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_pfvf_msg.h | 33 +++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/drivers/crypto/qat/qat_common/adf_pfvf_msg.h b/drivers/crypto/qat/qat_common/adf_pfvf_msg.h index 23f4c4b35dace..8b476072df285 100644 --- a/drivers/crypto/qat/qat_common/adf_pfvf_msg.h +++ b/drivers/crypto/qat/qat_common/adf_pfvf_msg.h @@ -60,8 +60,11 @@ #define ADF_PF2VF_IN_USE_BY_PF_MASK 0xFFFE0000 #define ADF_PF2VF_MSGTYPE_MASK 0x0000003C #define ADF_PF2VF_MSGTYPE_SHIFT 2 -#define ADF_PF2VF_MSGTYPE_RESTARTING 0x01 -#define ADF_PF2VF_MSGTYPE_VERSION_RESP 0x02 + +enum pf2vf_msgtype { + ADF_PF2VF_MSGTYPE_RESTARTING = 0x01, + ADF_PF2VF_MSGTYPE_VERSION_RESP = 0x02, +}; /* VF->PF messages */ #define ADF_VF2PF_INT BIT(16) @@ -70,14 +73,19 @@ #define ADF_VF2PF_IN_USE_BY_VF_MASK 0x0000FFFE #define ADF_VF2PF_MSGTYPE_MASK 0x003C0000 #define ADF_VF2PF_MSGTYPE_SHIFT 18 -#define ADF_VF2PF_MSGTYPE_INIT 0x3 -#define ADF_VF2PF_MSGTYPE_SHUTDOWN 0x4 -#define ADF_VF2PF_MSGTYPE_VERSION_REQ 0x5 -#define ADF_VF2PF_MSGTYPE_COMPAT_VER_REQ 0x6 + +enum vf2pf_msgtype { + ADF_VF2PF_MSGTYPE_INIT = 0x03, + ADF_VF2PF_MSGTYPE_SHUTDOWN = 0x04, + ADF_VF2PF_MSGTYPE_VERSION_REQ = 0x05, + ADF_VF2PF_MSGTYPE_COMPAT_VER_REQ = 0x06, +}; /* VF/PF compatibility version. */ -/* Reference to the current version */ -#define ADF_PFVF_COMPAT_THIS_VERSION 1 /* PF<->VF compat */ +enum pfvf_compatibility_version { + /* Reference to the current version */ + ADF_PFVF_COMPAT_THIS_VERSION = 0x01, +}; /* PF->VF Version Response */ #define ADF_PF2VF_MINORVERSION_SHIFT 6 @@ -86,9 +94,12 @@ #define ADF_PF2VF_VERSION_RESP_VERS_SHIFT 6 #define ADF_PF2VF_VERSION_RESP_RESULT_MASK 0x0000C000 #define ADF_PF2VF_VERSION_RESP_RESULT_SHIFT 14 -#define ADF_PF2VF_VF_COMPATIBLE 1 -#define ADF_PF2VF_VF_INCOMPATIBLE 2 -#define ADF_PF2VF_VF_COMPAT_UNKNOWN 3 + +enum pf2vf_compat_response { + ADF_PF2VF_VF_COMPATIBLE = 0x01, + ADF_PF2VF_VF_INCOMPATIBLE = 0x02, + ADF_PF2VF_VF_COMPAT_UNKNOWN = 0x03, +}; /* VF->PF Compatible Version Request */ #define ADF_VF2PF_COMPAT_VER_REQ_SHIFT 22 -- GitLab From 25110fd2e346449355cb795cd0d3e050ca5bdf11 Mon Sep 17 00:00:00 2001 From: Marco Chiappero Date: Wed, 17 Nov 2021 14:30:54 +0000 Subject: [PATCH 0193/1112] crypto: qat - pass the PF2VF responses back to the callers Currently, any PF response to a VF request is fully parsed during the interrupt handling. This way the individual response values are stored into the accel_dev structure, preventing the caller to access and decode the full response message itself. Change this behavior, by letting the API return back the entire message to the caller, in order to: - keep correlated code together, that is, the (building of the) request and the (decoding of the) response; - avoid polluting the accel_dev data structure with unnecessary and at times temporary values; only the entire message is stored in a temporary buffer. Signed-off-by: Marco Chiappero Reviewed-by: Giovanni Cabiddu Signed-off-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_c3xxxvf/adf_drv.c | 2 +- drivers/crypto/qat/qat_c62xvf/adf_drv.c | 2 +- .../crypto/qat/qat_common/adf_accel_devices.h | 4 ++-- .../crypto/qat/qat_common/adf_pfvf_vf_msg.c | 23 +++++++++++------- .../crypto/qat/qat_common/adf_pfvf_vf_proto.c | 24 +++++++++---------- .../crypto/qat/qat_common/adf_pfvf_vf_proto.h | 2 +- drivers/crypto/qat/qat_dh895xccvf/adf_drv.c | 2 +- 7 files changed, 33 insertions(+), 26 deletions(-) diff --git a/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c b/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c index 1df1b868978d9..0ba1d293bb819 100644 --- a/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c +++ b/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c @@ -171,7 +171,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } pci_set_master(pdev); /* Completion for VF2PF request/response message exchange */ - init_completion(&accel_dev->vf.iov_msg_completion); + init_completion(&accel_dev->vf.msg_received); ret = qat_crypto_dev_config(accel_dev); if (ret) diff --git a/drivers/crypto/qat/qat_c62xvf/adf_drv.c b/drivers/crypto/qat/qat_c62xvf/adf_drv.c index 8103bd81d617a..176d8e2786f47 100644 --- a/drivers/crypto/qat/qat_c62xvf/adf_drv.c +++ b/drivers/crypto/qat/qat_c62xvf/adf_drv.c @@ -171,7 +171,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } pci_set_master(pdev); /* Completion for VF2PF request/response message exchange */ - init_completion(&accel_dev->vf.iov_msg_completion); + init_completion(&accel_dev->vf.msg_received); ret = qat_crypto_dev_config(accel_dev); if (ret) diff --git a/drivers/crypto/qat/qat_common/adf_accel_devices.h b/drivers/crypto/qat/qat_common/adf_accel_devices.h index 35e62a73f9fa8..b05b217df24c4 100644 --- a/drivers/crypto/qat/qat_common/adf_accel_devices.h +++ b/drivers/crypto/qat/qat_common/adf_accel_devices.h @@ -271,8 +271,8 @@ struct adf_accel_dev { char irq_name[ADF_MAX_MSIX_VECTOR_NAME]; struct tasklet_struct pf2vf_bh_tasklet; struct mutex vf2pf_lock; /* protect CSR access */ - struct completion iov_msg_completion; - u8 compatible; + struct completion msg_received; + u32 response; /* temp field holding pf2vf response */ u8 pf_version; } vf; }; diff --git a/drivers/crypto/qat/qat_common/adf_pfvf_vf_msg.c b/drivers/crypto/qat/qat_common/adf_pfvf_vf_msg.c index 7969a644e24b7..d5cccec03a3b3 100644 --- a/drivers/crypto/qat/qat_common/adf_pfvf_vf_msg.c +++ b/drivers/crypto/qat/qat_common/adf_pfvf_vf_msg.c @@ -52,7 +52,10 @@ EXPORT_SYMBOL_GPL(adf_vf2pf_notify_shutdown); int adf_vf2pf_request_version(struct adf_accel_dev *accel_dev) { struct adf_hw_device_data *hw_data = accel_dev->hw_device; + u8 pf_version; u32 msg = 0; + int compat; + u32 resp; int ret; msg = ADF_VF2PF_MSGORIGIN_SYSTEM; @@ -60,34 +63,38 @@ int adf_vf2pf_request_version(struct adf_accel_dev *accel_dev) msg |= ADF_PFVF_COMPAT_THIS_VERSION << ADF_VF2PF_COMPAT_VER_REQ_SHIFT; BUILD_BUG_ON(ADF_PFVF_COMPAT_THIS_VERSION > 255); - ret = adf_send_vf2pf_req(accel_dev, msg); + ret = adf_send_vf2pf_req(accel_dev, msg, &resp); if (ret) { dev_err(&GET_DEV(accel_dev), "Failed to send Compatibility Version Request.\n"); return ret; } + pf_version = (resp & ADF_PF2VF_VERSION_RESP_VERS_MASK) + >> ADF_PF2VF_VERSION_RESP_VERS_SHIFT; + compat = (resp & ADF_PF2VF_VERSION_RESP_RESULT_MASK) + >> ADF_PF2VF_VERSION_RESP_RESULT_SHIFT; + /* Response from PF received, check compatibility */ - switch (accel_dev->vf.compatible) { + switch (compat) { case ADF_PF2VF_VF_COMPATIBLE: break; case ADF_PF2VF_VF_COMPAT_UNKNOWN: /* VF is newer than PF and decides whether it is compatible */ - if (accel_dev->vf.pf_version >= hw_data->min_iov_compat_ver) { - accel_dev->vf.compatible = ADF_PF2VF_VF_COMPATIBLE; + if (pf_version >= hw_data->min_iov_compat_ver) break; - } fallthrough; case ADF_PF2VF_VF_INCOMPATIBLE: dev_err(&GET_DEV(accel_dev), "PF (vers %d) and VF (vers %d) are not compatible\n", - accel_dev->vf.pf_version, - ADF_PFVF_COMPAT_THIS_VERSION); + pf_version, ADF_PFVF_COMPAT_THIS_VERSION); return -EINVAL; default: dev_err(&GET_DEV(accel_dev), "Invalid response from PF; assume not compatible\n"); return -EINVAL; } - return ret; + + accel_dev->vf.pf_version = pf_version; + return 0; } diff --git a/drivers/crypto/qat/qat_common/adf_pfvf_vf_proto.c b/drivers/crypto/qat/qat_common/adf_pfvf_vf_proto.c index 62817bcec121e..ea1a00e746ff5 100644 --- a/drivers/crypto/qat/qat_common/adf_pfvf_vf_proto.c +++ b/drivers/crypto/qat/qat_common/adf_pfvf_vf_proto.c @@ -47,18 +47,19 @@ static u32 adf_recv_pf2vf_msg(struct adf_accel_dev *accel_dev) * adf_send_vf2pf_req() - send VF2PF request message * @accel_dev: Pointer to acceleration device. * @msg: Request message to send + * @resp: Returned PF response * * This function sends a message that requires a response from the VF to the PF * and waits for a reply. * * Return: 0 on success, error code otherwise. */ -int adf_send_vf2pf_req(struct adf_accel_dev *accel_dev, u32 msg) +int adf_send_vf2pf_req(struct adf_accel_dev *accel_dev, u32 msg, u32 *resp) { unsigned long timeout = msecs_to_jiffies(ADF_PFVF_MSG_RESP_TIMEOUT); int ret; - reinit_completion(&accel_dev->vf.iov_msg_completion); + reinit_completion(&accel_dev->vf.msg_received); /* Send request from VF to PF */ ret = adf_send_vf2pf_msg(accel_dev, msg); @@ -69,13 +70,19 @@ int adf_send_vf2pf_req(struct adf_accel_dev *accel_dev, u32 msg) } /* Wait for response */ - if (!wait_for_completion_timeout(&accel_dev->vf.iov_msg_completion, + if (!wait_for_completion_timeout(&accel_dev->vf.msg_received, timeout)) { dev_err(&GET_DEV(accel_dev), "PFVF request/response message timeout expired\n"); return -EIO; } + if (likely(resp)) + *resp = accel_dev->vf.response; + + /* Once copied, set to an invalid value */ + accel_dev->vf.response = 0; + return 0; } @@ -89,15 +96,8 @@ static bool adf_handle_pf2vf_msg(struct adf_accel_dev *accel_dev, u32 msg) adf_pf2vf_handle_pf_restarting(accel_dev); return false; case ADF_PF2VF_MSGTYPE_VERSION_RESP: - dev_dbg(&GET_DEV(accel_dev), - "Version resp received from PF 0x%x\n", msg); - accel_dev->vf.pf_version = - (msg & ADF_PF2VF_VERSION_RESP_VERS_MASK) >> - ADF_PF2VF_VERSION_RESP_VERS_SHIFT; - accel_dev->vf.compatible = - (msg & ADF_PF2VF_VERSION_RESP_RESULT_MASK) >> - ADF_PF2VF_VERSION_RESP_RESULT_SHIFT; - complete(&accel_dev->vf.iov_msg_completion); + accel_dev->vf.response = msg; + complete(&accel_dev->vf.msg_received); return true; default: dev_err(&GET_DEV(accel_dev), diff --git a/drivers/crypto/qat/qat_common/adf_pfvf_vf_proto.h b/drivers/crypto/qat/qat_common/adf_pfvf_vf_proto.h index a3ab24c7d18bd..6226d4d9d520f 100644 --- a/drivers/crypto/qat/qat_common/adf_pfvf_vf_proto.h +++ b/drivers/crypto/qat/qat_common/adf_pfvf_vf_proto.h @@ -7,7 +7,7 @@ #include "adf_accel_devices.h" int adf_send_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 msg); -int adf_send_vf2pf_req(struct adf_accel_dev *accel_dev, u32 msg); +int adf_send_vf2pf_req(struct adf_accel_dev *accel_dev, u32 msg, u32 *resp); int adf_enable_vf2pf_comms(struct adf_accel_dev *accel_dev); diff --git a/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c b/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c index 99d90f3ea2b79..ee45d688b5d73 100644 --- a/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c +++ b/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c @@ -171,7 +171,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } pci_set_master(pdev); /* Completion for VF2PF request/response message exchange */ - init_completion(&accel_dev->vf.iov_msg_completion); + init_completion(&accel_dev->vf.msg_received); ret = qat_crypto_dev_config(accel_dev); if (ret) -- GitLab From c35c76c6919ebcaac590f5f3afa6b8924ad305f4 Mon Sep 17 00:00:00 2001 From: Marco Chiappero Date: Wed, 17 Nov 2021 14:30:55 +0000 Subject: [PATCH 0194/1112] crypto: qat - refactor pfvf version request messages Refactor version handling logic for ADF_VF2PF_MSGTYPE_COMPAT_VER_REQ and ADF_VF2PF_MSGTYPE_VERSION_REQ on the PF. Response messages are now filled only after fully parsing the request, in a consisted way with the rest of the PFVF codebase. This patch also fixes a harmless double setting for VERSION in the response for ADF_VF2PF_MSGTYPE_VERSION_REQ. Signed-off-by: Marco Chiappero Co-developed-by: Giovanni Cabiddu Signed-off-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- .../crypto/qat/qat_common/adf_pfvf_pf_proto.c | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.c b/drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.c index ac6a54cf17f6d..c0844fbd896c0 100644 --- a/drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.c +++ b/drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.c @@ -47,12 +47,7 @@ static int adf_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr, case ADF_VF2PF_MSGTYPE_COMPAT_VER_REQ: { u8 vf_compat_ver = msg >> ADF_VF2PF_COMPAT_VER_REQ_SHIFT; - - resp = (ADF_PF2VF_MSGORIGIN_SYSTEM | - (ADF_PF2VF_MSGTYPE_VERSION_RESP << - ADF_PF2VF_MSGTYPE_SHIFT) | - (ADF_PFVF_COMPAT_THIS_VERSION << - ADF_PF2VF_VERSION_RESP_VERS_SHIFT)); + u8 compat; dev_dbg(&GET_DEV(accel_dev), "Compatibility Version Request from VF%d vers=%u\n", @@ -62,37 +57,46 @@ static int adf_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr, dev_err(&GET_DEV(accel_dev), "VF (vers %d) incompatible with PF (vers %d)\n", vf_compat_ver, ADF_PFVF_COMPAT_THIS_VERSION); - resp |= ADF_PF2VF_VF_INCOMPATIBLE << - ADF_PF2VF_VERSION_RESP_RESULT_SHIFT; + compat = ADF_PF2VF_VF_INCOMPATIBLE; } else if (vf_compat_ver > ADF_PFVF_COMPAT_THIS_VERSION) { dev_err(&GET_DEV(accel_dev), "VF (vers %d) compat with PF (vers %d) unkn.\n", vf_compat_ver, ADF_PFVF_COMPAT_THIS_VERSION); - resp |= ADF_PF2VF_VF_COMPAT_UNKNOWN << - ADF_PF2VF_VERSION_RESP_RESULT_SHIFT; + compat = ADF_PF2VF_VF_COMPAT_UNKNOWN; } else { dev_dbg(&GET_DEV(accel_dev), "VF (vers %d) compatible with PF (vers %d)\n", vf_compat_ver, ADF_PFVF_COMPAT_THIS_VERSION); - resp |= ADF_PF2VF_VF_COMPATIBLE << - ADF_PF2VF_VERSION_RESP_RESULT_SHIFT; + compat = ADF_PF2VF_VF_COMPATIBLE; } + + resp = ADF_PF2VF_MSGORIGIN_SYSTEM; + resp |= ADF_PF2VF_MSGTYPE_VERSION_RESP << + ADF_PF2VF_MSGTYPE_SHIFT; + resp |= ADF_PFVF_COMPAT_THIS_VERSION << + ADF_PF2VF_VERSION_RESP_VERS_SHIFT; + resp |= compat << ADF_PF2VF_VERSION_RESP_RESULT_SHIFT; } break; case ADF_VF2PF_MSGTYPE_VERSION_REQ: + { + u8 compat; + dev_dbg(&GET_DEV(accel_dev), "Legacy VersionRequest received from VF%d 0x%x\n", vf_nr + 1, msg); - resp = (ADF_PF2VF_MSGORIGIN_SYSTEM | - (ADF_PF2VF_MSGTYPE_VERSION_RESP << - ADF_PF2VF_MSGTYPE_SHIFT) | - (ADF_PFVF_COMPAT_THIS_VERSION << - ADF_PF2VF_VERSION_RESP_VERS_SHIFT)); - resp |= ADF_PF2VF_VF_COMPATIBLE << - ADF_PF2VF_VERSION_RESP_RESULT_SHIFT; + + /* PF always newer than legacy VF */ + compat = ADF_PF2VF_VF_COMPATIBLE; + + resp = ADF_PF2VF_MSGORIGIN_SYSTEM; + resp |= ADF_PF2VF_MSGTYPE_VERSION_RESP << + ADF_PF2VF_MSGTYPE_SHIFT; /* Set legacy major and minor version num */ resp |= 1 << ADF_PF2VF_MAJORVERSION_SHIFT | 1 << ADF_PF2VF_MINORVERSION_SHIFT; + resp |= compat << ADF_PF2VF_VERSION_RESP_RESULT_SHIFT; + } break; case ADF_VF2PF_MSGTYPE_INIT: { -- GitLab From e669b4dedd899e8e4cad5ef91721d3387a3844fc Mon Sep 17 00:00:00 2001 From: Marco Chiappero Date: Wed, 17 Nov 2021 14:30:56 +0000 Subject: [PATCH 0195/1112] crypto: qat - do not rely on min version Remove min_iov_compat_ver field as for now all versions are compatible. Compatibility is determined by a series of rules and dynamic conditions such as specific configurations. In any case the minimum version requirement for compatibility is an inadequate and obsolete approach which should be removed. At this time compatibility can be assured across the currently available versions. Signed-off-by: Marco Chiappero Reviewed-by: Giovanni Cabiddu Signed-off-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c | 2 -- .../crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c | 2 -- .../qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c | 2 -- drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c | 2 -- .../crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c | 2 -- .../crypto/qat/qat_common/adf_accel_devices.h | 1 - .../crypto/qat/qat_common/adf_pfvf_pf_proto.c | 18 ++++++------------ .../crypto/qat/qat_common/adf_pfvf_vf_msg.c | 7 ++----- .../qat/qat_dh895xcc/adf_dh895xcc_hw_data.c | 2 -- .../qat_dh895xccvf/adf_dh895xccvf_hw_data.c | 2 -- 10 files changed, 8 insertions(+), 32 deletions(-) diff --git a/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c b/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c index 2a878d98f81aa..4658b7bf76da1 100644 --- a/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c +++ b/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c @@ -4,7 +4,6 @@ #include #include #include -#include #include "adf_4xxx_hw_data.h" #include "icp_qat_hw.h" @@ -257,7 +256,6 @@ void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data) hw_data->pfvf_ops.enable_comms = adf_pfvf_comms_disabled; hw_data->pfvf_ops.get_vf2pf_sources = get_vf2pf_sources; hw_data->disable_iov = adf_disable_sriov; - hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION; adf_gen4_init_hw_csr_ops(&hw_data->csr_ops); } diff --git a/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c b/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c index 94a11e72edae1..3987a44fa164b 100644 --- a/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c +++ b/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c @@ -4,7 +4,6 @@ #include #include #include -#include #include "adf_c3xxx_hw_data.h" #include "icp_qat_hw.h" @@ -137,7 +136,6 @@ void adf_init_hw_data_c3xxx(struct adf_hw_device_data *hw_data) hw_data->reset_device = adf_reset_flr; hw_data->set_ssm_wdtimer = adf_gen2_set_ssm_wdtimer; hw_data->disable_iov = adf_disable_sriov; - hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION; adf_gen2_init_pf_pfvf_ops(&hw_data->pfvf_ops); adf_gen2_init_hw_csr_ops(&hw_data->csr_ops); diff --git a/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c b/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c index 4c43a0d93fa60..85122013534de 100644 --- a/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c +++ b/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include "adf_c3xxxvf_hw_data.h" @@ -85,7 +84,6 @@ void adf_init_hw_data_c3xxxiov(struct adf_hw_device_data *hw_data) hw_data->get_misc_bar_id = get_misc_bar_id; hw_data->get_sku = get_sku; hw_data->enable_ints = adf_vf_void_noop; - hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION; hw_data->dev_class->instances++; adf_devmgr_update_class_index(hw_data); adf_gen2_init_vf_pfvf_ops(&hw_data->pfvf_ops); diff --git a/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c b/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c index 3cb1a88d97aec..a76e33d7a215a 100644 --- a/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c +++ b/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c @@ -4,7 +4,6 @@ #include #include #include -#include #include "adf_c62x_hw_data.h" #include "icp_qat_hw.h" @@ -139,7 +138,6 @@ void adf_init_hw_data_c62x(struct adf_hw_device_data *hw_data) hw_data->reset_device = adf_reset_flr; hw_data->set_ssm_wdtimer = adf_gen2_set_ssm_wdtimer; hw_data->disable_iov = adf_disable_sriov; - hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION; adf_gen2_init_pf_pfvf_ops(&hw_data->pfvf_ops); adf_gen2_init_hw_csr_ops(&hw_data->csr_ops); diff --git a/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c b/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c index c4b23e2cd5796..99c56405f88fb 100644 --- a/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c +++ b/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include "adf_c62xvf_hw_data.h" @@ -85,7 +84,6 @@ void adf_init_hw_data_c62xiov(struct adf_hw_device_data *hw_data) hw_data->get_misc_bar_id = get_misc_bar_id; hw_data->get_sku = get_sku; hw_data->enable_ints = adf_vf_void_noop; - hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION; hw_data->dev_class->instances++; adf_devmgr_update_class_index(hw_data); adf_gen2_init_vf_pfvf_ops(&hw_data->pfvf_ops); diff --git a/drivers/crypto/qat/qat_common/adf_accel_devices.h b/drivers/crypto/qat/qat_common/adf_accel_devices.h index b05b217df24c4..a1809a7d1c90d 100644 --- a/drivers/crypto/qat/qat_common/adf_accel_devices.h +++ b/drivers/crypto/qat/qat_common/adf_accel_devices.h @@ -209,7 +209,6 @@ struct adf_hw_device_data { u8 num_accel; u8 num_logical_accel; u8 num_engines; - u8 min_iov_compat_ver; }; /* CSR write macro */ diff --git a/drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.c b/drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.c index c0844fbd896c0..db5bbb9db32e3 100644 --- a/drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.c +++ b/drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.c @@ -40,7 +40,6 @@ static int adf_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr, u32 msg, u32 *response) { struct adf_accel_vf_info *vf_info = &accel_dev->pf.vf_info[vf_nr]; - struct adf_hw_device_data *hw_data = accel_dev->hw_device; u32 resp = 0; switch ((msg & ADF_VF2PF_MSGTYPE_MASK) >> ADF_VF2PF_MSGTYPE_SHIFT) { @@ -53,21 +52,16 @@ static int adf_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr, "Compatibility Version Request from VF%d vers=%u\n", vf_nr + 1, vf_compat_ver); - if (vf_compat_ver < hw_data->min_iov_compat_ver) { - dev_err(&GET_DEV(accel_dev), - "VF (vers %d) incompatible with PF (vers %d)\n", + if (vf_compat_ver <= ADF_PFVF_COMPAT_THIS_VERSION) { + compat = ADF_PF2VF_VF_COMPATIBLE; + dev_dbg(&GET_DEV(accel_dev), + "VF (vers %d) compatible with PF (vers %d)\n", vf_compat_ver, ADF_PFVF_COMPAT_THIS_VERSION); - compat = ADF_PF2VF_VF_INCOMPATIBLE; - } else if (vf_compat_ver > ADF_PFVF_COMPAT_THIS_VERSION) { + } else { + compat = ADF_PF2VF_VF_COMPAT_UNKNOWN; dev_err(&GET_DEV(accel_dev), "VF (vers %d) compat with PF (vers %d) unkn.\n", vf_compat_ver, ADF_PFVF_COMPAT_THIS_VERSION); - compat = ADF_PF2VF_VF_COMPAT_UNKNOWN; - } else { - dev_dbg(&GET_DEV(accel_dev), - "VF (vers %d) compatible with PF (vers %d)\n", - vf_compat_ver, ADF_PFVF_COMPAT_THIS_VERSION); - compat = ADF_PF2VF_VF_COMPATIBLE; } resp = ADF_PF2VF_MSGORIGIN_SYSTEM; diff --git a/drivers/crypto/qat/qat_common/adf_pfvf_vf_msg.c b/drivers/crypto/qat/qat_common/adf_pfvf_vf_msg.c index d5cccec03a3b3..7635818399024 100644 --- a/drivers/crypto/qat/qat_common/adf_pfvf_vf_msg.c +++ b/drivers/crypto/qat/qat_common/adf_pfvf_vf_msg.c @@ -51,7 +51,6 @@ EXPORT_SYMBOL_GPL(adf_vf2pf_notify_shutdown); int adf_vf2pf_request_version(struct adf_accel_dev *accel_dev) { - struct adf_hw_device_data *hw_data = accel_dev->hw_device; u8 pf_version; u32 msg = 0; int compat; @@ -80,10 +79,8 @@ int adf_vf2pf_request_version(struct adf_accel_dev *accel_dev) case ADF_PF2VF_VF_COMPATIBLE: break; case ADF_PF2VF_VF_COMPAT_UNKNOWN: - /* VF is newer than PF and decides whether it is compatible */ - if (pf_version >= hw_data->min_iov_compat_ver) - break; - fallthrough; + /* VF is newer than PF - compatible for now */ + break; case ADF_PF2VF_VF_INCOMPATIBLE: dev_err(&GET_DEV(accel_dev), "PF (vers %d) and VF (vers %d) are not compatible\n", diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c index 37f43b8c29eb7..27d4cab65dd88 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c +++ b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c @@ -4,7 +4,6 @@ #include #include #include -#include #include "adf_dh895xcc_hw_data.h" #include "icp_qat_hw.h" @@ -216,7 +215,6 @@ void adf_init_hw_data_dh895xcc(struct adf_hw_device_data *hw_data) hw_data->enable_ints = adf_enable_ints; hw_data->reset_device = adf_reset_sbr; hw_data->disable_iov = adf_disable_sriov; - hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION; adf_gen2_init_pf_pfvf_ops(&hw_data->pfvf_ops); hw_data->pfvf_ops.get_vf2pf_sources = get_vf2pf_sources; diff --git a/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c b/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c index d3795bab37255..5489d6c022561 100644 --- a/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c +++ b/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include "adf_dh895xccvf_hw_data.h" @@ -85,7 +84,6 @@ void adf_init_hw_data_dh895xcciov(struct adf_hw_device_data *hw_data) hw_data->get_misc_bar_id = get_misc_bar_id; hw_data->get_sku = get_sku; hw_data->enable_ints = adf_vf_void_noop; - hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION; hw_data->dev_class->instances++; adf_devmgr_update_class_index(hw_data); adf_gen2_init_vf_pfvf_ops(&hw_data->pfvf_ops); -- GitLab From 1d9a915fafabc27739ad6e19db6f86c233f676b2 Mon Sep 17 00:00:00 2001 From: Marco Chiappero Date: Wed, 17 Nov 2021 14:30:57 +0000 Subject: [PATCH 0196/1112] crypto: qat - fix VF IDs in PFVF log messages PFVF debug messages use a mix of zero and one based VF IDs. Switch to zero based VF numbers in all log messages. Signed-off-by: Marco Chiappero Reviewed-by: Giovanni Cabiddu Signed-off-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_isr.c | 2 +- drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/crypto/qat/qat_common/adf_isr.c b/drivers/crypto/qat/qat_common/adf_isr.c index 358200c0d5981..522e0c10d9b9b 100644 --- a/drivers/crypto/qat/qat_common/adf_isr.c +++ b/drivers/crypto/qat/qat_common/adf_isr.c @@ -123,7 +123,7 @@ static bool adf_handle_vf2pf_int(struct adf_accel_dev *accel_dev) if (!__ratelimit(&vf_info->vf2pf_ratelimit)) { dev_info(&GET_DEV(accel_dev), "Too many ints from VF%d\n", - vf_info->vf_nr + 1); + vf_info->vf_nr); continue; } diff --git a/drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.c b/drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.c index db5bbb9db32e3..b486b2b599c25 100644 --- a/drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.c +++ b/drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.c @@ -50,7 +50,7 @@ static int adf_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr, dev_dbg(&GET_DEV(accel_dev), "Compatibility Version Request from VF%d vers=%u\n", - vf_nr + 1, vf_compat_ver); + vf_nr, vf_compat_ver); if (vf_compat_ver <= ADF_PFVF_COMPAT_THIS_VERSION) { compat = ADF_PF2VF_VF_COMPATIBLE; @@ -78,7 +78,7 @@ static int adf_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr, dev_dbg(&GET_DEV(accel_dev), "Legacy VersionRequest received from VF%d 0x%x\n", - vf_nr + 1, msg); + vf_nr, msg); /* PF always newer than legacy VF */ compat = ADF_PF2VF_VF_COMPATIBLE; @@ -96,7 +96,7 @@ static int adf_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr, { dev_dbg(&GET_DEV(accel_dev), "Init message received from VF%d 0x%x\n", - vf_nr + 1, msg); + vf_nr, msg); vf_info->init = true; } break; @@ -104,13 +104,13 @@ static int adf_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr, { dev_dbg(&GET_DEV(accel_dev), "Shutdown message received from VF%d 0x%x\n", - vf_nr + 1, msg); + vf_nr, msg); vf_info->init = false; } break; default: dev_dbg(&GET_DEV(accel_dev), "Unknown message from VF%d (0x%x)\n", - vf_nr + 1, msg); + vf_nr, msg); return -ENOMSG; } -- GitLab From 8616b628ef697eff129b8319604058751eb3ebac Mon Sep 17 00:00:00 2001 From: Marco Chiappero Date: Wed, 17 Nov 2021 14:30:58 +0000 Subject: [PATCH 0197/1112] crypto: qat - improve logging of PFVF messages Improve and simplify logging of PFVF messages. Signed-off-by: Marco Chiappero Reviewed-by: Giovanni Cabiddu Signed-off-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_gen2_pfvf.c | 4 +-- .../crypto/qat/qat_common/adf_pfvf_pf_proto.c | 30 +++++++------------ .../crypto/qat/qat_common/adf_pfvf_vf_proto.c | 7 +++-- 3 files changed, 17 insertions(+), 24 deletions(-) diff --git a/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c b/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c index f3a0a9d651e0d..099e39808d139 100644 --- a/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c +++ b/drivers/crypto/qat/qat_common/adf_gen2_pfvf.c @@ -183,14 +183,14 @@ static u32 adf_gen2_pfvf_recv(struct adf_accel_dev *accel_dev, u8 vf_nr) msg = ADF_CSR_RD(pmisc_addr, pfvf_offset); if (!(msg & int_bit)) { dev_info(&GET_DEV(accel_dev), - "Spurious PFVF interrupt, msg %X. Ignored\n", msg); + "Spurious PFVF interrupt, msg 0x%.8x. Ignored\n", msg); return 0; } /* Ignore legacy non-system (non-kernel) VF2PF messages */ if (!(msg & msg_origin)) { dev_dbg(&GET_DEV(accel_dev), - "Ignored non-system message (0x%x);\n", msg); + "Ignored non-system message (0x%.8x);\n", msg); return 0; } diff --git a/drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.c b/drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.c index b486b2b599c25..4f20dd35fcd45 100644 --- a/drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.c +++ b/drivers/crypto/qat/qat_common/adf_pfvf_pf_proto.c @@ -49,20 +49,13 @@ static int adf_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr, u8 compat; dev_dbg(&GET_DEV(accel_dev), - "Compatibility Version Request from VF%d vers=%u\n", - vf_nr, vf_compat_ver); + "VersionRequest received from VF%d (vers %d) to PF (vers %d)\n", + vf_nr, vf_compat_ver, ADF_PFVF_COMPAT_THIS_VERSION); - if (vf_compat_ver <= ADF_PFVF_COMPAT_THIS_VERSION) { + if (vf_compat_ver <= ADF_PFVF_COMPAT_THIS_VERSION) compat = ADF_PF2VF_VF_COMPATIBLE; - dev_dbg(&GET_DEV(accel_dev), - "VF (vers %d) compatible with PF (vers %d)\n", - vf_compat_ver, ADF_PFVF_COMPAT_THIS_VERSION); - } else { + else compat = ADF_PF2VF_VF_COMPAT_UNKNOWN; - dev_err(&GET_DEV(accel_dev), - "VF (vers %d) compat with PF (vers %d) unkn.\n", - vf_compat_ver, ADF_PFVF_COMPAT_THIS_VERSION); - } resp = ADF_PF2VF_MSGORIGIN_SYSTEM; resp |= ADF_PF2VF_MSGTYPE_VERSION_RESP << @@ -77,8 +70,8 @@ static int adf_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr, u8 compat; dev_dbg(&GET_DEV(accel_dev), - "Legacy VersionRequest received from VF%d 0x%x\n", - vf_nr, msg); + "Legacy VersionRequest received from VF%d to PF (vers 1.1)\n", + vf_nr); /* PF always newer than legacy VF */ compat = ADF_PF2VF_VF_COMPATIBLE; @@ -95,21 +88,19 @@ static int adf_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr, case ADF_VF2PF_MSGTYPE_INIT: { dev_dbg(&GET_DEV(accel_dev), - "Init message received from VF%d 0x%x\n", - vf_nr, msg); + "Init message received from VF%d\n", vf_nr); vf_info->init = true; } break; case ADF_VF2PF_MSGTYPE_SHUTDOWN: { dev_dbg(&GET_DEV(accel_dev), - "Shutdown message received from VF%d 0x%x\n", - vf_nr, msg); + "Shutdown message received from VF%d\n", vf_nr); vf_info->init = false; } break; default: - dev_dbg(&GET_DEV(accel_dev), "Unknown message from VF%d (0x%x)\n", + dev_dbg(&GET_DEV(accel_dev), "Unknown message from VF%d (0x%.8x)\n", vf_nr, msg); return -ENOMSG; } @@ -132,7 +123,8 @@ bool adf_recv_and_handle_vf2pf_msg(struct adf_accel_dev *accel_dev, u32 vf_nr) return false; if (resp && adf_send_pf2vf_msg(accel_dev, vf_nr, resp)) - dev_err(&GET_DEV(accel_dev), "Failed to send response to VF\n"); + dev_err(&GET_DEV(accel_dev), + "Failed to send response to VF%d\n", vf_nr); return true; } diff --git a/drivers/crypto/qat/qat_common/adf_pfvf_vf_proto.c b/drivers/crypto/qat/qat_common/adf_pfvf_vf_proto.c index ea1a00e746ff5..9c7489ed122ca 100644 --- a/drivers/crypto/qat/qat_common/adf_pfvf_vf_proto.c +++ b/drivers/crypto/qat/qat_common/adf_pfvf_vf_proto.c @@ -90,18 +90,19 @@ static bool adf_handle_pf2vf_msg(struct adf_accel_dev *accel_dev, u32 msg) { switch ((msg & ADF_PF2VF_MSGTYPE_MASK) >> ADF_PF2VF_MSGTYPE_SHIFT) { case ADF_PF2VF_MSGTYPE_RESTARTING: - dev_dbg(&GET_DEV(accel_dev), - "Restarting msg received from PF 0x%x\n", msg); + dev_dbg(&GET_DEV(accel_dev), "Restarting message received from PF\n"); adf_pf2vf_handle_pf_restarting(accel_dev); return false; case ADF_PF2VF_MSGTYPE_VERSION_RESP: + dev_dbg(&GET_DEV(accel_dev), + "Response message received from PF (0x%.8x)\n", msg); accel_dev->vf.response = msg; complete(&accel_dev->vf.msg_received); return true; default: dev_err(&GET_DEV(accel_dev), - "Unknown PF2VF message(0x%x)\n", msg); + "Unknown PF2VF message (0x%.8x) from PF\n", msg); } return false; -- GitLab From 83f50f2948baef5fb5f2f547a573f113f03f2b15 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Thu, 18 Nov 2021 23:10:25 -0600 Subject: [PATCH 0198/1112] crypto: sun8i-ce - Add support for the D1 variant The Allwinner D1 SoC has a crypto engine compatible with sun8i-ce. Add support for it. Signed-off-by: Corentin Labbe Signed-off-by: Samuel Holland Signed-off-by: Herbert Xu --- .../crypto/allwinner/sun8i-ce/sun8i-ce-core.c | 21 +++++++++++++++++++ drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h | 1 + 2 files changed, 22 insertions(+) diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c index 00194d1d9ae69..d8623c7e0d1d6 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c @@ -106,6 +106,24 @@ static const struct ce_variant ce_a64_variant = { .trng = CE_ID_NOTSUPP, }; +static const struct ce_variant ce_d1_variant = { + .alg_cipher = { CE_ALG_AES, CE_ALG_DES, CE_ALG_3DES, + }, + .alg_hash = { CE_ALG_MD5, CE_ALG_SHA1, CE_ALG_SHA224, CE_ALG_SHA256, + CE_ALG_SHA384, CE_ALG_SHA512 + }, + .op_mode = { CE_OP_ECB, CE_OP_CBC + }, + .ce_clks = { + { "bus", 0, 200000000 }, + { "mod", 300000000, 0 }, + { "ram", 0, 400000000 }, + }, + .esr = ESR_D1, + .prng = CE_ALG_PRNG, + .trng = CE_ALG_TRNG, +}; + static const struct ce_variant ce_r40_variant = { .alg_cipher = { CE_ALG_AES, CE_ALG_DES, CE_ALG_3DES, }, @@ -192,6 +210,7 @@ int sun8i_ce_run_task(struct sun8i_ce_dev *ce, int flow, const char *name) dev_err(ce->dev, "CE ERROR: keysram access error for AES\n"); break; case ESR_A64: + case ESR_D1: case ESR_H5: case ESR_R40: v >>= (flow * 4); @@ -990,6 +1009,8 @@ static const struct of_device_id sun8i_ce_crypto_of_match_table[] = { .data = &ce_h3_variant }, { .compatible = "allwinner,sun8i-r40-crypto", .data = &ce_r40_variant }, + { .compatible = "allwinner,sun20i-d1-crypto", + .data = &ce_d1_variant }, { .compatible = "allwinner,sun50i-a64-crypto", .data = &ce_a64_variant }, { .compatible = "allwinner,sun50i-h5-crypto", diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h index cec781d5063c1..624a5926f21f1 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce.h @@ -94,6 +94,7 @@ #define ESR_R40 2 #define ESR_H5 3 #define ESR_H6 4 +#define ESR_D1 5 #define PRNG_DATA_SIZE (160 / 8) #define PRNG_SEED_SIZE DIV_ROUND_UP(175, 8) -- GitLab From b808f32023dd8127b0fa27f60fa69a959fd70388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20M=C3=BCller?= Date: Fri, 19 Nov 2021 07:55:33 +0100 Subject: [PATCH 0199/1112] crypto: kdf - Add key derivation self-test support code As a preparation to add the key derivation implementations, the self-test data structure definition and the common test code is made available. The test framework follows the testing applied by the NIST CAVP test approach. The structure of the test code follows the implementations found in crypto/testmgr.c|h. In case the KDF implementations will be made available via a kernel crypto API templates, the test code is intended to be merged into testmgr.c|h. Signed-off-by: Stephan Mueller Signed-off-by: Herbert Xu --- include/crypto/internal/kdf_selftest.h | 71 ++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 include/crypto/internal/kdf_selftest.h diff --git a/include/crypto/internal/kdf_selftest.h b/include/crypto/internal/kdf_selftest.h new file mode 100644 index 0000000000000..4d03d2af57b73 --- /dev/null +++ b/include/crypto/internal/kdf_selftest.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Copyright (C) 2021, Stephan Mueller + */ + +#ifndef _CRYPTO_KDF_SELFTEST_H +#define _CRYPTO_KDF_SELFTEST_H + +#include +#include + +struct kdf_testvec { + unsigned char *key; + size_t keylen; + unsigned char *ikm; + size_t ikmlen; + struct kvec info; + unsigned char *expected; + size_t expectedlen; +}; + +static inline int +kdf_test(const struct kdf_testvec *test, const char *name, + int (*crypto_kdf_setkey)(struct crypto_shash *kmd, + const u8 *key, size_t keylen, + const u8 *ikm, size_t ikmlen), + int (*crypto_kdf_generate)(struct crypto_shash *kmd, + const struct kvec *info, + unsigned int info_nvec, + u8 *dst, unsigned int dlen)) +{ + struct crypto_shash *kmd; + int ret; + u8 *buf = kzalloc(test->expectedlen, GFP_KERNEL); + + if (!buf) + return -ENOMEM; + + kmd = crypto_alloc_shash(name, 0, 0); + if (IS_ERR(kmd)) { + pr_err("alg: kdf: could not allocate hash handle for %s\n", + name); + kfree(buf); + return -ENOMEM; + } + + ret = crypto_kdf_setkey(kmd, test->key, test->keylen, + test->ikm, test->ikmlen); + if (ret) { + pr_err("alg: kdf: could not set key derivation key\n"); + goto err; + } + + ret = crypto_kdf_generate(kmd, &test->info, 1, buf, test->expectedlen); + if (ret) { + pr_err("alg: kdf: could not obtain key data\n"); + goto err; + } + + ret = memcmp(test->expected, buf, test->expectedlen); + if (ret) + ret = -EINVAL; + +err: + crypto_free_shash(kmd); + kfree(buf); + return ret; +} + +#endif /* _CRYPTO_KDF_SELFTEST_H */ -- GitLab From 026a733e66592e743a0905c7fd6b5d3bf89b2d7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20M=C3=BCller?= Date: Fri, 19 Nov 2021 07:55:58 +0100 Subject: [PATCH 0200/1112] crypto: kdf - add SP800-108 counter key derivation function SP800-108 defines three KDFs - this patch provides the counter KDF implementation. The KDF is implemented as a service function where the caller has to maintain the hash / HMAC state. Apart from this hash/HMAC state, no additional state is required to be maintained by either the caller or the KDF implementation. The key for the KDF is set with the crypto_kdf108_setkey function which is intended to be invoked before the caller requests a key derivation operation via crypto_kdf108_ctr_generate. SP800-108 allows the use of either a HMAC or a hash as crypto primitive for the KDF. When a HMAC primtive is intended to be used, crypto_kdf108_setkey must be used to set the HMAC key. Otherwise, for a hash crypto primitve crypto_kdf108_ctr_generate can be used immediately after allocating the hash handle. Signed-off-by: Stephan Mueller Signed-off-by: Herbert Xu --- crypto/Kconfig | 4 + crypto/Makefile | 5 ++ crypto/kdf_sp800108.c | 153 ++++++++++++++++++++++++++++++++++ include/crypto/kdf_sp800108.h | 61 ++++++++++++++ 4 files changed, 223 insertions(+) create mode 100644 crypto/kdf_sp800108.c create mode 100644 include/crypto/kdf_sp800108.h diff --git a/crypto/Kconfig b/crypto/Kconfig index 285f82647d2b7..01b9ca0836a51 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -1845,6 +1845,10 @@ config CRYPTO_JITTERENTROPY random numbers. This Jitterentropy RNG registers with the kernel crypto API and can be used by any caller. +config CRYPTO_KDF800108_CTR + tristate + select CRYPTO_HASH + config CRYPTO_USER_API tristate diff --git a/crypto/Makefile b/crypto/Makefile index 429c4d57458c3..d76bff8d0ffd9 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -200,3 +200,8 @@ obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys/ obj-$(CONFIG_CRYPTO_HASH_INFO) += hash_info.o crypto_simd-y := simd.o obj-$(CONFIG_CRYPTO_SIMD) += crypto_simd.o + +# +# Key derivation function +# +obj-$(CONFIG_CRYPTO_KDF800108_CTR) += kdf_sp800108.o diff --git a/crypto/kdf_sp800108.c b/crypto/kdf_sp800108.c new file mode 100644 index 0000000000000..58edf7797abfb --- /dev/null +++ b/crypto/kdf_sp800108.c @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * SP800-108 Key-derivation function + * + * Copyright (C) 2021, Stephan Mueller + */ + +#include +#include +#include +#include + +/* + * SP800-108 CTR KDF implementation + */ +int crypto_kdf108_ctr_generate(struct crypto_shash *kmd, + const struct kvec *info, unsigned int info_nvec, + u8 *dst, unsigned int dlen) +{ + SHASH_DESC_ON_STACK(desc, kmd); + __be32 counter = cpu_to_be32(1); + const unsigned int h = crypto_shash_digestsize(kmd), dlen_orig = dlen; + unsigned int i; + int err = 0; + u8 *dst_orig = dst; + + desc->tfm = kmd; + + while (dlen) { + err = crypto_shash_init(desc); + if (err) + goto out; + + err = crypto_shash_update(desc, (u8 *)&counter, sizeof(__be32)); + if (err) + goto out; + + for (i = 0; i < info_nvec; i++) { + err = crypto_shash_update(desc, info[i].iov_base, + info[i].iov_len); + if (err) + goto out; + } + + if (dlen < h) { + u8 tmpbuffer[HASH_MAX_DIGESTSIZE]; + + err = crypto_shash_final(desc, tmpbuffer); + if (err) + goto out; + memcpy(dst, tmpbuffer, dlen); + memzero_explicit(tmpbuffer, h); + goto out; + } + + err = crypto_shash_final(desc, dst); + if (err) + goto out; + + dlen -= h; + dst += h; + counter = cpu_to_be32(be32_to_cpu(counter) + 1); + } + +out: + if (err) + memzero_explicit(dst_orig, dlen_orig); + shash_desc_zero(desc); + return err; +} +EXPORT_SYMBOL(crypto_kdf108_ctr_generate); + +/* + * The seeding of the KDF + */ +int crypto_kdf108_setkey(struct crypto_shash *kmd, + const u8 *key, size_t keylen, + const u8 *ikm, size_t ikmlen) +{ + unsigned int ds = crypto_shash_digestsize(kmd); + + /* SP800-108 does not support IKM */ + if (ikm || ikmlen) + return -EINVAL; + + /* Check according to SP800-108 section 7.2 */ + if (ds > keylen) + return -EINVAL; + + /* Set the key for the MAC used for the KDF. */ + return crypto_shash_setkey(kmd, key, keylen); +} +EXPORT_SYMBOL(crypto_kdf108_setkey); + +/* + * Test vector obtained from + * http://csrc.nist.gov/groups/STM/cavp/documents/KBKDF800-108/CounterMode.zip + */ +static const struct kdf_testvec kdf_ctr_hmac_sha256_tv_template[] = { + { + .key = "\xdd\x1d\x91\xb7\xd9\x0b\x2b\xd3" + "\x13\x85\x33\xce\x92\xb2\x72\xfb" + "\xf8\xa3\x69\x31\x6a\xef\xe2\x42" + "\xe6\x59\xcc\x0a\xe2\x38\xaf\xe0", + .keylen = 32, + .ikm = NULL, + .ikmlen = 0, + .info = { + .iov_base = "\x01\x32\x2b\x96\xb3\x0a\xcd\x19" + "\x79\x79\x44\x4e\x46\x8e\x1c\x5c" + "\x68\x59\xbf\x1b\x1c\xf9\x51\xb7" + "\xe7\x25\x30\x3e\x23\x7e\x46\xb8" + "\x64\xa1\x45\xfa\xb2\x5e\x51\x7b" + "\x08\xf8\x68\x3d\x03\x15\xbb\x29" + "\x11\xd8\x0a\x0e\x8a\xba\x17\xf3" + "\xb4\x13\xfa\xac", + .iov_len = 60 + }, + .expected = "\x10\x62\x13\x42\xbf\xb0\xfd\x40" + "\x04\x6c\x0e\x29\xf2\xcf\xdb\xf0", + .expectedlen = 16 + } +}; + +static int __init crypto_kdf108_init(void) +{ + int ret = kdf_test(&kdf_ctr_hmac_sha256_tv_template[0], "hmac(sha256)", + crypto_kdf108_setkey, crypto_kdf108_ctr_generate); + + if (ret) { + if (fips_enabled) + panic("alg: self-tests for CTR-KDF (hmac(sha256)) failed (rc=%d)\n", + ret); + + WARN(1, + "alg: self-tests for CTR-KDF (hmac(sha256)) failed (rc=%d)\n", + ret); + } else { + pr_info("alg: self-tests for CTR-KDF (hmac(sha256)) passed\n"); + } + + return ret; +} + +static void __exit crypto_kdf108_exit(void) { } + +module_init(crypto_kdf108_init); +module_exit(crypto_kdf108_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Stephan Mueller "); +MODULE_DESCRIPTION("Key Derivation Function conformant to SP800-108"); diff --git a/include/crypto/kdf_sp800108.h b/include/crypto/kdf_sp800108.h new file mode 100644 index 0000000000000..b7b20a778fb7e --- /dev/null +++ b/include/crypto/kdf_sp800108.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Copyright (C) 2021, Stephan Mueller + */ + +#ifndef _CRYPTO_KDF108_H +#define _CRYPTO_KDF108_H + +#include +#include + +/** + * Counter KDF generate operation according to SP800-108 section 5.1 + * as well as SP800-56A section 5.8.1 (Single-step KDF). + * + * @kmd Keyed message digest whose key was set with crypto_kdf108_setkey or + * unkeyed message digest + * @info optional context and application specific information - this may be + * NULL + * @info_vec number of optional context/application specific information entries + * @dst destination buffer that the caller already allocated + * @dlen length of the destination buffer - the KDF derives that amount of + * bytes. + * + * To comply with SP800-108, the caller must provide Label || 0x00 || Context + * in the info parameter. + * + * @return 0 on success, < 0 on error + */ +int crypto_kdf108_ctr_generate(struct crypto_shash *kmd, + const struct kvec *info, unsigned int info_nvec, + u8 *dst, unsigned int dlen); + +/** + * Counter KDF setkey operation + * + * @kmd Keyed message digest allocated by the caller. The key should not have + * been set. + * @key Seed key to be used to initialize the keyed message digest context. + * @keylen This length of the key buffer. + * @ikm The SP800-108 KDF does not support IKM - this parameter must be NULL + * @ikmlen This parameter must be 0. + * + * According to SP800-108 section 7.2, the seed key must be at least as large as + * the message digest size of the used keyed message digest. This limitation + * is enforced by the implementation. + * + * SP800-108 allows the use of either a HMAC or a hash primitive. When + * the caller intends to use a hash primitive, the call to + * crypto_kdf108_setkey is not required and the key derivation operation can + * immediately performed using crypto_kdf108_ctr_generate after allocating + * a handle. + * + * @return 0 on success, < 0 on error + */ +int crypto_kdf108_setkey(struct crypto_shash *kmd, + const u8 *key, size_t keylen, + const u8 *ikm, size_t ikmlen); + +#endif /* _CRYPTO_KDF108_H */ -- GitLab From d7921344234d15ce24a151d932aa0748797fc502 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20M=C3=BCller?= Date: Fri, 19 Nov 2021 07:58:44 +0100 Subject: [PATCH 0201/1112] security: DH - remove dead code for zero padding Remove the specific code that adds a zero padding that was intended to be invoked when the DH operation result was smaller than the modulus. However, this cannot occur any more these days because the function mpi_write_to_sgl is used in the code path that calculates the shared secret in dh_compute_value. This MPI service function guarantees that leading zeros are introduced as needed to ensure the resulting data is exactly as long as the modulus. This implies that the specific code to add zero padding is dead code which can be safely removed. Signed-off-by: Stephan Mueller Acked-by: Mat Martineau Signed-off-by: Herbert Xu --- security/keys/dh.c | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/security/keys/dh.c b/security/keys/dh.c index 1abfa70ed6e10..56e12dae4534a 100644 --- a/security/keys/dh.c +++ b/security/keys/dh.c @@ -141,7 +141,7 @@ static void kdf_dealloc(struct kdf_sdesc *sdesc) * 'dlen' must be a multiple of the digest size. */ static int kdf_ctr(struct kdf_sdesc *sdesc, const u8 *src, unsigned int slen, - u8 *dst, unsigned int dlen, unsigned int zlen) + u8 *dst, unsigned int dlen) { struct shash_desc *desc = &sdesc->shash; unsigned int h = crypto_shash_digestsize(desc->tfm); @@ -158,22 +158,6 @@ static int kdf_ctr(struct kdf_sdesc *sdesc, const u8 *src, unsigned int slen, if (err) goto err; - if (zlen && h) { - u8 tmpbuffer[32]; - size_t chunk = min_t(size_t, zlen, sizeof(tmpbuffer)); - memset(tmpbuffer, 0, chunk); - - do { - err = crypto_shash_update(desc, tmpbuffer, - chunk); - if (err) - goto err; - - zlen -= chunk; - chunk = min_t(size_t, zlen, sizeof(tmpbuffer)); - } while (zlen); - } - if (src && slen) { err = crypto_shash_update(desc, src, slen); if (err) @@ -198,7 +182,7 @@ err: static int keyctl_dh_compute_kdf(struct kdf_sdesc *sdesc, char __user *buffer, size_t buflen, - uint8_t *kbuf, size_t kbuflen, size_t lzero) + uint8_t *kbuf, size_t kbuflen) { uint8_t *outbuf = NULL; int ret; @@ -211,7 +195,7 @@ static int keyctl_dh_compute_kdf(struct kdf_sdesc *sdesc, goto err; } - ret = kdf_ctr(sdesc, kbuf, kbuflen, outbuf, outbuf_len, lzero); + ret = kdf_ctr(sdesc, kbuf, kbuflen, outbuf, outbuf_len); if (ret) goto err; @@ -384,8 +368,7 @@ long __keyctl_dh_compute(struct keyctl_dh_params __user *params, } ret = keyctl_dh_compute_kdf(sdesc, buffer, buflen, outbuf, - req->dst_len + kdfcopy->otherinfolen, - outlen - req->dst_len); + req->dst_len + kdfcopy->otherinfolen); } else if (copy_to_user(buffer, outbuf, req->dst_len) == 0) { ret = req->dst_len; } else { -- GitLab From d3b04a4398fe8022c9ca4b5ac6ab08059334b180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20M=C3=BCller?= Date: Fri, 19 Nov 2021 07:59:09 +0100 Subject: [PATCH 0202/1112] security: DH - use KDF implementation from crypto API The kernel crypto API provides the SP800-108 counter KDF implementation. Thus, the separate implementation provided as part of the keys subsystem can be replaced with calls to the KDF offered by the kernel crypto API. The keys subsystem uses the counter KDF with a hash primitive. Thus, it only uses the call to crypto_kdf108_ctr_generate. Signed-off-by: Stephan Mueller Acked-by: Mat Martineau Signed-off-by: Herbert Xu --- security/keys/Kconfig | 2 +- security/keys/dh.c | 109 +++++++----------------------------------- 2 files changed, 19 insertions(+), 92 deletions(-) diff --git a/security/keys/Kconfig b/security/keys/Kconfig index 64b81abd087e3..969122c7b92f4 100644 --- a/security/keys/Kconfig +++ b/security/keys/Kconfig @@ -109,7 +109,7 @@ config KEY_DH_OPERATIONS bool "Diffie-Hellman operations on retained keys" depends on KEYS select CRYPTO - select CRYPTO_HASH + select CRYPTO_KDF800108_CTR select CRYPTO_DH help This option provides support for calculating Diffie-Hellman diff --git a/security/keys/dh.c b/security/keys/dh.c index 56e12dae4534a..4573fc15617dc 100644 --- a/security/keys/dh.c +++ b/security/keys/dh.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "internal.h" @@ -79,17 +80,9 @@ static void dh_crypto_done(struct crypto_async_request *req, int err) complete(&compl->completion); } -struct kdf_sdesc { - struct shash_desc shash; - char ctx[]; -}; - -static int kdf_alloc(struct kdf_sdesc **sdesc_ret, char *hashname) +static int kdf_alloc(struct crypto_shash **hash, char *hashname) { struct crypto_shash *tfm; - struct kdf_sdesc *sdesc; - int size; - int err; /* allocate synchronous hash */ tfm = crypto_alloc_shash(hashname, 0, 0); @@ -98,96 +91,30 @@ static int kdf_alloc(struct kdf_sdesc **sdesc_ret, char *hashname) return PTR_ERR(tfm); } - err = -EINVAL; - if (crypto_shash_digestsize(tfm) == 0) - goto out_free_tfm; - - err = -ENOMEM; - size = sizeof(struct shash_desc) + crypto_shash_descsize(tfm); - sdesc = kmalloc(size, GFP_KERNEL); - if (!sdesc) - goto out_free_tfm; - sdesc->shash.tfm = tfm; + if (crypto_shash_digestsize(tfm) == 0) { + crypto_free_shash(tfm); + return -EINVAL; + } - *sdesc_ret = sdesc; + *hash = tfm; return 0; - -out_free_tfm: - crypto_free_shash(tfm); - return err; } -static void kdf_dealloc(struct kdf_sdesc *sdesc) +static void kdf_dealloc(struct crypto_shash *hash) { - if (!sdesc) - return; - - if (sdesc->shash.tfm) - crypto_free_shash(sdesc->shash.tfm); - - kfree_sensitive(sdesc); -} - -/* - * Implementation of the KDF in counter mode according to SP800-108 section 5.1 - * as well as SP800-56A section 5.8.1 (Single-step KDF). - * - * SP800-56A: - * The src pointer is defined as Z || other info where Z is the shared secret - * from DH and other info is an arbitrary string (see SP800-56A section - * 5.8.1.2). - * - * 'dlen' must be a multiple of the digest size. - */ -static int kdf_ctr(struct kdf_sdesc *sdesc, const u8 *src, unsigned int slen, - u8 *dst, unsigned int dlen) -{ - struct shash_desc *desc = &sdesc->shash; - unsigned int h = crypto_shash_digestsize(desc->tfm); - int err = 0; - u8 *dst_orig = dst; - __be32 counter = cpu_to_be32(1); - - while (dlen) { - err = crypto_shash_init(desc); - if (err) - goto err; - - err = crypto_shash_update(desc, (u8 *)&counter, sizeof(__be32)); - if (err) - goto err; - - if (src && slen) { - err = crypto_shash_update(desc, src, slen); - if (err) - goto err; - } - - err = crypto_shash_final(desc, dst); - if (err) - goto err; - - dlen -= h; - dst += h; - counter = cpu_to_be32(be32_to_cpu(counter) + 1); - } - - return 0; - -err: - memzero_explicit(dst_orig, dlen); - return err; + if (hash) + crypto_free_shash(hash); } -static int keyctl_dh_compute_kdf(struct kdf_sdesc *sdesc, +static int keyctl_dh_compute_kdf(struct crypto_shash *hash, char __user *buffer, size_t buflen, uint8_t *kbuf, size_t kbuflen) { + struct kvec kbuf_iov = { .iov_base = kbuf, .iov_len = kbuflen }; uint8_t *outbuf = NULL; int ret; - size_t outbuf_len = roundup(buflen, - crypto_shash_digestsize(sdesc->shash.tfm)); + size_t outbuf_len = roundup(buflen, crypto_shash_digestsize(hash)); outbuf = kmalloc(outbuf_len, GFP_KERNEL); if (!outbuf) { @@ -195,7 +122,7 @@ static int keyctl_dh_compute_kdf(struct kdf_sdesc *sdesc, goto err; } - ret = kdf_ctr(sdesc, kbuf, kbuflen, outbuf, outbuf_len); + ret = crypto_kdf108_ctr_generate(hash, &kbuf_iov, 1, outbuf, outbuf_len); if (ret) goto err; @@ -224,7 +151,7 @@ long __keyctl_dh_compute(struct keyctl_dh_params __user *params, struct kpp_request *req; uint8_t *secret; uint8_t *outbuf; - struct kdf_sdesc *sdesc = NULL; + struct crypto_shash *hash = NULL; if (!params || (!buffer && buflen)) { ret = -EINVAL; @@ -257,7 +184,7 @@ long __keyctl_dh_compute(struct keyctl_dh_params __user *params, } /* allocate KDF from the kernel crypto API */ - ret = kdf_alloc(&sdesc, hashname); + ret = kdf_alloc(&hash, hashname); kfree(hashname); if (ret) goto out1; @@ -367,7 +294,7 @@ long __keyctl_dh_compute(struct keyctl_dh_params __user *params, goto out6; } - ret = keyctl_dh_compute_kdf(sdesc, buffer, buflen, outbuf, + ret = keyctl_dh_compute_kdf(hash, buffer, buflen, outbuf, req->dst_len + kdfcopy->otherinfolen); } else if (copy_to_user(buffer, outbuf, req->dst_len) == 0) { ret = req->dst_len; @@ -386,7 +313,7 @@ out3: out2: dh_free_data(&dh_inputs); out1: - kdf_dealloc(sdesc); + kdf_dealloc(hash); return ret; } -- GitLab From 376a5c3cdd7cf47d2436dd466548c0fff792f4c7 Mon Sep 17 00:00:00 2001 From: Kai Ye Date: Sat, 20 Nov 2021 12:47:36 +0800 Subject: [PATCH 0203/1112] crypto: hisilicon - modify the value of engine type rate Modify the value of type rate from new QM spec. Signed-off-by: Kai Ye Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/hpre/hpre_main.c | 2 +- drivers/crypto/hisilicon/sec2/sec_main.c | 2 +- drivers/crypto/hisilicon/zip/zip_main.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c index 65a641396c07f..ebfab3e14499a 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_main.c +++ b/drivers/crypto/hisilicon/hpre/hpre_main.c @@ -103,7 +103,7 @@ #define HPRE_QM_PM_FLR BIT(11) #define HPRE_QM_SRIOV_FLR BIT(12) -#define HPRE_SHAPER_TYPE_RATE 128 +#define HPRE_SHAPER_TYPE_RATE 640 #define HPRE_VIA_MSI_DSM 1 #define HPRE_SQE_MASK_OFFSET 8 #define HPRE_SQE_MASK_LEN 24 diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c index 90551bf38b523..26d3ab1d308ba 100644 --- a/drivers/crypto/hisilicon/sec2/sec_main.c +++ b/drivers/crypto/hisilicon/sec2/sec_main.c @@ -105,7 +105,7 @@ #define SEC_SQE_MASK_OFFSET 64 #define SEC_SQE_MASK_LEN 48 -#define SEC_SHAPER_TYPE_RATE 128 +#define SEC_SHAPER_TYPE_RATE 400 struct sec_hw_error { u32 int_msk; diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c index 873971ef9aeed..1a237d95d482f 100644 --- a/drivers/crypto/hisilicon/zip/zip_main.c +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -103,8 +103,8 @@ #define HZIP_PREFETCH_ENABLE (~(BIT(26) | BIT(17) | BIT(0))) #define HZIP_SVA_PREFETCH_DISABLE BIT(26) #define HZIP_SVA_DISABLE_READY (BIT(26) | BIT(30)) -#define HZIP_SHAPER_RATE_COMPRESS 252 -#define HZIP_SHAPER_RATE_DECOMPRESS 229 +#define HZIP_SHAPER_RATE_COMPRESS 750 +#define HZIP_SHAPER_RATE_DECOMPRESS 140 #define HZIP_DELAY_1_US 1 #define HZIP_POLL_TIMEOUT_US 1000 -- GitLab From ecc7169d4f7318512d70192ce03d899949b153b2 Mon Sep 17 00:00:00 2001 From: Kai Ye Date: Sat, 20 Nov 2021 12:47:37 +0800 Subject: [PATCH 0204/1112] crypto: hisilicon/qm - modify the value of qos initialization The value of qos should be reset after flr resetting or device resetting. So set the max of qos value for every function. Then update the value of qos when user writing the alg_qos. Signed-off-by: Kai Ye Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/qm.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 52d6cca6262e2..2b998afc57eae 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -1126,10 +1126,10 @@ static int qm_set_vft_common(struct hisi_qm *qm, enum vft_type type, static int qm_shaper_init_vft(struct hisi_qm *qm, u32 fun_num) { + u32 qos = qm->factor[fun_num].func_qos; int ret, i; - qm->factor[fun_num].func_qos = QM_QOS_MAX_VAL; - ret = qm_get_shaper_para(QM_QOS_MAX_VAL * QM_QOS_RATE, &qm->factor[fun_num]); + ret = qm_get_shaper_para(qos * QM_QOS_RATE, &qm->factor[fun_num]); if (ret) { dev_err(&qm->pdev->dev, "failed to calculate shaper parameter!\n"); return ret; @@ -5750,13 +5750,15 @@ err_init_qp_mem: static int hisi_qm_memory_init(struct hisi_qm *qm) { struct device *dev = &qm->pdev->dev; - int ret, total_vfs; + int ret, total_func, i; size_t off = 0; - total_vfs = pci_sriov_get_totalvfs(qm->pdev); - qm->factor = kcalloc(total_vfs + 1, sizeof(struct qm_shaper_factor), GFP_KERNEL); + total_func = pci_sriov_get_totalvfs(qm->pdev) + 1; + qm->factor = kcalloc(total_func, sizeof(struct qm_shaper_factor), GFP_KERNEL); if (!qm->factor) return -ENOMEM; + for (i = 0; i < total_func; i++) + qm->factor[i].func_qos = QM_QOS_MAX_VAL; #define QM_INIT_BUF(qm, type, num) do { \ (qm)->type = ((qm)->qdma.va + (off)); \ -- GitLab From 488f30d4b8b373cd1ed057bb689704d6fc2a9bc9 Mon Sep 17 00:00:00 2001 From: Kai Ye Date: Sat, 20 Nov 2021 12:47:38 +0800 Subject: [PATCH 0205/1112] crypto: hisilicon/qm - some optimizations of ths qos write process 1. Optimize overly long functions. 2. Fix the format symbol does not match the actual type. 3. Use the PCI_DEVFN to get the function id. Signed-off-by: Kai Ye Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/qm.c | 87 ++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 41 deletions(-) diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 2b998afc57eae..be4e8597b4527 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -4231,66 +4231,69 @@ static ssize_t qm_qos_value_init(const char *buf, unsigned long *val) return 0; } +static ssize_t qm_get_qos_value(struct hisi_qm *qm, const char *buf, + unsigned long *val, + unsigned int *fun_index) +{ + char tbuf_bdf[QM_DBG_READ_LEN] = {0}; + char val_buf[QM_QOS_VAL_MAX_LEN] = {0}; + u32 tmp1, device, function; + int ret, bus; + + ret = sscanf(buf, "%s %s", tbuf_bdf, val_buf); + if (ret != QM_QOS_PARAM_NUM) + return -EINVAL; + + ret = qm_qos_value_init(val_buf, val); + if (*val == 0 || *val > QM_QOS_MAX_VAL || ret) { + pci_err(qm->pdev, "input qos value is error, please set 1~1000!\n"); + return -EINVAL; + } + + ret = sscanf(tbuf_bdf, "%u:%x:%u.%u", &tmp1, &bus, &device, &function); + if (ret != QM_QOS_BDF_PARAM_NUM) { + pci_err(qm->pdev, "input pci bdf value is error!\n"); + return -EINVAL; + } + + *fun_index = PCI_DEVFN(device, function); + + return 0; +} + static ssize_t qm_algqos_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos) { struct hisi_qm *qm = filp->private_data; char tbuf[QM_DBG_READ_LEN]; - int tmp1, bus, device, function; - char tbuf_bdf[QM_DBG_READ_LEN] = {0}; - char val_buf[QM_QOS_VAL_MAX_LEN] = {0}; unsigned int fun_index; - unsigned long val = 0; + unsigned long val; int len, ret; if (qm->fun_type == QM_HW_VF) return -EINVAL; - /* Mailbox and reset cannot be operated at the same time */ - if (test_and_set_bit(QM_RESETTING, &qm->misc_ctl)) { - pci_err(qm->pdev, "dev resetting, write alg qos failed!\n"); - return -EAGAIN; - } - - if (*pos != 0) { - ret = 0; - goto err_get_status; - } + if (*pos != 0) + return 0; - if (count >= QM_DBG_READ_LEN) { - ret = -ENOSPC; - goto err_get_status; - } + if (count >= QM_DBG_READ_LEN) + return -ENOSPC; len = simple_write_to_buffer(tbuf, QM_DBG_READ_LEN - 1, pos, buf, count); - if (len < 0) { - ret = len; - goto err_get_status; - } + if (len < 0) + return len; tbuf[len] = '\0'; - ret = sscanf(tbuf, "%s %s", tbuf_bdf, val_buf); - if (ret != QM_QOS_PARAM_NUM) { - ret = -EINVAL; - goto err_get_status; - } - - ret = qm_qos_value_init(val_buf, &val); - if (val == 0 || val > QM_QOS_MAX_VAL || ret) { - pci_err(qm->pdev, "input qos value is error, please set 1~1000!\n"); - ret = -EINVAL; - goto err_get_status; - } + ret = qm_get_qos_value(qm, tbuf, &val, &fun_index); + if (ret) + return ret; - ret = sscanf(tbuf_bdf, "%d:%x:%d.%d", &tmp1, &bus, &device, &function); - if (ret != QM_QOS_BDF_PARAM_NUM) { - pci_err(qm->pdev, "input pci bdf value is error!\n"); - ret = -EINVAL; - goto err_get_status; + /* Mailbox and reset cannot be operated at the same time */ + if (test_and_set_bit(QM_RESETTING, &qm->misc_ctl)) { + pci_err(qm->pdev, "dev resetting, write alg qos failed!\n"); + return -EAGAIN; } - fun_index = device * 8 + function; - ret = qm_pm_get_sync(qm); if (ret) { ret = -EINVAL; @@ -4304,6 +4307,8 @@ static ssize_t qm_algqos_write(struct file *filp, const char __user *buf, goto err_put_sync; } + pci_info(qm->pdev, "the qos value of function%u is set to %lu.\n", + fun_index, val); ret = count; err_put_sync: -- GitLab From 13389403fe8a978bfc0a866b6d598451feaca212 Mon Sep 17 00:00:00 2001 From: Kai Ye Date: Sat, 20 Nov 2021 12:47:39 +0800 Subject: [PATCH 0206/1112] crypto: hisilicon/qm - simplified the calculation of qos shaper parameters Some optimize for the calculation of qos shaper parameters. and modify the comments. Signed-off-by: Kai Ye Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/qm.c | 84 +++++++++++++++++++++++------------ 1 file changed, 55 insertions(+), 29 deletions(-) diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index be4e8597b4527..ad706ccfe91a2 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -501,10 +501,30 @@ static const char * const qp_s[] = { "none", "init", "start", "stop", "close", }; -static const u32 typical_qos_val[QM_QOS_TYPICAL_NUM] = {100, 250, 500, 1000, - 10000, 25000, 50000, 100000}; -static const u32 typical_qos_cbs_s[QM_QOS_TYPICAL_NUM] = {9, 10, 11, 12, 16, - 17, 18, 19}; +struct qm_typical_qos_table { + u32 start; + u32 end; + u32 val; +}; + +/* the qos step is 100 */ +static struct qm_typical_qos_table shaper_cir_s[] = { + {100, 100, 4}, + {200, 200, 3}, + {300, 500, 2}, + {600, 1000, 1}, + {1100, 100000, 0}, +}; + +static struct qm_typical_qos_table shaper_cbs_s[] = { + {100, 200, 9}, + {300, 500, 11}, + {600, 1000, 12}, + {1100, 10000, 16}, + {10100, 25000, 17}, + {25100, 50000, 18}, + {50100, 100000, 19} +}; static bool qm_avail_state(struct hisi_qm *qm, enum qm_state new) { @@ -988,12 +1008,14 @@ static void qm_init_prefetch(struct hisi_qm *qm) } /* + * acc_shaper_para_calc() Get the IR value by the qos formula, the return value + * is the expected qos calculated. * the formula: * IR = X Mbps if ir = 1 means IR = 100 Mbps, if ir = 10000 means = 10Gbps * - * IR_b * (2 ^ IR_u) * 8 - * IR(Mbps) * 10 ^ -3 = ------------------------- - * Tick * (2 ^ IR_s) + * IR_b * (2 ^ IR_u) * 8000 + * IR(Mbps) = ------------------------- + * Tick * (2 ^ IR_s) */ static u32 acc_shaper_para_calc(u64 cir_b, u64 cir_u, u64 cir_s) { @@ -1003,17 +1025,28 @@ static u32 acc_shaper_para_calc(u64 cir_b, u64 cir_u, u64 cir_s) static u32 acc_shaper_calc_cbs_s(u32 ir) { + int table_size = ARRAY_SIZE(shaper_cbs_s); int i; - if (ir < typical_qos_val[0]) - return QM_SHAPER_MIN_CBS_S; + for (i = 0; i < table_size; i++) { + if (ir >= shaper_cbs_s[i].start && ir <= shaper_cbs_s[i].end) + return shaper_cbs_s[i].val; + } - for (i = 1; i < QM_QOS_TYPICAL_NUM; i++) { - if (ir >= typical_qos_val[i - 1] && ir < typical_qos_val[i]) - return typical_qos_cbs_s[i - 1]; + return QM_SHAPER_MIN_CBS_S; +} + +static u32 acc_shaper_calc_cir_s(u32 ir) +{ + int table_size = ARRAY_SIZE(shaper_cir_s); + int i; + + for (i = 0; i < table_size; i++) { + if (ir >= shaper_cir_s[i].start && ir <= shaper_cir_s[i].end) + return shaper_cir_s[i].val; } - return typical_qos_cbs_s[QM_QOS_TYPICAL_NUM - 1]; + return 0; } static int qm_get_shaper_para(u32 ir, struct qm_shaper_factor *factor) @@ -1022,25 +1055,18 @@ static int qm_get_shaper_para(u32 ir, struct qm_shaper_factor *factor) u32 error_rate; factor->cbs_s = acc_shaper_calc_cbs_s(ir); + cir_s = acc_shaper_calc_cir_s(ir); for (cir_b = QM_QOS_MIN_CIR_B; cir_b <= QM_QOS_MAX_CIR_B; cir_b++) { for (cir_u = 0; cir_u <= QM_QOS_MAX_CIR_U; cir_u++) { - for (cir_s = 0; cir_s <= QM_QOS_MAX_CIR_S; cir_s++) { - /** the formula is changed to: - * IR_b * (2 ^ IR_u) * DIVISOR_CLK - * IR(Mbps) = ------------------------- - * 768 * (2 ^ IR_s) - */ - ir_calc = acc_shaper_para_calc(cir_b, cir_u, - cir_s); - error_rate = QM_QOS_EXPAND_RATE * (u32)abs(ir_calc - ir) / ir; - if (error_rate <= QM_QOS_MIN_ERROR_RATE) { - factor->cir_b = cir_b; - factor->cir_u = cir_u; - factor->cir_s = cir_s; - - return 0; - } + ir_calc = acc_shaper_para_calc(cir_b, cir_u, cir_s); + + error_rate = QM_QOS_EXPAND_RATE * (u32)abs(ir_calc - ir) / ir; + if (error_rate <= QM_QOS_MIN_ERROR_RATE) { + factor->cir_b = cir_b; + factor->cir_u = cir_u; + factor->cir_s = cir_s; + return 0; } } } -- GitLab From 552d03a223eda3df84526ab2c1f4d82e15eaee7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20M=C3=BCller?= Date: Sun, 21 Nov 2021 15:14:20 +0100 Subject: [PATCH 0207/1112] crypto: jitter - consider 32 LSB for APT The APT compares the current time stamp with a pre-set value. The current code only considered the 4 LSB only. Yet, after reviews by mathematicians of the user space Jitter RNG version >= 3.1.0, it was concluded that the APT can be calculated on the 32 LSB of the time delta. Thi change is applied to the kernel. This fixes a bug where an AMD EPYC fails this test as its RDTSC value contains zeros in the LSB. The most appropriate fix would have been to apply a GCD calculation and divide the time stamp by the GCD. Yet, this is a significant code change that will be considered for a future update. Note, tests showed that constantly the GCD always was 32 on these systems, i.e. the 5 LSB were always zero (thus failing the APT since it only considered the 4 LSB for its calculation). Signed-off-by: Stephan Mueller Signed-off-by: Herbert Xu --- crypto/jitterentropy.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crypto/jitterentropy.c b/crypto/jitterentropy.c index 4dc2261cdeefb..788d90749715a 100644 --- a/crypto/jitterentropy.c +++ b/crypto/jitterentropy.c @@ -265,7 +265,6 @@ static int jent_stuck(struct rand_data *ec, __u64 current_delta) { __u64 delta2 = jent_delta(ec->last_delta, current_delta); __u64 delta3 = jent_delta(ec->last_delta2, delta2); - unsigned int delta_masked = current_delta & JENT_APT_WORD_MASK; ec->last_delta = current_delta; ec->last_delta2 = delta2; @@ -274,7 +273,7 @@ static int jent_stuck(struct rand_data *ec, __u64 current_delta) * Insert the result of the comparison of two back-to-back time * deltas. */ - jent_apt_insert(ec, delta_masked); + jent_apt_insert(ec, current_delta); if (!current_delta || !delta2 || !delta3) { /* RCT with a stuck bit */ -- GitLab From 1ce1bacc480965fab4420e561916ce45d2e90c05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20M=C3=BCller?= Date: Sun, 21 Nov 2021 15:31:27 +0100 Subject: [PATCH 0208/1112] crypto: rsa - limit key size to 2048 in FIPS mode FIPS disallows RSA with keys < 2048 bits. Thus, the kernel should consider the enforcement of this limit. Signed-off-by: Stephan Mueller Signed-off-by: Herbert Xu --- crypto/rsa.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crypto/rsa.c b/crypto/rsa.c index 4cdbec95d0779..39e04176b04b2 100644 --- a/crypto/rsa.c +++ b/crypto/rsa.c @@ -5,6 +5,7 @@ * Authors: Tadeusz Struk */ +#include #include #include #include @@ -144,6 +145,9 @@ static int rsa_check_key_length(unsigned int len) case 512: case 1024: case 1536: + if (fips_enabled) + return -EINVAL; + fallthrough; case 2048: case 3072: case 4096: -- GitLab From 1e146c393b152a31771b49af5d104d9ed846da9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20M=C3=BCller?= Date: Sun, 21 Nov 2021 15:51:44 +0100 Subject: [PATCH 0209/1112] crypto: dh - limit key size to 2048 in FIPS mode FIPS disallows DH with keys < 2048 bits. Thus, the kernel should consider the enforcement of this limit. Signed-off-by: Stephan Mueller Signed-off-by: Herbert Xu --- crypto/dh.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crypto/dh.c b/crypto/dh.c index cd4f32092e5ce..38557e64b4b31 100644 --- a/crypto/dh.c +++ b/crypto/dh.c @@ -5,6 +5,7 @@ * Authors: Salvatore Benedetto */ +#include #include #include #include @@ -47,6 +48,9 @@ static inline struct dh_ctx *dh_get_ctx(struct crypto_kpp *tfm) static int dh_check_params_length(unsigned int p_len) { + if (fips_enabled) + return (p_len < 2048) ? -EINVAL : 0; + return (p_len < 1536) ? -EINVAL : 0; } -- GitLab From 330507fbc9d8c3bc4525ea2ae9c3774738bc0c80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20M=C3=BCller?= Date: Sun, 21 Nov 2021 16:10:33 +0100 Subject: [PATCH 0210/1112] crypto: des - disallow des3 in FIPS mode On Dec 31 2023 NIST sunsets TDES for FIPS use. To prevent FIPS validations to be completed in the future to be affected by the TDES sunsetting, disallow TDES already now. Otherwise a FIPS validation would need to be "touched again" end 2023 to handle TDES accordingly. Signed-off-by: Stephan Mueller Signed-off-by: Herbert Xu --- crypto/testmgr.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 58eee8eab4bf7..5831d4bbc64fa 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -4193,7 +4193,6 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "authenc(hmac(sha1),cbc(des3_ede))", .test = alg_test_aead, - .fips_allowed = 1, .suite = { .aead = __VECS(hmac_sha1_des3_ede_cbc_tv_temp) } @@ -4220,7 +4219,6 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "authenc(hmac(sha224),cbc(des3_ede))", .test = alg_test_aead, - .fips_allowed = 1, .suite = { .aead = __VECS(hmac_sha224_des3_ede_cbc_tv_temp) } @@ -4240,7 +4238,6 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "authenc(hmac(sha256),cbc(des3_ede))", .test = alg_test_aead, - .fips_allowed = 1, .suite = { .aead = __VECS(hmac_sha256_des3_ede_cbc_tv_temp) } @@ -4261,7 +4258,6 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "authenc(hmac(sha384),cbc(des3_ede))", .test = alg_test_aead, - .fips_allowed = 1, .suite = { .aead = __VECS(hmac_sha384_des3_ede_cbc_tv_temp) } @@ -4289,7 +4285,6 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "authenc(hmac(sha512),cbc(des3_ede))", .test = alg_test_aead, - .fips_allowed = 1, .suite = { .aead = __VECS(hmac_sha512_des3_ede_cbc_tv_temp) } @@ -4399,7 +4394,6 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "cbc(des3_ede)", .test = alg_test_skcipher, - .fips_allowed = 1, .suite = { .cipher = __VECS(des3_ede_cbc_tv_template) }, @@ -4505,7 +4499,6 @@ static const struct alg_test_desc alg_test_descs[] = { } }, { .alg = "cmac(des3_ede)", - .fips_allowed = 1, .test = alg_test_hash, .suite = { .hash = __VECS(des3_ede_cmac64_tv_template) @@ -4580,7 +4573,6 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "ctr(des3_ede)", .test = alg_test_skcipher, - .fips_allowed = 1, .suite = { .cipher = __VECS(des3_ede_ctr_tv_template) } @@ -4846,7 +4838,6 @@ static const struct alg_test_desc alg_test_descs[] = { }, { .alg = "ecb(des3_ede)", .test = alg_test_skcipher, - .fips_allowed = 1, .suite = { .cipher = __VECS(des3_ede_tv_template) } -- GitLab From 76e95f331be09bac8764e971613439d294422d6e Mon Sep 17 00:00:00 2001 From: Dominik Kobinski Date: Tue, 23 Nov 2021 19:08:16 +0100 Subject: [PATCH 0211/1112] dt-bindings: regulator: qcom: spmi-regulator: Document pm8226 compatible Suggested-by: Ivaylo Ivanov Signed-off-by: Dominik Kobinski Link: https://lore.kernel.org/r/20211123180816.2835-1-dominikkobinski314@gmail.com Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/qcom,spmi-regulator.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt b/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt index 2b544059e029d..c2a39b121b1b9 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt @@ -6,6 +6,7 @@ Qualcomm SPMI Regulators Definition: must be one of: "qcom,pm8004-regulators" "qcom,pm8005-regulators" + "qcom,pm8226-regulators" "qcom,pm8841-regulators" "qcom,pm8916-regulators" "qcom,pm8941-regulators" -- GitLab From f8843e5e2dc85dc6a546ec130d76be66e62abed6 Mon Sep 17 00:00:00 2001 From: Dominik Kobinski Date: Tue, 23 Nov 2021 19:11:19 +0100 Subject: [PATCH 0212/1112] regulator: qcom_spmi: Add pm8226 regulators The PM8226 PMIC is very often seen on MSM8x26 boards. Suggested-by: Ivaylo Ivanov Signed-off-by: Dominik Kobinski Reviewed-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211123181119.2897-1-dominikkobinski314@gmail.com Signed-off-by: Mark Brown --- drivers/regulator/qcom_spmi-regulator.c | 39 +++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c index 41424a3366d0e..02bfce9811506 100644 --- a/drivers/regulator/qcom_spmi-regulator.c +++ b/drivers/regulator/qcom_spmi-regulator.c @@ -1895,6 +1895,44 @@ static const struct spmi_regulator_data pm8941_regulators[] = { { } }; +static const struct spmi_regulator_data pm8226_regulators[] = { + { "s1", 0x1400, "vdd_s1", }, + { "s2", 0x1700, "vdd_s2", }, + { "s3", 0x1a00, "vdd_s3", }, + { "s4", 0x1d00, "vdd_s4", }, + { "s5", 0x2000, "vdd_s5", }, + { "l1", 0x4000, "vdd_l1_l2_l4_l5", }, + { "l2", 0x4100, "vdd_l1_l2_l4_l5", }, + { "l3", 0x4200, "vdd_l3_l24_l26", }, + { "l4", 0x4300, "vdd_l1_l2_l4_l5", }, + { "l5", 0x4400, "vdd_l1_l2_l4_l5", }, + { "l6", 0x4500, "vdd_l6_l7_l8_l9_l27", }, + { "l7", 0x4600, "vdd_l6_l7_l8_l9_l27", }, + { "l8", 0x4700, "vdd_l6_l7_l8_l9_l27", }, + { "l9", 0x4800, "vdd_l6_l7_l8_l9_l27", }, + { "l10", 0x4900, "vdd_l10_l11_l13", }, + { "l11", 0x4a00, "vdd_l10_l11_l13", }, + { "l12", 0x4b00, "vdd_l12_l14", }, + { "l13", 0x4c00, "vdd_l10_l11_l13", }, + { "l14", 0x4d00, "vdd_l12_l14", }, + { "l15", 0x4e00, "vdd_l15_l16_l17_l18", }, + { "l16", 0x4f00, "vdd_l15_l16_l17_l18", }, + { "l17", 0x5000, "vdd_l15_l16_l17_l18", }, + { "l18", 0x5100, "vdd_l15_l16_l17_l18", }, + { "l19", 0x5200, "vdd_l19_l20_l21_l22_l23_l28", }, + { "l20", 0x5300, "vdd_l19_l20_l21_l22_l23_l28", }, + { "l21", 0x5400, "vdd_l19_l20_l21_l22_l23_l28", }, + { "l22", 0x5500, "vdd_l19_l20_l21_l22_l23_l28", }, + { "l23", 0x5600, "vdd_l19_l20_l21_l22_l23_l28", }, + { "l24", 0x5700, "vdd_l3_l24_l26", }, + { "l25", 0x5800, "vdd_l25", }, + { "l26", 0x5900, "vdd_l3_l24_l26", }, + { "l27", 0x5a00, "vdd_l6_l7_l8_l9_l27", }, + { "l28", 0x5b00, "vdd_l19_l20_l21_l22_l23_l28", }, + { "lvs1", 0x8000, "vdd_lvs1", }, + { } +}; + static const struct spmi_regulator_data pm8841_regulators[] = { { "s1", 0x1400, "vdd_s1", }, { "s2", 0x1700, "vdd_s2", NULL, 0x1c08 }, @@ -2095,6 +2133,7 @@ static const struct spmi_regulator_data pms405_regulators[] = { static const struct of_device_id qcom_spmi_regulator_match[] = { { .compatible = "qcom,pm8004-regulators", .data = &pm8004_regulators }, { .compatible = "qcom,pm8005-regulators", .data = &pm8005_regulators }, + { .compatible = "qcom,pm8226-regulators", .data = &pm8226_regulators }, { .compatible = "qcom,pm8841-regulators", .data = &pm8841_regulators }, { .compatible = "qcom,pm8916-regulators", .data = &pm8916_regulators }, { .compatible = "qcom,pm8941-regulators", .data = &pm8941_regulators }, -- GitLab From c1b00674aab0c6950970e52c0f059756064a9e8c Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Thu, 25 Nov 2021 14:41:09 +0200 Subject: [PATCH 0213/1112] spi: atmel: Drop slave_config argument in atmel_spi_dma_slave_config() The callers passed a pointer to slave_config as an argument of atmel_spi_dma_slave_config(), but they did not use it afterwards. Use instead a local variable in atmel_spi_dma_slave_config(), and stop passing arguments that are not needed in the callers. Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20211125124110.838037-2-tudor.ambarus@microchip.com Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index f872cf196c2f3..22c7239aff759 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -433,26 +433,25 @@ static bool atmel_spi_can_dma(struct spi_master *master, } -static int atmel_spi_dma_slave_config(struct atmel_spi *as, - struct dma_slave_config *slave_config, - u8 bits_per_word) +static int atmel_spi_dma_slave_config(struct atmel_spi *as, u8 bits_per_word) { struct spi_master *master = platform_get_drvdata(as->pdev); + struct dma_slave_config slave_config; int err = 0; if (bits_per_word > 8) { - slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; - slave_config->src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; } else { - slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; - slave_config->src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; } - slave_config->dst_addr = (dma_addr_t)as->phybase + SPI_TDR; - slave_config->src_addr = (dma_addr_t)as->phybase + SPI_RDR; - slave_config->src_maxburst = 1; - slave_config->dst_maxburst = 1; - slave_config->device_fc = false; + slave_config.dst_addr = (dma_addr_t)as->phybase + SPI_TDR; + slave_config.src_addr = (dma_addr_t)as->phybase + SPI_RDR; + slave_config.src_maxburst = 1; + slave_config.dst_maxburst = 1; + slave_config.device_fc = false; /* * This driver uses fixed peripheral select mode (PS bit set to '0' in @@ -468,8 +467,8 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as, * So we'd rather write only one data at the time. Hence the transmit * path works the same whether FIFOs are available (and enabled) or not. */ - slave_config->direction = DMA_MEM_TO_DEV; - if (dmaengine_slave_config(master->dma_tx, slave_config)) { + slave_config.direction = DMA_MEM_TO_DEV; + if (dmaengine_slave_config(master->dma_tx, &slave_config)) { dev_err(&as->pdev->dev, "failed to configure tx dma channel\n"); err = -EINVAL; @@ -483,8 +482,8 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as, * So the receive path works the same whether FIFOs are available (and * enabled) or not. */ - slave_config->direction = DMA_DEV_TO_MEM; - if (dmaengine_slave_config(master->dma_rx, slave_config)) { + slave_config.direction = DMA_DEV_TO_MEM; + if (dmaengine_slave_config(master->dma_rx, &slave_config)) { dev_err(&as->pdev->dev, "failed to configure rx dma channel\n"); err = -EINVAL; @@ -496,7 +495,6 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as, static int atmel_spi_configure_dma(struct spi_master *master, struct atmel_spi *as) { - struct dma_slave_config slave_config; struct device *dev = &as->pdev->dev; int err; @@ -518,7 +516,7 @@ static int atmel_spi_configure_dma(struct spi_master *master, goto error; } - err = atmel_spi_dma_slave_config(as, &slave_config, 8); + err = atmel_spi_dma_slave_config(as, 8); if (err) goto error; @@ -700,7 +698,6 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master, struct dma_chan *txchan = master->dma_tx; struct dma_async_tx_descriptor *rxdesc; struct dma_async_tx_descriptor *txdesc; - struct dma_slave_config slave_config; dma_cookie_t cookie; dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_dma_submit\n"); @@ -712,8 +709,7 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master, *plen = xfer->len; - if (atmel_spi_dma_slave_config(as, &slave_config, - xfer->bits_per_word)) + if (atmel_spi_dma_slave_config(as, xfer->bits_per_word)) goto err_exit; /* Send both scatterlists */ -- GitLab From f44a29ceb99fc99832ee1d55d7fe9c4dbf594660 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Thu, 25 Nov 2021 14:41:10 +0200 Subject: [PATCH 0214/1112] spi: atmel: Remove setting of deprecated member of struct dma_slave_config The 'direction' member of 'struct dma_slave_config' is deprecated. Instead, drivers should use the direction argument to the device_prep_slave_sg and device_prep_dma_cyclic functions or the dir field in the dma_interleaved_template structure. spi-atmel uses the direction argument to dmaengine_prep_slave_sg. slave_config.direction is not used in neither of the DMA controller drivers (at_h/xdmac) that spi-atmel is using, we can just remove the setting of slave_config.direction and live with whatever stack value is there. Signed-off-by: Tudor Ambarus Link: https://lore.kernel.org/r/20211125124110.838037-3-tudor.ambarus@microchip.com Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 22c7239aff759..f6626be4d4f77 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -467,7 +467,6 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as, u8 bits_per_word) * So we'd rather write only one data at the time. Hence the transmit * path works the same whether FIFOs are available (and enabled) or not. */ - slave_config.direction = DMA_MEM_TO_DEV; if (dmaengine_slave_config(master->dma_tx, &slave_config)) { dev_err(&as->pdev->dev, "failed to configure tx dma channel\n"); @@ -482,7 +481,6 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as, u8 bits_per_word) * So the receive path works the same whether FIFOs are available (and * enabled) or not. */ - slave_config.direction = DMA_DEV_TO_MEM; if (dmaengine_slave_config(master->dma_rx, &slave_config)) { dev_err(&as->pdev->dev, "failed to configure rx dma channel\n"); -- GitLab From f89d2cc3967af9948ffc58e4cc9a1331f1c4971a Mon Sep 17 00:00:00 2001 From: Krishna Yarlagadda Date: Thu, 25 Nov 2021 15:25:51 +0530 Subject: [PATCH 0215/1112] spi: tegra210-quad: use devm call for cdata memory Use devm alloc call to allocate memory for spi controller data and remove free calls from cleanup. Signed-off-by: Krishna Yarlagadda Link: https://lore.kernel.org/r/1637834152-32093-1-git-send-email-kyarlagadda@nvidia.com Signed-off-by: Mark Brown --- drivers/spi/spi-tegra210-quad.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c index c0f9a75b44b5d..ce1bdb4767ea3 100644 --- a/drivers/spi/spi-tegra210-quad.c +++ b/drivers/spi/spi-tegra210-quad.c @@ -877,7 +877,7 @@ static struct tegra_qspi_client_data *tegra_qspi_parse_cdata_dt(struct spi_devic struct tegra_qspi_client_data *cdata; struct device_node *slave_np = spi->dev.of_node; - cdata = kzalloc(sizeof(*cdata), GFP_KERNEL); + cdata = devm_kzalloc(&spi->dev, sizeof(*cdata), GFP_KERNEL); if (!cdata) return NULL; @@ -888,14 +888,6 @@ static struct tegra_qspi_client_data *tegra_qspi_parse_cdata_dt(struct spi_devic return cdata; } -static void tegra_qspi_cleanup(struct spi_device *spi) -{ - struct tegra_qspi_client_data *cdata = spi->controller_data; - - spi->controller_data = NULL; - kfree(cdata); -} - static int tegra_qspi_setup(struct spi_device *spi) { struct tegra_qspi *tqspi = spi_master_get_devdata(spi->master); @@ -1229,7 +1221,6 @@ static int tegra_qspi_probe(struct platform_device *pdev) SPI_TX_DUAL | SPI_RX_DUAL | SPI_TX_QUAD | SPI_RX_QUAD; master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | SPI_BPW_MASK(8); master->setup = tegra_qspi_setup; - master->cleanup = tegra_qspi_cleanup; master->transfer_one_message = tegra_qspi_transfer_one_message; master->num_chipselect = 1; master->auto_runtime_pm = true; -- GitLab From 4e0d84634445ed550498d613a49ea8f6cfa5e66c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 26 Nov 2021 10:58:40 +0100 Subject: [PATCH 0216/1112] futex: Fix sparc32/m68k/nds32 build regression The recent futex cleanup series, botched up a rename of some function names, breaking sparc32, m68k and nds32: include/asm-generic/futex.h:17:2: error: implicit declaration of function 'futex_atomic_cmpxchg_inatomic_local_generic'; did you mean 'futex_atomic_cmpxchg_inatomic_local'? [-Werror=implicit-function-declaration] Fix the macros to point to the correct functions. Fixes: 3f2bedabb62c ("futex: Ensure futex_atomic_cmpxchg_inatomic() is present") Reported-by: Stephen Rothwell Signed-off-by: Arnd Bergmann Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/r/20211126095852.455492-1-arnd@kernel.org --- include/asm-generic/futex.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/asm-generic/futex.h b/include/asm-generic/futex.h index 30e7fa63b5dfe..66d6843bfd024 100644 --- a/include/asm-generic/futex.h +++ b/include/asm-generic/futex.h @@ -14,9 +14,9 @@ * */ #define futex_atomic_cmpxchg_inatomic(uval, uaddr, oldval, newval) \ - futex_atomic_cmpxchg_inatomic_local_generic(uval, uaddr, oldval, newval) + futex_atomic_cmpxchg_inatomic_local(uval, uaddr, oldval, newval) #define arch_futex_atomic_op_inuser(op, oparg, oval, uaddr) \ - arch_futex_atomic_op_inuser_local_generic(op, oparg, oval, uaddr) + futex_atomic_op_inuser_local(op, oparg, oval, uaddr) #endif /* CONFIG_SMP */ #endif -- GitLab From 81a7297c5b50f8e72540bdf04149efffaf01748c Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Tue, 16 Nov 2021 14:53:03 +0200 Subject: [PATCH 0217/1112] dt-bindings: mfd: regulator: Drop BD70528 support The only known BD70528 use-cases are such that the PMIC is controlled from separate MCU which is not running Linux. I am not aware of any Linux driver users. Furthermore, it seems there is no demand for this IC. Let's ease the maintenance burden and drop the driver. We can always add it back if there is sudden need for it. Signed-off-by: Matti Vaittinen Acked-by: Rob Herring Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/64c88990270d9a22508446ef2fe3b6a2622a0b01.1637066805.git.matti.vaittinen@fi.rohmeurope.com --- .../bindings/mfd/rohm,bd70528-pmic.txt | 102 ------------------ .../regulator/rohm,bd70528-regulator.txt | 68 ------------ 2 files changed, 170 deletions(-) delete mode 100644 Documentation/devicetree/bindings/mfd/rohm,bd70528-pmic.txt delete mode 100644 Documentation/devicetree/bindings/regulator/rohm,bd70528-regulator.txt diff --git a/Documentation/devicetree/bindings/mfd/rohm,bd70528-pmic.txt b/Documentation/devicetree/bindings/mfd/rohm,bd70528-pmic.txt deleted file mode 100644 index 386eec06cf08d..0000000000000 --- a/Documentation/devicetree/bindings/mfd/rohm,bd70528-pmic.txt +++ /dev/null @@ -1,102 +0,0 @@ -* ROHM BD70528 Power Management Integrated Circuit bindings - -BD70528MWV is an ultra-low quiescent current general purpose, single-chip, -power management IC for battery-powered portable devices. The IC -integrates 3 ultra-low current consumption buck converters, 3 LDOs and 2 -LED Drivers. Also included are 4 GPIOs, a real-time clock (RTC), a 32kHz -clock gate, high-accuracy VREF for use with an external ADC, flexible -dual-input power path, 10 bit SAR ADC for battery temperature monitor and -1S battery charger with scalable charge currents. - -Required properties: - - compatible : Should be "rohm,bd70528" - - reg : I2C slave address. - - interrupts : The interrupt line the device is connected to. - - interrupt-controller : To indicate BD70528 acts as an interrupt controller. - - #interrupt-cells : Should be 2. Usage is compliant to the 2 cells - variant of ../interrupt-controller/interrupts.txt - - gpio-controller : To indicate BD70528 acts as a GPIO controller. - - #gpio-cells : Should be 2. The first cell is the pin number and - the second cell is used to specify flags. See - ../gpio/gpio.txt for more information. - - #clock-cells : Should be 0. - - regulators: : List of child nodes that specify the regulators. - Please see ../regulator/rohm,bd70528-regulator.txt - -Optional properties: - - clock-output-names : Should contain name for output clock. - -Example: -/* External oscillator */ -osc: oscillator { - compatible = "fixed-clock"; - #clock-cells = <1>; - clock-frequency = <32768>; - clock-output-names = "osc"; -}; - -pmic: pmic@4b { - compatible = "rohm,bd70528"; - reg = <0x4b>; - interrupt-parent = <&gpio1>; - interrupts = <29 IRQ_TYPE_LEVEL_LOW>; - clocks = <&osc 0>; - #clock-cells = <0>; - clock-output-names = "bd70528-32k-out"; - #gpio-cells = <2>; - gpio-controller; - interrupt-controller; - #interrupt-cells = <2>; - - regulators { - buck1: BUCK1 { - regulator-name = "buck1"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <3400000>; - regulator-boot-on; - regulator-ramp-delay = <125>; - }; - buck2: BUCK2 { - regulator-name = "buck2"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <3300000>; - regulator-boot-on; - regulator-ramp-delay = <125>; - }; - buck3: BUCK3 { - regulator-name = "buck3"; - regulator-min-microvolt = <800000>; - regulator-max-microvolt = <1800000>; - regulator-boot-on; - regulator-ramp-delay = <250>; - }; - ldo1: LDO1 { - regulator-name = "ldo1"; - regulator-min-microvolt = <1650000>; - regulator-max-microvolt = <3300000>; - regulator-boot-on; - }; - ldo2: LDO2 { - regulator-name = "ldo2"; - regulator-min-microvolt = <1650000>; - regulator-max-microvolt = <3300000>; - regulator-boot-on; - }; - - ldo3: LDO3 { - regulator-name = "ldo3"; - regulator-min-microvolt = <1650000>; - regulator-max-microvolt = <3300000>; - }; - led_ldo1: LED_LDO1 { - regulator-name = "led_ldo1"; - regulator-min-microvolt = <200000>; - regulator-max-microvolt = <300000>; - }; - led_ldo2: LED_LDO2 { - regulator-name = "led_ldo2"; - regulator-min-microvolt = <200000>; - regulator-max-microvolt = <300000>; - }; - }; -}; diff --git a/Documentation/devicetree/bindings/regulator/rohm,bd70528-regulator.txt b/Documentation/devicetree/bindings/regulator/rohm,bd70528-regulator.txt deleted file mode 100644 index 698cfc3bc3dd3..0000000000000 --- a/Documentation/devicetree/bindings/regulator/rohm,bd70528-regulator.txt +++ /dev/null @@ -1,68 +0,0 @@ -ROHM BD70528 Power Management Integrated Circuit regulator bindings - -Required properties: - - regulator-name: should be "buck1", "buck2", "buck3", "ldo1", "ldo2", "ldo3", - "led_ldo1", "led_ldo2" - -List of regulators provided by this controller. BD70528 regulators node -should be sub node of the BD70528 MFD node. See BD70528 MFD bindings at -Documentation/devicetree/bindings/mfd/rohm,bd70528-pmic.txt - -The valid names for BD70528 regulator nodes are: -BUCK1, BUCK2, BUCK3, LDO1, LDO2, LDO3, LED_LDO1, LED_LDO2 - -Optional properties: -- Any optional property defined in bindings/regulator/regulator.txt - -Example: -regulators { - buck1: BUCK1 { - regulator-name = "buck1"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <3400000>; - regulator-boot-on; - regulator-ramp-delay = <125>; - }; - buck2: BUCK2 { - regulator-name = "buck2"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <3300000>; - regulator-boot-on; - regulator-ramp-delay = <125>; - }; - buck3: BUCK3 { - regulator-name = "buck3"; - regulator-min-microvolt = <800000>; - regulator-max-microvolt = <1800000>; - regulator-boot-on; - regulator-ramp-delay = <250>; - }; - ldo1: LDO1 { - regulator-name = "ldo1"; - regulator-min-microvolt = <1650000>; - regulator-max-microvolt = <3300000>; - regulator-boot-on; - }; - ldo2: LDO2 { - regulator-name = "ldo2"; - regulator-min-microvolt = <1650000>; - regulator-max-microvolt = <3300000>; - regulator-boot-on; - }; - - ldo3: LDO3 { - regulator-name = "ldo3"; - regulator-min-microvolt = <1650000>; - regulator-max-microvolt = <3300000>; - }; - led_ldo1: LED_LDO1 { - regulator-name = "led_ldo1"; - regulator-min-microvolt = <200000>; - regulator-max-microvolt = <300000>; - }; - led_ldo2: LED_LDO2 { - regulator-name = "led_ldo2"; - regulator-min-microvolt = <200000>; - regulator-max-microvolt = <300000>; - }; -}; -- GitLab From da53cc634cea6eb5d21809512ef348f6d4130850 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Tue, 16 Nov 2021 14:54:06 +0200 Subject: [PATCH 0218/1112] gpio: bd70528 Drop BD70528 support The only known BD70528 use-cases are such that the PMIC is controlled from separate MCU which is not running Linux. I am not aware of any Linux driver users. Furthermore, it seems there is no demand for this IC. Let's ease the maintenance burden and drop the driver. We can always add it back if there is sudden need for it. Signed-off-by: Matti Vaittinen Acked-by: Bartosz Golaszewski Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/4eff6bd5eff8afc137dd8c1697cb5c6b2e3aacd2.1637066805.git.matti.vaittinen@fi.rohmeurope.com --- drivers/gpio/Kconfig | 11 -- drivers/gpio/Makefile | 1 - drivers/gpio/gpio-bd70528.c | 230 ------------------------------------ 3 files changed, 242 deletions(-) delete mode 100644 drivers/gpio/gpio-bd70528.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 072ed610f9c66..4c02ee52b701c 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1132,17 +1132,6 @@ config GPIO_ARIZONA help Support for GPIOs on Wolfson Arizona class devices. -config GPIO_BD70528 - tristate "ROHM BD70528 GPIO support" - depends on MFD_ROHM_BD70528 - help - Support for GPIOs on ROHM BD70528 PMIC. There are four GPIOs - available on the ROHM PMIC in total. The GPIOs can also - generate interrupts. - - This driver can also be built as a module. If so, the module - will be called gpio-bd70528. - config GPIO_BD71815 tristate "ROHM BD71815 PMIC GPIO support" depends on MFD_ROHM_BD71828 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 71ee9fc2ff837..ed5f9b1a75ce1 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -38,7 +38,6 @@ obj-$(CONFIG_GPIO_ASPEED_SGPIO) += gpio-aspeed-sgpio.o obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o obj-$(CONFIG_GPIO_BCM_XGS_IPROC) += gpio-xgs-iproc.o -obj-$(CONFIG_GPIO_BD70528) += gpio-bd70528.o obj-$(CONFIG_GPIO_BD71815) += gpio-bd71815.o obj-$(CONFIG_GPIO_BD71828) += gpio-bd71828.o obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o diff --git a/drivers/gpio/gpio-bd70528.c b/drivers/gpio/gpio-bd70528.c deleted file mode 100644 index 397a50d6bc654..0000000000000 --- a/drivers/gpio/gpio-bd70528.c +++ /dev/null @@ -1,230 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2018 ROHM Semiconductors -// gpio-bd70528.c ROHM BD70528MWV gpio driver - -#include -#include -#include -#include -#include - -#define GPIO_IN_REG(offset) (BD70528_REG_GPIO1_IN + (offset) * 2) -#define GPIO_OUT_REG(offset) (BD70528_REG_GPIO1_OUT + (offset) * 2) - -struct bd70528_gpio { - struct regmap *regmap; - struct device *dev; - struct gpio_chip gpio; -}; - -static int bd70528_set_debounce(struct bd70528_gpio *bdgpio, - unsigned int offset, unsigned int debounce) -{ - u8 val; - - switch (debounce) { - case 0: - val = BD70528_DEBOUNCE_DISABLE; - break; - case 1 ... 15000: - val = BD70528_DEBOUNCE_15MS; - break; - case 15001 ... 30000: - val = BD70528_DEBOUNCE_30MS; - break; - case 30001 ... 50000: - val = BD70528_DEBOUNCE_50MS; - break; - default: - dev_err(bdgpio->dev, - "Invalid debounce value %u\n", debounce); - return -EINVAL; - } - return regmap_update_bits(bdgpio->regmap, GPIO_IN_REG(offset), - BD70528_DEBOUNCE_MASK, val); -} - -static int bd70528_get_direction(struct gpio_chip *chip, unsigned int offset) -{ - struct bd70528_gpio *bdgpio = gpiochip_get_data(chip); - int val, ret; - - /* Do we need to do something to IRQs here? */ - ret = regmap_read(bdgpio->regmap, GPIO_OUT_REG(offset), &val); - if (ret) { - dev_err(bdgpio->dev, "Could not read gpio direction\n"); - return ret; - } - if (val & BD70528_GPIO_OUT_EN_MASK) - return GPIO_LINE_DIRECTION_OUT; - - return GPIO_LINE_DIRECTION_IN; -} - -static int bd70528_gpio_set_config(struct gpio_chip *chip, unsigned int offset, - unsigned long config) -{ - struct bd70528_gpio *bdgpio = gpiochip_get_data(chip); - - switch (pinconf_to_config_param(config)) { - case PIN_CONFIG_DRIVE_OPEN_DRAIN: - return regmap_update_bits(bdgpio->regmap, - GPIO_OUT_REG(offset), - BD70528_GPIO_DRIVE_MASK, - BD70528_GPIO_OPEN_DRAIN); - break; - case PIN_CONFIG_DRIVE_PUSH_PULL: - return regmap_update_bits(bdgpio->regmap, - GPIO_OUT_REG(offset), - BD70528_GPIO_DRIVE_MASK, - BD70528_GPIO_PUSH_PULL); - break; - case PIN_CONFIG_INPUT_DEBOUNCE: - return bd70528_set_debounce(bdgpio, offset, - pinconf_to_config_argument(config)); - break; - default: - break; - } - return -ENOTSUPP; -} - -static int bd70528_direction_input(struct gpio_chip *chip, unsigned int offset) -{ - struct bd70528_gpio *bdgpio = gpiochip_get_data(chip); - - /* Do we need to do something to IRQs here? */ - return regmap_update_bits(bdgpio->regmap, GPIO_OUT_REG(offset), - BD70528_GPIO_OUT_EN_MASK, - BD70528_GPIO_OUT_DISABLE); -} - -static void bd70528_gpio_set(struct gpio_chip *chip, unsigned int offset, - int value) -{ - int ret; - struct bd70528_gpio *bdgpio = gpiochip_get_data(chip); - u8 val = (value) ? BD70528_GPIO_OUT_HI : BD70528_GPIO_OUT_LO; - - ret = regmap_update_bits(bdgpio->regmap, GPIO_OUT_REG(offset), - BD70528_GPIO_OUT_MASK, val); - if (ret) - dev_err(bdgpio->dev, "Could not set gpio to %d\n", value); -} - -static int bd70528_direction_output(struct gpio_chip *chip, unsigned int offset, - int value) -{ - struct bd70528_gpio *bdgpio = gpiochip_get_data(chip); - - bd70528_gpio_set(chip, offset, value); - return regmap_update_bits(bdgpio->regmap, GPIO_OUT_REG(offset), - BD70528_GPIO_OUT_EN_MASK, - BD70528_GPIO_OUT_ENABLE); -} - -#define GPIO_IN_STATE_MASK(offset) (BD70528_GPIO_IN_STATE_BASE << (offset)) - -static int bd70528_gpio_get_o(struct bd70528_gpio *bdgpio, unsigned int offset) -{ - int ret; - unsigned int val; - - ret = regmap_read(bdgpio->regmap, GPIO_OUT_REG(offset), &val); - if (!ret) - ret = !!(val & BD70528_GPIO_OUT_MASK); - else - dev_err(bdgpio->dev, "GPIO (out) state read failed\n"); - - return ret; -} - -static int bd70528_gpio_get_i(struct bd70528_gpio *bdgpio, unsigned int offset) -{ - unsigned int val; - int ret; - - ret = regmap_read(bdgpio->regmap, BD70528_REG_GPIO_STATE, &val); - - if (!ret) - ret = !(val & GPIO_IN_STATE_MASK(offset)); - else - dev_err(bdgpio->dev, "GPIO (in) state read failed\n"); - - return ret; -} - -static int bd70528_gpio_get(struct gpio_chip *chip, unsigned int offset) -{ - int ret; - struct bd70528_gpio *bdgpio = gpiochip_get_data(chip); - - /* - * There is a race condition where someone might be changing the - * GPIO direction after we get it but before we read the value. But - * application design where GPIO direction may be changed just when - * we read GPIO value would be pointless as reader could not know - * whether the returned high/low state is caused by input or output. - * Or then there must be other ways to mitigate the issue. Thus - * locking would make no sense. - */ - ret = bd70528_get_direction(chip, offset); - if (ret == GPIO_LINE_DIRECTION_OUT) - ret = bd70528_gpio_get_o(bdgpio, offset); - else if (ret == GPIO_LINE_DIRECTION_IN) - ret = bd70528_gpio_get_i(bdgpio, offset); - else - dev_err(bdgpio->dev, "failed to read GPIO direction\n"); - - return ret; -} - -static int bd70528_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct bd70528_gpio *bdgpio; - int ret; - - bdgpio = devm_kzalloc(dev, sizeof(*bdgpio), GFP_KERNEL); - if (!bdgpio) - return -ENOMEM; - bdgpio->dev = dev; - bdgpio->gpio.parent = dev->parent; - bdgpio->gpio.label = "bd70528-gpio"; - bdgpio->gpio.owner = THIS_MODULE; - bdgpio->gpio.get_direction = bd70528_get_direction; - bdgpio->gpio.direction_input = bd70528_direction_input; - bdgpio->gpio.direction_output = bd70528_direction_output; - bdgpio->gpio.set_config = bd70528_gpio_set_config; - bdgpio->gpio.can_sleep = true; - bdgpio->gpio.get = bd70528_gpio_get; - bdgpio->gpio.set = bd70528_gpio_set; - bdgpio->gpio.ngpio = 4; - bdgpio->gpio.base = -1; -#ifdef CONFIG_OF_GPIO - bdgpio->gpio.of_node = dev->parent->of_node; -#endif - bdgpio->regmap = dev_get_regmap(dev->parent, NULL); - if (!bdgpio->regmap) - return -ENODEV; - - ret = devm_gpiochip_add_data(dev, &bdgpio->gpio, bdgpio); - if (ret) - dev_err(dev, "gpio_init: Failed to add bd70528-gpio\n"); - - return ret; -} - -static struct platform_driver bd70528_gpio = { - .driver = { - .name = "bd70528-gpio" - }, - .probe = bd70528_probe, -}; - -module_platform_driver(bd70528_gpio); - -MODULE_AUTHOR("Matti Vaittinen "); -MODULE_DESCRIPTION("BD70528 voltage regulator driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:bd70528-gpio"); -- GitLab From 306456c21c792ac633e660bc45f0854b612a0e98 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Tue, 16 Nov 2021 14:54:35 +0200 Subject: [PATCH 0219/1112] mfd: bd70528: Drop BD70528 support The only known BD70528 use-cases are such that the PMIC is controlled from separate MCU which is not running Linux. I am not aware of any Linux driver users. Furthermore, it seems there is no demand for this IC. Let's ease the maintenance burden and drop the driver. We can always add it back if there is sudden need for it. Signed-off-by: Matti Vaittinen Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/cf7dfd98b3403ad363b2b48b57bdbfd57a6416cb.1637066805.git.matti.vaittinen@fi.rohmeurope.com --- drivers/mfd/Kconfig | 17 -- drivers/mfd/Makefile | 1 - drivers/mfd/rohm-bd70528.c | 314 ------------------------- include/linux/mfd/rohm-bd70528.h | 389 ------------------------------- include/linux/mfd/rohm-generic.h | 1 - 5 files changed, 722 deletions(-) delete mode 100644 drivers/mfd/rohm-bd70528.c delete mode 100644 include/linux/mfd/rohm-bd70528.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 3fb4808185991..34c7d9d6b5800 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1945,23 +1945,6 @@ config MFD_ROHM_BD718XX NXP i.MX8. It contains 8 BUCK outputs and 7 LDOs, voltage monitoring and emergency shut down as well as 32,768KHz clock output. -config MFD_ROHM_BD70528 - tristate "ROHM BD70528 Power Management IC" - depends on I2C=y - depends on OF - select REGMAP_I2C - select REGMAP_IRQ - select MFD_CORE - help - Select this option to get support for the ROHM BD70528 Power - Management IC. BD71837 is general purpose single-chip power - management IC for battery-powered portable devices. It contains - 3 ultra-low current consumption buck converters, 3 LDOs and 2 LED - drivers. Also included are 4 GPIOs, a real-time clock (RTC), a 32kHz - crystal oscillator, high-accuracy VREF for use with an external ADC, - 10 bits SAR ADC for battery temperature monitor and 1S battery - charger. - config MFD_ROHM_BD71828 tristate "ROHM BD71828 and BD71815 Power Management IC" depends on I2C=y diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 0b1b629aef3e4..4d53e951a92d2 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -257,7 +257,6 @@ obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o obj-$(CONFIG_MFD_SC27XX_PMIC) += sprd-sc27xx-spi.o obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o -obj-$(CONFIG_MFD_ROHM_BD70528) += rohm-bd70528.o obj-$(CONFIG_MFD_ROHM_BD71828) += rohm-bd71828.o obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o obj-$(CONFIG_MFD_ROHM_BD957XMUF) += rohm-bd9576.o diff --git a/drivers/mfd/rohm-bd70528.c b/drivers/mfd/rohm-bd70528.c deleted file mode 100644 index 5c44d3b77b3e1..0000000000000 --- a/drivers/mfd/rohm-bd70528.c +++ /dev/null @@ -1,314 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// -// Copyright (C) 2019 ROHM Semiconductors -// -// ROHM BD70528 PMIC driver - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define BD70528_NUM_OF_GPIOS 4 - -static const struct resource rtc_irqs[] = { - DEFINE_RES_IRQ_NAMED(BD70528_INT_RTC_ALARM, "bd70528-rtc-alm"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_ELPS_TIM, "bd70528-elapsed-timer"), -}; - -static const struct resource charger_irqs[] = { - DEFINE_RES_IRQ_NAMED(BD70528_INT_BAT_OV_RES, "bd70528-bat-ov-res"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_BAT_OV_DET, "bd70528-bat-ov-det"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_DBAT_DET, "bd70528-bat-dead"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_BATTSD_COLD_RES, "bd70528-bat-warmed"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_BATTSD_COLD_DET, "bd70528-bat-cold"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_BATTSD_HOT_RES, "bd70528-bat-cooled"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_BATTSD_HOT_DET, "bd70528-bat-hot"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_CHG_TSD, "bd70528-chg-tshd"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_BAT_RMV, "bd70528-bat-removed"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_BAT_DET, "bd70528-bat-detected"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_DCIN2_OV_RES, "bd70528-dcin2-ov-res"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_DCIN2_OV_DET, "bd70528-dcin2-ov-det"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_DCIN2_RMV, "bd70528-dcin2-removed"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_DCIN2_DET, "bd70528-dcin2-detected"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_DCIN1_RMV, "bd70528-dcin1-removed"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_DCIN1_DET, "bd70528-dcin1-detected"), -}; - -static struct mfd_cell bd70528_mfd_cells[] = { - { .name = "bd70528-pmic", }, - { .name = "bd70528-gpio", }, - /* - * We use BD71837 driver to drive the clock block. Only differences to - * BD70528 clock gate are the register address and mask. - */ - { .name = "bd70528-clk", }, - { .name = "bd70528-wdt", }, - { - .name = "bd70528-power", - .resources = charger_irqs, - .num_resources = ARRAY_SIZE(charger_irqs), - }, { - .name = "bd70528-rtc", - .resources = rtc_irqs, - .num_resources = ARRAY_SIZE(rtc_irqs), - }, -}; - -static const struct regmap_range volatile_ranges[] = { - { - .range_min = BD70528_REG_INT_MAIN, - .range_max = BD70528_REG_INT_OP_FAIL, - }, { - .range_min = BD70528_REG_RTC_COUNT_H, - .range_max = BD70528_REG_RTC_ALM_REPEAT, - }, { - /* - * WDT control reg is special. Magic values must be written to - * it in order to change the control. Should not be cached. - */ - .range_min = BD70528_REG_WDT_CTRL, - .range_max = BD70528_REG_WDT_CTRL, - }, { - /* - * BD70528 also contains a few other registers which require - * magic sequences to be written in order to update the value. - * At least SHIPMODE, HWRESET, WARMRESET,and STANDBY - */ - .range_min = BD70528_REG_SHIPMODE, - .range_max = BD70528_REG_STANDBY, - }, -}; - -static const struct regmap_access_table volatile_regs = { - .yes_ranges = &volatile_ranges[0], - .n_yes_ranges = ARRAY_SIZE(volatile_ranges), -}; - -static struct regmap_config bd70528_regmap = { - .reg_bits = 8, - .val_bits = 8, - .volatile_table = &volatile_regs, - .max_register = BD70528_MAX_REGISTER, - .cache_type = REGCACHE_RBTREE, -}; - -/* - * Mapping of main IRQ register bits to sub-IRQ register offsets so that we can - * access corect sub-IRQ registers based on bits that are set in main IRQ - * register. - */ - -static unsigned int bit0_offsets[] = {0}; /* Shutdown */ -static unsigned int bit1_offsets[] = {1}; /* Power failure */ -static unsigned int bit2_offsets[] = {2}; /* VR FAULT */ -static unsigned int bit3_offsets[] = {3}; /* PMU interrupts */ -static unsigned int bit4_offsets[] = {4, 5}; /* Charger 1 and Charger 2 */ -static unsigned int bit5_offsets[] = {6}; /* RTC */ -static unsigned int bit6_offsets[] = {7}; /* GPIO */ -static unsigned int bit7_offsets[] = {8}; /* Invalid operation */ - -static struct regmap_irq_sub_irq_map bd70528_sub_irq_offsets[] = { - REGMAP_IRQ_MAIN_REG_OFFSET(bit0_offsets), - REGMAP_IRQ_MAIN_REG_OFFSET(bit1_offsets), - REGMAP_IRQ_MAIN_REG_OFFSET(bit2_offsets), - REGMAP_IRQ_MAIN_REG_OFFSET(bit3_offsets), - REGMAP_IRQ_MAIN_REG_OFFSET(bit4_offsets), - REGMAP_IRQ_MAIN_REG_OFFSET(bit5_offsets), - REGMAP_IRQ_MAIN_REG_OFFSET(bit6_offsets), - REGMAP_IRQ_MAIN_REG_OFFSET(bit7_offsets), -}; - -static struct regmap_irq bd70528_irqs[] = { - REGMAP_IRQ_REG(BD70528_INT_LONGPUSH, 0, BD70528_INT_LONGPUSH_MASK), - REGMAP_IRQ_REG(BD70528_INT_WDT, 0, BD70528_INT_WDT_MASK), - REGMAP_IRQ_REG(BD70528_INT_HWRESET, 0, BD70528_INT_HWRESET_MASK), - REGMAP_IRQ_REG(BD70528_INT_RSTB_FAULT, 0, BD70528_INT_RSTB_FAULT_MASK), - REGMAP_IRQ_REG(BD70528_INT_VBAT_UVLO, 0, BD70528_INT_VBAT_UVLO_MASK), - REGMAP_IRQ_REG(BD70528_INT_TSD, 0, BD70528_INT_TSD_MASK), - REGMAP_IRQ_REG(BD70528_INT_RSTIN, 0, BD70528_INT_RSTIN_MASK), - REGMAP_IRQ_REG(BD70528_INT_BUCK1_FAULT, 1, - BD70528_INT_BUCK1_FAULT_MASK), - REGMAP_IRQ_REG(BD70528_INT_BUCK2_FAULT, 1, - BD70528_INT_BUCK2_FAULT_MASK), - REGMAP_IRQ_REG(BD70528_INT_BUCK3_FAULT, 1, - BD70528_INT_BUCK3_FAULT_MASK), - REGMAP_IRQ_REG(BD70528_INT_LDO1_FAULT, 1, BD70528_INT_LDO1_FAULT_MASK), - REGMAP_IRQ_REG(BD70528_INT_LDO2_FAULT, 1, BD70528_INT_LDO2_FAULT_MASK), - REGMAP_IRQ_REG(BD70528_INT_LDO3_FAULT, 1, BD70528_INT_LDO3_FAULT_MASK), - REGMAP_IRQ_REG(BD70528_INT_LED1_FAULT, 1, BD70528_INT_LED1_FAULT_MASK), - REGMAP_IRQ_REG(BD70528_INT_LED2_FAULT, 1, BD70528_INT_LED2_FAULT_MASK), - REGMAP_IRQ_REG(BD70528_INT_BUCK1_OCP, 2, BD70528_INT_BUCK1_OCP_MASK), - REGMAP_IRQ_REG(BD70528_INT_BUCK2_OCP, 2, BD70528_INT_BUCK2_OCP_MASK), - REGMAP_IRQ_REG(BD70528_INT_BUCK3_OCP, 2, BD70528_INT_BUCK3_OCP_MASK), - REGMAP_IRQ_REG(BD70528_INT_LED1_OCP, 2, BD70528_INT_LED1_OCP_MASK), - REGMAP_IRQ_REG(BD70528_INT_LED2_OCP, 2, BD70528_INT_LED2_OCP_MASK), - REGMAP_IRQ_REG(BD70528_INT_BUCK1_FULLON, 2, - BD70528_INT_BUCK1_FULLON_MASK), - REGMAP_IRQ_REG(BD70528_INT_BUCK2_FULLON, 2, - BD70528_INT_BUCK2_FULLON_MASK), - REGMAP_IRQ_REG(BD70528_INT_SHORTPUSH, 3, BD70528_INT_SHORTPUSH_MASK), - REGMAP_IRQ_REG(BD70528_INT_AUTO_WAKEUP, 3, - BD70528_INT_AUTO_WAKEUP_MASK), - REGMAP_IRQ_REG(BD70528_INT_STATE_CHANGE, 3, - BD70528_INT_STATE_CHANGE_MASK), - REGMAP_IRQ_REG(BD70528_INT_BAT_OV_RES, 4, BD70528_INT_BAT_OV_RES_MASK), - REGMAP_IRQ_REG(BD70528_INT_BAT_OV_DET, 4, BD70528_INT_BAT_OV_DET_MASK), - REGMAP_IRQ_REG(BD70528_INT_DBAT_DET, 4, BD70528_INT_DBAT_DET_MASK), - REGMAP_IRQ_REG(BD70528_INT_BATTSD_COLD_RES, 4, - BD70528_INT_BATTSD_COLD_RES_MASK), - REGMAP_IRQ_REG(BD70528_INT_BATTSD_COLD_DET, 4, - BD70528_INT_BATTSD_COLD_DET_MASK), - REGMAP_IRQ_REG(BD70528_INT_BATTSD_HOT_RES, 4, - BD70528_INT_BATTSD_HOT_RES_MASK), - REGMAP_IRQ_REG(BD70528_INT_BATTSD_HOT_DET, 4, - BD70528_INT_BATTSD_HOT_DET_MASK), - REGMAP_IRQ_REG(BD70528_INT_CHG_TSD, 4, BD70528_INT_CHG_TSD_MASK), - REGMAP_IRQ_REG(BD70528_INT_BAT_RMV, 5, BD70528_INT_BAT_RMV_MASK), - REGMAP_IRQ_REG(BD70528_INT_BAT_DET, 5, BD70528_INT_BAT_DET_MASK), - REGMAP_IRQ_REG(BD70528_INT_DCIN2_OV_RES, 5, - BD70528_INT_DCIN2_OV_RES_MASK), - REGMAP_IRQ_REG(BD70528_INT_DCIN2_OV_DET, 5, - BD70528_INT_DCIN2_OV_DET_MASK), - REGMAP_IRQ_REG(BD70528_INT_DCIN2_RMV, 5, BD70528_INT_DCIN2_RMV_MASK), - REGMAP_IRQ_REG(BD70528_INT_DCIN2_DET, 5, BD70528_INT_DCIN2_DET_MASK), - REGMAP_IRQ_REG(BD70528_INT_DCIN1_RMV, 5, BD70528_INT_DCIN1_RMV_MASK), - REGMAP_IRQ_REG(BD70528_INT_DCIN1_DET, 5, BD70528_INT_DCIN1_DET_MASK), - REGMAP_IRQ_REG(BD70528_INT_RTC_ALARM, 6, BD70528_INT_RTC_ALARM_MASK), - REGMAP_IRQ_REG(BD70528_INT_ELPS_TIM, 6, BD70528_INT_ELPS_TIM_MASK), - REGMAP_IRQ_REG(BD70528_INT_GPIO0, 7, BD70528_INT_GPIO0_MASK), - REGMAP_IRQ_REG(BD70528_INT_GPIO1, 7, BD70528_INT_GPIO1_MASK), - REGMAP_IRQ_REG(BD70528_INT_GPIO2, 7, BD70528_INT_GPIO2_MASK), - REGMAP_IRQ_REG(BD70528_INT_GPIO3, 7, BD70528_INT_GPIO3_MASK), - REGMAP_IRQ_REG(BD70528_INT_BUCK1_DVS_OPFAIL, 8, - BD70528_INT_BUCK1_DVS_OPFAIL_MASK), - REGMAP_IRQ_REG(BD70528_INT_BUCK2_DVS_OPFAIL, 8, - BD70528_INT_BUCK2_DVS_OPFAIL_MASK), - REGMAP_IRQ_REG(BD70528_INT_BUCK3_DVS_OPFAIL, 8, - BD70528_INT_BUCK3_DVS_OPFAIL_MASK), - REGMAP_IRQ_REG(BD70528_INT_LED1_VOLT_OPFAIL, 8, - BD70528_INT_LED1_VOLT_OPFAIL_MASK), - REGMAP_IRQ_REG(BD70528_INT_LED2_VOLT_OPFAIL, 8, - BD70528_INT_LED2_VOLT_OPFAIL_MASK), -}; - -static struct regmap_irq_chip bd70528_irq_chip = { - .name = "bd70528_irq", - .main_status = BD70528_REG_INT_MAIN, - .irqs = &bd70528_irqs[0], - .num_irqs = ARRAY_SIZE(bd70528_irqs), - .status_base = BD70528_REG_INT_SHDN, - .mask_base = BD70528_REG_INT_SHDN_MASK, - .ack_base = BD70528_REG_INT_SHDN, - .type_base = BD70528_REG_GPIO1_IN, - .init_ack_masked = true, - .num_regs = 9, - .num_main_regs = 1, - .num_type_reg = 4, - .sub_reg_offsets = &bd70528_sub_irq_offsets[0], - .num_main_status_bits = 8, - .irq_reg_stride = 1, -}; - -static int bd70528_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - struct bd70528_data *bd70528; - struct regmap_irq_chip_data *irq_data; - int ret, i; - - if (!i2c->irq) { - dev_err(&i2c->dev, "No IRQ configured\n"); - return -EINVAL; - } - - bd70528 = devm_kzalloc(&i2c->dev, sizeof(*bd70528), GFP_KERNEL); - if (!bd70528) - return -ENOMEM; - - mutex_init(&bd70528->rtc_timer_lock); - - dev_set_drvdata(&i2c->dev, &bd70528->chip); - - bd70528->chip.regmap = devm_regmap_init_i2c(i2c, &bd70528_regmap); - if (IS_ERR(bd70528->chip.regmap)) { - dev_err(&i2c->dev, "Failed to initialize Regmap\n"); - return PTR_ERR(bd70528->chip.regmap); - } - - /* - * Disallow type setting for all IRQs by default as most of them do not - * support setting type. - */ - for (i = 0; i < ARRAY_SIZE(bd70528_irqs); i++) - bd70528_irqs[i].type.types_supported = 0; - - /* Set IRQ typesetting information for GPIO pins 0 - 3 */ - for (i = 0; i < BD70528_NUM_OF_GPIOS; i++) { - struct regmap_irq_type *type; - - type = &bd70528_irqs[BD70528_INT_GPIO0 + i].type; - type->type_reg_offset = 2 * i; - type->type_rising_val = 0x20; - type->type_falling_val = 0x10; - type->type_level_high_val = 0x40; - type->type_level_low_val = 0x50; - type->types_supported = (IRQ_TYPE_EDGE_BOTH | - IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW); - } - - ret = devm_regmap_add_irq_chip(&i2c->dev, bd70528->chip.regmap, - i2c->irq, IRQF_ONESHOT, 0, - &bd70528_irq_chip, &irq_data); - if (ret) { - dev_err(&i2c->dev, "Failed to add IRQ chip\n"); - return ret; - } - dev_dbg(&i2c->dev, "Registered %d IRQs for chip\n", - bd70528_irq_chip.num_irqs); - - /* - * BD70528 IRQ controller is not touching the main mask register. - * So enable the GPIO block interrupts at main level. We can just leave - * them enabled as the IRQ controller should disable IRQs from - * sub-registers when IRQ is disabled or freed. - */ - ret = regmap_update_bits(bd70528->chip.regmap, - BD70528_REG_INT_MAIN_MASK, - BD70528_INT_GPIO_MASK, 0); - - ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, - bd70528_mfd_cells, - ARRAY_SIZE(bd70528_mfd_cells), NULL, 0, - regmap_irq_get_domain(irq_data)); - if (ret) - dev_err(&i2c->dev, "Failed to create subdevices\n"); - - return ret; -} - -static const struct of_device_id bd70528_of_match[] = { - { .compatible = "rohm,bd70528", }, - { }, -}; -MODULE_DEVICE_TABLE(of, bd70528_of_match); - -static struct i2c_driver bd70528_drv = { - .driver = { - .name = "rohm-bd70528", - .of_match_table = bd70528_of_match, - }, - .probe = &bd70528_i2c_probe, -}; - -module_i2c_driver(bd70528_drv); - -MODULE_AUTHOR("Matti Vaittinen "); -MODULE_DESCRIPTION("ROHM BD70528 Power Management IC driver"); -MODULE_LICENSE("GPL"); diff --git a/include/linux/mfd/rohm-bd70528.h b/include/linux/mfd/rohm-bd70528.h deleted file mode 100644 index 4a5966475a35a..0000000000000 --- a/include/linux/mfd/rohm-bd70528.h +++ /dev/null @@ -1,389 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* Copyright (C) 2018 ROHM Semiconductors */ - -#ifndef __LINUX_MFD_BD70528_H__ -#define __LINUX_MFD_BD70528_H__ - -#include -#include -#include -#include -#include - -enum { - BD70528_BUCK1, - BD70528_BUCK2, - BD70528_BUCK3, - BD70528_LDO1, - BD70528_LDO2, - BD70528_LDO3, - BD70528_LED1, - BD70528_LED2, -}; - -struct bd70528_data { - struct rohm_regmap_dev chip; - struct mutex rtc_timer_lock; -}; - -#define BD70528_BUCK_VOLTS 0x10 -#define BD70528_LDO_VOLTS 0x20 - -#define BD70528_REG_BUCK1_EN 0x0F -#define BD70528_REG_BUCK1_VOLT 0x15 -#define BD70528_REG_BUCK2_EN 0x10 -#define BD70528_REG_BUCK2_VOLT 0x16 -#define BD70528_REG_BUCK3_EN 0x11 -#define BD70528_REG_BUCK3_VOLT 0x17 -#define BD70528_REG_LDO1_EN 0x1b -#define BD70528_REG_LDO1_VOLT 0x1e -#define BD70528_REG_LDO2_EN 0x1c -#define BD70528_REG_LDO2_VOLT 0x1f -#define BD70528_REG_LDO3_EN 0x1d -#define BD70528_REG_LDO3_VOLT 0x20 -#define BD70528_REG_LED_CTRL 0x2b -#define BD70528_REG_LED_VOLT 0x29 -#define BD70528_REG_LED_EN 0x2a - -/* main irq registers */ -#define BD70528_REG_INT_MAIN 0x7E -#define BD70528_REG_INT_MAIN_MASK 0x74 - -/* 'sub irq' registers */ -#define BD70528_REG_INT_SHDN 0x7F -#define BD70528_REG_INT_PWR_FLT 0x80 -#define BD70528_REG_INT_VR_FLT 0x81 -#define BD70528_REG_INT_MISC 0x82 -#define BD70528_REG_INT_BAT1 0x83 -#define BD70528_REG_INT_BAT2 0x84 -#define BD70528_REG_INT_RTC 0x85 -#define BD70528_REG_INT_GPIO 0x86 -#define BD70528_REG_INT_OP_FAIL 0x87 - -#define BD70528_REG_INT_SHDN_MASK 0x75 -#define BD70528_REG_INT_PWR_FLT_MASK 0x76 -#define BD70528_REG_INT_VR_FLT_MASK 0x77 -#define BD70528_REG_INT_MISC_MASK 0x78 -#define BD70528_REG_INT_BAT1_MASK 0x79 -#define BD70528_REG_INT_BAT2_MASK 0x7a -#define BD70528_REG_INT_RTC_MASK 0x7b -#define BD70528_REG_INT_GPIO_MASK 0x7c -#define BD70528_REG_INT_OP_FAIL_MASK 0x7d - -/* Reset related 'magic' registers */ -#define BD70528_REG_SHIPMODE 0x03 -#define BD70528_REG_HWRESET 0x04 -#define BD70528_REG_WARMRESET 0x05 -#define BD70528_REG_STANDBY 0x06 - -/* GPIO registers */ -#define BD70528_REG_GPIO_STATE 0x8F - -#define BD70528_REG_GPIO1_IN 0x4d -#define BD70528_REG_GPIO2_IN 0x4f -#define BD70528_REG_GPIO3_IN 0x51 -#define BD70528_REG_GPIO4_IN 0x53 -#define BD70528_REG_GPIO1_OUT 0x4e -#define BD70528_REG_GPIO2_OUT 0x50 -#define BD70528_REG_GPIO3_OUT 0x52 -#define BD70528_REG_GPIO4_OUT 0x54 - -/* RTC */ - -#define BD70528_REG_RTC_COUNT_H 0x2d -#define BD70528_REG_RTC_COUNT_L 0x2e -#define BD70528_REG_RTC_SEC 0x2f -#define BD70528_REG_RTC_MINUTE 0x30 -#define BD70528_REG_RTC_HOUR 0x31 -#define BD70528_REG_RTC_WEEK 0x32 -#define BD70528_REG_RTC_DAY 0x33 -#define BD70528_REG_RTC_MONTH 0x34 -#define BD70528_REG_RTC_YEAR 0x35 - -#define BD70528_REG_RTC_ALM_SEC 0x36 -#define BD70528_REG_RTC_ALM_START BD70528_REG_RTC_ALM_SEC -#define BD70528_REG_RTC_ALM_MINUTE 0x37 -#define BD70528_REG_RTC_ALM_HOUR 0x38 -#define BD70528_REG_RTC_ALM_WEEK 0x39 -#define BD70528_REG_RTC_ALM_DAY 0x3a -#define BD70528_REG_RTC_ALM_MONTH 0x3b -#define BD70528_REG_RTC_ALM_YEAR 0x3c -#define BD70528_REG_RTC_ALM_MASK 0x3d -#define BD70528_REG_RTC_ALM_REPEAT 0x3e -#define BD70528_REG_RTC_START BD70528_REG_RTC_SEC - -#define BD70528_REG_RTC_WAKE_SEC 0x43 -#define BD70528_REG_RTC_WAKE_START BD70528_REG_RTC_WAKE_SEC -#define BD70528_REG_RTC_WAKE_MIN 0x44 -#define BD70528_REG_RTC_WAKE_HOUR 0x45 -#define BD70528_REG_RTC_WAKE_CTRL 0x46 - -#define BD70528_REG_ELAPSED_TIMER_EN 0x42 -#define BD70528_REG_WAKE_EN 0x46 - -/* WDT registers */ -#define BD70528_REG_WDT_CTRL 0x4A -#define BD70528_REG_WDT_HOUR 0x49 -#define BD70528_REG_WDT_MINUTE 0x48 -#define BD70528_REG_WDT_SEC 0x47 - -/* Charger / Battery */ -#define BD70528_REG_CHG_CURR_STAT 0x59 -#define BD70528_REG_CHG_BAT_STAT 0x57 -#define BD70528_REG_CHG_BAT_TEMP 0x58 -#define BD70528_REG_CHG_IN_STAT 0x56 -#define BD70528_REG_CHG_DCIN_ILIM 0x5d -#define BD70528_REG_CHG_CHG_CURR_WARM 0x61 -#define BD70528_REG_CHG_CHG_CURR_COLD 0x62 - -/* Masks for main IRQ register bits */ -enum { - BD70528_INT_SHDN, -#define BD70528_INT_SHDN_MASK BIT(BD70528_INT_SHDN) - BD70528_INT_PWR_FLT, -#define BD70528_INT_PWR_FLT_MASK BIT(BD70528_INT_PWR_FLT) - BD70528_INT_VR_FLT, -#define BD70528_INT_VR_FLT_MASK BIT(BD70528_INT_VR_FLT) - BD70528_INT_MISC, -#define BD70528_INT_MISC_MASK BIT(BD70528_INT_MISC) - BD70528_INT_BAT1, -#define BD70528_INT_BAT1_MASK BIT(BD70528_INT_BAT1) - BD70528_INT_RTC, -#define BD70528_INT_RTC_MASK BIT(BD70528_INT_RTC) - BD70528_INT_GPIO, -#define BD70528_INT_GPIO_MASK BIT(BD70528_INT_GPIO) - BD70528_INT_OP_FAIL, -#define BD70528_INT_OP_FAIL_MASK BIT(BD70528_INT_OP_FAIL) -}; - -/* IRQs */ -enum { - /* Shutdown register IRQs */ - BD70528_INT_LONGPUSH, - BD70528_INT_WDT, - BD70528_INT_HWRESET, - BD70528_INT_RSTB_FAULT, - BD70528_INT_VBAT_UVLO, - BD70528_INT_TSD, - BD70528_INT_RSTIN, - /* Power failure register IRQs */ - BD70528_INT_BUCK1_FAULT, - BD70528_INT_BUCK2_FAULT, - BD70528_INT_BUCK3_FAULT, - BD70528_INT_LDO1_FAULT, - BD70528_INT_LDO2_FAULT, - BD70528_INT_LDO3_FAULT, - BD70528_INT_LED1_FAULT, - BD70528_INT_LED2_FAULT, - /* VR FAULT register IRQs */ - BD70528_INT_BUCK1_OCP, - BD70528_INT_BUCK2_OCP, - BD70528_INT_BUCK3_OCP, - BD70528_INT_LED1_OCP, - BD70528_INT_LED2_OCP, - BD70528_INT_BUCK1_FULLON, - BD70528_INT_BUCK2_FULLON, - /* PMU register interrupts */ - BD70528_INT_SHORTPUSH, - BD70528_INT_AUTO_WAKEUP, - BD70528_INT_STATE_CHANGE, - /* Charger 1 register IRQs */ - BD70528_INT_BAT_OV_RES, - BD70528_INT_BAT_OV_DET, - BD70528_INT_DBAT_DET, - BD70528_INT_BATTSD_COLD_RES, - BD70528_INT_BATTSD_COLD_DET, - BD70528_INT_BATTSD_HOT_RES, - BD70528_INT_BATTSD_HOT_DET, - BD70528_INT_CHG_TSD, - /* Charger 2 register IRQs */ - BD70528_INT_BAT_RMV, - BD70528_INT_BAT_DET, - BD70528_INT_DCIN2_OV_RES, - BD70528_INT_DCIN2_OV_DET, - BD70528_INT_DCIN2_RMV, - BD70528_INT_DCIN2_DET, - BD70528_INT_DCIN1_RMV, - BD70528_INT_DCIN1_DET, - /* RTC register IRQs */ - BD70528_INT_RTC_ALARM, - BD70528_INT_ELPS_TIM, - /* GPIO register IRQs */ - BD70528_INT_GPIO0, - BD70528_INT_GPIO1, - BD70528_INT_GPIO2, - BD70528_INT_GPIO3, - /* Invalid operation register IRQs */ - BD70528_INT_BUCK1_DVS_OPFAIL, - BD70528_INT_BUCK2_DVS_OPFAIL, - BD70528_INT_BUCK3_DVS_OPFAIL, - BD70528_INT_LED1_VOLT_OPFAIL, - BD70528_INT_LED2_VOLT_OPFAIL, -}; - -/* Masks */ -#define BD70528_INT_LONGPUSH_MASK 0x1 -#define BD70528_INT_WDT_MASK 0x2 -#define BD70528_INT_HWRESET_MASK 0x4 -#define BD70528_INT_RSTB_FAULT_MASK 0x8 -#define BD70528_INT_VBAT_UVLO_MASK 0x10 -#define BD70528_INT_TSD_MASK 0x20 -#define BD70528_INT_RSTIN_MASK 0x40 - -#define BD70528_INT_BUCK1_FAULT_MASK 0x1 -#define BD70528_INT_BUCK2_FAULT_MASK 0x2 -#define BD70528_INT_BUCK3_FAULT_MASK 0x4 -#define BD70528_INT_LDO1_FAULT_MASK 0x8 -#define BD70528_INT_LDO2_FAULT_MASK 0x10 -#define BD70528_INT_LDO3_FAULT_MASK 0x20 -#define BD70528_INT_LED1_FAULT_MASK 0x40 -#define BD70528_INT_LED2_FAULT_MASK 0x80 - -#define BD70528_INT_BUCK1_OCP_MASK 0x1 -#define BD70528_INT_BUCK2_OCP_MASK 0x2 -#define BD70528_INT_BUCK3_OCP_MASK 0x4 -#define BD70528_INT_LED1_OCP_MASK 0x8 -#define BD70528_INT_LED2_OCP_MASK 0x10 -#define BD70528_INT_BUCK1_FULLON_MASK 0x20 -#define BD70528_INT_BUCK2_FULLON_MASK 0x40 - -#define BD70528_INT_SHORTPUSH_MASK 0x1 -#define BD70528_INT_AUTO_WAKEUP_MASK 0x2 -#define BD70528_INT_STATE_CHANGE_MASK 0x10 - -#define BD70528_INT_BAT_OV_RES_MASK 0x1 -#define BD70528_INT_BAT_OV_DET_MASK 0x2 -#define BD70528_INT_DBAT_DET_MASK 0x4 -#define BD70528_INT_BATTSD_COLD_RES_MASK 0x8 -#define BD70528_INT_BATTSD_COLD_DET_MASK 0x10 -#define BD70528_INT_BATTSD_HOT_RES_MASK 0x20 -#define BD70528_INT_BATTSD_HOT_DET_MASK 0x40 -#define BD70528_INT_CHG_TSD_MASK 0x80 - -#define BD70528_INT_BAT_RMV_MASK 0x1 -#define BD70528_INT_BAT_DET_MASK 0x2 -#define BD70528_INT_DCIN2_OV_RES_MASK 0x4 -#define BD70528_INT_DCIN2_OV_DET_MASK 0x8 -#define BD70528_INT_DCIN2_RMV_MASK 0x10 -#define BD70528_INT_DCIN2_DET_MASK 0x20 -#define BD70528_INT_DCIN1_RMV_MASK 0x40 -#define BD70528_INT_DCIN1_DET_MASK 0x80 - -#define BD70528_INT_RTC_ALARM_MASK 0x1 -#define BD70528_INT_ELPS_TIM_MASK 0x2 - -#define BD70528_INT_GPIO0_MASK 0x1 -#define BD70528_INT_GPIO1_MASK 0x2 -#define BD70528_INT_GPIO2_MASK 0x4 -#define BD70528_INT_GPIO3_MASK 0x8 - -#define BD70528_INT_BUCK1_DVS_OPFAIL_MASK 0x1 -#define BD70528_INT_BUCK2_DVS_OPFAIL_MASK 0x2 -#define BD70528_INT_BUCK3_DVS_OPFAIL_MASK 0x4 -#define BD70528_INT_LED1_VOLT_OPFAIL_MASK 0x10 -#define BD70528_INT_LED2_VOLT_OPFAIL_MASK 0x20 - -#define BD70528_DEBOUNCE_MASK 0x3 - -#define BD70528_DEBOUNCE_DISABLE 0 -#define BD70528_DEBOUNCE_15MS 1 -#define BD70528_DEBOUNCE_30MS 2 -#define BD70528_DEBOUNCE_50MS 3 - -#define BD70528_GPIO_DRIVE_MASK 0x2 -#define BD70528_GPIO_PUSH_PULL 0x0 -#define BD70528_GPIO_OPEN_DRAIN 0x2 - -#define BD70528_GPIO_OUT_EN_MASK 0x80 -#define BD70528_GPIO_OUT_ENABLE 0x80 -#define BD70528_GPIO_OUT_DISABLE 0x0 - -#define BD70528_GPIO_OUT_HI 0x1 -#define BD70528_GPIO_OUT_LO 0x0 -#define BD70528_GPIO_OUT_MASK 0x1 - -#define BD70528_GPIO_IN_STATE_BASE 1 - -/* RTC masks to mask out reserved bits */ - -#define BD70528_MASK_ELAPSED_TIMER_EN 0x1 -/* Mask second, min and hour fields - * HW would support ALM irq for over 24h - * (by setting day, month and year too) - * but as we wish to keep this same as for - * wake-up we limit ALM to 24H and only - * unmask sec, min and hour - */ -#define BD70528_MASK_WAKE_EN 0x1 - -/* WDT masks */ -#define BD70528_MASK_WDT_EN 0x1 -#define BD70528_MASK_WDT_HOUR 0x1 -#define BD70528_MASK_WDT_MINUTE 0x7f -#define BD70528_MASK_WDT_SEC 0x7f - -#define BD70528_WDT_STATE_BIT 0x1 -#define BD70528_ELAPSED_STATE_BIT 0x2 -#define BD70528_WAKE_STATE_BIT 0x4 - -/* Charger masks */ -#define BD70528_MASK_CHG_STAT 0x7f -#define BD70528_MASK_CHG_BAT_TIMER 0x20 -#define BD70528_MASK_CHG_BAT_OVERVOLT 0x10 -#define BD70528_MASK_CHG_BAT_DETECT 0x1 -#define BD70528_MASK_CHG_DCIN1_UVLO 0x1 -#define BD70528_MASK_CHG_DCIN_ILIM 0x3f -#define BD70528_MASK_CHG_CHG_CURR 0x1f -#define BD70528_MASK_CHG_TRICKLE_CURR 0x10 - -/* - * Note, external battery register is the lonely rider at - * address 0xc5. See how to stuff that in the regmap - */ -#define BD70528_MAX_REGISTER 0x94 - -/* Buck control masks */ -#define BD70528_MASK_RUN_EN 0x4 -#define BD70528_MASK_STBY_EN 0x2 -#define BD70528_MASK_IDLE_EN 0x1 -#define BD70528_MASK_LED1_EN 0x1 -#define BD70528_MASK_LED2_EN 0x10 - -#define BD70528_MASK_BUCK_VOLT 0xf -#define BD70528_MASK_LDO_VOLT 0x1f -#define BD70528_MASK_LED1_VOLT 0x1 -#define BD70528_MASK_LED2_VOLT 0x10 - -/* Misc irq masks */ -#define BD70528_INT_MASK_SHORT_PUSH 1 -#define BD70528_INT_MASK_AUTO_WAKE 2 -#define BD70528_INT_MASK_POWER_STATE 4 - -#define BD70528_MASK_BUCK_RAMP 0x10 -#define BD70528_SIFT_BUCK_RAMP 4 - -#if IS_ENABLED(CONFIG_BD70528_WATCHDOG) - -int bd70528_wdt_set(struct rohm_regmap_dev *data, int enable, int *old_state); -void bd70528_wdt_lock(struct rohm_regmap_dev *data); -void bd70528_wdt_unlock(struct rohm_regmap_dev *data); - -#else /* CONFIG_BD70528_WATCHDOG */ - -static inline int bd70528_wdt_set(struct rohm_regmap_dev *data, int enable, - int *old_state) -{ - return 0; -} - -static inline void bd70528_wdt_lock(struct rohm_regmap_dev *data) -{ -} - -static inline void bd70528_wdt_unlock(struct rohm_regmap_dev *data) -{ -} - -#endif /* CONFIG_BD70528_WATCHDOG */ - -#endif /* __LINUX_MFD_BD70528_H__ */ diff --git a/include/linux/mfd/rohm-generic.h b/include/linux/mfd/rohm-generic.h index 35b392a0d73a1..8fb763a2265a0 100644 --- a/include/linux/mfd/rohm-generic.h +++ b/include/linux/mfd/rohm-generic.h @@ -12,7 +12,6 @@ enum rohm_chip_type { ROHM_CHIP_TYPE_BD9573, ROHM_CHIP_TYPE_BD9574, ROHM_CHIP_TYPE_BD9576, - ROHM_CHIP_TYPE_BD70528, ROHM_CHIP_TYPE_BD71815, ROHM_CHIP_TYPE_BD71828, ROHM_CHIP_TYPE_BD71837, -- GitLab From 2f746ea6e6a9036b2f33d80d776ac2464f4cea18 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Tue, 16 Nov 2021 14:55:05 +0200 Subject: [PATCH 0220/1112] MAINTAINERS: bd70528: Drop ROHM BD70528 drivers The only known BD70528 use-cases are such that the PMIC is controlled from separate MCU which is not running Linux. I am not aware of any Linux driver users. Furthermore, it seems there is no demand for this IC. Ease the maintenance burden and drop the driver. Signed-off-by: Matti Vaittinen Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/90b0565c0eb9429b0962f08d45292a5a9ebe5cea.1637066805.git.matti.vaittinen@fi.rohmeurope.com --- MAINTAINERS | 8 -------- 1 file changed, 8 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 7a2345ce85213..c3ebc417ba41c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16445,27 +16445,19 @@ ROHM POWER MANAGEMENT IC DEVICE DRIVERS R: Matti Vaittinen L: linux-power@fi.rohmeurope.com S: Supported -F: Documentation/devicetree/bindings/mfd/rohm,bd70528-pmic.txt -F: Documentation/devicetree/bindings/regulator/rohm,bd70528-regulator.txt F: drivers/clk/clk-bd718x7.c -F: drivers/gpio/gpio-bd70528.c F: drivers/gpio/gpio-bd71815.c F: drivers/gpio/gpio-bd71828.c -F: drivers/mfd/rohm-bd70528.c F: drivers/mfd/rohm-bd71828.c F: drivers/mfd/rohm-bd718x7.c F: drivers/mfd/rohm-bd9576.c -F: drivers/power/supply/bd70528-charger.c -F: drivers/regulator/bd70528-regulator.c F: drivers/regulator/bd71815-regulator.c F: drivers/regulator/bd71828-regulator.c F: drivers/regulator/bd718x7-regulator.c F: drivers/regulator/bd9576-regulator.c F: drivers/regulator/rohm-regulator.c F: drivers/rtc/rtc-bd70528.c -F: drivers/watchdog/bd70528_wdt.c F: drivers/watchdog/bd9576_wdt.c -F: include/linux/mfd/rohm-bd70528.h F: include/linux/mfd/rohm-bd71815.h F: include/linux/mfd/rohm-bd71828.h F: include/linux/mfd/rohm-bd718x7.h -- GitLab From ac88e9526d68f2532be3b4b439d45c0c8de7e170 Mon Sep 17 00:00:00 2001 From: Satya Priya Date: Tue, 23 Nov 2021 17:19:25 +0530 Subject: [PATCH 0221/1112] dt-bindings: regulator: Add compatible for pmg1110 Add compatible string for pmg1110 pmic. Signed-off-by: Satya Priya Link: https://lore.kernel.org/r/1637668167-31325-2-git-send-email-quic_c_skakit@quicinc.com Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/qcom,rpmh-regulator.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml index b959504e0ea43..c02f08a7014cc 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml @@ -63,6 +63,7 @@ properties: - qcom,pm8350-rpmh-regulators - qcom,pm8350c-rpmh-regulators - qcom,pm8998-rpmh-regulators + - qcom,pmg1110-rpmh-regulators - qcom,pmi8998-rpmh-regulators - qcom,pmm8155au-rpmh-regulators - qcom,pmr735a-rpmh-regulators -- GitLab From 59eadd2af3f717f2ff70dbb6c153757dc1650651 Mon Sep 17 00:00:00 2001 From: Satya Priya Date: Tue, 23 Nov 2021 17:19:26 +0530 Subject: [PATCH 0222/1112] regulator: qcom-rpmh: Add PMG1110 regulators Add support for PMG1110 regulators. Signed-off-by: Satya Priya Link: https://lore.kernel.org/r/1637668167-31325-3-git-send-email-quic_c_skakit@quicinc.com Signed-off-by: Mark Brown --- drivers/regulator/qcom-rpmh-regulator.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index 12425f667c002..684143c828a56 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -814,6 +814,11 @@ static const struct rpmh_vreg_init_data pm8998_vreg_data[] = { {} }; +static const struct rpmh_vreg_init_data pmg1110_vreg_data[] = { + RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"), + {} +}; + static const struct rpmh_vreg_init_data pmi8998_vreg_data[] = { RPMH_VREG("bob", "bob%s1", &pmic4_bob, "vdd-bob"), {} @@ -1217,6 +1222,10 @@ static const struct of_device_id __maybe_unused rpmh_regulator_match_table[] = { .compatible = "qcom,pm8998-rpmh-regulators", .data = pm8998_vreg_data, }, + { + .compatible = "qcom,pmg1110-rpmh-regulators", + .data = pmg1110_vreg_data, + }, { .compatible = "qcom,pmi8998-rpmh-regulators", .data = pmi8998_vreg_data, -- GitLab From 342e3ce0f6f4691b31b1c7c9c3ae37160c4a82d2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 23 Nov 2021 21:27:21 +0200 Subject: [PATCH 0223/1112] ARM: pxa/lubbock: Replace custom ->cs_control() by GPIO lookup table SPI PXA2xx driver supports GPIO chipselect by querying for known GPIO connection ID. Replace custom ->cs_control() by GPIO table, so the driver will use generic approach on this platform. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211123192723.44537-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- arch/arm/mach-pxa/lubbock.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index 742d18a1f7dc8..e2411971422d7 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -211,16 +211,17 @@ static struct ads7846_platform_data ads_info = { // .y_plate_ohms = 500, /* GUESS! */ }; -static void ads7846_cs(u32 command) -{ - static const unsigned TS_nCS = 1 << 11; - lubbock_set_misc_wr(TS_nCS, (command == PXA2XX_CS_ASSERT) ? 0 : TS_nCS); -} +static struct gpiod_lookup_table ads7846_cs_gpios = { + .dev_id = "ads7846", + .table = { + GPIO_LOOKUP("lubbock", 11, "cs", GPIO_ACTIVE_LOW), + {} + }, +}; static struct pxa2xx_spi_chip ads_hw = { .tx_threshold = 1, .rx_threshold = 2, - .cs_control = ads7846_cs, }; static struct spi_board_info spi_board_info[] __initdata = { { @@ -512,6 +513,8 @@ static void __init lubbock_init(void) lubbock_flash_data[flashboot].name = "boot-rom"; (void) platform_add_devices(devices, ARRAY_SIZE(devices)); + gpiod_add_lookup_table(&ads7846_cs_gpios); + pxa2xx_set_spi_info(1, &pxa_ssp_master_info); spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); } -- GitLab From a9c8f68ce2c37ced2f7a8667eda71b7753ede398 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 23 Nov 2021 21:27:22 +0200 Subject: [PATCH 0224/1112] spi: pxa2xx: Get rid of unused ->cs_control() Since the last user of the custom ->cs_control() gone, we may get rid of this legacy API completely. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211123192723.44537-2-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- Documentation/spi/pxa2xx.rst | 29 +++-------------------------- arch/arm/mach-pxa/stargate2.c | 2 +- drivers/spi/spi-pxa2xx.c | 18 ------------------ drivers/spi/spi-pxa2xx.h | 3 --- include/linux/spi/pxa2xx_spi.h | 4 ---- 5 files changed, 4 insertions(+), 52 deletions(-) diff --git a/Documentation/spi/pxa2xx.rst b/Documentation/spi/pxa2xx.rst index 6312968acfe99..dfc7673ed15df 100644 --- a/Documentation/spi/pxa2xx.rst +++ b/Documentation/spi/pxa2xx.rst @@ -102,7 +102,7 @@ device. All fields are optional. u8 dma_burst_size; u32 timeout; u8 enable_loopback; - void (*cs_control)(u32 command); + int gpio_cs; }; The "pxa2xx_spi_chip.tx_threshold" and "pxa2xx_spi_chip.rx_threshold" fields are @@ -133,11 +133,6 @@ into internal loopback mode. In this mode the SSP controller internally connects the SSPTX pin to the SSPRX pin. This is useful for initial setup testing. -The "pxa2xx_spi_chip.cs_control" field is used to point to a board specific -function for asserting/deasserting a slave device chip select. If the field is -NULL, the pxa2xx_spi master controller driver assumes that the SSP port is -configured to use GPIO or SSPFRM instead. - NOTE: the SPI driver cannot control the chip select if SSPFRM is used, so the chipselect is dropped after each spi_transfer. Most devices need chip select asserted around the complete message. Use SSPFRM as a GPIO (through a descriptor) @@ -152,30 +147,12 @@ field. Below is a sample configuration using the PXA255 NSSP. :: - /* Chip Select control for the CS8415A SPI slave device */ - static void cs8415a_cs_control(u32 command) - { - if (command & PXA2XX_CS_ASSERT) - GPCR(2) = GPIO_bit(2); - else - GPSR(2) = GPIO_bit(2); - } - - /* Chip Select control for the CS8405A SPI slave device */ - static void cs8405a_cs_control(u32 command) - { - if (command & PXA2XX_CS_ASSERT) - GPCR(3) = GPIO_bit(3); - else - GPSR(3) = GPIO_bit(3); - } - static struct pxa2xx_spi_chip cs8415a_chip_info = { .tx_threshold = 8, /* SSP hardward FIFO threshold */ .rx_threshold = 8, /* SSP hardward FIFO threshold */ .dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */ .timeout = 235, /* See Intel documentation */ - .cs_control = cs8415a_cs_control, /* Use external chip select */ + .gpio_cs = 2, /* Use external chip select */ }; static struct pxa2xx_spi_chip cs8405a_chip_info = { @@ -183,7 +160,7 @@ field. Below is a sample configuration using the PXA255 NSSP. .rx_threshold = 8, /* SSP hardward FIFO threshold */ .dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */ .timeout = 235, /* See Intel documentation */ - .cs_control = cs8405a_cs_control, /* Use external chip select */ + .gpio_cs = 3, /* Use external chip select */ }; static struct spi_board_info streetracer_spi_board_info[] __initdata = { diff --git a/arch/arm/mach-pxa/stargate2.c b/arch/arm/mach-pxa/stargate2.c index 7ad6274657686..8ca02ec1d44ce 100644 --- a/arch/arm/mach-pxa/stargate2.c +++ b/arch/arm/mach-pxa/stargate2.c @@ -347,7 +347,7 @@ static struct pxa2xx_spi_controller pxa_ssp_master_2_info = { }; /* An upcoming kernel change will scrap SFRM usage so these - * drivers have been moved to use gpio's via cs_control */ + * drivers have been moved to use GPIOs */ static struct pxa2xx_spi_chip staccel_chip_info = { .tx_threshold = 8, .rx_threshold = 8, diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index ee3297dd532e3..24196156c609d 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -427,7 +427,6 @@ static void lpss_ssp_cs_control(struct spi_device *spi, bool enable) static void cs_assert(struct spi_device *spi) { - struct chip_data *chip = spi_get_ctldata(spi); struct driver_data *drv_data = spi_controller_get_devdata(spi->controller); @@ -436,18 +435,12 @@ static void cs_assert(struct spi_device *spi) return; } - if (chip->cs_control) { - chip->cs_control(PXA2XX_CS_ASSERT); - return; - } - if (is_lpss_ssp(drv_data)) lpss_ssp_cs_control(spi, true); } static void cs_deassert(struct spi_device *spi) { - struct chip_data *chip = spi_get_ctldata(spi); struct driver_data *drv_data = spi_controller_get_devdata(spi->controller); unsigned long timeout; @@ -461,11 +454,6 @@ static void cs_deassert(struct spi_device *spi) !time_after(jiffies, timeout)) cpu_relax(); - if (chip->cs_control) { - chip->cs_control(PXA2XX_CS_DEASSERT); - return; - } - if (is_lpss_ssp(drv_data)) lpss_ssp_cs_control(spi, false); } @@ -1204,12 +1192,6 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip, */ cleanup_cs(spi); - /* If ->cs_control() is provided, ignore GPIO chip select */ - if (chip_info->cs_control) { - chip->cs_control = chip_info->cs_control; - return 0; - } - if (gpio_is_valid(chip_info->gpio_cs)) { int gpio = chip_info->gpio_cs; int err; diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index 4d77f4de6eda2..45cdbbc71c4b4 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -49,7 +49,6 @@ struct driver_data { int (*write)(struct driver_data *drv_data); int (*read)(struct driver_data *drv_data); irqreturn_t (*transfer_handler)(struct driver_data *drv_data); - void (*cs_control)(u32 command); void __iomem *lpss_base; @@ -67,8 +66,6 @@ struct chip_data { u32 threshold; u16 lpss_rx_threshold; u16 lpss_tx_threshold; - - void (*cs_control)(u32 command); }; static inline u32 pxa2xx_spi_read(const struct driver_data *drv_data, u32 reg) diff --git a/include/linux/spi/pxa2xx_spi.h b/include/linux/spi/pxa2xx_spi.h index eaab121ee5751..42e06bfbc2a4d 100644 --- a/include/linux/spi/pxa2xx_spi.h +++ b/include/linux/spi/pxa2xx_spi.h @@ -9,9 +9,6 @@ #include -#define PXA2XX_CS_ASSERT (0x01) -#define PXA2XX_CS_DEASSERT (0x02) - struct dma_chan; /* @@ -47,7 +44,6 @@ struct pxa2xx_spi_chip { u32 timeout; u8 enable_loopback; int gpio_cs; - void (*cs_control)(u32 command); }; #if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP) -- GitLab From 8393961c53b31078cfc877bc00eb0f67e1474edd Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 23 Nov 2021 21:27:23 +0200 Subject: [PATCH 0225/1112] spi: pxa2xx: Get rid of unused enable_loopback member There is no user of the enable_loopback member in the struct pxa2xx_spi_chip. Remote this legacy member completely. The mentioned in the documentation the testing phase can be performed with spidev_test tool. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211123192723.44537-3-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- Documentation/spi/pxa2xx.rst | 6 ------ drivers/spi/spi-pxa2xx.c | 5 ++--- include/linux/spi/pxa2xx_spi.h | 1 - 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/Documentation/spi/pxa2xx.rst b/Documentation/spi/pxa2xx.rst index dfc7673ed15df..6347580826bef 100644 --- a/Documentation/spi/pxa2xx.rst +++ b/Documentation/spi/pxa2xx.rst @@ -101,7 +101,6 @@ device. All fields are optional. u8 rx_threshold; u8 dma_burst_size; u32 timeout; - u8 enable_loopback; int gpio_cs; }; @@ -128,11 +127,6 @@ dependent on the SPI bus speed ("spi_board_info.max_speed_hz") and the specific slave device. Please note that the PXA2xx SSP 1 does not support trailing byte timeouts and must busy-wait any trailing bytes. -The "pxa2xx_spi_chip.enable_loopback" field is used to place the SSP porting -into internal loopback mode. In this mode the SSP controller internally -connects the SSPTX pin to the SSPRX pin. This is useful for initial setup -testing. - NOTE: the SPI driver cannot control the chip select if SSPFRM is used, so the chipselect is dropped after each spi_transfer. Most devices need chip select asserted around the complete message. Use SSPFRM as a GPIO (through a descriptor) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 24196156c609d..b3186bd0c2a8e 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1289,7 +1289,6 @@ static int setup(struct spi_device *spi) chip_info = spi->controller_data; /* chip_info isn't always needed */ - chip->cr1 = 0; if (chip_info) { if (chip_info->timeout) chip->timeout = chip_info->timeout; @@ -1300,9 +1299,9 @@ static int setup(struct spi_device *spi) if (chip_info->rx_threshold) rx_thres = chip_info->rx_threshold; chip->dma_threshold = 0; - if (chip_info->enable_loopback) - chip->cr1 = SSCR1_LBM; } + + chip->cr1 = 0; if (spi_controller_is_slave(drv_data->controller)) { chip->cr1 |= SSCR1_SCFR; chip->cr1 |= SSCR1_SCLKDIR; diff --git a/include/linux/spi/pxa2xx_spi.h b/include/linux/spi/pxa2xx_spi.h index 42e06bfbc2a4d..ca74dce367065 100644 --- a/include/linux/spi/pxa2xx_spi.h +++ b/include/linux/spi/pxa2xx_spi.h @@ -42,7 +42,6 @@ struct pxa2xx_spi_chip { u8 rx_threshold; u8 dma_burst_size; u32 timeout; - u8 enable_loopback; int gpio_cs; }; -- GitLab From f8689195d7dd0821457dcf158c063e3160a55ee1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 25 Nov 2021 08:48:25 +0100 Subject: [PATCH 0226/1112] regulator: dt-bindings: maxim,max77686: Convert to dtschema Convert the regulators of Maxim MAX77686 PMIC to DT schema format. Signed-off-by: Krzysztof Kozlowski Acked-by: Mark Brown Reviewed-by: Rob Herring Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20211125074826.7947-2-krzysztof.kozlowski@canonical.com --- .../bindings/regulator/max77686.txt | 71 ---------------- .../bindings/regulator/maxim,max77686.yaml | 83 +++++++++++++++++++ MAINTAINERS | 1 + 3 files changed, 84 insertions(+), 71 deletions(-) delete mode 100644 Documentation/devicetree/bindings/regulator/max77686.txt create mode 100644 Documentation/devicetree/bindings/regulator/maxim,max77686.yaml diff --git a/Documentation/devicetree/bindings/regulator/max77686.txt b/Documentation/devicetree/bindings/regulator/max77686.txt deleted file mode 100644 index ff3d2dec8c4ba..0000000000000 --- a/Documentation/devicetree/bindings/regulator/max77686.txt +++ /dev/null @@ -1,71 +0,0 @@ -Binding for Maxim MAX77686 regulators - -This is a part of the device tree bindings of MAX77686 multi-function device. -More information can be found in ../mfd/max77686.txt file. - -The MAX77686 PMIC has 9 high-efficiency Buck and 26 Low-DropOut (LDO) -regulators that can be controlled over I2C. - -Following properties should be present in main device node of the MFD chip. - -Optional node: -- voltage-regulators : The regulators of max77686 have to be instantiated - under subnode named "voltage-regulators" using the following format. - - regulator_name { - regulator-compatible = LDOn/BUCKn - standard regulator constraints.... - }; - refer Documentation/devicetree/bindings/regulator/regulator.txt - - The regulator node's name should be initialized with a string -to get matched with their hardware counterparts as follow: - - -LDOn : for LDOs, where n can lie in range 1 to 26. - example: LDO1, LDO2, LDO26. - -BUCKn : for BUCKs, where n can lie in range 1 to 9. - example: BUCK1, BUCK5, BUCK9. - - Regulators which can be turned off during system suspend: - -LDOn : 2, 6-8, 10-12, 14-16, - -BUCKn : 1-4. - Use standard regulator bindings for it ('regulator-off-in-suspend'). - - LDO20, LDO21, LDO22, BUCK8 and BUCK9 can be configured to GPIO enable - control. To turn this feature on this property must be added to the regulator - sub-node: - - maxim,ena-gpios : one GPIO specifier enable control (the gpio - flags are actually ignored and always - ACTIVE_HIGH is used) - -Example: - - max77686: pmic@9 { - compatible = "maxim,max77686"; - interrupt-parent = <&wakeup_eint>; - interrupts = <26 IRQ_TYPE_LEVEL_LOW>; - reg = <0x09>; - - voltage-regulators { - ldo11_reg: LDO11 { - regulator-name = "vdd_ldo11"; - regulator-min-microvolt = <1900000>; - regulator-max-microvolt = <1900000>; - regulator-always-on; - }; - - buck1_reg: BUCK1 { - regulator-name = "vdd_mif"; - regulator-min-microvolt = <950000>; - regulator-max-microvolt = <1300000>; - regulator-always-on; - regulator-boot-on; - }; - - buck9_reg: BUCK9 { - regulator-name = "CAM_ISP_CORE_1.2V"; - regulator-min-microvolt = <1000000>; - regulator-max-microvolt = <1200000>; - maxim,ena-gpios = <&gpm0 3 GPIO_ACTIVE_HIGH>; - }; - }; diff --git a/Documentation/devicetree/bindings/regulator/maxim,max77686.yaml b/Documentation/devicetree/bindings/regulator/maxim,max77686.yaml new file mode 100644 index 0000000000000..bb64b679f765a --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/maxim,max77686.yaml @@ -0,0 +1,83 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/maxim,max77686.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim MAX77686 Power Management IC regulators + +maintainers: + - Chanwoo Choi + - Krzysztof Kozlowski + +description: | + This is a part of device tree bindings for Maxim MAX77686 Power Management + Integrated Circuit (PMIC). + + The Maxim MAX77686 provides high-efficiency Buck and 26 Low-DropOut (LDO) + regulators. + + See also Documentation/devicetree/bindings/mfd/maxim,max77686.yaml for + additional information and example. + +patternProperties: + # 26 LDOs + "^LDO([1-9]|1[0-9]|2[3-6])$": + type: object + $ref: regulator.yaml# + unevaluatedProperties: false + description: | + Properties for single LDO regulator. + Regulators which can be turned off during system suspend: + LDO2, LDO6-8, LDO10-12, LDO14-16 + + required: + - regulator-name + + # LDO20-LDO22 with maxim,ena-gpios + "^LDO2[0-2]$": + type: object + $ref: regulator.yaml# + unevaluatedProperties: false + description: | + Properties for single LDO regulator. + + properties: + maxim,ena-gpios: + maxItems: 1 + description: | + GPIO specifier to enable the GPIO control (on/off) for regulator. + + required: + - regulator-name + + # 9 bucks + "^BUCK[1-7]$": + type: object + $ref: regulator.yaml# + unevaluatedProperties: false + description: | + Properties for single BUCK regulator. + Regulators which can be turned off during system suspend: + BUCK[1-4] + + required: + - regulator-name + + "^BUCK[89]$": + type: object + $ref: regulator.yaml# + unevaluatedProperties: false + description: | + Properties for single BUCK regulator. + + properties: + maxim,ena-gpios: + maxItems: 1 + description: | + GPIO specifier to enable the GPIO control (on/off) for regulator. + + required: + - regulator-name + +additionalProperties: false diff --git a/MAINTAINERS b/MAINTAINERS index c3ebc417ba41c..5cd3a2a68f709 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11595,6 +11595,7 @@ M: Bartlomiej Zolnierkiewicz L: linux-kernel@vger.kernel.org S: Supported F: Documentation/devicetree/bindings/*/max77686.txt +F: Documentation/devicetree/bindings/*/maxim,max77686.yaml F: Documentation/devicetree/bindings/clock/maxim,max77686.txt F: Documentation/devicetree/bindings/mfd/max14577.txt F: Documentation/devicetree/bindings/mfd/max77693.txt -- GitLab From 013db96da8b21c28b042f6fae904bbc0378a4349 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 25 Nov 2021 08:48:26 +0100 Subject: [PATCH 0227/1112] dt-bindings: mfd: maxim,max77686: Convert to dtschema Convert the MFD part of Maxim MAX77686 PMIC to DT schema format. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20211125074826.7947-3-krzysztof.kozlowski@canonical.com --- .../devicetree/bindings/mfd/max77686.txt | 26 ---- .../bindings/mfd/maxim,max77686.yaml | 132 ++++++++++++++++++ MAINTAINERS | 1 - 3 files changed, 132 insertions(+), 27 deletions(-) delete mode 100644 Documentation/devicetree/bindings/mfd/max77686.txt create mode 100644 Documentation/devicetree/bindings/mfd/maxim,max77686.yaml diff --git a/Documentation/devicetree/bindings/mfd/max77686.txt b/Documentation/devicetree/bindings/mfd/max77686.txt deleted file mode 100644 index 4447d074894a2..0000000000000 --- a/Documentation/devicetree/bindings/mfd/max77686.txt +++ /dev/null @@ -1,26 +0,0 @@ -Maxim MAX77686 multi-function device - -MAX77686 is a Multifunction device with PMIC, RTC and Charger on chip. It is -interfaced to host controller using i2c interface. PMIC and Charger submodules -are addressed using same i2c slave address whereas RTC submodule uses -different i2c slave address,presently for which we are statically creating i2c -client while probing.This document describes the binding for mfd device and -PMIC submodule. - -Bindings for the built-in 32k clock generator block and -regulators are defined in ../clk/maxim,max77686.txt and -../regulator/max77686.txt respectively. - -Required properties: -- compatible : Must be "maxim,max77686"; -- reg : Specifies the i2c slave address of PMIC block. -- interrupts : This i2c device has an IRQ line connected to the main SoC. - -Example: - - max77686: pmic@9 { - compatible = "maxim,max77686"; - interrupt-parent = <&wakeup_eint>; - interrupts = <26 IRQ_TYPE_LEVEL_LOW>; - reg = <0x09>; - }; diff --git a/Documentation/devicetree/bindings/mfd/maxim,max77686.yaml b/Documentation/devicetree/bindings/mfd/maxim,max77686.yaml new file mode 100644 index 0000000000000..859655a789c3b --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/maxim,max77686.yaml @@ -0,0 +1,132 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/maxim,max77686.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim MAX77686 Power Management IC + +maintainers: + - Chanwoo Choi + - Krzysztof Kozlowski + +description: | + This is a part of device tree bindings for Maxim MAX77686 Power Management + Integrated Circuit (PMIC). + + The Maxim MAX77686 is a Power Management IC which includes voltage and + current regulators, RTC and clock outputs. + + The MAX77686 provides three 32.768khz clock outputs that can be controlled + (gated/ungated) over I2C. The clock IDs are defined as preprocessor macros + in dt-bindings/clock/maxim,max77686.h. + +properties: + compatible: + const: maxim,max77686 + + '#clock-cells': + const: 1 + + interrupts: + maxItems: 1 + + reg: + maxItems: 1 + + voltage-regulators: + $ref: ../regulator/maxim,max77686.yaml + description: + List of child nodes that specify the regulators. + + wakeup-source: true + +required: + - compatible + - '#clock-cells' + - reg + +additionalProperties: false + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + max77686: pmic@9 { + compatible = "maxim,max77686"; + reg = <0x09>; + + interrupt-parent = <&gpx0>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; + pinctrl-0 = <&max77686_irq>; + pinctrl-names = "default"; + wakeup-source; + #clock-cells = <1>; + + voltage-regulators { + LDO1 { + regulator-name = "VALIVE_1.0V_AP"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + }; + + LDO2 { + regulator-name = "VM1M2_1.2V_AP"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + // ... + + LDO22 { + regulator-name = "VMEM_VDD_2.8V"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + maxim,ena-gpios = <&gpk0 2 GPIO_ACTIVE_HIGH>; + }; + + // ... + + BUCK1 { + regulator-name = "VDD_MIF"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + regulator-boot-on; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + BUCK2 { + regulator-name = "VDD_ARM"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <1500000>; + regulator-always-on; + regulator-boot-on; + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + // ... + + BUCK9 { + regulator-name = "CAM_ISP_CORE_1.2V"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1200000>; + maxim,ena-gpios = <&gpm0 3 GPIO_ACTIVE_HIGH>; + }; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 5cd3a2a68f709..9fce6324d0994 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11594,7 +11594,6 @@ M: Krzysztof Kozlowski M: Bartlomiej Zolnierkiewicz L: linux-kernel@vger.kernel.org S: Supported -F: Documentation/devicetree/bindings/*/max77686.txt F: Documentation/devicetree/bindings/*/maxim,max77686.yaml F: Documentation/devicetree/bindings/clock/maxim,max77686.txt F: Documentation/devicetree/bindings/mfd/max14577.txt -- GitLab From 8b2051a1defe26bd3c83595521e000405fda0835 Mon Sep 17 00:00:00 2001 From: Ed Schaller Date: Tue, 23 Nov 2021 12:01:14 -0600 Subject: [PATCH 0228/1112] mfd: intel-lpss: Add Intel Lakefield PCH PCI IDs Add new IDs of the Intel Lakefield chip to the list of supported devices. Signed-off-by: Ed Schaller Reviewed-by: Andy Shevchenko Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20211123180114.GA4747@darkmist.net --- drivers/mfd/intel-lpss-pci.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index a872b4485eacf..9700e5acd0cd2 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -359,7 +359,14 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { /* LKF */ { PCI_VDEVICE(INTEL, 0x98a8), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x98a9), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0x98aa), (kernel_ulong_t)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x98c5), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x98c6), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x98c7), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0x98e8), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x98e9), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x98ea), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x98eb), (kernel_ulong_t)&bxt_i2c_info }, /* SPT-LP */ { PCI_VDEVICE(INTEL, 0x9d27), (kernel_ulong_t)&spt_uart_info }, { PCI_VDEVICE(INTEL, 0x9d28), (kernel_ulong_t)&spt_uart_info }, -- GitLab From 983b62975e903a9a92ea3a3daef43e2a32cc8479 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 27 Oct 2021 14:34:32 +0200 Subject: [PATCH 0229/1112] dt-bindings: mfd: bd9571mwv: Convert to json-schema Convert the ROHM BD9571MWV/BD9574MWF Power Management Integrated Circuit (PMIC) Device Tree binding documentation to json-schema. Make the "regulators" subnode optional, as not all users describe the regulators. Signed-off-by: Geert Uytterhoeven Reviewed-by: Rob Herring Acked-by: Matti Vaittinen Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/76fdd209e6a2dada7ff50b8ad03eb14e7f3547a6.1635338031.git.geert+renesas@glider.be --- .../devicetree/bindings/mfd/bd9571mwv.txt | 69 ---------- .../bindings/mfd/rohm,bd9571mwv.yaml | 127 ++++++++++++++++++ 2 files changed, 127 insertions(+), 69 deletions(-) delete mode 100644 Documentation/devicetree/bindings/mfd/bd9571mwv.txt create mode 100644 Documentation/devicetree/bindings/mfd/rohm,bd9571mwv.yaml diff --git a/Documentation/devicetree/bindings/mfd/bd9571mwv.txt b/Documentation/devicetree/bindings/mfd/bd9571mwv.txt deleted file mode 100644 index 1d6413e96c376..0000000000000 --- a/Documentation/devicetree/bindings/mfd/bd9571mwv.txt +++ /dev/null @@ -1,69 +0,0 @@ -* ROHM BD9571MWV/BD9574MWF Power Management Integrated Circuit (PMIC) bindings - -Required properties: - - compatible : Should be "rohm,bd9571mwv" or "rohm,bd9574mwf". - - reg : I2C slave address. - - interrupts : The interrupt line the device is connected to. - - interrupt-controller : Marks the device node as an interrupt controller. - - #interrupt-cells : The number of cells to describe an IRQ, should be 2. - The first cell is the IRQ number. - The second cell is the flags, encoded as trigger - masks from ../interrupt-controller/interrupts.txt. - - gpio-controller : Marks the device node as a GPIO Controller. - - #gpio-cells : Should be two. The first cell is the pin number and - the second cell is used to specify flags. - See ../gpio/gpio.txt for more information. - - regulators: : List of child nodes that specify the regulator - initialization data. Child nodes must be named - after their hardware counterparts: - - vd09 - - vd18 - - vd25 - - vd33 - - dvfs - Each child node is defined using the standard - binding for regulators. - -Optional properties: - - rohm,ddr-backup-power : Value to use for DDR-Backup Power (default 0). - This is a bitmask that specifies which DDR power - rails need to be kept powered when backup mode is - entered, for system suspend: - - bit 0: DDR0 - - bit 1: DDR1 - - bit 2: DDR0C - - bit 3: DDR1C - These bits match the KEEPON_DDR* bits in the - documentation for the "BKUP Mode Cnt" register. - - rohm,rstbmode-level: The RSTB signal is configured for level mode, to - accommodate a toggle power switch (the RSTBMODE pin is - strapped low). - - rohm,rstbmode-pulse: The RSTB signal is configured for pulse mode, to - accommodate a momentary power switch (the RSTBMODE pin - is strapped high). - The two properties above are mutually exclusive. - -Example: - - pmic: pmic@30 { - compatible = "rohm,bd9571mwv"; - reg = <0x30>; - interrupt-parent = <&gpio2>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; - interrupt-controller; - #interrupt-cells = <2>; - gpio-controller; - #gpio-cells = <2>; - rohm,ddr-backup-power = <0xf>; - rohm,rstbmode-pulse; - - regulators { - dvfs: dvfs { - regulator-name = "dvfs"; - regulator-min-microvolt = <750000>; - regulator-max-microvolt = <1030000>; - regulator-boot-on; - regulator-always-on; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/mfd/rohm,bd9571mwv.yaml b/Documentation/devicetree/bindings/mfd/rohm,bd9571mwv.yaml new file mode 100644 index 0000000000000..89f9efee465b8 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/rohm,bd9571mwv.yaml @@ -0,0 +1,127 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/rohm,bd9571mwv.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ROHM BD9571MWV/BD9574MWF Power Management Integrated Circuit (PMIC) + +maintainers: + - Marek Vasut + +properties: + compatible: + enum: + - rohm,bd9571mwv + - rohm,bd9574mwf + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + interrupt-controller: true + + '#interrupt-cells': + const: 2 + + gpio-controller: true + + '#gpio-cells': + const: 2 + + rohm,ddr-backup-power: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0x0 + maximum: 0xf + description: | + Value to use for DDR-Backup Power (default 0). + This is a bitmask that specifies which DDR power rails need to be kept + powered when backup mode is entered, for system suspend: + - bit 0: DDR0 + - bit 1: DDR1 + - bit 2: DDR0C + - bit 3: DDR1C + These bits match the KEEPON_DDR* bits in the documentation for the "BKUP + Mode Cnt" register. + + rohm,rstbmode-level: + $ref: /schemas/types.yaml#/definitions/flag + description: + The RSTB signal is configured for level mode, to accommodate a toggle + power switch (the RSTBMODE pin is strapped low). + + rohm,rstbmode-pulse: + $ref: /schemas/types.yaml#/definitions/flag + description: + The RSTB signal is configured for pulse mode, to accommodate a momentary + power switch (the RSTBMODE pin is strapped high). + + regulators: + type: object + description: + List of child nodes that specify the regulator initialization data. + Child nodes must be named after their hardware counterparts. + + patternProperties: + "^(vd09|vd18|vd25|vd33|dvfs)$": + type: object + $ref: ../regulator/regulator.yaml# + + properties: + regulator-name: + pattern: "^(vd09|vd18|vd25|vd33|dvfs)$" + + unevaluatedProperties: false + + additionalProperties: false + +additionalProperties: false + +required: + - compatible + - reg + - interrupts + - interrupt-controller + - '#interrupt-cells' + - gpio-controller + - '#gpio-cells' + +oneOf: + - required: + - rohm,rstbmode-level + - required: + - rohm,rstbmode-pulse + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + pmic: pmic@30 { + compatible = "rohm,bd9571mwv"; + reg = <0x30>; + interrupt-parent = <&gpio2>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; + rohm,ddr-backup-power = <0xf>; + rohm,rstbmode-pulse; + + regulators { + dvfs: dvfs { + regulator-name = "dvfs"; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1030000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; + }; -- GitLab From 8c0fad75dcaa650e3f3145a2c35847bc6a65cb7f Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 28 Oct 2021 16:51:37 +0300 Subject: [PATCH 0230/1112] mfd: atmel-flexcom: Remove #ifdef CONFIG_PM_SLEEP Remove compilation flag and use __maybe_unused and pm_ptr instead. Signed-off-by: Claudiu Beznea Acked-by: Nicolas Ferre Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20211028135138.3481166-2-claudiu.beznea@microchip.com --- drivers/mfd/atmel-flexcom.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/mfd/atmel-flexcom.c b/drivers/mfd/atmel-flexcom.c index d2f5c073fdf31..962f66dc8813e 100644 --- a/drivers/mfd/atmel-flexcom.c +++ b/drivers/mfd/atmel-flexcom.c @@ -87,8 +87,7 @@ static const struct of_device_id atmel_flexcom_of_match[] = { }; MODULE_DEVICE_TABLE(of, atmel_flexcom_of_match); -#ifdef CONFIG_PM_SLEEP -static int atmel_flexcom_resume(struct device *dev) +static int __maybe_unused atmel_flexcom_resume(struct device *dev) { struct atmel_flexcom *ddata = dev_get_drvdata(dev); int err; @@ -105,7 +104,6 @@ static int atmel_flexcom_resume(struct device *dev) return 0; } -#endif static SIMPLE_DEV_PM_OPS(atmel_flexcom_pm_ops, NULL, atmel_flexcom_resume); @@ -114,7 +112,7 @@ static struct platform_driver atmel_flexcom_driver = { .probe = atmel_flexcom_probe, .driver = { .name = "atmel_flexcom", - .pm = &atmel_flexcom_pm_ops, + .pm = pm_ptr(&atmel_flexcom_pm_ops), .of_match_table = atmel_flexcom_of_match, }, }; -- GitLab From 5d051cf94fd5834a1513aa77e542c49fd973988a Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 28 Oct 2021 16:51:38 +0300 Subject: [PATCH 0231/1112] mfd: atmel-flexcom: Use .resume_noirq Flexcom IP embeds 3 other IPs: usart, i2c, spi and selects the operation mode (usart, i2c, spi) via mode register (FLEX_MR). On i2c bus there might be connected critical devices (like PMIC) which on suspend/resume should be suspended/resumed at the end/beginning. i2c uses .suspend_noirq/.resume_noirq for this kind of purposes. Align flexcom to use .resume_noirq as it should be resumed before the embedded IPs. Otherwise the embedded devices might behave badly. Fixes: 7fdec11015c3 ("atmel_flexcom: Support resuming after a chip reset") Signed-off-by: Claudiu Beznea Tested-by: Codrin Ciubotariu Acked-by: Nicolas Ferre Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20211028135138.3481166-3-claudiu.beznea@microchip.com --- drivers/mfd/atmel-flexcom.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/mfd/atmel-flexcom.c b/drivers/mfd/atmel-flexcom.c index 962f66dc8813e..559eb4d352b68 100644 --- a/drivers/mfd/atmel-flexcom.c +++ b/drivers/mfd/atmel-flexcom.c @@ -87,7 +87,7 @@ static const struct of_device_id atmel_flexcom_of_match[] = { }; MODULE_DEVICE_TABLE(of, atmel_flexcom_of_match); -static int __maybe_unused atmel_flexcom_resume(struct device *dev) +static int __maybe_unused atmel_flexcom_resume_noirq(struct device *dev) { struct atmel_flexcom *ddata = dev_get_drvdata(dev); int err; @@ -105,8 +105,9 @@ static int __maybe_unused atmel_flexcom_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(atmel_flexcom_pm_ops, NULL, - atmel_flexcom_resume); +static const struct dev_pm_ops atmel_flexcom_pm_ops = { + .resume_noirq = atmel_flexcom_resume_noirq, +}; static struct platform_driver atmel_flexcom_driver = { .probe = atmel_flexcom_probe, -- GitLab From 786c6f140bb67ba315962b4742326e93e8b3207c Mon Sep 17 00:00:00 2001 From: Oleksandr Suvorov Date: Wed, 27 Oct 2021 10:21:55 +0200 Subject: [PATCH 0232/1112] mfd: stmpe: Support disabling sub-functions Add support of sub-functions disabling. It allows one to define an stmpe sub-function device in devicetree, but keep it disabled. Signed-off-by: Oleksandr Suvorov Signed-off-by: Francesco Dolcini Reviewed-by: Linus Walleij Reviewed-by: Marcel Ziswiler Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20211027082155.206449-1-francesco.dolcini@toradex.com --- drivers/mfd/stmpe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index e928df95e3167..aeb9ea55f97d9 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -1361,7 +1361,7 @@ static void stmpe_of_probe(struct stmpe_platform_data *pdata, pdata->autosleep = (pdata->autosleep_timeout) ? true : false; - for_each_child_of_node(np, child) { + for_each_available_child_of_node(np, child) { if (of_node_name_eq(child, "stmpe_gpio")) { pdata->blocks |= STMPE_BLOCK_GPIO; } else if (of_node_name_eq(child, "stmpe_keypad")) { -- GitLab From 17247821ae9b40ea6df8d771cfca97d91675be93 Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Thu, 25 Nov 2021 23:46:42 +0100 Subject: [PATCH 0233/1112] mfd: ti_am335x_tscadc: Drop the CNTRLREG_TSC_8WIRE macro In TI's reference manual description for the `AFE_Pen_Ctrl' bit-field of the TSC's CTRL register, there is no mention of 8-wire touchscreens. Even commit f0933a60d190 ("mfd: ti_am335x_tscadc: Update logic in CTRL register for 5-wire TS") says that the value of this bit-field must be the same for 4-wire and 8-wire touchscreens. So let's remove the CNTRLREG_TSC_8WIRE macro to avoid misunderstandings. Signed-off-by: Dario Binacchi Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20211125224642.21011-5-dariobin@libero.it --- include/linux/mfd/ti_am335x_tscadc.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/mfd/ti_am335x_tscadc.h b/include/linux/mfd/ti_am335x_tscadc.h index ba13e043d9104..4063b0614d90a 100644 --- a/include/linux/mfd/ti_am335x_tscadc.h +++ b/include/linux/mfd/ti_am335x_tscadc.h @@ -103,7 +103,6 @@ #define CNTRLREG_TSC_AFE_CTRL(val) FIELD_PREP(GENMASK(6, 5), (val)) #define CNTRLREG_TSC_4WIRE CNTRLREG_TSC_AFE_CTRL(1) #define CNTRLREG_TSC_5WIRE CNTRLREG_TSC_AFE_CTRL(2) -#define CNTRLREG_TSC_8WIRE CNTRLREG_TSC_AFE_CTRL(3) #define CNTRLREG_TSC_ENB BIT(7) /*Control registers bitfields for MAGADC IP */ -- GitLab From c9e143084d1a602f829115612e1ec79df3727c8b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 1 Nov 2021 21:00:08 +0200 Subject: [PATCH 0234/1112] mfd: intel-lpss: Fix too early PM enablement in the ACPI ->probe() The runtime PM callback may be called as soon as the runtime PM facility is enabled and activated. It means that ->suspend() may be called before we finish probing the device in the ACPI case. Hence, NULL pointer dereference: intel-lpss INT34BA:00: IRQ index 0 not found BUG: kernel NULL pointer dereference, address: 0000000000000030 ... Workqueue: pm pm_runtime_work RIP: 0010:intel_lpss_suspend+0xb/0x40 [intel_lpss] To fix this, first try to register the device and only after that enable runtime PM facility. Fixes: 4b45efe85263 ("mfd: Add support for Intel Sunrisepoint LPSS devices") Reported-by: Orlando Chamberlain Reported-by: Aditya Garg Signed-off-by: Andy Shevchenko Tested-by: Aditya Garg Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20211101190008.86473-1-andriy.shevchenko@linux.intel.com --- drivers/mfd/intel-lpss-acpi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/mfd/intel-lpss-acpi.c b/drivers/mfd/intel-lpss-acpi.c index 3f1d976eb67cb..f2ea6540a01e1 100644 --- a/drivers/mfd/intel-lpss-acpi.c +++ b/drivers/mfd/intel-lpss-acpi.c @@ -136,6 +136,7 @@ static int intel_lpss_acpi_probe(struct platform_device *pdev) { struct intel_lpss_platform_info *info; const struct acpi_device_id *id; + int ret; id = acpi_match_device(intel_lpss_acpi_ids, &pdev->dev); if (!id) @@ -149,10 +150,14 @@ static int intel_lpss_acpi_probe(struct platform_device *pdev) info->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); info->irq = platform_get_irq(pdev, 0); + ret = intel_lpss_probe(&pdev->dev, info); + if (ret) + return ret; + pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); - return intel_lpss_probe(&pdev->dev, info); + return 0; } static int intel_lpss_acpi_remove(struct platform_device *pdev) -- GitLab From 9651cf2cb14726c785240e9dc01b274a68e9959e Mon Sep 17 00:00:00 2001 From: Orlando Chamberlain Date: Wed, 24 Nov 2021 09:19:44 +0000 Subject: [PATCH 0235/1112] mfd: intel-lpss-pci: Fix clock speed for 38a8 UART This device is found in the MacBookPro16,2, and as the MacBookPro16,1 is from the same generation of MacBooks and has a UART with bxt_uart_info, it was incorrectly assumed that the MacBookPro16,2's UART would have the same info. This led to the wrong clock speed being used, and the Bluetooth controller exposed by the UART receiving and sending random data, which was incorrectly assumed to be an issue with the Bluetooth stuff, not an error with the UART side of things. Changing the info to spt_uart_info changes the clock speed and makes it send and receive data correctly. Fixes: ddb1ada416fd ("mfd: intel-lpss: Add support for MacBookPro16,2 ICL-N UART") Signed-off-by: Orlando Chamberlain Reviewed-by: Andy Shevchenko Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20211124091846.11114-1-redecorating@protonmail.com --- drivers/mfd/intel-lpss-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index 9700e5acd0cd2..a59aa147959b3 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -254,7 +254,7 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x34eb), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x34fb), (kernel_ulong_t)&spt_info }, /* ICL-N */ - { PCI_VDEVICE(INTEL, 0x38a8), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0x38a8), (kernel_ulong_t)&spt_uart_info }, /* TGL-H */ { PCI_VDEVICE(INTEL, 0x43a7), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x43a8), (kernel_ulong_t)&bxt_uart_info }, -- GitLab From 5c6f0f456351f5ca7d3b1a82060821eac4a7dc5c Mon Sep 17 00:00:00 2001 From: Andrej Picej Date: Wed, 24 Nov 2021 07:51:19 +0100 Subject: [PATCH 0236/1112] mfd: da9062: Support SMBus and I2C mode Enable the I2C bus mode if I2C_FUNC_I2C is set. Based on da6093 commit: "586478bfc9f7 mfd: da9063: Support SMBus and I2C mode" Signed-off-by: Andrej Picej Reviewed-by: Adam Thomson Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20211124065119.2514872-1-andrej.picej@norik.com --- drivers/mfd/da9062-core.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/mfd/da9062-core.c b/drivers/mfd/da9062-core.c index 01f8e10dfa558..2774b2cbaea6d 100644 --- a/drivers/mfd/da9062-core.c +++ b/drivers/mfd/da9062-core.c @@ -556,6 +556,7 @@ static const struct regmap_range da9062_aa_writeable_ranges[] = { regmap_reg_range(DA9062AA_VBUCK3_B, DA9062AA_VBUCK3_B), regmap_reg_range(DA9062AA_VLDO1_B, DA9062AA_VLDO4_B), regmap_reg_range(DA9062AA_BBAT_CONT, DA9062AA_BBAT_CONT), + regmap_reg_range(DA9062AA_CONFIG_J, DA9062AA_CONFIG_J), regmap_reg_range(DA9062AA_GP_ID_0, DA9062AA_GP_ID_19), }; @@ -674,6 +675,17 @@ static int da9062_i2c_probe(struct i2c_client *i2c, return ret; } + /* If SMBus is not available and only I2C is possible, enter I2C mode */ + if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) { + dev_info(chip->dev, "Entering I2C mode!\n"); + ret = regmap_clear_bits(chip->regmap, DA9062AA_CONFIG_J, + DA9062AA_TWOWIRE_TO_MASK); + if (ret < 0) { + dev_err(chip->dev, "Failed to set Two-Wire Bus Mode.\n"); + return ret; + } + } + ret = da9062_clear_fault_log(chip); if (ret < 0) dev_warn(chip->dev, "Cannot clear fault log\n"); -- GitLab From fe07b0f1e86047162c6e85535a82278045d8492c Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Sat, 27 Nov 2021 01:06:20 +0200 Subject: [PATCH 0237/1112] dt-bindings: mfd: syscon: Add samsung,exynos850-sysreg Document Samsung Exynos850 compatible for system registers. Signed-off-by: Sam Protsenko Reviewed-by: Krzysztof Kozlowski Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20211126230620.478-1-semen.protsenko@linaro.org --- Documentation/devicetree/bindings/mfd/syscon.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mfd/syscon.yaml b/Documentation/devicetree/bindings/mfd/syscon.yaml index 5de16388a089d..fdd96e378df05 100644 --- a/Documentation/devicetree/bindings/mfd/syscon.yaml +++ b/Documentation/devicetree/bindings/mfd/syscon.yaml @@ -57,6 +57,7 @@ properties: - samsung,exynos4-sysreg - samsung,exynos5-sysreg - samsung,exynos5433-sysreg + - samsung,exynos850-sysreg - samsung,exynosautov9-sysreg - const: syscon -- GitLab From 54d4c88b37595173d7039ea9a57913edfee48f47 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 29 Nov 2021 14:23:56 +0100 Subject: [PATCH 0238/1112] mfd: Kconfig: Change INTEL_SOC_PMIC_CHTDC_TI to bool The INTEL_SOC_PMIC_CHTDC_TI should be initialized early, before loading the fbcon driver, as otherwise the i915 driver will fail to configure pwm: [ 13.674287] fb0: switching to inteldrmfb from EFI VGA [ 13.682380] Console: switching to colour dummy device 80x25 [ 13.682468] i915 0000:00:02.0: vgaarb: deactivate vga console [ 13.682686] [drm] Supports vblank timestamp caching Rev 2 (21.10.2013). [ 13.685773] i915 0000:00:02.0: vgaarb: changed VGA decodes: olddecodes=io+mem,decodes=io+mem:owns=io+mem [ 13.686219] i915 0000:00:02.0: [drm] *ERROR* Failed to configure the pwm chip [ 13.699572] [drm] Initialized i915 1.6.0 20200313 for 0000:00:02.0 on minor 0 [ 13.739044] fbcon: i915drmfb (fb0) is primary device [ 14.037792] intel_soc_pmic_exec_mipi_pmic_seq_element: No PMIC registered ... [ 24.621403] intel_pmic_install_opregion_handler: Ask to register OpRegion for bus ID=PMI2, HID=INT33F5 [ 24.630540] intel_pmic_install_opregion_handler: OpRegion registered (some extra debug printk's were added to the above) As suggested by Hans, this patch also addresses an issue with the dependencies, as, for this driver to be a bool, it also need the I2C core and the I2C_DESIGNWARE driver to be builtin. Suggested-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Hans de Goede Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/86f546b3233fd799b0c39b83afc521440ebfe004.1638192232.git.mchehab+huawei@kernel.org --- drivers/mfd/Kconfig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 34c7d9d6b5800..a21cbdf89477e 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -634,7 +634,7 @@ config INTEL_SOC_PMIC_CHTWC config INTEL_SOC_PMIC_CHTDC_TI tristate "Support for Intel Cherry Trail Dollar Cove TI PMIC" depends on GPIOLIB - depends on I2C + depends on I2C=y && I2C_DESIGNWARE_PLATFORM=y depends on ACPI depends on X86 select MFD_CORE @@ -644,6 +644,10 @@ config INTEL_SOC_PMIC_CHTDC_TI Select this option for supporting Dollar Cove (TI version) PMIC device that is found on some Intel Cherry Trail systems. + This option is a bool as it provides an ACPI OpRegion which must be + available before any devices using it are probed. This option also + needs the designware-i2c driver to be builtin for the same reason. + config INTEL_SOC_PMIC_MRFLD tristate "Support for Intel Merrifield Basin Cove PMIC" depends on GPIOLIB -- GitLab From 6e6609f21bbc46cbf61dacb467aeabcc128b5e1c Mon Sep 17 00:00:00 2001 From: Alexey Brodkin Date: Fri, 12 Nov 2021 09:50:59 +0300 Subject: [PATCH 0239/1112] docs: Add documentation for ARC processors ARC processors are supported in upstream kernel since v3.9 and so far there was no documentation about them except some Device Tree bindings. Fixing it with the simples set of docs now: 1. Overview with pointers to other informational resources 2. Autogenerated feature table Note though it's just the very beginning, there will be more for sure given time as there're many things worth documenting and in fact even contents itself is avaialble but just spread in some other places. Now we'll try to keep all here and then maintain it looking forward to match the state of development. Signed-off-by: Alexey Brodkin Cc: Randy Dunlap Cc: Vineet Gupta Reviewed-by: Randy Dunlap Link: https://lore.kernel.org/r/20211112065059.7273-1-abrodkin@synopsys.com Signed-off-by: Jonathan Corbet --- Documentation/arc/arc.rst | 81 ++++++++++++++++++++++++++++++++++ Documentation/arc/features.rst | 3 ++ Documentation/arc/index.rst | 17 +++++++ Documentation/arch.rst | 1 + MAINTAINERS | 1 + 5 files changed, 103 insertions(+) create mode 100644 Documentation/arc/arc.rst create mode 100644 Documentation/arc/features.rst create mode 100644 Documentation/arc/index.rst diff --git a/Documentation/arc/arc.rst b/Documentation/arc/arc.rst new file mode 100644 index 0000000000000..249d03c6be8e4 --- /dev/null +++ b/Documentation/arc/arc.rst @@ -0,0 +1,81 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Linux kernel for ARC processors +******************************* + +Other sources of information +############################ + +Below are some resources where more information can be found on +ARC processors and relevant open source projects. + +1. ``_ - Community portal for open source on ARC. +Good place to start to find relevant FOSS projects, toolchain releases, +news items and more. + +2. ``_ - +Home for all development activities regarding open source projects for +ARC processors. Some of the projects are forks of various upstream projects, +where "work in progress" is hosted prior to submission to upstream projects. +Other projects are developed by Synopsys and made available to community +as open source for use on ARC Processors. + +3. ``_ - +Official Synopsys ARC Processors website location, with access to some IP +documentation (Programmer's Reference Manuals, AKA "PRM's", see +``_) +and commercial tools (Free nSIM, +``_ and +MetaWare Light Edition, ``_) + +Important note on ARC processors configurability +################################################ + +ARC processors are highly configurable and several configurable options +are supported in Linux. Some options are transparent to software +(i.e cache geometries, some can be detected at runtime and configured +and used accordingly, while some need to be explicitly selected or configured +in the kernel's configuration utility (AKA "make menuconfig"). + +However not all configurable options are supported when an ARC processor +is to run Linux. SoC design teams should refer to "Appendix E: +Configuration for ARC Linux" in the ARC HS Databook for configurability +guidelines. + +Following these guidelines and selecting valid configuration options +up front is critical to help prevent any unwanted issues during +SoC bringup and software development in general. + +Building the Linux kernel for ARC processors +############################################ + +The process of kernel building for ARC processors is the same as for any other +architecture and could be done in 2 ways: + +1. cross-compilation: process of compiling for ARC targets on a development +host with a different processor architecture (generally x86_64/amd64). + +2. native compilation: process of compiling for ARC on a ARC platform +(hardware board or a simulator like QEMU) with complete development environment +(GNU toolchain, dtc, make etc) installed on the platform. + +In both cases, up-to-date GNU toolchain for ARC for the host is needed. +Synopsys offers prebuilt toolchain releases which can be used for this purpose, +available from: + +1. Synopsys GNU toolchain releases: +``_ +2. Linux kernel compilers collection: +``_ +3. Bootlin's toolchain collection: ``_ + +Once the toolchain is installed in the system, make sure its "bin" folder +is added in your ``PATH`` environment variable. Then set ``ARCH=arc`` & +``CROSS_COMPILE=arc-linux`` (or whatever matches installed ARC toolchain prefix) +and then as usual ``make defconfig && make``. + +This will produce "vmlinux" file in the root of the kernel source tree +usable for loading on the target system via JTAG. +If you need to get an image usable with U-Boot bootloader, +type ``make uImage`` and ``uImage`` will be produced in ``arch/arc/boot`` +folder. diff --git a/Documentation/arc/features.rst b/Documentation/arc/features.rst new file mode 100644 index 0000000000000..b793583d688a4 --- /dev/null +++ b/Documentation/arc/features.rst @@ -0,0 +1,3 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. kernel-feat:: $srctree/Documentation/features arc diff --git a/Documentation/arc/index.rst b/Documentation/arc/index.rst new file mode 100644 index 0000000000000..7b098d4a5e3eb --- /dev/null +++ b/Documentation/arc/index.rst @@ -0,0 +1,17 @@ +=================== +ARC architecture +=================== + +.. toctree:: + :maxdepth: 1 + + arc + + features + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/arch.rst b/Documentation/arch.rst index f10bd32a5972e..14bcd8294b93f 100644 --- a/Documentation/arch.rst +++ b/Documentation/arch.rst @@ -9,6 +9,7 @@ implementation. .. toctree:: :maxdepth: 2 + arc/index arm/index arm64/index ia64/index diff --git a/MAINTAINERS b/MAINTAINERS index 7a2345ce85213..811505d9b8302 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18291,6 +18291,7 @@ M: Vineet Gupta L: linux-snps-arc@lists.infradead.org S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc.git +F: Documentation/arc/ F: Documentation/devicetree/bindings/arc/* F: Documentation/devicetree/bindings/interrupt-controller/snps,arc* F: arch/arc/ -- GitLab From a09b34ebb0c923ae6726a8d34298907c534c7c49 Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Fri, 12 Nov 2021 10:20:59 +0800 Subject: [PATCH 0240/1112] docs/zh_CN: add pciebus-howto translation Translate .../PCI/pciebus-howto.rst into Chinese. Signed-off-by: Yanteng Si Reviewed-by: Alex Shi Link: https://lore.kernel.org/r/bd22bd2c4c1a9d869dbd69148a7b94b2e33f8e5c.1636683482.git.siyanteng@loongson.cn Signed-off-by: Jonathan Corbet --- .../translations/zh_CN/PCI/index.rst | 2 +- .../translations/zh_CN/PCI/pciebus-howto.rst | 192 ++++++++++++++++++ 2 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 Documentation/translations/zh_CN/PCI/pciebus-howto.rst diff --git a/Documentation/translations/zh_CN/PCI/index.rst b/Documentation/translations/zh_CN/PCI/index.rst index 5c96017e9f41b..d3bb2af773708 100644 --- a/Documentation/translations/zh_CN/PCI/index.rst +++ b/Documentation/translations/zh_CN/PCI/index.rst @@ -22,10 +22,10 @@ Linux PCI总线子系统 :numbered: pci + pciebus-howto Todolist: - pciebus-howto pci-iov-howto msi-howto sysfs-pci diff --git a/Documentation/translations/zh_CN/PCI/pciebus-howto.rst b/Documentation/translations/zh_CN/PCI/pciebus-howto.rst new file mode 100644 index 0000000000000..65c4301f12cd7 --- /dev/null +++ b/Documentation/translations/zh_CN/PCI/pciebus-howto.rst @@ -0,0 +1,192 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. include:: +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/PCI/pciebus-howto.rst + +:翻译: + + 司延腾 Yanteng Si + +:校译: + + + +.. _cn_pciebus-howto: + +=========================== +PCI Express端口总线驱动指南 +=========================== + +:作者: Tom L Nguyen tom.l.nguyen@intel.com 11/03/2004 +:版权: |copy| 2004 Intel Corporation + +关于本指南 +========== + +本指南介绍了PCI Express端口总线驱动程序的基本知识,并提供了如何使服务驱 +动程序在PCI Express端口总线驱动程序中注册/取消注册的介绍。 + + +什么是PCI Express端口总线驱动程序 +================================= + +一个PCI Express端口是一个逻辑的PCI-PCI桥结构。有两种类型的PCI Express端 +口:根端口和交换端口。根端口从PCI Express根综合体发起一个PCI Express链接, +交换端口将PCI Express链接连接到内部逻辑PCI总线。交换机端口,其二级总线代表 +交换机的内部路由逻辑,被称为交换机的上行端口。交换机的下行端口是从交换机的内部 +路由总线桥接到代表来自PCI Express交换机的下游PCI Express链接的总线。 + +一个PCI Express端口可以提供多达四个不同的功能,在本文中被称为服务,这取决于 +其端口类型。PCI Express端口的服务包括本地热拔插支持(HP)、电源管理事件支持(PME)、 +高级错误报告支持(AER)和虚拟通道支持(VC)。这些服务可以由一个复杂的驱动程序 +处理,也可以单独分布并由相应的服务驱动程序处理。 + +为什么要使用PCI Express端口总线驱动程序? +========================================= + +在现有的Linux内核中,Linux设备驱动模型允许一个物理设备只由一个驱动处理。 +PCI Express端口是一个具有多个不同服务的PCI-PCI桥设备。为了保持一个干净和简 +单的解决方案,每个服务都可以有自己的软件服务驱动。在这种情况下,几个服务驱动将 +竞争一个PCI-PCI桥设备。例如,如果PCI Express根端口的本机热拔插服务驱动程序 +首先被加载,它就会要求一个PCI-PCI桥根端口。因此,内核不会为该根端口加载其他服 +务驱动。换句话说,使用当前的驱动模型,不可能让多个服务驱动同时加载并运行在 +PCI-PCI桥设备上。 + +为了使多个服务驱动程序同时运行,需要有一个PCI Express端口总线驱动程序,它管 +理所有填充的PCI Express端口,并根据需要将所有提供的服务请求分配给相应的服务 +驱动程序。下面列出了使用PCI Express端口总线驱动程序的一些关键优势: + + - 允许在一个PCI-PCI桥接端口设备上同时运行多个服务驱动。 + + - 允许以独立的分阶段方式实施服务驱动程序。 + + - 允许一个服务驱动程序在多个PCI-PCI桥接端口设备上运行。 + + - 管理和分配PCI-PCI桥接端口设备的资源给要求的服务驱动程序。 + +配置PCI Express端口总线驱动程序与服务驱动程序 +============================================= + +将PCI Express端口总线驱动支持纳入内核 +------------------------------------- + +包括PCI Express端口总线驱动程序取决于内核配置中是否包含PCI Express支持。当内核 +中的PCI Express支持被启用时,内核将自动包含PCI Express端口总线驱动程序作为内核 +驱动程序。 + +启用服务驱动支持 +---------------- + +PCI设备驱动是基于Linux设备驱动模型实现的。所有的服务驱动都是PCI设备驱动。如上所述, +一旦内核加载了PCI Express端口总线驱动程序,就不可能再加载任何服务驱动程序。为了满 +足PCI Express端口总线驱动程序模型,需要对现有的服务驱动程序进行一些最小的改变,其 +对现有的服务驱动程序的功能没有影响。 + +服务驱动程序需要使用下面所示的两个API,将其服务注册到PCI Express端口总线驱动程 +序中(见第5.2.1和5.2.2节)。在调用这些API之前,服务驱动程序必须初始化头文件 +/include/linux/pcieport_if.h中的pcie_port_service_driver数据结构。如果不这 +样做,将导致身份不匹配,从而使PCI Express端口总线驱动程序无法加载服务驱动程序。 + +pcie_port_service_register +~~~~~~~~~~~~~~~~~~~~~~~~~~ +:: + + int pcie_port_service_register(struct pcie_port_service_driver *new) + +这个API取代了Linux驱动模型的 pci_register_driver API。一个服务驱动应该总是在模 +块启动时调用 pcie_port_service_register。请注意,在服务驱动被加载后,诸如 +pci_enable_device(dev) 和 pci_set_master(dev) 的调用不再需要,因为这些调用由 +PCI端口总线驱动执行。 + +pcie_port_service_unregister +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +:: + + void pcie_port_service_unregister(struct pcie_port_service_driver *new) + +pcie_port_service_unregister取代了Linux驱动模型的pci_unregister_driver。当一 +个模块退出时,它总是被服务驱动调用。 + +示例代码 +~~~~~~~~ + +下面是服务驱动代码示例,用于初始化端口服务的驱动程序数据结构。 +:: + + static struct pcie_port_service_id service_id[] = { { + .vendor = PCI_ANY_ID, + .device = PCI_ANY_ID, + .port_type = PCIE_RC_PORT, + .service_type = PCIE_PORT_SERVICE_AER, + }, { /* end: all zeroes */ } + }; + + static struct pcie_port_service_driver root_aerdrv = { + .name = (char *)device_name, + .id_table = &service_id[0], + + .probe = aerdrv_load, + .remove = aerdrv_unload, + + .suspend = aerdrv_suspend, + .resume = aerdrv_resume, + }; + +下面是一个注册/取消注册服务驱动的示例代码。 +:: + + static int __init aerdrv_service_init(void) + { + int retval = 0; + + retval = pcie_port_service_register(&root_aerdrv); + if (!retval) { + /* + * FIX ME + */ + } + return retval; + } + + static void __exit aerdrv_service_exit(void) + { + pcie_port_service_unregister(&root_aerdrv); + } + + module_init(aerdrv_service_init); + module_exit(aerdrv_service_exit); + +可能的资源冲突 +============== + +由于PCI-PCI桥接端口设备的所有服务驱动被允许同时运行,下面列出了一些可能的资源冲突和 +建议的解决方案。 + +MSI 和 MSI-X 向量资源 +--------------------- + +一旦设备上的MSI或MSI-X中断被启用,它就会一直保持这种模式,直到它们再次被禁用。由于同 +一个PCI-PCI桥接端口的服务驱动程序共享同一个物理设备,如果一个单独的服务驱动程序启用或 +禁用MSI/MSI-X模式,可能会导致不可预知的行为。 + +为了避免这种情况,所有的服务驱动程序都不允许在其设备上切换中断模式。PCI Express端口 +总线驱动程序负责确定中断模式,这对服务驱动程序来说应该是透明的。服务驱动程序只需要知道 +分配给结构体pcie_device的字段irq的向量IRQ,当PCI Express端口总线驱动程序探测每 +个服务驱动程序时,它被传入。服务驱动应该使用(struct pcie_device*)dev->irq来调用 +request_irq/free_irq。此外,中断模式被存储在struct pcie_device的interrupt_mode +字段中。 + +PCI内存/IO映射的区域 +-------------------- + +PCI Express电源管理(PME)、高级错误报告(AER)、热插拔(HP)和虚拟通道(VC)的服务 +驱动程序访问PCI Express端口的PCI配置空间。在所有情况下,访问的寄存器是相互独立的。这 +个补丁假定所有的服务驱动程序都会表现良好,不会覆盖其他服务驱动程序的配置设置。 + +PCI配置寄存器 +------------- + +每个服务驱动都在自己的功能结构体上运行PCI配置操作,除了PCI Express功能结构体,其中根控制 +寄存器和设备控制寄存器是在PME和AER之间共享。这个补丁假定所有的服务驱动都会表现良好,不会 +覆盖其他服务驱动的配置设置。 -- GitLab From d5b78edb5898613470a4f2928d4e474cd91e8832 Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Fri, 12 Nov 2021 10:21:00 +0800 Subject: [PATCH 0241/1112] docs/zh_CN: add pci-iov-howto translation Translate .../PCI/pci-iov-howto.rst into Chinese. Signed-off-by: Yanteng Si Reviewed-by: Alex Shi Link: https://lore.kernel.org/r/4c67e3a0ab6c8fe12b97adb924f079d7425d40c5.1636683482.git.siyanteng@loongson.cn Signed-off-by: Jonathan Corbet --- .../translations/zh_CN/PCI/index.rst | 3 +- .../translations/zh_CN/PCI/pci-iov-howto.rst | 170 ++++++++++++++++++ 2 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 Documentation/translations/zh_CN/PCI/pci-iov-howto.rst diff --git a/Documentation/translations/zh_CN/PCI/index.rst b/Documentation/translations/zh_CN/PCI/index.rst index d3bb2af773708..67860b7e5ac7b 100644 --- a/Documentation/translations/zh_CN/PCI/index.rst +++ b/Documentation/translations/zh_CN/PCI/index.rst @@ -23,10 +23,11 @@ Linux PCI总线子系统 pci pciebus-howto + pci-iov-howto Todolist: - pci-iov-howto + msi-howto sysfs-pci acpi-info diff --git a/Documentation/translations/zh_CN/PCI/pci-iov-howto.rst b/Documentation/translations/zh_CN/PCI/pci-iov-howto.rst new file mode 100644 index 0000000000000..fbc83dfdcead0 --- /dev/null +++ b/Documentation/translations/zh_CN/PCI/pci-iov-howto.rst @@ -0,0 +1,170 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. include:: +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/PCI/pci-iov-howto.rst + +:翻译: + + 司延腾 Yanteng Si + +:校译: + + + +.. _cn_pci-iov-howto: + +========================== +PCI Express I/O 虚拟化指南 +========================== + +:版权: |copy| 2009 Intel Corporation +:作者: - Yu Zhao + - Donald Dutile + +概述 +==== + +什么是SR-IOV +------------ + +单根I/O虚拟化(SR-IOV)是一种PCI Express扩展功能,它使一个物理设备显示为多个 +虚拟设备。物理设备被称为物理功能(PF),而虚拟设备被称为虚拟功能(VF)。VF的分 +配可以由PF通过封装在该功能中的寄存器动态控制。默认情况下,该功能未被启用,PF表 +现为传统的PCIe设备。一旦开启,每个VF的PCI配置空间都可以通过自己的总线、设备和 +功能编号(路由ID)来访问。而且每个VF也有PCI内存空间,用于映射其寄存器集。VF设 +备驱动程序对寄存器集进行操作,这样它就可以发挥功能,并作为一个真正的现有PCI设备 +出现。 + +使用指南 +======== + +我怎样才能启用SR-IOV功能 +------------------------ + +有多种方法可用于SR-IOV的启用。在第一种方法中,设备驱动(PF驱动)将通过SR-IOV +核心提供的API控制功能的启用和禁用。如果硬件具有SR-IOV能力,加载其PF驱动器将启 +用它和与PF相关的所有VF。一些PF驱动需要设置一个模块参数,以确定要启用的VF的数量。 +在第二种方法中,对sysfs文件sriov_numvfs的写入将启用和禁用与PCIe PF相关的VF。 +这种方法实现了每个PF的VF启用/禁用值,而第一种方法则适用于同一设备的所有PF。此外, +PCI SRIOV核心支持确保启用/禁用操作是有效的,以减少同一检查在多个驱动程序中的重 +复,例如,如果启用VF,检查numvfs == 0,确保numvfs <= totalvfs。 +第二种方法是对新的/未来的VF设备的推荐方法。 + +我怎样才能使用虚拟功能 +---------------------- + +在内核中,VF被视为热插拔的PCI设备,所以它们应该能够以与真正的PCI设备相同的方式 +工作。VF需要的设备驱动与普通PCI设备的驱动相同。 + +开发者指南 +========== + +SR-IOV API +---------- + +用来开启SR-IOV功能: + +(a) 对于第一种方法,在驱动程序中:: + + int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn); + +nr_virtfn'是要启用的VF的编号。 + +(b) 对于第二种方法,从sysfs:: + + echo 'nr_virtfn' > \ + /sys/bus/pci/devices//sriov_numvfs + +用来关闭SR-IOV功能: + +(a) 对于第一种方法,在驱动程序中:: + + void pci_disable_sriov(struct pci_dev *dev); + +(b) 对于第二种方法,从sysfs:: + + echo 0 > \ + /sys/bus/pci/devices//sriov_numvfs + +要想通过主机上的兼容驱动启用自动探测VF,在启用SR-IOV功能之前运行下面的命令。这 +是默认的行为。 +:: + + echo 1 > \ + /sys/bus/pci/devices//sriov_drivers_autoprobe + +要禁止主机上的兼容驱动自动探测VF,请在启用SR-IOV功能之前运行以下命令。更新这个 +入口不会影响已经被探测的VF。 +:: + + echo 0 > \ + /sys/bus/pci/devices//sriov_drivers_autoprobe + +用例 +---- + +下面的代码演示了SR-IOV API的用法 +:: + + static int dev_probe(struct pci_dev *dev, const struct pci_device_id *id) + { + pci_enable_sriov(dev, NR_VIRTFN); + + ... + + return 0; + } + + static void dev_remove(struct pci_dev *dev) + { + pci_disable_sriov(dev); + + ... + } + + static int dev_suspend(struct pci_dev *dev, pm_message_t state) + { + ... + + return 0; + } + + static int dev_resume(struct pci_dev *dev) + { + ... + + return 0; + } + + static void dev_shutdown(struct pci_dev *dev) + { + ... + } + + static int dev_sriov_configure(struct pci_dev *dev, int numvfs) + { + if (numvfs > 0) { + ... + pci_enable_sriov(dev, numvfs); + ... + return numvfs; + } + if (numvfs == 0) { + .... + pci_disable_sriov(dev); + ... + return 0; + } + } + + static struct pci_driver dev_driver = { + .name = "SR-IOV Physical Function driver", + .id_table = dev_id_table, + .probe = dev_probe, + .remove = dev_remove, + .suspend = dev_suspend, + .resume = dev_resume, + .shutdown = dev_shutdown, + .sriov_configure = dev_sriov_configure, + }; -- GitLab From 274f4df3bf09a28a64970834650a1b1f8ad640a4 Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Mon, 22 Nov 2021 15:40:28 +0800 Subject: [PATCH 0242/1112] docs/zh_CN: move sparse into dev-tools ../zh_CN/saprse.txt is alone at here, let's move it to ../zh_CN/dev-tools/sparse.rst. Signed-off-by: Yanteng Si Reviewed-by: Alex Shi Link: https://lore.kernel.org/r/0f1182add7afe4e3b42398353a823d1b4dcf5147.1637565886.git.siyanteng@loongson.cn Signed-off-by: Jonathan Corbet --- Documentation/translations/zh_CN/dev-tools/index.rst | 2 +- .../translations/zh_CN/{sparse.txt => dev-tools/sparse.rst} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename Documentation/translations/zh_CN/{sparse.txt => dev-tools/sparse.rst} (100%) diff --git a/Documentation/translations/zh_CN/dev-tools/index.rst b/Documentation/translations/zh_CN/dev-tools/index.rst index 0f770b8664e9a..77a8c44cdf49a 100644 --- a/Documentation/translations/zh_CN/dev-tools/index.rst +++ b/Documentation/translations/zh_CN/dev-tools/index.rst @@ -22,13 +22,13 @@ Documentation/translations/zh_CN/dev-tools/testing-overview.rst :maxdepth: 2 testing-overview + sparse gcov kasan Todolist: - coccinelle - - sparse - kcov - ubsan - kmemleak diff --git a/Documentation/translations/zh_CN/sparse.txt b/Documentation/translations/zh_CN/dev-tools/sparse.rst similarity index 100% rename from Documentation/translations/zh_CN/sparse.txt rename to Documentation/translations/zh_CN/dev-tools/sparse.rst -- GitLab From f5a46e9de65f31877ab9250f65e3de0caf3b4a37 Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Mon, 22 Nov 2021 15:40:29 +0800 Subject: [PATCH 0243/1112] docs/zh_CN: update sparse translation Sparse documents are too outdated,let's update sparse.rst to the latest version. Signed-off-by: Yanteng Si Reviewed-by: Alex Shi Link: https://lore.kernel.org/r/497c334954afc0190d5531716d273925baedfff2.1637565886.git.siyanteng@loongson.cn Signed-off-by: Jonathan Corbet --- .../translations/zh_CN/dev-tools/sparse.rst | 67 ++++++++++++------- 1 file changed, 42 insertions(+), 25 deletions(-) diff --git a/Documentation/translations/zh_CN/dev-tools/sparse.rst b/Documentation/translations/zh_CN/dev-tools/sparse.rst index 0f444b83d6395..556282437aad9 100644 --- a/Documentation/translations/zh_CN/dev-tools/sparse.rst +++ b/Documentation/translations/zh_CN/dev-tools/sparse.rst @@ -1,34 +1,34 @@ -Chinese translated version of Documentation/dev-tools/sparse.rst +Copyright 2004 Linus Torvalds +Copyright 2004 Pavel Machek +Copyright 2006 Bob Copeland -If you have any comment or update to the content, please contact the -original document maintainer directly. However, if you have a problem -communicating in English you can also ask the Chinese maintainer for -help. Contact the Chinese maintainer if this translation is outdated -or if there is a problem with the translation. +.. include:: ../disclaimer-zh_CN.rst -Chinese maintainer: Li Yang ---------------------------------------------------------------------- -Documentation/dev-tools/sparse.rst 的中文翻译 +:Original: Documentation/dev-tools/sparse.rst -如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文 -交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻 -译存在问题,请联系中文版维护者。 +:翻译: -中文版维护者: 李阳 Li Yang -中文版翻译者: 李阳 Li Yang + Li Yang +:校译: -以下为正文 ---------------------------------------------------------------------- + 司延腾 Yanteng Si -Copyright 2004 Linus Torvalds -Copyright 2004 Pavel Machek -Copyright 2006 Bob Copeland +.. _cn_sparse: + +Sparse +====== + +Sparse是一个C程序的语义检查器;它可以用来发现内核代码的一些潜在问题。 关 +于sparse的概述,请参见https://lwn.net/Articles/689907/;本文档包含 +一些针对内核的sparse信息。 +关于sparse的更多信息,主要是关于它的内部结构,可以在它的官方网页上找到: +https://sparse.docs.kernel.org。 使用 sparse 工具做类型检查 ~~~~~~~~~~~~~~~~~~~~~~~~~~ -"__bitwise" 是一种类型属性,所以你应该这样使用它: +"__bitwise" 是一种类型属性,所以你应该这样使用它:: typedef int __bitwise pm_request_t; @@ -48,7 +48,7 @@ Copyright 2006 Bob Copeland 坦白来说,你并不需要使用枚举类型。上面那些实际都可以浓缩成一个特殊的"int __bitwise"类型。 -所以更简单的办法只要这样做: +所以更简单的办法只要这样做:: typedef int __bitwise pm_request_t; @@ -60,25 +60,42 @@ __bitwise"类型。 一个小提醒:常数整数"0"是特殊的。你可以直接把常数零当作位方式整数使用而 不用担心 sparse 会抱怨。这是因为"bitwise"(恰如其名)是用来确保不同位方 式类型不会被弄混(小尾模式,大尾模式,cpu尾模式,或者其他),对他们来说 -常数"0"确实是特殊的。 +常数"0"确实 **是** 特殊的。 + +使用sparse进行锁检查 +-------------------- + +下面的宏对于 gcc 来说是未定义的,在 sparse 运行时定义,以使用sparse的“上下文” +跟踪功能,应用于锁定。 这些注释告诉 sparse 什么时候有锁,以及注释的函数的进入和 +退出。 + +__must_hold - 指定的锁在函数进入和退出时被持有。 + +__acquires - 指定的锁在函数退出时被持有,但在进入时不被持有。 + +__releases - 指定的锁在函数进入时被持有,但在退出时不被持有。 + +如果函数在不持有锁的情况下进入和退出,在函数内部以平衡的方式获取和释放锁,则不 +需要注释。 +上面的三个注释是针对sparse否则会报告上下文不平衡的情况。 获取 sparse 工具 ~~~~~~~~~~~~~~~~ 你可以从 Sparse 的主页获取最新的发布版本: - http://www.kernel.org/pub/linux/kernel/people/josh/sparse/ + https://www.kernel.org/pub/software/devel/sparse/dist/ 或者,你也可以使用 git 克隆最新的 sparse 开发版本: - git://git.kernel.org/pub/scm/linux/kernel/git/josh/sparse.git + git://git.kernel.org/pub/scm/devel/sparse/sparse.git 一旦你下载了源码,只要以普通用户身份运行: make make install -它将会被自动安装到你的 ~/bin 目录下。 +如果是标准的用户,它将会被自动安装到你的~/bin目录下。 使用 sparse 工具 ~~~~~~~~~~~~~~~~ -- GitLab From c4c5509006f91763fb0600a518a25346de2b011d Mon Sep 17 00:00:00 2001 From: Ahmed Zaki Date: Sun, 28 Nov 2021 10:17:19 -0700 Subject: [PATCH 0244/1112] Doc: networking: Fix the title's Sphinx overline in rds.rst A missing "=" caused the title and sections to not show up properly in the htmldocs. Signed-off-by: Ahmed Zaki Link: https://lore.kernel.org/r/20211128171719.3286255-1-anzaki@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/networking/rds.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/networking/rds.rst b/Documentation/networking/rds.rst index 44936c27ab3af..498395f5fbcbe 100644 --- a/Documentation/networking/rds.rst +++ b/Documentation/networking/rds.rst @@ -1,6 +1,6 @@ .. SPDX-License-Identifier: GPL-2.0 -== +=== RDS === -- GitLab From 065db2d90c6b8384c9072fe55f01c3eeda16c3c0 Mon Sep 17 00:00:00 2001 From: Yang Yang Date: Mon, 29 Nov 2021 06:51:14 +0000 Subject: [PATCH 0245/1112] docs/zh_CN: Add zh_CN/accounting/taskstats.rst Add translation zh_CN/accounting/taskstats.rst and links it to zh_CN/accounting/index.rst while clean its todo entry. Signed-off-by: Yang Yang Reviewed-by: Alex Shi Reviewed-by: Yanteng Si Link: https://lore.kernel.org/r/20211129065113.306748-1-yang.yang29@zte.com.cn [jc: removed excess RST label] Signed-off-by: Jonathan Corbet --- .../translations/zh_CN/accounting/index.rst | 2 +- .../zh_CN/accounting/taskstats.rst | 145 ++++++++++++++++++ 2 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 Documentation/translations/zh_CN/accounting/taskstats.rst diff --git a/Documentation/translations/zh_CN/accounting/index.rst b/Documentation/translations/zh_CN/accounting/index.rst index 362e907b41f9b..124b590fb01bb 100644 --- a/Documentation/translations/zh_CN/accounting/index.rst +++ b/Documentation/translations/zh_CN/accounting/index.rst @@ -16,10 +16,10 @@ :maxdepth: 1 psi + taskstats Todolist: cgroupstats delay-accounting - taskstats taskstats-struct diff --git a/Documentation/translations/zh_CN/accounting/taskstats.rst b/Documentation/translations/zh_CN/accounting/taskstats.rst new file mode 100644 index 0000000000000..307ac5ce0e4b1 --- /dev/null +++ b/Documentation/translations/zh_CN/accounting/taskstats.rst @@ -0,0 +1,145 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/accounting/taskstats.rst + +:Translator: Yang Yang + +================ +每任务的统计接口 +================ + +Taskstats是一个基于netlink的接口,用于从内核向用户空间发送每任务及每进程的 +统计信息。 + +Taskstats设计目的: + +- 在任务生命周期内和退出时高效的提供统计信息 +- 统一不同计数子系统的接口 +- 支持未来计数系统的扩展 + +术语 +---- + +“pid”、“tid”、“任务”互换使用,用于描述由struct task_struct定义的标准 +Linux任务。“每pid的统计数据”等价于“每任务的统计数据”。 + +“tgid”、“进程”、“线程组”互换使用,用于描述共享mm_struct的任务集, +也就是传统的Unix进程。尽管使用了tgid这个词,即使一个任务是线程组组长, +对它的处理也没有什么不同。只要一个进程还有任何归属它的任务,它就被认为 +活着。 + +用法 +---- + +为了在任务生命周期内获得统计信息,用户空间需打开一个单播的netlink套接字 +(NETLINK_GENERIC族)然后发送指定pid或tgid的命令。响应消息中包含单个 +任务的统计信息(若指定了pid)或进程所有任务汇总的统计信息(若指定了tgid)。 + +为了在任务退出时获取统计信息,用户空间的监听者发送一个指定cpu掩码的注册命令。 +cpu掩码内的cpu上有任务退出时,每pid的统计信息将发送给注册成功的监听者。使用 +cpu掩码可以限制一个监听者收到的数据,并有助于对netlink接口进行流量控制,后文 +将进行更详细的解释。 + +如果正在退出的任务是线程组中最后一个退出的线程,额外一条包含每tgid统计信息的 +记录也将发送给用户空间。后者包含线程组中所有线程(包括过去和现在)的每pid统计 +信息总和。 + +getdelays.c是一个简单的示例,用以演示如何使用taskstats接口获取延迟统计信息。 +用户可注册cpu掩码、发送命令和处理响应、监听每tid/tgid退出数据、将收到的数据 +写入文件、通过增大接收缓冲区进行基本的流量控制。 + +接口 +---- + +内核用户接口封装在include/linux/taskstats.h。 + +为避免本文档随着接口的演进而过期,本文仅给出当前版本的概要。当本文与taskstats.h +不一致时,以taskstats.h为准。 + +struct taskstats是每pid和每tgid数据共用的计数结构体。它是版本化的,可在内核新增 +计数子系统时进行扩展。taskstats.h中定义了各字段及语义。 + +用户、内核空间的数据交换是属于NETLINK_GENERIC族的netlink消息,使用netlink属性 +接口。消息格式如下:: + + +----------+- - -+-------------+-------------------+ + | nlmsghdr | Pad | genlmsghdr | taskstats payload | + +----------+- - -+-------------+-------------------+ + +Taskstats载荷有三种类型: + +1. 命令:由用户发送给内核。获取指定pid/tgid数据的命令包含一个类型为 +TASKSTATS_CMD_ATTR_PID/TGID的属性,该属性包含u32的pid或tgid载荷。 +pid/tgid指示用户空间要统计的任务/进程。 + +注册/注销获取指定cpu集上退出数据的命令包含一个类型为 +TASKSTATS_CMD_ATTR_REGISTER/DEREGISTER_CPUMASK的属性,该属性包含cpu掩码载荷。 +cpu掩码是以ascii码表示,用逗号分隔的cpu范围。例如若需监听1,2,3,5,7,8号cpu的 +退出数据,cpu掩码表示为"1-3,5,7-8"。若用户空间在关闭监听套接字前忘了注销监听 +的cpu集,随着时间的推移,内核会清理此监听集。但是,出于提效的目的,建议明确 +执行注销。 + +2. 命令的应答:内核发出应答用户空间的命令。载荷有三类属性: + +a) TASKSTATS_TYPE_AGGR_PID/TGID: 本属性不包含载荷,用以指示其后为被统计对象 +的pig/tgid。 + +b) TASKSTATS_TYPE_PID/TGID:本属性的载荷为pig/tgid,其统计信息将被返回。 + +c) TASKSTATS_TYPE_STATS:本属性的载荷为一个struct taskstats实例。每pid和 +每tgid统计信息共用该结构体。 + +3. 内核会在任务退出时发送新消息。其载荷包含一系列以下类型的属性: + +a) TASKSTATS_TYPE_AGGR_PID:指示其后两个属性为pid+stats。 +b) TASKSTATS_TYPE_PID:包含退出任务的pid。 +c) TASKSTATS_TYPE_STATS:包含退出任务的每pid统计信息 +d) TASKSTATS_TYPE_AGGR_TGID:指示其后两个属性为tgid+stats。 +e) TASKSTATS_TYPE_TGID:包含任务所属进程的tgid +f) TASKSTATS_TYPE_STATS:包含退出任务所属进程的每tgid统计信息 + +每tgid的统计 +------------ + +除了每任务的统计信息,taskstats还提供每进程的统计信息,因为资源管理通常以进程 +粒度完成,并且仅在用户空间聚合任务统计信息效率低下且可能不准确(缺乏原子性)。 + +然而,除了每任务统计信息,在内核中维护每进程统计信息存在额外的时间和空间开销。 +为解决此问题,taskstats代码将退出任务的统计信息累积到进程范围的数据结构中。 +当进程最后一个任务退出时,累积的进程级数据也会发送到用户空间(与每任务数据一起)。 + +当用户查询每tgid数据时,内核将指定线程组中所有活动线程的统计信息相加,并添加到 +该线程组的累积总数(含之前退出的线程)。 + +扩展taskstats +------------- + +有两种方法可在未来修改内核扩展taskstats接口,以导出更多的每任务/进程统计信息: + +1. 在现有struct taskstats末尾增加字段。该结构体中的版本号确保了向后兼容性。 +用户空间将仅使用与其版本对应的结构体字段。 + +2. 定义单独的统计结构体并使用netlink属性接口返回对应的数据。由于用户空间独立 +处理每个netlink属性,所以总是可以忽略其不理解类型的属性(因为使用了旧版本接口)。 + +在1.和2.之间进行选择,属于权衡灵活性和开销的问题。若仅需增加少数字段,那么1.是 +首选方法,因为内核和用户空间无需承担处理新netlink属性的开销。但若新字段过多的 +扩展现有结构体,导致不同的用户空间计数程序不必要的接收大型结构体,而对结构体 +字段并不感兴趣,那么2.是值得的。 + +Taskstats的流量控制 +------------------- + +当退出任务数速率变大,监听者可能跟不上内核发送每tid/tgid退出数据的速率,而导致 +数据丢失。taskstats结构体变大、cpu数量上升,都会导致这种可能性增加。 + +为避免统计信息丢失,用户空间应执行以下操作中至少一项: + +- 增大监听者用于接收退出数据的netlink套接字接收缓存区。 + +- 创建更多的监听者,减少每个监听者监听的cpu数量。极端情况下可为每个cpu创建 + 一个监听者。用户还可考虑将监听者的cpu亲和性设置为监听cpu的子集,特别是当他们 + 仅监听一个cpu。 + +尽管采取了这些措施,若用户空间仍收到指示接收缓存区溢出的ENOBUFS错误消息, +则应采取其他措施处理数据丢失。 -- GitLab From 502ce10704d7fb53e8d41bbadbbdd4814d7c9b52 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Thu, 18 Nov 2021 22:02:04 +0100 Subject: [PATCH 0246/1112] dt-bindings: power: supply: pm8941-charger: add pm8226 The charger in PM8226 (used in MSM8226) is similar to the charger in PM8941. Signed-off-by: Luca Weiss Acked-by: Rob Herring Signed-off-by: Sebastian Reichel --- .../devicetree/bindings/power/supply/qcom,pm8941-charger.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/power/supply/qcom,pm8941-charger.yaml b/Documentation/devicetree/bindings/power/supply/qcom,pm8941-charger.yaml index bc8904872d1b8..caeff68c66d5e 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom,pm8941-charger.yaml +++ b/Documentation/devicetree/bindings/power/supply/qcom,pm8941-charger.yaml @@ -11,7 +11,9 @@ maintainers: properties: compatible: - const: qcom,pm8941-charger + enum: + - qcom,pm8226-charger + - qcom,pm8941-charger reg: maxItems: 1 -- GitLab From 0838a3bfcd1b0c8d2ce38afcc94b81920486dabd Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Thu, 18 Nov 2021 22:02:05 +0100 Subject: [PATCH 0247/1112] power: supply: qcom_smbb: support pm8226 PM8226 (used in MSM8226) has v1 smbb hardware and works fine with the current driver. Signed-off-by: Luca Weiss Signed-off-by: Sebastian Reichel --- drivers/power/supply/qcom_smbb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/qcom_smbb.c b/drivers/power/supply/qcom_smbb.c index 84cc9fba029d5..bd50124eef9fe 100644 --- a/drivers/power/supply/qcom_smbb.c +++ b/drivers/power/supply/qcom_smbb.c @@ -863,8 +863,8 @@ static int smbb_charger_probe(struct platform_device *pdev) } chg->revision += 1; - if (chg->revision != 2 && chg->revision != 3) { - dev_err(&pdev->dev, "v1 hardware not supported\n"); + if (chg->revision != 1 && chg->revision != 2 && chg->revision != 3) { + dev_err(&pdev->dev, "v%d hardware not supported\n", chg->revision); return -ENODEV; } dev_info(&pdev->dev, "Initializing SMBB rev %u", chg->revision); @@ -1012,6 +1012,7 @@ static int smbb_charger_remove(struct platform_device *pdev) } static const struct of_device_id smbb_charger_id_table[] = { + { .compatible = "qcom,pm8226-charger" }, { .compatible = "qcom,pm8941-charger" }, { } }; -- GitLab From 24f0853228f3b98f1ef08d5824376c69bb8124d2 Mon Sep 17 00:00:00 2001 From: Adam Ward Date: Mon, 29 Nov 2021 22:10:12 +0000 Subject: [PATCH 0248/1112] regulator: da9121: Prevent current limit change when enabled Prevent changing current limit when enabled as a precaution against possibile instability due to tight integration with switching cycle Signed-off-by: Adam Ward Link: https://lore.kernel.org/r/52ee682476004a1736c1e0293358987319c1c415.1638223185.git.Adam.Ward.opensource@diasemi.com Signed-off-by: Mark Brown --- drivers/regulator/da9121-regulator.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/regulator/da9121-regulator.c b/drivers/regulator/da9121-regulator.c index a5a83b772a854..86149170bf6cd 100644 --- a/drivers/regulator/da9121-regulator.c +++ b/drivers/regulator/da9121-regulator.c @@ -253,6 +253,11 @@ static int da9121_set_current_limit(struct regulator_dev *rdev, goto error; } + if (rdev->desc->ops->is_enabled(rdev)) { + ret = -EBUSY; + goto error; + } + ret = da9121_ceiling_selector(rdev, min_ua, max_ua, &sel); if (ret < 0) goto error; -- GitLab From c5187a245e9bb0af2da8d37ede191569c824c66b Mon Sep 17 00:00:00 2001 From: Adam Ward Date: Mon, 29 Nov 2021 22:10:13 +0000 Subject: [PATCH 0249/1112] regulator: da9121: Add DA914x support Add the DA9141 and DA9142 regulators device recognition data and operational parameters. Signed-off-by: Adam Ward Link: https://lore.kernel.org/r/5f5b9b02f07578cd36c6bc266349a56efc9b08d1.1638223185.git.Adam.Ward.opensource@diasemi.com Signed-off-by: Mark Brown --- drivers/regulator/da9121-regulator.c | 108 ++++++++++++++++++++++++++- drivers/regulator/da9121-regulator.h | 21 +++++- 2 files changed, 124 insertions(+), 5 deletions(-) diff --git a/drivers/regulator/da9121-regulator.c b/drivers/regulator/da9121-regulator.c index 86149170bf6cd..6f21223a488e5 100644 --- a/drivers/regulator/da9121-regulator.c +++ b/drivers/regulator/da9121-regulator.c @@ -86,6 +86,22 @@ static struct da9121_range da9121_3A_1phase_current = { .reg_max = 6, }; +static struct da9121_range da914x_40A_4phase_current = { + .val_min = 14000000, + .val_max = 80000000, + .val_stp = 2000000, + .reg_min = 1, + .reg_max = 14, +}; + +static struct da9121_range da914x_20A_2phase_current = { + .val_min = 7000000, + .val_max = 40000000, + .val_stp = 2000000, + .reg_min = 1, + .reg_max = 14, +}; + struct da9121_variant_info { int num_bucks; int num_phases; @@ -97,6 +113,8 @@ static const struct da9121_variant_info variant_parameters[] = { { 2, 1, &da9121_3A_1phase_current }, //DA9121_TYPE_DA9220_DA9132 { 2, 1, &da9121_5A_1phase_current }, //DA9121_TYPE_DA9122_DA9131 { 1, 2, &da9121_6A_2phase_current }, //DA9121_TYPE_DA9217 + { 1, 4, &da914x_40A_4phase_current }, //DA9121_TYPE_DA9141 + { 1, 2, &da914x_20A_2phase_current }, //DA9121_TYPE_DA9142 }; struct da9121_field { @@ -542,11 +560,65 @@ static const struct regulator_desc da9217_reg = { .vsel_mask = DA9121_MASK_BUCK_BUCKx_5_CHx_A_VOUT, }; +#define DA914X_MIN_MV 500 +#define DA914X_MAX_MV 1000 +#define DA914X_STEP_MV 10 +#define DA914X_MIN_SEL (DA914X_MIN_MV / DA914X_STEP_MV) +#define DA914X_N_VOLTAGES (((DA914X_MAX_MV - DA914X_MIN_MV) / DA914X_STEP_MV) \ + + 1 + DA914X_MIN_SEL) + +static const struct regulator_desc da9141_reg = { + .id = DA9121_IDX_BUCK1, + .name = "DA9141", + .of_match = "buck1", + .of_parse_cb = da9121_of_parse_cb, + .owner = THIS_MODULE, + .regulators_node = of_match_ptr("regulators"), + .of_map_mode = da9121_map_mode, + .ops = &da9121_buck_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = DA914X_N_VOLTAGES, + .min_uV = DA914X_MIN_MV * 1000, + .uV_step = DA914X_STEP_MV * 1000, + .linear_min_sel = DA914X_MIN_SEL, + .vsel_reg = DA9121_REG_BUCK_BUCK1_5, + .vsel_mask = DA9121_MASK_BUCK_BUCKx_5_CHx_A_VOUT, + .enable_reg = DA9121_REG_BUCK_BUCK1_0, + .enable_mask = DA9121_MASK_BUCK_BUCKx_0_CHx_EN, + /* Default value of BUCK_BUCK1_0.CH1_SRC_DVC_UP */ + .ramp_delay = 20000, + /* tBUCK_EN */ + .enable_time = 20, +}; + +static const struct regulator_desc da9142_reg = { + .id = DA9121_IDX_BUCK1, + .name = "DA9142 BUCK1", + .of_match = "buck1", + .of_parse_cb = da9121_of_parse_cb, + .owner = THIS_MODULE, + .regulators_node = of_match_ptr("regulators"), + .of_map_mode = da9121_map_mode, + .ops = &da9121_buck_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = DA914X_N_VOLTAGES, + .min_uV = DA914X_MIN_MV * 1000, + .uV_step = DA914X_STEP_MV * 1000, + .linear_min_sel = DA914X_MIN_SEL, + .enable_reg = DA9121_REG_BUCK_BUCK1_0, + .enable_mask = DA9121_MASK_BUCK_BUCKx_0_CHx_EN, + .vsel_reg = DA9121_REG_BUCK_BUCK1_5, + .vsel_mask = DA9121_MASK_BUCK_BUCKx_5_CHx_A_VOUT, +}; + + static const struct regulator_desc *local_da9121_regulators[][DA9121_IDX_MAX] = { [DA9121_TYPE_DA9121_DA9130] = { &da9121_reg, NULL }, [DA9121_TYPE_DA9220_DA9132] = { &da9220_reg[0], &da9220_reg[1] }, [DA9121_TYPE_DA9122_DA9131] = { &da9122_reg[0], &da9122_reg[1] }, [DA9121_TYPE_DA9217] = { &da9217_reg, NULL }, + [DA9121_TYPE_DA9141] = { &da9141_reg, NULL }, + [DA9121_TYPE_DA9142] = { &da9142_reg, NULL }, }; static void da9121_status_poll_on(struct work_struct *work) @@ -840,7 +912,7 @@ static int da9121_check_device_type(struct i2c_client *i2c, struct da9121 *chip) goto error; } - if (device_id != DA9121_DEVICE_ID) { + if ((device_id != DA9121_DEVICE_ID) && (device_id != DA914x_DEVICE_ID)) { dev_err(chip->dev, "Invalid device ID: 0x%02x\n", device_id); ret = -ENODEV; goto error; @@ -882,6 +954,22 @@ static int da9121_check_device_type(struct i2c_client *i2c, struct da9121 *chip) break; } + if (device_id == DA914x_DEVICE_ID) { + switch (chip->subvariant_id) { + case DA9121_SUBTYPE_DA9141: + type = "DA9141"; + config_match = (variant_vrc == DA9141_VARIANT_VRC); + break; + case DA9121_SUBTYPE_DA9142: + type = "DA9142"; + config_match = (variant_vrc == DA9142_VARIANT_VRC); + break; + default: + type = "Unknown"; + break; + } + } + dev_info(chip->dev, "Device detected (device-ID: 0x%02X, var-ID: 0x%02X, %s)\n", device_id, variant_id, type); @@ -895,8 +983,10 @@ static int da9121_check_device_type(struct i2c_client *i2c, struct da9121 *chip) variant_mrc = (variant_id & DA9121_MASK_OTP_VARIANT_ID_MRC) >> DA9121_SHIFT_OTP_VARIANT_ID_MRC; - if ((device_id == DA9121_DEVICE_ID) && - (variant_mrc < DA9121_VARIANT_MRC_BASE)) { + if (((device_id == DA9121_DEVICE_ID) && + (variant_mrc < DA9121_VARIANT_MRC_BASE)) || + ((device_id == DA914x_DEVICE_ID) && + (variant_mrc != DA914x_VARIANT_MRC_BASE))) { dev_err(chip->dev, "Cannot support variant MRC: 0x%02X\n", variant_mrc); ret = -EINVAL; @@ -936,6 +1026,14 @@ static int da9121_assign_chip_model(struct i2c_client *i2c, chip->variant_id = DA9121_TYPE_DA9220_DA9132; regmap = &da9121_2ch_regmap_config; break; + case DA9121_SUBTYPE_DA9141: + chip->variant_id = DA9121_TYPE_DA9141; + regmap = &da9121_1ch_regmap_config; + break; + case DA9121_SUBTYPE_DA9142: + chip->variant_id = DA9121_TYPE_DA9142; + regmap = &da9121_2ch_regmap_config; + break; } /* Set these up for of_regulator_match call which may want .of_map_modes */ @@ -1015,6 +1113,8 @@ static const struct of_device_id da9121_dt_ids[] = { { .compatible = "dlg,da9131", .data = (void *) DA9121_SUBTYPE_DA9131 }, { .compatible = "dlg,da9220", .data = (void *) DA9121_SUBTYPE_DA9220 }, { .compatible = "dlg,da9132", .data = (void *) DA9121_SUBTYPE_DA9132 }, + { .compatible = "dlg,da9141", .data = (void *) DA9121_SUBTYPE_DA9141 }, + { .compatible = "dlg,da9142", .data = (void *) DA9121_SUBTYPE_DA9142 }, { } }; MODULE_DEVICE_TABLE(of, da9121_dt_ids); @@ -1089,6 +1189,8 @@ static const struct i2c_device_id da9121_i2c_id[] = { {"da9131", DA9121_TYPE_DA9122_DA9131}, {"da9220", DA9121_TYPE_DA9220_DA9132}, {"da9132", DA9121_TYPE_DA9220_DA9132}, + {"da9141", DA9121_TYPE_DA9141}, + {"da9142", DA9121_TYPE_DA9142}, {}, }; MODULE_DEVICE_TABLE(i2c, da9121_i2c_id); diff --git a/drivers/regulator/da9121-regulator.h b/drivers/regulator/da9121-regulator.h index 357f416e17c1d..a328a0bdfa29e 100644 --- a/drivers/regulator/da9121-regulator.h +++ b/drivers/regulator/da9121-regulator.h @@ -26,7 +26,9 @@ enum da9121_variant { DA9121_TYPE_DA9121_DA9130, DA9121_TYPE_DA9220_DA9132, DA9121_TYPE_DA9122_DA9131, - DA9121_TYPE_DA9217 + DA9121_TYPE_DA9217, + DA9121_TYPE_DA9141, + DA9121_TYPE_DA9142 }; enum da9121_subvariant { @@ -36,7 +38,9 @@ enum da9121_subvariant { DA9121_SUBTYPE_DA9132, DA9121_SUBTYPE_DA9122, DA9121_SUBTYPE_DA9131, - DA9121_SUBTYPE_DA9217 + DA9121_SUBTYPE_DA9217, + DA9121_SUBTYPE_DA9141, + DA9121_SUBTYPE_DA9142 }; /* Minimum, maximum and default polling millisecond periods are provided @@ -70,6 +74,14 @@ enum da9121_subvariant { #define DA9121_REG_SYS_GPIO1_1 0x13 #define DA9121_REG_SYS_GPIO2_0 0x14 #define DA9121_REG_SYS_GPIO2_1 0x15 +#define DA914x_REG_SYS_GPIO3_0 0x16 +#define DA914x_REG_SYS_GPIO3_1 0x17 +#define DA914x_REG_SYS_GPIO4_0 0x18 +#define DA914x_REG_SYS_GPIO4_1 0x19 +#define DA914x_REG_SYS_ADMUX1_0 0x1A +#define DA914x_REG_SYS_ADMUX1_1 0x1B +#define DA914x_REG_SYS_ADMUX2_0 0x1C +#define DA914x_REG_SYS_ADMUX2_1 0x1D #define DA9121_REG_BUCK_BUCK1_0 0x20 #define DA9121_REG_BUCK_BUCK1_1 0x21 #define DA9121_REG_BUCK_BUCK1_2 0x22 @@ -276,6 +288,7 @@ enum da9121_subvariant { #define DA9121_MASK_OTP_DEVICE_ID_DEV_ID 0xFF #define DA9121_DEVICE_ID 0x05 +#define DA914x_DEVICE_ID 0x26 /* DA9121_REG_OTP_VARIANT_ID */ @@ -293,6 +306,10 @@ enum da9121_subvariant { #define DA9131_VARIANT_VRC 0x1 #define DA9132_VARIANT_VRC 0x2 +#define DA914x_VARIANT_MRC_BASE 0x0 +#define DA9141_VARIANT_VRC 0x1 +#define DA9142_VARIANT_VRC 0x2 + /* DA9121_REG_OTP_CUSTOMER_ID */ #define DA9121_MASK_OTP_CUSTOMER_ID_CUST_ID 0xFF -- GitLab From b9c044b7d63b2ffae9664349721c80c4ab3e56c9 Mon Sep 17 00:00:00 2001 From: Adam Ward Date: Mon, 29 Nov 2021 22:10:10 +0000 Subject: [PATCH 0250/1112] regulator: da9121: Remove erroneous compatible from binding Clean away information from a test that was included accidentally Signed-off-by: Adam Ward Acked-by: Rob Herring Link: https://lore.kernel.org/r/530a626cee6bc12ff5b4ab16319ac7a1fac6e306.1638223185.git.Adam.Ward.opensource@diasemi.com Signed-off-by: Mark Brown --- .../bindings/regulator/dlg,da9121.yaml | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/Documentation/devicetree/bindings/regulator/dlg,da9121.yaml b/Documentation/devicetree/bindings/regulator/dlg,da9121.yaml index 228018c87bea8..0aee5fcd60937 100644 --- a/Documentation/devicetree/bindings/regulator/dlg,da9121.yaml +++ b/Documentation/devicetree/bindings/regulator/dlg,da9121.yaml @@ -25,19 +25,19 @@ description: | the rated current, this translates across the device range to per channel figures as so... - | DA9121 DA9122 DA9220 DA9217 DA9140 + | DA9121 DA9122 DA9220 DA9217 | /DA9130 /DA9131 /DA9132 - ----------------------------------------------------------------------------- - Output current / channel | 10000000 5000000 3000000 6000000 40000000 - Output current / phase | 5000000 5000000 3000000 3000000 9500000 - ----------------------------------------------------------------------------- - Min regulator-min-microvolt| 300000 300000 300000 300000 500000 - Max regulator-max-microvolt| 1900000 1900000 1900000 1900000 1000000 - Device hardware default | 1000000 1000000 1000000 1000000 1000000 - ----------------------------------------------------------------------------- - Min regulator-min-microamp | 7000000 3500000 3500000 7000000 26000000 - Max regulator-max-microamp | 20000000 10000000 6000000 12000000 78000000 - Device hardware default | 15000000 7500000 5500000 11000000 58000000 + ------------------------------------------------------------------- + Output current / channel | 10000000 5000000 3000000 6000000 + Output current / phase | 5000000 5000000 3000000 3000000 + ------------------------------------------------------------------- + Min regulator-min-microvolt| 300000 300000 300000 300000 + Max regulator-max-microvolt| 1900000 1900000 1900000 1900000 + Device hardware default | 1000000 1000000 1000000 1000000 + ------------------------------------------------------------------- + Min regulator-min-microamp | 7000000 3500000 3500000 7000000 + Max regulator-max-microamp | 20000000 10000000 6000000 12000000 + Device hardware default | 15000000 7500000 5500000 11000000 properties: $nodename: @@ -51,7 +51,6 @@ properties: - dlg,da9130 - dlg,da9131 - dlg,da9132 - - dlg,da9140 reg: maxItems: 1 -- GitLab From d07fef2fcd4d79198a700f4b4d2ca4670649c9ff Mon Sep 17 00:00:00 2001 From: Adam Ward Date: Mon, 29 Nov 2021 22:10:11 +0000 Subject: [PATCH 0251/1112] regulator: da9121: Add DA914x binding info Add the configuration for the DA9141 and DA9142 regulators. Also tidy the table, cleaning away superfluous information. Signed-off-by: Adam Ward Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/9293e3ae4ff8776704257085df65516b81209b87.1638223185.git.Adam.Ward.opensource@diasemi.com Signed-off-by: Mark Brown --- .../bindings/regulator/dlg,da9121.yaml | 75 +++++++++++-------- 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/Documentation/devicetree/bindings/regulator/dlg,da9121.yaml b/Documentation/devicetree/bindings/regulator/dlg,da9121.yaml index 0aee5fcd60937..24ace6e1e5ec6 100644 --- a/Documentation/devicetree/bindings/regulator/dlg,da9121.yaml +++ b/Documentation/devicetree/bindings/regulator/dlg,da9121.yaml @@ -17,27 +17,39 @@ description: | Dialog Semiconductor DA9130 Single-channel 10A double-phase buck converter Dialog Semiconductor DA9131 Double-channel 5A single-phase buck converter Dialog Semiconductor DA9132 Double-channel 3A single-phase buck converter - - Current limits - - This is PER PHASE, and the current limit setting in the devices reflect - that with a maximum 10A limit. Allowing for transients at/near double - the rated current, this translates across the device range to per - channel figures as so... - - | DA9121 DA9122 DA9220 DA9217 - | /DA9130 /DA9131 /DA9132 - ------------------------------------------------------------------- - Output current / channel | 10000000 5000000 3000000 6000000 - Output current / phase | 5000000 5000000 3000000 3000000 - ------------------------------------------------------------------- - Min regulator-min-microvolt| 300000 300000 300000 300000 - Max regulator-max-microvolt| 1900000 1900000 1900000 1900000 - Device hardware default | 1000000 1000000 1000000 1000000 - ------------------------------------------------------------------- - Min regulator-min-microamp | 7000000 3500000 3500000 7000000 - Max regulator-max-microamp | 20000000 10000000 6000000 12000000 - Device hardware default | 15000000 7500000 5500000 11000000 + Dialog Semiconductor DA9141 Single-channel 40A quad-phase buck converter + Dialog Semiconductor DA9142 Single-channel 20A double-phase buck converter + + Device parameter ranges + + The current limits can be set to at/near double the rated current per channel + to allow for transient peaks. + Current limit changes when the output is enabled are not supported, as a + precaution against undefined behaviour. + + |----------------------------------------------| + | | range & reset default value | + | Device |------------------------------| + | | microvolt | microamp | + |----------------------------------------------| + | DA9121/DA9130 | Min: 300000 | Min: 7000000 | + | | Max: 1900000 | Max: 20000000 | + |----------------------------------------------| + | DA9121/DA9131 | Min: 300000 | Min: 3500000 | + | | Max: 1900000 | Max: 10000000 | + |----------------------------------------------| + | DA9121/DA9131 | Min: 300000 | Min: 3500000 | + | | Max: 1900000 | Max: 6000000 | + |----------------------------------------------| + | DA9217 | Min: 300000 | Min: 7000000 | + | | Max: 1900000 | Max: 12000000 | + |----------------------------------------------| + | DA9141 | Min: 300000 | Min: 26000000 | + | | Max: 1300000 | Max: 78000000 | + |----------------------------------------------| + | DA9142 | Min: 300000 | Min: 13000000 | + | | Max: 1300000 | Max: 39000000 | + |----------------------------------------------| properties: $nodename: @@ -51,6 +63,8 @@ properties: - dlg,da9130 - dlg,da9131 - dlg,da9132 + - dlg,da9141 + - dlg,da9142 reg: maxItems: 1 @@ -69,26 +83,24 @@ properties: regulators: type: object - $ref: regulator.yaml# description: | - This node defines the settings for the BUCK. The content of the - sub-node is defined by the standard binding for regulators; see regulator.yaml. - The DA9121 regulator is bound using their names listed below - buck1 - BUCK1 - buck2 - BUCK2 //DA9122, DA9220, DA9131, DA9132 only + List of regulators provided by the device patternProperties: "^buck([1-2])$": type: object $ref: regulator.yaml# + description: | + Properties for a single BUCK regulator properties: - regulator-mode: - maxItems: 1 - description: Defined in include/dt-bindings/regulator/dlg,da9121-regulator.h + regulator-name: + pattern: "^BUCK([1-2])$" + description: | + BUCK2 present in DA9122, DA9220, DA9131, DA9132 only regulator-initial-mode: - maxItems: 1 + enum: [ 0, 1, 2, 3 ] description: Defined in include/dt-bindings/regulator/dlg,da9121-regulator.h enable-gpios: @@ -97,6 +109,7 @@ properties: dlg,ripple-cancel: $ref: "/schemas/types.yaml#/definitions/uint32" + enum: [ 0, 1, 2, 3 ] description: | Defined in include/dt-bindings/regulator/dlg,da9121-regulator.h Only present on multi-channel devices (DA9122, DA9220, DA9131, DA9132) -- GitLab From ddfe12944e84830fe7dc490992e55b4fa773555e Mon Sep 17 00:00:00 2001 From: Boqun Feng Date: Mon, 25 Oct 2021 22:54:14 +0800 Subject: [PATCH 0252/1112] tools/memory-model: Provide extra ordering for unlock+lock pair on the same CPU A recent discussion[1] shows that we are in favor of strengthening the ordering of unlock + lock on the same CPU: a unlock and a po-after lock should provide the so-called RCtso ordering, that is a memory access S po-before the unlock should be ordered against a memory access R po-after the lock, unless S is a store and R is a load. The strengthening meets programmers' expection that "sequence of two locked regions to be ordered wrt each other" (from Linus), and can reduce the mental burden when using locks. Therefore add it in LKMM. [1]: https://lore.kernel.org/lkml/20210909185937.GA12379@rowland.harvard.edu/ Co-developed-by: Alan Stern Signed-off-by: Alan Stern Signed-off-by: Boqun Feng Reviewed-by: Michael Ellerman (powerpc) Acked-by: Palmer Dabbelt (RISC-V) Acked-by: Peter Zijlstra (Intel) Signed-off-by: Paul E. McKenney --- .../Documentation/explanation.txt | 44 +++++++++++-------- tools/memory-model/linux-kernel.cat | 6 +-- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/tools/memory-model/Documentation/explanation.txt b/tools/memory-model/Documentation/explanation.txt index 5d72f3112e565..394ee57d58f2f 100644 --- a/tools/memory-model/Documentation/explanation.txt +++ b/tools/memory-model/Documentation/explanation.txt @@ -1813,15 +1813,16 @@ spin_trylock() -- we can call these things lock-releases and lock-acquires -- have two properties beyond those of ordinary releases and acquires. -First, when a lock-acquire reads from a lock-release, the LKMM -requires that every instruction po-before the lock-release must -execute before any instruction po-after the lock-acquire. This would -naturally hold if the release and acquire operations were on different -CPUs, but the LKMM says it holds even when they are on the same CPU. -For example: +First, when a lock-acquire reads from or is po-after a lock-release, +the LKMM requires that every instruction po-before the lock-release +must execute before any instruction po-after the lock-acquire. This +would naturally hold if the release and acquire operations were on +different CPUs and accessed the same lock variable, but the LKMM says +it also holds when they are on the same CPU, even if they access +different lock variables. For example: int x, y; - spinlock_t s; + spinlock_t s, t; P0() { @@ -1830,9 +1831,9 @@ For example: spin_lock(&s); r1 = READ_ONCE(x); spin_unlock(&s); - spin_lock(&s); + spin_lock(&t); r2 = READ_ONCE(y); - spin_unlock(&s); + spin_unlock(&t); } P1() @@ -1842,10 +1843,10 @@ For example: WRITE_ONCE(x, 1); } -Here the second spin_lock() reads from the first spin_unlock(), and -therefore the load of x must execute before the load of y. Thus we -cannot have r1 = 1 and r2 = 0 at the end (this is an instance of the -MP pattern). +Here the second spin_lock() is po-after the first spin_unlock(), and +therefore the load of x must execute before the load of y, even though +the two locking operations use different locks. Thus we cannot have +r1 = 1 and r2 = 0 at the end (this is an instance of the MP pattern). This requirement does not apply to ordinary release and acquire fences, only to lock-related operations. For instance, suppose P0() @@ -1872,13 +1873,13 @@ instructions in the following order: and thus it could load y before x, obtaining r2 = 0 and r1 = 1. -Second, when a lock-acquire reads from a lock-release, and some other -stores W and W' occur po-before the lock-release and po-after the -lock-acquire respectively, the LKMM requires that W must propagate to -each CPU before W' does. For example, consider: +Second, when a lock-acquire reads from or is po-after a lock-release, +and some other stores W and W' occur po-before the lock-release and +po-after the lock-acquire respectively, the LKMM requires that W must +propagate to each CPU before W' does. For example, consider: int x, y; - spinlock_t x; + spinlock_t s; P0() { @@ -1908,7 +1909,12 @@ each CPU before W' does. For example, consider: If r1 = 1 at the end then the spin_lock() in P1 must have read from the spin_unlock() in P0. Hence the store to x must propagate to P2 -before the store to y does, so we cannot have r2 = 1 and r3 = 0. +before the store to y does, so we cannot have r2 = 1 and r3 = 0. But +if P1 had used a lock variable different from s, the writes could have +propagated in either order. (On the other hand, if the code in P0 and +P1 had all executed on a single CPU, as in the example before this +one, then the writes would have propagated in order even if the two +critical sections used different lock variables.) These two special requirements for lock-release and lock-acquire do not arise from the operational model. Nevertheless, kernel developers diff --git a/tools/memory-model/linux-kernel.cat b/tools/memory-model/linux-kernel.cat index 2a9b4fe4a84eb..d70315fddef6e 100644 --- a/tools/memory-model/linux-kernel.cat +++ b/tools/memory-model/linux-kernel.cat @@ -27,7 +27,7 @@ include "lock.cat" (* Release Acquire *) let acq-po = [Acquire] ; po ; [M] let po-rel = [M] ; po ; [Release] -let po-unlock-rf-lock-po = po ; [UL] ; rf ; [LKR] ; po +let po-unlock-lock-po = po ; [UL] ; (po|rf) ; [LKR] ; po (* Fences *) let R4rmb = R \ Noreturn (* Reads for which rmb works *) @@ -70,12 +70,12 @@ let rwdep = (dep | ctrl) ; [W] let overwrite = co | fr let to-w = rwdep | (overwrite & int) | (addr ; [Plain] ; wmb) let to-r = addr | (dep ; [Marked] ; rfi) -let ppo = to-r | to-w | fence | (po-unlock-rf-lock-po & int) +let ppo = to-r | to-w | fence | (po-unlock-lock-po & int) (* Propagation: Ordering from release operations and strong fences. *) let A-cumul(r) = (rfe ; [Marked])? ; r let cumul-fence = [Marked] ; (A-cumul(strong-fence | po-rel) | wmb | - po-unlock-rf-lock-po) ; [Marked] + po-unlock-lock-po) ; [Marked] let prop = [Marked] ; (overwrite & ext)? ; cumul-fence* ; [Marked] ; rfe? ; [Marked] -- GitLab From b47c05ecf60bd8743ad8c0ee510d3e1c060529d7 Mon Sep 17 00:00:00 2001 From: Boqun Feng Date: Mon, 25 Oct 2021 22:54:15 +0800 Subject: [PATCH 0253/1112] tools/memory-model: doc: Describe the requirement of the litmus-tests directory It's better that we have some "standard" about which test should be put in the litmus-tests directory because it helps future contributors understand whether they should work on litmus-tests in kernel or Paul's GitHub repo. Therefore explain a little bit on what a "representative" litmus test is. Signed-off-by: Boqun Feng Acked-by: Peter Zijlstra (Intel) Signed-off-by: Paul E. McKenney --- tools/memory-model/README | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tools/memory-model/README b/tools/memory-model/README index 9a84c45504ab6..9edd402704c4f 100644 --- a/tools/memory-model/README +++ b/tools/memory-model/README @@ -195,6 +195,18 @@ litmus-tests are listed in litmus-tests/README. A great deal more litmus tests are available at https://github.com/paulmckrcu/litmus. + By "representative", it means the one in the litmus-tests + directory is: + + 1) simple, the number of threads should be relatively + small and each thread function should be relatively + simple. + 2) orthogonal, there should be no two litmus tests + describing the same aspect of the memory model. + 3) textbook, developers can easily copy-paste-modify + the litmus tests to use the patterns on their own + code. + lock.cat Provides a front-end analysis of lock acquisition and release, for example, associating a lock acquisition with the preceding -- GitLab From c438b7d860b4c1acb4ebff6d8d946d593ca5fe1e Mon Sep 17 00:00:00 2001 From: Boqun Feng Date: Mon, 25 Oct 2021 22:54:16 +0800 Subject: [PATCH 0254/1112] tools/memory-model: litmus: Add two tests for unlock(A)+lock(B) ordering The memory model has been updated to provide a stronger ordering guarantee for unlock(A)+lock(B) on the same CPU/thread. Therefore add two litmus tests describing this new guarantee, these tests are simple yet can clearly show the usage of the new guarantee, also they can serve as the self tests for the modification in the model. Co-developed-by: Alan Stern Signed-off-by: Alan Stern Signed-off-by: Boqun Feng Acked-by: Peter Zijlstra (Intel) Signed-off-by: Paul E. McKenney --- ...LB+unlocklockonceonce+poacquireonce.litmus | 35 +++++++++++++++++++ ...unlocklockonceonce+fencermbonceonce.litmus | 33 +++++++++++++++++ tools/memory-model/litmus-tests/README | 8 +++++ 3 files changed, 76 insertions(+) create mode 100644 tools/memory-model/litmus-tests/LB+unlocklockonceonce+poacquireonce.litmus create mode 100644 tools/memory-model/litmus-tests/MP+unlocklockonceonce+fencermbonceonce.litmus diff --git a/tools/memory-model/litmus-tests/LB+unlocklockonceonce+poacquireonce.litmus b/tools/memory-model/litmus-tests/LB+unlocklockonceonce+poacquireonce.litmus new file mode 100644 index 0000000000000..eb34123a6ffe0 --- /dev/null +++ b/tools/memory-model/litmus-tests/LB+unlocklockonceonce+poacquireonce.litmus @@ -0,0 +1,35 @@ +C LB+unlocklockonceonce+poacquireonce + +(* + * Result: Never + * + * If two locked critical sections execute on the same CPU, all accesses + * in the first must execute before any accesses in the second, even if the + * critical sections are protected by different locks. Note: Even when a + * write executes before a read, their memory effects can be reordered from + * the viewpoint of another CPU (the kind of reordering allowed by TSO). + *) + +{} + +P0(spinlock_t *s, spinlock_t *t, int *x, int *y) +{ + int r1; + + spin_lock(s); + r1 = READ_ONCE(*x); + spin_unlock(s); + spin_lock(t); + WRITE_ONCE(*y, 1); + spin_unlock(t); +} + +P1(int *x, int *y) +{ + int r2; + + r2 = smp_load_acquire(y); + WRITE_ONCE(*x, 1); +} + +exists (0:r1=1 /\ 1:r2=1) diff --git a/tools/memory-model/litmus-tests/MP+unlocklockonceonce+fencermbonceonce.litmus b/tools/memory-model/litmus-tests/MP+unlocklockonceonce+fencermbonceonce.litmus new file mode 100644 index 0000000000000..2feb1398be716 --- /dev/null +++ b/tools/memory-model/litmus-tests/MP+unlocklockonceonce+fencermbonceonce.litmus @@ -0,0 +1,33 @@ +C MP+unlocklockonceonce+fencermbonceonce + +(* + * Result: Never + * + * If two locked critical sections execute on the same CPU, stores in the + * first must propagate to each CPU before stores in the second do, even if + * the critical sections are protected by different locks. + *) + +{} + +P0(spinlock_t *s, spinlock_t *t, int *x, int *y) +{ + spin_lock(s); + WRITE_ONCE(*x, 1); + spin_unlock(s); + spin_lock(t); + WRITE_ONCE(*y, 1); + spin_unlock(t); +} + +P1(int *x, int *y) +{ + int r1; + int r2; + + r1 = READ_ONCE(*y); + smp_rmb(); + r2 = READ_ONCE(*x); +} + +exists (1:r1=1 /\ 1:r2=0) diff --git a/tools/memory-model/litmus-tests/README b/tools/memory-model/litmus-tests/README index 681f9067fa9ed..d311a0ff1ae64 100644 --- a/tools/memory-model/litmus-tests/README +++ b/tools/memory-model/litmus-tests/README @@ -63,6 +63,10 @@ LB+poonceonces.litmus As above, but with store-release replaced with WRITE_ONCE() and load-acquire replaced with READ_ONCE(). +LB+unlocklockonceonce+poacquireonce.litmus + Does a unlock+lock pair provides ordering guarantee between a + load and a store? + MP+onceassign+derefonce.litmus As below, but with rcu_assign_pointer() and an rcu_dereference(). @@ -90,6 +94,10 @@ MP+porevlocks.litmus As below, but with the first access of the writer process and the second access of reader process protected by a lock. +MP+unlocklockonceonce+fencermbonceonce.litmus + Does a unlock+lock pair provides ordering guarantee between a + store and another store? + MP+fencewmbonceonce+fencermbonceonce.litmus Does a smp_wmb() (between the stores) and an smp_rmb() (between the loads) suffice for the message-passing litmus test, where one -- GitLab From 4f45348934074553681a8964bae740a22599cf2e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 25 Nov 2021 16:20:43 +0100 Subject: [PATCH 0255/1112] dt-bindings: gpio: sifive,gpio: Group interrupt tuples To improve human readability and enable automatic validation, the tuples in "interrupts" properties should be grouped using angle brackets. Signed-off-by: Geert Uytterhoeven Acked-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- Documentation/devicetree/bindings/gpio/sifive,gpio.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/gpio/sifive,gpio.yaml b/Documentation/devicetree/bindings/gpio/sifive,gpio.yaml index c2902aac25145..e04349567eebb 100644 --- a/Documentation/devicetree/bindings/gpio/sifive,gpio.yaml +++ b/Documentation/devicetree/bindings/gpio/sifive,gpio.yaml @@ -77,7 +77,8 @@ examples: gpio@10060000 { compatible = "sifive,fu540-c000-gpio", "sifive,gpio0"; interrupt-parent = <&plic>; - interrupts = <7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22>; + interrupts = <7>, <8>, <9>, <10>, <11>, <12>, <13>, <14>, <15>, <16>, + <17>, <18>, <19>, <20>, <21>, <22>; reg = <0x10060000 0x1000>; clocks = <&tlclk PRCI_CLK_TLCLK>; gpio-controller; -- GitLab From 82b2cd4c8caebf0b61b39daf5e0ed6be170a4ae1 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 30 Nov 2021 16:08:37 -0600 Subject: [PATCH 0256/1112] gpio: pch: Use .driver_data instead of checking Device IDs again Previously, pch_gpio_probe() tested the Device ID to determine the type of IOH. But the driver core has already matched the Device ID with one of the IDs in the pch_gpio_pcidev_id[] table, and we can supply the IOH type there as .driver_data. Use the pci_device_id.driver_data to learn the IOH type instead of testing the Device ID again. No functional change intended. Signed-off-by: Bjorn Helgaas Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-pch.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index a552df298a974..625920421990b 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -368,14 +368,7 @@ static int pch_gpio_probe(struct pci_dev *pdev, } chip->base = pcim_iomap_table(pdev)[1]; - - if (pdev->device == 0x8803) - chip->ioh = INTEL_EG20T_PCH; - else if (pdev->device == 0x8014) - chip->ioh = OKISEMI_ML7223m_IOH; - else if (pdev->device == 0x8043) - chip->ioh = OKISEMI_ML7223n_IOH; - + chip->ioh = id->driver_data; chip->reg = chip->base; pci_set_drvdata(pdev, chip); spin_lock_init(&chip->spinlock); @@ -439,10 +432,14 @@ static int __maybe_unused pch_gpio_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(pch_gpio_pm_ops, pch_gpio_suspend, pch_gpio_resume); static const struct pci_device_id pch_gpio_pcidev_id[] = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8803) }, - { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8014) }, - { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8043) }, - { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8803) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8803), + .driver_data = INTEL_EG20T_PCH }, + { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8014), + .driver_data = OKISEMI_ML7223m_IOH }, + { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8043), + .driver_data = OKISEMI_ML7223n_IOH }, + { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8803), + .driver_data = INTEL_EG20T_PCH }, { 0, } }; MODULE_DEVICE_TABLE(pci, pch_gpio_pcidev_id); -- GitLab From 2822b02765ed0609825d3532ea15de3914b59f09 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 30 Nov 2021 16:08:38 -0600 Subject: [PATCH 0257/1112] gpio: pch: Cache &pdev->dev to reduce repetition pch_gpio_probe() repeats the "&pdev->dev" expression several times. Cache the result as "struct device *dev" to reduce the repetition. No functional change intended. Signed-off-by: Bjorn Helgaas Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-pch.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 625920421990b..3a0bd87957419 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -346,24 +346,25 @@ static int pch_gpio_alloc_generic_chip(struct pch_gpio *chip, static int pch_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id) { + struct device *dev = &pdev->dev; s32 ret; struct pch_gpio *chip; int irq_base; - chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; - chip->dev = &pdev->dev; + chip->dev = dev; ret = pcim_enable_device(pdev); if (ret) { - dev_err(&pdev->dev, "pci_enable_device FAILED"); + dev_err(dev, "pci_enable_device FAILED"); return ret; } ret = pcim_iomap_regions(pdev, BIT(1), KBUILD_MODNAME); if (ret) { - dev_err(&pdev->dev, "pci_request_regions FAILED-%d", ret); + dev_err(dev, "pci_request_regions FAILED-%d", ret); return ret; } @@ -374,16 +375,16 @@ static int pch_gpio_probe(struct pci_dev *pdev, spin_lock_init(&chip->spinlock); pch_gpio_setup(chip); - ret = devm_gpiochip_add_data(&pdev->dev, &chip->gpio, chip); + ret = devm_gpiochip_add_data(dev, &chip->gpio, chip); if (ret) { - dev_err(&pdev->dev, "PCH gpio: Failed to register GPIO\n"); + dev_err(dev, "PCH gpio: Failed to register GPIO\n"); return ret; } - irq_base = devm_irq_alloc_descs(&pdev->dev, -1, 0, + irq_base = devm_irq_alloc_descs(dev, -1, 0, gpio_pins[chip->ioh], NUMA_NO_NODE); if (irq_base < 0) { - dev_warn(&pdev->dev, "PCH gpio: Failed to get IRQ base num\n"); + dev_warn(dev, "PCH gpio: Failed to get IRQ base num\n"); chip->irq_base = -1; return 0; } @@ -393,10 +394,10 @@ static int pch_gpio_probe(struct pci_dev *pdev, iowrite32(BIT(gpio_pins[chip->ioh]) - 1, &chip->reg->imask); iowrite32(BIT(gpio_pins[chip->ioh]) - 1, &chip->reg->ien); - ret = devm_request_irq(&pdev->dev, pdev->irq, pch_gpio_handler, + ret = devm_request_irq(dev, pdev->irq, pch_gpio_handler, IRQF_SHARED, KBUILD_MODNAME, chip); if (ret) { - dev_err(&pdev->dev, "request_irq failed\n"); + dev_err(dev, "request_irq failed\n"); return ret; } -- GitLab From 06939f22ae5f7abf80d9a6ff5e43b4a916256f44 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 30 Nov 2021 16:08:39 -0600 Subject: [PATCH 0258/1112] gpio: ml-ioh: Cache &pdev->dev to reduce repetition ioh_gpio_probe() repeats the "&pdev->dev" expression several times. Cache the result as "struct device *dev" to reduce the repetition. No functional change intended. Signed-off-by: Bjorn Helgaas Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-ml-ioh.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index efa9acdc320a1..4e9528dd11529 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -401,6 +401,7 @@ static int ioh_gpio_alloc_generic_chip(struct ioh_gpio *chip, static int ioh_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id) { + struct device *dev = &pdev->dev; int ret; int i, j; struct ioh_gpio *chip; @@ -410,19 +411,19 @@ static int ioh_gpio_probe(struct pci_dev *pdev, ret = pci_enable_device(pdev); if (ret) { - dev_err(&pdev->dev, "%s : pci_enable_device failed", __func__); + dev_err(dev, "%s : pci_enable_device failed", __func__); goto err_pci_enable; } ret = pci_request_regions(pdev, KBUILD_MODNAME); if (ret) { - dev_err(&pdev->dev, "pci_request_regions failed-%d", ret); + dev_err(dev, "pci_request_regions failed-%d", ret); goto err_request_regions; } base = pci_iomap(pdev, 1, 0); if (!base) { - dev_err(&pdev->dev, "%s : pci_iomap failed", __func__); + dev_err(dev, "%s : pci_iomap failed", __func__); ret = -ENOMEM; goto err_iomap; } @@ -435,7 +436,7 @@ static int ioh_gpio_probe(struct pci_dev *pdev, chip = chip_save; for (i = 0; i < 8; i++, chip++) { - chip->dev = &pdev->dev; + chip->dev = dev; chip->base = base; chip->reg = chip->base; chip->ch = i; @@ -443,17 +444,17 @@ static int ioh_gpio_probe(struct pci_dev *pdev, ioh_gpio_setup(chip, num_ports[i]); ret = gpiochip_add_data(&chip->gpio, chip); if (ret) { - dev_err(&pdev->dev, "IOH gpio: Failed to register GPIO\n"); + dev_err(dev, "IOH gpio: Failed to register GPIO\n"); goto err_gpiochip_add; } } chip = chip_save; for (j = 0; j < 8; j++, chip++) { - irq_base = devm_irq_alloc_descs(&pdev->dev, -1, IOH_IRQ_BASE, + irq_base = devm_irq_alloc_descs(dev, -1, IOH_IRQ_BASE, num_ports[j], NUMA_NO_NODE); if (irq_base < 0) { - dev_warn(&pdev->dev, + dev_warn(dev, "ml_ioh_gpio: Failed to get IRQ base num\n"); ret = irq_base; goto err_gpiochip_add; @@ -467,11 +468,10 @@ static int ioh_gpio_probe(struct pci_dev *pdev, } chip = chip_save; - ret = devm_request_irq(&pdev->dev, pdev->irq, ioh_gpio_handler, + ret = devm_request_irq(dev, pdev->irq, ioh_gpio_handler, IRQF_SHARED, KBUILD_MODNAME, chip); if (ret != 0) { - dev_err(&pdev->dev, - "%s request_irq failed\n", __func__); + dev_err(dev, "%s request_irq failed\n", __func__); goto err_gpiochip_add; } @@ -498,7 +498,7 @@ err_request_regions: err_pci_enable: - dev_err(&pdev->dev, "%s Failed returns %d\n", __func__, ret); + dev_err(dev, "%s Failed returns %d\n", __func__, ret); return ret; } -- GitLab From 46155a0c55eb9c64da619e4f3a03537f47fbe583 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 30 Nov 2021 16:08:40 -0600 Subject: [PATCH 0259/1112] gpio: ml-ioh: Use BIT() to match gpio-pch.c The ML IOH driver is very similar to the PCH driver. To make it more similar, replace "1 << nr" with "BIT(nr)". No functional change intended. Signed-off-by: Bjorn Helgaas Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-ml-ioh.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index 4e9528dd11529..0fb9c8bc9b2d0 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -98,9 +98,9 @@ static void ioh_gpio_set(struct gpio_chip *gpio, unsigned nr, int val) spin_lock_irqsave(&chip->spinlock, flags); reg_val = ioread32(&chip->reg->regs[chip->ch].po); if (val) - reg_val |= (1 << nr); + reg_val |= BIT(nr); else - reg_val &= ~(1 << nr); + reg_val &= ~BIT(nr); iowrite32(reg_val, &chip->reg->regs[chip->ch].po); spin_unlock_irqrestore(&chip->spinlock, flags); @@ -110,7 +110,7 @@ static int ioh_gpio_get(struct gpio_chip *gpio, unsigned nr) { struct ioh_gpio *chip = gpiochip_get_data(gpio); - return !!(ioread32(&chip->reg->regs[chip->ch].pi) & (1 << nr)); + return !!(ioread32(&chip->reg->regs[chip->ch].pi) & BIT(nr)); } static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, @@ -123,15 +123,15 @@ static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, spin_lock_irqsave(&chip->spinlock, flags); pm = ioread32(&chip->reg->regs[chip->ch].pm) & - ((1 << num_ports[chip->ch]) - 1); - pm |= (1 << nr); + (BIT(num_ports[chip->ch]) - 1); + pm |= BIT(nr); iowrite32(pm, &chip->reg->regs[chip->ch].pm); reg_val = ioread32(&chip->reg->regs[chip->ch].po); if (val) - reg_val |= (1 << nr); + reg_val |= BIT(nr); else - reg_val &= ~(1 << nr); + reg_val &= ~BIT(nr); iowrite32(reg_val, &chip->reg->regs[chip->ch].po); spin_unlock_irqrestore(&chip->spinlock, flags); @@ -147,8 +147,8 @@ static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) spin_lock_irqsave(&chip->spinlock, flags); pm = ioread32(&chip->reg->regs[chip->ch].pm) & - ((1 << num_ports[chip->ch]) - 1); - pm &= ~(1 << nr); + (BIT(num_ports[chip->ch]) - 1); + pm &= ~BIT(nr); iowrite32(pm, &chip->reg->regs[chip->ch].pm); spin_unlock_irqrestore(&chip->spinlock, flags); @@ -304,7 +304,7 @@ static void ioh_irq_unmask(struct irq_data *d) struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct ioh_gpio *chip = gc->private; - iowrite32(1 << (d->irq - chip->irq_base), + iowrite32(BIT(d->irq - chip->irq_base), &chip->reg->regs[chip->ch].imaskclr); } @@ -313,7 +313,7 @@ static void ioh_irq_mask(struct irq_data *d) struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct ioh_gpio *chip = gc->private; - iowrite32(1 << (d->irq - chip->irq_base), + iowrite32(BIT(d->irq - chip->irq_base), &chip->reg->regs[chip->ch].imask); } @@ -326,7 +326,7 @@ static void ioh_irq_disable(struct irq_data *d) spin_lock_irqsave(&chip->spinlock, flags); ien = ioread32(&chip->reg->regs[chip->ch].ien); - ien &= ~(1 << (d->irq - chip->irq_base)); + ien &= ~BIT(d->irq - chip->irq_base); iowrite32(ien, &chip->reg->regs[chip->ch].ien); spin_unlock_irqrestore(&chip->spinlock, flags); } @@ -340,7 +340,7 @@ static void ioh_irq_enable(struct irq_data *d) spin_lock_irqsave(&chip->spinlock, flags); ien = ioread32(&chip->reg->regs[chip->ch].ien); - ien |= 1 << (d->irq - chip->irq_base); + ien |= BIT(d->irq - chip->irq_base); iowrite32(ien, &chip->reg->regs[chip->ch].ien); spin_unlock_irqrestore(&chip->spinlock, flags); } -- GitLab From 7bc14ff2952da56d445efab50256569fc96aa95b Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 30 Nov 2021 16:08:41 -0600 Subject: [PATCH 0260/1112] gpio: ml-ioh: Change whitespace to match gpio-pch.c The ML IOH driver is very similar to the PCH driver. To make it more similar, tweak the whitespace in ioh_gpio_direction_output() and ioh_gpio_direction_input(). No functional change intended. Signed-off-by: Bjorn Helgaas Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-ml-ioh.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index 0fb9c8bc9b2d0..b060c47736989 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -122,8 +122,8 @@ static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, unsigned long flags; spin_lock_irqsave(&chip->spinlock, flags); - pm = ioread32(&chip->reg->regs[chip->ch].pm) & - (BIT(num_ports[chip->ch]) - 1); + pm = ioread32(&chip->reg->regs[chip->ch].pm); + pm &= BIT(num_ports[chip->ch]) - 1; pm |= BIT(nr); iowrite32(pm, &chip->reg->regs[chip->ch].pm); @@ -146,8 +146,8 @@ static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) unsigned long flags; spin_lock_irqsave(&chip->spinlock, flags); - pm = ioread32(&chip->reg->regs[chip->ch].pm) & - (BIT(num_ports[chip->ch]) - 1); + pm = ioread32(&chip->reg->regs[chip->ch].pm); + pm &= BIT(num_ports[chip->ch]) - 1; pm &= ~BIT(nr); iowrite32(pm, &chip->reg->regs[chip->ch].pm); spin_unlock_irqrestore(&chip->spinlock, flags); -- GitLab From e1610431b95ccbada74e1393b0944ef4c2750624 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 30 Nov 2021 18:49:56 +0200 Subject: [PATCH 0261/1112] gpio: dwapb: clarify usage of the register file version First of all, it's obvious that different versions can't be provided simultaneously. Hence, versions can't be bit masks. Second, due to above we have to mask out the version field in the flags and only that can be evaluated against the certain version. Clarify all above by: - introducing GPIO_REG_OFFSET_V1 and GPIO_REG_OFFSET_MASK - replacing conditional to mask out bits and compare to a version Luckily there is no functional change, so no need to backport this. Signed-off-by: Andy Shevchenko Acked-by: Serge Semin Reviewed-by: Bartosz Golaszewski --- drivers/gpio/gpio-dwapb.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index f98fa33e16790..ec0767d7800dc 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -53,7 +53,9 @@ #define GPIO_SWPORT_DR_STRIDE 0x0c /* register stride 3*32 bits */ #define GPIO_SWPORT_DDR_STRIDE 0x0c /* register stride 3*32 bits */ +#define GPIO_REG_OFFSET_V1 0 #define GPIO_REG_OFFSET_V2 1 +#define GPIO_REG_OFFSET_MASK BIT(0) #define GPIO_INTMASK_V2 0x44 #define GPIO_INTTYPE_LEVEL_V2 0x34 @@ -141,7 +143,7 @@ static inline u32 gpio_reg_v2_convert(unsigned int offset) static inline u32 gpio_reg_convert(struct dwapb_gpio *gpio, unsigned int offset) { - if (gpio->flags & GPIO_REG_OFFSET_V2) + if ((gpio->flags & GPIO_REG_OFFSET_MASK) == GPIO_REG_OFFSET_V2) return gpio_reg_v2_convert(offset); return offset; @@ -668,15 +670,15 @@ static int dwapb_get_clks(struct dwapb_gpio *gpio) } static const struct of_device_id dwapb_of_match[] = { - { .compatible = "snps,dw-apb-gpio", .data = (void *)0}, + { .compatible = "snps,dw-apb-gpio", .data = (void *)GPIO_REG_OFFSET_V1}, { .compatible = "apm,xgene-gpio-v2", .data = (void *)GPIO_REG_OFFSET_V2}, { /* Sentinel */ } }; MODULE_DEVICE_TABLE(of, dwapb_of_match); static const struct acpi_device_id dwapb_acpi_match[] = { - {"HISI0181", 0}, - {"APMC0D07", 0}, + {"HISI0181", GPIO_REG_OFFSET_V1}, + {"APMC0D07", GPIO_REG_OFFSET_V1}, {"APMC0D81", GPIO_REG_OFFSET_V2}, { } }; -- GitLab From 7e508f2ca8bbda8cabbd4753bc727a7f66837a12 Mon Sep 17 00:00:00 2001 From: Huang Jianan Date: Sat, 13 Nov 2021 00:09:33 +0800 Subject: [PATCH 0262/1112] erofs: rename lz4_0pading to zero_padding Renaming lz4_0padding to zero_padding globally since LZMA and later algorithms also need that. Link: https://lore.kernel.org/r/20211112160935.19394-1-jnhuang95@gmail.com Reviewed-by: Chao Yu Signed-off-by: Huang Jianan Signed-off-by: Gao Xiang --- fs/erofs/decompressor.c | 4 ++-- fs/erofs/erofs_fs.h | 4 ++-- fs/erofs/internal.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/erofs/decompressor.c b/fs/erofs/decompressor.c index bf37fc76b1824..c373a199c4073 100644 --- a/fs/erofs/decompressor.c +++ b/fs/erofs/decompressor.c @@ -195,8 +195,8 @@ static int z_erofs_lz4_decompress_mem(struct z_erofs_decompress_req *rq, inputmargin = 0; support_0padding = false; - /* decompression inplace is only safe when 0padding is enabled */ - if (erofs_sb_has_lz4_0padding(EROFS_SB(rq->sb))) { + /* decompression inplace is only safe when zero_padding is enabled */ + if (erofs_sb_has_zero_padding(EROFS_SB(rq->sb))) { support_0padding = true; while (!headpage[inputmargin & ~PAGE_MASK]) diff --git a/fs/erofs/erofs_fs.h b/fs/erofs/erofs_fs.h index 083997a034e52..f4506a642a12d 100644 --- a/fs/erofs/erofs_fs.h +++ b/fs/erofs/erofs_fs.h @@ -17,14 +17,14 @@ * Any bits that aren't in EROFS_ALL_FEATURE_INCOMPAT should * be incompatible with this kernel version. */ -#define EROFS_FEATURE_INCOMPAT_LZ4_0PADDING 0x00000001 +#define EROFS_FEATURE_INCOMPAT_ZERO_PADDING 0x00000001 #define EROFS_FEATURE_INCOMPAT_COMPR_CFGS 0x00000002 #define EROFS_FEATURE_INCOMPAT_BIG_PCLUSTER 0x00000002 #define EROFS_FEATURE_INCOMPAT_CHUNKED_FILE 0x00000004 #define EROFS_FEATURE_INCOMPAT_DEVICE_TABLE 0x00000008 #define EROFS_FEATURE_INCOMPAT_COMPR_HEAD2 0x00000008 #define EROFS_ALL_FEATURE_INCOMPAT \ - (EROFS_FEATURE_INCOMPAT_LZ4_0PADDING | \ + (EROFS_FEATURE_INCOMPAT_ZERO_PADDING | \ EROFS_FEATURE_INCOMPAT_COMPR_CFGS | \ EROFS_FEATURE_INCOMPAT_BIG_PCLUSTER | \ EROFS_FEATURE_INCOMPAT_CHUNKED_FILE | \ diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h index 3265688af7f9f..273754e7b3402 100644 --- a/fs/erofs/internal.h +++ b/fs/erofs/internal.h @@ -258,7 +258,7 @@ static inline bool erofs_sb_has_##name(struct erofs_sb_info *sbi) \ return sbi->feature_##compat & EROFS_FEATURE_##feature; \ } -EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_LZ4_0PADDING) +EROFS_FEATURE_FUNCS(zero_padding, incompat, INCOMPAT_ZERO_PADDING) EROFS_FEATURE_FUNCS(compr_cfgs, incompat, INCOMPAT_COMPR_CFGS) EROFS_FEATURE_FUNCS(big_pcluster, incompat, INCOMPAT_BIG_PCLUSTER) EROFS_FEATURE_FUNCS(device_table, incompat, INCOMPAT_DEVICE_TABLE) -- GitLab From fa3b06f59a03a3a4639755478e0cf5b508a1b454 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Wed, 1 Dec 2021 12:55:14 +0530 Subject: [PATCH 0263/1112] regulator: qcom,rpmh: Add compatible for PM8450 Add compatible string for PM8450 used in SM8450 boards. Signed-off-by: Vinod Koul Link: https://lore.kernel.org/r/20211201072515.3968843-2-vkoul@kernel.org Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/qcom,rpmh-regulator.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml index c02f08a7014cc..5c73d3f639c78 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml @@ -43,6 +43,7 @@ description: | For PM8150L, smps1 - smps8, ldo1 - ldo11, bob, flash, rgb For PM8350, smps1 - smps12, ldo1 - ldo10 For PM8350C, smps1 - smps10, ldo1 - ldo13, bob + For PM8450, smps1 - smps6, ldo1 - ldo4 For PM8998, smps1 - smps13, ldo1 - ldo28, lvs1 - lvs2 For PMI8998, bob For PMR735A, smps1 - smps3, ldo1 - ldo7 @@ -62,6 +63,7 @@ properties: - qcom,pm8150l-rpmh-regulators - qcom,pm8350-rpmh-regulators - qcom,pm8350c-rpmh-regulators + - qcom,pm8450-rpmh-regulators - qcom,pm8998-rpmh-regulators - qcom,pmg1110-rpmh-regulators - qcom,pmi8998-rpmh-regulators -- GitLab From d69e19723f88a3ba6d4e0e52f51dd4c59cc2ae93 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Wed, 1 Dec 2021 12:55:15 +0530 Subject: [PATCH 0264/1112] regulator: qcom-rpmh: Add support for PM8450 regulators Add the rpmh regulators found in PM8450 PMIC Signed-off-by: Vinod Koul Tested-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20211201072515.3968843-3-vkoul@kernel.org Signed-off-by: Mark Brown --- drivers/regulator/qcom-rpmh-regulator.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index 684143c828a56..a3bc0eb6ceb8c 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -974,6 +974,20 @@ static const struct rpmh_vreg_init_data pm8350c_vreg_data[] = { {} }; +static const struct rpmh_vreg_init_data pm8450_vreg_data[] = { + RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps520, "vdd-s1"), + RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps520, "vdd-s2"), + RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps520, "vdd-s3"), + RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps520, "vdd-s4"), + RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps520, "vdd-s5"), + RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps520, "vdd-s6"), + RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1"), + RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2"), + RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"), + RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo_lv, "vdd-l4"), + {} +}; + static const struct rpmh_vreg_init_data pm8009_vreg_data[] = { RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps510, "vdd-s1"), RPMH_VREG("smps2", "smp%s2", &pmic5_hfsmps515, "vdd-s2"), @@ -1218,6 +1232,10 @@ static const struct of_device_id __maybe_unused rpmh_regulator_match_table[] = { .compatible = "qcom,pm8350c-rpmh-regulators", .data = pm8350c_vreg_data, }, + { + .compatible = "qcom,pm8450-rpmh-regulators", + .data = pm8450_vreg_data, + }, { .compatible = "qcom,pm8998-rpmh-regulators", .data = pm8998_vreg_data, -- GitLab From 8762b07c95c18fbbe1c6b3eb1e8e686091c346b5 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Tue, 9 Nov 2021 23:49:09 +0530 Subject: [PATCH 0265/1112] spi: dt-bindings: add schema listing peripheral-specific properties Many SPI controllers need to add properties to peripheral devices. This could be the delay in clock or data lines, etc. These properties are controller specific but need to be defined in the peripheral node because they are per-peripheral and there can be multiple peripherals attached to a controller. If these properties are not added to the peripheral binding, then the dtbs check emits a warning. But these properties do not make much sense in the peripheral binding because they are controller-specific and they will just pollute every peripheral binding. So this binding is added to collect all such properties from all such controllers. Peripheral bindings should simply refer to this binding and they should be rid of the warnings. There are some limitations with this approach. Firstly, there is no way to specify required properties. The schema contains properties for all controllers and there is no way to know which controller is being used. Secondly, there is no way to restrict additional properties. Since this schema will be used with an allOf operator, additionalProperties needs to be true. In addition, the peripheral schema will have to set unevaluatedProperties: false. Despite these limitations, this appears to be the best solution to this problem that doesn't involve modifying existing tools or schema specs. Signed-off-by: Pratyush Yadav Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20211109181911.2251-2-p.yadav@ti.com Signed-off-by: Mark Brown --- .../bindings/spi/spi-controller.yaml | 69 +-------------- .../bindings/spi/spi-peripheral-props.yaml | 87 +++++++++++++++++++ 2 files changed, 89 insertions(+), 67 deletions(-) create mode 100644 Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml diff --git a/Documentation/devicetree/bindings/spi/spi-controller.yaml b/Documentation/devicetree/bindings/spi/spi-controller.yaml index 8246891602e77..36b72518f5654 100644 --- a/Documentation/devicetree/bindings/spi/spi-controller.yaml +++ b/Documentation/devicetree/bindings/spi/spi-controller.yaml @@ -94,73 +94,8 @@ patternProperties: "^.*@[0-9a-f]+$": type: object - properties: - compatible: - description: - Compatible of the SPI device. - - reg: - minItems: 1 - maxItems: 256 - items: - minimum: 0 - maximum: 256 - description: - Chip select used by the device. - - spi-3wire: - $ref: /schemas/types.yaml#/definitions/flag - description: - The device requires 3-wire mode. - - spi-cpha: - $ref: /schemas/types.yaml#/definitions/flag - description: - The device requires shifted clock phase (CPHA) mode. - - spi-cpol: - $ref: /schemas/types.yaml#/definitions/flag - description: - The device requires inverse clock polarity (CPOL) mode. - - spi-cs-high: - $ref: /schemas/types.yaml#/definitions/flag - description: - The device requires the chip select active high. - - spi-lsb-first: - $ref: /schemas/types.yaml#/definitions/flag - description: - The device requires the LSB first mode. - - spi-max-frequency: - $ref: /schemas/types.yaml#/definitions/uint32 - description: - Maximum SPI clocking speed of the device in Hz. - - spi-rx-bus-width: - description: - Bus width to the SPI bus used for read transfers. - If 0 is provided, then no RX will be possible on this device. - $ref: /schemas/types.yaml#/definitions/uint32 - enum: [0, 1, 2, 4, 8] - default: 1 - - spi-rx-delay-us: - description: - Delay, in microseconds, after a read transfer. - - spi-tx-bus-width: - description: - Bus width to the SPI bus used for write transfers. - If 0 is provided, then no TX will be possible on this device. - $ref: /schemas/types.yaml#/definitions/uint32 - enum: [0, 1, 2, 4, 8] - default: 1 - - spi-tx-delay-us: - description: - Delay, in microseconds, after a write transfer. + allOf: + - $ref: spi-peripheral-props.yaml required: - compatible diff --git a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml new file mode 100644 index 0000000000000..105fa2840e72a --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml @@ -0,0 +1,87 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/spi-peripheral-props.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Peripheral-specific properties for a SPI bus. + +description: + Many SPI controllers need to add properties to peripheral devices. They could + be common properties like spi-max-frequency, spi-cpha, etc. or they could be + controller specific like delay in clock or data lines, etc. These properties + need to be defined in the peripheral node because they are per-peripheral and + there can be multiple peripherals attached to a controller. All those + properties are listed here. The controller specific properties should go in + their own separate schema that should be referenced from here. + +maintainers: + - Pratyush Yadav + +properties: + reg: + minItems: 1 + maxItems: 256 + items: + minimum: 0 + maximum: 256 + description: + Chip select used by the device. + + spi-3wire: + $ref: /schemas/types.yaml#/definitions/flag + description: + The device requires 3-wire mode. + + spi-cpha: + $ref: /schemas/types.yaml#/definitions/flag + description: + The device requires shifted clock phase (CPHA) mode. + + spi-cpol: + $ref: /schemas/types.yaml#/definitions/flag + description: + The device requires inverse clock polarity (CPOL) mode. + + spi-cs-high: + $ref: /schemas/types.yaml#/definitions/flag + description: + The device requires the chip select active high. + + spi-lsb-first: + $ref: /schemas/types.yaml#/definitions/flag + description: + The device requires the LSB first mode. + + spi-max-frequency: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Maximum SPI clocking speed of the device in Hz. + + spi-rx-bus-width: + description: + Bus width to the SPI bus used for read transfers. + If 0 is provided, then no RX will be possible on this device. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2, 4, 8] + default: 1 + + spi-rx-delay-us: + description: + Delay, in microseconds, after a read transfer. + + spi-tx-bus-width: + description: + Bus width to the SPI bus used for write transfers. + If 0 is provided, then no TX will be possible on this device. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2, 4, 8] + default: 1 + + spi-tx-delay-us: + description: + Delay, in microseconds, after a write transfer. + +# The controller specific properties go here. + +additionalProperties: true -- GitLab From b6bdc6e043906c70e949b2747772e6aa1d36f2a3 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Tue, 9 Nov 2021 23:49:10 +0530 Subject: [PATCH 0266/1112] spi: dt-bindings: cdns,qspi-nor: Move peripheral-specific properties out The spi-peripheral-props.yaml schema contains peripheral-specific properties for SPI controllers that should be present in the peripheral node. Move peripheral-specific properties to a separate file and refer to it in spi-peripheral-props.yaml. Signed-off-by: Pratyush Yadav Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20211109181911.2251-3-p.yadav@ti.com Signed-off-by: Mark Brown --- .../spi/cdns,qspi-nor-peripheral-props.yaml | 42 +++++++++++++++++++ .../bindings/spi/cdns,qspi-nor.yaml | 33 --------------- .../bindings/spi/spi-peripheral-props.yaml | 2 + 3 files changed, 44 insertions(+), 33 deletions(-) create mode 100644 Documentation/devicetree/bindings/spi/cdns,qspi-nor-peripheral-props.yaml diff --git a/Documentation/devicetree/bindings/spi/cdns,qspi-nor-peripheral-props.yaml b/Documentation/devicetree/bindings/spi/cdns,qspi-nor-peripheral-props.yaml new file mode 100644 index 0000000000000..553601a441a7d --- /dev/null +++ b/Documentation/devicetree/bindings/spi/cdns,qspi-nor-peripheral-props.yaml @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/cdns,qspi-nor-peripheral-props.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Peripheral-specific properties for the Cadence QSPI controller. + +description: + See spi-peripheral-props.yaml for more info. + +maintainers: + - Pratyush Yadav + +properties: + # cdns,qspi-nor.yaml + cdns,read-delay: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Delay for read capture logic, in clock cycles. + + cdns,tshsl-ns: + description: + Delay in nanoseconds for the length that the master mode chip select + outputs are de-asserted between transactions. + + cdns,tsd2d-ns: + description: + Delay in nanoseconds between one chip select being de-activated + and the activation of another. + + cdns,tchsh-ns: + description: + Delay in nanoseconds between last bit of current transaction and + deasserting the device chip select (qspi_n_ss_out). + + cdns,tslch-ns: + description: + Delay in nanoseconds between setting qspi_n_ss_out low and + first bit transfer. + +additionalProperties: true diff --git a/Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml b/Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml index ca155abbda7a3..a439e3ed753f9 100644 --- a/Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml +++ b/Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml @@ -86,39 +86,6 @@ properties: items: enum: [ qspi, qspi-ocp ] -# subnode's properties -patternProperties: - "@[0-9a-f]+$": - type: object - description: - Flash device uses the below defined properties in the subnode. - - properties: - cdns,read-delay: - $ref: /schemas/types.yaml#/definitions/uint32 - description: - Delay for read capture logic, in clock cycles. - - cdns,tshsl-ns: - description: - Delay in nanoseconds for the length that the master mode chip select - outputs are de-asserted between transactions. - - cdns,tsd2d-ns: - description: - Delay in nanoseconds between one chip select being de-activated - and the activation of another. - - cdns,tchsh-ns: - description: - Delay in nanoseconds between last bit of current transaction and - deasserting the device chip select (qspi_n_ss_out). - - cdns,tslch-ns: - description: - Delay in nanoseconds between setting qspi_n_ss_out low and - first bit transfer. - required: - compatible - reg diff --git a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml index 105fa2840e72a..5dd209206e880 100644 --- a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml +++ b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml @@ -83,5 +83,7 @@ properties: Delay, in microseconds, after a write transfer. # The controller specific properties go here. +allOf: + - $ref: cdns,qspi-nor-peripheral-props.yaml# additionalProperties: true -- GitLab From e9d7c323cfbbd07c365a419b4ce3dc2f161442c7 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Tue, 9 Nov 2021 23:49:11 +0530 Subject: [PATCH 0267/1112] dt-bindings: mtd: spi-nor: Add a reference to spi-peripheral-props.yaml The spi-peripheral-props.yaml schema contains peripheral-specific properties for SPI controllers that should be present in the peripheral node. Add a reference to that so its constraints are followed. additionalProperties: false cannot be used since it marks the controller properties as unknown. Use unevaluatedProperties: false instead. This has the side effect of allowing extra properties that are not specified in the schema. The alternative is to list all the controller properties in this schema but that would mean every peripheral binding would have to repeat the same set of properties for each controller. Signed-off-by: Pratyush Yadav Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20211109181911.2251-4-p.yadav@ti.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml index ed590d7c6e375..39421f7233e4c 100644 --- a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml +++ b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml @@ -11,6 +11,7 @@ maintainers: allOf: - $ref: "mtd.yaml#" + - $ref: /schemas/spi/spi-peripheral-props.yaml# properties: compatible: @@ -88,7 +89,7 @@ patternProperties: "^otp(-[0-9]+)?$": type: object -additionalProperties: false +unevaluatedProperties: false examples: - | -- GitLab From e518704d634fe3205903da6cbe97debf34885812 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 23 Nov 2021 22:05:23 +0100 Subject: [PATCH 0268/1112] platform/x86: thinkpad_acpi: Add LED_RETAIN_AT_SHUTDOWN to led_class_devs Add the LED_RETAIN_AT_SHUTDOWN flag to the registered led_class_devs so that the LEDs do not get turned-off when reloading the driver and thus so that they also stay under default EC control when reloading the driver, unless explicitly overridden by the user. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20211123210524.266705-1-hdegoede@redhat.com --- drivers/platform/x86/thinkpad_acpi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index c198acc6f53b7..07db6d5f1f902 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -5809,6 +5809,7 @@ static int __init tpacpi_init_led(unsigned int led) tpacpi_leds[led].led_classdev.brightness_get = &led_sysfs_get; tpacpi_leds[led].led_classdev.name = tpacpi_led_names[led]; + tpacpi_leds[led].led_classdev.flags = LED_RETAIN_AT_SHUTDOWN; tpacpi_leds[led].led = led; return led_classdev_register(&tpacpi_pdev->dev, &tpacpi_leds[led].led_classdev); -- GitLab From e1dbdd2f4a5247f579c930fe514de3cf0cc58e81 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 23 Nov 2021 22:05:24 +0100 Subject: [PATCH 0269/1112] platform/x86: thinkpad_acpi: Add lid_logo_dot to the list of safe LEDs There have been various bugs / forum threads about allowing control of the LED in the ThinkPad logo on the lid of various models. This seems to be something which users want to control and there really is no reason to require setting CONFIG_THINKPAD_ACPI_UNSAFE_LEDS for this. The lid-logo-dot is LED number 10, so change the name of the 10th led from unknown_led2 to lid_logo_dot and add it to the TPACPI_SAFE_LEDS mask. Link: https://www.reddit.com/r/thinkpad/comments/7n8eyu/thinkpad_led_control_under_gnulinux/ BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1943318 Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20211123210524.266705-2-hdegoede@redhat.com --- drivers/platform/x86/thinkpad_acpi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 07db6d5f1f902..38996e6e2a7a8 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -5643,11 +5643,11 @@ static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = { "tpacpi::standby", "tpacpi::dock_status1", "tpacpi::dock_status2", - "tpacpi::unknown_led2", + "tpacpi::lid_logo_dot", "tpacpi::unknown_led3", "tpacpi::thinkvantage", }; -#define TPACPI_SAFE_LEDS 0x1081U +#define TPACPI_SAFE_LEDS 0x1481U static inline bool tpacpi_is_led_restricted(const unsigned int led) { -- GitLab From 37f34df84ac76703536e5bec0b209f1e82a8a0cd Mon Sep 17 00:00:00 2001 From: Yang Li Date: Wed, 24 Nov 2021 10:02:12 +0800 Subject: [PATCH 0270/1112] platform/x86: asus-wmi: remove unneeded semicolon Eliminate the following coccicheck warning: ./drivers/platform/x86/asus-wmi.c:2386:2-3: Unneeded semicolon Reported-by: Abaci Robot Signed-off-by: Yang Li Link: https://lore.kernel.org/r/1637719332-45224-1-git-send-email-yang.lee@linux.alibaba.com Signed-off-by: Hans de Goede --- drivers/platform/x86/asus-wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index ab0c087d40cf8..6fa4b0be8e763 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -2383,7 +2383,7 @@ static ssize_t fan_curve_enable_store(struct device *dev, break; default: return -EINVAL; - }; + } if (data->enabled) { err = fan_curve_write(asus, data); -- GitLab From 60a076ea8a6d4e5216d5232d8bc98164c7bc1ffd Mon Sep 17 00:00:00 2001 From: Matan Ziv-Av Date: Tue, 23 Nov 2021 22:14:55 +0200 Subject: [PATCH 0271/1112] platform/x86: lg-laptop: Recognize more models LG uses 5 instead of 0 in the third digit (second digit after 2019) of the year string to indicate newer models in the same year. Handle this case as well. Signed-off-by: Matan Ziv-Av Link: https://lore.kernel.org/r/c752b3b2-9718-bd9a-732d-e165aa8a1fca@svgalib.org Signed-off-by: Hans de Goede --- drivers/platform/x86/lg-laptop.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/platform/x86/lg-laptop.c b/drivers/platform/x86/lg-laptop.c index ae9293024c77b..a91847a551a72 100644 --- a/drivers/platform/x86/lg-laptop.c +++ b/drivers/platform/x86/lg-laptop.c @@ -657,6 +657,18 @@ static int acpi_add(struct acpi_device *device) if (product && strlen(product) > 4) switch (product[4]) { case '5': + if (strlen(product) > 5) + switch (product[5]) { + case 'N': + year = 2021; + break; + case '0': + year = 2016; + break; + default: + year = 2022; + } + break; case '6': year = 2016; break; -- GitLab From a274cd66bc6461b45a450cd3f5653473a9aaea75 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 24 Nov 2021 18:51:25 +0100 Subject: [PATCH 0272/1112] platform/x86: touchscreen_dmi: Add TrekStor SurfTab duo W1 touchscreen info The TrekStor SurfTab duo W1 (ST10432-10b) has a Goodix touchscreen which has its x-axis mirrored. Add a quirk to fix this. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20211124175125.250329-1-hdegoede@redhat.com --- drivers/platform/x86/touchscreen_dmi.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c index fa8812039b82b..17dd54d4b783c 100644 --- a/drivers/platform/x86/touchscreen_dmi.c +++ b/drivers/platform/x86/touchscreen_dmi.c @@ -905,6 +905,16 @@ static const struct ts_dmi_data trekstor_primetab_t13b_data = { .properties = trekstor_primetab_t13b_props, }; +static const struct property_entry trekstor_surftab_duo_w1_props[] = { + PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"), + { } +}; + +static const struct ts_dmi_data trekstor_surftab_duo_w1_data = { + .acpi_name = "GDIX1001:00", + .properties = trekstor_surftab_duo_w1_props, +}; + static const struct property_entry trekstor_surftab_twin_10_1_props[] = { PROPERTY_ENTRY_U32("touchscreen-min-x", 20), PROPERTY_ENTRY_U32("touchscreen-min-y", 0), @@ -1502,6 +1512,14 @@ const struct dmi_system_id touchscreen_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Primetab T13B"), }, }, + { + /* TrekStor SurfTab duo W1 10.1 ST10432-10b */ + .driver_data = (void *)&trekstor_surftab_duo_w1_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TrekStor"), + DMI_MATCH(DMI_PRODUCT_NAME, "SurfTab duo W1 10.1 (VT4)"), + }, + }, { /* TrekStor SurfTab twin 10.1 ST10432-8 */ .driver_data = (void *)&trekstor_surftab_twin_10_1_data, -- GitLab From a602f5111fdd3d8a8ea2ac9e61f1c047d9794062 Mon Sep 17 00:00:00 2001 From: Fabrizio Bertocci Date: Mon, 29 Nov 2021 23:15:40 -0500 Subject: [PATCH 0273/1112] platform/x86: amd-pmc: Fix s2idle failures on certain AMD laptops On some AMD hardware laptops, the system fails communicating with the PMC when entering s2idle and the machine is battery powered. Hardware description: HP Pavilion Aero Laptop 13-be0097nr CPU: AMD Ryzen 7 5800U with Radeon Graphics GPU: 03:00.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Device [1002:1638] (rev c1) Detailed description of the problem (and investigation) here: https://gitlab.freedesktop.org/drm/amd/-/issues/1799 Patch is a single line: reduce the polling delay in half, from 100uSec to 50uSec when waiting for a change in state from the PMC after a write command operation. After changing the delay, I did not see a single failure on this machine (I have this fix for now more than one week and s2idle worked every single time on battery power). Cc: stable@vger.kernel.org Acked-by: Shyam Sundar S K Signed-off-by: Fabrizio Bertocci Link: https://lore.kernel.org/r/CADtzkx7TdfbwtaVEXUdD6YXPey52E-nZVQNs+Z41DTx7gqMqtw@mail.gmail.com Signed-off-by: Hans de Goede --- drivers/platform/x86/amd-pmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/amd-pmc.c b/drivers/platform/x86/amd-pmc.c index b7e50ed050a80..841c44cd64c2c 100644 --- a/drivers/platform/x86/amd-pmc.c +++ b/drivers/platform/x86/amd-pmc.c @@ -76,7 +76,7 @@ #define AMD_CPU_ID_CZN AMD_CPU_ID_RN #define AMD_CPU_ID_YC 0x14B5 -#define PMC_MSG_DELAY_MIN_US 100 +#define PMC_MSG_DELAY_MIN_US 50 #define RESPONSE_REGISTER_LOOP_MAX 20000 #define SOC_SUBSYSTEM_IP_MAX 12 -- GitLab From 9e3562080950b6e3fe38a5e34ddd5b1c618f2019 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 2 Dec 2021 10:53:33 +0100 Subject: [PATCH 0274/1112] HID: add suspend/resume helpers There is a lot of duplication of code in the HID low level drivers. Better have everything in one place so we can eventually extend it in a generic way. Signed-off-by: Benjamin Tissoires Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20211202095334.14399-4-benjamin.tissoires@redhat.com --- drivers/hid/hid-core.c | 29 ++++++++++++++++++++++ drivers/hid/i2c-hid/i2c-hid-core.c | 15 +++-------- drivers/hid/surface-hid/surface_hid_core.c | 25 ++++--------------- drivers/hid/usbhid/hid-core.c | 19 ++++++-------- include/linux/hid.h | 10 ++++++++ 5 files changed, 56 insertions(+), 42 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index dbed2524fd47b..5402329d6eca6 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2126,6 +2126,35 @@ void hid_hw_close(struct hid_device *hdev) } EXPORT_SYMBOL_GPL(hid_hw_close); +#ifdef CONFIG_PM +int hid_driver_suspend(struct hid_device *hdev, pm_message_t state) +{ + if (hdev->driver && hdev->driver->suspend) + return hdev->driver->suspend(hdev, state); + + return 0; +} +EXPORT_SYMBOL_GPL(hid_driver_suspend); + +int hid_driver_reset_resume(struct hid_device *hdev) +{ + if (hdev->driver && hdev->driver->reset_resume) + return hdev->driver->reset_resume(hdev); + + return 0; +} +EXPORT_SYMBOL_GPL(hid_driver_reset_resume); + +int hid_driver_resume(struct hid_device *hdev) +{ + if (hdev->driver && hdev->driver->resume) + return hdev->driver->resume(hdev); + + return 0; +} +EXPORT_SYMBOL_GPL(hid_driver_resume); +#endif /* CONFIG_PM */ + struct hid_dynid { struct list_head list; struct hid_device_id id; diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 517141138b007..4cdd862ca1cb6 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -1063,11 +1063,9 @@ static int i2c_hid_core_suspend(struct device *dev) int ret; int wake_status; - if (hid->driver && hid->driver->suspend) { - ret = hid->driver->suspend(hid, PMSG_SUSPEND); - if (ret < 0) - return ret; - } + ret = hid_driver_suspend(hid, PMSG_SUSPEND); + if (ret < 0) + return ret; /* Save some power */ i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); @@ -1125,12 +1123,7 @@ static int i2c_hid_core_resume(struct device *dev) if (ret) return ret; - if (hid->driver && hid->driver->reset_resume) { - ret = hid->driver->reset_resume(hid); - return ret; - } - - return 0; + return hid_driver_reset_resume(hid); } #endif diff --git a/drivers/hid/surface-hid/surface_hid_core.c b/drivers/hid/surface-hid/surface_hid_core.c index 5571e74abe91b..e46330b2e561a 100644 --- a/drivers/hid/surface-hid/surface_hid_core.c +++ b/drivers/hid/surface-hid/surface_hid_core.c @@ -204,50 +204,35 @@ static int surface_hid_suspend(struct device *dev) { struct surface_hid_device *d = dev_get_drvdata(dev); - if (d->hid->driver && d->hid->driver->suspend) - return d->hid->driver->suspend(d->hid, PMSG_SUSPEND); - - return 0; + return hid_driver_suspend(d->hid, PMSG_SUSPEND); } static int surface_hid_resume(struct device *dev) { struct surface_hid_device *d = dev_get_drvdata(dev); - if (d->hid->driver && d->hid->driver->resume) - return d->hid->driver->resume(d->hid); - - return 0; + return hid_driver_resume(d->hid); } static int surface_hid_freeze(struct device *dev) { struct surface_hid_device *d = dev_get_drvdata(dev); - if (d->hid->driver && d->hid->driver->suspend) - return d->hid->driver->suspend(d->hid, PMSG_FREEZE); - - return 0; + return hid_driver_suspend(d->hid, PMSG_FREEZE); } static int surface_hid_poweroff(struct device *dev) { struct surface_hid_device *d = dev_get_drvdata(dev); - if (d->hid->driver && d->hid->driver->suspend) - return d->hid->driver->suspend(d->hid, PMSG_HIBERNATE); - - return 0; + return hid_driver_suspend(d->hid, PMSG_HIBERNATE); } static int surface_hid_restore(struct device *dev) { struct surface_hid_device *d = dev_get_drvdata(dev); - if (d->hid->driver && d->hid->driver->reset_resume) - return d->hid->driver->reset_resume(d->hid); - - return 0; + return hid_driver_reset_resume(d->hid); } const struct dev_pm_ops surface_hid_pm_ops = { diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 2dcaf31eb9cdf..54752c85604b1 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -1563,8 +1563,8 @@ static int hid_resume_common(struct hid_device *hid, bool driver_suspended) int status = 0; hid_restart_io(hid); - if (driver_suspended && hid->driver && hid->driver->resume) - status = hid->driver->resume(hid); + if (driver_suspended) + status = hid_driver_resume(hid); return status; } @@ -1588,11 +1588,9 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message) { set_bit(HID_SUSPENDED, &usbhid->iofl); spin_unlock_irq(&usbhid->lock); - if (hid->driver && hid->driver->suspend) { - status = hid->driver->suspend(hid, message); - if (status < 0) - goto failed; - } + status = hid_driver_suspend(hid, message); + if (status < 0) + goto failed; driver_suspended = true; } else { usbhid_mark_busy(usbhid); @@ -1602,8 +1600,7 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message) } else { /* TODO: resume() might need to handle suspend failure */ - if (hid->driver && hid->driver->suspend) - status = hid->driver->suspend(hid, message); + status = hid_driver_suspend(hid, message); driver_suspended = true; spin_lock_irq(&usbhid->lock); set_bit(HID_SUSPENDED, &usbhid->iofl); @@ -1644,8 +1641,8 @@ static int hid_reset_resume(struct usb_interface *intf) int status; status = hid_post_reset(intf); - if (status >= 0 && hid->driver && hid->driver->reset_resume) { - int ret = hid->driver->reset_resume(hid); + if (status >= 0) { + int ret = hid_driver_reset_resume(hid); if (ret < 0) status = ret; } diff --git a/include/linux/hid.h b/include/linux/hid.h index 9e067f937dbc2..ebe3ec98db6b6 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -923,6 +923,16 @@ s32 hid_snto32(__u32 value, unsigned n); __u32 hid_field_extract(const struct hid_device *hid, __u8 *report, unsigned offset, unsigned n); +#ifdef CONFIG_PM +int hid_driver_suspend(struct hid_device *hdev, pm_message_t state); +int hid_driver_reset_resume(struct hid_device *hdev); +int hid_driver_resume(struct hid_device *hdev); +#else +static inline int hid_driver_suspend(struct hid_device *hdev, pm_message_t state) { return 0; } +static inline int hid_driver_reset_resume(struct hid_device *hdev) { return 0; } +static inline int hid_driver_resume(struct hid_device *hdev) { return 0; } +#endif + /** * hid_device_io_start - enable HID input during probe, remove * -- GitLab From f65a0b1f3e79444bba9ac56435eeb32db85ab2c9 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 2 Dec 2021 10:53:34 +0100 Subject: [PATCH 0275/1112] HID: do not inline some hid_hw_ functions We don't gain much by having them as inline, and it actually prevents us to attach a probe to those helpers. Signed-off-by: Benjamin Tissoires Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20211202095334.14399-5-benjamin.tissoires@redhat.com --- drivers/hid/hid-core.c | 64 +++++++++++++++++++++++++++++++++++++++ include/linux/hid.h | 68 ++++-------------------------------------- 2 files changed, 70 insertions(+), 62 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 5402329d6eca6..f1aed5bbd0008 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2126,6 +2126,70 @@ void hid_hw_close(struct hid_device *hdev) } EXPORT_SYMBOL_GPL(hid_hw_close); +/** + * hid_hw_request - send report request to device + * + * @hdev: hid device + * @report: report to send + * @reqtype: hid request type + */ +void hid_hw_request(struct hid_device *hdev, + struct hid_report *report, int reqtype) +{ + if (hdev->ll_driver->request) + return hdev->ll_driver->request(hdev, report, reqtype); + + __hid_request(hdev, report, reqtype); +} +EXPORT_SYMBOL_GPL(hid_hw_request); + +/** + * hid_hw_raw_request - send report request to device + * + * @hdev: hid device + * @reportnum: report ID + * @buf: in/out data to transfer + * @len: length of buf + * @rtype: HID report type + * @reqtype: HID_REQ_GET_REPORT or HID_REQ_SET_REPORT + * + * Return: count of data transferred, negative if error + * + * Same behavior as hid_hw_request, but with raw buffers instead. + */ +int hid_hw_raw_request(struct hid_device *hdev, + unsigned char reportnum, __u8 *buf, + size_t len, unsigned char rtype, int reqtype) +{ + if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf) + return -EINVAL; + + return hdev->ll_driver->raw_request(hdev, reportnum, buf, len, + rtype, reqtype); +} +EXPORT_SYMBOL_GPL(hid_hw_raw_request); + +/** + * hid_hw_output_report - send output report to device + * + * @hdev: hid device + * @buf: raw data to transfer + * @len: length of buf + * + * Return: count of data transferred, negative if error + */ +int hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len) +{ + if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf) + return -EINVAL; + + if (hdev->ll_driver->output_report) + return hdev->ll_driver->output_report(hdev, buf, len); + + return -ENOSYS; +} +EXPORT_SYMBOL_GPL(hid_hw_output_report); + #ifdef CONFIG_PM int hid_driver_suspend(struct hid_device *hdev, pm_message_t state) { diff --git a/include/linux/hid.h b/include/linux/hid.h index ebe3ec98db6b6..b2fea7fc54a1f 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -1066,6 +1066,12 @@ int __must_check hid_hw_start(struct hid_device *hdev, void hid_hw_stop(struct hid_device *hdev); int __must_check hid_hw_open(struct hid_device *hdev); void hid_hw_close(struct hid_device *hdev); +void hid_hw_request(struct hid_device *hdev, + struct hid_report *report, int reqtype); +int hid_hw_raw_request(struct hid_device *hdev, + unsigned char reportnum, __u8 *buf, + size_t len, unsigned char rtype, int reqtype); +int hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len); /** * hid_hw_power - requests underlying HW to go into given power mode @@ -1083,68 +1089,6 @@ static inline int hid_hw_power(struct hid_device *hdev, int level) } -/** - * hid_hw_request - send report request to device - * - * @hdev: hid device - * @report: report to send - * @reqtype: hid request type - */ -static inline void hid_hw_request(struct hid_device *hdev, - struct hid_report *report, int reqtype) -{ - if (hdev->ll_driver->request) - return hdev->ll_driver->request(hdev, report, reqtype); - - __hid_request(hdev, report, reqtype); -} - -/** - * hid_hw_raw_request - send report request to device - * - * @hdev: hid device - * @reportnum: report ID - * @buf: in/out data to transfer - * @len: length of buf - * @rtype: HID report type - * @reqtype: HID_REQ_GET_REPORT or HID_REQ_SET_REPORT - * - * Return: count of data transferred, negative if error - * - * Same behavior as hid_hw_request, but with raw buffers instead. - */ -static inline int hid_hw_raw_request(struct hid_device *hdev, - unsigned char reportnum, __u8 *buf, - size_t len, unsigned char rtype, int reqtype) -{ - if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf) - return -EINVAL; - - return hdev->ll_driver->raw_request(hdev, reportnum, buf, len, - rtype, reqtype); -} - -/** - * hid_hw_output_report - send output report to device - * - * @hdev: hid device - * @buf: raw data to transfer - * @len: length of buf - * - * Return: count of data transferred, negative if error - */ -static inline int hid_hw_output_report(struct hid_device *hdev, __u8 *buf, - size_t len) -{ - if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf) - return -EINVAL; - - if (hdev->ll_driver->output_report) - return hdev->ll_driver->output_report(hdev, buf, len); - - return -ENOSYS; -} - /** * hid_hw_idle - send idle request to device * -- GitLab From 9652c02428f3992129b73321fee32fe60b77c90f Mon Sep 17 00:00:00 2001 From: Angus Ainslie Date: Thu, 18 Nov 2021 08:18:45 -0800 Subject: [PATCH 0276/1112] power: bq25890: add POWER_SUPPLY_PROP_TEMP Add the POWER_SUPPLY_PROP_TEMP and a NTC 10K percent VREGN to degrees LUT. Make sure that a conversion is forced when the power supply is offline so the temperature is valid. Signed-off-by: Angus Ainslie Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq25890_charger.c | 37 +++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/bq25890_charger.c b/drivers/power/supply/bq25890_charger.c index 34ec186a2e9ab..78da6e7a8b5b1 100644 --- a/drivers/power/supply/bq25890_charger.c +++ b/drivers/power/supply/bq25890_charger.c @@ -266,6 +266,7 @@ enum bq25890_table_ids { /* lookup tables */ TBL_TREG, TBL_BOOSTI, + TBL_TSPCT, }; /* Thermal Regulation Threshold lookup table, in degrees Celsius */ @@ -280,6 +281,28 @@ static const u32 bq25890_boosti_tbl[] = { #define BQ25890_BOOSTI_TBL_SIZE ARRAY_SIZE(bq25890_boosti_tbl) +/* NTC 10K temperature lookup table in tenths of a degree */ +static const u32 bq25890_tspct_tbl[] = { + 850, 840, 830, 820, 810, 800, 790, 780, + 770, 760, 750, 740, 730, 720, 710, 700, + 690, 685, 680, 675, 670, 660, 650, 645, + 640, 630, 620, 615, 610, 600, 590, 585, + 580, 570, 565, 560, 550, 540, 535, 530, + 520, 515, 510, 500, 495, 490, 480, 475, + 470, 460, 455, 450, 440, 435, 430, 425, + 420, 410, 405, 400, 390, 385, 380, 370, + 365, 360, 355, 350, 340, 335, 330, 320, + 310, 305, 300, 290, 285, 280, 275, 270, + 260, 250, 245, 240, 230, 225, 220, 210, + 205, 200, 190, 180, 175, 170, 160, 150, + 145, 140, 130, 120, 115, 110, 100, 90, + 80, 70, 60, 50, 40, 30, 20, 10, + 0, -10, -20, -30, -40, -60, -70, -80, + -90, -10, -120, -140, -150, -170, -190, -210, +}; + +#define BQ25890_TSPCT_TBL_SIZE ARRAY_SIZE(bq25890_tspct_tbl) + struct bq25890_range { u32 min; u32 max; @@ -308,7 +331,8 @@ static const union { /* lookup tables */ [TBL_TREG] = { .lt = {bq25890_treg_tbl, BQ25890_TREG_TBL_SIZE} }, - [TBL_BOOSTI] = { .lt = {bq25890_boosti_tbl, BQ25890_BOOSTI_TBL_SIZE} } + [TBL_BOOSTI] = { .lt = {bq25890_boosti_tbl, BQ25890_BOOSTI_TBL_SIZE} }, + [TBL_TSPCT] = { .lt = {bq25890_tspct_tbl, BQ25890_TSPCT_TBL_SIZE} } }; static int bq25890_field_read(struct bq25890_device *bq, @@ -388,6 +412,7 @@ static bool bq25890_is_adc_property(enum power_supply_property psp) switch (psp) { case POWER_SUPPLY_PROP_VOLTAGE_NOW: case POWER_SUPPLY_PROP_CURRENT_NOW: + case POWER_SUPPLY_PROP_TEMP: return true; default: @@ -528,6 +553,15 @@ static int bq25890_power_supply_get_property(struct power_supply *psy, val->intval = ret * -50000; break; + case POWER_SUPPLY_PROP_TEMP: + ret = bq25890_field_read(bq, F_TSPCT); + if (ret < 0) + return ret; + + /* convert TS percentage into rough temperature */ + val->intval = bq25890_find_val(ret, TBL_TSPCT); + break; + default: return -EINVAL; } @@ -713,6 +747,7 @@ static const enum power_supply_property bq25890_power_supply_props[] = { POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_TEMP, }; static char *bq25890_charger_supplied_to[] = { -- GitLab From 087e1d715bccf25dc0e83294576e416b0386ba20 Mon Sep 17 00:00:00 2001 From: Gaurav Jain Date: Mon, 22 Nov 2021 17:02:34 +0530 Subject: [PATCH 0277/1112] crypto: caam - save caam memory to support crypto engine retry mechanism. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When caam queue is full (-ENOSPC), caam frees descriptor memory. crypto-engine checks if retry support is true and h/w queue is full(-ENOSPC), then requeue the crypto request. During processing the requested descriptor again, caam gives below error. (caam_jr 30902000.jr: 40000006: DECO: desc idx 0: Invalid KEY Command). This patch adds a check to return when caam input ring is full and retry support is true. so descriptor memory is not freed and requeued request can be processed again. Fixes: 2d653936eb2cf ("crypto: caam - enable crypto-engine retry mechanism") Signed-off-by: Gaurav Jain Reviewed-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 6 ++++++ drivers/crypto/caam/caamhash.c | 3 +++ drivers/crypto/caam/caampkc.c | 3 +++ 3 files changed, 12 insertions(+) diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 8697ae53b0633..d3d8bb0a69900 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -1533,6 +1533,9 @@ static int aead_do_one_req(struct crypto_engine *engine, void *areq) ret = caam_jr_enqueue(ctx->jrdev, desc, aead_crypt_done, req); + if (ret == -ENOSPC && engine->retry_support) + return ret; + if (ret != -EINPROGRESS) { aead_unmap(ctx->jrdev, rctx->edesc, req); kfree(rctx->edesc); @@ -1762,6 +1765,9 @@ static int skcipher_do_one_req(struct crypto_engine *engine, void *areq) ret = caam_jr_enqueue(ctx->jrdev, desc, skcipher_crypt_done, req); + if (ret == -ENOSPC && engine->retry_support) + return ret; + if (ret != -EINPROGRESS) { skcipher_unmap(ctx->jrdev, rctx->edesc, req); kfree(rctx->edesc); diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index e8a6d8bc43b5d..36ef738e4a181 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -765,6 +765,9 @@ static int ahash_do_one_req(struct crypto_engine *engine, void *areq) ret = caam_jr_enqueue(jrdev, desc, state->ahash_op_done, req); + if (ret == -ENOSPC && engine->retry_support) + return ret; + if (ret != -EINPROGRESS) { ahash_unmap(jrdev, state->edesc, req, 0); kfree(state->edesc); diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c index bf6275ffc4aad..8867275767101 100644 --- a/drivers/crypto/caam/caampkc.c +++ b/drivers/crypto/caam/caampkc.c @@ -380,6 +380,9 @@ static int akcipher_do_one_req(struct crypto_engine *engine, void *areq) ret = caam_jr_enqueue(jrdev, desc, req_ctx->akcipher_op_done, req); + if (ret == -ENOSPC && engine->retry_support) + return ret; + if (ret != -EINPROGRESS) { rsa_pub_unmap(jrdev, req_ctx->edesc, req); rsa_io_unmap(jrdev, req_ctx->edesc, req); -- GitLab From 5876b0cb883da7a16129dadc06250a36a79a8ee1 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 22 Nov 2021 16:54:02 +0100 Subject: [PATCH 0278/1112] crypto: sa2ul - Use bitfield helpers Use the FIELD_PREP() helper, instead of open-coding the same operation. Signed-off-by: Geert Uytterhoeven Signed-off-by: Herbert Xu --- drivers/crypto/sa2ul.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/crypto/sa2ul.c b/drivers/crypto/sa2ul.c index bcbc38dc6ae8f..51b58e57153f6 100644 --- a/drivers/crypto/sa2ul.c +++ b/drivers/crypto/sa2ul.c @@ -8,6 +8,7 @@ * Vitaly Andrianov * Tero Kristo */ +#include #include #include #include @@ -646,8 +647,8 @@ static inline void sa_update_cmdl(struct sa_req *req, u32 *cmdl, cmdl[upd_info->enc_offset.index] &= ~SA_CMDL_SOP_BYPASS_LEN_MASK; cmdl[upd_info->enc_offset.index] |= - ((u32)req->enc_offset << - __ffs(SA_CMDL_SOP_BYPASS_LEN_MASK)); + FIELD_PREP(SA_CMDL_SOP_BYPASS_LEN_MASK, + req->enc_offset); if (likely(upd_info->flags & SA_CMDL_UPD_ENC_IV)) { __be32 *data = (__be32 *)&cmdl[upd_info->enc_iv.index]; @@ -666,8 +667,8 @@ static inline void sa_update_cmdl(struct sa_req *req, u32 *cmdl, cmdl[upd_info->auth_offset.index] &= ~SA_CMDL_SOP_BYPASS_LEN_MASK; cmdl[upd_info->auth_offset.index] |= - ((u32)req->auth_offset << - __ffs(SA_CMDL_SOP_BYPASS_LEN_MASK)); + FIELD_PREP(SA_CMDL_SOP_BYPASS_LEN_MASK, + req->auth_offset); if (upd_info->flags & SA_CMDL_UPD_AUTH_IV) { sa_copy_iv((void *)&cmdl[upd_info->auth_iv.index], req->auth_iv, @@ -689,16 +690,16 @@ void sa_set_swinfo(u8 eng_id, u16 sc_id, dma_addr_t sc_phys, u8 hash_size, u32 *swinfo) { swinfo[0] = sc_id; - swinfo[0] |= (flags << __ffs(SA_SW0_FLAGS_MASK)); + swinfo[0] |= FIELD_PREP(SA_SW0_FLAGS_MASK, flags); if (likely(cmdl_present)) - swinfo[0] |= ((cmdl_offset | SA_SW0_CMDL_PRESENT) << - __ffs(SA_SW0_CMDL_INFO_MASK)); - swinfo[0] |= (eng_id << __ffs(SA_SW0_ENG_ID_MASK)); + swinfo[0] |= FIELD_PREP(SA_SW0_CMDL_INFO_MASK, + cmdl_offset | SA_SW0_CMDL_PRESENT); + swinfo[0] |= FIELD_PREP(SA_SW0_ENG_ID_MASK, eng_id); swinfo[0] |= SA_SW0_DEST_INFO_PRESENT; swinfo[1] = (u32)(sc_phys & 0xFFFFFFFFULL); swinfo[2] = (u32)((sc_phys & 0xFFFFFFFF00000000ULL) >> 32); - swinfo[2] |= (hash_size << __ffs(SA_SW2_EGRESS_LENGTH)); + swinfo[2] |= FIELD_PREP(SA_SW2_EGRESS_LENGTH, hash_size); } /* Dump the security context */ -- GitLab From 0ea275df84c389e910a3575a9233075118c173ee Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 27 Nov 2021 17:10:27 +0300 Subject: [PATCH 0279/1112] crypto: octeontx2 - uninitialized variable in kvf_limits_store() If kstrtoint() fails then "lfs_num" is uninitialized and the warning doesn't make any sense. Just delete it. Fixes: 8ec8015a3168 ("crypto: octeontx2 - add support to process the crypto request") Signed-off-by: Dan Carpenter Signed-off-by: Herbert Xu --- drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c b/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c index 146a55ac4b9b0..be1ad55a208f6 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c @@ -494,12 +494,11 @@ static ssize_t kvf_limits_store(struct device *dev, { struct otx2_cptpf_dev *cptpf = dev_get_drvdata(dev); int lfs_num; + int ret; - if (kstrtoint(buf, 0, &lfs_num)) { - dev_err(dev, "lfs count %d must be in range [1 - %d]\n", - lfs_num, num_online_cpus()); - return -EINVAL; - } + ret = kstrtoint(buf, 0, &lfs_num); + if (ret) + return ret; if (lfs_num < 1 || lfs_num > num_online_cpus()) { dev_err(dev, "lfs count %d must be in range [1 - %d]\n", lfs_num, num_online_cpus()); -- GitLab From 2966daf7d253d9904b337b040dd7a43472858b8a Mon Sep 17 00:00:00 2001 From: Andreas Oetken Date: Tue, 2 Nov 2021 18:26:04 +0100 Subject: [PATCH 0280/1112] mtd: Fixed breaking list in __mtd_del_partition. Not the child partition should be removed from the partition list but the partition itself. Otherwise the partition list gets broken and any subsequent remove operations leads to a kernel panic. Fixes: 46b5889cc2c5 ("mtd: implement proper partition handling") Signed-off-by: Andreas Oetken Cc: stable@vger.kernel.org Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20211102172604.2921065-1-andreas.oetken@siemens-energy.com --- drivers/mtd/mtdpart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 04af12b66110c..357661b62c94d 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -312,7 +312,7 @@ static int __mtd_del_partition(struct mtd_info *mtd) if (err) return err; - list_del(&child->part.node); + list_del(&mtd->part.node); free_partition(mtd); return 0; -- GitLab From e2748ad5257754a47376e28c0f9dda4f5c1e5ca3 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Tue, 2 Nov 2021 16:02:00 -0600 Subject: [PATCH 0281/1112] mtd: remove unused header file Commit d24dbd7541ff ("mtd: maps: Get rid of the latch-addr-flash driver") removed the last user of but left the header file behind. Nothing uses this file, delete it now. Cc: Boris Brezillon Cc: Miquel Raynal Cc: Richard Weinberger Cc: Vignesh Raghavendra Cc: linux-mtd@lists.infradead.org Signed-off-by: Jonathan Corbet Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20211102220203.940290-7-corbet@lwn.net --- include/linux/mtd/latch-addr-flash.h | 29 ---------------------------- 1 file changed, 29 deletions(-) delete mode 100644 include/linux/mtd/latch-addr-flash.h diff --git a/include/linux/mtd/latch-addr-flash.h b/include/linux/mtd/latch-addr-flash.h deleted file mode 100644 index e94b8e128074e..0000000000000 --- a/include/linux/mtd/latch-addr-flash.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Interface for NOR flash driver whose high address lines are latched - * - * Copyright © 2008 MontaVista Software, Inc. - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ -#ifndef __LATCH_ADDR_FLASH__ -#define __LATCH_ADDR_FLASH__ - -struct map_info; -struct mtd_partition; - -struct latch_addr_flash_data { - unsigned int width; - unsigned int size; - - int (*init)(void *data, int cs); - void (*done)(void *data); - void (*set_window)(unsigned long offset, void *data); - void *data; - - unsigned int nr_parts; - struct mtd_partition *parts; -}; - -#endif -- GitLab From c048b60d39e109c201d31ed5ad3a4f939064d6c4 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 4 Nov 2021 14:48:43 +0100 Subject: [PATCH 0282/1112] mtd: core: provide unique name for nvmem device If there is more than one mtd device which supports OTP, there will be a kernel warning about duplicated sysfs entries and the probing will fail. This is because the nvmem device name is not unique. Make it unique by prepending the name of the mtd. E.g. before the name was "user-otp", now it will be "mtd0-user-otp". For reference the kernel splash is: [ 4.665531] sysfs: cannot create duplicate filename '/bus/nvmem/devices/user-otp' [ 4.673056] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.15.0-next-20211101+ #1296 [ 4.680565] Hardware name: Kontron SMARC-sAL28 (Single PHY) on SMARC Eval 2.0 carrier (DT) [ 4.688856] Call trace: [ 4.691303] dump_backtrace+0x0/0x1bc [ 4.694984] show_stack+0x24/0x30 [ 4.698306] dump_stack_lvl+0x68/0x84 [ 4.701980] dump_stack+0x18/0x34 [ 4.705302] sysfs_warn_dup+0x70/0x90 [ 4.708973] sysfs_do_create_link_sd+0x144/0x150 [ 4.713603] sysfs_create_link+0x2c/0x50 [ 4.717535] bus_add_device+0x74/0x120 [ 4.721293] device_add+0x330/0x890 [ 4.724791] device_register+0x2c/0x40 [ 4.728550] nvmem_register+0x240/0x9f0 [ 4.732398] mtd_otp_nvmem_register+0xb0/0x10c [ 4.736854] mtd_device_parse_register+0x28c/0x2b4 [ 4.741659] spi_nor_probe+0x20c/0x2e0 [ 4.745418] spi_mem_probe+0x78/0xbc [ 4.749001] spi_probe+0x90/0xf0 [ 4.752237] really_probe.part.0+0xa4/0x320 .. [ 4.873936] mtd mtd1: Failed to register OTP NVMEM device [ 4.894468] spi-nor: probe of spi0.0 failed with error -17 Fixes: 4b361cfa8624 ("mtd: core: add OTP nvmem provider support") Signed-off-by: Michael Walle Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20211104134843.2642800-1-michael@walle.cc --- drivers/mtd/mtdcore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 9186268d361b4..fc0bed14bfb10 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -825,8 +825,7 @@ static struct nvmem_device *mtd_otp_nvmem_register(struct mtd_info *mtd, /* OTP nvmem will be registered on the physical device */ config.dev = mtd->dev.parent; - /* just reuse the compatible as name */ - config.name = compatible; + config.name = kasprintf(GFP_KERNEL, "%s-%s", dev_name(&mtd->dev), compatible); config.id = NVMEM_DEVID_NONE; config.owner = THIS_MODULE; config.type = NVMEM_TYPE_OTP; @@ -842,6 +841,7 @@ static struct nvmem_device *mtd_otp_nvmem_register(struct mtd_info *mtd, nvmem = NULL; of_node_put(np); + kfree(config.name); return nvmem; } -- GitLab From 4fea96afff3037ae8b353f08457b3e006ad8f875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 8 Nov 2021 10:31:49 +0100 Subject: [PATCH 0283/1112] mtd: dataflash: Warn about failure to unregister mtd device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mtd_device_unregister() shouldn't fail. Wail loudly if it does anyhow. This matches how other drivers (e.g. nand/raw/nandsim.c) use mtd_device_unregister(). By returning 0 in the spi remove callback a generic error message by the spi framework (and nothing else) is suppressed. Signed-off-by: Uwe Kleine-König Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20211108093153.63792-1-u.kleine-koenig@pengutronix.de --- drivers/mtd/devices/mtd_dataflash.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 9802e265fca80..293cab758299f 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -912,14 +912,14 @@ static int dataflash_probe(struct spi_device *spi) static int dataflash_remove(struct spi_device *spi) { struct dataflash *flash = spi_get_drvdata(spi); - int status; dev_dbg(&spi->dev, "remove\n"); - status = mtd_device_unregister(&flash->mtd); - if (status == 0) - kfree(flash); - return status; + WARN_ON(mtd_device_unregister(&flash->mtd)); + + kfree(flash); + + return 0; } static struct spi_driver dataflash_driver = { -- GitLab From 367cefbaed42eac9e1da5cc88f3b9220afc2db4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 8 Nov 2021 10:31:50 +0100 Subject: [PATCH 0284/1112] mtd: mchp23k256: Warn about failure to unregister mtd device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mtd_device_unregister() shouldn't fail. Wail loudly if it does anyhow. This matches how other drivers (e.g. nand/raw/nandsim.c) use mtd_device_unregister(). By returning 0 in the spi remove callback a generic error message by the spi framework (and nothing else) is suppressed. Signed-off-by: Uwe Kleine-König Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20211108093153.63792-2-u.kleine-koenig@pengutronix.de --- drivers/mtd/devices/mchp23k256.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/devices/mchp23k256.c b/drivers/mtd/devices/mchp23k256.c index 77c872fd3d839..a8b31bddf14b8 100644 --- a/drivers/mtd/devices/mchp23k256.c +++ b/drivers/mtd/devices/mchp23k256.c @@ -213,7 +213,9 @@ static int mchp23k256_remove(struct spi_device *spi) { struct mchp23k256_flash *flash = spi_get_drvdata(spi); - return mtd_device_unregister(&flash->mtd); + WARN_ON(mtd_device_unregister(&flash->mtd)); + + return 0; } static const struct of_device_id mchp23k256_of_table[] = { -- GitLab From 5765f4eb425cbe436f74a4ec700d0237caa36969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 8 Nov 2021 10:31:51 +0100 Subject: [PATCH 0285/1112] mtd: mchp48l640: Warn about failure to unregister mtd device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mtd_device_unregister() shouldn't fail. Wail loudly if it does anyhow. This matches how other drivers (e.g. nand/raw/nandsim.c) use mtd_device_unregister(). By returning 0 in the spi remove callback a generic error message by the spi framework (and nothing else) is suppressed. Signed-off-by: Uwe Kleine-König Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20211108093153.63792-3-u.kleine-koenig@pengutronix.de --- drivers/mtd/devices/mchp48l640.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/devices/mchp48l640.c b/drivers/mtd/devices/mchp48l640.c index 99400d0fb8c1e..231a107901960 100644 --- a/drivers/mtd/devices/mchp48l640.c +++ b/drivers/mtd/devices/mchp48l640.c @@ -345,7 +345,9 @@ static int mchp48l640_remove(struct spi_device *spi) { struct mchp48l640_flash *flash = spi_get_drvdata(spi); - return mtd_device_unregister(&flash->mtd); + WARN_ON(mtd_device_unregister(&flash->mtd)); + + return 0; } static const struct of_device_id mchp48l640_of_table[] = { -- GitLab From b4a0de29f083cf8a705e1f381076ceeed7010d50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 8 Nov 2021 10:31:52 +0100 Subject: [PATCH 0286/1112] mtd: sst25l: Warn about failure to unregister mtd device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mtd_device_unregister() shouldn't fail. Wail loudly if it does anyhow. This matches how other drivers (e.g. nand/raw/nandsim.c) use mtd_device_unregister(). By returning 0 in the spi remove callback a generic error message by the spi framework (and nothing else) is suppressed. Signed-off-by: Uwe Kleine-König Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20211108093153.63792-4-u.kleine-koenig@pengutronix.de --- drivers/mtd/devices/sst25l.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/devices/sst25l.c b/drivers/mtd/devices/sst25l.c index b81c3f0b85f94..7f124c1bfa406 100644 --- a/drivers/mtd/devices/sst25l.c +++ b/drivers/mtd/devices/sst25l.c @@ -402,7 +402,9 @@ static int sst25l_remove(struct spi_device *spi) { struct sst25l_flash *flash = spi_get_drvdata(spi); - return mtd_device_unregister(&flash->mtd); + WARN_ON(mtd_device_unregister(&flash->mtd)); + + return 0; } static struct spi_driver sst25l_driver = { -- GitLab From 00596576a05145a1b5672897a82ef87af00becf4 Mon Sep 17 00:00:00 2001 From: Zev Weiss Date: Fri, 15 Oct 2021 11:50:48 -0700 Subject: [PATCH 0287/1112] mtd: core: clear out unregistered devices a bit more This allows an MTD device that has been unregistered to be easily re-registered later without triggering spurious "already registered" warnings in mtd_device_parse_register() and add_mtd_device(). Signed-off-by: Zev Weiss Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20211015185049.3318-1-zev@bewilderbeest.net --- drivers/mtd/mtdcore.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index fc0bed14bfb10..a7723a708ea7e 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -747,6 +747,9 @@ int del_mtd_device(struct mtd_info *mtd) device_unregister(&mtd->dev); + /* Clear dev so mtd can be safely re-registered later if desired */ + memset(&mtd->dev, 0, sizeof(mtd->dev)); + idr_remove(&mtd_idr, mtd->index); of_node_put(mtd_get_of_node(mtd)); @@ -1018,8 +1021,10 @@ int mtd_device_unregister(struct mtd_info *master) { int err; - if (master->_reboot) + if (master->_reboot) { unregister_reboot_notifier(&master->reboot_notifier); + memset(&master->reboot_notifier, 0, sizeof(master->reboot_notifier)); + } if (master->otp_user_nvmem) nvmem_unregister(master->otp_user_nvmem); -- GitLab From 33a0da68fb073360d36ce1a0e852f75fede7c21e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 22 Nov 2021 14:21:38 +0100 Subject: [PATCH 0288/1112] mtd: rawnand: mpc5121: Remove unused variable in ads5121_select_chip() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/mtd/nand/raw/mpc5121_nfc.c: In function ‘ads5121_select_chip’: drivers/mtd/nand/raw/mpc5121_nfc.c:294:19: warning: unused variable ‘mtd’ [-Wunused-variable] 294 | struct mtd_info *mtd = nand_to_mtd(nand); | ^~~ Fixes: 758b56f58b66bebc ("mtd: rawnand: Pass a nand_chip object to chip->select_chip()") Signed-off-by: Geert Uytterhoeven Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20211122132138.3899138-1-geert@linux-m68k.org --- drivers/mtd/nand/raw/mpc5121_nfc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/nand/raw/mpc5121_nfc.c b/drivers/mtd/nand/raw/mpc5121_nfc.c index cb293c50acb87..5b9271b9c3265 100644 --- a/drivers/mtd/nand/raw/mpc5121_nfc.c +++ b/drivers/mtd/nand/raw/mpc5121_nfc.c @@ -291,7 +291,6 @@ static int ads5121_chipselect_init(struct mtd_info *mtd) /* Control chips select signal on ADS5121 board */ static void ads5121_select_chip(struct nand_chip *nand, int chip) { - struct mtd_info *mtd = nand_to_mtd(nand); struct mpc5121_nfc_prv *prv = nand_get_controller_data(nand); u8 v; -- GitLab From 49fdfe66400614ee1c484057c79dd6642c535fd4 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 3 Dec 2021 14:48:17 +0100 Subject: [PATCH 0289/1112] gpiolib: Let gpiod_add_lookup_table() call gpiod_add_lookup_tables() This saves 20 bytes on arm32, and 44 bytes on arm64. Signed-off-by: Geert Uytterhoeven Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index abfbf546d1599..85168f88a7fec 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3487,11 +3487,7 @@ EXPORT_SYMBOL_GPL(gpiod_set_array_value_cansleep); */ void gpiod_add_lookup_table(struct gpiod_lookup_table *table) { - mutex_lock(&gpio_lookup_lock); - - list_add_tail(&table->list, &gpio_lookup_list); - - mutex_unlock(&gpio_lookup_lock); + gpiod_add_lookup_tables(&table, 1); } EXPORT_SYMBOL_GPL(gpiod_add_lookup_table); -- GitLab From a00128dfc8fc0cc8848d9168d6e7cfff99bd46f0 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 3 Dec 2021 15:06:44 +0100 Subject: [PATCH 0290/1112] gpio: aggregator: Add interrupt support Currently the GPIO Aggregator does not support interrupts. This means that kernel drivers going from a GPIO to an IRQ using gpiod_to_irq(), and userspace applications using line events do not work. Add interrupt support by providing a gpio_chip.to_irq() callback, which just calls into the parent GPIO controller. Note that this does not implement full interrupt controller (irq_chip) support, so using e.g. gpio-keys with "interrupts" instead of "gpios" still does not work. Signed-off-by: Geert Uytterhoeven Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-aggregator.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index e9671d1660ef4..869dc952cf452 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -371,6 +371,13 @@ static int gpio_fwd_set_config(struct gpio_chip *chip, unsigned int offset, return gpiod_set_config(fwd->descs[offset], config); } +static int gpio_fwd_to_irq(struct gpio_chip *chip, unsigned int offset) +{ + struct gpiochip_fwd *fwd = gpiochip_get_data(chip); + + return gpiod_to_irq(fwd->descs[offset]); +} + /** * gpiochip_fwd_create() - Create a new GPIO forwarder * @dev: Parent device pointer @@ -411,7 +418,8 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, for (i = 0; i < ngpios; i++) { struct gpio_chip *parent = gpiod_to_chip(descs[i]); - dev_dbg(dev, "%u => gpio-%d\n", i, desc_to_gpio(descs[i])); + dev_dbg(dev, "%u => gpio %d irq %d\n", i, + desc_to_gpio(descs[i]), gpiod_to_irq(descs[i])); if (gpiod_cansleep(descs[i])) chip->can_sleep = true; @@ -429,6 +437,7 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, chip->get_multiple = gpio_fwd_get_multiple_locked; chip->set = gpio_fwd_set; chip->set_multiple = gpio_fwd_set_multiple_locked; + chip->to_irq = gpio_fwd_to_irq; chip->base = -1; chip->ngpio = ngpios; fwd->descs = descs; -- GitLab From adc8b4bf2a7f6f513c560bb8e225d4750ce5e872 Mon Sep 17 00:00:00 2001 From: John Keeping Date: Thu, 2 Dec 2021 15:50:21 +0000 Subject: [PATCH 0291/1112] gpio: rockchip: lock GPIOs used as interrupts Use the standard gpiochip request/release resource functions so that any GPIOs used as interrupts are properly locked. This allows libgpiod to correctly show these GPIOs as in-use. Signed-off-by: John Keeping Tested-by: Nicolas Frattaroli Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-rockchip.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c index ce63cbd14d69a..c1b8e5dbbcc47 100644 --- a/drivers/gpio/gpio-rockchip.c +++ b/drivers/gpio/gpio-rockchip.c @@ -465,6 +465,22 @@ out: return ret; } +static int rockchip_irq_reqres(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct rockchip_pin_bank *bank = gc->private; + + return gpiochip_reqres_irq(&bank->gpio_chip, d->hwirq); +} + +static void rockchip_irq_relres(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct rockchip_pin_bank *bank = gc->private; + + gpiochip_relres_irq(&bank->gpio_chip, d->hwirq); +} + static void rockchip_irq_suspend(struct irq_data *d) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); @@ -536,6 +552,8 @@ static int rockchip_interrupts_register(struct rockchip_pin_bank *bank) gc->chip_types[0].chip.irq_suspend = rockchip_irq_suspend; gc->chip_types[0].chip.irq_resume = rockchip_irq_resume; gc->chip_types[0].chip.irq_set_type = rockchip_irq_set_type; + gc->chip_types[0].chip.irq_request_resources = rockchip_irq_reqres; + gc->chip_types[0].chip.irq_release_resources = rockchip_irq_relres; gc->wake_enabled = IRQ_MSK(bank->nr_pins); /* -- GitLab From e320d9c2e900d988c82021c80a3cbff488977946 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 1 Dec 2021 15:43:05 -0600 Subject: [PATCH 0292/1112] gpio: xlp: Fix build errors from Netlogic XLP removal Commit ea708ac5bf41 ("gpio: xlp: Remove Netlogic XLP variants") has build errors with CONFIG_ACPI: drivers/gpio/gpio-xlp.c:300:23: error: 'GPIO_VARIANT_VULCAN' undeclared here (not in a function) and !CONFIG_OF: drivers/gpio/gpio-xlp.c:267:11: error: 'struct gpio_chip' has no member named 'of_node' Fix these errors. Fixes: ea708ac5bf41 ("gpio: xlp: Remove Netlogic XLP variants") Reported-by: Stephen Rothwell Reported-by: kernel test robot Cc: Linus Walleij Cc: Bartosz Golaszewski Cc: linux-gpio@vger.kernel.org Signed-off-by: Rob Herring Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-xlp.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-xlp.c b/drivers/gpio/gpio-xlp.c index 814cc34aef976..0199f545335fc 100644 --- a/drivers/gpio/gpio-xlp.c +++ b/drivers/gpio/gpio-xlp.c @@ -264,7 +264,6 @@ static int xlp_gpio_probe(struct platform_device *pdev) gc->base = 0; gc->parent = &pdev->dev; gc->ngpio = 70; - gc->of_node = pdev->dev.of_node; gc->direction_output = xlp_gpio_dir_output; gc->direction_input = xlp_gpio_dir_input; gc->set = xlp_gpio_set; @@ -297,8 +296,8 @@ static int xlp_gpio_probe(struct platform_device *pdev) #ifdef CONFIG_ACPI static const struct acpi_device_id xlp_gpio_acpi_match[] = { - { "BRCM9006", GPIO_VARIANT_VULCAN }, - { "CAV9006", GPIO_VARIANT_VULCAN }, + { "BRCM9006" }, + { "CAV9006" }, {}, }; MODULE_DEVICE_TABLE(acpi, xlp_gpio_acpi_match); -- GitLab From bb49e9e730c2906a958eee273a7819f401543d6c Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 3 Dec 2021 12:16:58 +0100 Subject: [PATCH 0293/1112] fs: add is_idmapped_mnt() helper Multiple places open-code the same check to determine whether a given mount is idmapped. Introduce a simple helper function that can be used instead. This allows us to get rid of the fragile open-coding. We will later change the check that is used to determine whether a given mount is idmapped. Introducing a helper allows us to do this in a single place instead of doing it for multiple places. Link: https://lore.kernel.org/r/20211123114227.3124056-2-brauner@kernel.org (v1) Link: https://lore.kernel.org/r/20211130121032.3753852-2-brauner@kernel.org (v2) Link: https://lore.kernel.org/r/20211203111707.3901969-2-brauner@kernel.org Cc: Seth Forshee Cc: Christoph Hellwig Cc: Al Viro CC: linux-fsdevel@vger.kernel.org Reviewed-by: Amir Goldstein Reviewed-by: Seth Forshee Signed-off-by: Christian Brauner --- fs/cachefiles/bind.c | 2 +- fs/ecryptfs/main.c | 2 +- fs/namespace.c | 2 +- fs/nfsd/export.c | 2 +- fs/overlayfs/super.c | 2 +- fs/proc_namespace.c | 2 +- include/linux/fs.h | 14 ++++++++++++++ 7 files changed, 20 insertions(+), 6 deletions(-) diff --git a/fs/cachefiles/bind.c b/fs/cachefiles/bind.c index d463d89f5db8c..146291be62637 100644 --- a/fs/cachefiles/bind.c +++ b/fs/cachefiles/bind.c @@ -117,7 +117,7 @@ static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache) root = path.dentry; ret = -EINVAL; - if (mnt_user_ns(path.mnt) != &init_user_ns) { + if (is_idmapped_mnt(path.mnt)) { pr_warn("File cache on idmapped mounts not supported"); goto error_unsupported; } diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index d66bbd2df191e..2dd23a82e0de5 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -537,7 +537,7 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags goto out_free; } - if (mnt_user_ns(path.mnt) != &init_user_ns) { + if (is_idmapped_mnt(path.mnt)) { rc = -EINVAL; printk(KERN_ERR "Mounting on idmapped mounts currently disallowed\n"); goto out_free; diff --git a/fs/namespace.c b/fs/namespace.c index 659a8f39c61af..4994b816a74c6 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -3936,7 +3936,7 @@ static int can_idmap_mount(const struct mount_kattr *kattr, struct mount *mnt) * mapping. It makes things simpler and callers can just create * another bind-mount they can idmap if they want to. */ - if (mnt_user_ns(m) != &init_user_ns) + if (is_idmapped_mnt(m)) return -EPERM; /* The underlying filesystem doesn't support idmapped mounts yet. */ diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 9421dae227374..668c7527b17e8 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -427,7 +427,7 @@ static int check_export(struct path *path, int *flags, unsigned char *uuid) return -EINVAL; } - if (mnt_user_ns(path->mnt) != &init_user_ns) { + if (is_idmapped_mnt(path->mnt)) { dprintk("exp_export: export of idmapped mounts not yet supported.\n"); return -EINVAL; } diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 265181c110ae2..7bb0a47cb6156 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -873,7 +873,7 @@ static int ovl_mount_dir_noesc(const char *name, struct path *path) pr_err("filesystem on '%s' not supported\n", name); goto out_put; } - if (mnt_user_ns(path->mnt) != &init_user_ns) { + if (is_idmapped_mnt(path->mnt)) { pr_err("idmapped layers are currently not supported\n"); goto out_put; } diff --git a/fs/proc_namespace.c b/fs/proc_namespace.c index 392ef5162655b..49650e54d2f88 100644 --- a/fs/proc_namespace.c +++ b/fs/proc_namespace.c @@ -80,7 +80,7 @@ static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt) seq_puts(m, fs_infop->str); } - if (mnt_user_ns(mnt) != &init_user_ns) + if (is_idmapped_mnt(mnt)) seq_puts(m, ",idmapped"); } diff --git a/include/linux/fs.h b/include/linux/fs.h index bbf812ce89a8c..06cbefd76de7e 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2724,6 +2724,20 @@ static inline struct user_namespace *file_mnt_user_ns(struct file *file) { return mnt_user_ns(file->f_path.mnt); } + +/** + * is_idmapped_mnt - check whether a mount is mapped + * @mnt: the mount to check + * + * If @mnt has an idmapping attached to it @mnt is mapped. + * + * Return: true if mount is mapped, false if not. + */ +static inline bool is_idmapped_mnt(const struct vfsmount *mnt) +{ + return mnt_user_ns(mnt) != &init_user_ns; +} + extern long vfs_truncate(const struct path *, loff_t); int do_truncate(struct user_namespace *, struct dentry *, loff_t start, unsigned int time_attrs, struct file *filp); -- GitLab From a793d79ea3e041081cd7cbd8ee43d0b5e4914a2b Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 3 Dec 2021 12:16:59 +0100 Subject: [PATCH 0294/1112] fs: move mapping helpers The low-level mapping helpers were so far crammed into fs.h. They are out of place there. The fs.h header should just contain the higher-level mapping helpers that interact directly with vfs objects such as struct super_block or struct inode and not the bare mapping helpers. Similarly, only vfs and specific fs code shall interact with low-level mapping helpers. And so they won't be made accessible automatically through regular {g,u}id helpers. Link: https://lore.kernel.org/r/20211123114227.3124056-3-brauner@kernel.org (v1) Link: https://lore.kernel.org/r/20211130121032.3753852-3-brauner@kernel.org (v2) Link: https://lore.kernel.org/r/20211203111707.3901969-3-brauner@kernel.org Cc: Seth Forshee Cc: Christoph Hellwig Cc: Al Viro CC: linux-fsdevel@vger.kernel.org Reviewed-by: Amir Goldstein Reviewed-by: Seth Forshee Signed-off-by: Christian Brauner --- fs/ksmbd/smbacl.c | 1 + fs/ksmbd/smbacl.h | 1 + fs/open.c | 1 + fs/posix_acl.c | 1 + fs/xfs/xfs_linux.h | 1 + include/linux/fs.h | 91 +----------------------------- include/linux/mnt_idmapping.h | 101 ++++++++++++++++++++++++++++++++++ security/commoncap.c | 1 + 8 files changed, 108 insertions(+), 90 deletions(-) create mode 100644 include/linux/mnt_idmapping.h diff --git a/fs/ksmbd/smbacl.c b/fs/ksmbd/smbacl.c index bd792db326239..ab8099e0fd7f2 100644 --- a/fs/ksmbd/smbacl.c +++ b/fs/ksmbd/smbacl.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "smbacl.h" #include "smb_common.h" diff --git a/fs/ksmbd/smbacl.h b/fs/ksmbd/smbacl.h index 73e08cad412bd..eba1ebb9e92ec 100644 --- a/fs/ksmbd/smbacl.h +++ b/fs/ksmbd/smbacl.h @@ -11,6 +11,7 @@ #include #include #include +#include #include "mgmt/tree_connect.h" diff --git a/fs/open.c b/fs/open.c index f732fb94600ce..2450cc1a2f64f 100644 --- a/fs/open.c +++ b/fs/open.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "internal.h" diff --git a/fs/posix_acl.c b/fs/posix_acl.c index 9323a854a60ae..632bfdcf7cc0a 100644 --- a/fs/posix_acl.c +++ b/fs/posix_acl.c @@ -23,6 +23,7 @@ #include #include #include +#include static struct posix_acl **acl_by_type(struct inode *inode, int type) { diff --git a/fs/xfs/xfs_linux.h b/fs/xfs/xfs_linux.h index c174262a074e3..09a8fba84ff99 100644 --- a/fs/xfs/xfs_linux.h +++ b/fs/xfs/xfs_linux.h @@ -61,6 +61,7 @@ typedef __u32 xfs_nlink_t; #include #include #include +#include #include #include diff --git a/include/linux/fs.h b/include/linux/fs.h index 06cbefd76de7e..b3bcb21296991 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -1624,34 +1625,6 @@ static inline void i_gid_write(struct inode *inode, gid_t gid) inode->i_gid = make_kgid(inode->i_sb->s_user_ns, gid); } -/** - * kuid_into_mnt - map a kuid down into a mnt_userns - * @mnt_userns: user namespace of the relevant mount - * @kuid: kuid to be mapped - * - * Return: @kuid mapped according to @mnt_userns. - * If @kuid has no mapping INVALID_UID is returned. - */ -static inline kuid_t kuid_into_mnt(struct user_namespace *mnt_userns, - kuid_t kuid) -{ - return make_kuid(mnt_userns, __kuid_val(kuid)); -} - -/** - * kgid_into_mnt - map a kgid down into a mnt_userns - * @mnt_userns: user namespace of the relevant mount - * @kgid: kgid to be mapped - * - * Return: @kgid mapped according to @mnt_userns. - * If @kgid has no mapping INVALID_GID is returned. - */ -static inline kgid_t kgid_into_mnt(struct user_namespace *mnt_userns, - kgid_t kgid) -{ - return make_kgid(mnt_userns, __kgid_val(kgid)); -} - /** * i_uid_into_mnt - map an inode's i_uid down into a mnt_userns * @mnt_userns: user namespace of the mount the inode was found from @@ -1680,68 +1653,6 @@ static inline kgid_t i_gid_into_mnt(struct user_namespace *mnt_userns, return kgid_into_mnt(mnt_userns, inode->i_gid); } -/** - * kuid_from_mnt - map a kuid up into a mnt_userns - * @mnt_userns: user namespace of the relevant mount - * @kuid: kuid to be mapped - * - * Return: @kuid mapped up according to @mnt_userns. - * If @kuid has no mapping INVALID_UID is returned. - */ -static inline kuid_t kuid_from_mnt(struct user_namespace *mnt_userns, - kuid_t kuid) -{ - return KUIDT_INIT(from_kuid(mnt_userns, kuid)); -} - -/** - * kgid_from_mnt - map a kgid up into a mnt_userns - * @mnt_userns: user namespace of the relevant mount - * @kgid: kgid to be mapped - * - * Return: @kgid mapped up according to @mnt_userns. - * If @kgid has no mapping INVALID_GID is returned. - */ -static inline kgid_t kgid_from_mnt(struct user_namespace *mnt_userns, - kgid_t kgid) -{ - return KGIDT_INIT(from_kgid(mnt_userns, kgid)); -} - -/** - * mapped_fsuid - return caller's fsuid mapped up into a mnt_userns - * @mnt_userns: user namespace of the relevant mount - * - * Use this helper to initialize a new vfs or filesystem object based on - * the caller's fsuid. A common example is initializing the i_uid field of - * a newly allocated inode triggered by a creation event such as mkdir or - * O_CREAT. Other examples include the allocation of quotas for a specific - * user. - * - * Return: the caller's current fsuid mapped up according to @mnt_userns. - */ -static inline kuid_t mapped_fsuid(struct user_namespace *mnt_userns) -{ - return kuid_from_mnt(mnt_userns, current_fsuid()); -} - -/** - * mapped_fsgid - return caller's fsgid mapped up into a mnt_userns - * @mnt_userns: user namespace of the relevant mount - * - * Use this helper to initialize a new vfs or filesystem object based on - * the caller's fsgid. A common example is initializing the i_gid field of - * a newly allocated inode triggered by a creation event such as mkdir or - * O_CREAT. Other examples include the allocation of quotas for a specific - * user. - * - * Return: the caller's current fsgid mapped up according to @mnt_userns. - */ -static inline kgid_t mapped_fsgid(struct user_namespace *mnt_userns) -{ - return kgid_from_mnt(mnt_userns, current_fsgid()); -} - /** * inode_fsuid_set - initialize inode's i_uid field with callers fsuid * @inode: inode to initialize diff --git a/include/linux/mnt_idmapping.h b/include/linux/mnt_idmapping.h new file mode 100644 index 0000000000000..47c7811fadfec --- /dev/null +++ b/include/linux/mnt_idmapping.h @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_MNT_IDMAPPING_H +#define _LINUX_MNT_IDMAPPING_H + +#include +#include + +struct user_namespace; +extern struct user_namespace init_user_ns; + +/** + * kuid_into_mnt - map a kuid down into a mnt_userns + * @mnt_userns: user namespace of the relevant mount + * @kuid: kuid to be mapped + * + * Return: @kuid mapped according to @mnt_userns. + * If @kuid has no mapping INVALID_UID is returned. + */ +static inline kuid_t kuid_into_mnt(struct user_namespace *mnt_userns, + kuid_t kuid) +{ + return make_kuid(mnt_userns, __kuid_val(kuid)); +} + +/** + * kgid_into_mnt - map a kgid down into a mnt_userns + * @mnt_userns: user namespace of the relevant mount + * @kgid: kgid to be mapped + * + * Return: @kgid mapped according to @mnt_userns. + * If @kgid has no mapping INVALID_GID is returned. + */ +static inline kgid_t kgid_into_mnt(struct user_namespace *mnt_userns, + kgid_t kgid) +{ + return make_kgid(mnt_userns, __kgid_val(kgid)); +} + +/** + * kuid_from_mnt - map a kuid up into a mnt_userns + * @mnt_userns: user namespace of the relevant mount + * @kuid: kuid to be mapped + * + * Return: @kuid mapped up according to @mnt_userns. + * If @kuid has no mapping INVALID_UID is returned. + */ +static inline kuid_t kuid_from_mnt(struct user_namespace *mnt_userns, + kuid_t kuid) +{ + return KUIDT_INIT(from_kuid(mnt_userns, kuid)); +} + +/** + * kgid_from_mnt - map a kgid up into a mnt_userns + * @mnt_userns: user namespace of the relevant mount + * @kgid: kgid to be mapped + * + * Return: @kgid mapped up according to @mnt_userns. + * If @kgid has no mapping INVALID_GID is returned. + */ +static inline kgid_t kgid_from_mnt(struct user_namespace *mnt_userns, + kgid_t kgid) +{ + return KGIDT_INIT(from_kgid(mnt_userns, kgid)); +} + +/** + * mapped_fsuid - return caller's fsuid mapped up into a mnt_userns + * @mnt_userns: user namespace of the relevant mount + * + * Use this helper to initialize a new vfs or filesystem object based on + * the caller's fsuid. A common example is initializing the i_uid field of + * a newly allocated inode triggered by a creation event such as mkdir or + * O_CREAT. Other examples include the allocation of quotas for a specific + * user. + * + * Return: the caller's current fsuid mapped up according to @mnt_userns. + */ +static inline kuid_t mapped_fsuid(struct user_namespace *mnt_userns) +{ + return kuid_from_mnt(mnt_userns, current_fsuid()); +} + +/** + * mapped_fsgid - return caller's fsgid mapped up into a mnt_userns + * @mnt_userns: user namespace of the relevant mount + * + * Use this helper to initialize a new vfs or filesystem object based on + * the caller's fsgid. A common example is initializing the i_gid field of + * a newly allocated inode triggered by a creation event such as mkdir or + * O_CREAT. Other examples include the allocation of quotas for a specific + * user. + * + * Return: the caller's current fsgid mapped up according to @mnt_userns. + */ +static inline kgid_t mapped_fsgid(struct user_namespace *mnt_userns) +{ + return kgid_from_mnt(mnt_userns, current_fsgid()); +} + +#endif /* _LINUX_MNT_IDMAPPING_H */ diff --git a/security/commoncap.c b/security/commoncap.c index 3f810d37b71bd..09479f71ee2ed 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -24,6 +24,7 @@ #include #include #include +#include /* * If a non-root user executes a setuid-root binary in -- GitLab From 476860b3eb4a50958243158861d5340066df5af2 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 3 Dec 2021 12:17:00 +0100 Subject: [PATCH 0295/1112] fs: tweak fsuidgid_has_mapping() If the caller's fs{g,u}id aren't mapped in the mount's idmapping we can return early and skip the check whether the mapped fs{g,u}id also have a mapping in the filesystem's idmapping. If the fs{g,u}id aren't mapped in the mount's idmapping they consequently can't be mapped in the filesystem's idmapping. So there's no point in checking that. Link: https://lore.kernel.org/r/20211123114227.3124056-4-brauner@kernel.org (v1) Link: https://lore.kernel.org/r/20211130121032.3753852-4-brauner@kernel.org (v2) Link: https://lore.kernel.org/r/20211203111707.3901969-4-brauner@kernel.org Cc: Seth Forshee Cc: Christoph Hellwig Cc: Al Viro CC: linux-fsdevel@vger.kernel.org Reviewed-by: Amir Goldstein Reviewed-by: Seth Forshee Signed-off-by: Christian Brauner --- include/linux/fs.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/include/linux/fs.h b/include/linux/fs.h index b3bcb21296991..db5ee15e36b19 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1695,10 +1695,18 @@ static inline void inode_fsgid_set(struct inode *inode, static inline bool fsuidgid_has_mapping(struct super_block *sb, struct user_namespace *mnt_userns) { - struct user_namespace *s_user_ns = sb->s_user_ns; + struct user_namespace *fs_userns = sb->s_user_ns; + kuid_t kuid; + kgid_t kgid; - return kuid_has_mapping(s_user_ns, mapped_fsuid(mnt_userns)) && - kgid_has_mapping(s_user_ns, mapped_fsgid(mnt_userns)); + kuid = mapped_fsuid(mnt_userns); + if (!uid_valid(kuid)) + return false; + kgid = mapped_fsgid(mnt_userns); + if (!gid_valid(kgid)) + return false; + return kuid_has_mapping(fs_userns, kuid) && + kgid_has_mapping(fs_userns, kgid); } extern struct timespec64 current_time(struct inode *inode); -- GitLab From 1ac2a4104968e0a60b4b3572216a92aab5c1b025 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 3 Dec 2021 12:17:01 +0100 Subject: [PATCH 0296/1112] fs: account for filesystem mappings Currently we only support idmapped mounts for filesystems mounted without an idmapping. This was a conscious decision mentioned in multiple places (cf. e.g. [1]). As explained at length in [3] it is perfectly fine to extend support for idmapped mounts to filesystem's mounted with an idmapping should the need arise. The need has been there for some time now. Various container projects in userspace need this to run unprivileged and nested unprivileged containers (cf. [2]). Before we can port any filesystem that is mountable with an idmapping to support idmapped mounts we need to first extend the mapping helpers to account for the filesystem's idmapping. This again, is explained at length in our documentation at [3] but I'll give an overview here again. Currently, the low-level mapping helpers implement the remapping algorithms described in [3] in a simplified manner. Because we could rely on the fact that all filesystems supporting idmapped mounts are mounted without an idmapping the translation step from or into the filesystem idmapping could be skipped. In order to support idmapped mounts of filesystem's mountable with an idmapping the translation step we were able to skip before cannot be skipped anymore. A filesystem mounted with an idmapping is very likely to not use an identity mapping and will instead use a non-identity mapping. So the translation step from or into the filesystem's idmapping in the remapping algorithm cannot be skipped for such filesystems. More details with examples can be found in [3]. This patch adds a few new and prepares some already existing low-level mapping helpers to perform the full translation algorithm explained in [3]. The low-level helpers can be written in a way that they only perform the additional translation step when the filesystem is indeed mounted with an idmapping. If the low-level helpers detect that they are not dealing with an idmapped mount they can simply return the relevant k{g,u}id unchanged; no remapping needs to be performed at all. The no_idmapping() helper detects whether the shortcut can be used. If the low-level helpers detected that they are dealing with an idmapped mount but the underlying filesystem is mounted without an idmapping we can rely on the previous shorcut and can continue to skip the translation step from or into the filesystem's idmapping. These checks guarantee that only the minimal amount of work is performed. As before, if idmapped mounts aren't used the low-level helpers are idempotent and no work is performed at all. This patch adds the helpers mapped_k{g,u}id_fs() and mapped_k{g,u}id_user(). Following patches will port all places to replace the old k{g,u}id_into_mnt() and k{g,u}id_from_mnt() with these two new helpers. After the conversion is done k{g,u}id_into_mnt() and k{g,u}id_from_mnt() will be removed. This also concludes the renaming of the mapping helpers we started in [4]. Now, all mapping helpers will started with the "mapped_" prefix making everything nice and consistent. The mapped_k{g,u}id_fs() helpers replace the k{g,u}id_into_mnt() helpers. They are to be used when k{g,u}ids are to be mapped from the vfs, e.g. from from struct inode's i_{g,u}id. Conversely, the mapped_k{g,u}id_user() helpers replace the k{g,u}id_from_mnt() helpers. They are to be used when k{g,u}ids are to be written to disk, e.g. when entering from a system call to change ownership of a file. This patch only introduces the helpers. It doesn't yet convert the relevant places to account for filesystem mounted with an idmapping. [1]: commit 2ca4dcc4909d ("fs/mount_setattr: tighten permission checks") [2]: https://github.com/containers/podman/issues/10374 [3]: Documentations/filesystems/idmappings.rst [4]: commit a65e58e791a1 ("fs: document and rename fsid helpers") Link: https://lore.kernel.org/r/20211123114227.3124056-5-brauner@kernel.org (v1) Link: https://lore.kernel.org/r/20211130121032.3753852-5-brauner@kernel.org (v2) Link: https://lore.kernel.org/r/20211203111707.3901969-5-brauner@kernel.org Cc: Seth Forshee Cc: Amir Goldstein Cc: Christoph Hellwig Cc: Al Viro CC: linux-fsdevel@vger.kernel.org Reviewed-by: Seth Forshee Signed-off-by: Christian Brauner --- include/linux/fs.h | 4 +- include/linux/mnt_idmapping.h | 193 +++++++++++++++++++++++++++++++++- 2 files changed, 191 insertions(+), 6 deletions(-) diff --git a/include/linux/fs.h b/include/linux/fs.h index db5ee15e36b19..57aee6ebba729 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1636,7 +1636,7 @@ static inline void i_gid_write(struct inode *inode, gid_t gid) static inline kuid_t i_uid_into_mnt(struct user_namespace *mnt_userns, const struct inode *inode) { - return kuid_into_mnt(mnt_userns, inode->i_uid); + return mapped_kuid_fs(mnt_userns, &init_user_ns, inode->i_uid); } /** @@ -1650,7 +1650,7 @@ static inline kuid_t i_uid_into_mnt(struct user_namespace *mnt_userns, static inline kgid_t i_gid_into_mnt(struct user_namespace *mnt_userns, const struct inode *inode) { - return kgid_into_mnt(mnt_userns, inode->i_gid); + return mapped_kgid_fs(mnt_userns, &init_user_ns, inode->i_gid); } /** diff --git a/include/linux/mnt_idmapping.h b/include/linux/mnt_idmapping.h index 47c7811fadfec..60341cd33ccc9 100644 --- a/include/linux/mnt_idmapping.h +++ b/include/linux/mnt_idmapping.h @@ -6,6 +6,11 @@ #include struct user_namespace; +/* + * Carries the initial idmapping of 0:0:4294967295 which is an identity + * mapping. This means that {g,u}id 0 is mapped to {g,u}id 0, {g,u}id 1 is + * mapped to {g,u}id 1, [...], {g,u}id 1000 to {g,u}id 1000, [...]. + */ extern struct user_namespace init_user_ns; /** @@ -64,9 +69,189 @@ static inline kgid_t kgid_from_mnt(struct user_namespace *mnt_userns, return KGIDT_INIT(from_kgid(mnt_userns, kgid)); } +/** + * initial_idmapping - check whether this is the initial mapping + * @ns: idmapping to check + * + * Check whether this is the initial mapping, mapping 0 to 0, 1 to 1, + * [...], 1000 to 1000 [...]. + * + * Return: true if this is the initial mapping, false if not. + */ +static inline bool initial_idmapping(const struct user_namespace *ns) +{ + return ns == &init_user_ns; +} + +/** + * no_idmapping - check whether we can skip remapping a kuid/gid + * @mnt_userns: the mount's idmapping + * @fs_userns: the filesystem's idmapping + * + * This function can be used to check whether a remapping between two + * idmappings is required. + * An idmapped mount is a mount that has an idmapping attached to it that + * is different from the filsystem's idmapping and the initial idmapping. + * If the initial mapping is used or the idmapping of the mount and the + * filesystem are identical no remapping is required. + * + * Return: true if remapping can be skipped, false if not. + */ +static inline bool no_idmapping(const struct user_namespace *mnt_userns, + const struct user_namespace *fs_userns) +{ + return initial_idmapping(mnt_userns) || mnt_userns == fs_userns; +} + +/** + * mapped_kuid_fs - map a filesystem kuid into a mnt_userns + * @mnt_userns: the mount's idmapping + * @fs_userns: the filesystem's idmapping + * @kuid : kuid to be mapped + * + * Take a @kuid and remap it from @fs_userns into @mnt_userns. Use this + * function when preparing a @kuid to be reported to userspace. + * + * If no_idmapping() determines that this is not an idmapped mount we can + * simply return @kuid unchanged. + * If initial_idmapping() tells us that the filesystem is not mounted with an + * idmapping we know the value of @kuid won't change when calling + * from_kuid() so we can simply retrieve the value via __kuid_val() + * directly. + * + * Return: @kuid mapped according to @mnt_userns. + * If @kuid has no mapping in either @mnt_userns or @fs_userns INVALID_UID is + * returned. + */ +static inline kuid_t mapped_kuid_fs(struct user_namespace *mnt_userns, + struct user_namespace *fs_userns, + kuid_t kuid) +{ + uid_t uid; + + if (no_idmapping(mnt_userns, fs_userns)) + return kuid; + if (initial_idmapping(fs_userns)) + uid = __kuid_val(kuid); + else + uid = from_kuid(fs_userns, kuid); + if (uid == (uid_t)-1) + return INVALID_UID; + return make_kuid(mnt_userns, uid); +} + +/** + * mapped_kgid_fs - map a filesystem kgid into a mnt_userns + * @mnt_userns: the mount's idmapping + * @fs_userns: the filesystem's idmapping + * @kgid : kgid to be mapped + * + * Take a @kgid and remap it from @fs_userns into @mnt_userns. Use this + * function when preparing a @kgid to be reported to userspace. + * + * If no_idmapping() determines that this is not an idmapped mount we can + * simply return @kgid unchanged. + * If initial_idmapping() tells us that the filesystem is not mounted with an + * idmapping we know the value of @kgid won't change when calling + * from_kgid() so we can simply retrieve the value via __kgid_val() + * directly. + * + * Return: @kgid mapped according to @mnt_userns. + * If @kgid has no mapping in either @mnt_userns or @fs_userns INVALID_GID is + * returned. + */ +static inline kgid_t mapped_kgid_fs(struct user_namespace *mnt_userns, + struct user_namespace *fs_userns, + kgid_t kgid) +{ + gid_t gid; + + if (no_idmapping(mnt_userns, fs_userns)) + return kgid; + if (initial_idmapping(fs_userns)) + gid = __kgid_val(kgid); + else + gid = from_kgid(fs_userns, kgid); + if (gid == (gid_t)-1) + return INVALID_GID; + return make_kgid(mnt_userns, gid); +} + +/** + * mapped_kuid_user - map a user kuid into a mnt_userns + * @mnt_userns: the mount's idmapping + * @fs_userns: the filesystem's idmapping + * @kuid : kuid to be mapped + * + * Use the idmapping of @mnt_userns to remap a @kuid into @fs_userns. Use this + * function when preparing a @kuid to be written to disk or inode. + * + * If no_idmapping() determines that this is not an idmapped mount we can + * simply return @kuid unchanged. + * If initial_idmapping() tells us that the filesystem is not mounted with an + * idmapping we know the value of @kuid won't change when calling + * make_kuid() so we can simply retrieve the value via KUIDT_INIT() + * directly. + * + * Return: @kuid mapped according to @mnt_userns. + * If @kuid has no mapping in either @mnt_userns or @fs_userns INVALID_UID is + * returned. + */ +static inline kuid_t mapped_kuid_user(struct user_namespace *mnt_userns, + struct user_namespace *fs_userns, + kuid_t kuid) +{ + uid_t uid; + + if (no_idmapping(mnt_userns, fs_userns)) + return kuid; + uid = from_kuid(mnt_userns, kuid); + if (uid == (uid_t)-1) + return INVALID_UID; + if (initial_idmapping(fs_userns)) + return KUIDT_INIT(uid); + return make_kuid(fs_userns, uid); +} + +/** + * mapped_kgid_user - map a user kgid into a mnt_userns + * @mnt_userns: the mount's idmapping + * @fs_userns: the filesystem's idmapping + * @kgid : kgid to be mapped + * + * Use the idmapping of @mnt_userns to remap a @kgid into @fs_userns. Use this + * function when preparing a @kgid to be written to disk or inode. + * + * If no_idmapping() determines that this is not an idmapped mount we can + * simply return @kgid unchanged. + * If initial_idmapping() tells us that the filesystem is not mounted with an + * idmapping we know the value of @kgid won't change when calling + * make_kgid() so we can simply retrieve the value via KGIDT_INIT() + * directly. + * + * Return: @kgid mapped according to @mnt_userns. + * If @kgid has no mapping in either @mnt_userns or @fs_userns INVALID_GID is + * returned. + */ +static inline kgid_t mapped_kgid_user(struct user_namespace *mnt_userns, + struct user_namespace *fs_userns, + kgid_t kgid) +{ + gid_t gid; + + if (no_idmapping(mnt_userns, fs_userns)) + return kgid; + gid = from_kgid(mnt_userns, kgid); + if (gid == (gid_t)-1) + return INVALID_GID; + if (initial_idmapping(fs_userns)) + return KGIDT_INIT(gid); + return make_kgid(fs_userns, gid); +} + /** * mapped_fsuid - return caller's fsuid mapped up into a mnt_userns - * @mnt_userns: user namespace of the relevant mount + * @mnt_userns: the mount's idmapping * * Use this helper to initialize a new vfs or filesystem object based on * the caller's fsuid. A common example is initializing the i_uid field of @@ -78,12 +263,12 @@ static inline kgid_t kgid_from_mnt(struct user_namespace *mnt_userns, */ static inline kuid_t mapped_fsuid(struct user_namespace *mnt_userns) { - return kuid_from_mnt(mnt_userns, current_fsuid()); + return mapped_kuid_user(mnt_userns, &init_user_ns, current_fsuid()); } /** * mapped_fsgid - return caller's fsgid mapped up into a mnt_userns - * @mnt_userns: user namespace of the relevant mount + * @mnt_userns: the mount's idmapping * * Use this helper to initialize a new vfs or filesystem object based on * the caller's fsgid. A common example is initializing the i_gid field of @@ -95,7 +280,7 @@ static inline kuid_t mapped_fsuid(struct user_namespace *mnt_userns) */ static inline kgid_t mapped_fsgid(struct user_namespace *mnt_userns) { - return kgid_from_mnt(mnt_userns, current_fsgid()); + return mapped_kgid_user(mnt_userns, &init_user_ns, current_fsgid()); } #endif /* _LINUX_MNT_IDMAPPING_H */ -- GitLab From 8cc5c54de44c5e8e104d364a627ac4296845fc7f Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 3 Dec 2021 12:17:02 +0100 Subject: [PATCH 0297/1112] docs: update mapping documentation Now that we implement the full remapping algorithms described in our documentation remove the section about shortcircuting them. Link: https://lore.kernel.org/r/20211123114227.3124056-6-brauner@kernel.org (v1) Link: https://lore.kernel.org/r/20211130121032.3753852-6-brauner@kernel.org (v2) Link: https://lore.kernel.org/r/20211203111707.3901969-6-brauner@kernel.org Cc: Seth Forshee Cc: Amir Goldstein Cc: Christoph Hellwig Cc: Al Viro CC: linux-fsdevel@vger.kernel.org Reviewed-by: Seth Forshee Signed-off-by: Christian Brauner --- Documentation/filesystems/idmappings.rst | 72 ------------------------ 1 file changed, 72 deletions(-) diff --git a/Documentation/filesystems/idmappings.rst b/Documentation/filesystems/idmappings.rst index 1229a75ec75dd..7a879ec3b6bf0 100644 --- a/Documentation/filesystems/idmappings.rst +++ b/Documentation/filesystems/idmappings.rst @@ -952,75 +952,3 @@ The raw userspace id that is put on disk is ``u1000`` so when the user takes their home directory back to their home computer where they are assigned ``u1000`` using the initial idmapping and mount the filesystem with the initial idmapping they will see all those files owned by ``u1000``. - -Shortcircuting --------------- - -Currently, the implementation of idmapped mounts enforces that the filesystem -is mounted with the initial idmapping. The reason is simply that none of the -filesystems that we targeted were mountable with a non-initial idmapping. But -that might change soon enough. As we've seen above, thanks to the properties of -idmappings the translation works for both filesystems mounted with the initial -idmapping and filesystem with non-initial idmappings. - -Based on this current restriction to filesystem mounted with the initial -idmapping two noticeable shortcuts have been taken: - -1. We always stash a reference to the initial user namespace in ``struct - vfsmount``. Idmapped mounts are thus mounts that have a non-initial user - namespace attached to them. - - In order to support idmapped mounts this needs to be changed. Instead of - stashing the initial user namespace the user namespace the filesystem was - mounted with must be stashed. An idmapped mount is then any mount that has - a different user namespace attached then the filesystem was mounted with. - This has no user-visible consequences. - -2. The translation algorithms in ``mapped_fs*id()`` and ``i_*id_into_mnt()`` - are simplified. - - Let's consider ``mapped_fs*id()`` first. This function translates the - caller's kernel id into a kernel id in the filesystem's idmapping via - a mount's idmapping. The full algorithm is:: - - mapped_fsuid(kid): - /* Map the kernel id up into a userspace id in the mount's idmapping. */ - from_kuid(mount-idmapping, kid) = uid - - /* Map the userspace id down into a kernel id in the filesystem's idmapping. */ - make_kuid(filesystem-idmapping, uid) = kuid - - We know that the filesystem is always mounted with the initial idmapping as - we enforce this in ``mount_setattr()``. So this can be shortened to:: - - mapped_fsuid(kid): - /* Map the kernel id up into a userspace id in the mount's idmapping. */ - from_kuid(mount-idmapping, kid) = uid - - /* Map the userspace id down into a kernel id in the filesystem's idmapping. */ - KUIDT_INIT(uid) = kuid - - Similarly, for ``i_*id_into_mnt()`` which translated the filesystem's kernel - id into a mount's kernel id:: - - i_uid_into_mnt(kid): - /* Map the kernel id up into a userspace id in the filesystem's idmapping. */ - from_kuid(filesystem-idmapping, kid) = uid - - /* Map the userspace id down into a kernel id in the mounts's idmapping. */ - make_kuid(mount-idmapping, uid) = kuid - - Again, we know that the filesystem is always mounted with the initial - idmapping as we enforce this in ``mount_setattr()``. So this can be - shortened to:: - - i_uid_into_mnt(kid): - /* Map the kernel id up into a userspace id in the filesystem's idmapping. */ - __kuid_val(kid) = uid - - /* Map the userspace id down into a kernel id in the mounts's idmapping. */ - make_kuid(mount-idmapping, uid) = kuid - -Handling filesystems mounted with non-initial idmappings requires that the -translation functions be converted to their full form. They can still be -shortcircuited on non-idmapped mounts. This has no user-visible consequences. -- GitLab From 4472071331549e911a5abad41aea6e3be855a1a4 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 3 Dec 2021 12:17:03 +0100 Subject: [PATCH 0298/1112] fs: use low-level mapping helpers In a few places the vfs needs to interact with bare k{g,u}ids directly instead of struct inode. These are just a few. In previous patches we introduced low-level mapping helpers that are able to support filesystems mounted an idmapping. This patch simply converts the places to use these new helpers. Link: https://lore.kernel.org/r/20211123114227.3124056-7-brauner@kernel.org (v1) Link: https://lore.kernel.org/r/20211130121032.3753852-7-brauner@kernel.org (v2) Link: https://lore.kernel.org/r/20211203111707.3901969-7-brauner@kernel.org Cc: Seth Forshee Cc: Amir Goldstein Cc: Christoph Hellwig Cc: Al Viro CC: linux-fsdevel@vger.kernel.org Reviewed-by: Seth Forshee Signed-off-by: Christian Brauner --- fs/ksmbd/smbacl.c | 18 ++---------------- fs/ksmbd/smbacl.h | 4 ++-- fs/open.c | 4 ++-- fs/posix_acl.c | 16 ++++++++++------ security/commoncap.c | 13 ++++++++----- 5 files changed, 24 insertions(+), 31 deletions(-) diff --git a/fs/ksmbd/smbacl.c b/fs/ksmbd/smbacl.c index ab8099e0fd7f2..6ecf55ea1fed5 100644 --- a/fs/ksmbd/smbacl.c +++ b/fs/ksmbd/smbacl.c @@ -275,14 +275,7 @@ static int sid_to_id(struct user_namespace *user_ns, uid_t id; id = le32_to_cpu(psid->sub_auth[psid->num_subauth - 1]); - /* - * Translate raw sid into kuid in the server's user - * namespace. - */ - uid = make_kuid(&init_user_ns, id); - - /* If this is an idmapped mount, apply the idmapping. */ - uid = kuid_from_mnt(user_ns, uid); + uid = mapped_kuid_user(user_ns, &init_user_ns, KUIDT_INIT(id)); if (uid_valid(uid)) { fattr->cf_uid = uid; rc = 0; @@ -292,14 +285,7 @@ static int sid_to_id(struct user_namespace *user_ns, gid_t id; id = le32_to_cpu(psid->sub_auth[psid->num_subauth - 1]); - /* - * Translate raw sid into kgid in the server's user - * namespace. - */ - gid = make_kgid(&init_user_ns, id); - - /* If this is an idmapped mount, apply the idmapping. */ - gid = kgid_from_mnt(user_ns, gid); + gid = mapped_kgid_user(user_ns, &init_user_ns, KGIDT_INIT(id)); if (gid_valid(gid)) { fattr->cf_gid = gid; rc = 0; diff --git a/fs/ksmbd/smbacl.h b/fs/ksmbd/smbacl.h index eba1ebb9e92ec..811af33094291 100644 --- a/fs/ksmbd/smbacl.h +++ b/fs/ksmbd/smbacl.h @@ -217,7 +217,7 @@ static inline uid_t posix_acl_uid_translate(struct user_namespace *mnt_userns, kuid_t kuid; /* If this is an idmapped mount, apply the idmapping. */ - kuid = kuid_into_mnt(mnt_userns, pace->e_uid); + kuid = mapped_kuid_fs(mnt_userns, &init_user_ns, pace->e_uid); /* Translate the kuid into a userspace id ksmbd would see. */ return from_kuid(&init_user_ns, kuid); @@ -229,7 +229,7 @@ static inline gid_t posix_acl_gid_translate(struct user_namespace *mnt_userns, kgid_t kgid; /* If this is an idmapped mount, apply the idmapping. */ - kgid = kgid_into_mnt(mnt_userns, pace->e_gid); + kgid = mapped_kgid_fs(mnt_userns, &init_user_ns, pace->e_gid); /* Translate the kgid into a userspace id ksmbd would see. */ return from_kgid(&init_user_ns, kgid); diff --git a/fs/open.c b/fs/open.c index 2450cc1a2f64f..40a00e71865ba 100644 --- a/fs/open.c +++ b/fs/open.c @@ -653,8 +653,8 @@ int chown_common(const struct path *path, uid_t user, gid_t group) gid = make_kgid(current_user_ns(), group); mnt_userns = mnt_user_ns(path->mnt); - uid = kuid_from_mnt(mnt_userns, uid); - gid = kgid_from_mnt(mnt_userns, gid); + uid = mapped_kuid_user(mnt_userns, &init_user_ns, uid); + gid = mapped_kgid_user(mnt_userns, &init_user_ns, gid); retry_deleg: newattrs.ia_valid = ATTR_CTIME; diff --git a/fs/posix_acl.c b/fs/posix_acl.c index 632bfdcf7cc0a..4b5fb9a9b90fa 100644 --- a/fs/posix_acl.c +++ b/fs/posix_acl.c @@ -375,7 +375,9 @@ posix_acl_permission(struct user_namespace *mnt_userns, struct inode *inode, goto check_perm; break; case ACL_USER: - uid = kuid_into_mnt(mnt_userns, pa->e_uid); + uid = mapped_kuid_fs(mnt_userns, + &init_user_ns, + pa->e_uid); if (uid_eq(uid, current_fsuid())) goto mask; break; @@ -388,7 +390,9 @@ posix_acl_permission(struct user_namespace *mnt_userns, struct inode *inode, } break; case ACL_GROUP: - gid = kgid_into_mnt(mnt_userns, pa->e_gid); + gid = mapped_kgid_fs(mnt_userns, + &init_user_ns, + pa->e_gid); if (in_group_p(gid)) { found = 1; if ((pa->e_perm & want) == want) @@ -735,17 +739,17 @@ static void posix_acl_fix_xattr_userns( case ACL_USER: uid = make_kuid(from, le32_to_cpu(entry->e_id)); if (from_user) - uid = kuid_from_mnt(mnt_userns, uid); + uid = mapped_kuid_user(mnt_userns, &init_user_ns, uid); else - uid = kuid_into_mnt(mnt_userns, uid); + uid = mapped_kuid_fs(mnt_userns, &init_user_ns, uid); entry->e_id = cpu_to_le32(from_kuid(to, uid)); break; case ACL_GROUP: gid = make_kgid(from, le32_to_cpu(entry->e_id)); if (from_user) - gid = kgid_from_mnt(mnt_userns, gid); + gid = mapped_kgid_user(mnt_userns, &init_user_ns, gid); else - gid = kgid_into_mnt(mnt_userns, gid); + gid = mapped_kgid_fs(mnt_userns, &init_user_ns, gid); entry->e_id = cpu_to_le32(from_kgid(to, gid)); break; default: diff --git a/security/commoncap.c b/security/commoncap.c index 09479f71ee2ed..d288a62e29996 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -419,7 +419,7 @@ int cap_inode_getsecurity(struct user_namespace *mnt_userns, kroot = make_kuid(fs_ns, root); /* If this is an idmapped mount shift the kuid. */ - kroot = kuid_into_mnt(mnt_userns, kroot); + kroot = mapped_kuid_fs(mnt_userns, &init_user_ns, kroot); /* If the root kuid maps to a valid uid in current ns, then return * this as a nscap. */ @@ -489,6 +489,7 @@ out_free: * @size: size of @ivalue * @task_ns: user namespace of the caller * @mnt_userns: user namespace of the mount the inode was found from + * @fs_userns: user namespace of the filesystem * * If the inode has been found through an idmapped mount the user namespace of * the vfsmount must be passed through @mnt_userns. This function will then @@ -498,7 +499,8 @@ out_free: */ static kuid_t rootid_from_xattr(const void *value, size_t size, struct user_namespace *task_ns, - struct user_namespace *mnt_userns) + struct user_namespace *mnt_userns, + struct user_namespace *fs_userns) { const struct vfs_ns_cap_data *nscap = value; kuid_t rootkid; @@ -508,7 +510,7 @@ static kuid_t rootid_from_xattr(const void *value, size_t size, rootid = le32_to_cpu(nscap->rootid); rootkid = make_kuid(task_ns, rootid); - return kuid_from_mnt(mnt_userns, rootkid); + return mapped_kuid_user(mnt_userns, fs_userns, rootkid); } static bool validheader(size_t size, const struct vfs_cap_data *cap) @@ -559,7 +561,8 @@ int cap_convert_nscap(struct user_namespace *mnt_userns, struct dentry *dentry, /* user is privileged, just write the v2 */ return size; - rootid = rootid_from_xattr(*ivalue, size, task_ns, mnt_userns); + rootid = rootid_from_xattr(*ivalue, size, task_ns, mnt_userns, + &init_user_ns); if (!uid_valid(rootid)) return -EINVAL; @@ -700,7 +703,7 @@ int get_vfs_caps_from_disk(struct user_namespace *mnt_userns, /* Limit the caps to the mounter of the filesystem * or the more limited uid specified in the xattr. */ - rootkuid = kuid_into_mnt(mnt_userns, rootkuid); + rootkuid = mapped_kuid_fs(mnt_userns, &init_user_ns, rootkuid); if (!rootid_owns_currentns(rootkuid)) return -ENODATA; -- GitLab From 8b4e74ccb582797f6f0b0a50372ebd9fd2372a27 Mon Sep 17 00:00:00 2001 From: Vincent Donnefort Date: Wed, 1 Dec 2021 14:34:50 +0000 Subject: [PATCH 0299/1112] sched/fair: Fix detection of per-CPU kthreads waking a task select_idle_sibling() has a special case for tasks woken up by a per-CPU kthread, where the selected CPU is the previous one. However, the current condition for this exit path is incomplete. A task can wake up from an interrupt context (e.g. hrtimer), while a per-CPU kthread is running. A such scenario would spuriously trigger the special case described above. Also, a recent change made the idle task like a regular per-CPU kthread, hence making that situation more likely to happen (is_per_cpu_kthread(swapper) being true now). Checking for task context makes sure select_idle_sibling() will not interpret a wake up from any other context as a wake up by a per-CPU kthread. Fixes: 52262ee567ad ("sched/fair: Allow a per-CPU kthread waking a task to stack on the same CPU, to fix XFS performance regression") Signed-off-by: Vincent Donnefort Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Vincent Guittot Reviewed-by: Valentin Schneider Link: https://lore.kernel.org/r/20211201143450.479472-1-vincent.donnefort@arm.com --- kernel/sched/fair.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 884f29d079637..5cd27986b43eb 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -6398,6 +6398,7 @@ static int select_idle_sibling(struct task_struct *p, int prev, int target) * pattern is IO completions. */ if (is_per_cpu_kthread(current) && + in_task() && prev == smp_processor_id() && this_rq()->nr_running <= 1) { return prev; -- GitLab From 014ba44e8184e1acf93e0cbb7089ee847802f8f0 Mon Sep 17 00:00:00 2001 From: Vincent Donnefort Date: Mon, 29 Nov 2021 17:31:15 +0000 Subject: [PATCH 0300/1112] sched/fair: Fix per-CPU kthread and wakee stacking for asym CPU capacity select_idle_sibling() has a special case for tasks woken up by a per-CPU kthread where the selected CPU is the previous one. For asymmetric CPU capacity systems, the assumption was that the wakee couldn't have a bigger utilization during task placement than it used to have during the last activation. That was not considering uclamp.min which can completely change between two task activations and as a consequence mandates the fitness criterion asym_fits_capacity(), even for the exit path described above. Fixes: b4c9c9f15649 ("sched/fair: Prefer prev cpu in asymmetric wakeup path") Signed-off-by: Vincent Donnefort Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Valentin Schneider Reviewed-by: Dietmar Eggemann Link: https://lkml.kernel.org/r/20211129173115.4006346-1-vincent.donnefort@arm.com --- kernel/sched/fair.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 5cd27986b43eb..06722188df49a 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -6400,7 +6400,8 @@ static int select_idle_sibling(struct task_struct *p, int prev, int target) if (is_per_cpu_kthread(current) && in_task() && prev == smp_processor_id() && - this_rq()->nr_running <= 1) { + this_rq()->nr_running <= 1 && + asym_fits_capacity(task_util, prev)) { return prev; } -- GitLab From 9d0df37797453f168afdb2e6fd0353c73718ae9a Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 29 Nov 2021 18:46:44 +0100 Subject: [PATCH 0301/1112] sched: Trigger warning if ->migration_disabled counter underflows. If migrate_enable() is used more often than its counter part then it remains undetected and rq::nr_pinned will underflow, too. Add a warning if migrate_enable() is attempted if without a matching a migrate_disable(). Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/r/20211129174654.668506-2-bigeasy@linutronix.de --- kernel/sched/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 3c9b0fda64ac0..300218ad98a24 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2173,6 +2173,9 @@ void migrate_enable(void) return; } + if (WARN_ON_ONCE(!p->migration_disabled)) + return; + /* * Ensure stop_task runs either before or after this, and that * __set_cpus_allowed_ptr(SCA_MIGRATE_ENABLE) doesn't schedule(). -- GitLab From e08f343be00c3fe8f9f6ac58085c81bcdd231fab Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 29 Nov 2021 18:46:45 +0100 Subject: [PATCH 0302/1112] locking: Remove rt_rwlock_is_contended(). rt_rwlock_is_contended() has no users. It makes no sense to use it as rwlock_is_contended() because it is a sleeping lock on RT and preemption is possible. It reports always != 0 if used by a writer and even if there is a waiter then the lock might not be handed over if the current owner has the highest priority. Remove rt_rwlock_is_contended(). Reported-by: kernel test robot Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/r/20211129174654.668506-3-bigeasy@linutronix.de --- kernel/locking/spinlock_rt.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/kernel/locking/spinlock_rt.c b/kernel/locking/spinlock_rt.c index b2e553f9255bf..9e396a09fe0fd 100644 --- a/kernel/locking/spinlock_rt.c +++ b/kernel/locking/spinlock_rt.c @@ -257,12 +257,6 @@ void __sched rt_write_unlock(rwlock_t *rwlock) } EXPORT_SYMBOL(rt_write_unlock); -int __sched rt_rwlock_is_contended(rwlock_t *rwlock) -{ - return rw_base_is_contended(&rwlock->rwbase); -} -EXPORT_SYMBOL(rt_rwlock_is_contended); - #ifdef CONFIG_DEBUG_LOCK_ALLOC void __rt_rwlock_init(rwlock_t *rwlock, const char *name, struct lock_class_key *key) -- GitLab From 02ea9fc96fe976e7f7e067f38b12202f126e3f2f Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 29 Nov 2021 18:46:46 +0100 Subject: [PATCH 0303/1112] locking/rtmutex: Squash self-deadlock check for ww_rt_mutex. Similar to the issues in commits: 6467822b8cc9 ("locking/rtmutex: Prevent spurious EDEADLK return caused by ww_mutexes") a055fcc132d4 ("locking/rtmutex: Return success on deadlock for ww_mutex waiters") ww_rt_mutex_lock() should not return EDEADLK without first going through the __ww_mutex logic to set the required state. In fact, the chain-walk can deal with the spurious cycles (per the above commits) this check warns about and is trying to avoid. Therefore ignore this test for ww_rt_mutex and simply let things fall in place. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/r/20211129174654.668506-4-bigeasy@linutronix.de --- kernel/locking/rtmutex.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c index 0c6a48dfcecb3..f89620852774d 100644 --- a/kernel/locking/rtmutex.c +++ b/kernel/locking/rtmutex.c @@ -1103,8 +1103,11 @@ static int __sched task_blocks_on_rt_mutex(struct rt_mutex_base *lock, * the other will detect the deadlock and return -EDEADLOCK, * which is wrong, as the other waiter is not in a deadlock * situation. + * + * Except for ww_mutex, in that case the chain walk must already deal + * with spurious cycles, see the comments at [3] and [6]. */ - if (owner == task) + if (owner == task && !(build_ww_mutex() && ww_ctx)) return -EDEADLK; raw_spin_lock(&task->pi_lock); -- GitLab From a3642021923b26d86bb27d88c826494827612c06 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 29 Nov 2021 18:46:47 +0100 Subject: [PATCH 0304/1112] locking/rtmutex: Add rt_mutex_lock_nest_lock() and rt_mutex_lock_killable(). The locking selftest for ww-mutex expects to operate directly on the base-mutex which becomes a rtmutex on PREEMPT_RT. Add a rtmutex based implementation of mutex_lock_nest_lock() and mutex_lock_killable() named rt_mutex_lock_nest_lock() abd rt_mutex_lock_killable(). Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/r/20211129174654.668506-5-bigeasy@linutronix.de --- include/linux/rtmutex.h | 9 +++++++++ kernel/locking/rtmutex_api.c | 30 ++++++++++++++++++++++++++---- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/include/linux/rtmutex.h b/include/linux/rtmutex.h index 9deedfeec2b17..7d049883a08ac 100644 --- a/include/linux/rtmutex.h +++ b/include/linux/rtmutex.h @@ -99,13 +99,22 @@ extern void __rt_mutex_init(struct rt_mutex *lock, const char *name, struct lock #ifdef CONFIG_DEBUG_LOCK_ALLOC extern void rt_mutex_lock_nested(struct rt_mutex *lock, unsigned int subclass); +extern void _rt_mutex_lock_nest_lock(struct rt_mutex *lock, struct lockdep_map *nest_lock); #define rt_mutex_lock(lock) rt_mutex_lock_nested(lock, 0) +#define rt_mutex_lock_nest_lock(lock, nest_lock) \ + do { \ + typecheck(struct lockdep_map *, &(nest_lock)->dep_map); \ + _rt_mutex_lock_nest_lock(lock, &(nest_lock)->dep_map); \ + } while (0) + #else extern void rt_mutex_lock(struct rt_mutex *lock); #define rt_mutex_lock_nested(lock, subclass) rt_mutex_lock(lock) +#define rt_mutex_lock_nest_lock(lock, nest_lock) rt_mutex_lock(lock) #endif extern int rt_mutex_lock_interruptible(struct rt_mutex *lock); +extern int rt_mutex_lock_killable(struct rt_mutex *lock); extern int rt_mutex_trylock(struct rt_mutex *lock); extern void rt_mutex_unlock(struct rt_mutex *lock); diff --git a/kernel/locking/rtmutex_api.c b/kernel/locking/rtmutex_api.c index 5c9299aaabae1..900220941caac 100644 --- a/kernel/locking/rtmutex_api.c +++ b/kernel/locking/rtmutex_api.c @@ -21,12 +21,13 @@ int max_lock_depth = 1024; */ static __always_inline int __rt_mutex_lock_common(struct rt_mutex *lock, unsigned int state, + struct lockdep_map *nest_lock, unsigned int subclass) { int ret; might_sleep(); - mutex_acquire(&lock->dep_map, subclass, 0, _RET_IP_); + mutex_acquire_nest(&lock->dep_map, subclass, 0, nest_lock, _RET_IP_); ret = __rt_mutex_lock(&lock->rtmutex, state); if (ret) mutex_release(&lock->dep_map, _RET_IP_); @@ -48,10 +49,16 @@ EXPORT_SYMBOL(rt_mutex_base_init); */ void __sched rt_mutex_lock_nested(struct rt_mutex *lock, unsigned int subclass) { - __rt_mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, subclass); + __rt_mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, NULL, subclass); } EXPORT_SYMBOL_GPL(rt_mutex_lock_nested); +void __sched _rt_mutex_lock_nest_lock(struct rt_mutex *lock, struct lockdep_map *nest_lock) +{ + __rt_mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, nest_lock, 0); +} +EXPORT_SYMBOL_GPL(_rt_mutex_lock_nest_lock); + #else /* !CONFIG_DEBUG_LOCK_ALLOC */ /** @@ -61,7 +68,7 @@ EXPORT_SYMBOL_GPL(rt_mutex_lock_nested); */ void __sched rt_mutex_lock(struct rt_mutex *lock) { - __rt_mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0); + __rt_mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, NULL, 0); } EXPORT_SYMBOL_GPL(rt_mutex_lock); #endif @@ -77,10 +84,25 @@ EXPORT_SYMBOL_GPL(rt_mutex_lock); */ int __sched rt_mutex_lock_interruptible(struct rt_mutex *lock) { - return __rt_mutex_lock_common(lock, TASK_INTERRUPTIBLE, 0); + return __rt_mutex_lock_common(lock, TASK_INTERRUPTIBLE, NULL, 0); } EXPORT_SYMBOL_GPL(rt_mutex_lock_interruptible); +/** + * rt_mutex_lock_killable - lock a rt_mutex killable + * + * @lock: the rt_mutex to be locked + * + * Returns: + * 0 on success + * -EINTR when interrupted by a signal + */ +int __sched rt_mutex_lock_killable(struct rt_mutex *lock) +{ + return __rt_mutex_lock_common(lock, TASK_KILLABLE, NULL, 0); +} +EXPORT_SYMBOL_GPL(rt_mutex_lock_killable); + /** * rt_mutex_trylock - try to lock a rt_mutex * -- GitLab From 0c1d7a2c2d32fac7ff4a644724b2d52a64184645 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 29 Nov 2021 18:46:48 +0100 Subject: [PATCH 0305/1112] lockdep: Remove softirq accounting on PREEMPT_RT. There is not really a softirq context on PREEMPT_RT. Softirqs on PREEMPT_RT are always invoked within the context of a threaded interrupt handler or within ksoftirqd. The "in-softirq" context is preemptible and is protected by a per-CPU lock to ensure mutual exclusion. There is no difference on PREEMPT_RT between spin_lock_irq() and spin_lock() because the former does not disable interrupts. Therefore if a lock is used in_softirq() and locked once with spin_lock_irq() then lockdep will report this with "inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W} usage". Teach lockdep that we don't really do softirqs on -RT. Signed-off-by: Thomas Gleixner Signed-off-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/r/20211129174654.668506-6-bigeasy@linutronix.de --- include/linux/irqflags.h | 23 +++++++++++++++-------- kernel/locking/lockdep.c | 2 ++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/include/linux/irqflags.h b/include/linux/irqflags.h index 600c10da321a7..4b140938b03e2 100644 --- a/include/linux/irqflags.h +++ b/include/linux/irqflags.h @@ -71,14 +71,6 @@ do { \ do { \ __this_cpu_dec(hardirq_context); \ } while (0) -# define lockdep_softirq_enter() \ -do { \ - current->softirq_context++; \ -} while (0) -# define lockdep_softirq_exit() \ -do { \ - current->softirq_context--; \ -} while (0) # define lockdep_hrtimer_enter(__hrtimer) \ ({ \ @@ -140,6 +132,21 @@ do { \ # define lockdep_irq_work_exit(__work) do { } while (0) #endif +#if defined(CONFIG_TRACE_IRQFLAGS) && !defined(CONFIG_PREEMPT_RT) +# define lockdep_softirq_enter() \ +do { \ + current->softirq_context++; \ +} while (0) +# define lockdep_softirq_exit() \ +do { \ + current->softirq_context--; \ +} while (0) + +#else +# define lockdep_softirq_enter() do { } while (0) +# define lockdep_softirq_exit() do { } while (0) +#endif + #if defined(CONFIG_IRQSOFF_TRACER) || \ defined(CONFIG_PREEMPT_TRACER) extern void stop_critical_timings(void); diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index 2270ec68f10a1..4a882f83aeb9d 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -5485,6 +5485,7 @@ static noinstr void check_flags(unsigned long flags) } } +#ifndef CONFIG_PREEMPT_RT /* * We dont accurately track softirq state in e.g. * hardirq contexts (such as on 4KSTACKS), so only @@ -5499,6 +5500,7 @@ static noinstr void check_flags(unsigned long flags) DEBUG_LOCKS_WARN_ON(!current->softirqs_enabled); } } +#endif if (!debug_locks) print_irqtrace_events(current); -- GitLab From fc78dd08e64011865799764d5b641bf823f84c66 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 29 Nov 2021 18:46:49 +0100 Subject: [PATCH 0306/1112] lockdep/selftests: Avoid using local_lock_{acquire|release}(). The local_lock related functions local_lock_acquire() local_lock_release() are part of the internal implementation and should be avoided. Define the lock as DEFINE_PER_CPU so the normal local_lock() function can be used. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/r/20211129174654.668506-7-bigeasy@linutronix.de --- lib/locking-selftest.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/locking-selftest.c b/lib/locking-selftest.c index 71652e1c397cf..4d614c74e6ec5 100644 --- a/lib/locking-selftest.c +++ b/lib/locking-selftest.c @@ -139,7 +139,7 @@ static DEFINE_RT_MUTEX(rtmutex_Z2); #endif -static local_lock_t local_A = INIT_LOCAL_LOCK(local_A); +static DEFINE_PER_CPU(local_lock_t, local_A); /* * non-inlined runtime initializers, to let separate locks share @@ -1320,7 +1320,7 @@ GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion3_soft_wlock) # define I_MUTEX(x) lockdep_reset_lock(&mutex_##x.dep_map) # define I_RWSEM(x) lockdep_reset_lock(&rwsem_##x.dep_map) # define I_WW(x) lockdep_reset_lock(&x.dep_map) -# define I_LOCAL_LOCK(x) lockdep_reset_lock(&local_##x.dep_map) +# define I_LOCAL_LOCK(x) lockdep_reset_lock(this_cpu_ptr(&local_##x.dep_map)) #ifdef CONFIG_RT_MUTEXES # define I_RTMUTEX(x) lockdep_reset_lock(&rtmutex_##x.dep_map) #endif @@ -1380,7 +1380,7 @@ static void reset_locks(void) init_shared_classes(); raw_spin_lock_init(&raw_lock_A); raw_spin_lock_init(&raw_lock_B); - local_lock_init(&local_A); + local_lock_init(this_cpu_ptr(&local_A)); ww_mutex_init(&o, &ww_lockdep); ww_mutex_init(&o2, &ww_lockdep); ww_mutex_init(&o3, &ww_lockdep); memset(&t, 0, sizeof(t)); memset(&t2, 0, sizeof(t2)); @@ -2646,8 +2646,8 @@ static void wait_context_tests(void) static void local_lock_2(void) { - local_lock_acquire(&local_A); /* IRQ-ON */ - local_lock_release(&local_A); + local_lock(&local_A); /* IRQ-ON */ + local_unlock(&local_A); HARDIRQ_ENTER(); spin_lock(&lock_A); /* IN-IRQ */ @@ -2656,18 +2656,18 @@ static void local_lock_2(void) HARDIRQ_DISABLE(); spin_lock(&lock_A); - local_lock_acquire(&local_A); /* IN-IRQ <-> IRQ-ON cycle, false */ - local_lock_release(&local_A); + local_lock(&local_A); /* IN-IRQ <-> IRQ-ON cycle, false */ + local_unlock(&local_A); spin_unlock(&lock_A); HARDIRQ_ENABLE(); } static void local_lock_3A(void) { - local_lock_acquire(&local_A); /* IRQ-ON */ + local_lock(&local_A); /* IRQ-ON */ spin_lock(&lock_B); /* IRQ-ON */ spin_unlock(&lock_B); - local_lock_release(&local_A); + local_unlock(&local_A); HARDIRQ_ENTER(); spin_lock(&lock_A); /* IN-IRQ */ @@ -2676,18 +2676,18 @@ static void local_lock_3A(void) HARDIRQ_DISABLE(); spin_lock(&lock_A); - local_lock_acquire(&local_A); /* IN-IRQ <-> IRQ-ON cycle only if we count local_lock(), false */ - local_lock_release(&local_A); + local_lock(&local_A); /* IN-IRQ <-> IRQ-ON cycle only if we count local_lock(), false */ + local_unlock(&local_A); spin_unlock(&lock_A); HARDIRQ_ENABLE(); } static void local_lock_3B(void) { - local_lock_acquire(&local_A); /* IRQ-ON */ + local_lock(&local_A); /* IRQ-ON */ spin_lock(&lock_B); /* IRQ-ON */ spin_unlock(&lock_B); - local_lock_release(&local_A); + local_unlock(&local_A); HARDIRQ_ENTER(); spin_lock(&lock_A); /* IN-IRQ */ @@ -2696,8 +2696,8 @@ static void local_lock_3B(void) HARDIRQ_DISABLE(); spin_lock(&lock_A); - local_lock_acquire(&local_A); /* IN-IRQ <-> IRQ-ON cycle only if we count local_lock(), false */ - local_lock_release(&local_A); + local_lock(&local_A); /* IN-IRQ <-> IRQ-ON cycle only if we count local_lock(), false */ + local_unlock(&local_A); spin_unlock(&lock_A); HARDIRQ_ENABLE(); @@ -2812,7 +2812,7 @@ void locking_selftest(void) printk("------------------------\n"); printk("| Locking API testsuite:\n"); printk("----------------------------------------------------------------------------\n"); - printk(" | spin |wlock |rlock |mutex | wsem | rsem |\n"); + printk(" | spin |wlock |rlock |mutex | wsem | rsem |rtmutex\n"); printk(" --------------------------------------------------------------------------\n"); init_shared_classes(); -- GitLab From 512bf713cb4c8a42ae76e5ba1a78e70a768af301 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 29 Nov 2021 18:46:50 +0100 Subject: [PATCH 0307/1112] lockdep/selftests: Unbalanced migrate_disable() & rcu_read_lock(). The tests with unbalanced lock() + unlock() operation leave a modified preemption counter behind which is then reset to its original value after the test. The spin_lock() function on PREEMPT_RT does not include a preempt_disable() statement but migrate_disable() and read_rcu_lock(). As a consequence both counter never get back to their original value and the system explodes later after the selftest. In the double-unlock case on PREEMPT_RT, the migrate_disable() and RCU code will trigger a warning which should be avoided. These counter should not be decremented below their initial value. Save both counters and bring them back to their original value after the test. In the double-unlock case, increment both counter in advance to they become balanced after the double unlock. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/r/20211129174654.668506-8-bigeasy@linutronix.de --- lib/locking-selftest.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/locking-selftest.c b/lib/locking-selftest.c index 4d614c74e6ec5..417056ba28e1f 100644 --- a/lib/locking-selftest.c +++ b/lib/locking-selftest.c @@ -712,12 +712,18 @@ GENERATE_TESTCASE(ABCDBCDA_rtmutex); #undef E +#ifdef CONFIG_PREEMPT_RT +# define RT_PREPARE_DBL_UNLOCK() { migrate_disable(); rcu_read_lock(); } +#else +# define RT_PREPARE_DBL_UNLOCK() +#endif /* * Double unlock: */ #define E() \ \ LOCK(A); \ + RT_PREPARE_DBL_UNLOCK(); \ UNLOCK(A); \ UNLOCK(A); /* fail */ @@ -1398,7 +1404,13 @@ static int unexpected_testcase_failures; static void dotest(void (*testcase_fn)(void), int expected, int lockclass_mask) { - unsigned long saved_preempt_count = preempt_count(); + int saved_preempt_count = preempt_count(); +#ifdef CONFIG_PREEMPT_RT +#ifdef CONFIG_SMP + int saved_mgd_count = current->migration_disabled; +#endif + int saved_rcu_count = current->rcu_read_lock_nesting; +#endif WARN_ON(irqs_disabled()); @@ -1432,6 +1444,18 @@ static void dotest(void (*testcase_fn)(void), int expected, int lockclass_mask) * count, so restore it: */ preempt_count_set(saved_preempt_count); + +#ifdef CONFIG_PREEMPT_RT +#ifdef CONFIG_SMP + while (current->migration_disabled > saved_mgd_count) + migrate_enable(); +#endif + + while (current->rcu_read_lock_nesting > saved_rcu_count) + rcu_read_unlock(); + WARN_ON_ONCE(current->rcu_read_lock_nesting < saved_rcu_count); +#endif + #ifdef CONFIG_TRACE_IRQFLAGS if (softirq_count()) current->softirqs_enabled = 0; -- GitLab From a529f8db897625859b640b565325463e5d5ff01e Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 29 Nov 2021 18:46:51 +0100 Subject: [PATCH 0308/1112] lockdep/selftests: Skip the softirq related tests on PREEMPT_RT The softirq context on PREEMPT_RT is different compared to !PREEMPT_RT. As such lockdep_softirq_enter() is a nop and the all the "softirq safe" tests fail on PREEMPT_RT because there is no difference. Skip the softirq context tests on PREEMPT_RT. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/r/20211129174654.668506-9-bigeasy@linutronix.de --- lib/locking-selftest.c | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/lib/locking-selftest.c b/lib/locking-selftest.c index 417056ba28e1f..9031f50905aed 100644 --- a/lib/locking-selftest.c +++ b/lib/locking-selftest.c @@ -26,6 +26,12 @@ #include #include +#ifdef CONFIG_PREEMPT_RT +# define NON_RT(...) +#else +# define NON_RT(...) __VA_ARGS__ +#endif + /* * Change this to 1 if you want to see the failure printouts: */ @@ -808,6 +814,7 @@ GENERATE_PERMUTATIONS_2_EVENTS(irqsafe1_hard_rlock) #include "locking-selftest-wlock-hardirq.h" GENERATE_PERMUTATIONS_2_EVENTS(irqsafe1_hard_wlock) +#ifndef CONFIG_PREEMPT_RT #include "locking-selftest-spin-softirq.h" GENERATE_PERMUTATIONS_2_EVENTS(irqsafe1_soft_spin) @@ -816,10 +823,12 @@ GENERATE_PERMUTATIONS_2_EVENTS(irqsafe1_soft_rlock) #include "locking-selftest-wlock-softirq.h" GENERATE_PERMUTATIONS_2_EVENTS(irqsafe1_soft_wlock) +#endif #undef E1 #undef E2 +#ifndef CONFIG_PREEMPT_RT /* * Enabling hardirqs with a softirq-safe lock held: */ @@ -852,6 +861,8 @@ GENERATE_PERMUTATIONS_2_EVENTS(irqsafe2A_rlock) #undef E1 #undef E2 +#endif + /* * Enabling irqs with an irq-safe lock held: */ @@ -881,6 +892,7 @@ GENERATE_PERMUTATIONS_2_EVENTS(irqsafe2B_hard_rlock) #include "locking-selftest-wlock-hardirq.h" GENERATE_PERMUTATIONS_2_EVENTS(irqsafe2B_hard_wlock) +#ifndef CONFIG_PREEMPT_RT #include "locking-selftest-spin-softirq.h" GENERATE_PERMUTATIONS_2_EVENTS(irqsafe2B_soft_spin) @@ -889,6 +901,7 @@ GENERATE_PERMUTATIONS_2_EVENTS(irqsafe2B_soft_rlock) #include "locking-selftest-wlock-softirq.h" GENERATE_PERMUTATIONS_2_EVENTS(irqsafe2B_soft_wlock) +#endif #undef E1 #undef E2 @@ -927,6 +940,7 @@ GENERATE_PERMUTATIONS_3_EVENTS(irqsafe3_hard_rlock) #include "locking-selftest-wlock-hardirq.h" GENERATE_PERMUTATIONS_3_EVENTS(irqsafe3_hard_wlock) +#ifndef CONFIG_PREEMPT_RT #include "locking-selftest-spin-softirq.h" GENERATE_PERMUTATIONS_3_EVENTS(irqsafe3_soft_spin) @@ -935,6 +949,7 @@ GENERATE_PERMUTATIONS_3_EVENTS(irqsafe3_soft_rlock) #include "locking-selftest-wlock-softirq.h" GENERATE_PERMUTATIONS_3_EVENTS(irqsafe3_soft_wlock) +#endif #undef E1 #undef E2 @@ -975,6 +990,7 @@ GENERATE_PERMUTATIONS_3_EVENTS(irqsafe4_hard_rlock) #include "locking-selftest-wlock-hardirq.h" GENERATE_PERMUTATIONS_3_EVENTS(irqsafe4_hard_wlock) +#ifndef CONFIG_PREEMPT_RT #include "locking-selftest-spin-softirq.h" GENERATE_PERMUTATIONS_3_EVENTS(irqsafe4_soft_spin) @@ -983,6 +999,7 @@ GENERATE_PERMUTATIONS_3_EVENTS(irqsafe4_soft_rlock) #include "locking-selftest-wlock-softirq.h" GENERATE_PERMUTATIONS_3_EVENTS(irqsafe4_soft_wlock) +#endif #undef E1 #undef E2 @@ -1037,6 +1054,7 @@ GENERATE_PERMUTATIONS_3_EVENTS(irq_inversion_hard_rlock) #include "locking-selftest-wlock-hardirq.h" GENERATE_PERMUTATIONS_3_EVENTS(irq_inversion_hard_wlock) +#ifndef CONFIG_PREEMPT_RT #include "locking-selftest-spin-softirq.h" GENERATE_PERMUTATIONS_3_EVENTS(irq_inversion_soft_spin) @@ -1045,6 +1063,7 @@ GENERATE_PERMUTATIONS_3_EVENTS(irq_inversion_soft_rlock) #include "locking-selftest-wlock-softirq.h" GENERATE_PERMUTATIONS_3_EVENTS(irq_inversion_soft_wlock) +#endif #undef E1 #undef E2 @@ -1212,12 +1231,14 @@ GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion_hard_rlock) #include "locking-selftest-wlock.h" GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion_hard_wlock) +#ifndef CONFIG_PREEMPT_RT #include "locking-selftest-softirq.h" #include "locking-selftest-rlock.h" GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion_soft_rlock) #include "locking-selftest-wlock.h" GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion_soft_wlock) +#endif #undef E1 #undef E2 @@ -1258,12 +1279,14 @@ GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion2_hard_rlock) #include "locking-selftest-wlock.h" GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion2_hard_wlock) +#ifndef CONFIG_PREEMPT_RT #include "locking-selftest-softirq.h" #include "locking-selftest-rlock.h" GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion2_soft_rlock) #include "locking-selftest-wlock.h" GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion2_soft_wlock) +#endif #undef E1 #undef E2 @@ -1312,12 +1335,14 @@ GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion3_hard_rlock) #include "locking-selftest-wlock.h" GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion3_hard_wlock) +#ifndef CONFIG_PREEMPT_RT #include "locking-selftest-softirq.h" #include "locking-selftest-rlock.h" GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion3_soft_rlock) #include "locking-selftest-wlock.h" GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion3_soft_wlock) +#endif #ifdef CONFIG_DEBUG_LOCK_ALLOC # define I_SPINLOCK(x) lockdep_reset_lock(&lock_##x.dep_map) @@ -1523,7 +1548,7 @@ static inline void print_testname(const char *testname) #define DO_TESTCASE_2x2RW(desc, name, nr) \ DO_TESTCASE_2RW("hard-"desc, name##_hard, nr) \ - DO_TESTCASE_2RW("soft-"desc, name##_soft, nr) \ + NON_RT(DO_TESTCASE_2RW("soft-"desc, name##_soft, nr)) \ #define DO_TESTCASE_6x2x2RW(desc, name) \ DO_TESTCASE_2x2RW(desc, name, 123); \ @@ -1571,19 +1596,19 @@ static inline void print_testname(const char *testname) #define DO_TESTCASE_2I(desc, name, nr) \ DO_TESTCASE_1("hard-"desc, name##_hard, nr); \ - DO_TESTCASE_1("soft-"desc, name##_soft, nr); + NON_RT(DO_TESTCASE_1("soft-"desc, name##_soft, nr)); #define DO_TESTCASE_2IB(desc, name, nr) \ DO_TESTCASE_1B("hard-"desc, name##_hard, nr); \ - DO_TESTCASE_1B("soft-"desc, name##_soft, nr); + NON_RT(DO_TESTCASE_1B("soft-"desc, name##_soft, nr)); #define DO_TESTCASE_6I(desc, name, nr) \ DO_TESTCASE_3("hard-"desc, name##_hard, nr); \ - DO_TESTCASE_3("soft-"desc, name##_soft, nr); + NON_RT(DO_TESTCASE_3("soft-"desc, name##_soft, nr)); #define DO_TESTCASE_6IRW(desc, name, nr) \ DO_TESTCASE_3RW("hard-"desc, name##_hard, nr); \ - DO_TESTCASE_3RW("soft-"desc, name##_soft, nr); + NON_RT(DO_TESTCASE_3RW("soft-"desc, name##_soft, nr)); #define DO_TESTCASE_2x3(desc, name) \ DO_TESTCASE_3(desc, name, 12); \ @@ -2909,12 +2934,11 @@ void locking_selftest(void) DO_TESTCASE_6x1RR("rlock W1R2/R2R3/W3W1", W1R2_R2R3_W3W1); printk(" --------------------------------------------------------------------------\n"); - /* * irq-context testcases: */ DO_TESTCASE_2x6("irqs-on + irq-safe-A", irqsafe1); - DO_TESTCASE_2x3("sirq-safe-A => hirqs-on", irqsafe2A); + NON_RT(DO_TESTCASE_2x3("sirq-safe-A => hirqs-on", irqsafe2A)); DO_TESTCASE_2x6("safe-A + irqs-on", irqsafe2B); DO_TESTCASE_6x6("safe-A + unsafe-B #1", irqsafe3); DO_TESTCASE_6x6("safe-A + unsafe-B #2", irqsafe4); -- GitLab From 9a75bd0c52df6cff44735f73dfb9d00e67969fc5 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 29 Nov 2021 18:46:52 +0100 Subject: [PATCH 0309/1112] lockdep/selftests: Adapt ww-tests for PREEMPT_RT The ww-mutex selftest operates directly on ww_mutex::base and assumes its type is struct mutex. This isn't true on PREEMPT_RT which turns the mutex into a rtmutex. Add a ww_mutex_base_ abstraction which maps to the relevant mutex_ or rt_mutex_ function. Change the CONFIG_DEBUG_MUTEXES ifdef to DEBUG_WW_MUTEXES. The latter is true for the MUTEX and RTMUTEX implementation of WW-MUTEX. The assignment is required in order to pass the tests. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/r/20211129174654.668506-10-bigeasy@linutronix.de --- lib/locking-selftest.c | 76 +++++++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 30 deletions(-) diff --git a/lib/locking-selftest.c b/lib/locking-selftest.c index 9031f50905aed..8d24279fad055 100644 --- a/lib/locking-selftest.c +++ b/lib/locking-selftest.c @@ -1700,6 +1700,22 @@ static void ww_test_fail_acquire(void) #endif } +#ifdef CONFIG_PREEMPT_RT +#define ww_mutex_base_lock(b) rt_mutex_lock(b) +#define ww_mutex_base_trylock(b) rt_mutex_trylock(b) +#define ww_mutex_base_lock_nest_lock(b, b2) rt_mutex_lock_nest_lock(b, b2) +#define ww_mutex_base_lock_interruptible(b) rt_mutex_lock_interruptible(b) +#define ww_mutex_base_lock_killable(b) rt_mutex_lock_killable(b) +#define ww_mutex_base_unlock(b) rt_mutex_unlock(b) +#else +#define ww_mutex_base_lock(b) mutex_lock(b) +#define ww_mutex_base_trylock(b) mutex_trylock(b) +#define ww_mutex_base_lock_nest_lock(b, b2) mutex_lock_nest_lock(b, b2) +#define ww_mutex_base_lock_interruptible(b) mutex_lock_interruptible(b) +#define ww_mutex_base_lock_killable(b) mutex_lock_killable(b) +#define ww_mutex_base_unlock(b) mutex_unlock(b) +#endif + static void ww_test_normal(void) { int ret; @@ -1714,50 +1730,50 @@ static void ww_test_normal(void) /* mutex_lock (and indirectly, mutex_lock_nested) */ o.ctx = (void *)~0UL; - mutex_lock(&o.base); - mutex_unlock(&o.base); + ww_mutex_base_lock(&o.base); + ww_mutex_base_unlock(&o.base); WARN_ON(o.ctx != (void *)~0UL); /* mutex_lock_interruptible (and *_nested) */ o.ctx = (void *)~0UL; - ret = mutex_lock_interruptible(&o.base); + ret = ww_mutex_base_lock_interruptible(&o.base); if (!ret) - mutex_unlock(&o.base); + ww_mutex_base_unlock(&o.base); else WARN_ON(1); WARN_ON(o.ctx != (void *)~0UL); /* mutex_lock_killable (and *_nested) */ o.ctx = (void *)~0UL; - ret = mutex_lock_killable(&o.base); + ret = ww_mutex_base_lock_killable(&o.base); if (!ret) - mutex_unlock(&o.base); + ww_mutex_base_unlock(&o.base); else WARN_ON(1); WARN_ON(o.ctx != (void *)~0UL); /* trylock, succeeding */ o.ctx = (void *)~0UL; - ret = mutex_trylock(&o.base); + ret = ww_mutex_base_trylock(&o.base); WARN_ON(!ret); if (ret) - mutex_unlock(&o.base); + ww_mutex_base_unlock(&o.base); else WARN_ON(1); WARN_ON(o.ctx != (void *)~0UL); /* trylock, failing */ o.ctx = (void *)~0UL; - mutex_lock(&o.base); - ret = mutex_trylock(&o.base); + ww_mutex_base_lock(&o.base); + ret = ww_mutex_base_trylock(&o.base); WARN_ON(ret); - mutex_unlock(&o.base); + ww_mutex_base_unlock(&o.base); WARN_ON(o.ctx != (void *)~0UL); /* nest_lock */ o.ctx = (void *)~0UL; - mutex_lock_nest_lock(&o.base, &t); - mutex_unlock(&o.base); + ww_mutex_base_lock_nest_lock(&o.base, &t); + ww_mutex_base_unlock(&o.base); WARN_ON(o.ctx != (void *)~0UL); } @@ -1770,7 +1786,7 @@ static void ww_test_two_contexts(void) static void ww_test_diff_class(void) { WWAI(&t); -#ifdef CONFIG_DEBUG_MUTEXES +#ifdef DEBUG_WW_MUTEXES t.ww_class = NULL; #endif WWL(&o, &t); @@ -1834,7 +1850,7 @@ static void ww_test_edeadlk_normal(void) { int ret; - mutex_lock(&o2.base); + ww_mutex_base_lock(&o2.base); o2.ctx = &t2; mutex_release(&o2.base.dep_map, _THIS_IP_); @@ -1850,7 +1866,7 @@ static void ww_test_edeadlk_normal(void) o2.ctx = NULL; mutex_acquire(&o2.base.dep_map, 0, 1, _THIS_IP_); - mutex_unlock(&o2.base); + ww_mutex_base_unlock(&o2.base); WWU(&o); WWL(&o2, &t); @@ -1860,7 +1876,7 @@ static void ww_test_edeadlk_normal_slow(void) { int ret; - mutex_lock(&o2.base); + ww_mutex_base_lock(&o2.base); mutex_release(&o2.base.dep_map, _THIS_IP_); o2.ctx = &t2; @@ -1876,7 +1892,7 @@ static void ww_test_edeadlk_normal_slow(void) o2.ctx = NULL; mutex_acquire(&o2.base.dep_map, 0, 1, _THIS_IP_); - mutex_unlock(&o2.base); + ww_mutex_base_unlock(&o2.base); WWU(&o); ww_mutex_lock_slow(&o2, &t); @@ -1886,7 +1902,7 @@ static void ww_test_edeadlk_no_unlock(void) { int ret; - mutex_lock(&o2.base); + ww_mutex_base_lock(&o2.base); o2.ctx = &t2; mutex_release(&o2.base.dep_map, _THIS_IP_); @@ -1902,7 +1918,7 @@ static void ww_test_edeadlk_no_unlock(void) o2.ctx = NULL; mutex_acquire(&o2.base.dep_map, 0, 1, _THIS_IP_); - mutex_unlock(&o2.base); + ww_mutex_base_unlock(&o2.base); WWL(&o2, &t); } @@ -1911,7 +1927,7 @@ static void ww_test_edeadlk_no_unlock_slow(void) { int ret; - mutex_lock(&o2.base); + ww_mutex_base_lock(&o2.base); mutex_release(&o2.base.dep_map, _THIS_IP_); o2.ctx = &t2; @@ -1927,7 +1943,7 @@ static void ww_test_edeadlk_no_unlock_slow(void) o2.ctx = NULL; mutex_acquire(&o2.base.dep_map, 0, 1, _THIS_IP_); - mutex_unlock(&o2.base); + ww_mutex_base_unlock(&o2.base); ww_mutex_lock_slow(&o2, &t); } @@ -1936,7 +1952,7 @@ static void ww_test_edeadlk_acquire_more(void) { int ret; - mutex_lock(&o2.base); + ww_mutex_base_lock(&o2.base); mutex_release(&o2.base.dep_map, _THIS_IP_); o2.ctx = &t2; @@ -1957,7 +1973,7 @@ static void ww_test_edeadlk_acquire_more_slow(void) { int ret; - mutex_lock(&o2.base); + ww_mutex_base_lock(&o2.base); mutex_release(&o2.base.dep_map, _THIS_IP_); o2.ctx = &t2; @@ -1978,11 +1994,11 @@ static void ww_test_edeadlk_acquire_more_edeadlk(void) { int ret; - mutex_lock(&o2.base); + ww_mutex_base_lock(&o2.base); mutex_release(&o2.base.dep_map, _THIS_IP_); o2.ctx = &t2; - mutex_lock(&o3.base); + ww_mutex_base_lock(&o3.base); mutex_release(&o3.base.dep_map, _THIS_IP_); o3.ctx = &t2; @@ -2004,11 +2020,11 @@ static void ww_test_edeadlk_acquire_more_edeadlk_slow(void) { int ret; - mutex_lock(&o2.base); + ww_mutex_base_lock(&o2.base); mutex_release(&o2.base.dep_map, _THIS_IP_); o2.ctx = &t2; - mutex_lock(&o3.base); + ww_mutex_base_lock(&o3.base); mutex_release(&o3.base.dep_map, _THIS_IP_); o3.ctx = &t2; @@ -2029,7 +2045,7 @@ static void ww_test_edeadlk_acquire_wrong(void) { int ret; - mutex_lock(&o2.base); + ww_mutex_base_lock(&o2.base); mutex_release(&o2.base.dep_map, _THIS_IP_); o2.ctx = &t2; @@ -2054,7 +2070,7 @@ static void ww_test_edeadlk_acquire_wrong_slow(void) { int ret; - mutex_lock(&o2.base); + ww_mutex_base_lock(&o2.base); mutex_release(&o2.base.dep_map, _THIS_IP_); o2.ctx = &t2; -- GitLab From c0bed69daf4b67809b58cc7cd81a8fa4f45bc161 Mon Sep 17 00:00:00 2001 From: Kefeng Wang Date: Fri, 3 Dec 2021 15:59:34 +0800 Subject: [PATCH 0310/1112] locking: Make owner_on_cpu() into Move the owner_on_cpu() from kernel/locking/rwsem.c into include/linux/sched.h with under CONFIG_SMP, then use it in the mutex/rwsem/rtmutex to simplify the code. Signed-off-by: Kefeng Wang Signed-off-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/r/20211203075935.136808-2-wangkefeng.wang@huawei.com --- include/linux/sched.h | 9 +++++++++ kernel/locking/mutex.c | 11 ++--------- kernel/locking/rtmutex.c | 5 ++--- kernel/locking/rwsem.c | 9 --------- 4 files changed, 13 insertions(+), 21 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 78c351e35fec6..ff609d9c2f21f 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2171,6 +2171,15 @@ extern long sched_getaffinity(pid_t pid, struct cpumask *mask); #endif #ifdef CONFIG_SMP +static inline bool owner_on_cpu(struct task_struct *owner) +{ + /* + * As lock holder preemption issue, we both skip spinning if + * task is not on cpu or its cpu is preempted + */ + return owner->on_cpu && !vcpu_is_preempted(task_cpu(owner)); +} + /* Returns effective CPU energy utilization, as seen by the scheduler */ unsigned long sched_cpu_util(int cpu, unsigned long max); #endif /* CONFIG_SMP */ diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c index db19136111921..5e3585950ec8f 100644 --- a/kernel/locking/mutex.c +++ b/kernel/locking/mutex.c @@ -367,8 +367,7 @@ bool mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner, /* * Use vcpu_is_preempted to detect lock holder preemption issue. */ - if (!owner->on_cpu || need_resched() || - vcpu_is_preempted(task_cpu(owner))) { + if (!owner_on_cpu(owner) || need_resched()) { ret = false; break; } @@ -403,14 +402,8 @@ static inline int mutex_can_spin_on_owner(struct mutex *lock) * structure won't go away during the spinning period. */ owner = __mutex_owner(lock); - - /* - * As lock holder preemption issue, we both skip spinning if task is not - * on cpu or its cpu is preempted - */ - if (owner) - retval = owner->on_cpu && !vcpu_is_preempted(task_cpu(owner)); + retval = owner_on_cpu(owner); /* * If lock->owner is not set, the mutex has been released. Return true diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c index f89620852774d..0c1f2e3f019a3 100644 --- a/kernel/locking/rtmutex.c +++ b/kernel/locking/rtmutex.c @@ -1382,9 +1382,8 @@ static bool rtmutex_spin_on_owner(struct rt_mutex_base *lock, * for CONFIG_PREEMPT_RCU=y) * - the VCPU on which owner runs is preempted */ - if (!owner->on_cpu || need_resched() || - rt_mutex_waiter_is_top_waiter(lock, waiter) || - vcpu_is_preempted(task_cpu(owner))) { + if (!owner_on_cpu(owner) || need_resched() || + rt_mutex_waiter_is_top_waiter(lock, waiter)) { res = false; break; } diff --git a/kernel/locking/rwsem.c b/kernel/locking/rwsem.c index c51387a432657..b92d0a8305682 100644 --- a/kernel/locking/rwsem.c +++ b/kernel/locking/rwsem.c @@ -613,15 +613,6 @@ static inline bool rwsem_try_write_lock_unqueued(struct rw_semaphore *sem) return false; } -static inline bool owner_on_cpu(struct task_struct *owner) -{ - /* - * As lock holder preemption issue, we both skip spinning if - * task is not on cpu or its cpu is preempted - */ - return owner->on_cpu && !vcpu_is_preempted(task_cpu(owner)); -} - static inline bool rwsem_can_spin_on_owner(struct rw_semaphore *sem) { struct task_struct *owner; -- GitLab From 4cf75fd4a2545ca4deea992f929602c9fdbe8058 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Fri, 3 Dec 2021 15:59:35 +0800 Subject: [PATCH 0311/1112] locking: Mark racy reads of owner->on_cpu One of the more frequent data races reported by KCSAN is the racy read in mutex_spin_on_owner(), which is usually reported as "race of unknown origin" without showing the writer. This is due to the racing write occurring in kernel/sched. Locally enabling KCSAN in kernel/sched shows: | write (marked) to 0xffff97f205079934 of 4 bytes by task 316 on cpu 6: | finish_task kernel/sched/core.c:4632 [inline] | finish_task_switch kernel/sched/core.c:4848 | context_switch kernel/sched/core.c:4975 [inline] | __schedule kernel/sched/core.c:6253 | schedule kernel/sched/core.c:6326 | schedule_preempt_disabled kernel/sched/core.c:6385 | __mutex_lock_common kernel/locking/mutex.c:680 | __mutex_lock kernel/locking/mutex.c:740 [inline] | __mutex_lock_slowpath kernel/locking/mutex.c:1028 | mutex_lock kernel/locking/mutex.c:283 | tty_open_by_driver drivers/tty/tty_io.c:2062 [inline] | ... | | read to 0xffff97f205079934 of 4 bytes by task 322 on cpu 3: | mutex_spin_on_owner kernel/locking/mutex.c:370 | mutex_optimistic_spin kernel/locking/mutex.c:480 | __mutex_lock_common kernel/locking/mutex.c:610 | __mutex_lock kernel/locking/mutex.c:740 [inline] | __mutex_lock_slowpath kernel/locking/mutex.c:1028 | mutex_lock kernel/locking/mutex.c:283 | tty_open_by_driver drivers/tty/tty_io.c:2062 [inline] | ... | | value changed: 0x00000001 -> 0x00000000 This race is clearly intentional, and the potential for miscompilation is slim due to surrounding barrier() and cpu_relax(), and the value being used as a boolean. Nevertheless, marking this reader would more clearly denote intent and make it obvious that concurrency is expected. Use READ_ONCE() to avoid having to reason about compiler optimizations now and in future. With previous refactor, mark the read to owner->on_cpu in owner_on_cpu(), which immediately precedes the loop executing mutex_spin_on_owner(). Signed-off-by: Marco Elver Signed-off-by: Kefeng Wang Signed-off-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/r/20211203075935.136808-3-wangkefeng.wang@huawei.com --- include/linux/sched.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index ff609d9c2f21f..0b9b0e3f4791e 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2177,7 +2177,7 @@ static inline bool owner_on_cpu(struct task_struct *owner) * As lock holder preemption issue, we both skip spinning if * task is not on cpu or its cpu is preempted */ - return owner->on_cpu && !vcpu_is_preempted(task_cpu(owner)); + return READ_ONCE(owner->on_cpu) && !vcpu_is_preempted(task_cpu(owner)); } /* Returns effective CPU energy utilization, as seen by the scheduler */ -- GitLab From ffd0cd3c2f10e2241771056566fa0fe36b3855ce Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 18 Nov 2021 20:33:00 +0100 Subject: [PATCH 0312/1112] gfs2: Fix __gfs2_holder_init function name in kernel-doc comment The function name in the kernel-doc comment wasn't updated when the function was renamed. Fixes: b016d9a84abd ("gfs2: Save ip from gfs2_glock_nq_init") Signed-off-by: Andreas Gruenbacher --- fs/gfs2/glock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 44a7a4288956b..3f18aa51ec855 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1245,7 +1245,7 @@ out: } /** - * gfs2_holder_init - initialize a struct gfs2_holder in the default way + * __gfs2_holder_init - initialize a struct gfs2_holder in the default way * @gl: the glock * @state: the state we're requesting * @flags: the modifier flags -- GitLab From 1d05ee7e0d10283107cd6c2ed37005b67cd2f5b7 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Fri, 12 Nov 2021 13:52:06 -0600 Subject: [PATCH 0313/1112] gfs2: remove redundant set of INSTANTIATE_NEEDED Function rgrp_go_inval calls gfs2_rgrp_brelse to invalidate the in-core rgrp structures. After the call it set GLF_INSTANTIATE_NEEDED, which is redundant, since gfs2_rgrp_brelse also sets it. This patch simply removes the redundant set_bit. Signed-off-by: Bob Peterson Signed-off-by: Andreas Gruenbacher --- fs/gfs2/glops.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 650ad77c4d0b4..e054ddae78349 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -228,7 +228,6 @@ static void rgrp_go_inval(struct gfs2_glock *gl, int flags) gfs2_rgrp_brelse(rgd); WARN_ON_ONCE(!(flags & DIO_METADATA)); truncate_inode_pages_range(mapping, start, end); - set_bit(GLF_INSTANTIATE_NEEDED, &gl->gl_flags); } static void gfs2_rgrp_go_dump(struct seq_file *seq, struct gfs2_glock *gl, -- GitLab From 8d567162ef288ee0df6674f291e3d9c290306f1e Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Tue, 30 Nov 2021 10:06:11 +0100 Subject: [PATCH 0314/1112] gfs2: Remove redundant check for GLF_INSTANTIATE_NEEDED If the GLF_INSTANTIATE_NEEDED flag isn't set, gfs2_instantiate() is a no-op. Signed-off-by: Andreas Gruenbacher --- fs/gfs2/super.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 0f93e8beca4d9..64c67090f5036 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -1244,11 +1244,9 @@ static enum dinode_demise evict_should_delete(struct inode *inode, if (ret) return SHOULD_NOT_DELETE_DINODE; - if (test_bit(GLF_INSTANTIATE_NEEDED, &ip->i_gl->gl_flags)) { - ret = gfs2_instantiate(gh); - if (ret) - return SHOULD_NOT_DELETE_DINODE; - } + ret = gfs2_instantiate(gh); + if (ret) + return SHOULD_NOT_DELETE_DINODE; /* * The inode may have been recreated in the meantime. -- GitLab From 3c5c67ec29a918dfb2ffc94429437794ddd225e8 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Mon, 29 Nov 2021 21:56:16 +0100 Subject: [PATCH 0315/1112] gfs2: Fix gfs2_instantiate description The description of gfs2_instantiate accidentally lists a glock argument, but the function takes a glock holder. Signed-off-by: Andreas Gruenbacher --- fs/gfs2/glock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 3f18aa51ec855..b7ab8430333c2 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -477,7 +477,7 @@ find_first_strong_holder(struct gfs2_glock *gl) /* * gfs2_instantiate - Call the glops instantiate function - * @gl: The glock + * @gh: The glock holder * * Returns: 0 if instantiate was successful, 2 if type specific operation is * underway, or error. -- GitLab From 02e4079913500f24ceb082d8d87d8665f044b298 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 3 Dec 2021 12:17:04 +0100 Subject: [PATCH 0316/1112] fs: remove unused low-level mapping helpers Now that we ported all places to use the new low-level mapping helpers that are able to support filesystems mounted with an idmapping we can remove the old low-level mapping helpers. With the removal of these old helpers we also conclude the renaming of the mapping helpers we started in commit a65e58e791a1 ("fs: document and rename fsid helpers"). Link: https://lore.kernel.org/r/20211123114227.3124056-8-brauner@kernel.org (v1) Link: https://lore.kernel.org/r/20211130121032.3753852-8-brauner@kernel.org (v2) Link: https://lore.kernel.org/r/20211203111707.3901969-8-brauner@kernel.org Cc: Seth Forshee Cc: Christoph Hellwig Cc: Al Viro CC: linux-fsdevel@vger.kernel.org Reviewed-by: Amir Goldstein Reviewed-by: Seth Forshee Signed-off-by: Christian Brauner --- include/linux/mnt_idmapping.h | 56 ----------------------------------- 1 file changed, 56 deletions(-) diff --git a/include/linux/mnt_idmapping.h b/include/linux/mnt_idmapping.h index 60341cd33ccc9..0c6ab3f4c9527 100644 --- a/include/linux/mnt_idmapping.h +++ b/include/linux/mnt_idmapping.h @@ -13,62 +13,6 @@ struct user_namespace; */ extern struct user_namespace init_user_ns; -/** - * kuid_into_mnt - map a kuid down into a mnt_userns - * @mnt_userns: user namespace of the relevant mount - * @kuid: kuid to be mapped - * - * Return: @kuid mapped according to @mnt_userns. - * If @kuid has no mapping INVALID_UID is returned. - */ -static inline kuid_t kuid_into_mnt(struct user_namespace *mnt_userns, - kuid_t kuid) -{ - return make_kuid(mnt_userns, __kuid_val(kuid)); -} - -/** - * kgid_into_mnt - map a kgid down into a mnt_userns - * @mnt_userns: user namespace of the relevant mount - * @kgid: kgid to be mapped - * - * Return: @kgid mapped according to @mnt_userns. - * If @kgid has no mapping INVALID_GID is returned. - */ -static inline kgid_t kgid_into_mnt(struct user_namespace *mnt_userns, - kgid_t kgid) -{ - return make_kgid(mnt_userns, __kgid_val(kgid)); -} - -/** - * kuid_from_mnt - map a kuid up into a mnt_userns - * @mnt_userns: user namespace of the relevant mount - * @kuid: kuid to be mapped - * - * Return: @kuid mapped up according to @mnt_userns. - * If @kuid has no mapping INVALID_UID is returned. - */ -static inline kuid_t kuid_from_mnt(struct user_namespace *mnt_userns, - kuid_t kuid) -{ - return KUIDT_INIT(from_kuid(mnt_userns, kuid)); -} - -/** - * kgid_from_mnt - map a kgid up into a mnt_userns - * @mnt_userns: user namespace of the relevant mount - * @kgid: kgid to be mapped - * - * Return: @kgid mapped up according to @mnt_userns. - * If @kgid has no mapping INVALID_GID is returned. - */ -static inline kgid_t kgid_from_mnt(struct user_namespace *mnt_userns, - kgid_t kgid) -{ - return KGIDT_INIT(from_kgid(mnt_userns, kgid)); -} - /** * initial_idmapping - check whether this is the initial mapping * @ns: idmapping to check -- GitLab From 209188ce75d0d357c292f6bb81d712acdd4e7db7 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 3 Dec 2021 12:17:05 +0100 Subject: [PATCH 0317/1112] fs: port higher-level mapping helpers Enable the mapped_fs{g,u}id() helpers to support filesystems mounted with an idmapping. Apart from core mapping helpers that use mapped_fs{g,u}id() to initialize struct inode's i_{g,u}id fields xfs is the only place that uses these low-level helpers directly. The patch only extends the helpers to be able to take the filesystem idmapping into account. Since we don't actually yet pass the filesystem's idmapping in no functional changes happen. This will happen in a final patch. Link: https://lore.kernel.org/r/20211123114227.3124056-9-brauner@kernel.org (v1) Link: https://lore.kernel.org/r/20211130121032.3753852-9-brauner@kernel.org (v2) Link: https://lore.kernel.org/r/20211203111707.3901969-9-brauner@kernel.org Cc: Seth Forshee Cc: Christoph Hellwig Cc: Al Viro CC: linux-fsdevel@vger.kernel.org Reviewed-by: Amir Goldstein Reviewed-by: Seth Forshee Signed-off-by: Christian Brauner --- fs/xfs/xfs_inode.c | 8 ++++---- fs/xfs/xfs_symlink.c | 4 ++-- include/linux/fs.h | 8 ++++---- include/linux/mnt_idmapping.h | 12 ++++++++---- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 64b9bf3348065..5ca689459bed4 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -988,8 +988,8 @@ xfs_create( /* * Make sure that we have allocated dquot(s) on disk. */ - error = xfs_qm_vop_dqalloc(dp, mapped_fsuid(mnt_userns), - mapped_fsgid(mnt_userns), prid, + error = xfs_qm_vop_dqalloc(dp, mapped_fsuid(mnt_userns, &init_user_ns), + mapped_fsgid(mnt_userns, &init_user_ns), prid, XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp, &pdqp); if (error) @@ -1142,8 +1142,8 @@ xfs_create_tmpfile( /* * Make sure that we have allocated dquot(s) on disk. */ - error = xfs_qm_vop_dqalloc(dp, mapped_fsuid(mnt_userns), - mapped_fsgid(mnt_userns), prid, + error = xfs_qm_vop_dqalloc(dp, mapped_fsuid(mnt_userns, &init_user_ns), + mapped_fsgid(mnt_userns, &init_user_ns), prid, XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp, &pdqp); if (error) diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c index fc2c6a4046471..a31d2e5d03214 100644 --- a/fs/xfs/xfs_symlink.c +++ b/fs/xfs/xfs_symlink.c @@ -184,8 +184,8 @@ xfs_symlink( /* * Make sure that we have allocated dquot(s) on disk. */ - error = xfs_qm_vop_dqalloc(dp, mapped_fsuid(mnt_userns), - mapped_fsgid(mnt_userns), prid, + error = xfs_qm_vop_dqalloc(dp, mapped_fsuid(mnt_userns, &init_user_ns), + mapped_fsgid(mnt_userns, &init_user_ns), prid, XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp, &pdqp); if (error) diff --git a/include/linux/fs.h b/include/linux/fs.h index 57aee6ebba729..e1f28f757f1bf 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1664,7 +1664,7 @@ static inline kgid_t i_gid_into_mnt(struct user_namespace *mnt_userns, static inline void inode_fsuid_set(struct inode *inode, struct user_namespace *mnt_userns) { - inode->i_uid = mapped_fsuid(mnt_userns); + inode->i_uid = mapped_fsuid(mnt_userns, &init_user_ns); } /** @@ -1678,7 +1678,7 @@ static inline void inode_fsuid_set(struct inode *inode, static inline void inode_fsgid_set(struct inode *inode, struct user_namespace *mnt_userns) { - inode->i_gid = mapped_fsgid(mnt_userns); + inode->i_gid = mapped_fsgid(mnt_userns, &init_user_ns); } /** @@ -1699,10 +1699,10 @@ static inline bool fsuidgid_has_mapping(struct super_block *sb, kuid_t kuid; kgid_t kgid; - kuid = mapped_fsuid(mnt_userns); + kuid = mapped_fsuid(mnt_userns, &init_user_ns); if (!uid_valid(kuid)) return false; - kgid = mapped_fsgid(mnt_userns); + kgid = mapped_fsgid(mnt_userns, &init_user_ns); if (!gid_valid(kgid)) return false; return kuid_has_mapping(fs_userns, kuid) && diff --git a/include/linux/mnt_idmapping.h b/include/linux/mnt_idmapping.h index 0c6ab3f4c9527..ee5a217de2a88 100644 --- a/include/linux/mnt_idmapping.h +++ b/include/linux/mnt_idmapping.h @@ -196,6 +196,7 @@ static inline kgid_t mapped_kgid_user(struct user_namespace *mnt_userns, /** * mapped_fsuid - return caller's fsuid mapped up into a mnt_userns * @mnt_userns: the mount's idmapping + * @fs_userns: the filesystem's idmapping * * Use this helper to initialize a new vfs or filesystem object based on * the caller's fsuid. A common example is initializing the i_uid field of @@ -205,14 +206,16 @@ static inline kgid_t mapped_kgid_user(struct user_namespace *mnt_userns, * * Return: the caller's current fsuid mapped up according to @mnt_userns. */ -static inline kuid_t mapped_fsuid(struct user_namespace *mnt_userns) +static inline kuid_t mapped_fsuid(struct user_namespace *mnt_userns, + struct user_namespace *fs_userns) { - return mapped_kuid_user(mnt_userns, &init_user_ns, current_fsuid()); + return mapped_kuid_user(mnt_userns, fs_userns, current_fsuid()); } /** * mapped_fsgid - return caller's fsgid mapped up into a mnt_userns * @mnt_userns: the mount's idmapping + * @fs_userns: the filesystem's idmapping * * Use this helper to initialize a new vfs or filesystem object based on * the caller's fsgid. A common example is initializing the i_gid field of @@ -222,9 +225,10 @@ static inline kuid_t mapped_fsuid(struct user_namespace *mnt_userns) * * Return: the caller's current fsgid mapped up according to @mnt_userns. */ -static inline kgid_t mapped_fsgid(struct user_namespace *mnt_userns) +static inline kgid_t mapped_fsgid(struct user_namespace *mnt_userns, + struct user_namespace *fs_userns) { - return mapped_kgid_user(mnt_userns, &init_user_ns, current_fsgid()); + return mapped_kgid_user(mnt_userns, fs_userns, current_fsgid()); } #endif /* _LINUX_MNT_IDMAPPING_H */ -- GitLab From a1ec9040a2a9122605ac26e5725c6de019184419 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 3 Dec 2021 12:17:06 +0100 Subject: [PATCH 0318/1112] fs: add i_user_ns() helper Since we'll be passing the filesystem's idmapping in even more places in the following patches and we do already dereference struct inode to get to the filesystem's idmapping multiple times add a tiny helper. Link: https://lore.kernel.org/r/20211123114227.3124056-10-brauner@kernel.org (v1) Link: https://lore.kernel.org/r/20211130121032.3753852-10-brauner@kernel.org (v2) Link: https://lore.kernel.org/r/20211203111707.3901969-10-brauner@kernel.org Cc: Seth Forshee Cc: Christoph Hellwig Cc: Al Viro CC: linux-fsdevel@vger.kernel.org Reviewed-by: Amir Goldstein Reviewed-by: Seth Forshee Signed-off-by: Christian Brauner --- include/linux/fs.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/include/linux/fs.h b/include/linux/fs.h index e1f28f757f1bf..3d6d514943ab9 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1600,6 +1600,11 @@ struct super_block { struct list_head s_inodes_wb; /* writeback inodes */ } __randomize_layout; +static inline struct user_namespace *i_user_ns(const struct inode *inode) +{ + return inode->i_sb->s_user_ns; +} + /* Helper functions so that in most cases filesystems will * not need to deal directly with kuid_t and kgid_t and can * instead deal with the raw numeric values that are stored @@ -1607,22 +1612,22 @@ struct super_block { */ static inline uid_t i_uid_read(const struct inode *inode) { - return from_kuid(inode->i_sb->s_user_ns, inode->i_uid); + return from_kuid(i_user_ns(inode), inode->i_uid); } static inline gid_t i_gid_read(const struct inode *inode) { - return from_kgid(inode->i_sb->s_user_ns, inode->i_gid); + return from_kgid(i_user_ns(inode), inode->i_gid); } static inline void i_uid_write(struct inode *inode, uid_t uid) { - inode->i_uid = make_kuid(inode->i_sb->s_user_ns, uid); + inode->i_uid = make_kuid(i_user_ns(inode), uid); } static inline void i_gid_write(struct inode *inode, gid_t gid) { - inode->i_gid = make_kgid(inode->i_sb->s_user_ns, gid); + inode->i_gid = make_kgid(i_user_ns(inode), gid); } /** -- GitLab From bd303368b776eead1c29e6cdda82bde7128b82a7 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 3 Dec 2021 12:17:07 +0100 Subject: [PATCH 0319/1112] fs: support mapped mounts of mapped filesystems In previous patches we added new and modified existing helpers to handle idmapped mounts of filesystems mounted with an idmapping. In this final patch we convert all relevant places in the vfs to actually pass the filesystem's idmapping into these helpers. With this the vfs is in shape to handle idmapped mounts of filesystems mounted with an idmapping. Note that this is just the generic infrastructure. Actually adding support for idmapped mounts to a filesystem mountable with an idmapping is follow-up work. In this patch we extend the definition of an idmapped mount from a mount that that has the initial idmapping attached to it to a mount that has an idmapping attached to it which is not the same as the idmapping the filesystem was mounted with. As before we do not allow the initial idmapping to be attached to a mount. In addition this patch prevents that the idmapping the filesystem was mounted with can be attached to a mount created based on this filesystem. This has multiple reasons and advantages. First, attaching the initial idmapping or the filesystem's idmapping doesn't make much sense as in both cases the values of the i_{g,u}id and other places where k{g,u}ids are used do not change. Second, a user that really wants to do this for whatever reason can just create a separate dedicated identical idmapping to attach to the mount. Third, we can continue to use the initial idmapping as an indicator that a mount is not idmapped allowing us to continue to keep passing the initial idmapping into the mapping helpers to tell them that something isn't an idmapped mount even if the filesystem is mounted with an idmapping. Link: https://lore.kernel.org/r/20211123114227.3124056-11-brauner@kernel.org (v1) Link: https://lore.kernel.org/r/20211130121032.3753852-11-brauner@kernel.org (v2) Link: https://lore.kernel.org/r/20211203111707.3901969-11-brauner@kernel.org Cc: Seth Forshee Cc: Amir Goldstein Cc: Christoph Hellwig Cc: Al Viro CC: linux-fsdevel@vger.kernel.org Reviewed-by: Seth Forshee Signed-off-by: Christian Brauner --- fs/namespace.c | 51 +++++++++++++++++++++++++++++++++----------- fs/open.c | 7 +++--- fs/posix_acl.c | 8 +++---- include/linux/fs.h | 17 ++++++++------- security/commoncap.c | 9 ++++---- 5 files changed, 59 insertions(+), 33 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index 4994b816a74c6..08266a35c0c19 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "pnode.h" #include "internal.h" @@ -561,7 +562,7 @@ static void free_vfsmnt(struct mount *mnt) struct user_namespace *mnt_userns; mnt_userns = mnt_user_ns(&mnt->mnt); - if (mnt_userns != &init_user_ns) + if (!initial_idmapping(mnt_userns)) put_user_ns(mnt_userns); kfree_const(mnt->mnt_devname); #ifdef CONFIG_SMP @@ -965,6 +966,7 @@ static struct mount *skip_mnt_tree(struct mount *p) struct vfsmount *vfs_create_mount(struct fs_context *fc) { struct mount *mnt; + struct user_namespace *fs_userns; if (!fc->root) return ERR_PTR(-EINVAL); @@ -982,6 +984,10 @@ struct vfsmount *vfs_create_mount(struct fs_context *fc) mnt->mnt_mountpoint = mnt->mnt.mnt_root; mnt->mnt_parent = mnt; + fs_userns = mnt->mnt.mnt_sb->s_user_ns; + if (!initial_idmapping(fs_userns)) + mnt->mnt.mnt_userns = get_user_ns(fs_userns); + lock_mount_hash(); list_add_tail(&mnt->mnt_instance, &mnt->mnt.mnt_sb->s_mounts); unlock_mount_hash(); @@ -1072,7 +1078,7 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, atomic_inc(&sb->s_active); mnt->mnt.mnt_userns = mnt_user_ns(&old->mnt); - if (mnt->mnt.mnt_userns != &init_user_ns) + if (!initial_idmapping(mnt->mnt.mnt_userns)) mnt->mnt.mnt_userns = get_user_ns(mnt->mnt.mnt_userns); mnt->mnt.mnt_sb = sb; mnt->mnt.mnt_root = dget(root); @@ -3927,10 +3933,18 @@ static unsigned int recalc_flags(struct mount_kattr *kattr, struct mount *mnt) static int can_idmap_mount(const struct mount_kattr *kattr, struct mount *mnt) { struct vfsmount *m = &mnt->mnt; + struct user_namespace *fs_userns = m->mnt_sb->s_user_ns; if (!kattr->mnt_userns) return 0; + /* + * Creating an idmapped mount with the filesystem wide idmapping + * doesn't make sense so block that. We don't allow mushy semantics. + */ + if (kattr->mnt_userns == fs_userns) + return -EINVAL; + /* * Once a mount has been idmapped we don't allow it to change its * mapping. It makes things simpler and callers can just create @@ -3943,12 +3957,8 @@ static int can_idmap_mount(const struct mount_kattr *kattr, struct mount *mnt) if (!(m->mnt_sb->s_type->fs_flags & FS_ALLOW_IDMAP)) return -EINVAL; - /* Don't yet support filesystem mountable in user namespaces. */ - if (m->mnt_sb->s_user_ns != &init_user_ns) - return -EINVAL; - /* We're not controlling the superblock. */ - if (!capable(CAP_SYS_ADMIN)) + if (!ns_capable(fs_userns, CAP_SYS_ADMIN)) return -EPERM; /* Mount has already been visible in the filesystem hierarchy. */ @@ -4002,14 +4012,27 @@ out: static void do_idmap_mount(const struct mount_kattr *kattr, struct mount *mnt) { - struct user_namespace *mnt_userns; + struct user_namespace *mnt_userns, *old_mnt_userns; if (!kattr->mnt_userns) return; + /* + * We're the only ones able to change the mount's idmapping. So + * mnt->mnt.mnt_userns is stable and we can retrieve it directly. + */ + old_mnt_userns = mnt->mnt.mnt_userns; + mnt_userns = get_user_ns(kattr->mnt_userns); /* Pairs with smp_load_acquire() in mnt_user_ns(). */ smp_store_release(&mnt->mnt.mnt_userns, mnt_userns); + + /* + * If this is an idmapped filesystem drop the reference we've taken + * in vfs_create_mount() before. + */ + if (!initial_idmapping(old_mnt_userns)) + put_user_ns(old_mnt_userns); } static void mount_setattr_commit(struct mount_kattr *kattr, @@ -4133,13 +4156,15 @@ static int build_mount_idmapped(const struct mount_attr *attr, size_t usize, } /* - * The init_user_ns is used to indicate that a vfsmount is not idmapped. - * This is simpler than just having to treat NULL as unmapped. Users - * wanting to idmap a mount to init_user_ns can just use a namespace - * with an identity mapping. + * The initial idmapping cannot be used to create an idmapped + * mount. We use the initial idmapping as an indicator of a mount + * that is not idmapped. It can simply be passed into helpers that + * are aware of idmapped mounts as a convenient shortcut. A user + * can just create a dedicated identity mapping to achieve the same + * result. */ mnt_userns = container_of(ns, struct user_namespace, ns); - if (mnt_userns == &init_user_ns) { + if (initial_idmapping(mnt_userns)) { err = -EPERM; goto out_fput; } diff --git a/fs/open.c b/fs/open.c index 40a00e71865ba..9ff2f621b760b 100644 --- a/fs/open.c +++ b/fs/open.c @@ -641,7 +641,7 @@ SYSCALL_DEFINE2(chmod, const char __user *, filename, umode_t, mode) int chown_common(const struct path *path, uid_t user, gid_t group) { - struct user_namespace *mnt_userns; + struct user_namespace *mnt_userns, *fs_userns; struct inode *inode = path->dentry->d_inode; struct inode *delegated_inode = NULL; int error; @@ -653,8 +653,9 @@ int chown_common(const struct path *path, uid_t user, gid_t group) gid = make_kgid(current_user_ns(), group); mnt_userns = mnt_user_ns(path->mnt); - uid = mapped_kuid_user(mnt_userns, &init_user_ns, uid); - gid = mapped_kgid_user(mnt_userns, &init_user_ns, gid); + fs_userns = i_user_ns(inode); + uid = mapped_kuid_user(mnt_userns, fs_userns, uid); + gid = mapped_kgid_user(mnt_userns, fs_userns, gid); retry_deleg: newattrs.ia_valid = ATTR_CTIME; diff --git a/fs/posix_acl.c b/fs/posix_acl.c index 4b5fb9a9b90fa..80acb6885cf90 100644 --- a/fs/posix_acl.c +++ b/fs/posix_acl.c @@ -376,8 +376,8 @@ posix_acl_permission(struct user_namespace *mnt_userns, struct inode *inode, break; case ACL_USER: uid = mapped_kuid_fs(mnt_userns, - &init_user_ns, - pa->e_uid); + i_user_ns(inode), + pa->e_uid); if (uid_eq(uid, current_fsuid())) goto mask; break; @@ -391,8 +391,8 @@ posix_acl_permission(struct user_namespace *mnt_userns, struct inode *inode, break; case ACL_GROUP: gid = mapped_kgid_fs(mnt_userns, - &init_user_ns, - pa->e_gid); + i_user_ns(inode), + pa->e_gid); if (in_group_p(gid)) { found = 1; if ((pa->e_perm & want) == want) diff --git a/include/linux/fs.h b/include/linux/fs.h index 3d6d514943ab9..493b87e3616b8 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1641,7 +1641,7 @@ static inline void i_gid_write(struct inode *inode, gid_t gid) static inline kuid_t i_uid_into_mnt(struct user_namespace *mnt_userns, const struct inode *inode) { - return mapped_kuid_fs(mnt_userns, &init_user_ns, inode->i_uid); + return mapped_kuid_fs(mnt_userns, i_user_ns(inode), inode->i_uid); } /** @@ -1655,7 +1655,7 @@ static inline kuid_t i_uid_into_mnt(struct user_namespace *mnt_userns, static inline kgid_t i_gid_into_mnt(struct user_namespace *mnt_userns, const struct inode *inode) { - return mapped_kgid_fs(mnt_userns, &init_user_ns, inode->i_gid); + return mapped_kgid_fs(mnt_userns, i_user_ns(inode), inode->i_gid); } /** @@ -1669,7 +1669,7 @@ static inline kgid_t i_gid_into_mnt(struct user_namespace *mnt_userns, static inline void inode_fsuid_set(struct inode *inode, struct user_namespace *mnt_userns) { - inode->i_uid = mapped_fsuid(mnt_userns, &init_user_ns); + inode->i_uid = mapped_fsuid(mnt_userns, i_user_ns(inode)); } /** @@ -1683,7 +1683,7 @@ static inline void inode_fsuid_set(struct inode *inode, static inline void inode_fsgid_set(struct inode *inode, struct user_namespace *mnt_userns) { - inode->i_gid = mapped_fsgid(mnt_userns, &init_user_ns); + inode->i_gid = mapped_fsgid(mnt_userns, i_user_ns(inode)); } /** @@ -1704,10 +1704,10 @@ static inline bool fsuidgid_has_mapping(struct super_block *sb, kuid_t kuid; kgid_t kgid; - kuid = mapped_fsuid(mnt_userns, &init_user_ns); + kuid = mapped_fsuid(mnt_userns, fs_userns); if (!uid_valid(kuid)) return false; - kgid = mapped_fsgid(mnt_userns, &init_user_ns); + kgid = mapped_fsgid(mnt_userns, fs_userns); if (!gid_valid(kgid)) return false; return kuid_has_mapping(fs_userns, kuid) && @@ -2653,13 +2653,14 @@ static inline struct user_namespace *file_mnt_user_ns(struct file *file) * is_idmapped_mnt - check whether a mount is mapped * @mnt: the mount to check * - * If @mnt has an idmapping attached to it @mnt is mapped. + * If @mnt has an idmapping attached different from the + * filesystem's idmapping then @mnt is mapped. * * Return: true if mount is mapped, false if not. */ static inline bool is_idmapped_mnt(const struct vfsmount *mnt) { - return mnt_user_ns(mnt) != &init_user_ns; + return mnt_user_ns(mnt) != mnt->mnt_sb->s_user_ns; } extern long vfs_truncate(const struct path *, loff_t); diff --git a/security/commoncap.c b/security/commoncap.c index d288a62e29996..5fc8986c3c77c 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -419,7 +419,7 @@ int cap_inode_getsecurity(struct user_namespace *mnt_userns, kroot = make_kuid(fs_ns, root); /* If this is an idmapped mount shift the kuid. */ - kroot = mapped_kuid_fs(mnt_userns, &init_user_ns, kroot); + kroot = mapped_kuid_fs(mnt_userns, fs_ns, kroot); /* If the root kuid maps to a valid uid in current ns, then return * this as a nscap. */ @@ -556,13 +556,12 @@ int cap_convert_nscap(struct user_namespace *mnt_userns, struct dentry *dentry, return -EINVAL; if (!capable_wrt_inode_uidgid(mnt_userns, inode, CAP_SETFCAP)) return -EPERM; - if (size == XATTR_CAPS_SZ_2 && (mnt_userns == &init_user_ns)) + if (size == XATTR_CAPS_SZ_2 && (mnt_userns == fs_ns)) if (ns_capable(inode->i_sb->s_user_ns, CAP_SETFCAP)) /* user is privileged, just write the v2 */ return size; - rootid = rootid_from_xattr(*ivalue, size, task_ns, mnt_userns, - &init_user_ns); + rootid = rootid_from_xattr(*ivalue, size, task_ns, mnt_userns, fs_ns); if (!uid_valid(rootid)) return -EINVAL; @@ -703,7 +702,7 @@ int get_vfs_caps_from_disk(struct user_namespace *mnt_userns, /* Limit the caps to the mounter of the filesystem * or the more limited uid specified in the xattr. */ - rootkuid = mapped_kuid_fs(mnt_userns, &init_user_ns, rootkuid); + rootkuid = mapped_kuid_fs(mnt_userns, fs_ns, rootkuid); if (!rootid_owns_currentns(rootkuid)) return -ENODATA; -- GitLab From 5fe375728983b3fca6b958434a2e3f547bbbb2aa Mon Sep 17 00:00:00 2001 From: Xiu Jianfeng Date: Thu, 2 Dec 2021 15:35:33 +0800 Subject: [PATCH 0320/1112] selinux: Use struct_size() helper in kmalloc() Make use of struct_size() helper instead of an open-coded calculation. Link: https://github.com/KSPP/linux/issues/160 Signed-off-by: Xiu Jianfeng Signed-off-by: Paul Moore --- security/selinux/ss/sidtab.c | 2 +- security/selinux/xfrm.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c index 656d50b09f762..293ec048af08c 100644 --- a/security/selinux/ss/sidtab.c +++ b/security/selinux/ss/sidtab.c @@ -570,7 +570,7 @@ void sidtab_sid2str_put(struct sidtab *s, struct sidtab_entry *entry, goto out_unlock; } - cache = kmalloc(sizeof(struct sidtab_str_cache) + str_len, GFP_ATOMIC); + cache = kmalloc(struct_size(cache, str, str_len), GFP_ATOMIC); if (!cache) goto out_unlock; diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index be83e5ce4469c..90697317895fb 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -89,7 +89,7 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp, if (str_len >= PAGE_SIZE) return -ENOMEM; - ctx = kmalloc(sizeof(*ctx) + str_len + 1, gfp); + ctx = kmalloc(struct_size(ctx, ctx_str, str_len + 1), gfp); if (!ctx) return -ENOMEM; @@ -360,7 +360,7 @@ int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x, if (rc) return rc; - ctx = kmalloc(sizeof(*ctx) + str_len, GFP_ATOMIC); + ctx = kmalloc(struct_size(ctx, ctx_str, str_len), GFP_ATOMIC); if (!ctx) { rc = -ENOMEM; goto out; -- GitLab From e5ab49cd3d6937b1818b80cb5eb09dc018ae0718 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 2 Dec 2021 14:40:33 +0100 Subject: [PATCH 0321/1112] gpiolib: improve coding style for local variables Drop unneeded whitespaces and put the variables of the same type together for consistency with the rest of the code. Signed-off-by: Bartosz Golaszewski Reviewed-by: Linus Walleij Reviewed-by: Andy Shevchenko --- drivers/gpio/gpiolib.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 85168f88a7fec..bc5ba52865ec0 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -594,11 +594,11 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, struct lock_class_key *request_key) { struct fwnode_handle *fwnode = gc->parent ? dev_fwnode(gc->parent) : NULL; - unsigned long flags; - int ret = 0; - unsigned i; - int base = gc->base; struct gpio_device *gdev; + unsigned long flags; + int base = gc->base; + unsigned int i; + int ret = 0; /* * First: allocate and populate the internal stat container, and -- GitLab From 9dbd1ab20509e85cd3fac9479a00c59e83c08196 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 2 Dec 2021 14:40:34 +0100 Subject: [PATCH 0322/1112] gpiolib: check the 'ngpios' property in core gpiolib code Several drivers read the 'ngpios' device property on their own, but since it's defined as a standard GPIO property in the device tree bindings anyway, it's a good candidate for generalization. If the driver didn't set its gc->ngpio, try to read the 'ngpios' property from the GPIO device's firmware node before bailing out. Signed-off-by: Bartosz Golaszewski Suggested-by: Andy Shevchenko Reviewed-by: Linus Walleij Reviewed-by: Andy Shevchenko --- drivers/gpio/gpiolib.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index bc5ba52865ec0..535eb1b509c19 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -599,6 +599,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, int base = gc->base; unsigned int i; int ret = 0; + u32 ngpios; /* * First: allocate and populate the internal stat container, and @@ -646,6 +647,26 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, goto err_free_dev_name; } + /* + * Try the device properties if the driver didn't supply the number + * of GPIO lines. + */ + if (gc->ngpio == 0) { + ret = device_property_read_u32(&gdev->dev, "ngpios", &ngpios); + if (ret == -ENODATA) + /* + * -ENODATA means that there is no property found and + * we want to issue the error message to the user. + * Besides that, we want to return different error code + * to state that supplied value is not valid. + */ + ngpios = 0; + else if (ret) + goto err_free_descs; + + gc->ngpio = ngpios; + } + if (gc->ngpio == 0) { chip_err(gc, "tried to insert a GPIO chip with zero lines\n"); ret = -EINVAL; -- GitLab From d733ac93113572b701ccf0236a46ce4511c1b051 Mon Sep 17 00:00:00 2001 From: Tang Yizhou Date: Thu, 2 Dec 2021 22:23:12 +0800 Subject: [PATCH 0323/1112] doc/zh-CN: Update cpufreq-stats.rst to make it more readable These Chinese translations are easier to understand. Also add proofreader. Signed-off-by: Tang Yizhou Acked-by: Yanteng Si Link: https://lore.kernel.org/r/20211202142312.20052-1-tangyizhou@huawei.com Signed-off-by: Jonathan Corbet --- .../zh_CN/cpu-freq/cpufreq-stats.rst | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/Documentation/translations/zh_CN/cpu-freq/cpufreq-stats.rst b/Documentation/translations/zh_CN/cpu-freq/cpufreq-stats.rst index f14423099d4b9..e8fdba923cd5a 100644 --- a/Documentation/translations/zh_CN/cpu-freq/cpufreq-stats.rst +++ b/Documentation/translations/zh_CN/cpu-freq/cpufreq-stats.rst @@ -8,13 +8,15 @@ 司延腾 Yanteng Si -.. _cn_cpufreq-stats.rst: +:校译: + + 唐艺舟 Tang Yizhou ========================================== sysfs CPUFreq Stats的一般说明 ========================================== -用户信息 +为使用者准备的信息 作者: Venkatesh Pallipadi @@ -29,17 +31,16 @@ sysfs CPUFreq Stats的一般说明 1. 简介 =============== -cpufreq-stats是一个为每个CPU提供CPU频率统计的驱动。 -这些统计数据在/sysfs中以一堆只读接口的形式提供。这个接口(在配置好后)将出现在 -/sysfs(/devices/system/cpu/cpuX/cpufreq/stats/)中cpufreq下的一个单 -独的目录中,提供给每个CPU。 -各种统计数据将在此目录下形成只读文件。 +cpufreq-stats是一种为每个CPU提供CPU频率统计的驱动。 +这些统计数据以/sysfs中一系列只读接口的形式呈现。cpufreq-stats接口(若已配置)将为每个CPU生成 +/sysfs(/devices/system/cpu/cpuX/cpufreq/stats/)中cpufreq目录下的stats目录。 +各项统计数据将在stats目录下形成对应的只读文件。 -此驱动是独立于任何可能运行在你所用CPU上的特定cpufreq_driver而设计的。因此,它将与所有 -cpufreq_driver一起工作。 +此驱动是以独立于任何可能运行在你所用CPU上的特定cpufreq_driver的方式设计的。因此,它将能和任何 +cpufreq_driver协同工作。 -2. 提供的统计数据(举例说明) +2. 已提供的统计数据(有例子) ===================================== cpufreq stats提供了以下统计数据(在下面详细解释)。 @@ -48,8 +49,8 @@ cpufreq stats提供了以下统计数据(在下面详细解释)。 - total_trans - trans_table -所有的统计数据将从统计驱动被载入的时间(或统计被重置的时间)开始,到某一统计数据被读取的时间为止。 -显然,统计驱动不会有任何关于统计驱动载入之前的频率转换信息。 +所有统计数据来自以下时间范围:从统计驱动被加载的时间(或统计数据被重置的时间)开始,到某一统计数据被读取的时间为止。 +显然,统计驱动不会保存它被加载之前的任何频率转换信息。 :: @@ -64,14 +65,14 @@ cpufreq stats提供了以下统计数据(在下面详细解释)。 - **reset** -只写属性,可用于重置统计计数器。这对于评估不同调节器下的系统行为非常有用,且无需重启。 +只写属性,可用于重置统计计数器。这对于评估不同调节器的系统行为非常有用,且无需重启。 - **time_in_state** -此项给出了这个CPU所支持的每个频率所花费的时间。cat输出的每一行都会有" -