]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 4.19
authorSasha Levin <sashal@kernel.org>
Fri, 8 Dec 2023 10:04:30 +0000 (05:04 -0500)
committerSasha Levin <sashal@kernel.org>
Fri, 8 Dec 2023 10:04:30 +0000 (05:04 -0500)
Signed-off-by: Sasha Levin <sashal@kernel.org>
13 files changed:
queue-4.19/block-introduce-multi-page-bvec-helpers.patch [new file with mode: 0644]
queue-4.19/drm-amdgpu-correct-chunk_ptr-to-a-pointer-to-chunk.patch [new file with mode: 0644]
queue-4.19/hrtimers-push-pending-hrtimers-away-from-outgoing-cp.patch [new file with mode: 0644]
queue-4.19/kconfig-fix-memory-leak-from-range-properties.patch [new file with mode: 0644]
queue-4.19/media-davinci-vpif_capture-fix-potential-double-free.patch [new file with mode: 0644]
queue-4.19/netfilter-ipset-fix-race-condition-between-swap-dest.patch [new file with mode: 0644]
queue-4.19/series [new file with mode: 0644]
queue-4.19/spi-imx-add-a-device-specific-prepare_message-callba.patch [new file with mode: 0644]
queue-4.19/spi-imx-correct-wml-as-the-last-sg-length.patch [new file with mode: 0644]
queue-4.19/spi-imx-move-wml-setting-to-later-than-setup_transfe.patch [new file with mode: 0644]
queue-4.19/spi-imx-mx51-ecspi-move-some-initialisation-to-prepa.patch [new file with mode: 0644]
queue-4.19/tg3-increment-tx_dropped-in-tg3_tso_bug.patch [new file with mode: 0644]
queue-4.19/tg3-move-the-rt-x_dropped-counters-to-tg3_napi.patch [new file with mode: 0644]

diff --git a/queue-4.19/block-introduce-multi-page-bvec-helpers.patch b/queue-4.19/block-introduce-multi-page-bvec-helpers.patch
new file mode 100644 (file)
index 0000000..cf9f6c2
--- /dev/null
@@ -0,0 +1,117 @@
+From 8ae400c0add40e6d7fd80c616b3f6f7974b2f254 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 15 Feb 2019 19:13:10 +0800
+Subject: block: introduce multi-page bvec helpers
+
+From: Ming Lei <ming.lei@redhat.com>
+
+[ Upstream commit 3d75ca0adef4280650c6690a0c4702a74a6f3c95 ]
+
+This patch introduces helpers of 'mp_bvec_iter_*' for multi-page bvec
+support.
+
+The introduced helpers treate one bvec as real multi-page segment,
+which may include more than one pages.
+
+The existed helpers of bvec_iter_* are interfaces for supporting current
+bvec iterator which is thought as single-page by drivers, fs, dm and
+etc. These introduced helpers will build single-page bvec in flight, so
+this way won't break current bio/bvec users, which needn't any change.
+
+Follows some multi-page bvec background:
+
+- bvecs stored in bio->bi_io_vec is always multi-page style
+
+- bvec(struct bio_vec) represents one physically contiguous I/O
+  buffer, now the buffer may include more than one page after
+  multi-page bvec is supported, and all these pages represented
+  by one bvec is physically contiguous. Before multi-page bvec
+  support, at most one page is included in one bvec, we call it
+  single-page bvec.
+
+- .bv_page of the bvec points to the 1st page in the multi-page bvec
+
+- .bv_offset of the bvec is the offset of the buffer in the bvec
+
+The effect on the current drivers/filesystem/dm/bcache/...:
+
+- almost everyone supposes that one bvec only includes one single
+  page, so we keep the sp interface not changed, for example,
+  bio_for_each_segment() still returns single-page bvec
+
+- bio_for_each_segment_all() will return single-page bvec too
+
+- during iterating, iterator variable(struct bvec_iter) is always
+  updated in multi-page bvec style, and bvec_iter_advance() is kept
+  not changed
+
+- returned(copied) single-page bvec is built in flight by bvec
+  helpers from the stored multi-page bvec
+
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Omar Sandoval <osandov@fb.com>
+Signed-off-by: Ming Lei <ming.lei@redhat.com>
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/bvec.h | 30 +++++++++++++++++++++++++++---
+ 1 file changed, 27 insertions(+), 3 deletions(-)
+
+diff --git a/include/linux/bvec.h b/include/linux/bvec.h
+index bc1f16e9f3f4d..cd43c03e31129 100644
+--- a/include/linux/bvec.h
++++ b/include/linux/bvec.h
+@@ -23,6 +23,7 @@
+ #include <linux/kernel.h>
+ #include <linux/bug.h>
+ #include <linux/errno.h>
++#include <linux/mm.h>
+ /*
+  * was unsigned short, but we might as well be ready for > 64kB I/O pages
+@@ -52,16 +53,39 @@ struct bvec_iter {
+  */
+ #define __bvec_iter_bvec(bvec, iter)  (&(bvec)[(iter).bi_idx])
+-#define bvec_iter_page(bvec, iter)                            \
++/* multi-page (mp_bvec) helpers */
++#define mp_bvec_iter_page(bvec, iter)                         \
+       (__bvec_iter_bvec((bvec), (iter))->bv_page)
+-#define bvec_iter_len(bvec, iter)                             \
++#define mp_bvec_iter_len(bvec, iter)                          \
+       min((iter).bi_size,                                     \
+           __bvec_iter_bvec((bvec), (iter))->bv_len - (iter).bi_bvec_done)
+-#define bvec_iter_offset(bvec, iter)                          \
++#define mp_bvec_iter_offset(bvec, iter)                               \
+       (__bvec_iter_bvec((bvec), (iter))->bv_offset + (iter).bi_bvec_done)
++#define mp_bvec_iter_page_idx(bvec, iter)                     \
++      (mp_bvec_iter_offset((bvec), (iter)) / PAGE_SIZE)
++
++#define mp_bvec_iter_bvec(bvec, iter)                         \
++((struct bio_vec) {                                           \
++      .bv_page        = mp_bvec_iter_page((bvec), (iter)),    \
++      .bv_len         = mp_bvec_iter_len((bvec), (iter)),     \
++      .bv_offset      = mp_bvec_iter_offset((bvec), (iter)),  \
++})
++
++/* For building single-page bvec in flight */
++ #define bvec_iter_offset(bvec, iter)                         \
++      (mp_bvec_iter_offset((bvec), (iter)) % PAGE_SIZE)
++
++#define bvec_iter_len(bvec, iter)                             \
++      min_t(unsigned, mp_bvec_iter_len((bvec), (iter)),               \
++            PAGE_SIZE - bvec_iter_offset((bvec), (iter)))
++
++#define bvec_iter_page(bvec, iter)                            \
++      nth_page(mp_bvec_iter_page((bvec), (iter)),             \
++               mp_bvec_iter_page_idx((bvec), (iter)))
++
+ #define bvec_iter_bvec(bvec, iter)                            \
+ ((struct bio_vec) {                                           \
+       .bv_page        = bvec_iter_page((bvec), (iter)),       \
+-- 
+2.42.0
+
diff --git a/queue-4.19/drm-amdgpu-correct-chunk_ptr-to-a-pointer-to-chunk.patch b/queue-4.19/drm-amdgpu-correct-chunk_ptr-to-a-pointer-to-chunk.patch
new file mode 100644 (file)
index 0000000..7327cb5
--- /dev/null
@@ -0,0 +1,40 @@
+From cde4432152118ac85da2bbea2c07d5ab6266be48 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Oct 2023 10:32:37 +0800
+Subject: drm/amdgpu: correct chunk_ptr to a pointer to chunk.
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: YuanShang <YuanShang.Mao@amd.com>
+
+[ Upstream commit 50d51374b498457c4dea26779d32ccfed12ddaff ]
+
+The variable "chunk_ptr" should be a pointer pointing
+to a struct drm_amdgpu_cs_chunk instead of to a pointer
+of that.
+
+Signed-off-by: YuanShang <YuanShang.Mao@amd.com>
+Reviewed-by: Christian König <christian.koenig@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+index 70e446c2acf82..94b06c918e80d 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+@@ -147,7 +147,7 @@ static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, union drm_amdgpu_cs
+       }
+       for (i = 0; i < p->nchunks; i++) {
+-              struct drm_amdgpu_cs_chunk __user **chunk_ptr = NULL;
++              struct drm_amdgpu_cs_chunk __user *chunk_ptr = NULL;
+               struct drm_amdgpu_cs_chunk user_chunk;
+               uint32_t __user *cdata;
+-- 
+2.42.0
+
diff --git a/queue-4.19/hrtimers-push-pending-hrtimers-away-from-outgoing-cp.patch b/queue-4.19/hrtimers-push-pending-hrtimers-away-from-outgoing-cp.patch
new file mode 100644 (file)
index 0000000..fc6accc
--- /dev/null
@@ -0,0 +1,155 @@
+From 052a7117914ed4824dda3350818af593662d07ca Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 7 Nov 2023 15:57:13 +0100
+Subject: hrtimers: Push pending hrtimers away from outgoing CPU earlier
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+[ Upstream commit 5c0930ccaad5a74d74e8b18b648c5eb21ed2fe94 ]
+
+2b8272ff4a70 ("cpu/hotplug: Prevent self deadlock on CPU hot-unplug")
+solved the straight forward CPU hotplug deadlock vs. the scheduler
+bandwidth timer. Yu discovered a more involved variant where a task which
+has a bandwidth timer started on the outgoing CPU holds a lock and then
+gets throttled. If the lock required by one of the CPU hotplug callbacks
+the hotplug operation deadlocks because the unthrottling timer event is not
+handled on the dying CPU and can only be recovered once the control CPU
+reaches the hotplug state which pulls the pending hrtimers from the dead
+CPU.
+
+Solve this by pushing the hrtimers away from the dying CPU in the dying
+callbacks. Nothing can queue a hrtimer on the dying CPU at that point because
+all other CPUs spin in stop_machine() with interrupts disabled and once the
+operation is finished the CPU is marked offline.
+
+Reported-by: Yu Liao <liaoyu15@huawei.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Tested-by: Liu Tie <liutie4@huawei.com>
+Link: https://lore.kernel.org/r/87a5rphara.ffs@tglx
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/cpuhotplug.h |  1 +
+ include/linux/hrtimer.h    |  4 ++--
+ kernel/cpu.c               |  8 +++++++-
+ kernel/time/hrtimer.c      | 33 ++++++++++++---------------------
+ 4 files changed, 22 insertions(+), 24 deletions(-)
+
+diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
+index 71a0a5ffdbb1a..dd9f035be63f7 100644
+--- a/include/linux/cpuhotplug.h
++++ b/include/linux/cpuhotplug.h
+@@ -139,6 +139,7 @@ enum cpuhp_state {
+       CPUHP_AP_ARM_CORESIGHT_STARTING,
+       CPUHP_AP_ARM64_ISNDEP_STARTING,
+       CPUHP_AP_SMPCFD_DYING,
++      CPUHP_AP_HRTIMERS_DYING,
+       CPUHP_AP_X86_TBOOT_DYING,
+       CPUHP_AP_ARM_CACHE_B15_RAC_DYING,
+       CPUHP_AP_ONLINE,
+diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
+index 542b4fa2cda9b..3bdaa92a2cab3 100644
+--- a/include/linux/hrtimer.h
++++ b/include/linux/hrtimer.h
+@@ -508,9 +508,9 @@ extern void sysrq_timer_list_show(void);
+ int hrtimers_prepare_cpu(unsigned int cpu);
+ #ifdef CONFIG_HOTPLUG_CPU
+-int hrtimers_dead_cpu(unsigned int cpu);
++int hrtimers_cpu_dying(unsigned int cpu);
+ #else
+-#define hrtimers_dead_cpu     NULL
++#define hrtimers_cpu_dying    NULL
+ #endif
+ #endif
+diff --git a/kernel/cpu.c b/kernel/cpu.c
+index c9ca190ec0347..34c09c3d37bc6 100644
+--- a/kernel/cpu.c
++++ b/kernel/cpu.c
+@@ -1418,7 +1418,7 @@ static struct cpuhp_step cpuhp_hp_states[] = {
+       [CPUHP_HRTIMERS_PREPARE] = {
+               .name                   = "hrtimers:prepare",
+               .startup.single         = hrtimers_prepare_cpu,
+-              .teardown.single        = hrtimers_dead_cpu,
++              .teardown.single        = NULL,
+       },
+       [CPUHP_SMPCFD_PREPARE] = {
+               .name                   = "smpcfd:prepare",
+@@ -1485,6 +1485,12 @@ static struct cpuhp_step cpuhp_hp_states[] = {
+               .startup.single         = NULL,
+               .teardown.single        = smpcfd_dying_cpu,
+       },
++      [CPUHP_AP_HRTIMERS_DYING] = {
++              .name                   = "hrtimers:dying",
++              .startup.single         = NULL,
++              .teardown.single        = hrtimers_cpu_dying,
++      },
++
+       /* Entry state on starting. Interrupts enabled from here on. Transient
+        * state for synchronsization */
+       [CPUHP_AP_ONLINE] = {
+diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
+index 8512f06f0ebef..bf74f43e42af0 100644
+--- a/kernel/time/hrtimer.c
++++ b/kernel/time/hrtimer.c
+@@ -1922,29 +1922,22 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
+       }
+ }
+-int hrtimers_dead_cpu(unsigned int scpu)
++int hrtimers_cpu_dying(unsigned int dying_cpu)
+ {
+       struct hrtimer_cpu_base *old_base, *new_base;
+-      int i;
++      int i, ncpu = cpumask_first(cpu_active_mask);
+-      BUG_ON(cpu_online(scpu));
+-      tick_cancel_sched_timer(scpu);
++      tick_cancel_sched_timer(dying_cpu);
++
++      old_base = this_cpu_ptr(&hrtimer_bases);
++      new_base = &per_cpu(hrtimer_bases, ncpu);
+-      /*
+-       * this BH disable ensures that raise_softirq_irqoff() does
+-       * not wakeup ksoftirqd (and acquire the pi-lock) while
+-       * holding the cpu_base lock
+-       */
+-      local_bh_disable();
+-      local_irq_disable();
+-      old_base = &per_cpu(hrtimer_bases, scpu);
+-      new_base = this_cpu_ptr(&hrtimer_bases);
+       /*
+        * The caller is globally serialized and nobody else
+        * takes two locks at once, deadlock is not possible.
+        */
+-      raw_spin_lock(&new_base->lock);
+-      raw_spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING);
++      raw_spin_lock(&old_base->lock);
++      raw_spin_lock_nested(&new_base->lock, SINGLE_DEPTH_NESTING);
+       for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
+               migrate_hrtimer_list(&old_base->clock_base[i],
+@@ -1955,15 +1948,13 @@ int hrtimers_dead_cpu(unsigned int scpu)
+        * The migration might have changed the first expiring softirq
+        * timer on this CPU. Update it.
+        */
+-      hrtimer_update_softirq_timer(new_base, false);
++      __hrtimer_get_next_event(new_base, HRTIMER_ACTIVE_SOFT);
++      /* Tell the other CPU to retrigger the next event */
++      smp_call_function_single(ncpu, retrigger_next_event, NULL, 0);
+-      raw_spin_unlock(&old_base->lock);
+       raw_spin_unlock(&new_base->lock);
++      raw_spin_unlock(&old_base->lock);
+-      /* Check, if we got expired work to do */
+-      __hrtimer_peek_ahead_timers();
+-      local_irq_enable();
+-      local_bh_enable();
+       return 0;
+ }
+-- 
+2.42.0
+
diff --git a/queue-4.19/kconfig-fix-memory-leak-from-range-properties.patch b/queue-4.19/kconfig-fix-memory-leak-from-range-properties.patch
new file mode 100644 (file)
index 0000000..0613ee7
--- /dev/null
@@ -0,0 +1,92 @@
+From 379bc3ff94894e35c07c93c50c1b75be94ef69e1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Nov 2023 13:16:53 +0900
+Subject: kconfig: fix memory leak from range properties
+
+From: Masahiro Yamada <masahiroy@kernel.org>
+
+[ Upstream commit ae1eff0349f2e908fc083630e8441ea6dc434dc0 ]
+
+Currently, sym_validate_range() duplicates the range string using
+xstrdup(), which is overwritten by a subsequent sym_calc_value() call.
+It results in a memory leak.
+
+Instead, only the pointer should be copied.
+
+Below is a test case, with a summary from Valgrind.
+
+[Test Kconfig]
+
+  config FOO
+          int "foo"
+          range 10 20
+
+[Test .config]
+
+  CONFIG_FOO=0
+
+[Before]
+
+  LEAK SUMMARY:
+     definitely lost: 3 bytes in 1 blocks
+     indirectly lost: 0 bytes in 0 blocks
+       possibly lost: 0 bytes in 0 blocks
+     still reachable: 17,465 bytes in 21 blocks
+          suppressed: 0 bytes in 0 blocks
+
+[After]
+
+  LEAK SUMMARY:
+     definitely lost: 0 bytes in 0 blocks
+     indirectly lost: 0 bytes in 0 blocks
+       possibly lost: 0 bytes in 0 blocks
+     still reachable: 17,462 bytes in 20 blocks
+          suppressed: 0 bytes in 0 blocks
+
+Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ scripts/kconfig/symbol.c | 14 ++++++--------
+ 1 file changed, 6 insertions(+), 8 deletions(-)
+
+diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
+index 703b9b899ee9c..5adb60b7e12f3 100644
+--- a/scripts/kconfig/symbol.c
++++ b/scripts/kconfig/symbol.c
+@@ -119,9 +119,9 @@ static long long sym_get_range_val(struct symbol *sym, int base)
+ static void sym_validate_range(struct symbol *sym)
+ {
+       struct property *prop;
++      struct symbol *range_sym;
+       int base;
+       long long val, val2;
+-      char str[64];
+       switch (sym->type) {
+       case S_INT:
+@@ -137,17 +137,15 @@ static void sym_validate_range(struct symbol *sym)
+       if (!prop)
+               return;
+       val = strtoll(sym->curr.val, NULL, base);
+-      val2 = sym_get_range_val(prop->expr->left.sym, base);
++      range_sym = prop->expr->left.sym;
++      val2 = sym_get_range_val(range_sym, base);
+       if (val >= val2) {
+-              val2 = sym_get_range_val(prop->expr->right.sym, base);
++              range_sym = prop->expr->right.sym;
++              val2 = sym_get_range_val(range_sym, base);
+               if (val <= val2)
+                       return;
+       }
+-      if (sym->type == S_INT)
+-              sprintf(str, "%lld", val2);
+-      else
+-              sprintf(str, "0x%llx", val2);
+-      sym->curr.val = xstrdup(str);
++      sym->curr.val = range_sym->curr.val;
+ }
+ static void sym_set_changed(struct symbol *sym)
+-- 
+2.42.0
+
diff --git a/queue-4.19/media-davinci-vpif_capture-fix-potential-double-free.patch b/queue-4.19/media-davinci-vpif_capture-fix-potential-double-free.patch
new file mode 100644 (file)
index 0000000..06fafb9
--- /dev/null
@@ -0,0 +1,40 @@
+From b0950ab9659e1e6f3a9191b2bf862e77a657fe93 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 23 Jul 2020 19:04:53 +0200
+Subject: media: davinci: vpif_capture: fix potential double free
+
+From: Evgeny Novikov <novikov@ispras.ru>
+
+[ Upstream commit 602649eadaa0c977e362e641f51ec306bc1d365d ]
+
+In case of errors vpif_probe_complete() releases memory for vpif_obj.sd
+and unregisters the V4L2 device. But then this is done again by
+vpif_probe() itself. The patch removes the cleaning from
+vpif_probe_complete().
+
+Found by Linux Driver Verification project (linuxtesting.org).
+
+Signed-off-by: Evgeny Novikov <novikov@ispras.ru>
+Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
+Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/platform/davinci/vpif_capture.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c
+index a96f53ce80886..cf1d11e6dd8c4 100644
+--- a/drivers/media/platform/davinci/vpif_capture.c
++++ b/drivers/media/platform/davinci/vpif_capture.c
+@@ -1489,8 +1489,6 @@ static int vpif_probe_complete(void)
+               /* Unregister video device */
+               video_unregister_device(&ch->video_dev);
+       }
+-      kfree(vpif_obj.sd);
+-      v4l2_device_unregister(&vpif_obj.v4l2_dev);
+       return err;
+ }
+-- 
+2.42.0
+
diff --git a/queue-4.19/netfilter-ipset-fix-race-condition-between-swap-dest.patch b/queue-4.19/netfilter-ipset-fix-race-condition-between-swap-dest.patch
new file mode 100644 (file)
index 0000000..238e55b
--- /dev/null
@@ -0,0 +1,105 @@
+From 98d22c406779c2cb93568db16dbad8c6a4d3a0f4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Nov 2023 21:13:23 +0100
+Subject: netfilter: ipset: fix race condition between swap/destroy and kernel
+ side add/del/test
+
+From: Jozsef Kadlecsik <kadlec@netfilter.org>
+
+[ Upstream commit 28628fa952fefc7f2072ce6e8016968cc452b1ba ]
+
+Linkui Xiao reported that there's a race condition when ipset swap and destroy is
+called, which can lead to crash in add/del/test element operations. Swap then
+destroy are usual operations to replace a set with another one in a production
+system. The issue can in some cases be reproduced with the script:
+
+ipset create hash_ip1 hash:net family inet hashsize 1024 maxelem 1048576
+ipset add hash_ip1 172.20.0.0/16
+ipset add hash_ip1 192.168.0.0/16
+iptables -A INPUT -m set --match-set hash_ip1 src -j ACCEPT
+while [ 1 ]
+do
+       # ... Ongoing traffic...
+        ipset create hash_ip2 hash:net family inet hashsize 1024 maxelem 1048576
+        ipset add hash_ip2 172.20.0.0/16
+        ipset swap hash_ip1 hash_ip2
+        ipset destroy hash_ip2
+        sleep 0.05
+done
+
+In the race case the possible order of the operations are
+
+       CPU0                    CPU1
+       ip_set_test
+                               ipset swap hash_ip1 hash_ip2
+                               ipset destroy hash_ip2
+       hash_net_kadt
+
+Swap replaces hash_ip1 with hash_ip2 and then destroy removes hash_ip2 which
+is the original hash_ip1. ip_set_test was called on hash_ip1 and because destroy
+removed it, hash_net_kadt crashes.
+
+The fix is to force ip_set_swap() to wait for all readers to finish accessing the
+old set pointers by calling synchronize_rcu().
+
+The first version of the patch was written by Linkui Xiao <xiaolinkui@kylinos.cn>.
+
+v2: synchronize_rcu() is moved into ip_set_swap() in order not to burden
+    ip_set_destroy() unnecessarily when all sets are destroyed.
+v3: Florian Westphal pointed out that all netfilter hooks run with rcu_read_lock() held
+    and em_ipset.c wraps the entire ip_set_test() in rcu read lock/unlock pair.
+    So there's no need to extend the rcu read locked area in ipset itself.
+
+Closes: https://lore.kernel.org/all/69e7963b-e7f8-3ad0-210-7b86eebf7f78@netfilter.org/
+Reported by: Linkui Xiao <xiaolinkui@kylinos.cn>
+Signed-off-by: Jozsef Kadlecsik <kadlec@netfilter.org>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/ipset/ip_set_core.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
+index 31756d1bf83e7..031bb83aed70a 100644
+--- a/net/netfilter/ipset/ip_set_core.c
++++ b/net/netfilter/ipset/ip_set_core.c
+@@ -64,6 +64,8 @@ MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_IPSET);
+       ip_set_dereference((inst)->ip_set_list)[id]
+ #define ip_set_ref_netlink(inst,id)   \
+       rcu_dereference_raw((inst)->ip_set_list)[id]
++#define ip_set_dereference_nfnl(p)    \
++      rcu_dereference_check(p, lockdep_nfnl_is_held(NFNL_SUBSYS_IPSET))
+ /* The set types are implemented in modules and registered set types
+  * can be found in ip_set_type_list. Adding/deleting types is
+@@ -552,15 +554,10 @@ __ip_set_put_netlink(struct ip_set *set)
+ static inline struct ip_set *
+ ip_set_rcu_get(struct net *net, ip_set_id_t index)
+ {
+-      struct ip_set *set;
+       struct ip_set_net *inst = ip_set_pernet(net);
+-      rcu_read_lock();
+-      /* ip_set_list itself needs to be protected */
+-      set = rcu_dereference(inst->ip_set_list)[index];
+-      rcu_read_unlock();
+-
+-      return set;
++      /* ip_set_list and the set pointer need to be protected */
++      return ip_set_dereference_nfnl(inst->ip_set_list)[index];
+ }
+ int
+@@ -1227,6 +1224,9 @@ static int ip_set_swap(struct net *net, struct sock *ctnl, struct sk_buff *skb,
+       ip_set(inst, to_id) = from;
+       write_unlock_bh(&ip_set_ref_lock);
++      /* Make sure all readers of the old set pointers are completed. */
++      synchronize_rcu();
++
+       return 0;
+ }
+-- 
+2.42.0
+
diff --git a/queue-4.19/series b/queue-4.19/series
new file mode 100644 (file)
index 0000000..b9b74dd
--- /dev/null
@@ -0,0 +1,12 @@
+spi-imx-add-a-device-specific-prepare_message-callba.patch
+spi-imx-move-wml-setting-to-later-than-setup_transfe.patch
+spi-imx-correct-wml-as-the-last-sg-length.patch
+spi-imx-mx51-ecspi-move-some-initialisation-to-prepa.patch
+media-davinci-vpif_capture-fix-potential-double-free.patch
+block-introduce-multi-page-bvec-helpers.patch
+hrtimers-push-pending-hrtimers-away-from-outgoing-cp.patch
+netfilter-ipset-fix-race-condition-between-swap-dest.patch
+tg3-move-the-rt-x_dropped-counters-to-tg3_napi.patch
+tg3-increment-tx_dropped-in-tg3_tso_bug.patch
+kconfig-fix-memory-leak-from-range-properties.patch
+drm-amdgpu-correct-chunk_ptr-to-a-pointer-to-chunk.patch
diff --git a/queue-4.19/spi-imx-add-a-device-specific-prepare_message-callba.patch b/queue-4.19/spi-imx-add-a-device-specific-prepare_message-callba.patch
new file mode 100644 (file)
index 0000000..248573a
--- /dev/null
@@ -0,0 +1,162 @@
+From b19a3770ce84da3c16acc7142e754cd8ff80ad3d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 30 Nov 2018 07:47:05 +0100
+Subject: spi: imx: add a device specific prepare_message callback
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+
+[ Upstream commit e697271c4e2987b333148e16a2eb8b5b924fd40a ]
+
+This is just preparatory work which allows to move some initialisation
+that currently is done in the per transfer hook .config to an earlier
+point in time in the next few patches. There is no change in behaviour
+introduced by this patch.
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/spi/spi-imx.c | 40 +++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 39 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
+index 1ad4b69292ad8..eb27f47578eb9 100644
+--- a/drivers/spi/spi-imx.c
++++ b/drivers/spi/spi-imx.c
+@@ -59,6 +59,7 @@ struct spi_imx_data;
+ struct spi_imx_devtype_data {
+       void (*intctrl)(struct spi_imx_data *, int);
++      int (*prepare_message)(struct spi_imx_data *, struct spi_message *);
+       int (*config)(struct spi_device *);
+       void (*trigger)(struct spi_imx_data *);
+       int (*rx_available)(struct spi_imx_data *);
+@@ -502,6 +503,12 @@ static void mx51_ecspi_disable(struct spi_imx_data *spi_imx)
+       writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
+ }
++static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
++                                    struct spi_message *msg)
++{
++      return 0;
++}
++
+ static int mx51_ecspi_config(struct spi_device *spi)
+ {
+       struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
+@@ -672,6 +679,12 @@ static void mx31_trigger(struct spi_imx_data *spi_imx)
+       writel(reg, spi_imx->base + MXC_CSPICTRL);
+ }
++static int mx31_prepare_message(struct spi_imx_data *spi_imx,
++                              struct spi_message *msg)
++{
++      return 0;
++}
++
+ static int mx31_config(struct spi_device *spi)
+ {
+       struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
+@@ -768,6 +781,12 @@ static void mx21_trigger(struct spi_imx_data *spi_imx)
+       writel(reg, spi_imx->base + MXC_CSPICTRL);
+ }
++static int mx21_prepare_message(struct spi_imx_data *spi_imx,
++                              struct spi_message *msg)
++{
++      return 0;
++}
++
+ static int mx21_config(struct spi_device *spi)
+ {
+       struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
+@@ -837,6 +856,12 @@ static void mx1_trigger(struct spi_imx_data *spi_imx)
+       writel(reg, spi_imx->base + MXC_CSPICTRL);
+ }
++static int mx1_prepare_message(struct spi_imx_data *spi_imx,
++                             struct spi_message *msg)
++{
++      return 0;
++}
++
+ static int mx1_config(struct spi_device *spi)
+ {
+       struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
+@@ -871,6 +896,7 @@ static void mx1_reset(struct spi_imx_data *spi_imx)
+ static struct spi_imx_devtype_data imx1_cspi_devtype_data = {
+       .intctrl = mx1_intctrl,
++      .prepare_message = mx1_prepare_message,
+       .config = mx1_config,
+       .trigger = mx1_trigger,
+       .rx_available = mx1_rx_available,
+@@ -884,6 +910,7 @@ static struct spi_imx_devtype_data imx1_cspi_devtype_data = {
+ static struct spi_imx_devtype_data imx21_cspi_devtype_data = {
+       .intctrl = mx21_intctrl,
++      .prepare_message = mx21_prepare_message,
+       .config = mx21_config,
+       .trigger = mx21_trigger,
+       .rx_available = mx21_rx_available,
+@@ -898,6 +925,7 @@ static struct spi_imx_devtype_data imx21_cspi_devtype_data = {
+ static struct spi_imx_devtype_data imx27_cspi_devtype_data = {
+       /* i.mx27 cspi shares the functions with i.mx21 one */
+       .intctrl = mx21_intctrl,
++      .prepare_message = mx21_prepare_message,
+       .config = mx21_config,
+       .trigger = mx21_trigger,
+       .rx_available = mx21_rx_available,
+@@ -911,6 +939,7 @@ static struct spi_imx_devtype_data imx27_cspi_devtype_data = {
+ static struct spi_imx_devtype_data imx31_cspi_devtype_data = {
+       .intctrl = mx31_intctrl,
++      .prepare_message = mx31_prepare_message,
+       .config = mx31_config,
+       .trigger = mx31_trigger,
+       .rx_available = mx31_rx_available,
+@@ -925,6 +954,7 @@ static struct spi_imx_devtype_data imx31_cspi_devtype_data = {
+ static struct spi_imx_devtype_data imx35_cspi_devtype_data = {
+       /* i.mx35 and later cspi shares the functions with i.mx31 one */
+       .intctrl = mx31_intctrl,
++      .prepare_message = mx31_prepare_message,
+       .config = mx31_config,
+       .trigger = mx31_trigger,
+       .rx_available = mx31_rx_available,
+@@ -938,6 +968,7 @@ static struct spi_imx_devtype_data imx35_cspi_devtype_data = {
+ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = {
+       .intctrl = mx51_ecspi_intctrl,
++      .prepare_message = mx51_ecspi_prepare_message,
+       .config = mx51_ecspi_config,
+       .trigger = mx51_ecspi_trigger,
+       .rx_available = mx51_ecspi_rx_available,
+@@ -952,6 +983,7 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = {
+ static struct spi_imx_devtype_data imx53_ecspi_devtype_data = {
+       .intctrl = mx51_ecspi_intctrl,
++      .prepare_message = mx51_ecspi_prepare_message,
+       .config = mx51_ecspi_config,
+       .trigger = mx51_ecspi_trigger,
+       .rx_available = mx51_ecspi_rx_available,
+@@ -1486,7 +1518,13 @@ spi_imx_prepare_message(struct spi_master *master, struct spi_message *msg)
+               return ret;
+       }
+-      return 0;
++      ret = spi_imx->devtype_data->prepare_message(spi_imx, msg);
++      if (ret) {
++              clk_disable(spi_imx->clk_ipg);
++              clk_disable(spi_imx->clk_per);
++      }
++
++      return ret;
+ }
+ static int
+-- 
+2.42.0
+
diff --git a/queue-4.19/spi-imx-correct-wml-as-the-last-sg-length.patch b/queue-4.19/spi-imx-correct-wml-as-the-last-sg-length.patch
new file mode 100644 (file)
index 0000000..2b7343b
--- /dev/null
@@ -0,0 +1,107 @@
+From 27dc9c921f14e759f83577ff923313fa05f6d032 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 10 Oct 2018 10:32:45 +0000
+Subject: spi: imx: correct wml as the last sg length
+
+From: Robin Gong <yibin.gong@nxp.com>
+
+[ Upstream commit 5ba5a3730639caddf42af11c60f3f3d99d9a5f00 ]
+
+Correct wml as the last rx sg length instead of the whole transfer
+length. Otherwise, mtd_stresstest will be failed as below:
+
+insmod mtd_stresstest.ko dev=0
+=================================================
+mtd_stresstest: MTD device: 0
+mtd_stresstest: not NAND flash, assume page size is 512 bytes.
+mtd_stresstest: MTD device size 4194304, eraseblock size 65536, page size 512, count of eraseblocks 64, pa0
+mtd_stresstest: doing operations
+mtd_stresstest: 0 operations done
+mtd_test: mtd_read from 1ff532, size 880
+mtd_test: mtd_read from 20c267, size 64998
+spi_master spi0: I/O Error in DMA RX
+m25p80 spi0.0: SPI transfer failed: -110
+spi_master spi0: failed to transfer one message from queue
+mtd_test: error: read failed at 0x20c267
+mtd_stresstest: error -110 occurred
+=================================================
+insmod: ERROR: could not insert module mtd_stresstest.ko: Connection timed out
+
+Signed-off-by: Robin Gong <yibin.gong@nxp.com>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Stable-dep-of: 00b80ac93553 ("spi: imx: mx51-ecspi: Move some initialisation to prepare_message hook.")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/spi/spi-imx.c | 29 +++++++++++++++++++----------
+ 1 file changed, 19 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
+index 686251e05edfe..139127e27a147 100644
+--- a/drivers/spi/spi-imx.c
++++ b/drivers/spi/spi-imx.c
+@@ -218,7 +218,6 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
+                        struct spi_transfer *transfer)
+ {
+       struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
+-      unsigned int bytes_per_word, i;
+       if (!master->dma_rx)
+               return false;
+@@ -226,14 +225,6 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
+       if (spi_imx->slave_mode)
+               return false;
+-      bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word);
+-
+-      for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) {
+-              if (!(transfer->len % (i * bytes_per_word)))
+-                      break;
+-      }
+-
+-      spi_imx->wml = i;
+       spi_imx->dynamic_burst = 0;
+       return true;
+@@ -612,7 +603,7 @@ static void mx51_setup_wml(struct spi_imx_data *spi_imx)
+        * and enable DMA request.
+        */
+-      writel(MX51_ECSPI_DMA_RX_WML(spi_imx->wml) |
++      writel(MX51_ECSPI_DMA_RX_WML(spi_imx->wml - 1) |
+               MX51_ECSPI_DMA_TX_WML(spi_imx->wml) |
+               MX51_ECSPI_DMA_RXT_WML(spi_imx->wml) |
+               MX51_ECSPI_DMA_TEDEN | MX51_ECSPI_DMA_RXDEN |
+@@ -1330,12 +1321,30 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
+       unsigned long timeout;
+       struct spi_master *master = spi_imx->bitbang.master;
+       struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg;
++      struct scatterlist *last_sg = sg_last(rx->sgl, rx->nents);
++      unsigned int bytes_per_word, i;
+       int ret;
++      /* Get the right burst length from the last sg to ensure no tail data */
++      bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word);
++      for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) {
++              if (!(sg_dma_len(last_sg) % (i * bytes_per_word)))
++                      break;
++      }
++      /* Use 1 as wml in case no available burst length got */
++      if (i == 0)
++              i = 1;
++
++      spi_imx->wml =  i;
++
+       ret = spi_imx_dma_configure(master);
+       if (ret)
+               return ret;
++      if (!spi_imx->devtype_data->setup_wml) {
++              dev_err(spi_imx->dev, "No setup_wml()?\n");
++              return -EINVAL;
++      }
+       spi_imx->devtype_data->setup_wml(spi_imx);
+       /*
+-- 
+2.42.0
+
diff --git a/queue-4.19/spi-imx-move-wml-setting-to-later-than-setup_transfe.patch b/queue-4.19/spi-imx-move-wml-setting-to-later-than-setup_transfe.patch
new file mode 100644 (file)
index 0000000..50738c1
--- /dev/null
@@ -0,0 +1,104 @@
+From 0391ed229fc995b3d20f5062507b3b4f20a59e83 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 10 Oct 2018 10:32:42 +0000
+Subject: spi: imx: move wml setting to later than setup_transfer
+
+From: Robin Gong <yibin.gong@nxp.com>
+
+[ Upstream commit 987a2dfe3f0485a82d87106e7e1c43f35c1d3b09 ]
+
+Current dynamic burst length is based on the whole transfer length,
+that's ok if there is only one sg, but is not right in case multi sgs
+in one transfer,because the tail data should be based on the last sg
+length instead of the whole transfer length. Move wml setting for DMA
+to the later place, thus, the next patch could get the right last sg
+length for wml setting. This patch is a preparation one, no any
+function change involved.
+
+Signed-off-by: Robin Gong <yibin.gong@nxp.com>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Stable-dep-of: 00b80ac93553 ("spi: imx: mx51-ecspi: Move some initialisation to prepare_message hook.")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/spi/spi-imx.c | 23 ++++++++++++++---------
+ 1 file changed, 14 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
+index eb27f47578eb9..686251e05edfe 100644
+--- a/drivers/spi/spi-imx.c
++++ b/drivers/spi/spi-imx.c
+@@ -64,6 +64,7 @@ struct spi_imx_devtype_data {
+       void (*trigger)(struct spi_imx_data *);
+       int (*rx_available)(struct spi_imx_data *);
+       void (*reset)(struct spi_imx_data *);
++      void (*setup_wml)(struct spi_imx_data *);
+       void (*disable)(struct spi_imx_data *);
+       bool has_dmamode;
+       bool has_slavemode;
+@@ -601,6 +602,11 @@ static int mx51_ecspi_config(struct spi_device *spi)
+       else                    /* SCLK is _very_ slow */
+               usleep_range(delay, delay + 10);
++      return 0;
++}
++
++static void mx51_setup_wml(struct spi_imx_data *spi_imx)
++{
+       /*
+        * Configure the DMA register: setup the watermark
+        * and enable DMA request.
+@@ -611,8 +617,6 @@ static int mx51_ecspi_config(struct spi_device *spi)
+               MX51_ECSPI_DMA_RXT_WML(spi_imx->wml) |
+               MX51_ECSPI_DMA_TEDEN | MX51_ECSPI_DMA_RXDEN |
+               MX51_ECSPI_DMA_RXTDEN, spi_imx->base + MX51_ECSPI_DMA);
+-
+-      return 0;
+ }
+ static int mx51_ecspi_rx_available(struct spi_imx_data *spi_imx)
+@@ -973,6 +977,7 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = {
+       .trigger = mx51_ecspi_trigger,
+       .rx_available = mx51_ecspi_rx_available,
+       .reset = mx51_ecspi_reset,
++      .setup_wml = mx51_setup_wml,
+       .fifo_size = 64,
+       .has_dmamode = true,
+       .dynamic_burst = true,
+@@ -1181,7 +1186,6 @@ static int spi_imx_setupxfer(struct spi_device *spi,
+                                struct spi_transfer *t)
+ {
+       struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
+-      int ret;
+       if (!t)
+               return 0;
+@@ -1222,12 +1226,6 @@ static int spi_imx_setupxfer(struct spi_device *spi,
+       else
+               spi_imx->usedma = 0;
+-      if (spi_imx->usedma) {
+-              ret = spi_imx_dma_configure(spi->master);
+-              if (ret)
+-                      return ret;
+-      }
+-
+       if (is_imx53_ecspi(spi_imx) && spi_imx->slave_mode) {
+               spi_imx->rx = mx53_ecspi_rx_slave;
+               spi_imx->tx = mx53_ecspi_tx_slave;
+@@ -1332,6 +1330,13 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
+       unsigned long timeout;
+       struct spi_master *master = spi_imx->bitbang.master;
+       struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg;
++      int ret;
++
++      ret = spi_imx_dma_configure(master);
++      if (ret)
++              return ret;
++
++      spi_imx->devtype_data->setup_wml(spi_imx);
+       /*
+        * The TX DMA setup starts the transfer, so make sure RX is configured
+-- 
+2.42.0
+
diff --git a/queue-4.19/spi-imx-mx51-ecspi-move-some-initialisation-to-prepa.patch b/queue-4.19/spi-imx-mx51-ecspi-move-some-initialisation-to-prepa.patch
new file mode 100644 (file)
index 0000000..c4411eb
--- /dev/null
@@ -0,0 +1,141 @@
+From 8b50c221ed0e63ba2a57a4bded321db6f9c689c0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 30 Nov 2018 07:47:06 +0100
+Subject: spi: imx: mx51-ecspi: Move some initialisation to prepare_message
+ hook.
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+
+[ Upstream commit 00b80ac9355397455adec24c9ee76f1b0225cd27 ]
+
+The relevant difference between prepare_message and config is that the
+former is run before the CS signal is asserted. So the polarity of the
+CLK line must be configured in prepare_message as an edge generated by
+config might already result in a latch of the MOSI line.
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/spi/spi-imx.c | 67 ++++++++++++++++++++++++++-----------------
+ 1 file changed, 40 insertions(+), 27 deletions(-)
+
+diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
+index 139127e27a147..0078cb365d8c2 100644
+--- a/drivers/spi/spi-imx.c
++++ b/drivers/spi/spi-imx.c
+@@ -498,14 +498,9 @@ static void mx51_ecspi_disable(struct spi_imx_data *spi_imx)
+ static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
+                                     struct spi_message *msg)
+ {
+-      return 0;
+-}
+-
+-static int mx51_ecspi_config(struct spi_device *spi)
+-{
+-      struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
++      struct spi_device *spi = msg->spi;
+       u32 ctrl = MX51_ECSPI_CTRL_ENABLE;
+-      u32 clk = spi_imx->speed_hz, delay, reg;
++      u32 testreg;
+       u32 cfg = readl(spi_imx->base + MX51_ECSPI_CONFIG);
+       /* set Master or Slave mode */
+@@ -520,19 +515,21 @@ static int mx51_ecspi_config(struct spi_device *spi)
+       if (spi->mode & SPI_READY)
+               ctrl |= MX51_ECSPI_CTRL_DRCTL(spi_imx->spi_drctl);
+-      /* set clock speed */
+-      ctrl |= mx51_ecspi_clkdiv(spi_imx, spi_imx->speed_hz, &clk);
+-      spi_imx->spi_bus_clk = clk;
+-
+       /* set chip select to use */
+       ctrl |= MX51_ECSPI_CTRL_CS(spi->chip_select);
+-      if (spi_imx->slave_mode && is_imx53_ecspi(spi_imx))
+-              ctrl |= (spi_imx->slave_burst * 8 - 1)
+-                      << MX51_ECSPI_CTRL_BL_OFFSET;
++      /*
++       * The ctrl register must be written first, with the EN bit set other
++       * registers must not be written to.
++       */
++      writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
++
++      testreg = readl(spi_imx->base + MX51_ECSPI_TESTREG);
++      if (spi->mode & SPI_LOOP)
++              testreg |= MX51_ECSPI_TESTREG_LBC;
+       else
+-              ctrl |= (spi_imx->bits_per_word - 1)
+-                      << MX51_ECSPI_CTRL_BL_OFFSET;
++              testreg &= ~MX51_ECSPI_TESTREG_LBC;
++      writel(testreg, spi_imx->base + MX51_ECSPI_TESTREG);
+       /*
+        * eCSPI burst completion by Chip Select signal in Slave mode
+@@ -556,25 +553,42 @@ static int mx51_ecspi_config(struct spi_device *spi)
+               cfg &= ~MX51_ECSPI_CONFIG_SCLKPOL(spi->chip_select);
+               cfg &= ~MX51_ECSPI_CONFIG_SCLKCTL(spi->chip_select);
+       }
++
+       if (spi->mode & SPI_CS_HIGH)
+               cfg |= MX51_ECSPI_CONFIG_SSBPOL(spi->chip_select);
+       else
+               cfg &= ~MX51_ECSPI_CONFIG_SSBPOL(spi->chip_select);
+-      if (spi_imx->usedma)
+-              ctrl |= MX51_ECSPI_CTRL_SMC;
++      writel(cfg, spi_imx->base + MX51_ECSPI_CONFIG);
+-      /* CTRL register always go first to bring out controller from reset */
+-      writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
++      return 0;
++}
+-      reg = readl(spi_imx->base + MX51_ECSPI_TESTREG);
+-      if (spi->mode & SPI_LOOP)
+-              reg |= MX51_ECSPI_TESTREG_LBC;
++static int mx51_ecspi_config(struct spi_device *spi)
++{
++      struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
++      u32 ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL);
++      u32 clk = spi_imx->speed_hz, delay;
++
++      /* Clear BL field and set the right value */
++      ctrl &= ~MX51_ECSPI_CTRL_BL_MASK;
++      if (spi_imx->slave_mode && is_imx53_ecspi(spi_imx))
++              ctrl |= (spi_imx->slave_burst * 8 - 1)
++                      << MX51_ECSPI_CTRL_BL_OFFSET;
+       else
+-              reg &= ~MX51_ECSPI_TESTREG_LBC;
+-      writel(reg, spi_imx->base + MX51_ECSPI_TESTREG);
++              ctrl |= (spi_imx->bits_per_word - 1)
++                      << MX51_ECSPI_CTRL_BL_OFFSET;
+-      writel(cfg, spi_imx->base + MX51_ECSPI_CONFIG);
++      /* set clock speed */
++      ctrl &= ~(0xf << MX51_ECSPI_CTRL_POSTDIV_OFFSET |
++                0xf << MX51_ECSPI_CTRL_PREDIV_OFFSET);
++      ctrl |= mx51_ecspi_clkdiv(spi_imx, spi_imx->speed_hz, &clk);
++      spi_imx->spi_bus_clk = clk;
++
++      if (spi_imx->usedma)
++              ctrl |= MX51_ECSPI_CTRL_SMC;
++
++      writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
+       /*
+        * Wait until the changes in the configuration register CONFIGREG
+@@ -602,7 +616,6 @@ static void mx51_setup_wml(struct spi_imx_data *spi_imx)
+        * Configure the DMA register: setup the watermark
+        * and enable DMA request.
+        */
+-
+       writel(MX51_ECSPI_DMA_RX_WML(spi_imx->wml - 1) |
+               MX51_ECSPI_DMA_TX_WML(spi_imx->wml) |
+               MX51_ECSPI_DMA_RXT_WML(spi_imx->wml) |
+-- 
+2.42.0
+
diff --git a/queue-4.19/tg3-increment-tx_dropped-in-tg3_tso_bug.patch b/queue-4.19/tg3-increment-tx_dropped-in-tg3_tso_bug.patch
new file mode 100644 (file)
index 0000000..3734bdc
--- /dev/null
@@ -0,0 +1,41 @@
+From 6cd6f9c23587b1a5dd272cb199168fbcdc49d896 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Nov 2023 10:23:50 -0800
+Subject: tg3: Increment tx_dropped in tg3_tso_bug()
+
+From: Alex Pakhunov <alexey.pakhunov@spacex.com>
+
+[ Upstream commit 17dd5efe5f36a96bd78012594fabe21efb01186b ]
+
+tg3_tso_bug() drops a packet if it cannot be segmented for any reason.
+The number of discarded frames should be incremented accordingly.
+
+Signed-off-by: Alex Pakhunov <alexey.pakhunov@spacex.com>
+Signed-off-by: Vincent Wong <vincent.wong2@spacex.com>
+Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Link: https://lore.kernel.org/r/20231113182350.37472-2-alexey.pakhunov@spacex.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/tg3.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
+index 84a5bddf614c8..68bb4a2ff7cee 100644
+--- a/drivers/net/ethernet/broadcom/tg3.c
++++ b/drivers/net/ethernet/broadcom/tg3.c
+@@ -7889,8 +7889,10 @@ static int tg3_tso_bug(struct tg3 *tp, struct tg3_napi *tnapi,
+       segs = skb_gso_segment(skb, tp->dev->features &
+                                   ~(NETIF_F_TSO | NETIF_F_TSO6));
+-      if (IS_ERR(segs) || !segs)
++      if (IS_ERR(segs) || !segs) {
++              tnapi->tx_dropped++;
+               goto tg3_tso_bug_end;
++      }
+       do {
+               nskb = segs;
+-- 
+2.42.0
+
diff --git a/queue-4.19/tg3-move-the-rt-x_dropped-counters-to-tg3_napi.patch b/queue-4.19/tg3-move-the-rt-x_dropped-counters-to-tg3_napi.patch
new file mode 100644 (file)
index 0000000..cfd4ca2
--- /dev/null
@@ -0,0 +1,139 @@
+From 1ad92b149ef06fd3a4adc6cc2703ce78cf3e65e4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Nov 2023 10:23:49 -0800
+Subject: tg3: Move the [rt]x_dropped counters to tg3_napi
+
+From: Alex Pakhunov <alexey.pakhunov@spacex.com>
+
+[ Upstream commit 907d1bdb8b2cc0357d03a1c34d2a08d9943760b1 ]
+
+This change moves [rt]x_dropped counters to tg3_napi so that they can be
+updated by a single writer, race-free.
+
+Signed-off-by: Alex Pakhunov <alexey.pakhunov@spacex.com>
+Signed-off-by: Vincent Wong <vincent.wong2@spacex.com>
+Reviewed-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://lore.kernel.org/r/20231113182350.37472-1-alexey.pakhunov@spacex.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/tg3.c | 38 +++++++++++++++++++++++++----
+ drivers/net/ethernet/broadcom/tg3.h |  4 +--
+ 2 files changed, 35 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
+index f0b5c8a4d29f5..84a5bddf614c8 100644
+--- a/drivers/net/ethernet/broadcom/tg3.c
++++ b/drivers/net/ethernet/broadcom/tg3.c
+@@ -6859,7 +6859,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
+                                      desc_idx, *post_ptr);
+               drop_it_no_recycle:
+                       /* Other statistics kept track of by card. */
+-                      tp->rx_dropped++;
++                      tnapi->rx_dropped++;
+                       goto next_pkt;
+               }
+@@ -8163,7 +8163,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ drop:
+       dev_kfree_skb_any(skb);
+ drop_nofree:
+-      tp->tx_dropped++;
++      tnapi->tx_dropped++;
+       return NETDEV_TX_OK;
+ }
+@@ -9342,7 +9342,7 @@ static void __tg3_set_rx_mode(struct net_device *);
+ /* tp->lock is held. */
+ static int tg3_halt(struct tg3 *tp, int kind, bool silent)
+ {
+-      int err;
++      int err, i;
+       tg3_stop_fw(tp);
+@@ -9363,6 +9363,13 @@ static int tg3_halt(struct tg3 *tp, int kind, bool silent)
+               /* And make sure the next sample is new data */
+               memset(tp->hw_stats, 0, sizeof(struct tg3_hw_stats));
++
++              for (i = 0; i < TG3_IRQ_MAX_VECS; ++i) {
++                      struct tg3_napi *tnapi = &tp->napi[i];
++
++                      tnapi->rx_dropped = 0;
++                      tnapi->tx_dropped = 0;
++              }
+       }
+       return err;
+@@ -11919,6 +11926,9 @@ static void tg3_get_nstats(struct tg3 *tp, struct rtnl_link_stats64 *stats)
+ {
+       struct rtnl_link_stats64 *old_stats = &tp->net_stats_prev;
+       struct tg3_hw_stats *hw_stats = tp->hw_stats;
++      unsigned long rx_dropped;
++      unsigned long tx_dropped;
++      int i;
+       stats->rx_packets = old_stats->rx_packets +
+               get_stat64(&hw_stats->rx_ucast_packets) +
+@@ -11965,8 +11975,26 @@ static void tg3_get_nstats(struct tg3 *tp, struct rtnl_link_stats64 *stats)
+       stats->rx_missed_errors = old_stats->rx_missed_errors +
+               get_stat64(&hw_stats->rx_discards);
+-      stats->rx_dropped = tp->rx_dropped;
+-      stats->tx_dropped = tp->tx_dropped;
++      /* Aggregate per-queue counters. The per-queue counters are updated
++       * by a single writer, race-free. The result computed by this loop
++       * might not be 100% accurate (counters can be updated in the middle of
++       * the loop) but the next tg3_get_nstats() will recompute the current
++       * value so it is acceptable.
++       *
++       * Note that these counters wrap around at 4G on 32bit machines.
++       */
++      rx_dropped = (unsigned long)(old_stats->rx_dropped);
++      tx_dropped = (unsigned long)(old_stats->tx_dropped);
++
++      for (i = 0; i < tp->irq_cnt; i++) {
++              struct tg3_napi *tnapi = &tp->napi[i];
++
++              rx_dropped += tnapi->rx_dropped;
++              tx_dropped += tnapi->tx_dropped;
++      }
++
++      stats->rx_dropped = rx_dropped;
++      stats->tx_dropped = tx_dropped;
+ }
+ static int tg3_get_regs_len(struct net_device *dev)
+diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h
+index a772a33b685c5..b8cc8ff4e8782 100644
+--- a/drivers/net/ethernet/broadcom/tg3.h
++++ b/drivers/net/ethernet/broadcom/tg3.h
+@@ -3018,6 +3018,7 @@ struct tg3_napi {
+       u16                             *rx_rcb_prod_idx;
+       struct tg3_rx_prodring_set      prodring;
+       struct tg3_rx_buffer_desc       *rx_rcb;
++      unsigned long                   rx_dropped;
+       u32                             tx_prod ____cacheline_aligned;
+       u32                             tx_cons;
+@@ -3026,6 +3027,7 @@ struct tg3_napi {
+       u32                             prodmbox;
+       struct tg3_tx_buffer_desc       *tx_ring;
+       struct tg3_tx_ring_info         *tx_buffers;
++      unsigned long                   tx_dropped;
+       dma_addr_t                      status_mapping;
+       dma_addr_t                      rx_rcb_mapping;
+@@ -3219,8 +3221,6 @@ struct tg3 {
+       /* begin "everything else" cacheline(s) section */
+-      unsigned long                   rx_dropped;
+-      unsigned long                   tx_dropped;
+       struct rtnl_link_stats64        net_stats_prev;
+       struct tg3_ethtool_stats        estats_prev;
+-- 
+2.42.0
+