]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 5.4
authorSasha Levin <sashal@kernel.org>
Sun, 10 Mar 2024 02:31:49 +0000 (21:31 -0500)
committerSasha Levin <sashal@kernel.org>
Sun, 10 Mar 2024 02:31:49 +0000 (21:31 -0500)
Signed-off-by: Sasha Levin <sashal@kernel.org>
32 files changed:
queue-5.4/exit-fix-typo-in-comment-s-sub-theads-sub-threads.patch [new file with mode: 0644]
queue-5.4/exit-wait_task_zombie-kill-the-no-longer-necessary-s.patch [new file with mode: 0644]
queue-5.4/getrusage-add-the-signal_struct-sig-local-variable.patch [new file with mode: 0644]
queue-5.4/getrusage-move-thread_group_cputime_adjusted-outside.patch [new file with mode: 0644]
queue-5.4/getrusage-use-__for_each_thread.patch [new file with mode: 0644]
queue-5.4/getrusage-use-sig-stats_lock-rather-than-lock_task_s.patch [new file with mode: 0644]
queue-5.4/hv_netvsc-make-netvsc-vf-binding-check-both-mac-and-.patch [new file with mode: 0644]
queue-5.4/hv_netvsc-register-vf-in-netvsc_probe-if-net_device_.patch [new file with mode: 0644]
queue-5.4/hv_netvsc-use-netif_is_bond_master-instead-of-open-c.patch [new file with mode: 0644]
queue-5.4/input-i8042-fix-strange-behavior-of-touchpad-on-clev.patch [new file with mode: 0644]
queue-5.4/nfsd-add-documenting-comment-for-nfsd4_release_locko.patch [new file with mode: 0644]
queue-5.4/nfsd-don-t-take-fi_lock-in-nfsd_break_deleg_cb.patch [new file with mode: 0644]
queue-5.4/nfsd-fix-release_lockowner.patch [new file with mode: 0644]
queue-5.4/nfsd-modernize-nfsd4_release_lockowner.patch [new file with mode: 0644]
queue-5.4/regmap-add-bulk-read-write-callbacks-into-regmap_con.patch [new file with mode: 0644]
queue-5.4/regmap-allow-to-define-reg_update_bits-for-no-bus-co.patch [new file with mode: 0644]
queue-5.4/selftests-mm-fix-map_hugetlb-failure-on-64k-page-siz.patch [new file with mode: 0644]
queue-5.4/serial-max310x-fail-probe-if-clock-crystal-is-unstab.patch [new file with mode: 0644]
queue-5.4/serial-max310x-fix-io-data-corruption-in-batched-ope.patch [new file with mode: 0644]
queue-5.4/serial-max310x-implement-i2c-support.patch [new file with mode: 0644]
queue-5.4/serial-max310x-make-accessing-revision-id-interface-.patch [new file with mode: 0644]
queue-5.4/serial-max310x-make-use-of-device-properties.patch [new file with mode: 0644]
queue-5.4/serial-max310x-prevent-infinite-while-loop-in-port-s.patch [new file with mode: 0644]
queue-5.4/serial-max310x-try-to-get-crystal-clock-rate-from-pr.patch [new file with mode: 0644]
queue-5.4/serial-max310x-unprepare-and-disable-clock-in-error-.patch [new file with mode: 0644]
queue-5.4/serial-max310x-use-a-separate-regmap-for-each-port.patch [new file with mode: 0644]
queue-5.4/serial-max310x-use-devm_clk_get_optional-to-get-the-.patch [new file with mode: 0644]
queue-5.4/serial-max310x-use-regmap-methods-for-spi-batch-oper.patch [new file with mode: 0644]
queue-5.4/series
queue-5.4/um-allow-not-setting-extra-rpaths-in-the-linux-binar.patch [new file with mode: 0644]
queue-5.4/um-fix-adding-no-pie-for-clang.patch [new file with mode: 0644]
queue-5.4/y2038-rusage-use-__kernel_old_timeval.patch [new file with mode: 0644]

diff --git a/queue-5.4/exit-fix-typo-in-comment-s-sub-theads-sub-threads.patch b/queue-5.4/exit-fix-typo-in-comment-s-sub-theads-sub-threads.patch
new file mode 100644 (file)
index 0000000..e278387
--- /dev/null
@@ -0,0 +1,33 @@
+From f858d2888a122906a127696661e39aa58d929af6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 3 Aug 2022 10:43:42 +0200
+Subject: exit: Fix typo in comment: s/sub-theads/sub-threads
+
+From: Ingo Molnar <mingo@kernel.org>
+
+[ Upstream commit dcca34754a3f5290406403b8066e3b15dda9f4bf ]
+
+Cc: linux-kernel@vger.kernel.org
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Stable-dep-of: c1be35a16b2f ("exit: wait_task_zombie: kill the no longer necessary spin_lock_irq(siglock)")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/exit.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/kernel/exit.c b/kernel/exit.c
+index c764d16328f6a..b2a005acb6cda 100644
+--- a/kernel/exit.c
++++ b/kernel/exit.c
+@@ -1106,7 +1106,7 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
+                * p->signal fields because the whole thread group is dead
+                * and nobody can change them.
+                *
+-               * psig->stats_lock also protects us from our sub-theads
++               * psig->stats_lock also protects us from our sub-threads
+                * which can reap other children at the same time. Until
+                * we change k_getrusage()-like users to rely on this lock
+                * we have to take ->siglock as well.
+-- 
+2.43.0
+
diff --git a/queue-5.4/exit-wait_task_zombie-kill-the-no-longer-necessary-s.patch b/queue-5.4/exit-wait_task_zombie-kill-the-no-longer-necessary-s.patch
new file mode 100644 (file)
index 0000000..2a2eb86
--- /dev/null
@@ -0,0 +1,65 @@
+From 7e23a3520b944858b6c7c096b9e9f907b668c73f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 23 Jan 2024 16:34:00 +0100
+Subject: exit: wait_task_zombie: kill the no longer necessary
+ spin_lock_irq(siglock)
+
+From: Oleg Nesterov <oleg@redhat.com>
+
+[ Upstream commit c1be35a16b2f1fe21f4f26f9de030ad6eaaf6a25 ]
+
+After the recent changes nobody use siglock to read the values protected
+by stats_lock, we can kill spin_lock_irq(&current->sighand->siglock) and
+update the comment.
+
+With this patch only __exit_signal() and thread_group_start_cputime() take
+stats_lock under siglock.
+
+Link: https://lkml.kernel.org/r/20240123153359.GA21866@redhat.com
+Signed-off-by: Oleg Nesterov <oleg@redhat.com>
+Signed-off-by: Dylan Hatch <dylanbhatch@google.com>
+Cc: Eric W. Biederman <ebiederm@xmission.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/exit.c | 10 +++-------
+ 1 file changed, 3 insertions(+), 7 deletions(-)
+
+diff --git a/kernel/exit.c b/kernel/exit.c
+index b2a005acb6cda..7a8a67aed9cac 100644
+--- a/kernel/exit.c
++++ b/kernel/exit.c
+@@ -1107,17 +1107,14 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
+                * and nobody can change them.
+                *
+                * psig->stats_lock also protects us from our sub-threads
+-               * which can reap other children at the same time. Until
+-               * we change k_getrusage()-like users to rely on this lock
+-               * we have to take ->siglock as well.
++               * which can reap other children at the same time.
+                *
+                * We use thread_group_cputime_adjusted() to get times for
+                * the thread group, which consolidates times for all threads
+                * in the group including the group leader.
+                */
+               thread_group_cputime_adjusted(p, &tgutime, &tgstime);
+-              spin_lock_irq(&current->sighand->siglock);
+-              write_seqlock(&psig->stats_lock);
++              write_seqlock_irq(&psig->stats_lock);
+               psig->cutime += tgutime + sig->cutime;
+               psig->cstime += tgstime + sig->cstime;
+               psig->cgtime += task_gtime(p) + sig->gtime + sig->cgtime;
+@@ -1140,8 +1137,7 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
+                       psig->cmaxrss = maxrss;
+               task_io_accounting_add(&psig->ioac, &p->ioac);
+               task_io_accounting_add(&psig->ioac, &sig->ioac);
+-              write_sequnlock(&psig->stats_lock);
+-              spin_unlock_irq(&current->sighand->siglock);
++              write_sequnlock_irq(&psig->stats_lock);
+       }
+       if (wo->wo_rusage)
+-- 
+2.43.0
+
diff --git a/queue-5.4/getrusage-add-the-signal_struct-sig-local-variable.patch b/queue-5.4/getrusage-add-the-signal_struct-sig-local-variable.patch
new file mode 100644 (file)
index 0000000..a2a7ed9
--- /dev/null
@@ -0,0 +1,93 @@
+From 7fa92c4ff10a9ab5af240f4567353a41a944173f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 9 Sep 2023 19:25:54 +0200
+Subject: getrusage: add the "signal_struct *sig" local variable
+
+From: Oleg Nesterov <oleg@redhat.com>
+
+[ Upstream commit c7ac8231ace9b07306d0299969e42073b189c70a ]
+
+No functional changes, cleanup/preparation.
+
+Link: https://lkml.kernel.org/r/20230909172554.GA20441@redhat.com
+Signed-off-by: Oleg Nesterov <oleg@redhat.com>
+Cc: Eric W. Biederman <ebiederm@xmission.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Stable-dep-of: daa694e41375 ("getrusage: move thread_group_cputime_adjusted() outside of lock_task_sighand()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/sys.c | 37 +++++++++++++++++++------------------
+ 1 file changed, 19 insertions(+), 18 deletions(-)
+
+diff --git a/kernel/sys.c b/kernel/sys.c
+index bc3cd0ef894e6..76b601d56c027 100644
+--- a/kernel/sys.c
++++ b/kernel/sys.c
+@@ -1712,6 +1712,7 @@ void getrusage(struct task_struct *p, int who, struct rusage *r)
+       unsigned long flags;
+       u64 tgutime, tgstime, utime, stime;
+       unsigned long maxrss = 0;
++      struct signal_struct *sig = p->signal;
+       memset((char *)r, 0, sizeof (*r));
+       utime = stime = 0;
+@@ -1719,7 +1720,7 @@ void getrusage(struct task_struct *p, int who, struct rusage *r)
+       if (who == RUSAGE_THREAD) {
+               task_cputime_adjusted(current, &utime, &stime);
+               accumulate_thread_rusage(p, r);
+-              maxrss = p->signal->maxrss;
++              maxrss = sig->maxrss;
+               goto out;
+       }
+@@ -1729,15 +1730,15 @@ void getrusage(struct task_struct *p, int who, struct rusage *r)
+       switch (who) {
+       case RUSAGE_BOTH:
+       case RUSAGE_CHILDREN:
+-              utime = p->signal->cutime;
+-              stime = p->signal->cstime;
+-              r->ru_nvcsw = p->signal->cnvcsw;
+-              r->ru_nivcsw = p->signal->cnivcsw;
+-              r->ru_minflt = p->signal->cmin_flt;
+-              r->ru_majflt = p->signal->cmaj_flt;
+-              r->ru_inblock = p->signal->cinblock;
+-              r->ru_oublock = p->signal->coublock;
+-              maxrss = p->signal->cmaxrss;
++              utime = sig->cutime;
++              stime = sig->cstime;
++              r->ru_nvcsw = sig->cnvcsw;
++              r->ru_nivcsw = sig->cnivcsw;
++              r->ru_minflt = sig->cmin_flt;
++              r->ru_majflt = sig->cmaj_flt;
++              r->ru_inblock = sig->cinblock;
++              r->ru_oublock = sig->coublock;
++              maxrss = sig->cmaxrss;
+               if (who == RUSAGE_CHILDREN)
+                       break;
+@@ -1747,14 +1748,14 @@ void getrusage(struct task_struct *p, int who, struct rusage *r)
+               thread_group_cputime_adjusted(p, &tgutime, &tgstime);
+               utime += tgutime;
+               stime += tgstime;
+-              r->ru_nvcsw += p->signal->nvcsw;
+-              r->ru_nivcsw += p->signal->nivcsw;
+-              r->ru_minflt += p->signal->min_flt;
+-              r->ru_majflt += p->signal->maj_flt;
+-              r->ru_inblock += p->signal->inblock;
+-              r->ru_oublock += p->signal->oublock;
+-              if (maxrss < p->signal->maxrss)
+-                      maxrss = p->signal->maxrss;
++              r->ru_nvcsw += sig->nvcsw;
++              r->ru_nivcsw += sig->nivcsw;
++              r->ru_minflt += sig->min_flt;
++              r->ru_majflt += sig->maj_flt;
++              r->ru_inblock += sig->inblock;
++              r->ru_oublock += sig->oublock;
++              if (maxrss < sig->maxrss)
++                      maxrss = sig->maxrss;
+               t = p;
+               do {
+                       accumulate_thread_rusage(t, r);
+-- 
+2.43.0
+
diff --git a/queue-5.4/getrusage-move-thread_group_cputime_adjusted-outside.patch b/queue-5.4/getrusage-move-thread_group_cputime_adjusted-outside.patch
new file mode 100644 (file)
index 0000000..9b368b9
--- /dev/null
@@ -0,0 +1,111 @@
+From 9692651ea2f138a80620182402239fe56a3e3cc1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 22 Jan 2024 16:50:50 +0100
+Subject: getrusage: move thread_group_cputime_adjusted() outside of
+ lock_task_sighand()
+
+From: Oleg Nesterov <oleg@redhat.com>
+
+[ Upstream commit daa694e4137571b4ebec330f9a9b4d54aa8b8089 ]
+
+Patch series "getrusage: use sig->stats_lock", v2.
+
+This patch (of 2):
+
+thread_group_cputime() does its own locking, we can safely shift
+thread_group_cputime_adjusted() which does another for_each_thread loop
+outside of ->siglock protected section.
+
+This is also preparation for the next patch which changes getrusage() to
+use stats_lock instead of siglock, thread_group_cputime() takes the same
+lock.  With the current implementation recursive read_seqbegin_or_lock()
+is fine, thread_group_cputime() can't enter the slow mode if the caller
+holds stats_lock, yet this looks more safe and better performance-wise.
+
+Link: https://lkml.kernel.org/r/20240122155023.GA26169@redhat.com
+Link: https://lkml.kernel.org/r/20240122155050.GA26205@redhat.com
+Signed-off-by: Oleg Nesterov <oleg@redhat.com>
+Reported-by: Dylan Hatch <dylanbhatch@google.com>
+Tested-by: Dylan Hatch <dylanbhatch@google.com>
+Cc: Eric W. Biederman <ebiederm@xmission.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/sys.c | 34 +++++++++++++++++++---------------
+ 1 file changed, 19 insertions(+), 15 deletions(-)
+
+diff --git a/kernel/sys.c b/kernel/sys.c
+index 76b601d56c027..b53ad9e50e465 100644
+--- a/kernel/sys.c
++++ b/kernel/sys.c
+@@ -1711,17 +1711,19 @@ void getrusage(struct task_struct *p, int who, struct rusage *r)
+       struct task_struct *t;
+       unsigned long flags;
+       u64 tgutime, tgstime, utime, stime;
+-      unsigned long maxrss = 0;
++      unsigned long maxrss;
++      struct mm_struct *mm;
+       struct signal_struct *sig = p->signal;
+-      memset((char *)r, 0, sizeof (*r));
++      memset(r, 0, sizeof(*r));
+       utime = stime = 0;
++      maxrss = 0;
+       if (who == RUSAGE_THREAD) {
+               task_cputime_adjusted(current, &utime, &stime);
+               accumulate_thread_rusage(p, r);
+               maxrss = sig->maxrss;
+-              goto out;
++              goto out_thread;
+       }
+       if (!lock_task_sighand(p, &flags))
+@@ -1745,9 +1747,6 @@ void getrusage(struct task_struct *p, int who, struct rusage *r)
+               /* fall through */
+       case RUSAGE_SELF:
+-              thread_group_cputime_adjusted(p, &tgutime, &tgstime);
+-              utime += tgutime;
+-              stime += tgstime;
+               r->ru_nvcsw += sig->nvcsw;
+               r->ru_nivcsw += sig->nivcsw;
+               r->ru_minflt += sig->min_flt;
+@@ -1767,19 +1766,24 @@ void getrusage(struct task_struct *p, int who, struct rusage *r)
+       }
+       unlock_task_sighand(p, &flags);
+-out:
+-      r->ru_utime = ns_to_kernel_old_timeval(utime);
+-      r->ru_stime = ns_to_kernel_old_timeval(stime);
++      if (who == RUSAGE_CHILDREN)
++              goto out_children;
+-      if (who != RUSAGE_CHILDREN) {
+-              struct mm_struct *mm = get_task_mm(p);
++      thread_group_cputime_adjusted(p, &tgutime, &tgstime);
++      utime += tgutime;
++      stime += tgstime;
+-              if (mm) {
+-                      setmax_mm_hiwater_rss(&maxrss, mm);
+-                      mmput(mm);
+-              }
++out_thread:
++      mm = get_task_mm(p);
++      if (mm) {
++              setmax_mm_hiwater_rss(&maxrss, mm);
++              mmput(mm);
+       }
++
++out_children:
+       r->ru_maxrss = maxrss * (PAGE_SIZE / 1024); /* convert pages to KBs */
++      r->ru_utime = ns_to_kernel_old_timeval(utime);
++      r->ru_stime = ns_to_kernel_old_timeval(stime);
+ }
+ SYSCALL_DEFINE2(getrusage, int, who, struct rusage __user *, ru)
+-- 
+2.43.0
+
diff --git a/queue-5.4/getrusage-use-__for_each_thread.patch b/queue-5.4/getrusage-use-__for_each_thread.patch
new file mode 100644 (file)
index 0000000..ea3c605
--- /dev/null
@@ -0,0 +1,43 @@
+From 6be831de71f2408044b8bbbe43b5cd8373bee791 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 9 Sep 2023 19:26:29 +0200
+Subject: getrusage: use __for_each_thread()
+
+From: Oleg Nesterov <oleg@redhat.com>
+
+[ Upstream commit 13b7bc60b5353371460a203df6c38ccd38ad7a3a ]
+
+do/while_each_thread should be avoided when possible.
+
+Plus this change allows to avoid lock_task_sighand(), we can use rcu
+and/or sig->stats_lock instead.
+
+Link: https://lkml.kernel.org/r/20230909172629.GA20454@redhat.com
+Signed-off-by: Oleg Nesterov <oleg@redhat.com>
+Cc: Eric W. Biederman <ebiederm@xmission.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Stable-dep-of: f7ec1cd5cc7e ("getrusage: use sig->stats_lock rather than lock_task_sighand()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/sys.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/kernel/sys.c b/kernel/sys.c
+index b53ad9e50e465..4a5b03ad6e9b4 100644
+--- a/kernel/sys.c
++++ b/kernel/sys.c
+@@ -1755,10 +1755,8 @@ void getrusage(struct task_struct *p, int who, struct rusage *r)
+               r->ru_oublock += sig->oublock;
+               if (maxrss < sig->maxrss)
+                       maxrss = sig->maxrss;
+-              t = p;
+-              do {
++              __for_each_thread(sig, t)
+                       accumulate_thread_rusage(t, r);
+-              } while_each_thread(p, t);
+               break;
+       default:
+-- 
+2.43.0
+
diff --git a/queue-5.4/getrusage-use-sig-stats_lock-rather-than-lock_task_s.patch b/queue-5.4/getrusage-use-sig-stats_lock-rather-than-lock_task_s.patch
new file mode 100644 (file)
index 0000000..04b1495
--- /dev/null
@@ -0,0 +1,92 @@
+From 718c1b93d5f861bcd400e2d97f6f1813ad5deddb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 22 Jan 2024 16:50:53 +0100
+Subject: getrusage: use sig->stats_lock rather than lock_task_sighand()
+
+From: Oleg Nesterov <oleg@redhat.com>
+
+[ Upstream commit f7ec1cd5cc7ef3ad964b677ba82b8b77f1c93009 ]
+
+lock_task_sighand() can trigger a hard lockup. If NR_CPUS threads call
+getrusage() at the same time and the process has NR_THREADS, spin_lock_irq
+will spin with irqs disabled O(NR_CPUS * NR_THREADS) time.
+
+Change getrusage() to use sig->stats_lock, it was specifically designed
+for this type of use. This way it runs lockless in the likely case.
+
+TODO:
+       - Change do_task_stat() to use sig->stats_lock too, then we can
+         remove spin_lock_irq(siglock) in wait_task_zombie().
+
+       - Turn sig->stats_lock into seqcount_rwlock_t, this way the
+         readers in the slow mode won't exclude each other. See
+         https://lore.kernel.org/all/20230913154907.GA26210@redhat.com/
+
+       - stats_lock has to disable irqs because ->siglock can be taken
+         in irq context, it would be very nice to change __exit_signal()
+         to avoid the siglock->stats_lock dependency.
+
+Link: https://lkml.kernel.org/r/20240122155053.GA26214@redhat.com
+Signed-off-by: Oleg Nesterov <oleg@redhat.com>
+Reported-by: Dylan Hatch <dylanbhatch@google.com>
+Tested-by: Dylan Hatch <dylanbhatch@google.com>
+Cc: Eric W. Biederman <ebiederm@xmission.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/sys.c | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+diff --git a/kernel/sys.c b/kernel/sys.c
+index 4a5b03ad6e9b4..23e88587df87d 100644
+--- a/kernel/sys.c
++++ b/kernel/sys.c
+@@ -1714,7 +1714,9 @@ void getrusage(struct task_struct *p, int who, struct rusage *r)
+       unsigned long maxrss;
+       struct mm_struct *mm;
+       struct signal_struct *sig = p->signal;
++      unsigned int seq = 0;
++retry:
+       memset(r, 0, sizeof(*r));
+       utime = stime = 0;
+       maxrss = 0;
+@@ -1726,8 +1728,7 @@ void getrusage(struct task_struct *p, int who, struct rusage *r)
+               goto out_thread;
+       }
+-      if (!lock_task_sighand(p, &flags))
+-              return;
++      flags = read_seqbegin_or_lock_irqsave(&sig->stats_lock, &seq);
+       switch (who) {
+       case RUSAGE_BOTH:
+@@ -1755,14 +1756,23 @@ void getrusage(struct task_struct *p, int who, struct rusage *r)
+               r->ru_oublock += sig->oublock;
+               if (maxrss < sig->maxrss)
+                       maxrss = sig->maxrss;
++
++              rcu_read_lock();
+               __for_each_thread(sig, t)
+                       accumulate_thread_rusage(t, r);
++              rcu_read_unlock();
++
+               break;
+       default:
+               BUG();
+       }
+-      unlock_task_sighand(p, &flags);
++
++      if (need_seqretry(&sig->stats_lock, seq)) {
++              seq = 1;
++              goto retry;
++      }
++      done_seqretry_irqrestore(&sig->stats_lock, seq, flags);
+       if (who == RUSAGE_CHILDREN)
+               goto out_children;
+-- 
+2.43.0
+
diff --git a/queue-5.4/hv_netvsc-make-netvsc-vf-binding-check-both-mac-and-.patch b/queue-5.4/hv_netvsc-make-netvsc-vf-binding-check-both-mac-and-.patch
new file mode 100644 (file)
index 0000000..5785b43
--- /dev/null
@@ -0,0 +1,60 @@
+From 9abf378f71894606bbd59d9cbc15cd23b62d8d24 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 23 Apr 2021 18:12:35 -0700
+Subject: hv_netvsc: Make netvsc/VF binding check both MAC and serial number
+
+From: Dexuan Cui <decui@microsoft.com>
+
+[ Upstream commit 64ff412ad41fe3a5bf759ff4844dc1382176485c ]
+
+Currently the netvsc/VF binding logic only checks the PCI serial number.
+
+The Microsoft Azure Network Adapter (MANA) supports multiple net_device
+interfaces (each such interface is called a "vPort", and has its unique
+MAC address) which are backed by the same VF PCI device, so the binding
+logic should check both the MAC address and the PCI serial number.
+
+The change should not break any other existing VF drivers, because
+Hyper-V NIC SR-IOV implementation requires the netvsc network
+interface and the VF network interface have the same MAC address.
+
+Co-developed-by: Haiyang Zhang <haiyangz@microsoft.com>
+Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
+Co-developed-by: Shachar Raindel <shacharr@microsoft.com>
+Signed-off-by: Shachar Raindel <shacharr@microsoft.com>
+Acked-by: Stephen Hemminger <stephen@networkplumber.org>
+Signed-off-by: Dexuan Cui <decui@microsoft.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: 9cae43da9867 ("hv_netvsc: Register VF in netvsc_probe if NET_DEVICE_REGISTER missed")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/hyperv/netvsc_drv.c | 13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
+index 31301cd242076..5697fe709f687 100644
+--- a/drivers/net/hyperv/netvsc_drv.c
++++ b/drivers/net/hyperv/netvsc_drv.c
+@@ -2153,8 +2153,17 @@ static struct net_device *get_netvsc_byslot(const struct net_device *vf_netdev)
+               if (!ndev_ctx->vf_alloc)
+                       continue;
+-              if (ndev_ctx->vf_serial == serial)
+-                      return hv_get_drvdata(ndev_ctx->device_ctx);
++              if (ndev_ctx->vf_serial != serial)
++                      continue;
++
++              ndev = hv_get_drvdata(ndev_ctx->device_ctx);
++              if (ndev->addr_len != vf_netdev->addr_len ||
++                  memcmp(ndev->perm_addr, vf_netdev->perm_addr,
++                         ndev->addr_len) != 0)
++                      continue;
++
++              return ndev;
++
+       }
+       /* Fallback path to check synthetic vf with help of mac addr.
+-- 
+2.43.0
+
diff --git a/queue-5.4/hv_netvsc-register-vf-in-netvsc_probe-if-net_device_.patch b/queue-5.4/hv_netvsc-register-vf-in-netvsc_probe-if-net_device_.patch
new file mode 100644 (file)
index 0000000..56eb6a5
--- /dev/null
@@ -0,0 +1,184 @@
+From 9c78b28af28a27e4f666bbda91057683beaf4210 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 1 Feb 2024 20:40:38 -0800
+Subject: hv_netvsc: Register VF in netvsc_probe if NET_DEVICE_REGISTER missed
+
+From: Shradha Gupta <shradhagupta@linux.microsoft.com>
+
+[ Upstream commit 9cae43da9867412f8bd09aee5c8a8dc5e8dc3dc2 ]
+
+If hv_netvsc driver is unloaded and reloaded, the NET_DEVICE_REGISTER
+handler cannot perform VF register successfully as the register call
+is received before netvsc_probe is finished. This is because we
+register register_netdevice_notifier() very early( even before
+vmbus_driver_register()).
+To fix this, we try to register each such matching VF( if it is visible
+as a netdevice) at the end of netvsc_probe.
+
+Cc: stable@vger.kernel.org
+Fixes: 85520856466e ("hv_netvsc: Fix race of register_netdevice_notifier and VF register")
+Suggested-by: Dexuan Cui <decui@microsoft.com>
+Signed-off-by: Shradha Gupta <shradhagupta@linux.microsoft.com>
+Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
+Reviewed-by: Dexuan Cui <decui@microsoft.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/hyperv/netvsc_drv.c | 82 +++++++++++++++++++++++++--------
+ 1 file changed, 62 insertions(+), 20 deletions(-)
+
+diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
+index 880c3f69c9c10..e42102a1de41f 100644
+--- a/drivers/net/hyperv/netvsc_drv.c
++++ b/drivers/net/hyperv/netvsc_drv.c
+@@ -43,6 +43,10 @@
+ #define LINKCHANGE_INT (2 * HZ)
+ #define VF_TAKEOVER_INT (HZ / 10)
++/* Macros to define the context of vf registration */
++#define VF_REG_IN_PROBE               1
++#define VF_REG_IN_NOTIFIER    2
++
+ static unsigned int ring_size __ro_after_init = 128;
+ module_param(ring_size, uint, 0444);
+ MODULE_PARM_DESC(ring_size, "Ring buffer size (# of pages)");
+@@ -2037,7 +2041,7 @@ static rx_handler_result_t netvsc_vf_handle_frame(struct sk_buff **pskb)
+ }
+ static int netvsc_vf_join(struct net_device *vf_netdev,
+-                        struct net_device *ndev)
++                        struct net_device *ndev, int context)
+ {
+       struct net_device_context *ndev_ctx = netdev_priv(ndev);
+       int ret;
+@@ -2060,7 +2064,11 @@ static int netvsc_vf_join(struct net_device *vf_netdev,
+               goto upper_link_failed;
+       }
+-      schedule_delayed_work(&ndev_ctx->vf_takeover, VF_TAKEOVER_INT);
++      /* If this registration is called from probe context vf_takeover
++       * is taken care of later in probe itself.
++       */
++      if (context == VF_REG_IN_NOTIFIER)
++              schedule_delayed_work(&ndev_ctx->vf_takeover, VF_TAKEOVER_INT);
+       call_netdevice_notifiers(NETDEV_JOIN, vf_netdev);
+@@ -2198,7 +2206,7 @@ static int netvsc_prepare_bonding(struct net_device *vf_netdev)
+       return NOTIFY_DONE;
+ }
+-static int netvsc_register_vf(struct net_device *vf_netdev)
++static int netvsc_register_vf(struct net_device *vf_netdev, int context)
+ {
+       struct net_device_context *net_device_ctx;
+       struct netvsc_device *netvsc_dev;
+@@ -2237,7 +2245,7 @@ static int netvsc_register_vf(struct net_device *vf_netdev)
+       netdev_info(ndev, "VF registering: %s\n", vf_netdev->name);
+-      if (netvsc_vf_join(vf_netdev, ndev) != 0)
++      if (netvsc_vf_join(vf_netdev, ndev, context) != 0)
+               return NOTIFY_DONE;
+       dev_hold(vf_netdev);
+@@ -2301,10 +2309,31 @@ static int netvsc_unregister_vf(struct net_device *vf_netdev)
+       return NOTIFY_OK;
+ }
++static int check_dev_is_matching_vf(struct net_device *event_ndev)
++{
++      /* Skip NetVSC interfaces */
++      if (event_ndev->netdev_ops == &device_ops)
++              return -ENODEV;
++
++      /* Avoid non-Ethernet type devices */
++      if (event_ndev->type != ARPHRD_ETHER)
++              return -ENODEV;
++
++      /* Avoid Vlan dev with same MAC registering as VF */
++      if (is_vlan_dev(event_ndev))
++              return -ENODEV;
++
++      /* Avoid Bonding master dev with same MAC registering as VF */
++      if (netif_is_bond_master(event_ndev))
++              return -ENODEV;
++
++      return 0;
++}
++
+ static int netvsc_probe(struct hv_device *dev,
+                       const struct hv_vmbus_device_id *dev_id)
+ {
+-      struct net_device *net = NULL;
++      struct net_device *net = NULL, *vf_netdev;
+       struct net_device_context *net_device_ctx;
+       struct netvsc_device_info *device_info = NULL;
+       struct netvsc_device *nvdev;
+@@ -2405,6 +2434,30 @@ static int netvsc_probe(struct hv_device *dev,
+       }
+       list_add(&net_device_ctx->list, &netvsc_dev_list);
++
++      /* When the hv_netvsc driver is unloaded and reloaded, the
++       * NET_DEVICE_REGISTER for the vf device is replayed before probe
++       * is complete. This is because register_netdevice_notifier() gets
++       * registered before vmbus_driver_register() so that callback func
++       * is set before probe and we don't miss events like NETDEV_POST_INIT
++       * So, in this section we try to register the matching vf device that
++       * is present as a netdevice, knowing that its register call is not
++       * processed in the netvsc_netdev_notifier(as probing is progress and
++       * get_netvsc_byslot fails).
++       */
++      for_each_netdev(dev_net(net), vf_netdev) {
++              ret = check_dev_is_matching_vf(vf_netdev);
++              if (ret != 0)
++                      continue;
++
++              if (net != get_netvsc_byslot(vf_netdev))
++                      continue;
++
++              netvsc_prepare_bonding(vf_netdev);
++              netvsc_register_vf(vf_netdev, VF_REG_IN_PROBE);
++              __netvsc_vf_setup(net, vf_netdev);
++              break;
++      }
+       rtnl_unlock();
+       kfree(device_info);
+@@ -2497,28 +2550,17 @@ static int netvsc_netdev_event(struct notifier_block *this,
+                              unsigned long event, void *ptr)
+ {
+       struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
++      int ret = 0;
+-      /* Skip our own events */
+-      if (event_dev->netdev_ops == &device_ops)
+-              return NOTIFY_DONE;
+-
+-      /* Avoid non-Ethernet type devices */
+-      if (event_dev->type != ARPHRD_ETHER)
+-              return NOTIFY_DONE;
+-
+-      /* Avoid Vlan dev with same MAC registering as VF */
+-      if (is_vlan_dev(event_dev))
+-              return NOTIFY_DONE;
+-
+-      /* Avoid Bonding master dev with same MAC registering as VF */
+-      if (netif_is_bond_master(event_dev))
++      ret = check_dev_is_matching_vf(event_dev);
++      if (ret != 0)
+               return NOTIFY_DONE;
+       switch (event) {
+       case NETDEV_POST_INIT:
+               return netvsc_prepare_bonding(event_dev);
+       case NETDEV_REGISTER:
+-              return netvsc_register_vf(event_dev);
++              return netvsc_register_vf(event_dev, VF_REG_IN_NOTIFIER);
+       case NETDEV_UNREGISTER:
+               return netvsc_unregister_vf(event_dev);
+       case NETDEV_UP:
+-- 
+2.43.0
+
diff --git a/queue-5.4/hv_netvsc-use-netif_is_bond_master-instead-of-open-c.patch b/queue-5.4/hv_netvsc-use-netif_is_bond_master-instead-of-open-c.patch
new file mode 100644 (file)
index 0000000..f5ecd10
--- /dev/null
@@ -0,0 +1,38 @@
+From 937eea928bffd0cd94b2c3232260e7e91c1433c8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 10 Oct 2021 13:03:28 +0900
+Subject: hv_netvsc: use netif_is_bond_master() instead of open code
+
+From: Juhee Kang <claudiajkang@gmail.com>
+
+[ Upstream commit c60882a4566a0a62dc3a40c85131103aad83dcb3 ]
+
+Use netif_is_bond_master() function instead of open code, which is
+((event_dev->priv_flags & IFF_BONDING) && (event_dev->flags & IFF_MASTER)).
+This patch doesn't change logic.
+
+Signed-off-by: Juhee Kang <claudiajkang@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: 9cae43da9867 ("hv_netvsc: Register VF in netvsc_probe if NET_DEVICE_REGISTER missed")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/hyperv/netvsc_drv.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
+index 5697fe709f687..880c3f69c9c10 100644
+--- a/drivers/net/hyperv/netvsc_drv.c
++++ b/drivers/net/hyperv/netvsc_drv.c
+@@ -2511,8 +2511,7 @@ static int netvsc_netdev_event(struct notifier_block *this,
+               return NOTIFY_DONE;
+       /* Avoid Bonding master dev with same MAC registering as VF */
+-      if ((event_dev->priv_flags & IFF_BONDING) &&
+-          (event_dev->flags & IFF_MASTER))
++      if (netif_is_bond_master(event_dev))
+               return NOTIFY_DONE;
+       switch (event) {
+-- 
+2.43.0
+
diff --git a/queue-5.4/input-i8042-fix-strange-behavior-of-touchpad-on-clev.patch b/queue-5.4/input-i8042-fix-strange-behavior-of-touchpad-on-clev.patch
new file mode 100644 (file)
index 0000000..ff17705
--- /dev/null
@@ -0,0 +1,52 @@
+From 8eb55170abc5fa5188f30a429872f516c5883cf9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 5 Dec 2023 17:36:01 +0100
+Subject: Input: i8042 - fix strange behavior of touchpad on Clevo NS70PU
+
+From: Werner Sembach <wse@tuxedocomputers.com>
+
+[ Upstream commit a60e6c3918d20848906ffcdfcf72ca6a8cfbcf2e ]
+
+When closing the laptop lid with an external screen connected, the mouse
+pointer has a constant movement to the lower right corner. Opening the
+lid again stops this movement, but after that the touchpad does no longer
+register clicks.
+
+The touchpad is connected both via i2c-hid and PS/2, the predecessor of
+this device (NS70MU) has the same layout in this regard and also strange
+behaviour caused by the psmouse and the i2c-hid driver fighting over
+touchpad control. This fix is reusing the same workaround by just
+disabling the PS/2 aux port, that is only used by the touchpad, to give the
+i2c-hid driver the lone control over the touchpad.
+
+v2: Rebased on current master
+
+Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/r/20231205163602.16106-1-wse@tuxedocomputers.com
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/input/serio/i8042-x86ia64io.h | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
+index 1ab7f27bc9062..4ae96bd56253c 100644
+--- a/drivers/input/serio/i8042-x86ia64io.h
++++ b/drivers/input/serio/i8042-x86ia64io.h
+@@ -1179,6 +1179,12 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
+                                       SERIO_QUIRK_RESET_ALWAYS | SERIO_QUIRK_NOLOOP |
+                                       SERIO_QUIRK_NOPNP)
+       },
++      {
++              .matches = {
++                      DMI_MATCH(DMI_BOARD_NAME, "NS5x_7xPU"),
++              },
++              .driver_data = (void *)(SERIO_QUIRK_NOAUX)
++      },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_NAME, "NJ50_70CU"),
+-- 
+2.43.0
+
diff --git a/queue-5.4/nfsd-add-documenting-comment-for-nfsd4_release_locko.patch b/queue-5.4/nfsd-add-documenting-comment-for-nfsd4_release_locko.patch
new file mode 100644 (file)
index 0000000..e5682b9
--- /dev/null
@@ -0,0 +1,73 @@
+From 1ca2280735b8291e782b15e200b62980b5c6af8f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 22 May 2022 12:34:38 -0400
+Subject: NFSD: Add documenting comment for nfsd4_release_lockowner()
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit 043862b09cc00273e35e6c3a6389957953a34207 ]
+
+And return explicit nfserr values that match what is documented in the
+new comment / API contract.
+
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Stable-dep-of: edcf9725150e ("nfsd: fix RELEASE_LOCKOWNER")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/nfsd/nfs4state.c | 23 ++++++++++++++++++++---
+ 1 file changed, 20 insertions(+), 3 deletions(-)
+
+diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
+index 9a77a3eac4acc..0dfc45d376587 100644
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -6867,6 +6867,23 @@ check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner)
+       return status;
+ }
++/**
++ * nfsd4_release_lockowner - process NFSv4.0 RELEASE_LOCKOWNER operations
++ * @rqstp: RPC transaction
++ * @cstate: NFSv4 COMPOUND state
++ * @u: RELEASE_LOCKOWNER arguments
++ *
++ * The lockowner's so_count is bumped when a lock record is added
++ * or when copying a conflicting lock. The latter case is brief,
++ * but can lead to fleeting false positives when looking for
++ * locks-in-use.
++ *
++ * Return values:
++ *   %nfs_ok: lockowner released or not found
++ *   %nfserr_locks_held: lockowner still in use
++ *   %nfserr_stale_clientid: clientid no longer active
++ *   %nfserr_expired: clientid not recognized
++ */
+ __be32
+ nfsd4_release_lockowner(struct svc_rqst *rqstp,
+                       struct nfsd4_compound_state *cstate,
+@@ -6893,7 +6910,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
+       lo = find_lockowner_str_locked(clp, &rlockowner->rl_owner);
+       if (!lo) {
+               spin_unlock(&clp->cl_lock);
+-              return status;
++              return nfs_ok;
+       }
+       if (atomic_read(&lo->lo_owner.so_count) != 2) {
+               spin_unlock(&clp->cl_lock);
+@@ -6909,11 +6926,11 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
+               put_ol_stateid_locked(stp, &reaplist);
+       }
+       spin_unlock(&clp->cl_lock);
++
+       free_ol_stateid_reaplist(&reaplist);
+       remove_blocked_locks(lo);
+       nfs4_put_stateowner(&lo->lo_owner);
+-
+-      return status;
++      return nfs_ok;
+ }
+ static inline struct nfs4_client_reclaim *
+-- 
+2.43.0
+
diff --git a/queue-5.4/nfsd-don-t-take-fi_lock-in-nfsd_break_deleg_cb.patch b/queue-5.4/nfsd-don-t-take-fi_lock-in-nfsd_break_deleg_cb.patch
new file mode 100644 (file)
index 0000000..ad8cf6e
--- /dev/null
@@ -0,0 +1,97 @@
+From 45b3428bc3d461644256799e2d05af43a3e5f67d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 5 Feb 2024 13:22:39 +1100
+Subject: nfsd: don't take fi_lock in nfsd_break_deleg_cb()
+
+From: NeilBrown <neilb@suse.de>
+
+[ Upstream commit 5ea9a7c5fe4149f165f0e3b624fe08df02b6c301 ]
+
+A recent change to check_for_locks() changed it to take ->flc_lock while
+holding ->fi_lock.  This creates a lock inversion (reported by lockdep)
+because there is a case where ->fi_lock is taken while holding
+->flc_lock.
+
+->flc_lock is held across ->fl_lmops callbacks, and
+nfsd_break_deleg_cb() is one of those and does take ->fi_lock.  However
+it doesn't need to.
+
+Prior to v4.17-rc1~110^2~22 ("nfsd: create a separate lease for each
+delegation") nfsd_break_deleg_cb() would walk the ->fi_delegations list
+and so needed the lock.  Since then it doesn't walk the list and doesn't
+need the lock.
+
+Two actions are performed under the lock.  One is to call
+nfsd_break_one_deleg which calls nfsd4_run_cb().  These doesn't act on
+the nfs4_file at all, so don't need the lock.
+
+The other is to set ->fi_had_conflict which is in the nfs4_file.
+This field is only ever set here (except when initialised to false)
+so there is no possible problem will multiple threads racing when
+setting it.
+
+The field is tested twice in nfs4_set_delegation().  The first test does
+not hold a lock and is documented as an opportunistic optimisation, so
+it doesn't impose any need to hold ->fi_lock while setting
+->fi_had_conflict.
+
+The second test in nfs4_set_delegation() *is* make under ->fi_lock, so
+removing the locking when ->fi_had_conflict is set could make a change.
+The change could only be interesting if ->fi_had_conflict tested as
+false even though nfsd_break_one_deleg() ran before ->fi_lock was
+unlocked.  i.e. while hash_delegation_locked() was running.
+As hash_delegation_lock() doesn't interact in any way with nfs4_run_cb()
+there can be no importance to this interaction.
+
+So this patch removes the locking from nfsd_break_one_deleg() and moves
+the final test on ->fi_had_conflict out of the locked region to make it
+clear that locking isn't important to the test.  It is still tested
+*after* vfs_setlease() has succeeded.  This might be significant and as
+vfs_setlease() takes ->flc_lock, and nfsd_break_one_deleg() is called
+under ->flc_lock this "after" is a true ordering provided by a spinlock.
+
+Fixes: edcf9725150e ("nfsd: fix RELEASE_LOCKOWNER")
+Signed-off-by: NeilBrown <neilb@suse.de>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/nfsd/nfs4state.c | 11 +++++------
+ 1 file changed, 5 insertions(+), 6 deletions(-)
+
+diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
+index bca22325083c0..c479c45892075 100644
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -4506,10 +4506,8 @@ nfsd_break_deleg_cb(struct file_lock *fl)
+        */
+       fl->fl_break_time = 0;
+-      spin_lock(&fp->fi_lock);
+       fp->fi_had_conflict = true;
+       nfsd_break_one_deleg(dp);
+-      spin_unlock(&fp->fi_lock);
+       return ret;
+ }
+@@ -4907,12 +4905,13 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
+       if (status)
+               goto out_clnt_odstate;
++      status = -EAGAIN;
++      if (fp->fi_had_conflict)
++              goto out_unlock;
++
+       spin_lock(&state_lock);
+       spin_lock(&fp->fi_lock);
+-      if (fp->fi_had_conflict)
+-              status = -EAGAIN;
+-      else
+-              status = hash_delegation_locked(dp, fp);
++      status = hash_delegation_locked(dp, fp);
+       spin_unlock(&fp->fi_lock);
+       spin_unlock(&state_lock);
+-- 
+2.43.0
+
diff --git a/queue-5.4/nfsd-fix-release_lockowner.patch b/queue-5.4/nfsd-fix-release_lockowner.patch
new file mode 100644 (file)
index 0000000..89329d2
--- /dev/null
@@ -0,0 +1,149 @@
+From ac66408be68cc89cfe278cfd29c3bdfa7efbb17e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 22 Jan 2024 14:58:16 +1100
+Subject: nfsd: fix RELEASE_LOCKOWNER
+
+From: NeilBrown <neilb@suse.de>
+
+[ Upstream commit edcf9725150e42beeca42d085149f4c88fa97afd ]
+
+The test on so_count in nfsd4_release_lockowner() is nonsense and
+harmful.  Revert to using check_for_locks(), changing that to not sleep.
+
+First: harmful.
+As is documented in the kdoc comment for nfsd4_release_lockowner(), the
+test on so_count can transiently return a false positive resulting in a
+return of NFS4ERR_LOCKS_HELD when in fact no locks are held.  This is
+clearly a protocol violation and with the Linux NFS client it can cause
+incorrect behaviour.
+
+If RELEASE_LOCKOWNER is sent while some other thread is still
+processing a LOCK request which failed because, at the time that request
+was received, the given owner held a conflicting lock, then the nfsd
+thread processing that LOCK request can hold a reference (conflock) to
+the lock owner that causes nfsd4_release_lockowner() to return an
+incorrect error.
+
+The Linux NFS client ignores that NFS4ERR_LOCKS_HELD error because it
+never sends NFS4_RELEASE_LOCKOWNER without first releasing any locks, so
+it knows that the error is impossible.  It assumes the lock owner was in
+fact released so it feels free to use the same lock owner identifier in
+some later locking request.
+
+When it does reuse a lock owner identifier for which a previous RELEASE
+failed, it will naturally use a lock_seqid of zero.  However the server,
+which didn't release the lock owner, will expect a larger lock_seqid and
+so will respond with NFS4ERR_BAD_SEQID.
+
+So clearly it is harmful to allow a false positive, which testing
+so_count allows.
+
+The test is nonsense because ... well... it doesn't mean anything.
+
+so_count is the sum of three different counts.
+1/ the set of states listed on so_stateids
+2/ the set of active vfs locks owned by any of those states
+3/ various transient counts such as for conflicting locks.
+
+When it is tested against '2' it is clear that one of these is the
+transient reference obtained by find_lockowner_str_locked().  It is not
+clear what the other one is expected to be.
+
+In practice, the count is often 2 because there is precisely one state
+on so_stateids.  If there were more, this would fail.
+
+In my testing I see two circumstances when RELEASE_LOCKOWNER is called.
+In one case, CLOSE is called before RELEASE_LOCKOWNER.  That results in
+all the lock states being removed, and so the lockowner being discarded
+(it is removed when there are no more references which usually happens
+when the lock state is discarded).  When nfsd4_release_lockowner() finds
+that the lock owner doesn't exist, it returns success.
+
+The other case shows an so_count of '2' and precisely one state listed
+in so_stateid.  It appears that the Linux client uses a separate lock
+owner for each file resulting in one lock state per lock owner, so this
+test on '2' is safe.  For another client it might not be safe.
+
+So this patch changes check_for_locks() to use the (newish)
+find_any_file_locked() so that it doesn't take a reference on the
+nfs4_file and so never calls nfsd_file_put(), and so never sleeps.  With
+this check is it safe to restore the use of check_for_locks() rather
+than testing so_count against the mysterious '2'.
+
+Fixes: ce3c4ad7f4ce ("NFSD: Fix possible sleep during nfsd4_release_lockowner()")
+Signed-off-by: NeilBrown <neilb@suse.de>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Cc: stable@vger.kernel.org # v6.2+
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/nfsd/nfs4state.c | 26 +++++++++++++++-----------
+ 1 file changed, 15 insertions(+), 11 deletions(-)
+
+diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
+index 0dfc45d376587..bca22325083c0 100644
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -6840,14 +6840,16 @@ check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner)
+ {
+       struct file_lock *fl;
+       int status = false;
+-      struct nfsd_file *nf = find_any_file(fp);
++      struct nfsd_file *nf;
+       struct inode *inode;
+       struct file_lock_context *flctx;
++      spin_lock(&fp->fi_lock);
++      nf = find_any_file_locked(fp);
+       if (!nf) {
+               /* Any valid lock stateid should have some sort of access */
+               WARN_ON_ONCE(1);
+-              return status;
++              goto out;
+       }
+       inode = locks_inode(nf->nf_file);
+@@ -6863,7 +6865,8 @@ check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner)
+               }
+               spin_unlock(&flctx->flc_lock);
+       }
+-      nfsd_file_put(nf);
++out:
++      spin_unlock(&fp->fi_lock);
+       return status;
+ }
+@@ -6873,10 +6876,8 @@ check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner)
+  * @cstate: NFSv4 COMPOUND state
+  * @u: RELEASE_LOCKOWNER arguments
+  *
+- * The lockowner's so_count is bumped when a lock record is added
+- * or when copying a conflicting lock. The latter case is brief,
+- * but can lead to fleeting false positives when looking for
+- * locks-in-use.
++ * Check if theree are any locks still held and if not - free the lockowner
++ * and any lock state that is owned.
+  *
+  * Return values:
+  *   %nfs_ok: lockowner released or not found
+@@ -6912,10 +6913,13 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
+               spin_unlock(&clp->cl_lock);
+               return nfs_ok;
+       }
+-      if (atomic_read(&lo->lo_owner.so_count) != 2) {
+-              spin_unlock(&clp->cl_lock);
+-              nfs4_put_stateowner(&lo->lo_owner);
+-              return nfserr_locks_held;
++
++      list_for_each_entry(stp, &lo->lo_owner.so_stateids, st_perstateowner) {
++              if (check_for_locks(stp->st_stid.sc_file, lo)) {
++                      spin_unlock(&clp->cl_lock);
++                      nfs4_put_stateowner(&lo->lo_owner);
++                      return nfserr_locks_held;
++              }
+       }
+       unhash_lockowner_locked(lo);
+       while (!list_empty(&lo->lo_owner.so_stateids)) {
+-- 
+2.43.0
+
diff --git a/queue-5.4/nfsd-modernize-nfsd4_release_lockowner.patch b/queue-5.4/nfsd-modernize-nfsd4_release_lockowner.patch
new file mode 100644 (file)
index 0000000..277a978
--- /dev/null
@@ -0,0 +1,86 @@
+From 17087f9cfb05d32235f210d1c257dfaeb8730f95 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 22 May 2022 12:07:18 -0400
+Subject: NFSD: Modernize nfsd4_release_lockowner()
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit bd8fdb6e545f950f4654a9a10d7e819ad48146e5 ]
+
+Refactor: Use existing helpers that other lock operations use. This
+change removes several automatic variables, so re-organize the
+variable declarations for readability.
+
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Stable-dep-of: edcf9725150e ("nfsd: fix RELEASE_LOCKOWNER")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/nfsd/nfs4state.c | 36 +++++++++++-------------------------
+ 1 file changed, 11 insertions(+), 25 deletions(-)
+
+diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
+index a0aa7e63739df..9a77a3eac4acc 100644
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -6873,16 +6873,13 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
+                       union nfsd4_op_u *u)
+ {
+       struct nfsd4_release_lockowner *rlockowner = &u->release_lockowner;
++      struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
+       clientid_t *clid = &rlockowner->rl_clientid;
+-      struct nfs4_stateowner *sop;
+-      struct nfs4_lockowner *lo = NULL;
+       struct nfs4_ol_stateid *stp;
+-      struct xdr_netobj *owner = &rlockowner->rl_owner;
+-      unsigned int hashval = ownerstr_hashval(owner);
+-      __be32 status;
+-      struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
++      struct nfs4_lockowner *lo;
+       struct nfs4_client *clp;
+-      LIST_HEAD (reaplist);
++      LIST_HEAD(reaplist);
++      __be32 status;
+       dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
+               clid->cl_boot, clid->cl_id);
+@@ -6890,30 +6887,19 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
+       status = lookup_clientid(clid, cstate, nn);
+       if (status)
+               return status;
+-
+       clp = cstate->clp;
+-      /* Find the matching lock stateowner */
+-      spin_lock(&clp->cl_lock);
+-      list_for_each_entry(sop, &clp->cl_ownerstr_hashtbl[hashval],
+-                          so_strhash) {
+-              if (sop->so_is_open_owner || !same_owner_str(sop, owner))
+-                      continue;
+-
+-              if (atomic_read(&sop->so_count) != 1) {
+-                      spin_unlock(&clp->cl_lock);
+-                      return nfserr_locks_held;
+-              }
+-
+-              lo = lockowner(sop);
+-              nfs4_get_stateowner(sop);
+-              break;
+-      }
++      spin_lock(&clp->cl_lock);
++      lo = find_lockowner_str_locked(clp, &rlockowner->rl_owner);
+       if (!lo) {
+               spin_unlock(&clp->cl_lock);
+               return status;
+       }
+-
++      if (atomic_read(&lo->lo_owner.so_count) != 2) {
++              spin_unlock(&clp->cl_lock);
++              nfs4_put_stateowner(&lo->lo_owner);
++              return nfserr_locks_held;
++      }
+       unhash_lockowner_locked(lo);
+       while (!list_empty(&lo->lo_owner.so_stateids)) {
+               stp = list_first_entry(&lo->lo_owner.so_stateids,
+-- 
+2.43.0
+
diff --git a/queue-5.4/regmap-add-bulk-read-write-callbacks-into-regmap_con.patch b/queue-5.4/regmap-add-bulk-read-write-callbacks-into-regmap_con.patch
new file mode 100644 (file)
index 0000000..47aae53
--- /dev/null
@@ -0,0 +1,300 @@
+From 252006fc58a9519446186d9f0ef8b0b98e604b44 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 30 Apr 2022 04:51:44 +0200
+Subject: regmap: Add bulk read/write callbacks into regmap_config
+
+From: Marek Vasut <marex@denx.de>
+
+[ Upstream commit d77e745613680c54708470402e2b623dcd769681 ]
+
+Currently the regmap_config structure only allows the user to implement
+single element register read/write using .reg_read/.reg_write callbacks.
+The regmap_bus already implements bulk counterparts of both, and is being
+misused as a workaround for the missing bulk read/write callbacks in
+regmap_config by a couple of drivers. To stop this misuse, add the bulk
+read/write callbacks to regmap_config and call them from the regmap core
+code.
+
+Signed-off-by: Marek Vasut <marex@denx.de>
+Cc: Jagan Teki <jagan@amarulasolutions.com>
+Cc: Mark Brown <broonie@kernel.org>
+Cc: Maxime Ripard <maxime@cerno.tech>
+Cc: Robert Foss <robert.foss@linaro.org>
+Cc: Sam Ravnborg <sam@ravnborg.org>
+Cc: Thomas Zimmermann <tzimmermann@suse.de>
+To: dri-devel@lists.freedesktop.org
+Link: https://lore.kernel.org/r/20220430025145.640305-1-marex@denx.de
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Stable-dep-of: 3f42b142ea11 ("serial: max310x: fix IO data corruption in batched operations")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/base/regmap/internal.h |  4 ++
+ drivers/base/regmap/regmap.c   | 76 ++++++++++++++++++----------------
+ include/linux/regmap.h         | 12 ++++++
+ 3 files changed, 56 insertions(+), 36 deletions(-)
+
+diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
+index d7c01b70e43db..af6ac068ca5d3 100644
+--- a/drivers/base/regmap/internal.h
++++ b/drivers/base/regmap/internal.h
+@@ -104,6 +104,10 @@ struct regmap {
+       int (*reg_write)(void *context, unsigned int reg, unsigned int val);
+       int (*reg_update_bits)(void *context, unsigned int reg,
+                              unsigned int mask, unsigned int val);
++      /* Bulk read/write */
++      int (*read)(void *context, const void *reg_buf, size_t reg_size,
++                  void *val_buf, size_t val_size);
++      int (*write)(void *context, const void *data, size_t count);
+       bool defer_caching;
+diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
+index 961b206f6ab2d..6f580883c1973 100644
+--- a/drivers/base/regmap/regmap.c
++++ b/drivers/base/regmap/regmap.c
+@@ -771,12 +771,15 @@ struct regmap *__regmap_init(struct device *dev,
+               map->reg_stride_order = ilog2(map->reg_stride);
+       else
+               map->reg_stride_order = -1;
+-      map->use_single_read = config->use_single_read || !bus || !bus->read;
+-      map->use_single_write = config->use_single_write || !bus || !bus->write;
+-      map->can_multi_write = config->can_multi_write && bus && bus->write;
++      map->use_single_read = config->use_single_read || !(config->read || (bus && bus->read));
++      map->use_single_write = config->use_single_write || !(config->write || (bus && bus->write));
++      map->can_multi_write = config->can_multi_write && (config->write || (bus && bus->write));
+       if (bus) {
+               map->max_raw_read = bus->max_raw_read;
+               map->max_raw_write = bus->max_raw_write;
++      } else if (config->max_raw_read && config->max_raw_write) {
++              map->max_raw_read = config->max_raw_read;
++              map->max_raw_write = config->max_raw_write;
+       }
+       map->dev = dev;
+       map->bus = bus;
+@@ -810,7 +813,16 @@ struct regmap *__regmap_init(struct device *dev,
+               map->read_flag_mask = bus->read_flag_mask;
+       }
+-      if (!bus) {
++      if (config && config->read && config->write) {
++              map->reg_read  = _regmap_bus_read;
++
++              /* Bulk read/write */
++              map->read = config->read;
++              map->write = config->write;
++
++              reg_endian = REGMAP_ENDIAN_NATIVE;
++              val_endian = REGMAP_ENDIAN_NATIVE;
++      } else if (!bus) {
+               map->reg_read  = config->reg_read;
+               map->reg_write = config->reg_write;
+               map->reg_update_bits = config->reg_update_bits;
+@@ -826,10 +838,13 @@ struct regmap *__regmap_init(struct device *dev,
+       } else {
+               map->reg_read  = _regmap_bus_read;
+               map->reg_update_bits = bus->reg_update_bits;
+-      }
++              /* Bulk read/write */
++              map->read = bus->read;
++              map->write = bus->write;
+-      reg_endian = regmap_get_reg_endian(bus, config);
+-      val_endian = regmap_get_val_endian(dev, bus, config);
++              reg_endian = regmap_get_reg_endian(bus, config);
++              val_endian = regmap_get_val_endian(dev, bus, config);
++      }
+       switch (config->reg_bits + map->reg_shift) {
+       case 2:
+@@ -1480,8 +1495,6 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg,
+       size_t len;
+       int i;
+-      WARN_ON(!map->bus);
+-
+       /* Check for unwritable or noinc registers in range
+        * before we start
+        */
+@@ -1563,7 +1576,7 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg,
+               val = work_val;
+       }
+-      if (map->async && map->bus->async_write) {
++      if (map->async && map->bus && map->bus->async_write) {
+               struct regmap_async *async;
+               trace_regmap_async_write_start(map, reg, val_len);
+@@ -1631,10 +1644,10 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg,
+        * write.
+        */
+       if (val == work_val)
+-              ret = map->bus->write(map->bus_context, map->work_buf,
+-                                    map->format.reg_bytes +
+-                                    map->format.pad_bytes +
+-                                    val_len);
++              ret = map->write(map->bus_context, map->work_buf,
++                               map->format.reg_bytes +
++                               map->format.pad_bytes +
++                               val_len);
+       else if (map->bus->gather_write)
+               ret = map->bus->gather_write(map->bus_context, map->work_buf,
+                                            map->format.reg_bytes +
+@@ -1653,7 +1666,7 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg,
+               memcpy(buf, map->work_buf, map->format.reg_bytes);
+               memcpy(buf + map->format.reg_bytes + map->format.pad_bytes,
+                      val, val_len);
+-              ret = map->bus->write(map->bus_context, buf, len);
++              ret = map->write(map->bus_context, buf, len);
+               kfree(buf);
+       } else if (ret != 0 && !map->cache_bypass && map->format.parse_val) {
+@@ -1710,7 +1723,7 @@ static int _regmap_bus_formatted_write(void *context, unsigned int reg,
+       struct regmap_range_node *range;
+       struct regmap *map = context;
+-      WARN_ON(!map->bus || !map->format.format_write);
++      WARN_ON(!map->format.format_write);
+       range = _regmap_range_lookup(map, reg);
+       if (range) {
+@@ -1723,8 +1736,7 @@ static int _regmap_bus_formatted_write(void *context, unsigned int reg,
+       trace_regmap_hw_write_start(map, reg, 1);
+-      ret = map->bus->write(map->bus_context, map->work_buf,
+-                            map->format.buf_size);
++      ret = map->write(map->bus_context, map->work_buf, map->format.buf_size);
+       trace_regmap_hw_write_done(map, reg, 1);
+@@ -1744,7 +1756,7 @@ static int _regmap_bus_raw_write(void *context, unsigned int reg,
+ {
+       struct regmap *map = context;
+-      WARN_ON(!map->bus || !map->format.format_val);
++      WARN_ON(!map->format.format_val);
+       map->format.format_val(map->work_buf + map->format.reg_bytes
+                              + map->format.pad_bytes, val, 0);
+@@ -1758,7 +1770,7 @@ static int _regmap_bus_raw_write(void *context, unsigned int reg,
+ static inline void *_regmap_map_get_context(struct regmap *map)
+ {
+-      return (map->bus) ? map : map->bus_context;
++      return (map->bus || (!map->bus && map->read)) ? map : map->bus_context;
+ }
+ int _regmap_write(struct regmap *map, unsigned int reg,
+@@ -2167,7 +2179,7 @@ static int _regmap_raw_multi_reg_write(struct regmap *map,
+       u8 = buf;
+       *u8 |= map->write_flag_mask;
+-      ret = map->bus->write(map->bus_context, buf, len);
++      ret = map->write(map->bus_context, buf, len);
+       kfree(buf);
+@@ -2465,9 +2477,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
+       struct regmap_range_node *range;
+       int ret;
+-      WARN_ON(!map->bus);
+-
+-      if (!map->bus || !map->bus->read)
++      if (!map->read)
+               return -EINVAL;
+       range = _regmap_range_lookup(map, reg);
+@@ -2483,9 +2493,9 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
+                                     map->read_flag_mask);
+       trace_regmap_hw_read_start(map, reg, val_len / map->format.val_bytes);
+-      ret = map->bus->read(map->bus_context, map->work_buf,
+-                           map->format.reg_bytes + map->format.pad_bytes,
+-                           val, val_len);
++      ret = map->read(map->bus_context, map->work_buf,
++                      map->format.reg_bytes + map->format.pad_bytes,
++                      val, val_len);
+       trace_regmap_hw_read_done(map, reg, val_len / map->format.val_bytes);
+@@ -2596,8 +2606,6 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
+       unsigned int v;
+       int ret, i;
+-      if (!map->bus)
+-              return -EINVAL;
+       if (val_len % map->format.val_bytes)
+               return -EINVAL;
+       if (!IS_ALIGNED(reg, map->reg_stride))
+@@ -2612,7 +2620,7 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
+               size_t chunk_count, chunk_bytes;
+               size_t chunk_regs = val_count;
+-              if (!map->bus->read) {
++              if (!map->read) {
+                       ret = -ENOTSUPP;
+                       goto out;
+               }
+@@ -2672,7 +2680,7 @@ EXPORT_SYMBOL_GPL(regmap_raw_read);
+  * @val: Pointer to data buffer
+  * @val_len: Length of output buffer in bytes.
+  *
+- * The regmap API usually assumes that bulk bus read operations will read a
++ * The regmap API usually assumes that bulk read operations will read a
+  * range of registers. Some devices have certain registers for which a read
+  * operation read will read from an internal FIFO.
+  *
+@@ -2690,10 +2698,6 @@ int regmap_noinc_read(struct regmap *map, unsigned int reg,
+       size_t read_len;
+       int ret;
+-      if (!map->bus)
+-              return -EINVAL;
+-      if (!map->bus->read)
+-              return -ENOTSUPP;
+       if (val_len % map->format.val_bytes)
+               return -EINVAL;
+       if (!IS_ALIGNED(reg, map->reg_stride))
+@@ -2807,7 +2811,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
+       if (val_count == 0)
+               return -EINVAL;
+-      if (map->bus && map->format.parse_inplace && (vol || map->cache_type == REGCACHE_NONE)) {
++      if (map->format.parse_inplace && (vol || map->cache_type == REGCACHE_NONE)) {
+               ret = regmap_raw_read(map, reg, val, val_bytes * val_count);
+               if (ret != 0)
+                       return ret;
+diff --git a/include/linux/regmap.h b/include/linux/regmap.h
+index 29661bbd137d7..edc095434787b 100644
+--- a/include/linux/regmap.h
++++ b/include/linux/regmap.h
+@@ -300,6 +300,12 @@ typedef void (*regmap_unlock)(void *);
+  *                 if the function require special handling with lock and reg
+  *                 handling and the operation cannot be represented as a simple
+  *                 update_bits operation on a bus such as SPI, I2C, etc.
++ * @read: Optional callback that if filled will be used to perform all the
++ *        bulk reads from the registers. Data is returned in the buffer used
++ *        to transmit data.
++ * @write: Same as above for writing.
++ * @max_raw_read: Max raw read size that can be used on the device.
++ * @max_raw_write: Max raw write size that can be used on the device.
+  * @fast_io:    Register IO is fast. Use a spinlock instead of a mutex
+  *              to perform locking. This field is ignored if custom lock/unlock
+  *              functions are used (see fields lock/unlock of struct regmap_config).
+@@ -378,6 +384,12 @@ struct regmap_config {
+       int (*reg_write)(void *context, unsigned int reg, unsigned int val);
+       int (*reg_update_bits)(void *context, unsigned int reg,
+                              unsigned int mask, unsigned int val);
++      /* Bulk read/write */
++      int (*read)(void *context, const void *reg_buf, size_t reg_size,
++                  void *val_buf, size_t val_size);
++      int (*write)(void *context, const void *data, size_t count);
++      size_t max_raw_read;
++      size_t max_raw_write;
+       bool fast_io;
+-- 
+2.43.0
+
diff --git a/queue-5.4/regmap-allow-to-define-reg_update_bits-for-no-bus-co.patch b/queue-5.4/regmap-allow-to-define-reg_update_bits-for-no-bus-co.patch
new file mode 100644 (file)
index 0000000..b65b424
--- /dev/null
@@ -0,0 +1,65 @@
+From 12a1eb8fcdfa672b3d3c13044754643d8986cf66 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 4 Nov 2021 16:00:40 +0100
+Subject: regmap: allow to define reg_update_bits for no bus configuration
+
+From: Ansuel Smith <ansuelsmth@gmail.com>
+
+[ Upstream commit 02d6fdecb9c38de19065f6bed8d5214556fd061d ]
+
+Some device requires a special handling for reg_update_bits and can't use
+the normal regmap read write logic. An example is when locking is
+handled by the device and rmw operations requires to do atomic operations.
+Allow to declare a dedicated function in regmap_config for
+reg_update_bits in no bus configuration.
+
+Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
+Link: https://lore.kernel.org/r/20211104150040.1260-1-ansuelsmth@gmail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Stable-dep-of: 3f42b142ea11 ("serial: max310x: fix IO data corruption in batched operations")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/base/regmap/regmap.c | 1 +
+ include/linux/regmap.h       | 7 +++++++
+ 2 files changed, 8 insertions(+)
+
+diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
+index 23574c328616f..961b206f6ab2d 100644
+--- a/drivers/base/regmap/regmap.c
++++ b/drivers/base/regmap/regmap.c
+@@ -813,6 +813,7 @@ struct regmap *__regmap_init(struct device *dev,
+       if (!bus) {
+               map->reg_read  = config->reg_read;
+               map->reg_write = config->reg_write;
++              map->reg_update_bits = config->reg_update_bits;
+               map->defer_caching = false;
+               goto skip_format_initialization;
+diff --git a/include/linux/regmap.h b/include/linux/regmap.h
+index dfe493ac692d2..29661bbd137d7 100644
+--- a/include/linux/regmap.h
++++ b/include/linux/regmap.h
+@@ -295,6 +295,11 @@ typedef void (*regmap_unlock)(void *);
+  *              read operation on a bus such as SPI, I2C, etc. Most of the
+  *              devices do not need this.
+  * @reg_write:          Same as above for writing.
++ * @reg_update_bits: Optional callback that if filled will be used to perform
++ *                 all the update_bits(rmw) operation. Should only be provided
++ *                 if the function require special handling with lock and reg
++ *                 handling and the operation cannot be represented as a simple
++ *                 update_bits operation on a bus such as SPI, I2C, etc.
+  * @fast_io:    Register IO is fast. Use a spinlock instead of a mutex
+  *              to perform locking. This field is ignored if custom lock/unlock
+  *              functions are used (see fields lock/unlock of struct regmap_config).
+@@ -371,6 +376,8 @@ struct regmap_config {
+       int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
+       int (*reg_write)(void *context, unsigned int reg, unsigned int val);
++      int (*reg_update_bits)(void *context, unsigned int reg,
++                             unsigned int mask, unsigned int val);
+       bool fast_io;
+-- 
+2.43.0
+
diff --git a/queue-5.4/selftests-mm-fix-map_hugetlb-failure-on-64k-page-siz.patch b/queue-5.4/selftests-mm-fix-map_hugetlb-failure-on-64k-page-siz.patch
new file mode 100644 (file)
index 0000000..3e02ca4
--- /dev/null
@@ -0,0 +1,61 @@
+From f3f9371cf2f034ed30820fe6668cdea470858ed1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 19 Jan 2024 06:14:29 -0700
+Subject: selftests: mm: fix map_hugetlb failure on 64K page size systems
+
+From: Nico Pache <npache@redhat.com>
+
+[ Upstream commit 91b80cc5b39f00399e8e2d17527cad2c7fa535e2 ]
+
+On systems with 64k page size and 512M huge page sizes, the allocation and
+test succeeds but errors out at the munmap.  As the comment states, munmap
+will failure if its not HUGEPAGE aligned.  This is due to the length of
+the mapping being 1/2 the size of the hugepage causing the munmap to not
+be hugepage aligned.  Fix this by making the mapping length the full
+hugepage if the hugepage is larger than the length of the mapping.
+
+Link: https://lkml.kernel.org/r/20240119131429.172448-1-npache@redhat.com
+Signed-off-by: Nico Pache <npache@redhat.com>
+Cc: Donet Tom <donettom@linux.vnet.ibm.com>
+Cc: Shuah Khan <shuah@kernel.org>
+Cc: Christophe Leroy <christophe.leroy@c-s.fr>
+Cc: Michael Ellerman <mpe@ellerman.id.au>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/testing/selftests/vm/map_hugetlb.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/tools/testing/selftests/vm/map_hugetlb.c b/tools/testing/selftests/vm/map_hugetlb.c
+index 312889edb84ab..c65c55b7a789f 100644
+--- a/tools/testing/selftests/vm/map_hugetlb.c
++++ b/tools/testing/selftests/vm/map_hugetlb.c
+@@ -15,6 +15,7 @@
+ #include <unistd.h>
+ #include <sys/mman.h>
+ #include <fcntl.h>
++#include "vm_util.h"
+ #define LENGTH (256UL*1024*1024)
+ #define PROTECTION (PROT_READ | PROT_WRITE)
+@@ -70,10 +71,16 @@ int main(int argc, char **argv)
+ {
+       void *addr;
+       int ret;
++      size_t hugepage_size;
+       size_t length = LENGTH;
+       int flags = FLAGS;
+       int shift = 0;
++      hugepage_size = default_huge_page_size();
++      /* munmap with fail if the length is not page aligned */
++      if (hugepage_size > length)
++              length = hugepage_size;
++
+       if (argc > 1)
+               length = atol(argv[1]) << 20;
+       if (argc > 2) {
+-- 
+2.43.0
+
diff --git a/queue-5.4/serial-max310x-fail-probe-if-clock-crystal-is-unstab.patch b/queue-5.4/serial-max310x-fail-probe-if-clock-crystal-is-unstab.patch
new file mode 100644 (file)
index 0000000..26c580d
--- /dev/null
@@ -0,0 +1,75 @@
+From e542be1e38a3d629ccc7dbc1322a7e59df70f243 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 16 Jan 2024 16:30:00 -0500
+Subject: serial: max310x: fail probe if clock crystal is unstable
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Hugo Villeneuve <hvilleneuve@dimonoff.com>
+
+[ Upstream commit 8afa6c6decea37e7cb473d2c60473f37f46cea35 ]
+
+A stable clock is really required in order to use this UART, so log an
+error message and bail out if the chip reports that the clock is not
+stable.
+
+Fixes: 4cf9a888fd3c ("serial: max310x: Check the clock readiness")
+Cc: stable@vger.kernel.org
+Suggested-by: Jan Kundrát <jan.kundrat@cesnet.cz>
+Link: https://www.spinics.net/lists/linux-serial/msg35773.html
+Signed-off-by: Hugo Villeneuve <hvilleneuve@dimonoff.com>
+Link: https://lore.kernel.org/r/20240116213001.3691629-4-hugo@hugovil.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/max310x.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
+index 0e0f778d75cd4..bbf45c0626681 100644
+--- a/drivers/tty/serial/max310x.c
++++ b/drivers/tty/serial/max310x.c
+@@ -556,7 +556,7 @@ static int max310x_update_best_err(unsigned long f, long *besterr)
+       return 1;
+ }
+-static u32 max310x_set_ref_clk(struct device *dev, struct max310x_port *s,
++static s32 max310x_set_ref_clk(struct device *dev, struct max310x_port *s,
+                              unsigned long freq, bool xtal)
+ {
+       unsigned int div, clksrc, pllcfg = 0;
+@@ -626,7 +626,8 @@ static u32 max310x_set_ref_clk(struct device *dev, struct max310x_port *s,
+               } while (!stable && (++try < MAX310X_XTAL_WAIT_RETRIES));
+               if (!stable)
+-                      dev_warn(dev, "clock is not stable yet\n");
++                      return dev_err_probe(dev, -EAGAIN,
++                                           "clock is not stable\n");
+       }
+       return bestfreq;
+@@ -1266,7 +1267,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
+ {
+       int i, ret, fmin, fmax, freq;
+       struct max310x_port *s;
+-      u32 uartclk = 0;
++      s32 uartclk = 0;
+       bool xtal;
+       if (IS_ERR(regmap))
+@@ -1350,6 +1351,11 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
+       }
+       uartclk = max310x_set_ref_clk(dev, s, freq, xtal);
++      if (uartclk < 0) {
++              ret = uartclk;
++              goto out_uart;
++      }
++
+       dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk);
+       for (i = 0; i < devtype->nr; i++) {
+-- 
+2.43.0
+
diff --git a/queue-5.4/serial-max310x-fix-io-data-corruption-in-batched-ope.patch b/queue-5.4/serial-max310x-fix-io-data-corruption-in-batched-ope.patch
new file mode 100644 (file)
index 0000000..5a90acb
--- /dev/null
@@ -0,0 +1,99 @@
+From d7faa29817ea3f45b730da93db62aab57b9e9f4b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Apr 2023 22:14:23 +0200
+Subject: serial: max310x: fix IO data corruption in batched operations
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Jan Kundrát <jan.kundrat@cesnet.cz>
+
+[ Upstream commit 3f42b142ea1171967e40e10e4b0241c0d6d28d41 ]
+
+After upgrading from 5.16 to 6.1, our board with a MAX14830 started
+producing lots of garbage data over UART. Bisection pointed out commit
+285e76fc049c as the culprit. That patch tried to replace hand-written
+code which I added in 2b4bac48c1084 ("serial: max310x: Use batched reads
+when reasonably safe") with the generic regmap infrastructure for
+batched operations.
+
+Unfortunately, the `regmap_raw_read` and `regmap_raw_write` which were
+used are actually functions which perform IO over *multiple* registers.
+That's not what is needed for accessing these Tx/Rx FIFOs; the
+appropriate functions are the `_noinc_` versions, not the `_raw_` ones.
+
+Fix this regression by using `regmap_noinc_read()` and
+`regmap_noinc_write()` along with the necessary `regmap_config` setup;
+with this patch in place, our board communicates happily again. Since
+our board uses SPI for talking to this chip, the I2C part is completely
+untested.
+
+Fixes: 285e76fc049c ("serial: max310x: use regmap methods for SPI batch operations")
+Cc: stable@vger.kernel.org
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Signed-off-by: Jan Kundrát <jan.kundrat@cesnet.cz>
+Link: https://lore.kernel.org/r/79db8e82aadb0e174bc82b9996423c3503c8fb37.1680732084.git.jan.kundrat@cesnet.cz
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/max310x.c | 17 +++++++++++++++--
+ 1 file changed, 15 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
+index ed1aaa19854fd..2f88eae8a55a1 100644
+--- a/drivers/tty/serial/max310x.c
++++ b/drivers/tty/serial/max310x.c
+@@ -533,6 +533,11 @@ static bool max310x_reg_precious(struct device *dev, unsigned int reg)
+       return false;
+ }
++static bool max310x_reg_noinc(struct device *dev, unsigned int reg)
++{
++      return reg == MAX310X_RHR_REG;
++}
++
+ static int max310x_set_baud(struct uart_port *port, int baud)
+ {
+       unsigned int mode = 0, div = 0, frac = 0, c = 0, F = 0;
+@@ -667,14 +672,14 @@ static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int
+ {
+       struct max310x_one *one = to_max310x_port(port);
+-      regmap_raw_write(one->regmap, MAX310X_THR_REG, txbuf, len);
++      regmap_noinc_write(one->regmap, MAX310X_THR_REG, txbuf, len);
+ }
+ static void max310x_batch_read(struct uart_port *port, u8 *rxbuf, unsigned int len)
+ {
+       struct max310x_one *one = to_max310x_port(port);
+-      regmap_raw_read(one->regmap, MAX310X_RHR_REG, rxbuf, len);
++      regmap_noinc_read(one->regmap, MAX310X_RHR_REG, rxbuf, len);
+ }
+ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
+@@ -1508,6 +1513,10 @@ static struct regmap_config regcfg = {
+       .writeable_reg = max310x_reg_writeable,
+       .volatile_reg = max310x_reg_volatile,
+       .precious_reg = max310x_reg_precious,
++      .writeable_noinc_reg = max310x_reg_noinc,
++      .readable_noinc_reg = max310x_reg_noinc,
++      .max_raw_read = MAX310X_FIFO_SIZE,
++      .max_raw_write = MAX310X_FIFO_SIZE,
+ };
+ #ifdef CONFIG_SPI_MASTER
+@@ -1593,6 +1602,10 @@ static struct regmap_config regcfg_i2c = {
+       .volatile_reg = max310x_reg_volatile,
+       .precious_reg = max310x_reg_precious,
+       .max_register = MAX310X_I2C_REVID_EXTREG,
++      .writeable_noinc_reg = max310x_reg_noinc,
++      .readable_noinc_reg = max310x_reg_noinc,
++      .max_raw_read = MAX310X_FIFO_SIZE,
++      .max_raw_write = MAX310X_FIFO_SIZE,
+ };
+ static const struct max310x_if_cfg max310x_i2c_if_cfg = {
+-- 
+2.43.0
+
diff --git a/queue-5.4/serial-max310x-implement-i2c-support.patch b/queue-5.4/serial-max310x-implement-i2c-support.patch
new file mode 100644 (file)
index 0000000..602d5ef
--- /dev/null
@@ -0,0 +1,270 @@
+From ce44f6e98f89dcb367521cd8df8d1f42847ed7e9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 5 Jun 2022 17:46:59 +0300
+Subject: serial: max310x: implement I2C support
+
+From: Cosmin Tanislav <cosmin.tanislav@analog.com>
+
+[ Upstream commit 2e1f2d9a9bdbe12ee475c82a45ac46a278e8049a ]
+
+I2C implementation on this chip has a few key differences
+compared to SPI, as described in previous patches.
+ * extended register space access needs no extra logic
+ * slave address is used to select which UART to communicate
+   with
+
+To accommodate these differences, add an I2C interface config,
+set the RevID register address and implement an empty method
+for setting the GlobalCommand register, since no special handling
+is needed for the extended register space.
+
+To handle the port-specific slave address, create an I2C dummy
+device for each port, except the base one (UART0), which is
+expected to be the one specified in firmware, and create a
+regmap for each I2C device.
+Add minimum and maximum slave addresses to each devtype for
+sanity checking.
+
+Also, use a separate regmap config with no write_flag_mask,
+since I2C has a R/W bit in its slave address, and set the
+max register to the address of the RevID register, since the
+extended register space needs no extra logic.
+
+Finally, add the I2C driver.
+
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Signed-off-by: Cosmin Tanislav <cosmin.tanislav@analog.com>
+Link: https://lore.kernel.org/r/20220605144659.4169853-5-demonsingur@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 3f42b142ea11 ("serial: max310x: fix IO data corruption in batched operations")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/Kconfig   |   1 +
+ drivers/tty/serial/max310x.c | 135 ++++++++++++++++++++++++++++++++++-
+ 2 files changed, 135 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
+index a9751a83d5dbb..def45baec28f8 100644
+--- a/drivers/tty/serial/Kconfig
++++ b/drivers/tty/serial/Kconfig
+@@ -354,6 +354,7 @@ config SERIAL_MAX310X
+       depends on SPI_MASTER
+       select SERIAL_CORE
+       select REGMAP_SPI if SPI_MASTER
++      select REGMAP_I2C if I2C
+       help
+         This selects support for an advanced UART from Maxim (Dallas).
+         Supported ICs are MAX3107, MAX3108, MAX3109, MAX14830.
+diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
+index b90281ac54c85..ed1aaa19854fd 100644
+--- a/drivers/tty/serial/max310x.c
++++ b/drivers/tty/serial/max310x.c
+@@ -14,6 +14,7 @@
+ #include <linux/delay.h>
+ #include <linux/device.h>
+ #include <linux/gpio/driver.h>
++#include <linux/i2c.h>
+ #include <linux/module.h>
+ #include <linux/mod_devicetable.h>
+ #include <linux/property.h>
+@@ -73,6 +74,7 @@
+ /* Extended registers */
+ #define MAX310X_SPI_REVID_EXTREG      MAX310X_REG_05 /* Revision ID */
++#define MAX310X_I2C_REVID_EXTREG      (0x25) /* Revision ID */
+ /* IRQ register bits */
+ #define MAX310X_IRQ_LSR_BIT           (1 << 0) /* LSR interrupt */
+@@ -260,6 +262,10 @@ struct max310x_if_cfg {
+ };
+ struct max310x_devtype {
++      struct {
++              unsigned short min;
++              unsigned short max;
++      } slave_addr;
+       char    name[9];
+       int     nr;
+       u8      mode1;
+@@ -431,6 +437,10 @@ static const struct max310x_devtype max3107_devtype = {
+       .mode1  = MAX310X_MODE1_AUTOSLEEP_BIT | MAX310X_MODE1_IRQSEL_BIT,
+       .detect = max3107_detect,
+       .power  = max310x_power,
++      .slave_addr     = {
++              .min = 0x2c,
++              .max = 0x2f,
++      },
+ };
+ static const struct max310x_devtype max3108_devtype = {
+@@ -439,6 +449,10 @@ static const struct max310x_devtype max3108_devtype = {
+       .mode1  = MAX310X_MODE1_AUTOSLEEP_BIT,
+       .detect = max3108_detect,
+       .power  = max310x_power,
++      .slave_addr     = {
++              .min = 0x60,
++              .max = 0x6f,
++      },
+ };
+ static const struct max310x_devtype max3109_devtype = {
+@@ -447,6 +461,10 @@ static const struct max310x_devtype max3109_devtype = {
+       .mode1  = MAX310X_MODE1_AUTOSLEEP_BIT,
+       .detect = max3109_detect,
+       .power  = max310x_power,
++      .slave_addr     = {
++              .min = 0x60,
++              .max = 0x6f,
++      },
+ };
+ static const struct max310x_devtype max14830_devtype = {
+@@ -455,6 +473,10 @@ static const struct max310x_devtype max14830_devtype = {
+       .mode1  = MAX310X_MODE1_IRQSEL_BIT,
+       .detect = max14830_detect,
+       .power  = max14830_power,
++      .slave_addr     = {
++              .min = 0x60,
++              .max = 0x6f,
++      },
+ };
+ static bool max310x_reg_writeable(struct device *dev, unsigned int reg)
+@@ -1557,6 +1579,97 @@ static struct spi_driver max310x_spi_driver = {
+ };
+ #endif
++#ifdef CONFIG_I2C
++static int max310x_i2c_extended_reg_enable(struct device *dev, bool enable)
++{
++      return 0;
++}
++
++static struct regmap_config regcfg_i2c = {
++      .reg_bits = 8,
++      .val_bits = 8,
++      .cache_type = REGCACHE_RBTREE,
++      .writeable_reg = max310x_reg_writeable,
++      .volatile_reg = max310x_reg_volatile,
++      .precious_reg = max310x_reg_precious,
++      .max_register = MAX310X_I2C_REVID_EXTREG,
++};
++
++static const struct max310x_if_cfg max310x_i2c_if_cfg = {
++      .extended_reg_enable = max310x_i2c_extended_reg_enable,
++      .rev_id_reg = MAX310X_I2C_REVID_EXTREG,
++};
++
++static unsigned short max310x_i2c_slave_addr(unsigned short addr,
++                                           unsigned int nr)
++{
++      /*
++       * For MAX14830 and MAX3109, the slave address depends on what the
++       * A0 and A1 pins are tied to.
++       * See Table I2C Address Map of the datasheet.
++       * Based on that table, the following formulas were determined.
++       * UART1 - UART0 = 0x10
++       * UART2 - UART1 = 0x20 + 0x10
++       * UART3 - UART2 = 0x10
++       */
++
++      addr -= nr * 0x10;
++
++      if (nr >= 2)
++              addr -= 0x20;
++
++      return addr;
++}
++
++static int max310x_i2c_probe(struct i2c_client *client)
++{
++      const struct max310x_devtype *devtype =
++                      device_get_match_data(&client->dev);
++      struct i2c_client *port_client;
++      struct regmap *regmaps[4];
++      unsigned int i;
++      u8 port_addr;
++
++      if (client->addr < devtype->slave_addr.min ||
++              client->addr > devtype->slave_addr.max)
++              return dev_err_probe(&client->dev, -EINVAL,
++                                   "Slave addr 0x%x outside of range [0x%x, 0x%x]\n",
++                                   client->addr, devtype->slave_addr.min,
++                                   devtype->slave_addr.max);
++
++      regmaps[0] = devm_regmap_init_i2c(client, &regcfg_i2c);
++
++      for (i = 1; i < devtype->nr; i++) {
++              port_addr = max310x_i2c_slave_addr(client->addr, i);
++              port_client = devm_i2c_new_dummy_device(&client->dev,
++                                                      client->adapter,
++                                                      port_addr);
++
++              regmaps[i] = devm_regmap_init_i2c(port_client, &regcfg_i2c);
++      }
++
++      return max310x_probe(&client->dev, devtype, &max310x_i2c_if_cfg,
++                           regmaps, client->irq);
++}
++
++static int max310x_i2c_remove(struct i2c_client *client)
++{
++      max310x_remove(&client->dev);
++
++      return 0;
++}
++
++static struct i2c_driver max310x_i2c_driver = {
++      .driver = {
++              .name           = MAX310X_NAME,
++              .of_match_table = max310x_dt_ids,
++              .pm             = &max310x_pm_ops,
++      },
++      .probe_new      = max310x_i2c_probe,
++      .remove         = max310x_i2c_remove,
++};
++#endif
++
+ static int __init max310x_uart_init(void)
+ {
+       int ret;
+@@ -1570,15 +1683,35 @@ static int __init max310x_uart_init(void)
+ #ifdef CONFIG_SPI_MASTER
+       ret = spi_register_driver(&max310x_spi_driver);
+       if (ret)
+-              uart_unregister_driver(&max310x_uart);
++              goto err_spi_register;
++#endif
++
++#ifdef CONFIG_I2C
++      ret = i2c_add_driver(&max310x_i2c_driver);
++      if (ret)
++              goto err_i2c_register;
+ #endif
++      return 0;
++
++#ifdef CONFIG_I2C
++err_i2c_register:
++      spi_unregister_driver(&max310x_spi_driver);
++#endif
++
++err_spi_register:
++      uart_unregister_driver(&max310x_uart);
++
+       return ret;
+ }
+ module_init(max310x_uart_init);
+ static void __exit max310x_uart_exit(void)
+ {
++#ifdef CONFIG_I2C
++      i2c_del_driver(&max310x_i2c_driver);
++#endif
++
+ #ifdef CONFIG_SPI_MASTER
+       spi_unregister_driver(&max310x_spi_driver);
+ #endif
+-- 
+2.43.0
+
diff --git a/queue-5.4/serial-max310x-make-accessing-revision-id-interface-.patch b/queue-5.4/serial-max310x-make-accessing-revision-id-interface-.patch
new file mode 100644 (file)
index 0000000..8218082
--- /dev/null
@@ -0,0 +1,157 @@
+From f628946031c9456db1a1d2f4df172ce9e7486ce1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 5 Jun 2022 17:46:58 +0300
+Subject: serial: max310x: make accessing revision id interface-agnostic
+
+From: Cosmin Tanislav <cosmin.tanislav@analog.com>
+
+[ Upstream commit b3883ab5e95713e479f774ea68be275413e8e5b2 ]
+
+SPI can only use 5 address bits, since one bit is reserved for
+specifying R/W and 2 bits are used to specify the UART port.
+To access registers that have addresses past 0x1F, an extended
+register space can be enabled by writing to the GlobalCommand
+register (address 0x1F).
+
+I2C uses 8 address bits. The R/W bit is placed in the slave
+address, and so is the UART port. Because of this, registers
+that have addresses higher than 0x1F can be accessed normally.
+
+To access the RevID register, on SPI, 0xCE must be written to
+the 0x1F address to enable the extended register space, after
+which the RevID register is accessible at address 0x5. 0xCD
+must be written to the 0x1F address to disable the extended
+register space.
+
+On I2C, the RevID register is accessible at address 0x25.
+
+Create an interface config struct, and add a method for
+toggling the extended register space and a member for the RevId
+register address. Implement these for SPI.
+
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Signed-off-by: Cosmin Tanislav <cosmin.tanislav@analog.com>
+Link: https://lore.kernel.org/r/20220605144659.4169853-4-demonsingur@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 3f42b142ea11 ("serial: max310x: fix IO data corruption in batched operations")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/max310x.c | 40 +++++++++++++++++++++++++++---------
+ 1 file changed, 30 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
+index a09ec46e0310d..b90281ac54c85 100644
+--- a/drivers/tty/serial/max310x.c
++++ b/drivers/tty/serial/max310x.c
+@@ -72,7 +72,7 @@
+ #define MAX310X_GLOBALCMD_REG         MAX310X_REG_1F /* Global Command (WO) */
+ /* Extended registers */
+-#define MAX310X_REVID_EXTREG          MAX310X_REG_05 /* Revision ID */
++#define MAX310X_SPI_REVID_EXTREG      MAX310X_REG_05 /* Revision ID */
+ /* IRQ register bits */
+ #define MAX310X_IRQ_LSR_BIT           (1 << 0) /* LSR interrupt */
+@@ -253,6 +253,12 @@
+ #define MAX14830_BRGCFG_CLKDIS_BIT    (1 << 6) /* Clock Disable */
+ #define MAX14830_REV_ID                       (0xb0)
++struct max310x_if_cfg {
++      int (*extended_reg_enable)(struct device *dev, bool enable);
++
++      unsigned int rev_id_reg;
++};
++
+ struct max310x_devtype {
+       char    name[9];
+       int     nr;
+@@ -275,6 +281,7 @@ struct max310x_one {
+ struct max310x_port {
+       const struct max310x_devtype *devtype;
++      const struct max310x_if_cfg *if_cfg;
+       struct regmap           *regmap;
+       struct clk              *clk;
+ #ifdef CONFIG_GPIOLIB
+@@ -364,13 +371,12 @@ static int max3109_detect(struct device *dev)
+       unsigned int val = 0;
+       int ret;
+-      ret = regmap_write(s->regmap, MAX310X_GLOBALCMD_REG,
+-                         MAX310X_EXTREG_ENBL);
++      ret = s->if_cfg->extended_reg_enable(dev, true);
+       if (ret)
+               return ret;
+-      regmap_read(s->regmap, MAX310X_REVID_EXTREG, &val);
+-      regmap_write(s->regmap, MAX310X_GLOBALCMD_REG, MAX310X_EXTREG_DSBL);
++      regmap_read(s->regmap, s->if_cfg->rev_id_reg, &val);
++      s->if_cfg->extended_reg_enable(dev, false);
+       if (((val & MAX310x_REV_MASK) != MAX3109_REV_ID)) {
+               dev_err(dev,
+                       "%s ID 0x%02x does not match\n", s->devtype->name, val);
+@@ -395,13 +401,12 @@ static int max14830_detect(struct device *dev)
+       unsigned int val = 0;
+       int ret;
+-      ret = regmap_write(s->regmap, MAX310X_GLOBALCMD_REG,
+-                         MAX310X_EXTREG_ENBL);
++      ret = s->if_cfg->extended_reg_enable(dev, true);
+       if (ret)
+               return ret;
+       
+-      regmap_read(s->regmap, MAX310X_REVID_EXTREG, &val);
+-      regmap_write(s->regmap, MAX310X_GLOBALCMD_REG, MAX310X_EXTREG_DSBL);
++      regmap_read(s->regmap, s->if_cfg->rev_id_reg, &val);
++      s->if_cfg->extended_reg_enable(dev, false);
+       if (((val & MAX310x_REV_MASK) != MAX14830_REV_ID)) {
+               dev_err(dev,
+                       "%s ID 0x%02x does not match\n", s->devtype->name, val);
+@@ -1250,6 +1255,7 @@ static int max310x_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+ #endif
+ static int max310x_probe(struct device *dev, const struct max310x_devtype *devtype,
++                       const struct max310x_if_cfg *if_cfg,
+                        struct regmap *regmaps[], int irq)
+ {
+       int i, ret, fmin, fmax, freq;
+@@ -1313,6 +1319,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
+       s->regmap = regmaps[0];
+       s->devtype = devtype;
++      s->if_cfg = if_cfg;
+       dev_set_drvdata(dev, s);
+       /* Check device to ensure we are talking to what we expect */
+@@ -1482,6 +1489,19 @@ static struct regmap_config regcfg = {
+ };
+ #ifdef CONFIG_SPI_MASTER
++static int max310x_spi_extended_reg_enable(struct device *dev, bool enable)
++{
++      struct max310x_port *s = dev_get_drvdata(dev);
++
++      return regmap_write(s->regmap, MAX310X_GLOBALCMD_REG,
++                          enable ? MAX310X_EXTREG_ENBL : MAX310X_EXTREG_DSBL);
++}
++
++static const struct max310x_if_cfg __maybe_unused max310x_spi_if_cfg = {
++      .extended_reg_enable = max310x_spi_extended_reg_enable,
++      .rev_id_reg = MAX310X_SPI_REVID_EXTREG,
++};
++
+ static int max310x_spi_probe(struct spi_device *spi)
+ {
+       const struct max310x_devtype *devtype;
+@@ -1508,7 +1528,7 @@ static int max310x_spi_probe(struct spi_device *spi)
+               regmaps[i] = devm_regmap_init_spi(spi, &regcfg);
+       }
+-      return max310x_probe(&spi->dev, devtype, regmaps, spi->irq);
++      return max310x_probe(&spi->dev, devtype, &max310x_spi_if_cfg, regmaps, spi->irq);
+ }
+ static int max310x_spi_remove(struct spi_device *spi)
+-- 
+2.43.0
+
diff --git a/queue-5.4/serial-max310x-make-use-of-device-properties.patch b/queue-5.4/serial-max310x-make-use-of-device-properties.patch
new file mode 100644 (file)
index 0000000..6d2688a
--- /dev/null
@@ -0,0 +1,97 @@
+From 42c6a6b7bb0caada01334af98ab3386e6f8451a2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 7 Oct 2020 11:46:34 +0300
+Subject: serial: max310x: Make use of device properties
+
+From: Andy Shevchenko <andy.shevchenko@gmail.com>
+
+[ Upstream commit c808fab604ca62cff19ee6b261211483830807aa ]
+
+Device property API allows to gather device resources from different sources,
+such as ACPI. Convert the drivers to unleash the power of device property API.
+
+Signed-off-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Link: https://lore.kernel.org/r/20201007084635.594991-1-andy.shevchenko@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: b35f8dbbce81 ("serial: max310x: prevent infinite while() loop in port startup")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/max310x.c | 27 +++++++++------------------
+ 1 file changed, 9 insertions(+), 18 deletions(-)
+
+diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
+index bbf45c0626681..8d42c537ee5ea 100644
+--- a/drivers/tty/serial/max310x.c
++++ b/drivers/tty/serial/max310x.c
+@@ -15,8 +15,8 @@
+ #include <linux/device.h>
+ #include <linux/gpio/driver.h>
+ #include <linux/module.h>
+-#include <linux/of.h>
+-#include <linux/of_device.h>
++#include <linux/mod_devicetable.h>
++#include <linux/property.h>
+ #include <linux/regmap.h>
+ #include <linux/serial_core.h>
+ #include <linux/serial.h>
+@@ -271,7 +271,7 @@ struct max310x_one {
+       container_of(_port, struct max310x_one, port)
+ struct max310x_port {
+-      struct max310x_devtype  *devtype;
++      const struct max310x_devtype *devtype;
+       struct regmap           *regmap;
+       struct clk              *clk;
+ #ifdef CONFIG_GPIOLIB
+@@ -1262,7 +1262,7 @@ static int max310x_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+ }
+ #endif
+-static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
++static int max310x_probe(struct device *dev, const struct max310x_devtype *devtype,
+                        struct regmap *regmap, int irq)
+ {
+       int i, ret, fmin, fmax, freq;
+@@ -1488,7 +1488,7 @@ static struct regmap_config regcfg = {
+ #ifdef CONFIG_SPI_MASTER
+ static int max310x_spi_probe(struct spi_device *spi)
+ {
+-      struct max310x_devtype *devtype;
++      const struct max310x_devtype *devtype;
+       struct regmap *regmap;
+       int ret;
+@@ -1500,18 +1500,9 @@ static int max310x_spi_probe(struct spi_device *spi)
+       if (ret)
+               return ret;
+-      if (spi->dev.of_node) {
+-              const struct of_device_id *of_id =
+-                      of_match_device(max310x_dt_ids, &spi->dev);
+-              if (!of_id)
+-                      return -ENODEV;
+-
+-              devtype = (struct max310x_devtype *)of_id->data;
+-      } else {
+-              const struct spi_device_id *id_entry = spi_get_device_id(spi);
+-
+-              devtype = (struct max310x_devtype *)id_entry->driver_data;
+-      }
++      devtype = device_get_match_data(&spi->dev);
++      if (!devtype)
++              devtype = (struct max310x_devtype *)spi_get_device_id(spi)->driver_data;
+       regcfg.max_register = devtype->nr * 0x20 - 1;
+       regmap = devm_regmap_init_spi(spi, &regcfg);
+@@ -1536,7 +1527,7 @@ MODULE_DEVICE_TABLE(spi, max310x_id_table);
+ static struct spi_driver max310x_spi_driver = {
+       .driver = {
+               .name           = MAX310X_NAME,
+-              .of_match_table = of_match_ptr(max310x_dt_ids),
++              .of_match_table = max310x_dt_ids,
+               .pm             = &max310x_pm_ops,
+       },
+       .probe          = max310x_spi_probe,
+-- 
+2.43.0
+
diff --git a/queue-5.4/serial-max310x-prevent-infinite-while-loop-in-port-s.patch b/queue-5.4/serial-max310x-prevent-infinite-while-loop-in-port-s.patch
new file mode 100644 (file)
index 0000000..1670435
--- /dev/null
@@ -0,0 +1,76 @@
+From 75e06784237bda9c93318d2b291801fda5dbdc6a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 16 Jan 2024 16:30:01 -0500
+Subject: serial: max310x: prevent infinite while() loop in port startup
+
+From: Hugo Villeneuve <hvilleneuve@dimonoff.com>
+
+[ Upstream commit b35f8dbbce818b02c730dc85133dc7754266e084 ]
+
+If there is a problem after resetting a port, the do/while() loop that
+checks the default value of DIVLSB register may run forever and spam the
+I2C bus.
+
+Add a delay before each read of DIVLSB, and a maximum number of tries to
+prevent that situation from happening.
+
+Also fail probe if port reset is unsuccessful.
+
+Fixes: 10d8b34a4217 ("serial: max310x: Driver rework")
+Cc: stable@vger.kernel.org
+Signed-off-by: Hugo Villeneuve <hvilleneuve@dimonoff.com>
+Link: https://lore.kernel.org/r/20240116213001.3691629-5-hugo@hugovil.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/max310x.c | 20 ++++++++++++++++++--
+ 1 file changed, 18 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
+index 80298a5714bcb..978d9d93127e5 100644
+--- a/drivers/tty/serial/max310x.c
++++ b/drivers/tty/serial/max310x.c
+@@ -235,6 +235,10 @@
+ #define MAX310x_REV_MASK              (0xf8)
+ #define MAX310X_WRITE_BIT             0x80
++/* Port startup definitions */
++#define MAX310X_PORT_STARTUP_WAIT_RETRIES     20 /* Number of retries */
++#define MAX310X_PORT_STARTUP_WAIT_DELAY_MS    10 /* Delay between retries */
++
+ /* Crystal-related definitions */
+ #define MAX310X_XTAL_WAIT_RETRIES     20 /* Number of retries */
+ #define MAX310X_XTAL_WAIT_DELAY_MS    10 /* Delay between retries */
+@@ -1316,6 +1320,9 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
+               goto out_clk;
+       for (i = 0; i < devtype->nr; i++) {
++              bool started = false;
++              unsigned int try = 0, val = 0;
++
+               /* Reset port */
+               regmap_write(regmaps[i], MAX310X_MODE2_REG,
+                            MAX310X_MODE2_RST_BIT);
+@@ -1324,8 +1331,17 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
+               /* Wait for port startup */
+               do {
+-                      regmap_read(regmaps[i], MAX310X_BRGDIVLSB_REG, &ret);
+-              } while (ret != 0x01);
++                      msleep(MAX310X_PORT_STARTUP_WAIT_DELAY_MS);
++                      regmap_read(regmaps[i], MAX310X_BRGDIVLSB_REG, &val);
++
++                      if (val == 0x01)
++                              started = true;
++              } while (!started && (++try < MAX310X_PORT_STARTUP_WAIT_RETRIES));
++
++              if (!started) {
++                      ret = dev_err_probe(dev, -EAGAIN, "port reset failed\n");
++                      goto out_uart;
++              }
+               regmap_write(regmaps[i], MAX310X_MODE1_REG, devtype->mode1);
+       }
+-- 
+2.43.0
+
diff --git a/queue-5.4/serial-max310x-try-to-get-crystal-clock-rate-from-pr.patch b/queue-5.4/serial-max310x-try-to-get-crystal-clock-rate-from-pr.patch
new file mode 100644 (file)
index 0000000..aeefcc8
--- /dev/null
@@ -0,0 +1,113 @@
+From c8f40c24cc6ed198202f32af1eb395087de90936 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 May 2021 20:29:30 +0300
+Subject: serial: max310x: Try to get crystal clock rate from property
+
+From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+
+[ Upstream commit d4d6f03c4fb3a91dadfe147b47edd40e4d7e4d36 ]
+
+In some configurations, mainly ACPI-based, the clock frequency of the device
+is supplied by very well established 'clock-frequency' property. Hence, try
+to get it from the property at last if no other providers are available.
+
+Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Link: https://lore.kernel.org/r/20210517172930.83353-1-andriy.shevchenko@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 8afa6c6decea ("serial: max310x: fail probe if clock crystal is unstable")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/max310x.c | 40 +++++++++++++++++++++++-------------
+ 1 file changed, 26 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
+index 8bf3c5ab59431..0e0f778d75cd4 100644
+--- a/drivers/tty/serial/max310x.c
++++ b/drivers/tty/serial/max310x.c
+@@ -556,7 +556,7 @@ static int max310x_update_best_err(unsigned long f, long *besterr)
+       return 1;
+ }
+-static int max310x_set_ref_clk(struct device *dev, struct max310x_port *s,
++static u32 max310x_set_ref_clk(struct device *dev, struct max310x_port *s,
+                              unsigned long freq, bool xtal)
+ {
+       unsigned int div, clksrc, pllcfg = 0;
+@@ -629,7 +629,7 @@ static int max310x_set_ref_clk(struct device *dev, struct max310x_port *s,
+                       dev_warn(dev, "clock is not stable yet\n");
+       }
+-      return (int)bestfreq;
++      return bestfreq;
+ }
+ static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int len)
+@@ -1264,9 +1264,10 @@ static int max310x_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
+                        struct regmap *regmap, int irq)
+ {
+-      int i, ret, fmin, fmax, freq, uartclk;
++      int i, ret, fmin, fmax, freq;
+       struct max310x_port *s;
+-      bool xtal = false;
++      u32 uartclk = 0;
++      bool xtal;
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+@@ -1278,24 +1279,20 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
+               return -ENOMEM;
+       }
++      /* Always ask for fixed clock rate from a property. */
++      device_property_read_u32(dev, "clock-frequency", &uartclk);
++
+       s->clk = devm_clk_get_optional(dev, "osc");
+       if (IS_ERR(s->clk))
+               return PTR_ERR(s->clk);
+       if (s->clk) {
+-              fmin = 500000;
+-              fmax = 35000000;
++              xtal = false;
+       } else {
+               s->clk = devm_clk_get_optional(dev, "xtal");
+               if (IS_ERR(s->clk))
+                       return PTR_ERR(s->clk);
+-              if (s->clk) {
+-                      fmin = 1000000;
+-                      fmax = 4000000;
+-                      xtal = true;
+-              } else {
+-                      dev_err(dev, "Cannot get clock\n");
+-                      return -EINVAL;
+-              }
++
++              xtal = true;
+       }
+       ret = clk_prepare_enable(s->clk);
+@@ -1303,6 +1300,21 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
+               return ret;
+       freq = clk_get_rate(s->clk);
++      if (freq == 0)
++              freq = uartclk;
++      if (freq == 0) {
++              dev_err(dev, "Cannot get clock rate\n");
++              return -EINVAL;
++      }
++
++      if (xtal) {
++              fmin = 1000000;
++              fmax = 4000000;
++      } else {
++              fmin = 500000;
++              fmax = 35000000;
++      }
++
+       /* Check frequency limits */
+       if (freq < fmin || freq > fmax) {
+               ret = -ERANGE;
+-- 
+2.43.0
+
diff --git a/queue-5.4/serial-max310x-unprepare-and-disable-clock-in-error-.patch b/queue-5.4/serial-max310x-unprepare-and-disable-clock-in-error-.patch
new file mode 100644 (file)
index 0000000..8d8c7ed
--- /dev/null
@@ -0,0 +1,40 @@
+From 540ef3422d7c8b78f5c8f628e07ea8d0fc2687ac Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 25 Jun 2021 18:37:33 +0300
+Subject: serial: max310x: Unprepare and disable clock in error path
+
+From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+
+[ Upstream commit 61acabaae5ba58b3c32e6e90d24c2c0827fd27a8 ]
+
+In one error case the clock may be left prepared and enabled.
+Unprepare and disable clock in that case to balance state of
+the hardware.
+
+Fixes: d4d6f03c4fb3 ("serial: max310x: Try to get crystal clock rate from property")
+Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
+Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Link: https://lore.kernel.org/r/20210625153733.12911-1-andriy.shevchenko@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/max310x.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
+index 978d9d93127e5..a09ec46e0310d 100644
+--- a/drivers/tty/serial/max310x.c
++++ b/drivers/tty/serial/max310x.c
+@@ -1293,7 +1293,8 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
+               freq = uartclk;
+       if (freq == 0) {
+               dev_err(dev, "Cannot get clock rate\n");
+-              return -EINVAL;
++              ret = -EINVAL;
++              goto out_clk;
+       }
+       if (xtal) {
+-- 
+2.43.0
+
diff --git a/queue-5.4/serial-max310x-use-a-separate-regmap-for-each-port.patch b/queue-5.4/serial-max310x-use-a-separate-regmap-for-each-port.patch
new file mode 100644 (file)
index 0000000..8f1452e
--- /dev/null
@@ -0,0 +1,243 @@
+From 2b22639ab2198e802bce2d213ac11c3a9ef69a54 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 5 Jun 2022 17:46:57 +0300
+Subject: serial: max310x: use a separate regmap for each port
+
+From: Cosmin Tanislav <cosmin.tanislav@analog.com>
+
+[ Upstream commit 6ef281daf020592c219fa91780abc381c6c20db5 ]
+
+The driver currently does manual register manipulation in
+multiple places to talk to a specific UART port.
+
+In order to talk to a specific UART port over SPI, the bits U1
+and U0 of the register address can be set, as explained in the
+Command byte configuration section of the datasheet.
+
+Make this more elegant by creating regmaps for each UART port
+and setting the read_flag_mask and write_flag_mask
+accordingly.
+
+All communcations regarding global registers are done on UART
+port 0, so replace the global regmap entirely with the port 0
+regmap.
+
+Also, remove the 0x1f masks from reg_writeable(), reg_volatile()
+and reg_precious() methods, since setting the U1 and U0 bits of
+the register address happens inside the regmap core now.
+
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Signed-off-by: Cosmin Tanislav <cosmin.tanislav@analog.com>
+Link: https://lore.kernel.org/r/20220605144659.4169853-3-demonsingur@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: b35f8dbbce81 ("serial: max310x: prevent infinite while() loop in port startup")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/max310x.c | 68 +++++++++++++++++++-----------------
+ 1 file changed, 36 insertions(+), 32 deletions(-)
+
+diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
+index c0fa4ad104774..80298a5714bcb 100644
+--- a/drivers/tty/serial/max310x.c
++++ b/drivers/tty/serial/max310x.c
+@@ -262,6 +262,7 @@ struct max310x_one {
+       struct work_struct      tx_work;
+       struct work_struct      md_work;
+       struct work_struct      rs_work;
++      struct regmap           *regmap;
+       u8 rx_buf[MAX310X_FIFO_SIZE];
+ };
+@@ -291,26 +292,26 @@ static DECLARE_BITMAP(max310x_lines, MAX310X_UART_NRMAX);
+ static u8 max310x_port_read(struct uart_port *port, u8 reg)
+ {
+-      struct max310x_port *s = dev_get_drvdata(port->dev);
++      struct max310x_one *one = to_max310x_port(port);
+       unsigned int val = 0;
+-      regmap_read(s->regmap, port->iobase + reg, &val);
++      regmap_read(one->regmap, reg, &val);
+       return val;
+ }
+ static void max310x_port_write(struct uart_port *port, u8 reg, u8 val)
+ {
+-      struct max310x_port *s = dev_get_drvdata(port->dev);
++      struct max310x_one *one = to_max310x_port(port);
+-      regmap_write(s->regmap, port->iobase + reg, val);
++      regmap_write(one->regmap, reg, val);
+ }
+ static void max310x_port_update(struct uart_port *port, u8 reg, u8 mask, u8 val)
+ {
+-      struct max310x_port *s = dev_get_drvdata(port->dev);
++      struct max310x_one *one = to_max310x_port(port);
+-      regmap_update_bits(s->regmap, port->iobase + reg, mask, val);
++      regmap_update_bits(one->regmap, reg, mask, val);
+ }
+ static int max3107_detect(struct device *dev)
+@@ -449,7 +450,7 @@ static const struct max310x_devtype max14830_devtype = {
+ static bool max310x_reg_writeable(struct device *dev, unsigned int reg)
+ {
+-      switch (reg & 0x1f) {
++      switch (reg) {
+       case MAX310X_IRQSTS_REG:
+       case MAX310X_LSR_IRQSTS_REG:
+       case MAX310X_SPCHR_IRQSTS_REG:
+@@ -466,7 +467,7 @@ static bool max310x_reg_writeable(struct device *dev, unsigned int reg)
+ static bool max310x_reg_volatile(struct device *dev, unsigned int reg)
+ {
+-      switch (reg & 0x1f) {
++      switch (reg) {
+       case MAX310X_RHR_REG:
+       case MAX310X_IRQSTS_REG:
+       case MAX310X_LSR_IRQSTS_REG:
+@@ -488,7 +489,7 @@ static bool max310x_reg_volatile(struct device *dev, unsigned int reg)
+ static bool max310x_reg_precious(struct device *dev, unsigned int reg)
+ {
+-      switch (reg & 0x1f) {
++      switch (reg) {
+       case MAX310X_RHR_REG:
+       case MAX310X_IRQSTS_REG:
+       case MAX310X_SPCHR_IRQSTS_REG:
+@@ -633,18 +634,16 @@ static s32 max310x_set_ref_clk(struct device *dev, struct max310x_port *s,
+ static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int len)
+ {
+-      struct max310x_port *s = dev_get_drvdata(port->dev);
+-      u8 reg = port->iobase + MAX310X_THR_REG;
++      struct max310x_one *one = to_max310x_port(port);
+-      regmap_raw_write(s->regmap, reg, txbuf, len);
++      regmap_raw_write(one->regmap, MAX310X_THR_REG, txbuf, len);
+ }
+ static void max310x_batch_read(struct uart_port *port, u8 *rxbuf, unsigned int len)
+ {
+-      struct max310x_port *s = dev_get_drvdata(port->dev);
+-      u8 reg = port->iobase + MAX310X_RHR_REG;
++      struct max310x_one *one = to_max310x_port(port);
+-      regmap_raw_read(s->regmap, reg, rxbuf, len);
++      regmap_raw_read(one->regmap, MAX310X_RHR_REG, rxbuf, len);
+ }
+ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
+@@ -1247,15 +1246,16 @@ static int max310x_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+ #endif
+ static int max310x_probe(struct device *dev, const struct max310x_devtype *devtype,
+-                       struct regmap *regmap, int irq)
++                       struct regmap *regmaps[], int irq)
+ {
+       int i, ret, fmin, fmax, freq;
+       struct max310x_port *s;
+       s32 uartclk = 0;
+       bool xtal;
+-      if (IS_ERR(regmap))
+-              return PTR_ERR(regmap);
++      for (i = 0; i < devtype->nr; i++)
++              if (IS_ERR(regmaps[i]))
++                      return PTR_ERR(regmaps[i]);
+       /* Alloc port structure */
+       s = devm_kzalloc(dev, struct_size(s, p, devtype->nr), GFP_KERNEL);
+@@ -1306,7 +1306,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
+               goto out_clk;
+       }
+-      s->regmap = regmap;
++      s->regmap = regmaps[0];
+       s->devtype = devtype;
+       dev_set_drvdata(dev, s);
+@@ -1316,22 +1316,18 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
+               goto out_clk;
+       for (i = 0; i < devtype->nr; i++) {
+-              unsigned int offs = i << 5;
+-
+               /* Reset port */
+-              regmap_write(s->regmap, MAX310X_MODE2_REG + offs,
++              regmap_write(regmaps[i], MAX310X_MODE2_REG,
+                            MAX310X_MODE2_RST_BIT);
+               /* Clear port reset */
+-              regmap_write(s->regmap, MAX310X_MODE2_REG + offs, 0);
++              regmap_write(regmaps[i], MAX310X_MODE2_REG, 0);
+               /* Wait for port startup */
+               do {
+-                      regmap_read(s->regmap,
+-                                  MAX310X_BRGDIVLSB_REG + offs, &ret);
++                      regmap_read(regmaps[i], MAX310X_BRGDIVLSB_REG, &ret);
+               } while (ret != 0x01);
+-              regmap_write(s->regmap, MAX310X_MODE1_REG + offs,
+-                           devtype->mode1);
++              regmap_write(regmaps[i], MAX310X_MODE1_REG, devtype->mode1);
+       }
+       uartclk = max310x_set_ref_clk(dev, s, freq, xtal);
+@@ -1359,11 +1355,13 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
+               s->p[i].port.fifosize   = MAX310X_FIFO_SIZE;
+               s->p[i].port.flags      = UPF_FIXED_TYPE | UPF_LOW_LATENCY;
+               s->p[i].port.iotype     = UPIO_PORT;
+-              s->p[i].port.iobase     = i * 0x20;
++              s->p[i].port.iobase     = i;
+               s->p[i].port.membase    = (void __iomem *)~0;
+               s->p[i].port.uartclk    = uartclk;
+               s->p[i].port.rs485_config = max310x_rs485_config;
+               s->p[i].port.ops        = &max310x_ops;
++              s->p[i].regmap          = regmaps[i];
++
+               /* Disable all interrupts */
+               max310x_port_write(&s->p[i].port, MAX310X_IRQEN_REG, 0);
+               /* Clear IRQ status register */
+@@ -1460,6 +1458,7 @@ static struct regmap_config regcfg = {
+       .val_bits = 8,
+       .write_flag_mask = MAX310X_WRITE_BIT,
+       .cache_type = REGCACHE_RBTREE,
++      .max_register = MAX310X_REG_1F,
+       .writeable_reg = max310x_reg_writeable,
+       .volatile_reg = max310x_reg_volatile,
+       .precious_reg = max310x_reg_precious,
+@@ -1469,7 +1468,8 @@ static struct regmap_config regcfg = {
+ static int max310x_spi_probe(struct spi_device *spi)
+ {
+       const struct max310x_devtype *devtype;
+-      struct regmap *regmap;
++      struct regmap *regmaps[4];
++      unsigned int i;
+       int ret;
+       /* Setup SPI bus */
+@@ -1484,10 +1484,14 @@ static int max310x_spi_probe(struct spi_device *spi)
+       if (!devtype)
+               devtype = (struct max310x_devtype *)spi_get_device_id(spi)->driver_data;
+-      regcfg.max_register = devtype->nr * 0x20 - 1;
+-      regmap = devm_regmap_init_spi(spi, &regcfg);
++      for (i = 0; i < devtype->nr; i++) {
++              u8 port_mask = i * 0x20;
++              regcfg.read_flag_mask = port_mask;
++              regcfg.write_flag_mask = port_mask | MAX310X_WRITE_BIT;
++              regmaps[i] = devm_regmap_init_spi(spi, &regcfg);
++      }
+-      return max310x_probe(&spi->dev, devtype, regmap, spi->irq);
++      return max310x_probe(&spi->dev, devtype, regmaps, spi->irq);
+ }
+ static int max310x_spi_remove(struct spi_device *spi)
+-- 
+2.43.0
+
diff --git a/queue-5.4/serial-max310x-use-devm_clk_get_optional-to-get-the-.patch b/queue-5.4/serial-max310x-use-devm_clk_get_optional-to-get-the-.patch
new file mode 100644 (file)
index 0000000..d9ae97b
--- /dev/null
@@ -0,0 +1,77 @@
+From e1028af9d83efd88d3e0edd666d1b874945d446c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 7 Oct 2020 11:46:35 +0300
+Subject: serial: max310x: Use devm_clk_get_optional() to get the input clock
+
+From: Andy Shevchenko <andy.shevchenko@gmail.com>
+
+[ Upstream commit 974e454d6f96da0c0ab1b4115b92587dd9406f6a ]
+
+Simplify the code which fetches the input clock by using
+devm_clk_get_optional(). If no input clock is present
+devm_clk_get_optional() will return NULL instead of an error
+which matches the behavior of the old code.
+
+Signed-off-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Link: https://lore.kernel.org/r/20201007084635.594991-2-andy.shevchenko@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 8afa6c6decea ("serial: max310x: fail probe if clock crystal is unstable")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/max310x.c | 30 +++++++++++++++---------------
+ 1 file changed, 15 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
+index 14537878f9855..8bf3c5ab59431 100644
+--- a/drivers/tty/serial/max310x.c
++++ b/drivers/tty/serial/max310x.c
+@@ -1265,7 +1265,6 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
+                        struct regmap *regmap, int irq)
+ {
+       int i, ret, fmin, fmax, freq, uartclk;
+-      struct clk *clk_osc, *clk_xtal;
+       struct max310x_port *s;
+       bool xtal = false;
+@@ -1279,23 +1278,24 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
+               return -ENOMEM;
+       }
+-      clk_osc = devm_clk_get(dev, "osc");
+-      clk_xtal = devm_clk_get(dev, "xtal");
+-      if (!IS_ERR(clk_osc)) {
+-              s->clk = clk_osc;
++      s->clk = devm_clk_get_optional(dev, "osc");
++      if (IS_ERR(s->clk))
++              return PTR_ERR(s->clk);
++      if (s->clk) {
+               fmin = 500000;
+               fmax = 35000000;
+-      } else if (!IS_ERR(clk_xtal)) {
+-              s->clk = clk_xtal;
+-              fmin = 1000000;
+-              fmax = 4000000;
+-              xtal = true;
+-      } else if (PTR_ERR(clk_osc) == -EPROBE_DEFER ||
+-                 PTR_ERR(clk_xtal) == -EPROBE_DEFER) {
+-              return -EPROBE_DEFER;
+       } else {
+-              dev_err(dev, "Cannot get clock\n");
+-              return -EINVAL;
++              s->clk = devm_clk_get_optional(dev, "xtal");
++              if (IS_ERR(s->clk))
++                      return PTR_ERR(s->clk);
++              if (s->clk) {
++                      fmin = 1000000;
++                      fmax = 4000000;
++                      xtal = true;
++              } else {
++                      dev_err(dev, "Cannot get clock\n");
++                      return -EINVAL;
++              }
+       }
+       ret = clk_prepare_enable(s->clk);
+-- 
+2.43.0
+
diff --git a/queue-5.4/serial-max310x-use-regmap-methods-for-spi-batch-oper.patch b/queue-5.4/serial-max310x-use-regmap-methods-for-spi-batch-oper.patch
new file mode 100644 (file)
index 0000000..55e4ffe
--- /dev/null
@@ -0,0 +1,93 @@
+From 169b9e3eb17685a3681218505fb91fac050bef77 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 5 Jun 2022 17:46:56 +0300
+Subject: serial: max310x: use regmap methods for SPI batch operations
+
+From: Cosmin Tanislav <cosmin.tanislav@analog.com>
+
+[ Upstream commit 285e76fc049c4d32c772eea9460a7ef28a193802 ]
+
+The SPI batch read/write operations can be implemented as simple
+regmap raw read and write, which will also try to do a gather
+write just as it is done here.
+
+Use the regmap raw read and write methods.
+
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Signed-off-by: Cosmin Tanislav <cosmin.tanislav@analog.com>
+Link: https://lore.kernel.org/r/20220605144659.4169853-2-demonsingur@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: b35f8dbbce81 ("serial: max310x: prevent infinite while() loop in port startup")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/max310x.c | 36 ++++++++----------------------------
+ 1 file changed, 8 insertions(+), 28 deletions(-)
+
+diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
+index 8d42c537ee5ea..c0fa4ad104774 100644
+--- a/drivers/tty/serial/max310x.c
++++ b/drivers/tty/serial/max310x.c
+@@ -263,8 +263,6 @@ struct max310x_one {
+       struct work_struct      md_work;
+       struct work_struct      rs_work;
+-      u8 wr_header;
+-      u8 rd_header;
+       u8 rx_buf[MAX310X_FIFO_SIZE];
+ };
+ #define to_max310x_port(_port) \
+@@ -635,32 +633,18 @@ static s32 max310x_set_ref_clk(struct device *dev, struct max310x_port *s,
+ static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int len)
+ {
+-      struct max310x_one *one = to_max310x_port(port);
+-      struct spi_transfer xfer[] = {
+-              {
+-                      .tx_buf = &one->wr_header,
+-                      .len = sizeof(one->wr_header),
+-              }, {
+-                      .tx_buf = txbuf,
+-                      .len = len,
+-              }
+-      };
+-      spi_sync_transfer(to_spi_device(port->dev), xfer, ARRAY_SIZE(xfer));
++      struct max310x_port *s = dev_get_drvdata(port->dev);
++      u8 reg = port->iobase + MAX310X_THR_REG;
++
++      regmap_raw_write(s->regmap, reg, txbuf, len);
+ }
+ static void max310x_batch_read(struct uart_port *port, u8 *rxbuf, unsigned int len)
+ {
+-      struct max310x_one *one = to_max310x_port(port);
+-      struct spi_transfer xfer[] = {
+-              {
+-                      .tx_buf = &one->rd_header,
+-                      .len = sizeof(one->rd_header),
+-              }, {
+-                      .rx_buf = rxbuf,
+-                      .len = len,
+-              }
+-      };
+-      spi_sync_transfer(to_spi_device(port->dev), xfer, ARRAY_SIZE(xfer));
++      struct max310x_port *s = dev_get_drvdata(port->dev);
++      u8 reg = port->iobase + MAX310X_RHR_REG;
++
++      regmap_raw_read(s->regmap, reg, rxbuf, len);
+ }
+ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
+@@ -1390,10 +1374,6 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
+               INIT_WORK(&s->p[i].md_work, max310x_md_proc);
+               /* Initialize queue for changing RS485 mode */
+               INIT_WORK(&s->p[i].rs_work, max310x_rs_proc);
+-              /* Initialize SPI-transfer buffers */
+-              s->p[i].wr_header = (s->p[i].port.iobase + MAX310X_THR_REG) |
+-                                  MAX310X_WRITE_BIT;
+-              s->p[i].rd_header = (s->p[i].port.iobase + MAX310X_RHR_REG);
+               /* Register port */
+               ret = uart_add_one_port(&max310x_uart, &s->p[i].port);
+-- 
+2.43.0
+
index a45fe809fe5806cfc6126d38ac6951f79353ea35..69667b88aca6541cab0c1f793bb50b5fa8e427de 100644 (file)
@@ -22,3 +22,34 @@ netrom-fix-a-data-race-around-sysctl_netrom_transpor.patch-31728
 netrom-fix-a-data-race-around-sysctl_netrom_routing_.patch
 netrom-fix-a-data-race-around-sysctl_netrom_link_fai.patch
 netrom-fix-data-races-around-sysctl_net_busy_read.patch
+nfsd-modernize-nfsd4_release_lockowner.patch
+nfsd-add-documenting-comment-for-nfsd4_release_locko.patch
+nfsd-fix-release_lockowner.patch
+selftests-mm-fix-map_hugetlb-failure-on-64k-page-siz.patch
+um-allow-not-setting-extra-rpaths-in-the-linux-binar.patch
+um-fix-adding-no-pie-for-clang.patch
+serial-max310x-use-devm_clk_get_optional-to-get-the-.patch
+serial-max310x-try-to-get-crystal-clock-rate-from-pr.patch
+serial-max310x-fail-probe-if-clock-crystal-is-unstab.patch
+serial-max310x-make-use-of-device-properties.patch
+serial-max310x-use-regmap-methods-for-spi-batch-oper.patch
+serial-max310x-use-a-separate-regmap-for-each-port.patch
+serial-max310x-prevent-infinite-while-loop-in-port-s.patch
+input-i8042-fix-strange-behavior-of-touchpad-on-clev.patch
+hv_netvsc-make-netvsc-vf-binding-check-both-mac-and-.patch
+hv_netvsc-use-netif_is_bond_master-instead-of-open-c.patch
+hv_netvsc-register-vf-in-netvsc_probe-if-net_device_.patch
+y2038-rusage-use-__kernel_old_timeval.patch
+getrusage-add-the-signal_struct-sig-local-variable.patch
+getrusage-move-thread_group_cputime_adjusted-outside.patch
+getrusage-use-__for_each_thread.patch
+getrusage-use-sig-stats_lock-rather-than-lock_task_s.patch
+exit-fix-typo-in-comment-s-sub-theads-sub-threads.patch
+exit-wait_task_zombie-kill-the-no-longer-necessary-s.patch
+nfsd-don-t-take-fi_lock-in-nfsd_break_deleg_cb.patch
+serial-max310x-unprepare-and-disable-clock-in-error-.patch
+regmap-allow-to-define-reg_update_bits-for-no-bus-co.patch
+regmap-add-bulk-read-write-callbacks-into-regmap_con.patch
+serial-max310x-make-accessing-revision-id-interface-.patch
+serial-max310x-implement-i2c-support.patch
+serial-max310x-fix-io-data-corruption-in-batched-ope.patch
diff --git a/queue-5.4/um-allow-not-setting-extra-rpaths-in-the-linux-binar.patch b/queue-5.4/um-allow-not-setting-extra-rpaths-in-the-linux-binar.patch
new file mode 100644 (file)
index 0000000..b287803
--- /dev/null
@@ -0,0 +1,82 @@
+From 26f3b5f71fb03300d8be7a87bf4ce8ef00880be5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 8 Mar 2021 14:02:37 +0100
+Subject: um: allow not setting extra rpaths in the linux binary
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+[ Upstream commit 386093c68ba3e8bcfe7f46deba901e0e80713c29 ]
+
+There doesn't seem to be any reason for the rpath being set in
+the binaries, at on systems that I tested on. On the other hand,
+setting rpath is actually harming binaries in some cases, e.g.
+if using nix-based compilation environments where /lib & /lib64
+are not part of the actual environment.
+
+Add a new Kconfig option (under EXPERT, for less user confusion)
+that allows disabling the rpath additions.
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Richard Weinberger <richard@nod.at>
+Stable-dep-of: 846cfbeed09b ("um: Fix adding '-no-pie' for clang")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/um/Kconfig      | 13 +++++++++++++
+ arch/um/Makefile     |  3 ++-
+ arch/x86/Makefile.um |  2 +-
+ 3 files changed, 16 insertions(+), 2 deletions(-)
+
+diff --git a/arch/um/Kconfig b/arch/um/Kconfig
+index 468a5d63ef269..107a0bc668e9f 100644
+--- a/arch/um/Kconfig
++++ b/arch/um/Kconfig
+@@ -85,6 +85,19 @@ config LD_SCRIPT_DYN
+       depends on !LD_SCRIPT_STATIC
+       select MODULE_REL_CRCS if MODVERSIONS
++config LD_SCRIPT_DYN_RPATH
++      bool "set rpath in the binary" if EXPERT
++      default y
++      depends on LD_SCRIPT_DYN
++      help
++        Add /lib (and /lib64 for 64-bit) to the linux binary's rpath
++        explicitly.
++
++        You may need to turn this off if compiling for nix systems
++        that have their libraries in random /nix directories and
++        might otherwise unexpected use libraries from /lib or /lib64
++        instead of the desired ones.
++
+ config HOSTFS
+       tristate "Host filesystem"
+       help
+diff --git a/arch/um/Makefile b/arch/um/Makefile
+index 773120be0f56f..94cea8d46b222 100644
+--- a/arch/um/Makefile
++++ b/arch/um/Makefile
+@@ -118,7 +118,8 @@ archprepare:
+       $(Q)$(MAKE) $(build)=$(HOST_DIR)/um include/generated/user_constants.h
+ LINK-$(CONFIG_LD_SCRIPT_STATIC) += -static
+-LINK-$(CONFIG_LD_SCRIPT_DYN) += -Wl,-rpath,/lib $(call cc-option, -no-pie)
++LINK-$(CONFIG_LD_SCRIPT_DYN) += $(call cc-option, -no-pie)
++LINK-$(CONFIG_LD_SCRIPT_DYN_RPATH) += -Wl,-rpath,/lib
+ CFLAGS_NO_HARDENING := $(call cc-option, -fno-PIC,) $(call cc-option, -fno-pic,) \
+       $(call cc-option, -fno-stack-protector,) \
+diff --git a/arch/x86/Makefile.um b/arch/x86/Makefile.um
+index 1db7913795f51..b3c1ae084180d 100644
+--- a/arch/x86/Makefile.um
++++ b/arch/x86/Makefile.um
+@@ -44,7 +44,7 @@ ELF_FORMAT := elf64-x86-64
+ # Not on all 64-bit distros /lib is a symlink to /lib64. PLD is an example.
+-LINK-$(CONFIG_LD_SCRIPT_DYN) += -Wl,-rpath,/lib64
++LINK-$(CONFIG_LD_SCRIPT_DYN_RPATH) += -Wl,-rpath,/lib64
+ LINK-y += -m64
+ endif
+-- 
+2.43.0
+
diff --git a/queue-5.4/um-fix-adding-no-pie-for-clang.patch b/queue-5.4/um-fix-adding-no-pie-for-clang.patch
new file mode 100644 (file)
index 0000000..8437f4b
--- /dev/null
@@ -0,0 +1,68 @@
+From 8ea84d1ab02214ad66ba8d958fdb4697065eb362 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 23 Jan 2024 15:59:54 -0700
+Subject: um: Fix adding '-no-pie' for clang
+
+From: Nathan Chancellor <nathan@kernel.org>
+
+[ Upstream commit 846cfbeed09b45d985079a9173cf390cc053715b ]
+
+The kernel builds with -fno-PIE, so commit 883354afbc10 ("um: link
+vmlinux with -no-pie") added the compiler linker flag '-no-pie' via
+cc-option because '-no-pie' was only supported in GCC 6.1.0 and newer.
+
+While this works for GCC, this does not work for clang because cc-option
+uses '-c', which stops the pipeline right before linking, so '-no-pie'
+is unconsumed and clang warns, causing cc-option to fail just as it
+would if the option was entirely unsupported:
+
+  $ clang -Werror -no-pie -c -o /dev/null -x c /dev/null
+  clang-16: error: argument unused during compilation: '-no-pie' [-Werror,-Wunused-command-line-argument]
+
+A recent version of clang exposes this because it generates a relocation
+under '-mcmodel=large' that is not supported in PIE mode:
+
+  /usr/sbin/ld: init/main.o: relocation R_X86_64_32 against symbol `saved_command_line' can not be used when making a PIE object; recompile with -fPIE
+  /usr/sbin/ld: failed to set dynamic section sizes: bad value
+  clang: error: linker command failed with exit code 1 (use -v to see invocation)
+
+Remove the cc-option check altogether. It is wasteful to invoke the
+compiler to check for '-no-pie' because only one supported compiler
+version does not support it, GCC 5.x (as it is supported with the
+minimum version of clang and GCC 6.1.0+). Use a combination of the
+gcc-min-version macro and CONFIG_CC_IS_CLANG to unconditionally add
+'-no-pie' with CONFIG_LD_SCRIPT_DYN=y, so that it is enabled with all
+compilers that support this. Furthermore, using gcc-min-version can help
+turn this back into
+
+  LINK-$(CONFIG_LD_SCRIPT_DYN) += -no-pie
+
+when the minimum version of GCC is bumped past 6.1.0.
+
+Cc: stable@vger.kernel.org
+Closes: https://github.com/ClangBuiltLinux/linux/issues/1982
+Signed-off-by: Nathan Chancellor <nathan@kernel.org>
+Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/um/Makefile | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/arch/um/Makefile b/arch/um/Makefile
+index 94cea8d46b222..4125bf63f5275 100644
+--- a/arch/um/Makefile
++++ b/arch/um/Makefile
+@@ -118,7 +118,9 @@ archprepare:
+       $(Q)$(MAKE) $(build)=$(HOST_DIR)/um include/generated/user_constants.h
+ LINK-$(CONFIG_LD_SCRIPT_STATIC) += -static
+-LINK-$(CONFIG_LD_SCRIPT_DYN) += $(call cc-option, -no-pie)
++ifdef CONFIG_LD_SCRIPT_DYN
++LINK-$(call gcc-min-version, 60100)$(CONFIG_CC_IS_CLANG) += -no-pie
++endif
+ LINK-$(CONFIG_LD_SCRIPT_DYN_RPATH) += -Wl,-rpath,/lib
+ CFLAGS_NO_HARDENING := $(call cc-option, -fno-PIC,) $(call cc-option, -fno-pic,) \
+-- 
+2.43.0
+
diff --git a/queue-5.4/y2038-rusage-use-__kernel_old_timeval.patch b/queue-5.4/y2038-rusage-use-__kernel_old_timeval.patch
new file mode 100644 (file)
index 0000000..4dd88a2
--- /dev/null
@@ -0,0 +1,81 @@
+From fd7d98c0acaaecde1cb3206f834d95079d7e2a39 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 25 Oct 2019 22:46:48 +0200
+Subject: y2038: rusage: use __kernel_old_timeval
+
+From: Arnd Bergmann <arnd@arndb.de>
+
+[ Upstream commit bdd565f817a74b9e30edec108f7cb1dbc762b8a6 ]
+
+There are two 'struct timeval' fields in 'struct rusage'.
+
+Unfortunately the definition of timeval is now ambiguous when used in
+user space with a libc that has a 64-bit time_t, and this also changes
+the 'rusage' definition in user space in a way that is incompatible with
+the system call interface.
+
+While there is no good solution to avoid all ambiguity here, change
+the definition in the kernel headers to be compatible with the kernel
+ABI, using __kernel_old_timeval as an unambiguous base type.
+
+In previous discussions, there was also a plan to add a replacement
+for rusage based on 64-bit timestamps and nanosecond resolution,
+i.e. 'struct __kernel_timespec'. I have patches for that as well,
+if anyone thinks we should do that.
+
+Reviewed-by: Cyrill Gorcunov <gorcunov@gmail.com>
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Stable-dep-of: daa694e41375 ("getrusage: move thread_group_cputime_adjusted() outside of lock_task_sighand()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/alpha/kernel/osf_sys.c   | 2 +-
+ include/uapi/linux/resource.h | 4 ++--
+ kernel/sys.c                  | 4 ++--
+ 3 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
+index bf497b8b0ec60..bbe7a0da6264f 100644
+--- a/arch/alpha/kernel/osf_sys.c
++++ b/arch/alpha/kernel/osf_sys.c
+@@ -963,7 +963,7 @@ put_tv32(struct timeval32 __user *o, struct timespec64 *i)
+ }
+ static inline long
+-put_tv_to_tv32(struct timeval32 __user *o, struct timeval *i)
++put_tv_to_tv32(struct timeval32 __user *o, struct __kernel_old_timeval *i)
+ {
+       return copy_to_user(o, &(struct timeval32){
+                               .tv_sec = i->tv_sec,
+diff --git a/include/uapi/linux/resource.h b/include/uapi/linux/resource.h
+index cc00fd0796317..74ef57b38f9f5 100644
+--- a/include/uapi/linux/resource.h
++++ b/include/uapi/linux/resource.h
+@@ -22,8 +22,8 @@
+ #define       RUSAGE_THREAD   1               /* only the calling thread */
+ struct        rusage {
+-      struct timeval ru_utime;        /* user time used */
+-      struct timeval ru_stime;        /* system time used */
++      struct __kernel_old_timeval ru_utime;   /* user time used */
++      struct __kernel_old_timeval ru_stime;   /* system time used */
+       __kernel_long_t ru_maxrss;      /* maximum resident set size */
+       __kernel_long_t ru_ixrss;       /* integral shared memory size */
+       __kernel_long_t ru_idrss;       /* integral unshared data size */
+diff --git a/kernel/sys.c b/kernel/sys.c
+index f6d6ce8da3e4a..bc3cd0ef894e6 100644
+--- a/kernel/sys.c
++++ b/kernel/sys.c
+@@ -1767,8 +1767,8 @@ void getrusage(struct task_struct *p, int who, struct rusage *r)
+       unlock_task_sighand(p, &flags);
+ out:
+-      r->ru_utime = ns_to_timeval(utime);
+-      r->ru_stime = ns_to_timeval(stime);
++      r->ru_utime = ns_to_kernel_old_timeval(utime);
++      r->ru_stime = ns_to_kernel_old_timeval(stime);
+       if (who != RUSAGE_CHILDREN) {
+               struct mm_struct *mm = get_task_mm(p);
+-- 
+2.43.0
+