]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 5.4
authorSasha Levin <sashal@kernel.org>
Mon, 17 Jun 2024 11:30:34 +0000 (07:30 -0400)
committerSasha Levin <sashal@kernel.org>
Mon, 17 Jun 2024 11:30:34 +0000 (07:30 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
24 files changed:
queue-5.4/bitops-introduce-the-for_each_set_clump8-macro.patch [new file with mode: 0644]
queue-5.4/bluetooth-l2cap-fix-rejecting-l2cap_conn_param_updat.patch [new file with mode: 0644]
queue-5.4/clk-sifive-do-not-register-clkdevs-for-prci-clocks.patch [new file with mode: 0644]
queue-5.4/clk-sifive-extract-prci-core-to-common-base.patch [new file with mode: 0644]
queue-5.4/drm-bridge-panel-fix-runtime-warning-on-panel-bridge.patch [new file with mode: 0644]
queue-5.4/drm-komeda-check-for-error-valued-pointer.patch [new file with mode: 0644]
queue-5.4/gpio-tqmx86-fix-typo-in-kconfig-label.patch [new file with mode: 0644]
queue-5.4/gpio-tqmx86-introduce-shadow-register-for-gpio-outpu.patch [new file with mode: 0644]
queue-5.4/gpio-tqmx86-remove-unneeded-call-to-platform_set_drv.patch [new file with mode: 0644]
queue-5.4/hid-core-remove-unnecessary-warn_on-in-implement.patch [new file with mode: 0644]
queue-5.4/hid-logitech-dj-fix-memory-leak-in-logi_dj_recv_swit.patch [new file with mode: 0644]
queue-5.4/iommu-amd-fix-sysfs-leak-in-iommu-init.patch [new file with mode: 0644]
queue-5.4/iommu-amd-introduce-pci-segment-structure.patch [new file with mode: 0644]
queue-5.4/iommu-amd-use-4k-page-for-completion-wait-write-back.patch [new file with mode: 0644]
queue-5.4/iommu-return-right-value-in-iommu_sva_bind_device.patch [new file with mode: 0644]
queue-5.4/ionic-fix-use-after-netif_napi_del.patch [new file with mode: 0644]
queue-5.4/liquidio-adjust-a-null-pointer-handling-path-in-lio_.patch [new file with mode: 0644]
queue-5.4/net-ipv6-fix-the-rt-cache-flush-via-sysctl-using-a-p.patch [new file with mode: 0644]
queue-5.4/net-mlx5e-fix-features-validation-check-for-tunneled.patch [new file with mode: 0644]
queue-5.4/netfilter-ipset-fix-race-between-namespace-cleanup-a.patch [new file with mode: 0644]
queue-5.4/netfilter-use-flowlabel-flow-key-when-re-routing-man.patch [new file with mode: 0644]
queue-5.4/series
queue-5.4/sunrpc-return-proper-error-from-gss_wrap_req_priv.patch [new file with mode: 0644]
queue-5.4/tcp-fix-race-in-tcp_v6_syn_recv_sock.patch [new file with mode: 0644]

diff --git a/queue-5.4/bitops-introduce-the-for_each_set_clump8-macro.patch b/queue-5.4/bitops-introduce-the-for_each_set_clump8-macro.patch
new file mode 100644 (file)
index 0000000..12c0cc5
--- /dev/null
@@ -0,0 +1,231 @@
+From c140c3bd62861ac1b796f37deabbc405e9112b17 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 4 Dec 2019 16:50:57 -0800
+Subject: bitops: introduce the for_each_set_clump8 macro
+
+From: William Breathitt Gray <vilhelm.gray@gmail.com>
+
+[ Upstream commit 169c474fb22d8a5e909e172f177b957546d0519d ]
+
+Pach series "Introduce the for_each_set_clump8 macro", v18.
+
+While adding GPIO get_multiple/set_multiple callback support for various
+drivers, I noticed a pattern of looping manifesting that would be useful
+standardized as a macro.
+
+This patchset introduces the for_each_set_clump8 macro and utilizes it
+in several GPIO drivers.  The for_each_set_clump macro8 facilitates a
+for-loop syntax that iterates over a memory region entire groups of set
+bits at a time.
+
+For example, suppose you would like to iterate over a 32-bit integer 8
+bits at a time, skipping over 8-bit groups with no set bit, where
+XXXXXXXX represents the current 8-bit group:
+
+    Example:        10111110 00000000 11111111 00110011
+    First loop:     10111110 00000000 11111111 XXXXXXXX
+    Second loop:    10111110 00000000 XXXXXXXX 00110011
+    Third loop:     XXXXXXXX 00000000 11111111 00110011
+
+Each iteration of the loop returns the next 8-bit group that has at
+least one set bit.
+
+The for_each_set_clump8 macro has four parameters:
+
+    * start: set to the bit offset of the current clump
+    * clump: set to the current clump value
+    * bits: bitmap to search within
+    * size: bitmap size in number of bits
+
+In this version of the patchset, the for_each_set_clump macro has been
+reimplemented and simplified based on the suggestions provided by Rasmus
+Villemoes and Andy Shevchenko in the version 4 submission.
+
+In particular, the function of the for_each_set_clump macro has been
+restricted to handle only 8-bit clumps; the drivers that use the
+for_each_set_clump macro only handle 8-bit ports so a generic
+for_each_set_clump implementation is not necessary.  Thus, a solution
+for large clumps (i.e.  those larger than the width of a bitmap word)
+can be postponed until a driver appears that actually requires such a
+generic for_each_set_clump implementation.
+
+For what it's worth, a semi-generic for_each_set_clump (i.e.  for clumps
+smaller than the width of a bitmap word) can be implemented by simply
+replacing the hardcoded '8' and '0xFF' instances with respective
+variables.  I have not yet had a need for such an implementation, and
+since it falls short of a true generic for_each_set_clump function, I
+have decided to forgo such an implementation for now.
+
+In addition, the bitmap_get_value8 and bitmap_set_value8 functions are
+introduced to get and set 8-bit values respectively.  Their use is based
+on the behavior suggested in the patchset version 4 review.
+
+This patch (of 14):
+
+This macro iterates for each 8-bit group of bits (clump) with set bits,
+within a bitmap memory region.  For each iteration, "start" is set to
+the bit offset of the found clump, while the respective clump value is
+stored to the location pointed by "clump".  Additionally, the
+bitmap_get_value8 and bitmap_set_value8 functions are introduced to
+respectively get and set an 8-bit value in a bitmap memory region.
+
+[gustavo@embeddedor.com: fix potential sign-extension overflow]
+  Link: http://lkml.kernel.org/r/20191015184657.GA26541@embeddedor
+[akpm@linux-foundation.org: s/ULL/UL/, per Joe]
+[vilhelm.gray@gmail.com: add for_each_set_clump8 documentation]
+  Link: http://lkml.kernel.org/r/20191016161825.301082-1-vilhelm.gray@gmail.com
+Link: http://lkml.kernel.org/r/893c3b4f03266c9496137cc98ac2b1bd27f92c73.1570641097.git.vilhelm.gray@gmail.com
+Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
+Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com>
+Suggested-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Suggested-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
+Suggested-by: Lukas Wunner <lukas@wunner.de>
+Tested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Cc: Linus Walleij <linus.walleij@linaro.org>
+Cc: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
+Cc: Geert Uytterhoeven <geert@linux-m68k.org>
+Cc: Phil Reid <preid@electromag.com.au>
+Cc: Geert Uytterhoeven <geert+renesas@glider.be>
+Cc: Mathias Duckeck <m.duckeck@kunbus.de>
+Cc: Morten Hein Tiljeset <morten.tiljeset@prevas.dk>
+Cc: Sean Nyekjaer <sean.nyekjaer@prevas.dk>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Stable-dep-of: 9d6a811b522b ("gpio: tqmx86: introduce shadow register for GPIO output value")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/asm-generic/bitops/find.h | 17 +++++++++++++++
+ include/linux/bitmap.h            | 35 +++++++++++++++++++++++++++++++
+ include/linux/bitops.h            | 12 +++++++++++
+ lib/find_bit.c                    | 14 +++++++++++++
+ 4 files changed, 78 insertions(+)
+
+diff --git a/include/asm-generic/bitops/find.h b/include/asm-generic/bitops/find.h
+index 8a1ee10014def..9fdf21302fdf3 100644
+--- a/include/asm-generic/bitops/find.h
++++ b/include/asm-generic/bitops/find.h
+@@ -80,4 +80,21 @@ extern unsigned long find_first_zero_bit(const unsigned long *addr,
+ #endif /* CONFIG_GENERIC_FIND_FIRST_BIT */
++/**
++ * find_next_clump8 - find next 8-bit clump with set bits in a memory region
++ * @clump: location to store copy of found clump
++ * @addr: address to base the search on
++ * @size: bitmap size in number of bits
++ * @offset: bit offset at which to start searching
++ *
++ * Returns the bit offset for the next set clump; the found clump value is
++ * copied to the location pointed by @clump. If no bits are set, returns @size.
++ */
++extern unsigned long find_next_clump8(unsigned long *clump,
++                                    const unsigned long *addr,
++                                    unsigned long size, unsigned long offset);
++
++#define find_first_clump8(clump, bits, size) \
++      find_next_clump8((clump), (bits), (size), 0)
++
+ #endif /*_ASM_GENERIC_BITOPS_FIND_H_ */
+diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h
+index 29fc933df3bf0..9f046609e8090 100644
+--- a/include/linux/bitmap.h
++++ b/include/linux/bitmap.h
+@@ -66,6 +66,8 @@
+  *  bitmap_allocate_region(bitmap, pos, order)  Allocate specified bit region
+  *  bitmap_from_arr32(dst, buf, nbits)          Copy nbits from u32[] buf to dst
+  *  bitmap_to_arr32(buf, src, nbits)            Copy nbits from buf to u32[] dst
++ *  bitmap_get_value8(map, start)               Get 8bit value from map at start
++ *  bitmap_set_value8(map, value, start)        Set 8bit value to map at start
+  *
+  * Note, bitmap_zero() and bitmap_fill() operate over the region of
+  * unsigned longs, that is, bits behind bitmap till the unsigned long
+@@ -489,6 +491,39 @@ static inline void bitmap_from_u64(unsigned long *dst, u64 mask)
+               dst[1] = mask >> 32;
+ }
++/**
++ * bitmap_get_value8 - get an 8-bit value within a memory region
++ * @map: address to the bitmap memory region
++ * @start: bit offset of the 8-bit value; must be a multiple of 8
++ *
++ * Returns the 8-bit value located at the @start bit offset within the @src
++ * memory region.
++ */
++static inline unsigned long bitmap_get_value8(const unsigned long *map,
++                                            unsigned long start)
++{
++      const size_t index = BIT_WORD(start);
++      const unsigned long offset = start % BITS_PER_LONG;
++
++      return (map[index] >> offset) & 0xFF;
++}
++
++/**
++ * bitmap_set_value8 - set an 8-bit value within a memory region
++ * @map: address to the bitmap memory region
++ * @value: the 8-bit value; values wider than 8 bits may clobber bitmap
++ * @start: bit offset of the 8-bit value; must be a multiple of 8
++ */
++static inline void bitmap_set_value8(unsigned long *map, unsigned long value,
++                                   unsigned long start)
++{
++      const size_t index = BIT_WORD(start);
++      const unsigned long offset = start % BITS_PER_LONG;
++
++      map[index] &= ~(0xFFUL << offset);
++      map[index] |= value << offset;
++}
++
+ #endif /* __ASSEMBLY__ */
+ #endif /* __LINUX_BITMAP_H */
+diff --git a/include/linux/bitops.h b/include/linux/bitops.h
+index e9e74af163fab..5e51d28b33f8d 100644
+--- a/include/linux/bitops.h
++++ b/include/linux/bitops.h
+@@ -48,6 +48,18 @@ extern unsigned long __sw_hweight64(__u64 w);
+            (bit) < (size);                                    \
+            (bit) = find_next_zero_bit((addr), (size), (bit) + 1))
++/**
++ * for_each_set_clump8 - iterate over bitmap for each 8-bit clump with set bits
++ * @start: bit offset to start search and to store the current iteration offset
++ * @clump: location to store copy of current 8-bit clump
++ * @bits: bitmap address to base the search on
++ * @size: bitmap size in number of bits
++ */
++#define for_each_set_clump8(start, clump, bits, size) \
++      for ((start) = find_first_clump8(&(clump), (bits), (size)); \
++           (start) < (size); \
++           (start) = find_next_clump8(&(clump), (bits), (size), (start) + 8))
++
+ static inline int get_bitmask_order(unsigned int count)
+ {
+       int order;
+diff --git a/lib/find_bit.c b/lib/find_bit.c
+index 4e68490fa7035..06e503c339f37 100644
+--- a/lib/find_bit.c
++++ b/lib/find_bit.c
+@@ -202,3 +202,17 @@ EXPORT_SYMBOL(find_next_bit_le);
+ #endif
+ #endif /* __BIG_ENDIAN */
++
++unsigned long find_next_clump8(unsigned long *clump, const unsigned long *addr,
++                             unsigned long size, unsigned long offset)
++{
++      offset = find_next_bit(addr, size, offset);
++      if (offset == size)
++              return size;
++
++      offset = round_down(offset, 8);
++      *clump = bitmap_get_value8(addr, offset);
++
++      return offset;
++}
++EXPORT_SYMBOL(find_next_clump8);
+-- 
+2.43.0
+
diff --git a/queue-5.4/bluetooth-l2cap-fix-rejecting-l2cap_conn_param_updat.patch b/queue-5.4/bluetooth-l2cap-fix-rejecting-l2cap_conn_param_updat.patch
new file mode 100644 (file)
index 0000000..569a744
--- /dev/null
@@ -0,0 +1,108 @@
+From bd7a017e7caae750488b32f3242330e6f881a8d2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 20 May 2024 16:03:07 -0400
+Subject: Bluetooth: L2CAP: Fix rejecting L2CAP_CONN_PARAM_UPDATE_REQ
+
+From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+
+[ Upstream commit 806a5198c05987b748b50f3d0c0cfb3d417381a4 ]
+
+This removes the bogus check for max > hcon->le_conn_max_interval since
+the later is just the initial maximum conn interval not the maximum the
+stack could support which is really 3200=4000ms.
+
+In order to pass GAP/CONN/CPUP/BV-05-C one shall probably enter values
+of the following fields in IXIT that would cause hci_check_conn_params
+to fail:
+
+TSPX_conn_update_int_min
+TSPX_conn_update_int_max
+TSPX_conn_update_peripheral_latency
+TSPX_conn_update_supervision_timeout
+
+Link: https://github.com/bluez/bluez/issues/847
+Fixes: e4b019515f95 ("Bluetooth: Enforce validation on max value of connection interval")
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/bluetooth/hci_core.h | 36 ++++++++++++++++++++++++++++----
+ net/bluetooth/l2cap_core.c       |  8 +------
+ 2 files changed, 33 insertions(+), 11 deletions(-)
+
+diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
+index 26983d26af197..6ba83a54dda7a 100644
+--- a/include/net/bluetooth/hci_core.h
++++ b/include/net/bluetooth/hci_core.h
+@@ -1451,18 +1451,46 @@ static inline int hci_check_conn_params(u16 min, u16 max, u16 latency,
+ {
+       u16 max_latency;
+-      if (min > max || min < 6 || max > 3200)
++      if (min > max) {
++              BT_WARN("min %d > max %d", min, max);
+               return -EINVAL;
++      }
++
++      if (min < 6) {
++              BT_WARN("min %d < 6", min);
++              return -EINVAL;
++      }
++
++      if (max > 3200) {
++              BT_WARN("max %d > 3200", max);
++              return -EINVAL;
++      }
++
++      if (to_multiplier < 10) {
++              BT_WARN("to_multiplier %d < 10", to_multiplier);
++              return -EINVAL;
++      }
+-      if (to_multiplier < 10 || to_multiplier > 3200)
++      if (to_multiplier > 3200) {
++              BT_WARN("to_multiplier %d > 3200", to_multiplier);
+               return -EINVAL;
++      }
+-      if (max >= to_multiplier * 8)
++      if (max >= to_multiplier * 8) {
++              BT_WARN("max %d >= to_multiplier %d * 8", max, to_multiplier);
+               return -EINVAL;
++      }
+       max_latency = (to_multiplier * 4 / max) - 1;
+-      if (latency > 499 || latency > max_latency)
++      if (latency > 499) {
++              BT_WARN("latency %d > 499", latency);
+               return -EINVAL;
++      }
++
++      if (latency > max_latency) {
++              BT_WARN("latency %d > max_latency %d", latency, max_latency);
++              return -EINVAL;
++      }
+       return 0;
+ }
+diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
+index 8709c4506343f..2eea802a9cb2f 100644
+--- a/net/bluetooth/l2cap_core.c
++++ b/net/bluetooth/l2cap_core.c
+@@ -5334,13 +5334,7 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
+       memset(&rsp, 0, sizeof(rsp));
+-      if (max > hcon->le_conn_max_interval) {
+-              BT_DBG("requested connection interval exceeds current bounds.");
+-              err = -EINVAL;
+-      } else {
+-              err = hci_check_conn_params(min, max, latency, to_multiplier);
+-      }
+-
++      err = hci_check_conn_params(min, max, latency, to_multiplier);
+       if (err)
+               rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
+       else
+-- 
+2.43.0
+
diff --git a/queue-5.4/clk-sifive-do-not-register-clkdevs-for-prci-clocks.patch b/queue-5.4/clk-sifive-do-not-register-clkdevs-for-prci-clocks.patch
new file mode 100644 (file)
index 0000000..642106f
--- /dev/null
@@ -0,0 +1,62 @@
+From b0091af68f4e670ec34dedc4d0a8b6abb5833e72 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 27 May 2024 17:14:12 -0700
+Subject: clk: sifive: Do not register clkdevs for PRCI clocks
+
+From: Samuel Holland <samuel.holland@sifive.com>
+
+[ Upstream commit 2607133196c35f31892ee199ce7ffa717bea4ad1 ]
+
+These clkdevs were unnecessary, because systems using this driver always
+look up clocks using the devicetree. And as Russell King points out[1],
+since the provided device name was truncated, lookups via clkdev would
+never match.
+
+Recently, commit 8d532528ff6a ("clkdev: report over-sized strings when
+creating clkdev entries") caused clkdev registration to fail due to the
+truncation, and this now prevents the driver from probing. Fix the
+driver by removing the clkdev registration.
+
+Link: https://lore.kernel.org/linux-clk/ZkfYqj+OcAxd9O2t@shell.armlinux.org.uk/ [1]
+Fixes: 30b8e27e3b58 ("clk: sifive: add a driver for the SiFive FU540 PRCI IP block")
+Fixes: 8d532528ff6a ("clkdev: report over-sized strings when creating clkdev entries")
+Reported-by: Guenter Roeck <linux@roeck-us.net>
+Closes: https://lore.kernel.org/linux-clk/7eda7621-0dde-4153-89e4-172e4c095d01@roeck-us.net/
+Suggested-by: Russell King <linux@armlinux.org.uk>
+Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
+Link: https://lore.kernel.org/r/20240528001432.1200403-1-samuel.holland@sifive.com
+Signed-off-by: Stephen Boyd <sboyd@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/clk/sifive/sifive-prci.c | 8 --------
+ 1 file changed, 8 deletions(-)
+
+diff --git a/drivers/clk/sifive/sifive-prci.c b/drivers/clk/sifive/sifive-prci.c
+index 70653d33f33fe..b043180ad3e5d 100644
+--- a/drivers/clk/sifive/sifive-prci.c
++++ b/drivers/clk/sifive/sifive-prci.c
+@@ -4,7 +4,6 @@
+  * Copyright (C) 2020 Zong Li
+  */
+-#include <linux/clkdev.h>
+ #include <linux/delay.h>
+ #include <linux/io.h>
+ #include <linux/of_device.h>
+@@ -317,13 +316,6 @@ static int __prci_register_clocks(struct device *dev, struct __prci_data *pd,
+                       return r;
+               }
+-              r = clk_hw_register_clkdev(&pic->hw, pic->name, dev_name(dev));
+-              if (r) {
+-                      dev_warn(dev, "Failed to register clkdev for %s: %d\n",
+-                               init.name, r);
+-                      return r;
+-              }
+-
+               pd->hw_clks.hws[i] = &pic->hw;
+       }
+-- 
+2.43.0
+
diff --git a/queue-5.4/clk-sifive-extract-prci-core-to-common-base.patch b/queue-5.4/clk-sifive-extract-prci-core-to-common-base.patch
new file mode 100644 (file)
index 0000000..f29d5e6
--- /dev/null
@@ -0,0 +1,1318 @@
+From baabbf2cda9ad8d5a6053f5aa8a006f06af32de8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 9 Dec 2020 17:49:12 +0800
+Subject: clk: sifive: Extract prci core to common base
+
+From: Zong Li <zong.li@sifive.com>
+
+[ Upstream commit c816e1ddf2b60b31d121118488c5a854d9a2fad9 ]
+
+Extract common core of prci driver to an independent file, it could
+allow other chips to reuse it. Separate SoCs-dependent code 'fu540'
+from prci core, then we can easily add 'fu740' later.
+
+Almost these changes are code movement. The different is adding the
+private data for each SoC use, so it needs to get match data in probe
+callback function, then use the data for initialization.
+
+Signed-off-by: Zong Li <zong.li@sifive.com>
+Reviewed-by: Pragnesh Patel <Pragnesh.patel@sifive.com>
+Acked-by: Palmer Dabbelt <palmerdabbelt@google.com>
+Link: https://lore.kernel.org/r/20201209094916.17383-2-zong.li@sifive.com
+[sboyd@kernel.org: Include header to silence sparse]
+Signed-off-by: Stephen Boyd <sboyd@kernel.org>
+Stable-dep-of: 2607133196c3 ("clk: sifive: Do not register clkdevs for PRCI clocks")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/clk/sifive/Makefile      |   2 +-
+ drivers/clk/sifive/fu540-prci.c  | 593 ++-----------------------------
+ drivers/clk/sifive/fu540-prci.h  |  21 ++
+ drivers/clk/sifive/sifive-prci.c | 395 ++++++++++++++++++++
+ drivers/clk/sifive/sifive-prci.h | 201 +++++++++++
+ 5 files changed, 641 insertions(+), 571 deletions(-)
+ create mode 100644 drivers/clk/sifive/fu540-prci.h
+ create mode 100644 drivers/clk/sifive/sifive-prci.c
+ create mode 100644 drivers/clk/sifive/sifive-prci.h
+
+diff --git a/drivers/clk/sifive/Makefile b/drivers/clk/sifive/Makefile
+index 0797f14fef6b6..51b6ebc359e44 100644
+--- a/drivers/clk/sifive/Makefile
++++ b/drivers/clk/sifive/Makefile
+@@ -1,2 +1,2 @@
+ # SPDX-License-Identifier: GPL-2.0-only
+-obj-$(CONFIG_CLK_SIFIVE_FU540_PRCI)   += fu540-prci.o
++obj-$(CONFIG_CLK_SIFIVE_FU540_PRCI)   += sifive-prci.o fu540-prci.o
+diff --git a/drivers/clk/sifive/fu540-prci.c b/drivers/clk/sifive/fu540-prci.c
+index a8901f90a61ac..83ced24b0b949 100644
+--- a/drivers/clk/sifive/fu540-prci.c
++++ b/drivers/clk/sifive/fu540-prci.c
+@@ -1,17 +1,9 @@
+ // SPDX-License-Identifier: GPL-2.0
+ /*
+  * Copyright (C) 2018-2019 SiFive, Inc.
+- * Wesley Terpstra
+- * Paul Walmsley
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License version 2 as
+- * published by the Free Software Foundation.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
++ * Copyright (C) 2018-2019 Wesley Terpstra
++ * Copyright (C) 2018-2019 Paul Walmsley
++ * Copyright (C) 2020 Zong Li
+  *
+  * The FU540 PRCI implements clock and reset control for the SiFive
+  * FU540-C000 chip.  This driver assumes that it has sole control
+@@ -24,464 +16,47 @@
+  * - SiFive FU540-C000 manual v1p0, Chapter 7 "Clocking and Reset"
+  */
+-#include <dt-bindings/clock/sifive-fu540-prci.h>
+-#include <linux/clkdev.h>
+-#include <linux/clk-provider.h>
+-#include <linux/clk/analogbits-wrpll-cln28hpc.h>
+-#include <linux/delay.h>
+-#include <linux/err.h>
+-#include <linux/io.h>
+ #include <linux/module.h>
+-#include <linux/of.h>
+-#include <linux/of_clk.h>
+-#include <linux/platform_device.h>
+-#include <linux/slab.h>
+-
+-/*
+- * EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects:
+- *     hfclk and rtcclk
+- */
+-#define EXPECTED_CLK_PARENT_COUNT             2
+-
+-/*
+- * Register offsets and bitmasks
+- */
+-
+-/* COREPLLCFG0 */
+-#define PRCI_COREPLLCFG0_OFFSET                       0x4
+-# define PRCI_COREPLLCFG0_DIVR_SHIFT          0
+-# define PRCI_COREPLLCFG0_DIVR_MASK           (0x3f << PRCI_COREPLLCFG0_DIVR_SHIFT)
+-# define PRCI_COREPLLCFG0_DIVF_SHIFT          6
+-# define PRCI_COREPLLCFG0_DIVF_MASK           (0x1ff << PRCI_COREPLLCFG0_DIVF_SHIFT)
+-# define PRCI_COREPLLCFG0_DIVQ_SHIFT          15
+-# define PRCI_COREPLLCFG0_DIVQ_MASK           (0x7 << PRCI_COREPLLCFG0_DIVQ_SHIFT)
+-# define PRCI_COREPLLCFG0_RANGE_SHIFT         18
+-# define PRCI_COREPLLCFG0_RANGE_MASK          (0x7 << PRCI_COREPLLCFG0_RANGE_SHIFT)
+-# define PRCI_COREPLLCFG0_BYPASS_SHIFT                24
+-# define PRCI_COREPLLCFG0_BYPASS_MASK         (0x1 << PRCI_COREPLLCFG0_BYPASS_SHIFT)
+-# define PRCI_COREPLLCFG0_FSE_SHIFT           25
+-# define PRCI_COREPLLCFG0_FSE_MASK            (0x1 << PRCI_COREPLLCFG0_FSE_SHIFT)
+-# define PRCI_COREPLLCFG0_LOCK_SHIFT          31
+-# define PRCI_COREPLLCFG0_LOCK_MASK           (0x1 << PRCI_COREPLLCFG0_LOCK_SHIFT)
+-/* DDRPLLCFG0 */
+-#define PRCI_DDRPLLCFG0_OFFSET                        0xc
+-# define PRCI_DDRPLLCFG0_DIVR_SHIFT           0
+-# define PRCI_DDRPLLCFG0_DIVR_MASK            (0x3f << PRCI_DDRPLLCFG0_DIVR_SHIFT)
+-# define PRCI_DDRPLLCFG0_DIVF_SHIFT           6
+-# define PRCI_DDRPLLCFG0_DIVF_MASK            (0x1ff << PRCI_DDRPLLCFG0_DIVF_SHIFT)
+-# define PRCI_DDRPLLCFG0_DIVQ_SHIFT           15
+-# define PRCI_DDRPLLCFG0_DIVQ_MASK            (0x7 << PRCI_DDRPLLCFG0_DIVQ_SHIFT)
+-# define PRCI_DDRPLLCFG0_RANGE_SHIFT          18
+-# define PRCI_DDRPLLCFG0_RANGE_MASK           (0x7 << PRCI_DDRPLLCFG0_RANGE_SHIFT)
+-# define PRCI_DDRPLLCFG0_BYPASS_SHIFT         24
+-# define PRCI_DDRPLLCFG0_BYPASS_MASK          (0x1 << PRCI_DDRPLLCFG0_BYPASS_SHIFT)
+-# define PRCI_DDRPLLCFG0_FSE_SHIFT            25
+-# define PRCI_DDRPLLCFG0_FSE_MASK             (0x1 << PRCI_DDRPLLCFG0_FSE_SHIFT)
+-# define PRCI_DDRPLLCFG0_LOCK_SHIFT           31
+-# define PRCI_DDRPLLCFG0_LOCK_MASK            (0x1 << PRCI_DDRPLLCFG0_LOCK_SHIFT)
+-
+-/* DDRPLLCFG1 */
+-#define PRCI_DDRPLLCFG1_OFFSET                        0x10
+-# define PRCI_DDRPLLCFG1_CKE_SHIFT            24
+-# define PRCI_DDRPLLCFG1_CKE_MASK             (0x1 << PRCI_DDRPLLCFG1_CKE_SHIFT)
+-
+-/* GEMGXLPLLCFG0 */
+-#define PRCI_GEMGXLPLLCFG0_OFFSET             0x1c
+-# define PRCI_GEMGXLPLLCFG0_DIVR_SHIFT                0
+-# define PRCI_GEMGXLPLLCFG0_DIVR_MASK         (0x3f << PRCI_GEMGXLPLLCFG0_DIVR_SHIFT)
+-# define PRCI_GEMGXLPLLCFG0_DIVF_SHIFT                6
+-# define PRCI_GEMGXLPLLCFG0_DIVF_MASK         (0x1ff << PRCI_GEMGXLPLLCFG0_DIVF_SHIFT)
+-# define PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT                15
+-# define PRCI_GEMGXLPLLCFG0_DIVQ_MASK         (0x7 << PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT)
+-# define PRCI_GEMGXLPLLCFG0_RANGE_SHIFT               18
+-# define PRCI_GEMGXLPLLCFG0_RANGE_MASK                (0x7 << PRCI_GEMGXLPLLCFG0_RANGE_SHIFT)
+-# define PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT      24
+-# define PRCI_GEMGXLPLLCFG0_BYPASS_MASK               (0x1 << PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT)
+-# define PRCI_GEMGXLPLLCFG0_FSE_SHIFT         25
+-# define PRCI_GEMGXLPLLCFG0_FSE_MASK          (0x1 << PRCI_GEMGXLPLLCFG0_FSE_SHIFT)
+-# define PRCI_GEMGXLPLLCFG0_LOCK_SHIFT                31
+-# define PRCI_GEMGXLPLLCFG0_LOCK_MASK         (0x1 << PRCI_GEMGXLPLLCFG0_LOCK_SHIFT)
+-
+-/* GEMGXLPLLCFG1 */
+-#define PRCI_GEMGXLPLLCFG1_OFFSET             0x20
+-# define PRCI_GEMGXLPLLCFG1_CKE_SHIFT         24
+-# define PRCI_GEMGXLPLLCFG1_CKE_MASK          (0x1 << PRCI_GEMGXLPLLCFG1_CKE_SHIFT)
+-
+-/* CORECLKSEL */
+-#define PRCI_CORECLKSEL_OFFSET                        0x24
+-# define PRCI_CORECLKSEL_CORECLKSEL_SHIFT     0
+-# define PRCI_CORECLKSEL_CORECLKSEL_MASK      (0x1 << PRCI_CORECLKSEL_CORECLKSEL_SHIFT)
+-
+-/* DEVICESRESETREG */
+-#define PRCI_DEVICESRESETREG_OFFSET                   0x28
+-# define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT    0
+-# define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_MASK     (0x1 << PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT)
+-# define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT     1
+-# define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_MASK      (0x1 << PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT)
+-# define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT     2
+-# define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_MASK      (0x1 << PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT)
+-# define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT     3
+-# define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_MASK      (0x1 << PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT)
+-# define PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT      5
+-# define PRCI_DEVICESRESETREG_GEMGXL_RST_N_MASK               (0x1 << PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT)
++#include <dt-bindings/clock/sifive-fu540-prci.h>
+-/* CLKMUXSTATUSREG */
+-#define PRCI_CLKMUXSTATUSREG_OFFSET                   0x2c
+-# define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT   1
+-# define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK    (0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT)
++#include "fu540-prci.h"
++#include "sifive-prci.h"
+-/*
+- * Private structures
+- */
++/* PRCI integration data for each WRPLL instance */
+-/**
+- * struct __prci_data - per-device-instance data
+- * @va: base virtual address of the PRCI IP block
+- * @hw_clks: encapsulates struct clk_hw records
+- *
+- * PRCI per-device instance data
+- */
+-struct __prci_data {
+-      void __iomem *va;
+-      struct clk_hw_onecell_data hw_clks;
++static struct __prci_wrpll_data __prci_corepll_data = {
++      .cfg0_offs = PRCI_COREPLLCFG0_OFFSET,
++      .enable_bypass = sifive_prci_coreclksel_use_hfclk,
++      .disable_bypass = sifive_prci_coreclksel_use_corepll,
+ };
+-/**
+- * struct __prci_wrpll_data - WRPLL configuration and integration data
+- * @c: WRPLL current configuration record
+- * @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL)
+- * @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL)
+- * @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address
+- *
+- * @enable_bypass and @disable_bypass are used for WRPLL instances
+- * that contain a separate external glitchless clock mux downstream
+- * from the PLL.  The WRPLL internal bypass mux is not glitchless.
+- */
+-struct __prci_wrpll_data {
+-      struct wrpll_cfg c;
+-      void (*enable_bypass)(struct __prci_data *pd);
+-      void (*disable_bypass)(struct __prci_data *pd);
+-      u8 cfg0_offs;
++static struct __prci_wrpll_data __prci_ddrpll_data = {
++      .cfg0_offs = PRCI_DDRPLLCFG0_OFFSET,
+ };
+-/**
+- * struct __prci_clock - describes a clock device managed by PRCI
+- * @name: user-readable clock name string - should match the manual
+- * @parent_name: parent name for this clock
+- * @ops: struct clk_ops for the Linux clock framework to use for control
+- * @hw: Linux-private clock data
+- * @pwd: WRPLL-specific data, associated with this clock (if not NULL)
+- * @pd: PRCI-specific data associated with this clock (if not NULL)
+- *
+- * PRCI clock data.  Used by the PRCI driver to register PRCI-provided
+- * clocks to the Linux clock infrastructure.
+- */
+-struct __prci_clock {
+-      const char *name;
+-      const char *parent_name;
+-      const struct clk_ops *ops;
+-      struct clk_hw hw;
+-      struct __prci_wrpll_data *pwd;
+-      struct __prci_data *pd;
++static struct __prci_wrpll_data __prci_gemgxlpll_data = {
++      .cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET,
+ };
+-#define clk_hw_to_prci_clock(pwd) container_of(pwd, struct __prci_clock, hw)
+-
+-/*
+- * Private functions
+- */
+-
+-/**
+- * __prci_readl() - read from a PRCI register
+- * @pd: PRCI context
+- * @offs: register offset to read from (in bytes, from PRCI base address)
+- *
+- * Read the register located at offset @offs from the base virtual
+- * address of the PRCI register target described by @pd, and return
+- * the value to the caller.
+- *
+- * Context: Any context.
+- *
+- * Return: the contents of the register described by @pd and @offs.
+- */
+-static u32 __prci_readl(struct __prci_data *pd, u32 offs)
+-{
+-      return readl_relaxed(pd->va + offs);
+-}
+-
+-static void __prci_writel(u32 v, u32 offs, struct __prci_data *pd)
+-{
+-      writel_relaxed(v, pd->va + offs);
+-}
+-
+-/* WRPLL-related private functions */
+-
+-/**
+- * __prci_wrpll_unpack() - unpack WRPLL configuration registers into parameters
+- * @c: ptr to a struct wrpll_cfg record to write config into
+- * @r: value read from the PRCI PLL configuration register
+- *
+- * Given a value @r read from an FU540 PRCI PLL configuration register,
+- * split it into fields and populate it into the WRPLL configuration record
+- * pointed to by @c.
+- *
+- * The COREPLLCFG0 macros are used below, but the other *PLLCFG0 macros
+- * have the same register layout.
+- *
+- * Context: Any context.
+- */
+-static void __prci_wrpll_unpack(struct wrpll_cfg *c, u32 r)
+-{
+-      u32 v;
+-
+-      v = r & PRCI_COREPLLCFG0_DIVR_MASK;
+-      v >>= PRCI_COREPLLCFG0_DIVR_SHIFT;
+-      c->divr = v;
+-
+-      v = r & PRCI_COREPLLCFG0_DIVF_MASK;
+-      v >>= PRCI_COREPLLCFG0_DIVF_SHIFT;
+-      c->divf = v;
+-
+-      v = r & PRCI_COREPLLCFG0_DIVQ_MASK;
+-      v >>= PRCI_COREPLLCFG0_DIVQ_SHIFT;
+-      c->divq = v;
+-
+-      v = r & PRCI_COREPLLCFG0_RANGE_MASK;
+-      v >>= PRCI_COREPLLCFG0_RANGE_SHIFT;
+-      c->range = v;
+-
+-      c->flags &= (WRPLL_FLAGS_INT_FEEDBACK_MASK |
+-                   WRPLL_FLAGS_EXT_FEEDBACK_MASK);
+-
+-      /* external feedback mode not supported */
+-      c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK;
+-}
+-
+-/**
+- * __prci_wrpll_pack() - pack PLL configuration parameters into a register value
+- * @c: pointer to a struct wrpll_cfg record containing the PLL's cfg
+- *
+- * Using a set of WRPLL configuration values pointed to by @c,
+- * assemble a PRCI PLL configuration register value, and return it to
+- * the caller.
+- *
+- * Context: Any context.  Caller must ensure that the contents of the
+- *          record pointed to by @c do not change during the execution
+- *          of this function.
+- *
+- * Returns: a value suitable for writing into a PRCI PLL configuration
+- *          register
+- */
+-static u32 __prci_wrpll_pack(const struct wrpll_cfg *c)
+-{
+-      u32 r = 0;
+-
+-      r |= c->divr << PRCI_COREPLLCFG0_DIVR_SHIFT;
+-      r |= c->divf << PRCI_COREPLLCFG0_DIVF_SHIFT;
+-      r |= c->divq << PRCI_COREPLLCFG0_DIVQ_SHIFT;
+-      r |= c->range << PRCI_COREPLLCFG0_RANGE_SHIFT;
+-
+-      /* external feedback mode not supported */
+-      r |= PRCI_COREPLLCFG0_FSE_MASK;
+-
+-      return r;
+-}
+-
+-/**
+- * __prci_wrpll_read_cfg() - read the WRPLL configuration from the PRCI
+- * @pd: PRCI context
+- * @pwd: PRCI WRPLL metadata
+- *
+- * Read the current configuration of the PLL identified by @pwd from
+- * the PRCI identified by @pd, and store it into the local configuration
+- * cache in @pwd.
+- *
+- * Context: Any context.  Caller must prevent the records pointed to by
+- *          @pd and @pwd from changing during execution.
+- */
+-static void __prci_wrpll_read_cfg(struct __prci_data *pd,
+-                                struct __prci_wrpll_data *pwd)
+-{
+-      __prci_wrpll_unpack(&pwd->c, __prci_readl(pd, pwd->cfg0_offs));
+-}
+-
+-/**
+- * __prci_wrpll_write_cfg() - write WRPLL configuration into the PRCI
+- * @pd: PRCI context
+- * @pwd: PRCI WRPLL metadata
+- * @c: WRPLL configuration record to write
+- *
+- * Write the WRPLL configuration described by @c into the WRPLL
+- * configuration register identified by @pwd in the PRCI instance
+- * described by @c.  Make a cached copy of the WRPLL's current
+- * configuration so it can be used by other code.
+- *
+- * Context: Any context.  Caller must prevent the records pointed to by
+- *          @pd and @pwd from changing during execution.
+- */
+-static void __prci_wrpll_write_cfg(struct __prci_data *pd,
+-                                 struct __prci_wrpll_data *pwd,
+-                                 struct wrpll_cfg *c)
+-{
+-      __prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd);
+-
+-      memcpy(&pwd->c, c, sizeof(*c));
+-}
+-
+-/* Core clock mux control */
+-
+-/**
+- * __prci_coreclksel_use_hfclk() - switch the CORECLK mux to output HFCLK
+- * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
+- *
+- * Switch the CORECLK mux to the HFCLK input source; return once complete.
+- *
+- * Context: Any context.  Caller must prevent concurrent changes to the
+- *          PRCI_CORECLKSEL_OFFSET register.
+- */
+-static void __prci_coreclksel_use_hfclk(struct __prci_data *pd)
+-{
+-      u32 r;
+-
+-      r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
+-      r |= PRCI_CORECLKSEL_CORECLKSEL_MASK;
+-      __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
+-
+-      r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */
+-}
+-
+-/**
+- * __prci_coreclksel_use_corepll() - switch the CORECLK mux to output COREPLL
+- * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
+- *
+- * Switch the CORECLK mux to the PLL output clock; return once complete.
+- *
+- * Context: Any context.  Caller must prevent concurrent changes to the
+- *          PRCI_CORECLKSEL_OFFSET register.
+- */
+-static void __prci_coreclksel_use_corepll(struct __prci_data *pd)
+-{
+-      u32 r;
+-
+-      r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
+-      r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK;
+-      __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
+-
+-      r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */
+-}
+-
+-/*
+- * Linux clock framework integration
+- *
+- * See the Linux clock framework documentation for more information on
+- * these functions.
+- */
+-
+-static unsigned long sifive_fu540_prci_wrpll_recalc_rate(struct clk_hw *hw,
+-                                                       unsigned long parent_rate)
+-{
+-      struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+-      struct __prci_wrpll_data *pwd = pc->pwd;
+-
+-      return wrpll_calc_output_rate(&pwd->c, parent_rate);
+-}
+-
+-static long sifive_fu540_prci_wrpll_round_rate(struct clk_hw *hw,
+-                                             unsigned long rate,
+-                                             unsigned long *parent_rate)
+-{
+-      struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+-      struct __prci_wrpll_data *pwd = pc->pwd;
+-      struct wrpll_cfg c;
+-
+-      memcpy(&c, &pwd->c, sizeof(c));
+-
+-      wrpll_configure_for_rate(&c, rate, *parent_rate);
+-
+-      return wrpll_calc_output_rate(&c, *parent_rate);
+-}
+-
+-static int sifive_fu540_prci_wrpll_set_rate(struct clk_hw *hw,
+-                                          unsigned long rate,
+-                                          unsigned long parent_rate)
+-{
+-      struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+-      struct __prci_wrpll_data *pwd = pc->pwd;
+-      struct __prci_data *pd = pc->pd;
+-      int r;
+-
+-      r = wrpll_configure_for_rate(&pwd->c, rate, parent_rate);
+-      if (r)
+-              return r;
+-
+-      if (pwd->enable_bypass)
+-              pwd->enable_bypass(pd);
+-
+-      __prci_wrpll_write_cfg(pd, pwd, &pwd->c);
+-
+-      udelay(wrpll_calc_max_lock_us(&pwd->c));
+-
+-      if (pwd->disable_bypass)
+-              pwd->disable_bypass(pd);
+-
+-      return 0;
+-}
++/* Linux clock framework integration */
+ static const struct clk_ops sifive_fu540_prci_wrpll_clk_ops = {
+-      .set_rate = sifive_fu540_prci_wrpll_set_rate,
+-      .round_rate = sifive_fu540_prci_wrpll_round_rate,
+-      .recalc_rate = sifive_fu540_prci_wrpll_recalc_rate,
++      .set_rate = sifive_prci_wrpll_set_rate,
++      .round_rate = sifive_prci_wrpll_round_rate,
++      .recalc_rate = sifive_prci_wrpll_recalc_rate,
+ };
+ static const struct clk_ops sifive_fu540_prci_wrpll_ro_clk_ops = {
+-      .recalc_rate = sifive_fu540_prci_wrpll_recalc_rate,
++      .recalc_rate = sifive_prci_wrpll_recalc_rate,
+ };
+-/* TLCLKSEL clock integration */
+-
+-static unsigned long sifive_fu540_prci_tlclksel_recalc_rate(struct clk_hw *hw,
+-                                                          unsigned long parent_rate)
+-{
+-      struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
+-      struct __prci_data *pd = pc->pd;
+-      u32 v;
+-      u8 div;
+-
+-      v = __prci_readl(pd, PRCI_CLKMUXSTATUSREG_OFFSET);
+-      v &= PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK;
+-      div = v ? 1 : 2;
+-
+-      return div_u64(parent_rate, div);
+-}
+-
+ static const struct clk_ops sifive_fu540_prci_tlclksel_clk_ops = {
+-      .recalc_rate = sifive_fu540_prci_tlclksel_recalc_rate,
+-};
+-
+-/*
+- * PRCI integration data for each WRPLL instance
+- */
+-
+-static struct __prci_wrpll_data __prci_corepll_data = {
+-      .cfg0_offs = PRCI_COREPLLCFG0_OFFSET,
+-      .enable_bypass = __prci_coreclksel_use_hfclk,
+-      .disable_bypass = __prci_coreclksel_use_corepll,
+-};
+-
+-static struct __prci_wrpll_data __prci_ddrpll_data = {
+-      .cfg0_offs = PRCI_DDRPLLCFG0_OFFSET,
++      .recalc_rate = sifive_prci_tlclksel_recalc_rate,
+ };
+-static struct __prci_wrpll_data __prci_gemgxlpll_data = {
+-      .cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET,
+-};
+-
+-/*
+- * List of clock controls provided by the PRCI
+- */
+-
+-static struct __prci_clock __prci_init_clocks[] = {
++/* List of clock controls provided by the PRCI */
++struct __prci_clock __prci_init_clocks_fu540[] = {
+       [PRCI_CLK_COREPLL] = {
+               .name = "corepll",
+               .parent_name = "hfclk",
+@@ -506,125 +81,3 @@ static struct __prci_clock __prci_init_clocks[] = {
+               .ops = &sifive_fu540_prci_tlclksel_clk_ops,
+       },
+ };
+-
+-/**
+- * __prci_register_clocks() - register clock controls in the PRCI with Linux
+- * @dev: Linux struct device *
+- *
+- * Register the list of clock controls described in __prci_init_plls[] with
+- * the Linux clock framework.
+- *
+- * Return: 0 upon success or a negative error code upon failure.
+- */
+-static int __prci_register_clocks(struct device *dev, struct __prci_data *pd)
+-{
+-      struct clk_init_data init = { };
+-      struct __prci_clock *pic;
+-      int parent_count, i, r;
+-
+-      parent_count = of_clk_get_parent_count(dev->of_node);
+-      if (parent_count != EXPECTED_CLK_PARENT_COUNT) {
+-              dev_err(dev, "expected only two parent clocks, found %d\n",
+-                      parent_count);
+-              return -EINVAL;
+-      }
+-
+-      /* Register PLLs */
+-      for (i = 0; i < ARRAY_SIZE(__prci_init_clocks); ++i) {
+-              pic = &__prci_init_clocks[i];
+-
+-              init.name = pic->name;
+-              init.parent_names = &pic->parent_name;
+-              init.num_parents = 1;
+-              init.ops = pic->ops;
+-              pic->hw.init = &init;
+-
+-              pic->pd = pd;
+-
+-              if (pic->pwd)
+-                      __prci_wrpll_read_cfg(pd, pic->pwd);
+-
+-              r = devm_clk_hw_register(dev, &pic->hw);
+-              if (r) {
+-                      dev_warn(dev, "Failed to register clock %s: %d\n",
+-                               init.name, r);
+-                      return r;
+-              }
+-
+-              r = clk_hw_register_clkdev(&pic->hw, pic->name, dev_name(dev));
+-              if (r) {
+-                      dev_warn(dev, "Failed to register clkdev for %s: %d\n",
+-                               init.name, r);
+-                      return r;
+-              }
+-
+-              pd->hw_clks.hws[i] = &pic->hw;
+-      }
+-
+-      pd->hw_clks.num = i;
+-
+-      r = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
+-                                      &pd->hw_clks);
+-      if (r) {
+-              dev_err(dev, "could not add hw_provider: %d\n", r);
+-              return r;
+-      }
+-
+-      return 0;
+-}
+-
+-/*
+- * Linux device model integration
+- *
+- * See the Linux device model documentation for more information about
+- * these functions.
+- */
+-static int sifive_fu540_prci_probe(struct platform_device *pdev)
+-{
+-      struct device *dev = &pdev->dev;
+-      struct resource *res;
+-      struct __prci_data *pd;
+-      int r;
+-
+-      pd = devm_kzalloc(dev,
+-                        struct_size(pd, hw_clks.hws,
+-                                    ARRAY_SIZE(__prci_init_clocks)),
+-                        GFP_KERNEL);
+-      if (!pd)
+-              return -ENOMEM;
+-
+-      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-      pd->va = devm_ioremap_resource(dev, res);
+-      if (IS_ERR(pd->va))
+-              return PTR_ERR(pd->va);
+-
+-      r = __prci_register_clocks(dev, pd);
+-      if (r) {
+-              dev_err(dev, "could not register clocks: %d\n", r);
+-              return r;
+-      }
+-
+-      dev_dbg(dev, "SiFive FU540 PRCI probed\n");
+-
+-      return 0;
+-}
+-
+-static const struct of_device_id sifive_fu540_prci_of_match[] = {
+-      { .compatible = "sifive,fu540-c000-prci", },
+-      {}
+-};
+-MODULE_DEVICE_TABLE(of, sifive_fu540_prci_of_match);
+-
+-static struct platform_driver sifive_fu540_prci_driver = {
+-      .driver = {
+-              .name = "sifive-fu540-prci",
+-              .of_match_table = sifive_fu540_prci_of_match,
+-      },
+-      .probe = sifive_fu540_prci_probe,
+-};
+-
+-static int __init sifive_fu540_prci_init(void)
+-{
+-      return platform_driver_register(&sifive_fu540_prci_driver);
+-}
+-core_initcall(sifive_fu540_prci_init);
+diff --git a/drivers/clk/sifive/fu540-prci.h b/drivers/clk/sifive/fu540-prci.h
+new file mode 100644
+index 0000000000000..c8271efa7bdc7
+--- /dev/null
++++ b/drivers/clk/sifive/fu540-prci.h
+@@ -0,0 +1,21 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2020 SiFive, Inc.
++ * Zong Li
++ */
++
++#ifndef __SIFIVE_CLK_FU540_PRCI_H
++#define __SIFIVE_CLK_FU540_PRCI_H
++
++#include "sifive-prci.h"
++
++#define NUM_CLOCK_FU540       4
++
++extern struct __prci_clock __prci_init_clocks_fu540[NUM_CLOCK_FU540];
++
++static const struct prci_clk_desc prci_clk_fu540 = {
++      .clks = __prci_init_clocks_fu540,
++      .num_clks = ARRAY_SIZE(__prci_init_clocks_fu540),
++};
++
++#endif /* __SIFIVE_CLK_FU540_PRCI_H */
+diff --git a/drivers/clk/sifive/sifive-prci.c b/drivers/clk/sifive/sifive-prci.c
+new file mode 100644
+index 0000000000000..70653d33f33fe
+--- /dev/null
++++ b/drivers/clk/sifive/sifive-prci.c
+@@ -0,0 +1,395 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2020 SiFive, Inc.
++ * Copyright (C) 2020 Zong Li
++ */
++
++#include <linux/clkdev.h>
++#include <linux/delay.h>
++#include <linux/io.h>
++#include <linux/of_device.h>
++#include "sifive-prci.h"
++#include "fu540-prci.h"
++
++/*
++ * Private functions
++ */
++
++/**
++ * __prci_readl() - read from a PRCI register
++ * @pd: PRCI context
++ * @offs: register offset to read from (in bytes, from PRCI base address)
++ *
++ * Read the register located at offset @offs from the base virtual
++ * address of the PRCI register target described by @pd, and return
++ * the value to the caller.
++ *
++ * Context: Any context.
++ *
++ * Return: the contents of the register described by @pd and @offs.
++ */
++static u32 __prci_readl(struct __prci_data *pd, u32 offs)
++{
++      return readl_relaxed(pd->va + offs);
++}
++
++static void __prci_writel(u32 v, u32 offs, struct __prci_data *pd)
++{
++      writel_relaxed(v, pd->va + offs);
++}
++
++/* WRPLL-related private functions */
++
++/**
++ * __prci_wrpll_unpack() - unpack WRPLL configuration registers into parameters
++ * @c: ptr to a struct wrpll_cfg record to write config into
++ * @r: value read from the PRCI PLL configuration register
++ *
++ * Given a value @r read from an FU740 PRCI PLL configuration register,
++ * split it into fields and populate it into the WRPLL configuration record
++ * pointed to by @c.
++ *
++ * The COREPLLCFG0 macros are used below, but the other *PLLCFG0 macros
++ * have the same register layout.
++ *
++ * Context: Any context.
++ */
++static void __prci_wrpll_unpack(struct wrpll_cfg *c, u32 r)
++{
++      u32 v;
++
++      v = r & PRCI_COREPLLCFG0_DIVR_MASK;
++      v >>= PRCI_COREPLLCFG0_DIVR_SHIFT;
++      c->divr = v;
++
++      v = r & PRCI_COREPLLCFG0_DIVF_MASK;
++      v >>= PRCI_COREPLLCFG0_DIVF_SHIFT;
++      c->divf = v;
++
++      v = r & PRCI_COREPLLCFG0_DIVQ_MASK;
++      v >>= PRCI_COREPLLCFG0_DIVQ_SHIFT;
++      c->divq = v;
++
++      v = r & PRCI_COREPLLCFG0_RANGE_MASK;
++      v >>= PRCI_COREPLLCFG0_RANGE_SHIFT;
++      c->range = v;
++
++      c->flags &=
++          (WRPLL_FLAGS_INT_FEEDBACK_MASK | WRPLL_FLAGS_EXT_FEEDBACK_MASK);
++
++      /* external feedback mode not supported */
++      c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK;
++}
++
++/**
++ * __prci_wrpll_pack() - pack PLL configuration parameters into a register value
++ * @c: pointer to a struct wrpll_cfg record containing the PLL's cfg
++ *
++ * Using a set of WRPLL configuration values pointed to by @c,
++ * assemble a PRCI PLL configuration register value, and return it to
++ * the caller.
++ *
++ * Context: Any context.  Caller must ensure that the contents of the
++ *          record pointed to by @c do not change during the execution
++ *          of this function.
++ *
++ * Returns: a value suitable for writing into a PRCI PLL configuration
++ *          register
++ */
++static u32 __prci_wrpll_pack(const struct wrpll_cfg *c)
++{
++      u32 r = 0;
++
++      r |= c->divr << PRCI_COREPLLCFG0_DIVR_SHIFT;
++      r |= c->divf << PRCI_COREPLLCFG0_DIVF_SHIFT;
++      r |= c->divq << PRCI_COREPLLCFG0_DIVQ_SHIFT;
++      r |= c->range << PRCI_COREPLLCFG0_RANGE_SHIFT;
++
++      /* external feedback mode not supported */
++      r |= PRCI_COREPLLCFG0_FSE_MASK;
++
++      return r;
++}
++
++/**
++ * __prci_wrpll_read_cfg() - read the WRPLL configuration from the PRCI
++ * @pd: PRCI context
++ * @pwd: PRCI WRPLL metadata
++ *
++ * Read the current configuration of the PLL identified by @pwd from
++ * the PRCI identified by @pd, and store it into the local configuration
++ * cache in @pwd.
++ *
++ * Context: Any context.  Caller must prevent the records pointed to by
++ *          @pd and @pwd from changing during execution.
++ */
++static void __prci_wrpll_read_cfg(struct __prci_data *pd,
++                                struct __prci_wrpll_data *pwd)
++{
++      __prci_wrpll_unpack(&pwd->c, __prci_readl(pd, pwd->cfg0_offs));
++}
++
++/**
++ * __prci_wrpll_write_cfg() - write WRPLL configuration into the PRCI
++ * @pd: PRCI context
++ * @pwd: PRCI WRPLL metadata
++ * @c: WRPLL configuration record to write
++ *
++ * Write the WRPLL configuration described by @c into the WRPLL
++ * configuration register identified by @pwd in the PRCI instance
++ * described by @c.  Make a cached copy of the WRPLL's current
++ * configuration so it can be used by other code.
++ *
++ * Context: Any context.  Caller must prevent the records pointed to by
++ *          @pd and @pwd from changing during execution.
++ */
++static void __prci_wrpll_write_cfg(struct __prci_data *pd,
++                                 struct __prci_wrpll_data *pwd,
++                                 struct wrpll_cfg *c)
++{
++      __prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd);
++
++      memcpy(&pwd->c, c, sizeof(*c));
++}
++
++/*
++ * Linux clock framework integration
++ *
++ * See the Linux clock framework documentation for more information on
++ * these functions.
++ */
++
++unsigned long sifive_prci_wrpll_recalc_rate(struct clk_hw *hw,
++                                          unsigned long parent_rate)
++{
++      struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
++      struct __prci_wrpll_data *pwd = pc->pwd;
++
++      return wrpll_calc_output_rate(&pwd->c, parent_rate);
++}
++
++long sifive_prci_wrpll_round_rate(struct clk_hw *hw,
++                                unsigned long rate,
++                                unsigned long *parent_rate)
++{
++      struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
++      struct __prci_wrpll_data *pwd = pc->pwd;
++      struct wrpll_cfg c;
++
++      memcpy(&c, &pwd->c, sizeof(c));
++
++      wrpll_configure_for_rate(&c, rate, *parent_rate);
++
++      return wrpll_calc_output_rate(&c, *parent_rate);
++}
++
++int sifive_prci_wrpll_set_rate(struct clk_hw *hw,
++                             unsigned long rate, unsigned long parent_rate)
++{
++      struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
++      struct __prci_wrpll_data *pwd = pc->pwd;
++      struct __prci_data *pd = pc->pd;
++      int r;
++
++      r = wrpll_configure_for_rate(&pwd->c, rate, parent_rate);
++      if (r)
++              return r;
++
++      if (pwd->enable_bypass)
++              pwd->enable_bypass(pd);
++
++      __prci_wrpll_write_cfg(pd, pwd, &pwd->c);
++
++      udelay(wrpll_calc_max_lock_us(&pwd->c));
++
++      if (pwd->disable_bypass)
++              pwd->disable_bypass(pd);
++
++      return 0;
++}
++
++/* TLCLKSEL clock integration */
++
++unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw,
++                                             unsigned long parent_rate)
++{
++      struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
++      struct __prci_data *pd = pc->pd;
++      u32 v;
++      u8 div;
++
++      v = __prci_readl(pd, PRCI_CLKMUXSTATUSREG_OFFSET);
++      v &= PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK;
++      div = v ? 1 : 2;
++
++      return div_u64(parent_rate, div);
++}
++
++/*
++ * Core clock mux control
++ */
++
++/**
++ * sifive_prci_coreclksel_use_hfclk() - switch the CORECLK mux to output HFCLK
++ * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
++ *
++ * Switch the CORECLK mux to the HFCLK input source; return once complete.
++ *
++ * Context: Any context.  Caller must prevent concurrent changes to the
++ *          PRCI_CORECLKSEL_OFFSET register.
++ */
++void sifive_prci_coreclksel_use_hfclk(struct __prci_data *pd)
++{
++      u32 r;
++
++      r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
++      r |= PRCI_CORECLKSEL_CORECLKSEL_MASK;
++      __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
++
++      r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);   /* barrier */
++}
++
++/**
++ * sifive_prci_coreclksel_use_corepll() - switch the CORECLK mux to output
++ * COREPLL
++ * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
++ *
++ * Switch the CORECLK mux to the COREPLL output clock; return once complete.
++ *
++ * Context: Any context.  Caller must prevent concurrent changes to the
++ *          PRCI_CORECLKSEL_OFFSET register.
++ */
++void sifive_prci_coreclksel_use_corepll(struct __prci_data *pd)
++{
++      u32 r;
++
++      r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
++      r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK;
++      __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
++
++      r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);   /* barrier */
++}
++
++/**
++ * __prci_register_clocks() - register clock controls in the PRCI
++ * @dev: Linux struct device
++ * @pd: The pointer for PRCI per-device instance data
++ * @desc: The pointer for the information of clocks of each SoCs
++ *
++ * Register the list of clock controls described in __prci_init_clocks[] with
++ * the Linux clock framework.
++ *
++ * Return: 0 upon success or a negative error code upon failure.
++ */
++static int __prci_register_clocks(struct device *dev, struct __prci_data *pd,
++                                const struct prci_clk_desc *desc)
++{
++      struct clk_init_data init = { };
++      struct __prci_clock *pic;
++      int parent_count, i, r;
++
++      parent_count = of_clk_get_parent_count(dev->of_node);
++      if (parent_count != EXPECTED_CLK_PARENT_COUNT) {
++              dev_err(dev, "expected only two parent clocks, found %d\n",
++                      parent_count);
++              return -EINVAL;
++      }
++
++      /* Register PLLs */
++      for (i = 0; i < desc->num_clks; ++i) {
++              pic = &(desc->clks[i]);
++
++              init.name = pic->name;
++              init.parent_names = &pic->parent_name;
++              init.num_parents = 1;
++              init.ops = pic->ops;
++              pic->hw.init = &init;
++
++              pic->pd = pd;
++
++              if (pic->pwd)
++                      __prci_wrpll_read_cfg(pd, pic->pwd);
++
++              r = devm_clk_hw_register(dev, &pic->hw);
++              if (r) {
++                      dev_warn(dev, "Failed to register clock %s: %d\n",
++                               init.name, r);
++                      return r;
++              }
++
++              r = clk_hw_register_clkdev(&pic->hw, pic->name, dev_name(dev));
++              if (r) {
++                      dev_warn(dev, "Failed to register clkdev for %s: %d\n",
++                               init.name, r);
++                      return r;
++              }
++
++              pd->hw_clks.hws[i] = &pic->hw;
++      }
++
++      pd->hw_clks.num = i;
++
++      r = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
++                                      &pd->hw_clks);
++      if (r) {
++              dev_err(dev, "could not add hw_provider: %d\n", r);
++              return r;
++      }
++
++      return 0;
++}
++
++/**
++ * sifive_prci_init() - initialize prci data and check parent count
++ * @pdev: platform device pointer for the prci
++ *
++ * Return: 0 upon success or a negative error code upon failure.
++ */
++static int sifive_prci_probe(struct platform_device *pdev)
++{
++      struct device *dev = &pdev->dev;
++      struct resource *res;
++      struct __prci_data *pd;
++      const struct prci_clk_desc *desc;
++      int r;
++
++      desc = of_device_get_match_data(&pdev->dev);
++
++      pd = devm_kzalloc(dev, struct_size(pd, hw_clks.hws, desc->num_clks), GFP_KERNEL);
++      if (!pd)
++              return -ENOMEM;
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      pd->va = devm_ioremap_resource(dev, res);
++      if (IS_ERR(pd->va))
++              return PTR_ERR(pd->va);
++
++      r = __prci_register_clocks(dev, pd, desc);
++      if (r) {
++              dev_err(dev, "could not register clocks: %d\n", r);
++              return r;
++      }
++
++      dev_dbg(dev, "SiFive PRCI probed\n");
++
++      return 0;
++}
++
++static const struct of_device_id sifive_prci_of_match[] = {
++      {.compatible = "sifive,fu540-c000-prci", .data = &prci_clk_fu540},
++      {}
++};
++
++static struct platform_driver sifive_prci_driver = {
++      .driver = {
++              .name = "sifive-clk-prci",
++              .of_match_table = sifive_prci_of_match,
++      },
++      .probe = sifive_prci_probe,
++};
++
++static int __init sifive_prci_init(void)
++{
++      return platform_driver_register(&sifive_prci_driver);
++}
++core_initcall(sifive_prci_init);
+diff --git a/drivers/clk/sifive/sifive-prci.h b/drivers/clk/sifive/sifive-prci.h
+new file mode 100644
+index 0000000000000..280df63b4b928
+--- /dev/null
++++ b/drivers/clk/sifive/sifive-prci.h
+@@ -0,0 +1,201 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2018-2019 SiFive, Inc.
++ * Wesley Terpstra
++ * Paul Walmsley
++ * Zong Li
++ */
++
++#ifndef __SIFIVE_CLK_SIFIVE_PRCI_H
++#define __SIFIVE_CLK_SIFIVE_PRCI_H
++
++#include <linux/clk/analogbits-wrpll-cln28hpc.h>
++#include <linux/clk-provider.h>
++#include <linux/platform_device.h>
++
++/*
++ * EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects:
++ *     hfclk and rtcclk
++ */
++#define EXPECTED_CLK_PARENT_COUNT 2
++
++/*
++ * Register offsets and bitmasks
++ */
++
++/* COREPLLCFG0 */
++#define PRCI_COREPLLCFG0_OFFSET               0x4
++#define PRCI_COREPLLCFG0_DIVR_SHIFT   0
++#define PRCI_COREPLLCFG0_DIVR_MASK    (0x3f << PRCI_COREPLLCFG0_DIVR_SHIFT)
++#define PRCI_COREPLLCFG0_DIVF_SHIFT   6
++#define PRCI_COREPLLCFG0_DIVF_MASK    (0x1ff << PRCI_COREPLLCFG0_DIVF_SHIFT)
++#define PRCI_COREPLLCFG0_DIVQ_SHIFT   15
++#define PRCI_COREPLLCFG0_DIVQ_MASK    (0x7 << PRCI_COREPLLCFG0_DIVQ_SHIFT)
++#define PRCI_COREPLLCFG0_RANGE_SHIFT  18
++#define PRCI_COREPLLCFG0_RANGE_MASK   (0x7 << PRCI_COREPLLCFG0_RANGE_SHIFT)
++#define PRCI_COREPLLCFG0_BYPASS_SHIFT 24
++#define PRCI_COREPLLCFG0_BYPASS_MASK  (0x1 << PRCI_COREPLLCFG0_BYPASS_SHIFT)
++#define PRCI_COREPLLCFG0_FSE_SHIFT    25
++#define PRCI_COREPLLCFG0_FSE_MASK     (0x1 << PRCI_COREPLLCFG0_FSE_SHIFT)
++#define PRCI_COREPLLCFG0_LOCK_SHIFT   31
++#define PRCI_COREPLLCFG0_LOCK_MASK    (0x1 << PRCI_COREPLLCFG0_LOCK_SHIFT)
++
++/* DDRPLLCFG0 */
++#define PRCI_DDRPLLCFG0_OFFSET                0xc
++#define PRCI_DDRPLLCFG0_DIVR_SHIFT    0
++#define PRCI_DDRPLLCFG0_DIVR_MASK     (0x3f << PRCI_DDRPLLCFG0_DIVR_SHIFT)
++#define PRCI_DDRPLLCFG0_DIVF_SHIFT    6
++#define PRCI_DDRPLLCFG0_DIVF_MASK     (0x1ff << PRCI_DDRPLLCFG0_DIVF_SHIFT)
++#define PRCI_DDRPLLCFG0_DIVQ_SHIFT    15
++#define PRCI_DDRPLLCFG0_DIVQ_MASK     (0x7 << PRCI_DDRPLLCFG0_DIVQ_SHIFT)
++#define PRCI_DDRPLLCFG0_RANGE_SHIFT   18
++#define PRCI_DDRPLLCFG0_RANGE_MASK    (0x7 << PRCI_DDRPLLCFG0_RANGE_SHIFT)
++#define PRCI_DDRPLLCFG0_BYPASS_SHIFT  24
++#define PRCI_DDRPLLCFG0_BYPASS_MASK   (0x1 << PRCI_DDRPLLCFG0_BYPASS_SHIFT)
++#define PRCI_DDRPLLCFG0_FSE_SHIFT     25
++#define PRCI_DDRPLLCFG0_FSE_MASK      (0x1 << PRCI_DDRPLLCFG0_FSE_SHIFT)
++#define PRCI_DDRPLLCFG0_LOCK_SHIFT    31
++#define PRCI_DDRPLLCFG0_LOCK_MASK     (0x1 << PRCI_DDRPLLCFG0_LOCK_SHIFT)
++
++/* DDRPLLCFG1 */
++#define PRCI_DDRPLLCFG1_OFFSET                0x10
++#define PRCI_DDRPLLCFG1_CKE_SHIFT     24
++#define PRCI_DDRPLLCFG1_CKE_MASK      (0x1 << PRCI_DDRPLLCFG1_CKE_SHIFT)
++
++/* GEMGXLPLLCFG0 */
++#define PRCI_GEMGXLPLLCFG0_OFFSET     0x1c
++#define PRCI_GEMGXLPLLCFG0_DIVR_SHIFT 0
++#define PRCI_GEMGXLPLLCFG0_DIVR_MASK  (0x3f << PRCI_GEMGXLPLLCFG0_DIVR_SHIFT)
++#define PRCI_GEMGXLPLLCFG0_DIVF_SHIFT 6
++#define PRCI_GEMGXLPLLCFG0_DIVF_MASK  (0x1ff << PRCI_GEMGXLPLLCFG0_DIVF_SHIFT)
++#define PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT 15
++#define PRCI_GEMGXLPLLCFG0_DIVQ_MASK  (0x7 << PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT)
++#define PRCI_GEMGXLPLLCFG0_RANGE_SHIFT        18
++#define PRCI_GEMGXLPLLCFG0_RANGE_MASK (0x7 << PRCI_GEMGXLPLLCFG0_RANGE_SHIFT)
++#define PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT       24
++#define PRCI_GEMGXLPLLCFG0_BYPASS_MASK        (0x1 << PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT)
++#define PRCI_GEMGXLPLLCFG0_FSE_SHIFT  25
++#define PRCI_GEMGXLPLLCFG0_FSE_MASK   (0x1 << PRCI_GEMGXLPLLCFG0_FSE_SHIFT)
++#define PRCI_GEMGXLPLLCFG0_LOCK_SHIFT 31
++#define PRCI_GEMGXLPLLCFG0_LOCK_MASK  (0x1 << PRCI_GEMGXLPLLCFG0_LOCK_SHIFT)
++
++/* GEMGXLPLLCFG1 */
++#define PRCI_GEMGXLPLLCFG1_OFFSET     0x20
++#define PRCI_GEMGXLPLLCFG1_CKE_SHIFT  24
++#define PRCI_GEMGXLPLLCFG1_CKE_MASK   (0x1 << PRCI_GEMGXLPLLCFG1_CKE_SHIFT)
++
++/* CORECLKSEL */
++#define PRCI_CORECLKSEL_OFFSET                        0x24
++#define PRCI_CORECLKSEL_CORECLKSEL_SHIFT      0
++#define PRCI_CORECLKSEL_CORECLKSEL_MASK                                       \
++              (0x1 << PRCI_CORECLKSEL_CORECLKSEL_SHIFT)
++
++/* DEVICESRESETREG */
++#define PRCI_DEVICESRESETREG_OFFSET                           0x28
++#define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT             0
++#define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_MASK                      \
++              (0x1 << PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT)
++#define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT              1
++#define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_MASK                               \
++              (0x1 << PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT)
++#define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT              2
++#define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_MASK                               \
++              (0x1 << PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT)
++#define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT              3
++#define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_MASK                               \
++              (0x1 << PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT)
++#define PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT                       5
++#define PRCI_DEVICESRESETREG_GEMGXL_RST_N_MASK                                \
++              (0x1 << PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT)
++#define PRCI_DEVICESRESETREG_CHIPLINK_RST_N_SHIFT             6
++#define PRCI_DEVICESRESETREG_CHIPLINK_RST_N_MASK                      \
++              (0x1 << PRCI_DEVICESRESETREG_CHIPLINK_RST_N_SHIFT)
++
++/* CLKMUXSTATUSREG */
++#define PRCI_CLKMUXSTATUSREG_OFFSET                           0x2c
++#define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT            1
++#define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK                     \
++              (0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT)
++
++/*
++ * Private structures
++ */
++
++/**
++ * struct __prci_data - per-device-instance data
++ * @va: base virtual address of the PRCI IP block
++ * @hw_clks: encapsulates struct clk_hw records
++ *
++ * PRCI per-device instance data
++ */
++struct __prci_data {
++      void __iomem *va;
++      struct clk_hw_onecell_data hw_clks;
++};
++
++/**
++ * struct __prci_wrpll_data - WRPLL configuration and integration data
++ * @c: WRPLL current configuration record
++ * @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL)
++ * @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL)
++ * @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address
++ *
++ * @enable_bypass and @disable_bypass are used for WRPLL instances
++ * that contain a separate external glitchless clock mux downstream
++ * from the PLL.  The WRPLL internal bypass mux is not glitchless.
++ */
++struct __prci_wrpll_data {
++      struct wrpll_cfg c;
++      void (*enable_bypass)(struct __prci_data *pd);
++      void (*disable_bypass)(struct __prci_data *pd);
++      u8 cfg0_offs;
++};
++
++/**
++ * struct __prci_clock - describes a clock device managed by PRCI
++ * @name: user-readable clock name string - should match the manual
++ * @parent_name: parent name for this clock
++ * @ops: struct clk_ops for the Linux clock framework to use for control
++ * @hw: Linux-private clock data
++ * @pwd: WRPLL-specific data, associated with this clock (if not NULL)
++ * @pd: PRCI-specific data associated with this clock (if not NULL)
++ *
++ * PRCI clock data.  Used by the PRCI driver to register PRCI-provided
++ * clocks to the Linux clock infrastructure.
++ */
++struct __prci_clock {
++      const char *name;
++      const char *parent_name;
++      const struct clk_ops *ops;
++      struct clk_hw hw;
++      struct __prci_wrpll_data *pwd;
++      struct __prci_data *pd;
++};
++
++#define clk_hw_to_prci_clock(pwd) container_of(pwd, struct __prci_clock, hw)
++
++/*
++ * struct prci_clk_desc - describes the information of clocks of each SoCs
++ * @clks: point to a array of __prci_clock
++ * @num_clks: the number of element of clks
++ */
++struct prci_clk_desc {
++      struct __prci_clock *clks;
++      size_t num_clks;
++};
++
++/* Core clock mux control */
++void sifive_prci_coreclksel_use_hfclk(struct __prci_data *pd);
++void sifive_prci_coreclksel_use_corepll(struct __prci_data *pd);
++
++/* Linux clock framework integration */
++long sifive_prci_wrpll_round_rate(struct clk_hw *hw, unsigned long rate,
++                                unsigned long *parent_rate);
++int sifive_prci_wrpll_set_rate(struct clk_hw *hw, unsigned long rate,
++                             unsigned long parent_rate);
++unsigned long sifive_prci_wrpll_recalc_rate(struct clk_hw *hw,
++                                          unsigned long parent_rate);
++unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw,
++                                             unsigned long parent_rate);
++
++#endif /* __SIFIVE_CLK_SIFIVE_PRCI_H */
+-- 
+2.43.0
+
diff --git a/queue-5.4/drm-bridge-panel-fix-runtime-warning-on-panel-bridge.patch b/queue-5.4/drm-bridge-panel-fix-runtime-warning-on-panel-bridge.patch
new file mode 100644 (file)
index 0000000..e8068b8
--- /dev/null
@@ -0,0 +1,51 @@
+From ec65bc6f7ba1471dbd167783e87d24e886f87d99 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Jun 2024 11:27:39 +0100
+Subject: drm/bridge/panel: Fix runtime warning on panel bridge release
+
+From: Adam Miotk <adam.miotk@arm.com>
+
+[ Upstream commit ce62600c4dbee8d43b02277669dd91785a9b81d9 ]
+
+Device managed panel bridge wrappers are created by calling to
+drm_panel_bridge_add_typed() and registering a release handler for
+clean-up when the device gets unbound.
+
+Since the memory for this bridge is also managed and linked to the panel
+device, the release function should not try to free that memory.
+Moreover, the call to devm_kfree() inside drm_panel_bridge_remove() will
+fail in this case and emit a warning because the panel bridge resource
+is no longer on the device resources list (it has been removed from
+there before the call to release handlers).
+
+Fixes: 67022227ffb1 ("drm/bridge: Add a devm_ allocator for panel bridge.")
+Signed-off-by: Adam Miotk <adam.miotk@arm.com>
+Signed-off-by: Maxime Ripard <mripard@kernel.org>
+Link: https://patchwork.freedesktop.org/patch/msgid/20240610102739.139852-1-adam.miotk@arm.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/bridge/panel.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
+index b12ae3a4c5f11..695dba0f018f8 100644
+--- a/drivers/gpu/drm/bridge/panel.c
++++ b/drivers/gpu/drm/bridge/panel.c
+@@ -203,9 +203,12 @@ EXPORT_SYMBOL(drm_panel_bridge_remove);
+ static void devm_drm_panel_bridge_release(struct device *dev, void *res)
+ {
+-      struct drm_bridge **bridge = res;
++      struct drm_bridge *bridge = *(struct drm_bridge **)res;
+-      drm_panel_bridge_remove(*bridge);
++      if (!bridge)
++              return;
++
++      drm_bridge_remove(bridge);
+ }
+ /**
+-- 
+2.43.0
+
diff --git a/queue-5.4/drm-komeda-check-for-error-valued-pointer.patch b/queue-5.4/drm-komeda-check-for-error-valued-pointer.patch
new file mode 100644 (file)
index 0000000..eafa1ad
--- /dev/null
@@ -0,0 +1,37 @@
+From 70fb9a548cd43d13eb1275b7f4195b9d11a438af Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Jun 2024 11:20:56 +0100
+Subject: drm/komeda: check for error-valued pointer
+
+From: Amjad Ouled-Ameur <amjad.ouled-ameur@arm.com>
+
+[ Upstream commit b880018edd3a577e50366338194dee9b899947e0 ]
+
+komeda_pipeline_get_state() may return an error-valued pointer, thus
+check the pointer for negative or null value before dereferencing.
+
+Fixes: 502932a03fce ("drm/komeda: Add the initial scaler support for CORE")
+Signed-off-by: Amjad Ouled-Ameur <amjad.ouled-ameur@arm.com>
+Signed-off-by: Maxime Ripard <mripard@kernel.org>
+Link: https://patchwork.freedesktop.org/patch/msgid/20240610102056.40406-1-amjad.ouled-ameur@arm.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
+index 31527fb66b5c5..c6c4847c6904c 100644
+--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
++++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
+@@ -259,7 +259,7 @@ komeda_component_get_avail_scaler(struct komeda_component *c,
+       u32 avail_scalers;
+       pipe_st = komeda_pipeline_get_state(c->pipeline, state);
+-      if (!pipe_st)
++      if (IS_ERR_OR_NULL(pipe_st))
+               return NULL;
+       avail_scalers = (pipe_st->active_comps & KOMEDA_PIPELINE_SCALERS) ^
+-- 
+2.43.0
+
diff --git a/queue-5.4/gpio-tqmx86-fix-typo-in-kconfig-label.patch b/queue-5.4/gpio-tqmx86-fix-typo-in-kconfig-label.patch
new file mode 100644 (file)
index 0000000..9d76499
--- /dev/null
@@ -0,0 +1,38 @@
+From 8ef7b91485bf945fbba92e07c8a83ddfd86523e5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 May 2024 12:19:59 +0200
+Subject: gpio: tqmx86: fix typo in Kconfig label
+
+From: Gregor Herburger <gregor.herburger@tq-group.com>
+
+[ Upstream commit 8c219e52ca4d9a67cd6a7074e91bf29b55edc075 ]
+
+Fix description for GPIO_TQMX86 from QTMX86 to TQMx86.
+
+Fixes: b868db94a6a7 ("gpio: tqmx86: Add GPIO from for this IO controller")
+Signed-off-by: Gregor Herburger <gregor.herburger@tq-group.com>
+Signed-off-by: Matthias Schiffer <matthias.schiffer@ew.tq-group.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Link: https://lore.kernel.org/r/e0e38c9944ad6d281d9a662a45d289b88edc808e.1717063994.git.matthias.schiffer@ew.tq-group.com
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpio/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
+index ae414045a7506..370065e7bd3ad 100644
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -1230,7 +1230,7 @@ config GPIO_TPS68470
+         drivers are loaded.
+ config GPIO_TQMX86
+-      tristate "TQ-Systems QTMX86 GPIO"
++      tristate "TQ-Systems TQMx86 GPIO"
+       depends on MFD_TQMX86 || COMPILE_TEST
+       depends on HAS_IOPORT_MAP
+       select GPIOLIB_IRQCHIP
+-- 
+2.43.0
+
diff --git a/queue-5.4/gpio-tqmx86-introduce-shadow-register-for-gpio-outpu.patch b/queue-5.4/gpio-tqmx86-introduce-shadow-register-for-gpio-outpu.patch
new file mode 100644 (file)
index 0000000..6df638e
--- /dev/null
@@ -0,0 +1,89 @@
+From 2cf382de1e1ac754e72c6cbbbf66868d99251b70 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 May 2024 12:20:00 +0200
+Subject: gpio: tqmx86: introduce shadow register for GPIO output value
+
+From: Matthias Schiffer <matthias.schiffer@ew.tq-group.com>
+
+[ Upstream commit 9d6a811b522ba558bcb4ec01d12e72a0af8e9f6e ]
+
+The TQMx86 GPIO controller uses the same register address for input and
+output data. Reading the register will always return current inputs
+rather than the previously set outputs (regardless of the current
+direction setting). Therefore, using a RMW pattern does not make sense
+when setting output values. Instead, the previously set output register
+value needs to be stored as a shadow register.
+
+As there is no reliable way to get the current output values from the
+hardware, also initialize all channels to 0, to ensure that stored and
+actual output values match. This should usually not have any effect in
+practise, as the TQMx86 UEFI sets all outputs to 0 during boot.
+
+Also prepare for extension of the driver to more than 8 GPIOs by using
+DECLARE_BITMAP.
+
+Fixes: b868db94a6a7 ("gpio: tqmx86: Add GPIO from for this IO controller")
+Signed-off-by: Matthias Schiffer <matthias.schiffer@ew.tq-group.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Link: https://lore.kernel.org/r/d0555933becd45fa92a85675d26e4d59343ddc01.1717063994.git.matthias.schiffer@ew.tq-group.com
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpio/gpio-tqmx86.c | 18 +++++++++++-------
+ 1 file changed, 11 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/gpio/gpio-tqmx86.c b/drivers/gpio/gpio-tqmx86.c
+index ea8b7c7f1fd45..d7b79f658faa6 100644
+--- a/drivers/gpio/gpio-tqmx86.c
++++ b/drivers/gpio/gpio-tqmx86.c
+@@ -6,6 +6,7 @@
+  *   Vadim V.Vlasov <vvlasov@dev.rtsoft.ru>
+  */
++#include <linux/bitmap.h>
+ #include <linux/bitops.h>
+ #include <linux/errno.h>
+ #include <linux/gpio/driver.h>
+@@ -38,6 +39,7 @@ struct tqmx86_gpio_data {
+       void __iomem            *io_base;
+       int                     irq;
+       raw_spinlock_t          spinlock;
++      DECLARE_BITMAP(output, TQMX86_NGPIO);
+       u8                      irq_type[TQMX86_NGPI];
+ };
+@@ -64,15 +66,10 @@ static void tqmx86_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ {
+       struct tqmx86_gpio_data *gpio = gpiochip_get_data(chip);
+       unsigned long flags;
+-      u8 val;
+       raw_spin_lock_irqsave(&gpio->spinlock, flags);
+-      val = tqmx86_gpio_read(gpio, TQMX86_GPIOD);
+-      if (value)
+-              val |= BIT(offset);
+-      else
+-              val &= ~BIT(offset);
+-      tqmx86_gpio_write(gpio, val, TQMX86_GPIOD);
++      __assign_bit(offset, gpio->output, value);
++      tqmx86_gpio_write(gpio, bitmap_get_value8(gpio->output, 0), TQMX86_GPIOD);
+       raw_spin_unlock_irqrestore(&gpio->spinlock, flags);
+ }
+@@ -258,6 +255,13 @@ static int tqmx86_gpio_probe(struct platform_device *pdev)
+       tqmx86_gpio_write(gpio, (u8)~TQMX86_DIR_INPUT_MASK, TQMX86_GPIODD);
++      /*
++       * Reading the previous output state is not possible with TQMx86 hardware.
++       * Initialize all outputs to 0 to have a defined state that matches the
++       * shadow register.
++       */
++      tqmx86_gpio_write(gpio, 0, TQMX86_GPIOD);
++
+       chip = &gpio->chip;
+       chip->label = "gpio-tqmx86";
+       chip->owner = THIS_MODULE;
+-- 
+2.43.0
+
diff --git a/queue-5.4/gpio-tqmx86-remove-unneeded-call-to-platform_set_drv.patch b/queue-5.4/gpio-tqmx86-remove-unneeded-call-to-platform_set_drv.patch
new file mode 100644 (file)
index 0000000..cab8dd8
--- /dev/null
@@ -0,0 +1,40 @@
+From 94b8455c2f62f874a6dfa7ef13b5ed732abbf90d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 1 Aug 2023 23:38:39 +0300
+Subject: gpio: tqmx86: remove unneeded call to platform_set_drvdata()
+
+From: Andrei Coardos <aboutphysycs@gmail.com>
+
+[ Upstream commit 0a5e9306b812fe3517548fab92b3d3d6ce7576e5 ]
+
+This function call was found to be unnecessary as there is no equivalent
+platform_get_drvdata() call to access the private data of the driver. Also,
+the private data is defined in this driver, so there is no risk of it being
+accessed outside of this driver file.
+
+Reviewed-by: Alexandru Ardelean <alex@shruggie.ro>
+Signed-off-by: Andrei Coardos <aboutphysycs@gmail.com>
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Stable-dep-of: 9d6a811b522b ("gpio: tqmx86: introduce shadow register for GPIO output value")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpio/gpio-tqmx86.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/drivers/gpio/gpio-tqmx86.c b/drivers/gpio/gpio-tqmx86.c
+index 09ca493b36176..ea8b7c7f1fd45 100644
+--- a/drivers/gpio/gpio-tqmx86.c
++++ b/drivers/gpio/gpio-tqmx86.c
+@@ -258,8 +258,6 @@ static int tqmx86_gpio_probe(struct platform_device *pdev)
+       tqmx86_gpio_write(gpio, (u8)~TQMX86_DIR_INPUT_MASK, TQMX86_GPIODD);
+-      platform_set_drvdata(pdev, gpio);
+-
+       chip = &gpio->chip;
+       chip->label = "gpio-tqmx86";
+       chip->owner = THIS_MODULE;
+-- 
+2.43.0
+
diff --git a/queue-5.4/hid-core-remove-unnecessary-warn_on-in-implement.patch b/queue-5.4/hid-core-remove-unnecessary-warn_on-in-implement.patch
new file mode 100644 (file)
index 0000000..642a706
--- /dev/null
@@ -0,0 +1,67 @@
+From 933d5d6d7ace6da46310b1503b2c73b6f4749f1b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 May 2024 07:19:14 -0700
+Subject: HID: core: remove unnecessary WARN_ON() in implement()
+
+From: Nikita Zhandarovich <n.zhandarovich@fintech.ru>
+
+[ Upstream commit 4aa2dcfbad538adf7becd0034a3754e1bd01b2b5 ]
+
+Syzkaller hit a warning [1] in a call to implement() when trying
+to write a value into a field of smaller size in an output report.
+
+Since implement() already has a warn message printed out with the
+help of hid_warn() and value in question gets trimmed with:
+       ...
+       value &= m;
+       ...
+WARN_ON may be considered superfluous. Remove it to suppress future
+syzkaller triggers.
+
+[1]
+WARNING: CPU: 0 PID: 5084 at drivers/hid/hid-core.c:1451 implement drivers/hid/hid-core.c:1451 [inline]
+WARNING: CPU: 0 PID: 5084 at drivers/hid/hid-core.c:1451 hid_output_report+0x548/0x760 drivers/hid/hid-core.c:1863
+Modules linked in:
+CPU: 0 PID: 5084 Comm: syz-executor424 Not tainted 6.9.0-rc7-syzkaller-00183-gcf87f46fd34d #0
+Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 04/02/2024
+RIP: 0010:implement drivers/hid/hid-core.c:1451 [inline]
+RIP: 0010:hid_output_report+0x548/0x760 drivers/hid/hid-core.c:1863
+...
+Call Trace:
+ <TASK>
+ __usbhid_submit_report drivers/hid/usbhid/hid-core.c:591 [inline]
+ usbhid_submit_report+0x43d/0x9e0 drivers/hid/usbhid/hid-core.c:636
+ hiddev_ioctl+0x138b/0x1f00 drivers/hid/usbhid/hiddev.c:726
+ vfs_ioctl fs/ioctl.c:51 [inline]
+ __do_sys_ioctl fs/ioctl.c:904 [inline]
+ __se_sys_ioctl+0xfc/0x170 fs/ioctl.c:890
+ do_syscall_x64 arch/x86/entry/common.c:52 [inline]
+ do_syscall_64+0xf5/0x240 arch/x86/entry/common.c:83
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+...
+
+Fixes: 95d1c8951e5b ("HID: simplify implement() a bit")
+Reported-by: <syzbot+5186630949e3c55f0799@syzkaller.appspotmail.com>
+Suggested-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Nikita Zhandarovich <n.zhandarovich@fintech.ru>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/hid-core.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
+index e0820feb7e19a..2462be8c4ae65 100644
+--- a/drivers/hid/hid-core.c
++++ b/drivers/hid/hid-core.c
+@@ -1439,7 +1439,6 @@ static void implement(const struct hid_device *hid, u8 *report,
+                       hid_warn(hid,
+                                "%s() called with too large value %d (n: %d)! (%s)\n",
+                                __func__, value, n, current->comm);
+-                      WARN_ON(1);
+                       value &= m;
+               }
+       }
+-- 
+2.43.0
+
diff --git a/queue-5.4/hid-logitech-dj-fix-memory-leak-in-logi_dj_recv_swit.patch b/queue-5.4/hid-logitech-dj-fix-memory-leak-in-logi_dj_recv_swit.patch
new file mode 100644 (file)
index 0000000..d06c5db
--- /dev/null
@@ -0,0 +1,41 @@
+From cec7b0fe4e1e0a5eadcb4e3e2165061cda99cb6e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 May 2024 15:05:39 +0200
+Subject: HID: logitech-dj: Fix memory leak in logi_dj_recv_switch_to_dj_mode()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: José Expósito <jose.exposito89@gmail.com>
+
+[ Upstream commit ce3af2ee95170b7d9e15fff6e500d67deab1e7b3 ]
+
+Fix a memory leak on logi_dj_recv_send_report() error path.
+
+Fixes: 6f20d3261265 ("HID: logitech-dj: Fix error handling in logi_dj_recv_switch_to_dj_mode()")
+Signed-off-by: José Expósito <jose.exposito89@gmail.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hid/hid-logitech-dj.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
+index 0c2aa9024b878..be19f299f9ec8 100644
+--- a/drivers/hid/hid-logitech-dj.c
++++ b/drivers/hid/hid-logitech-dj.c
+@@ -1213,8 +1213,10 @@ static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev,
+                */
+               msleep(50);
+-              if (retval)
++              if (retval) {
++                      kfree(dj_report);
+                       return retval;
++              }
+       }
+       /*
+-- 
+2.43.0
+
diff --git a/queue-5.4/iommu-amd-fix-sysfs-leak-in-iommu-init.patch b/queue-5.4/iommu-amd-fix-sysfs-leak-in-iommu-init.patch
new file mode 100644 (file)
index 0000000..23f8eac
--- /dev/null
@@ -0,0 +1,47 @@
+From b8fa99c8234efcb5289dc6f37784fbb4dba6ad05 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 May 2024 08:42:20 +0800
+Subject: iommu/amd: Fix sysfs leak in iommu init
+
+From: Kun(llfl) <llfl@linux.alibaba.com>
+
+[ Upstream commit a295ec52c8624883885396fde7b4df1a179627c3 ]
+
+During the iommu initialization, iommu_init_pci() adds sysfs nodes.
+However, these nodes aren't remove in free_iommu_resources() subsequently.
+
+Fixes: 39ab9555c241 ("iommu: Add sysfs bindings for struct iommu_device")
+Signed-off-by: Kun(llfl) <llfl@linux.alibaba.com>
+Reviewed-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
+Link: https://lore.kernel.org/r/c8e0d11c6ab1ee48299c288009cf9c5dae07b42d.1715215003.git.llfl@linux.alibaba.com
+Signed-off-by: Joerg Roedel <jroedel@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/amd_iommu_init.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
+index 7f3c0a1710baf..a7359e14d083f 100644
+--- a/drivers/iommu/amd_iommu_init.c
++++ b/drivers/iommu/amd_iommu_init.c
+@@ -1461,8 +1461,17 @@ static void __init free_pci_segments(void)
+       }
+ }
++static void __init free_sysfs(struct amd_iommu *iommu)
++{
++      if (iommu->iommu.dev) {
++              iommu_device_unregister(&iommu->iommu);
++              iommu_device_sysfs_remove(&iommu->iommu);
++      }
++}
++
+ static void __init free_iommu_one(struct amd_iommu *iommu)
+ {
++      free_sysfs(iommu);
+       free_cwwb_sem(iommu);
+       free_command_buffer(iommu);
+       free_event_buffer(iommu);
+-- 
+2.43.0
+
diff --git a/queue-5.4/iommu-amd-introduce-pci-segment-structure.patch b/queue-5.4/iommu-amd-introduce-pci-segment-structure.patch
new file mode 100644 (file)
index 0000000..834c407
--- /dev/null
@@ -0,0 +1,182 @@
+From bb34e2d8534a3f87874fd21e77e09e3c29b5a8d9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 6 Jul 2022 17:07:52 +0530
+Subject: iommu/amd: Introduce pci segment structure
+
+From: Vasant Hegde <vasant.hegde@amd.com>
+
+[ Upstream commit 404ec4e4c169fb64da6b2a38b471c13ac0897c76 ]
+
+Newer AMD systems can support multiple PCI segments, where each segment
+contains one or more IOMMU instances. However, an IOMMU instance can only
+support a single PCI segment.
+
+Current code assumes that system contains only one pci segment (segment 0)
+and creates global data structures such as device table, rlookup table,
+etc.
+
+Introducing per PCI segment data structure, which contains segment
+specific data structures. This will eventually replace the global
+data structures.
+
+Also update `amd_iommu->pci_seg` variable to point to PCI segment
+structure instead of PCI segment ID.
+
+Co-developed-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
+Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
+Signed-off-by: Vasant Hegde <vasant.hegde@amd.com>
+Link: https://lore.kernel.org/r/20220706113825.25582-3-vasant.hegde@amd.com
+Signed-off-by: Joerg Roedel <jroedel@suse.de>
+Stable-dep-of: a295ec52c862 ("iommu/amd: Fix sysfs leak in iommu init")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/amd_iommu_init.c  | 46 ++++++++++++++++++++++++++++++++-
+ drivers/iommu/amd_iommu_types.h | 24 ++++++++++++++++-
+ 2 files changed, 68 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
+index 4803b1750a620..7f3c0a1710baf 100644
+--- a/drivers/iommu/amd_iommu_init.c
++++ b/drivers/iommu/amd_iommu_init.c
+@@ -164,6 +164,7 @@ LIST_HEAD(amd_iommu_unity_map);            /* a list of required unity mappings
+                                          we find in ACPI */
+ bool amd_iommu_unmap_flush;           /* if true, flush on every unmap */
++LIST_HEAD(amd_iommu_pci_seg_list);    /* list of all PCI segments */
+ LIST_HEAD(amd_iommu_list);            /* list of all AMD IOMMUs in the
+                                          system */
+@@ -1423,6 +1424,43 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
+       return 0;
+ }
++/* Allocate PCI segment data structure */
++static struct amd_iommu_pci_seg *__init alloc_pci_segment(u16 id)
++{
++      struct amd_iommu_pci_seg *pci_seg;
++
++      pci_seg = kzalloc(sizeof(struct amd_iommu_pci_seg), GFP_KERNEL);
++      if (pci_seg == NULL)
++              return NULL;
++
++      pci_seg->id = id;
++      list_add_tail(&pci_seg->list, &amd_iommu_pci_seg_list);
++
++      return pci_seg;
++}
++
++static struct amd_iommu_pci_seg *__init get_pci_segment(u16 id)
++{
++      struct amd_iommu_pci_seg *pci_seg;
++
++      for_each_pci_segment(pci_seg) {
++              if (pci_seg->id == id)
++                      return pci_seg;
++      }
++
++      return alloc_pci_segment(id);
++}
++
++static void __init free_pci_segments(void)
++{
++      struct amd_iommu_pci_seg *pci_seg, *next;
++
++      for_each_pci_segment_safe(pci_seg, next) {
++              list_del(&pci_seg->list);
++              kfree(pci_seg);
++      }
++}
++
+ static void __init free_iommu_one(struct amd_iommu *iommu)
+ {
+       free_cwwb_sem(iommu);
+@@ -1509,8 +1547,14 @@ static void amd_iommu_ats_write_check_workaround(struct amd_iommu *iommu)
+  */
+ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
+ {
++      struct amd_iommu_pci_seg *pci_seg;
+       int ret;
++      pci_seg = get_pci_segment(h->pci_seg);
++      if (pci_seg == NULL)
++              return -ENOMEM;
++      iommu->pci_seg = pci_seg;
++
+       raw_spin_lock_init(&iommu->lock);
+       iommu->cmd_sem_val = 0;
+@@ -1531,7 +1575,6 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
+        */
+       iommu->devid   = h->devid;
+       iommu->cap_ptr = h->cap_ptr;
+-      iommu->pci_seg = h->pci_seg;
+       iommu->mmio_phys = h->mmio_phys;
+       switch (h->type) {
+@@ -2461,6 +2504,7 @@ static void __init free_iommu_resources(void)
+       amd_iommu_dev_table = NULL;
+       free_iommu_all();
++      free_pci_segments();
+ }
+ /* SB IOAPIC is always on this device in AMD systems */
+diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h
+index 036973a6655cb..d472937f995e5 100644
+--- a/drivers/iommu/amd_iommu_types.h
++++ b/drivers/iommu/amd_iommu_types.h
+@@ -427,6 +427,11 @@ extern bool amd_iommu_irq_remap;
+ /* kmem_cache to get tables with 128 byte alignement */
+ extern struct kmem_cache *amd_iommu_irq_cache;
++/* Make iterating over all pci segment easier */
++#define for_each_pci_segment(pci_seg) \
++      list_for_each_entry((pci_seg), &amd_iommu_pci_seg_list, list)
++#define for_each_pci_segment_safe(pci_seg, next) \
++      list_for_each_entry_safe((pci_seg), (next), &amd_iommu_pci_seg_list, list)
+ /*
+  * Make iterating over all IOMMUs easier
+  */
+@@ -483,6 +488,17 @@ struct protection_domain {
+       unsigned dev_iommu[MAX_IOMMUS]; /* per-IOMMU reference count */
+ };
++/*
++ * This structure contains information about one PCI segment in the system.
++ */
++struct amd_iommu_pci_seg {
++      /* List with all PCI segments in the system */
++      struct list_head list;
++
++      /* PCI segment number */
++      u16 id;
++};
++
+ /*
+  * Structure where we save information about one hardware AMD IOMMU in the
+  * system.
+@@ -534,7 +550,7 @@ struct amd_iommu {
+       u16 cap_ptr;
+       /* pci domain of this IOMMU */
+-      u16 pci_seg;
++      struct amd_iommu_pci_seg *pci_seg;
+       /* start of exclusion range of that IOMMU */
+       u64 exclusion_start;
+@@ -666,6 +682,12 @@ extern struct list_head ioapic_map;
+ extern struct list_head hpet_map;
+ extern struct list_head acpihid_map;
++/*
++ * List with all PCI segments in the system. This list is not locked because
++ * it is only written at driver initialization time
++ */
++extern struct list_head amd_iommu_pci_seg_list;
++
+ /*
+  * List with all IOMMUs in the system. This list is not locked because it is
+  * only written and read at driver initialization or suspend time
+-- 
+2.43.0
+
diff --git a/queue-5.4/iommu-amd-use-4k-page-for-completion-wait-write-back.patch b/queue-5.4/iommu-amd-use-4k-page-for-completion-wait-write-back.patch
new file mode 100644 (file)
index 0000000..9b70ecb
--- /dev/null
@@ -0,0 +1,166 @@
+From c81f495cf20aa687b1b6817cca5afb50b04032f8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 23 Sep 2020 12:13:45 +0000
+Subject: iommu/amd: Use 4K page for completion wait write-back semaphore
+
+From: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
+
+[ Upstream commit c69d89aff393a212b9635c95990173b48d8bd74d ]
+
+IOMMU SNP support requires the completion wait write-back semaphore to be
+implemented using a 4K-aligned page, where the page address is to be
+programmed into the newly introduced MMIO base/range registers.
+
+This new scheme uses a per-iommu atomic variable to store the current
+semaphore value, which is incremented for every completion wait command.
+
+Since this new scheme is also compatible with non-SNP mode,
+generalize the driver to use 4K page for completion-wait semaphore in
+both modes.
+
+Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
+Cc: Brijesh Singh <brijesh.singh@amd.com>
+Link: https://lore.kernel.org/r/20200923121347.25365-2-suravee.suthikulpanit@amd.com
+Signed-off-by: Joerg Roedel <jroedel@suse.de>
+Stable-dep-of: a295ec52c862 ("iommu/amd: Fix sysfs leak in iommu init")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/amd_iommu.c       | 23 +++++++++++------------
+ drivers/iommu/amd_iommu_init.c  | 18 ++++++++++++++++++
+ drivers/iommu/amd_iommu_types.h |  3 ++-
+ 3 files changed, 31 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
+index a30aac41af426..c7bf32fbc9cb8 100644
+--- a/drivers/iommu/amd_iommu.c
++++ b/drivers/iommu/amd_iommu.c
+@@ -838,11 +838,11 @@ irqreturn_t amd_iommu_int_handler(int irq, void *data)
+  *
+  ****************************************************************************/
+-static int wait_on_sem(volatile u64 *sem)
++static int wait_on_sem(struct amd_iommu *iommu, u64 data)
+ {
+       int i = 0;
+-      while (*sem == 0 && i < LOOP_TIMEOUT) {
++      while (*iommu->cmd_sem != data && i < LOOP_TIMEOUT) {
+               udelay(1);
+               i += 1;
+       }
+@@ -872,16 +872,16 @@ static void copy_cmd_to_buffer(struct amd_iommu *iommu,
+       writel(iommu->cmd_buf_tail, iommu->mmio_base + MMIO_CMD_TAIL_OFFSET);
+ }
+-static void build_completion_wait(struct iommu_cmd *cmd, u64 address)
++static void build_completion_wait(struct iommu_cmd *cmd,
++                                struct amd_iommu *iommu,
++                                u64 data)
+ {
+-      u64 paddr = iommu_virt_to_phys((void *)address);
+-
+-      WARN_ON(address & 0x7ULL);
++      u64 paddr = iommu_virt_to_phys((void *)iommu->cmd_sem);
+       memset(cmd, 0, sizeof(*cmd));
+       cmd->data[0] = lower_32_bits(paddr) | CMD_COMPL_WAIT_STORE_MASK;
+       cmd->data[1] = upper_32_bits(paddr);
+-      cmd->data[2] = 1;
++      cmd->data[2] = data;
+       CMD_SET_TYPE(cmd, CMD_COMPL_WAIT);
+ }
+@@ -1090,22 +1090,21 @@ static int iommu_completion_wait(struct amd_iommu *iommu)
+       struct iommu_cmd cmd;
+       unsigned long flags;
+       int ret;
++      u64 data;
+       if (!iommu->need_sync)
+               return 0;
+-
+-      build_completion_wait(&cmd, (u64)&iommu->cmd_sem);
+-
+       raw_spin_lock_irqsave(&iommu->lock, flags);
+-      iommu->cmd_sem = 0;
++      data = ++iommu->cmd_sem_val;
++      build_completion_wait(&cmd, iommu, data);
+       ret = __iommu_queue_command_sync(iommu, &cmd, false);
+       if (ret)
+               goto out_unlock;
+-      ret = wait_on_sem(&iommu->cmd_sem);
++      ret = wait_on_sem(iommu, data);
+ out_unlock:
+       raw_spin_unlock_irqrestore(&iommu->lock, flags);
+diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
+index 15e25f712f393..4803b1750a620 100644
+--- a/drivers/iommu/amd_iommu_init.c
++++ b/drivers/iommu/amd_iommu_init.c
+@@ -826,6 +826,19 @@ static int iommu_init_ga(struct amd_iommu *iommu)
+       return ret;
+ }
++static int __init alloc_cwwb_sem(struct amd_iommu *iommu)
++{
++      iommu->cmd_sem = (void *)get_zeroed_page(GFP_KERNEL);
++
++      return iommu->cmd_sem ? 0 : -ENOMEM;
++}
++
++static void __init free_cwwb_sem(struct amd_iommu *iommu)
++{
++      if (iommu->cmd_sem)
++              free_page((unsigned long)iommu->cmd_sem);
++}
++
+ static void iommu_enable_xt(struct amd_iommu *iommu)
+ {
+ #ifdef CONFIG_IRQ_REMAP
+@@ -1412,6 +1425,7 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
+ static void __init free_iommu_one(struct amd_iommu *iommu)
+ {
++      free_cwwb_sem(iommu);
+       free_command_buffer(iommu);
+       free_event_buffer(iommu);
+       free_ppr_log(iommu);
+@@ -1498,6 +1512,7 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
+       int ret;
+       raw_spin_lock_init(&iommu->lock);
++      iommu->cmd_sem_val = 0;
+       /* Add IOMMU to internal data structures */
+       list_add_tail(&iommu->list, &amd_iommu_list);
+@@ -1575,6 +1590,9 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
+       if (!iommu->mmio_base)
+               return -ENOMEM;
++      if (alloc_cwwb_sem(iommu))
++              return -ENOMEM;
++
+       if (alloc_command_buffer(iommu))
+               return -ENOMEM;
+diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h
+index 15eef44efd030..036973a6655cb 100644
+--- a/drivers/iommu/amd_iommu_types.h
++++ b/drivers/iommu/amd_iommu_types.h
+@@ -596,7 +596,8 @@ struct amd_iommu {
+ #endif
+       u32 flags;
+-      volatile u64 __aligned(8) cmd_sem;
++      volatile u64 *cmd_sem;
++      u64 cmd_sem_val;
+ #ifdef CONFIG_AMD_IOMMU_DEBUGFS
+       /* DebugFS Info */
+-- 
+2.43.0
+
diff --git a/queue-5.4/iommu-return-right-value-in-iommu_sva_bind_device.patch b/queue-5.4/iommu-return-right-value-in-iommu_sva_bind_device.patch
new file mode 100644 (file)
index 0000000..74f2ca3
--- /dev/null
@@ -0,0 +1,49 @@
+From 1d70dc2be51e677ec2429ab0cb76daefc3850192 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 28 May 2024 12:25:28 +0800
+Subject: iommu: Return right value in iommu_sva_bind_device()
+
+From: Lu Baolu <baolu.lu@linux.intel.com>
+
+[ Upstream commit 89e8a2366e3bce584b6c01549d5019c5cda1205e ]
+
+iommu_sva_bind_device() should return either a sva bond handle or an
+ERR_PTR value in error cases. Existing drivers (idxd and uacce) only
+check the return value with IS_ERR(). This could potentially lead to
+a kernel NULL pointer dereference issue if the function returns NULL
+instead of an error pointer.
+
+In reality, this doesn't cause any problems because iommu_sva_bind_device()
+only returns NULL when the kernel is not configured with CONFIG_IOMMU_SVA.
+In this case, iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA) will
+return an error, and the device drivers won't call iommu_sva_bind_device()
+at all.
+
+Fixes: 26b25a2b98e4 ("iommu: Bind process address spaces to devices")
+Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
+Reviewed-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
+Reviewed-by: Kevin Tian <kevin.tian@intel.com>
+Reviewed-by: Vasant Hegde <vasant.hegde@amd.com>
+Link: https://lore.kernel.org/r/20240528042528.71396-1-baolu.lu@linux.intel.com
+Signed-off-by: Joerg Roedel <jroedel@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/iommu.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/include/linux/iommu.h b/include/linux/iommu.h
+index 6ca3fb2873d7d..9246521bd627f 100644
+--- a/include/linux/iommu.h
++++ b/include/linux/iommu.h
+@@ -1006,7 +1006,7 @@ iommu_aux_get_pasid(struct iommu_domain *domain, struct device *dev)
+ static inline struct iommu_sva *
+ iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata)
+ {
+-      return NULL;
++      return ERR_PTR(-ENODEV);
+ }
+ static inline void iommu_sva_unbind_device(struct iommu_sva *handle)
+-- 
+2.43.0
+
diff --git a/queue-5.4/ionic-fix-use-after-netif_napi_del.patch b/queue-5.4/ionic-fix-use-after-netif_napi_del.patch
new file mode 100644 (file)
index 0000000..9159496
--- /dev/null
@@ -0,0 +1,97 @@
+From b616851dc0c6f654ce6e271c6e9ba7aca512ce2a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Jun 2024 06:04:46 +0000
+Subject: ionic: fix use after netif_napi_del()
+
+From: Taehee Yoo <ap420073@gmail.com>
+
+[ Upstream commit 79f18a41dd056115d685f3b0a419c7cd40055e13 ]
+
+When queues are started, netif_napi_add() and napi_enable() are called.
+If there are 4 queues and only 3 queues are used for the current
+configuration, only 3 queues' napi should be registered and enabled.
+The ionic_qcq_enable() checks whether the .poll pointer is not NULL for
+enabling only the using queue' napi. Unused queues' napi will not be
+registered by netif_napi_add(), so the .poll pointer indicates NULL.
+But it couldn't distinguish whether the napi was unregistered or not
+because netif_napi_del() doesn't reset the .poll pointer to NULL.
+So, ionic_qcq_enable() calls napi_enable() for the queue, which was
+unregistered by netif_napi_del().
+
+Reproducer:
+   ethtool -L <interface name> rx 1 tx 1 combined 0
+   ethtool -L <interface name> rx 0 tx 0 combined 1
+   ethtool -L <interface name> rx 0 tx 0 combined 4
+
+Splat looks like:
+kernel BUG at net/core/dev.c:6666!
+Oops: invalid opcode: 0000 [#1] PREEMPT SMP NOPTI
+CPU: 3 PID: 1057 Comm: kworker/3:3 Not tainted 6.10.0-rc2+ #16
+Workqueue: events ionic_lif_deferred_work [ionic]
+RIP: 0010:napi_enable+0x3b/0x40
+Code: 48 89 c2 48 83 e2 f6 80 b9 61 09 00 00 00 74 0d 48 83 bf 60 01 00 00 00 74 03 80 ce 01 f0 4f
+RSP: 0018:ffffb6ed83227d48 EFLAGS: 00010246
+RAX: 0000000000000000 RBX: ffff97560cda0828 RCX: 0000000000000029
+RDX: 0000000000000001 RSI: 0000000000000000 RDI: ffff97560cda0a28
+RBP: ffffb6ed83227d50 R08: 0000000000000400 R09: 0000000000000001
+R10: 0000000000000001 R11: 0000000000000001 R12: 0000000000000000
+R13: ffff97560ce3c1a0 R14: 0000000000000000 R15: ffff975613ba0a20
+FS:  0000000000000000(0000) GS:ffff975d5f780000(0000) knlGS:0000000000000000
+CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+CR2: 00007f8f734ee200 CR3: 0000000103e50000 CR4: 00000000007506f0
+PKRU: 55555554
+Call Trace:
+ <TASK>
+ ? die+0x33/0x90
+ ? do_trap+0xd9/0x100
+ ? napi_enable+0x3b/0x40
+ ? do_error_trap+0x83/0xb0
+ ? napi_enable+0x3b/0x40
+ ? napi_enable+0x3b/0x40
+ ? exc_invalid_op+0x4e/0x70
+ ? napi_enable+0x3b/0x40
+ ? asm_exc_invalid_op+0x16/0x20
+ ? napi_enable+0x3b/0x40
+ ionic_qcq_enable+0xb7/0x180 [ionic 59bdfc8a035436e1c4224ff7d10789e3f14643f8]
+ ionic_start_queues+0xc4/0x290 [ionic 59bdfc8a035436e1c4224ff7d10789e3f14643f8]
+ ionic_link_status_check+0x11c/0x170 [ionic 59bdfc8a035436e1c4224ff7d10789e3f14643f8]
+ ionic_lif_deferred_work+0x129/0x280 [ionic 59bdfc8a035436e1c4224ff7d10789e3f14643f8]
+ process_one_work+0x145/0x360
+ worker_thread+0x2bb/0x3d0
+ ? __pfx_worker_thread+0x10/0x10
+ kthread+0xcc/0x100
+ ? __pfx_kthread+0x10/0x10
+ ret_from_fork+0x2d/0x50
+ ? __pfx_kthread+0x10/0x10
+ ret_from_fork_asm+0x1a/0x30
+
+Fixes: 0f3154e6bcb3 ("ionic: Add Tx and Rx handling")
+Signed-off-by: Taehee Yoo <ap420073@gmail.com>
+Reviewed-by: Brett Creeley <brett.creeley@amd.com>
+Reviewed-by: Shannon Nelson <shannon.nelson@amd.com>
+Link: https://lore.kernel.org/r/20240612060446.1754392-1-ap420073@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/pensando/ionic/ionic_lif.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
+index e7d868da6a380..7adad91617d8c 100644
+--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c
++++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
+@@ -205,10 +205,8 @@ static int ionic_qcq_enable(struct ionic_qcq *qcq)
+       if (ret)
+               return ret;
+-      if (qcq->napi.poll)
+-              napi_enable(&qcq->napi);
+-
+       if (qcq->flags & IONIC_QCQ_F_INTR) {
++              napi_enable(&qcq->napi);
+               irq_set_affinity_hint(qcq->intr.vector,
+                                     &qcq->intr.affinity_mask);
+               ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
+-- 
+2.43.0
+
diff --git a/queue-5.4/liquidio-adjust-a-null-pointer-handling-path-in-lio_.patch b/queue-5.4/liquidio-adjust-a-null-pointer-handling-path-in-lio_.patch
new file mode 100644 (file)
index 0000000..5a366cb
--- /dev/null
@@ -0,0 +1,69 @@
+From 3d2d4e62644d22682a10f2311b39aa151c0ca9dc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Jun 2024 13:11:35 +0300
+Subject: liquidio: Adjust a NULL pointer handling path in
+ lio_vf_rep_copy_packet
+
+From: Aleksandr Mishin <amishin@t-argos.ru>
+
+[ Upstream commit c44711b78608c98a3e6b49ce91678cd0917d5349 ]
+
+In lio_vf_rep_copy_packet() pg_info->page is compared to a NULL value,
+but then it is unconditionally passed to skb_add_rx_frag() which looks
+strange and could lead to null pointer dereference.
+
+lio_vf_rep_copy_packet() call trace looks like:
+       octeon_droq_process_packets
+        octeon_droq_fast_process_packets
+         octeon_droq_dispatch_pkt
+          octeon_create_recv_info
+           ...search in the dispatch_list...
+            ->disp_fn(rdisp->rinfo, ...)
+             lio_vf_rep_pkt_recv(struct octeon_recv_info *recv_info, ...)
+In this path there is no code which sets pg_info->page to NULL.
+So this check looks unneeded and doesn't solve potential problem.
+But I guess the author had reason to add a check and I have no such card
+and can't do real test.
+In addition, the code in the function liquidio_push_packet() in
+liquidio/lio_core.c does exactly the same.
+
+Based on this, I consider the most acceptable compromise solution to
+adjust this issue by moving skb_add_rx_frag() into conditional scope.
+
+Found by Linux Verification Center (linuxtesting.org) with SVACE.
+
+Fixes: 1f233f327913 ("liquidio: switchdev support for LiquidIO NIC")
+Signed-off-by: Aleksandr Mishin <amishin@t-argos.ru>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c | 11 +++++------
+ 1 file changed, 5 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c
+index f3f2e71431acb..07334f83ccfe3 100644
+--- a/drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c
++++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_rep.c
+@@ -272,13 +272,12 @@ lio_vf_rep_copy_packet(struct octeon_device *oct,
+                               pg_info->page_offset;
+                       memcpy(skb->data, va, MIN_SKB_SIZE);
+                       skb_put(skb, MIN_SKB_SIZE);
++                      skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
++                                      pg_info->page,
++                                      pg_info->page_offset + MIN_SKB_SIZE,
++                                      len - MIN_SKB_SIZE,
++                                      LIO_RXBUFFER_SZ);
+               }
+-
+-              skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
+-                              pg_info->page,
+-                              pg_info->page_offset + MIN_SKB_SIZE,
+-                              len - MIN_SKB_SIZE,
+-                              LIO_RXBUFFER_SZ);
+       } else {
+               struct octeon_skb_page_info *pg_info =
+                       ((struct octeon_skb_page_info *)(skb->cb));
+-- 
+2.43.0
+
diff --git a/queue-5.4/net-ipv6-fix-the-rt-cache-flush-via-sysctl-using-a-p.patch b/queue-5.4/net-ipv6-fix-the-rt-cache-flush-via-sysctl-using-a-p.patch
new file mode 100644 (file)
index 0000000..61ba2d4
--- /dev/null
@@ -0,0 +1,53 @@
+From 9e60a2d65bc7b981cc96a6004572bc452b3c46d6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Jun 2024 13:28:28 +0200
+Subject: net/ipv6: Fix the RT cache flush via sysctl using a previous delay
+
+From: Petr Pavlu <petr.pavlu@suse.com>
+
+[ Upstream commit 14a20e5b4ad998793c5f43b0330d9e1388446cf3 ]
+
+The net.ipv6.route.flush system parameter takes a value which specifies
+a delay used during the flush operation for aging exception routes. The
+written value is however not used in the currently requested flush and
+instead utilized only in the next one.
+
+A problem is that ipv6_sysctl_rtcache_flush() first reads the old value
+of net->ipv6.sysctl.flush_delay into a local delay variable and then
+calls proc_dointvec() which actually updates the sysctl based on the
+provided input.
+
+Fix the problem by switching the order of the two operations.
+
+Fixes: 4990509f19e8 ("[NETNS][IPV6]: Make sysctls route per namespace.")
+Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
+Reviewed-by: David Ahern <dsahern@kernel.org>
+Link: https://lore.kernel.org/r/20240607112828.30285-1-petr.pavlu@suse.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/route.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/ipv6/route.c b/net/ipv6/route.c
+index 65772800d0d33..08cdb38d41d86 100644
+--- a/net/ipv6/route.c
++++ b/net/ipv6/route.c
+@@ -6142,12 +6142,12 @@ int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
+       if (!write)
+               return -EINVAL;
+-      net = (struct net *)ctl->extra1;
+-      delay = net->ipv6.sysctl.flush_delay;
+       ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
+       if (ret)
+               return ret;
++      net = (struct net *)ctl->extra1;
++      delay = net->ipv6.sysctl.flush_delay;
+       fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
+       return 0;
+ }
+-- 
+2.43.0
+
diff --git a/queue-5.4/net-mlx5e-fix-features-validation-check-for-tunneled.patch b/queue-5.4/net-mlx5e-fix-features-validation-check-for-tunneled.patch
new file mode 100644 (file)
index 0000000..8fc99f4
--- /dev/null
@@ -0,0 +1,53 @@
+From afff2dd18b645d35f4c682c513c7670ce7efced5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Jun 2024 23:32:49 +0300
+Subject: net/mlx5e: Fix features validation check for tunneled UDP (non-VXLAN)
+ packets
+
+From: Gal Pressman <gal@nvidia.com>
+
+[ Upstream commit 791b4089e326271424b78f2fae778b20e53d071b ]
+
+Move the vxlan_features_check() call to after we verified the packet is
+a tunneled VXLAN packet.
+
+Without this, tunneled UDP non-VXLAN packets (for ex. GENENVE) might
+wrongly not get offloaded.
+In some cases, it worked by chance as GENEVE header is the same size as
+VXLAN, but it is obviously incorrect.
+
+Fixes: e3cfc7e6b7bd ("net/mlx5e: TX, Add geneve tunnel stateless offload support")
+Signed-off-by: Gal Pressman <gal@nvidia.com>
+Reviewed-by: Dragos Tatulea <dtatulea@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Reviewed-by: Wojciech Drewek <wojciech.drewek@intel.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+index facbbd3fac66a..363c4ab059909 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+@@ -4433,7 +4433,7 @@ static netdev_features_t mlx5e_tunnel_features_check(struct mlx5e_priv *priv,
+               /* Verify if UDP port is being offloaded by HW */
+               if (mlx5_vxlan_lookup_port(priv->mdev->vxlan, port))
+-                      return features;
++                      return vxlan_features_check(skb, features);
+ #if IS_ENABLED(CONFIG_GENEVE)
+               /* Support Geneve offload for default UDP port */
+@@ -4454,7 +4454,6 @@ netdev_features_t mlx5e_features_check(struct sk_buff *skb,
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+       features = vlan_features_check(skb, features);
+-      features = vxlan_features_check(skb, features);
+ #ifdef CONFIG_MLX5_EN_IPSEC
+       if (mlx5e_ipsec_feature_check(skb, netdev, features))
+-- 
+2.43.0
+
diff --git a/queue-5.4/netfilter-ipset-fix-race-between-namespace-cleanup-a.patch b/queue-5.4/netfilter-ipset-fix-race-between-namespace-cleanup-a.patch
new file mode 100644 (file)
index 0000000..02b745c
--- /dev/null
@@ -0,0 +1,289 @@
+From c4aff3d38c3241b2bc8b65e898be1e592927e48c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Jun 2024 15:58:03 +0200
+Subject: netfilter: ipset: Fix race between namespace cleanup and gc in the
+ list:set type
+
+From: Jozsef Kadlecsik <kadlec@netfilter.org>
+
+[ Upstream commit 4e7aaa6b82d63e8ddcbfb56b4fd3d014ca586f10 ]
+
+Lion Ackermann reported that there is a race condition between namespace cleanup
+in ipset and the garbage collection of the list:set type. The namespace
+cleanup can destroy the list:set type of sets while the gc of the set type is
+waiting to run in rcu cleanup. The latter uses data from the destroyed set which
+thus leads use after free. The patch contains the following parts:
+
+- When destroying all sets, first remove the garbage collectors, then wait
+  if needed and then destroy the sets.
+- Fix the badly ordered "wait then remove gc" for the destroy a single set
+  case.
+- Fix the missing rcu locking in the list:set type in the userspace test
+  case.
+- Use proper RCU list handlings in the list:set type.
+
+The patch depends on c1193d9bbbd3 (netfilter: ipset: Add list flush to cancel_gc).
+
+Fixes: 97f7cf1cd80e (netfilter: ipset: fix performance regression in swap operation)
+Reported-by: Lion Ackermann <nnamrec@gmail.com>
+Tested-by: Lion Ackermann <nnamrec@gmail.com>
+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     | 81 +++++++++++++++------------
+ net/netfilter/ipset/ip_set_list_set.c | 30 +++++-----
+ 2 files changed, 60 insertions(+), 51 deletions(-)
+
+diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
+index 544106475d4f6..04273f94504fb 100644
+--- a/net/netfilter/ipset/ip_set_core.c
++++ b/net/netfilter/ipset/ip_set_core.c
+@@ -1024,23 +1024,50 @@ ip_set_setname_policy[IPSET_ATTR_CMD_MAX + 1] = {
+                                   .len = IPSET_MAXNAMELEN - 1 },
+ };
++/* In order to return quickly when destroying a single set, it is split
++ * into two stages:
++ * - Cancel garbage collector
++ * - Destroy the set itself via call_rcu()
++ */
++
+ static void
+-ip_set_destroy_set(struct ip_set *set)
++ip_set_destroy_set_rcu(struct rcu_head *head)
+ {
+-      pr_debug("set: %s\n",  set->name);
++      struct ip_set *set = container_of(head, struct ip_set, rcu);
+-      /* Must call it without holding any lock */
+       set->variant->destroy(set);
+       module_put(set->type->me);
+       kfree(set);
+ }
+ static void
+-ip_set_destroy_set_rcu(struct rcu_head *head)
++_destroy_all_sets(struct ip_set_net *inst)
+ {
+-      struct ip_set *set = container_of(head, struct ip_set, rcu);
++      struct ip_set *set;
++      ip_set_id_t i;
++      bool need_wait = false;
+-      ip_set_destroy_set(set);
++      /* First cancel gc's: set:list sets are flushed as well */
++      for (i = 0; i < inst->ip_set_max; i++) {
++              set = ip_set(inst, i);
++              if (set) {
++                      set->variant->cancel_gc(set);
++                      if (set->type->features & IPSET_TYPE_NAME)
++                              need_wait = true;
++              }
++      }
++      /* Must wait for flush to be really finished  */
++      if (need_wait)
++              rcu_barrier();
++      for (i = 0; i < inst->ip_set_max; i++) {
++              set = ip_set(inst, i);
++              if (set) {
++                      ip_set(inst, i) = NULL;
++                      set->variant->destroy(set);
++                      module_put(set->type->me);
++                      kfree(set);
++              }
++      }
+ }
+ static int ip_set_destroy(struct net *net, struct sock *ctnl,
+@@ -1056,11 +1083,10 @@ static int ip_set_destroy(struct net *net, struct sock *ctnl,
+       if (unlikely(protocol_min_failed(attr)))
+               return -IPSET_ERR_PROTOCOL;
+-
+       /* Commands are serialized and references are
+        * protected by the ip_set_ref_lock.
+        * External systems (i.e. xt_set) must call
+-       * ip_set_put|get_nfnl_* functions, that way we
++       * ip_set_nfnl_get_* functions, that way we
+        * can safely check references here.
+        *
+        * list:set timer can only decrement the reference
+@@ -1068,8 +1094,6 @@ static int ip_set_destroy(struct net *net, struct sock *ctnl,
+        * without holding the lock.
+        */
+       if (!attr[IPSET_ATTR_SETNAME]) {
+-              /* Must wait for flush to be really finished in list:set */
+-              rcu_barrier();
+               read_lock_bh(&ip_set_ref_lock);
+               for (i = 0; i < inst->ip_set_max; i++) {
+                       s = ip_set(inst, i);
+@@ -1080,15 +1104,7 @@ static int ip_set_destroy(struct net *net, struct sock *ctnl,
+               }
+               inst->is_destroyed = true;
+               read_unlock_bh(&ip_set_ref_lock);
+-              for (i = 0; i < inst->ip_set_max; i++) {
+-                      s = ip_set(inst, i);
+-                      if (s) {
+-                              ip_set(inst, i) = NULL;
+-                              /* Must cancel garbage collectors */
+-                              s->variant->cancel_gc(s);
+-                              ip_set_destroy_set(s);
+-                      }
+-              }
++              _destroy_all_sets(inst);
+               /* Modified by ip_set_destroy() only, which is serialized */
+               inst->is_destroyed = false;
+       } else {
+@@ -1107,12 +1123,12 @@ static int ip_set_destroy(struct net *net, struct sock *ctnl,
+               features = s->type->features;
+               ip_set(inst, i) = NULL;
+               read_unlock_bh(&ip_set_ref_lock);
++              /* Must cancel garbage collectors */
++              s->variant->cancel_gc(s);
+               if (features & IPSET_TYPE_NAME) {
+                       /* Must wait for flush to be really finished  */
+                       rcu_barrier();
+               }
+-              /* Must cancel garbage collectors */
+-              s->variant->cancel_gc(s);
+               call_rcu(&s->rcu, ip_set_destroy_set_rcu);
+       }
+       return 0;
+@@ -2223,30 +2239,25 @@ ip_set_net_init(struct net *net)
+ }
+ static void __net_exit
+-ip_set_net_exit(struct net *net)
++ip_set_net_pre_exit(struct net *net)
+ {
+       struct ip_set_net *inst = ip_set_pernet(net);
+-      struct ip_set *set = NULL;
+-      ip_set_id_t i;
+-
+       inst->is_deleted = true; /* flag for ip_set_nfnl_put */
++}
+-      nfnl_lock(NFNL_SUBSYS_IPSET);
+-      for (i = 0; i < inst->ip_set_max; i++) {
+-              set = ip_set(inst, i);
+-              if (set) {
+-                      ip_set(inst, i) = NULL;
+-                      set->variant->cancel_gc(set);
+-                      ip_set_destroy_set(set);
+-              }
+-      }
+-      nfnl_unlock(NFNL_SUBSYS_IPSET);
++static void __net_exit
++ip_set_net_exit(struct net *net)
++{
++      struct ip_set_net *inst = ip_set_pernet(net);
++
++      _destroy_all_sets(inst);
+       kvfree(rcu_dereference_protected(inst->ip_set_list, 1));
+ }
+ static struct pernet_operations ip_set_net_ops = {
+       .init   = ip_set_net_init,
++      .pre_exit = ip_set_net_pre_exit,
+       .exit   = ip_set_net_exit,
+       .id     = &ip_set_net_id,
+       .size   = sizeof(struct ip_set_net),
+diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
+index 64cc3e2131f3f..9f4f0126d6ed5 100644
+--- a/net/netfilter/ipset/ip_set_list_set.c
++++ b/net/netfilter/ipset/ip_set_list_set.c
+@@ -79,7 +79,7 @@ list_set_kadd(struct ip_set *set, const struct sk_buff *skb,
+       struct set_elem *e;
+       int ret;
+-      list_for_each_entry(e, &map->members, list) {
++      list_for_each_entry_rcu(e, &map->members, list) {
+               if (SET_WITH_TIMEOUT(set) &&
+                   ip_set_timeout_expired(ext_timeout(e, set)))
+                       continue;
+@@ -99,7 +99,7 @@ list_set_kdel(struct ip_set *set, const struct sk_buff *skb,
+       struct set_elem *e;
+       int ret;
+-      list_for_each_entry(e, &map->members, list) {
++      list_for_each_entry_rcu(e, &map->members, list) {
+               if (SET_WITH_TIMEOUT(set) &&
+                   ip_set_timeout_expired(ext_timeout(e, set)))
+                       continue;
+@@ -188,9 +188,10 @@ list_set_utest(struct ip_set *set, void *value, const struct ip_set_ext *ext,
+       struct list_set *map = set->data;
+       struct set_adt_elem *d = value;
+       struct set_elem *e, *next, *prev = NULL;
+-      int ret;
++      int ret = 0;
+-      list_for_each_entry(e, &map->members, list) {
++      rcu_read_lock();
++      list_for_each_entry_rcu(e, &map->members, list) {
+               if (SET_WITH_TIMEOUT(set) &&
+                   ip_set_timeout_expired(ext_timeout(e, set)))
+                       continue;
+@@ -201,6 +202,7 @@ list_set_utest(struct ip_set *set, void *value, const struct ip_set_ext *ext,
+               if (d->before == 0) {
+                       ret = 1;
++                      goto out;
+               } else if (d->before > 0) {
+                       next = list_next_entry(e, list);
+                       ret = !list_is_last(&e->list, &map->members) &&
+@@ -208,9 +210,11 @@ list_set_utest(struct ip_set *set, void *value, const struct ip_set_ext *ext,
+               } else {
+                       ret = prev && prev->id == d->refid;
+               }
+-              return ret;
++              goto out;
+       }
+-      return 0;
++out:
++      rcu_read_unlock();
++      return ret;
+ }
+ static void
+@@ -239,7 +243,7 @@ list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,
+       /* Find where to add the new entry */
+       n = prev = next = NULL;
+-      list_for_each_entry(e, &map->members, list) {
++      list_for_each_entry_rcu(e, &map->members, list) {
+               if (SET_WITH_TIMEOUT(set) &&
+                   ip_set_timeout_expired(ext_timeout(e, set)))
+                       continue;
+@@ -316,9 +320,9 @@ list_set_udel(struct ip_set *set, void *value, const struct ip_set_ext *ext,
+ {
+       struct list_set *map = set->data;
+       struct set_adt_elem *d = value;
+-      struct set_elem *e, *next, *prev = NULL;
++      struct set_elem *e, *n, *next, *prev = NULL;
+-      list_for_each_entry(e, &map->members, list) {
++      list_for_each_entry_safe(e, n, &map->members, list) {
+               if (SET_WITH_TIMEOUT(set) &&
+                   ip_set_timeout_expired(ext_timeout(e, set)))
+                       continue;
+@@ -424,14 +428,8 @@ static void
+ list_set_destroy(struct ip_set *set)
+ {
+       struct list_set *map = set->data;
+-      struct set_elem *e, *n;
+-      list_for_each_entry_safe(e, n, &map->members, list) {
+-              list_del(&e->list);
+-              ip_set_put_byindex(map->net, e->id);
+-              ip_set_ext_destroy(set, e);
+-              kfree(e);
+-      }
++      WARN_ON_ONCE(!list_empty(&map->members));
+       kfree(map);
+       set->data = NULL;
+-- 
+2.43.0
+
diff --git a/queue-5.4/netfilter-use-flowlabel-flow-key-when-re-routing-man.patch b/queue-5.4/netfilter-use-flowlabel-flow-key-when-re-routing-man.patch
new file mode 100644 (file)
index 0000000..2f77918
--- /dev/null
@@ -0,0 +1,41 @@
+From 5f1d40bcae0284f18f12ef76a33ef216281bb3a0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Jun 2024 12:23:31 +0200
+Subject: netfilter: Use flowlabel flow key when re-routing mangled packets
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit 6f8f132cc7bac2ac76911e47d5baa378aafda4cb ]
+
+'ip6 dscp set $v' in an nftables outpute route chain has no effect.
+While nftables does detect the dscp change and calls the reroute hook.
+But ip6_route_me_harder never sets the dscp/flowlabel:
+flowlabel/dsfield routing rules are ignored and no reroute takes place.
+
+Thanks to Yi Chen for an excellent reproducer script that I used
+to validate this change.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Reported-by: Yi Chen <yiche@redhat.com>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/netfilter.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
+index ab9a279dd6d47..ef06d248c3c3d 100644
+--- a/net/ipv6/netfilter.c
++++ b/net/ipv6/netfilter.c
+@@ -35,6 +35,7 @@ int ip6_route_me_harder(struct net *net, struct sock *sk_partial, struct sk_buff
+               .flowi6_uid = sock_net_uid(net, sk),
+               .daddr = iph->daddr,
+               .saddr = iph->saddr,
++              .flowlabel = ip6_flowinfo(iph),
+       };
+       int err;
+-- 
+2.43.0
+
index 1d6a25b7bd32ce8399b93a4c71823f6fda7e3c11..4afdcdbeb670d976db7fef8e66d4597e6e6c09d1 100644 (file)
@@ -55,3 +55,26 @@ xhci-apply-reset-resume-quirk-to-etron-ej188-xhci-host.patch
 xhci-apply-broken-streams-quirk-to-etron-ej188-xhci-host.patch
 scsi-mpt3sas-avoid-test-set_bit-operating-in-non-allocated-memory.patch
 input-try-trimming-too-long-modalias-strings.patch
+clk-sifive-extract-prci-core-to-common-base.patch
+clk-sifive-do-not-register-clkdevs-for-prci-clocks.patch
+sunrpc-return-proper-error-from-gss_wrap_req_priv.patch
+gpio-tqmx86-fix-typo-in-kconfig-label.patch
+bitops-introduce-the-for_each_set_clump8-macro.patch
+gpio-tqmx86-remove-unneeded-call-to-platform_set_drv.patch
+gpio-tqmx86-introduce-shadow-register-for-gpio-outpu.patch
+hid-core-remove-unnecessary-warn_on-in-implement.patch
+iommu-amd-use-4k-page-for-completion-wait-write-back.patch
+iommu-amd-introduce-pci-segment-structure.patch
+iommu-amd-fix-sysfs-leak-in-iommu-init.patch
+iommu-return-right-value-in-iommu_sva_bind_device.patch
+hid-logitech-dj-fix-memory-leak-in-logi_dj_recv_swit.patch
+liquidio-adjust-a-null-pointer-handling-path-in-lio_.patch
+drm-komeda-check-for-error-valued-pointer.patch
+drm-bridge-panel-fix-runtime-warning-on-panel-bridge.patch
+tcp-fix-race-in-tcp_v6_syn_recv_sock.patch
+net-mlx5e-fix-features-validation-check-for-tunneled.patch
+bluetooth-l2cap-fix-rejecting-l2cap_conn_param_updat.patch
+netfilter-ipset-fix-race-between-namespace-cleanup-a.patch
+netfilter-use-flowlabel-flow-key-when-re-routing-man.patch
+net-ipv6-fix-the-rt-cache-flush-via-sysctl-using-a-p.patch
+ionic-fix-use-after-netif_napi_del.patch
diff --git a/queue-5.4/sunrpc-return-proper-error-from-gss_wrap_req_priv.patch b/queue-5.4/sunrpc-return-proper-error-from-gss_wrap_req_priv.patch
new file mode 100644 (file)
index 0000000..fe4336f
--- /dev/null
@@ -0,0 +1,40 @@
+From 76295a60a5aa9b4d724645bbc9af4ed480bc7ded Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 23 May 2024 16:47:16 +0800
+Subject: SUNRPC: return proper error from gss_wrap_req_priv
+
+From: Chen Hanxiao <chenhx.fnst@fujitsu.com>
+
+[ Upstream commit 33c94d7e3cb84f6d130678d6d59ba475a6c489cf ]
+
+don't return 0 if snd_buf->len really greater than snd_buf->buflen
+
+Signed-off-by: Chen Hanxiao <chenhx.fnst@fujitsu.com>
+Fixes: 0c77668ddb4e ("SUNRPC: Introduce trace points in rpc_auth_gss.ko")
+Reviewed-by: Benjamin Coddington <bcodding@redhat.com>
+Reviewed-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sunrpc/auth_gss/auth_gss.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
+index 4d3cf146f50a5..a1aa4f3d7e50e 100644
+--- a/net/sunrpc/auth_gss/auth_gss.c
++++ b/net/sunrpc/auth_gss/auth_gss.c
+@@ -1849,8 +1849,10 @@ static int gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
+       offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base;
+       maj_stat = gss_wrap(ctx->gc_gss_ctx, offset, snd_buf, inpages);
+       /* slack space should prevent this ever happening: */
+-      if (unlikely(snd_buf->len > snd_buf->buflen))
++      if (unlikely(snd_buf->len > snd_buf->buflen)) {
++              status = -EIO;
+               goto wrap_failed;
++      }
+       /* We're assuming that when GSS_S_CONTEXT_EXPIRED, the encryption was
+        * done anyway, so it's safe to put the request on the wire: */
+       if (maj_stat == GSS_S_CONTEXT_EXPIRED)
+-- 
+2.43.0
+
diff --git a/queue-5.4/tcp-fix-race-in-tcp_v6_syn_recv_sock.patch b/queue-5.4/tcp-fix-race-in-tcp_v6_syn_recv_sock.patch
new file mode 100644 (file)
index 0000000..40d214c
--- /dev/null
@@ -0,0 +1,54 @@
+From a2183de305f2f8aca4c26e94d2796888dd3b35e4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Jun 2024 15:46:51 +0000
+Subject: tcp: fix race in tcp_v6_syn_recv_sock()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit d37fe4255abe8e7b419b90c5847e8ec2b8debb08 ]
+
+tcp_v6_syn_recv_sock() calls ip6_dst_store() before
+inet_sk(newsk)->pinet6 has been set up.
+
+This means ip6_dst_store() writes over the parent (listener)
+np->dst_cookie.
+
+This is racy because multiple threads could share the same
+parent and their final np->dst_cookie could be wrong.
+
+Move ip6_dst_store() call after inet_sk(newsk)->pinet6
+has been changed and after the copy of parent ipv6_pinfo.
+
+Fixes: e994b2f0fb92 ("tcp: do not lock listener to process SYN packets")
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/tcp_ipv6.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
+index 7cb622d300aa2..c5efbfe2a2c4a 100644
+--- a/net/ipv6/tcp_ipv6.c
++++ b/net/ipv6/tcp_ipv6.c
+@@ -1228,7 +1228,6 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
+        */
+       newsk->sk_gso_type = SKB_GSO_TCPV6;
+-      ip6_dst_store(newsk, dst, NULL, NULL);
+       inet6_sk_rx_dst_set(newsk, skb);
+       inet_sk(newsk)->pinet6 = tcp_inet6_sk(newsk);
+@@ -1239,6 +1238,8 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
+       memcpy(newnp, np, sizeof(struct ipv6_pinfo));
++      ip6_dst_store(newsk, dst, NULL, NULL);
++
+       newsk->sk_v6_daddr = ireq->ir_v6_rmt_addr;
+       newnp->saddr = ireq->ir_v6_loc_addr;
+       newsk->sk_v6_rcv_saddr = ireq->ir_v6_loc_addr;
+-- 
+2.43.0
+