From 35f27aca23a430a2611e0a63a89c53e4a6f4bcac Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Mon, 17 Jun 2024 07:30:34 -0400 Subject: [PATCH] Fixes for 5.4 Signed-off-by: Sasha Levin --- ...roduce-the-for_each_set_clump8-macro.patch | 231 +++ ...fix-rejecting-l2cap_conn_param_updat.patch | 108 ++ ...not-register-clkdevs-for-prci-clocks.patch | 62 + ...ive-extract-prci-core-to-common-base.patch | 1318 +++++++++++++++++ ...-fix-runtime-warning-on-panel-bridge.patch | 51 + ...omeda-check-for-error-valued-pointer.patch | 37 + ...pio-tqmx86-fix-typo-in-kconfig-label.patch | 38 + ...oduce-shadow-register-for-gpio-outpu.patch | 89 ++ ...ve-unneeded-call-to-platform_set_drv.patch | 40 + ...ove-unnecessary-warn_on-in-implement.patch | 67 + ...fix-memory-leak-in-logi_dj_recv_swit.patch | 41 + ...mmu-amd-fix-sysfs-leak-in-iommu-init.patch | 47 + ...-amd-introduce-pci-segment-structure.patch | 182 +++ ...-page-for-completion-wait-write-back.patch | 166 +++ ...right-value-in-iommu_sva_bind_device.patch | 49 + .../ionic-fix-use-after-netif_napi_del.patch | 97 ++ ...a-null-pointer-handling-path-in-lio_.patch | 69 + ...-rt-cache-flush-via-sysctl-using-a-p.patch | 53 + ...atures-validation-check-for-tunneled.patch | 53 + ...fix-race-between-namespace-cleanup-a.patch | 289 ++++ ...owlabel-flow-key-when-re-routing-man.patch | 41 + queue-5.4/series | 23 + ...-proper-error-from-gss_wrap_req_priv.patch | 40 + ...tcp-fix-race-in-tcp_v6_syn_recv_sock.patch | 54 + 24 files changed, 3245 insertions(+) create mode 100644 queue-5.4/bitops-introduce-the-for_each_set_clump8-macro.patch create mode 100644 queue-5.4/bluetooth-l2cap-fix-rejecting-l2cap_conn_param_updat.patch create mode 100644 queue-5.4/clk-sifive-do-not-register-clkdevs-for-prci-clocks.patch create mode 100644 queue-5.4/clk-sifive-extract-prci-core-to-common-base.patch create mode 100644 queue-5.4/drm-bridge-panel-fix-runtime-warning-on-panel-bridge.patch create mode 100644 queue-5.4/drm-komeda-check-for-error-valued-pointer.patch create mode 100644 queue-5.4/gpio-tqmx86-fix-typo-in-kconfig-label.patch create mode 100644 queue-5.4/gpio-tqmx86-introduce-shadow-register-for-gpio-outpu.patch create mode 100644 queue-5.4/gpio-tqmx86-remove-unneeded-call-to-platform_set_drv.patch create mode 100644 queue-5.4/hid-core-remove-unnecessary-warn_on-in-implement.patch create mode 100644 queue-5.4/hid-logitech-dj-fix-memory-leak-in-logi_dj_recv_swit.patch create mode 100644 queue-5.4/iommu-amd-fix-sysfs-leak-in-iommu-init.patch create mode 100644 queue-5.4/iommu-amd-introduce-pci-segment-structure.patch create mode 100644 queue-5.4/iommu-amd-use-4k-page-for-completion-wait-write-back.patch create mode 100644 queue-5.4/iommu-return-right-value-in-iommu_sva_bind_device.patch create mode 100644 queue-5.4/ionic-fix-use-after-netif_napi_del.patch create mode 100644 queue-5.4/liquidio-adjust-a-null-pointer-handling-path-in-lio_.patch create mode 100644 queue-5.4/net-ipv6-fix-the-rt-cache-flush-via-sysctl-using-a-p.patch create mode 100644 queue-5.4/net-mlx5e-fix-features-validation-check-for-tunneled.patch create mode 100644 queue-5.4/netfilter-ipset-fix-race-between-namespace-cleanup-a.patch create mode 100644 queue-5.4/netfilter-use-flowlabel-flow-key-when-re-routing-man.patch create mode 100644 queue-5.4/sunrpc-return-proper-error-from-gss_wrap_req_priv.patch create mode 100644 queue-5.4/tcp-fix-race-in-tcp_v6_syn_recv_sock.patch 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 index 00000000000..12c0cc595b1 --- /dev/null +++ b/queue-5.4/bitops-introduce-the-for_each_set_clump8-macro.patch @@ -0,0 +1,231 @@ +From c140c3bd62861ac1b796f37deabbc405e9112b17 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Dec 2019 16:50:57 -0800 +Subject: bitops: introduce the for_each_set_clump8 macro + +From: William Breathitt Gray + +[ 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 +Signed-off-by: Gustavo A. R. Silva +Suggested-by: Andy Shevchenko +Suggested-by: Rasmus Villemoes +Suggested-by: Lukas Wunner +Tested-by: Andy Shevchenko +Cc: Arnd Bergmann +Cc: Linus Walleij +Cc: Bartosz Golaszewski +Cc: Masahiro Yamada +Cc: Geert Uytterhoeven +Cc: Phil Reid +Cc: Geert Uytterhoeven +Cc: Mathias Duckeck +Cc: Morten Hein Tiljeset +Cc: Sean Nyekjaer +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Stable-dep-of: 9d6a811b522b ("gpio: tqmx86: introduce shadow register for GPIO output value") +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..569a744da63 --- /dev/null +++ b/queue-5.4/bluetooth-l2cap-fix-rejecting-l2cap_conn_param_updat.patch @@ -0,0 +1,108 @@ +From bd7a017e7caae750488b32f3242330e6f881a8d2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 May 2024 16:03:07 -0400 +Subject: Bluetooth: L2CAP: Fix rejecting L2CAP_CONN_PARAM_UPDATE_REQ + +From: Luiz Augusto von Dentz + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..642106f0fcf --- /dev/null +++ b/queue-5.4/clk-sifive-do-not-register-clkdevs-for-prci-clocks.patch @@ -0,0 +1,62 @@ +From b0091af68f4e670ec34dedc4d0a8b6abb5833e72 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 May 2024 17:14:12 -0700 +Subject: clk: sifive: Do not register clkdevs for PRCI clocks + +From: Samuel Holland + +[ 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 +Closes: https://lore.kernel.org/linux-clk/7eda7621-0dde-4153-89e4-172e4c095d01@roeck-us.net/ +Suggested-by: Russell King +Signed-off-by: Samuel Holland +Link: https://lore.kernel.org/r/20240528001432.1200403-1-samuel.holland@sifive.com +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + 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 + #include + #include + #include +@@ -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 index 00000000000..f29d5e6344a --- /dev/null +++ b/queue-5.4/clk-sifive-extract-prci-core-to-common-base.patch @@ -0,0 +1,1318 @@ +From baabbf2cda9ad8d5a6053f5aa8a006f06af32de8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 9 Dec 2020 17:49:12 +0800 +Subject: clk: sifive: Extract prci core to common base + +From: Zong Li + +[ 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 +Reviewed-by: Pragnesh Patel +Acked-by: Palmer Dabbelt +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 +Stable-dep-of: 2607133196c3 ("clk: sifive: Do not register clkdevs for PRCI clocks") +Signed-off-by: Sasha Levin +--- + 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 +-#include +-#include +-#include +-#include +-#include +-#include + #include +-#include +-#include +-#include +-#include +- +-/* +- * 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 + +-/* 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 ++#include ++#include ++#include ++#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 ++#include ++#include ++ ++/* ++ * 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 index 00000000000..e8068b8bc6a --- /dev/null +++ b/queue-5.4/drm-bridge-panel-fix-runtime-warning-on-panel-bridge.patch @@ -0,0 +1,51 @@ +From ec65bc6f7ba1471dbd167783e87d24e886f87d99 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 10 Jun 2024 11:27:39 +0100 +Subject: drm/bridge/panel: Fix runtime warning on panel bridge release + +From: Adam Miotk + +[ 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 +Signed-off-by: Maxime Ripard +Link: https://patchwork.freedesktop.org/patch/msgid/20240610102739.139852-1-adam.miotk@arm.com +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..eafa1ad25cc --- /dev/null +++ b/queue-5.4/drm-komeda-check-for-error-valued-pointer.patch @@ -0,0 +1,37 @@ +From 70fb9a548cd43d13eb1275b7f4195b9d11a438af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 10 Jun 2024 11:20:56 +0100 +Subject: drm/komeda: check for error-valued pointer + +From: Amjad Ouled-Ameur + +[ 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 +Signed-off-by: Maxime Ripard +Link: https://patchwork.freedesktop.org/patch/msgid/20240610102056.40406-1-amjad.ouled-ameur@arm.com +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..9d76499f3f3 --- /dev/null +++ b/queue-5.4/gpio-tqmx86-fix-typo-in-kconfig-label.patch @@ -0,0 +1,38 @@ +From 8ef7b91485bf945fbba92e07c8a83ddfd86523e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 May 2024 12:19:59 +0200 +Subject: gpio: tqmx86: fix typo in Kconfig label + +From: Gregor Herburger + +[ 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 +Signed-off-by: Matthias Schiffer +Reviewed-by: Andrew Lunn +Link: https://lore.kernel.org/r/e0e38c9944ad6d281d9a662a45d289b88edc808e.1717063994.git.matthias.schiffer@ew.tq-group.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..6df638e53b6 --- /dev/null +++ b/queue-5.4/gpio-tqmx86-introduce-shadow-register-for-gpio-outpu.patch @@ -0,0 +1,89 @@ +From 2cf382de1e1ac754e72c6cbbbf66868d99251b70 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 May 2024 12:20:00 +0200 +Subject: gpio: tqmx86: introduce shadow register for GPIO output value + +From: Matthias Schiffer + +[ 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 +Reviewed-by: Andrew Lunn +Link: https://lore.kernel.org/r/d0555933becd45fa92a85675d26e4d59343ddc01.1717063994.git.matthias.schiffer@ew.tq-group.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + 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 + */ + ++#include + #include + #include + #include +@@ -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 index 00000000000..cab8dd88dfb --- /dev/null +++ b/queue-5.4/gpio-tqmx86-remove-unneeded-call-to-platform_set_drv.patch @@ -0,0 +1,40 @@ +From 94b8455c2f62f874a6dfa7ef13b5ed732abbf90d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 1 Aug 2023 23:38:39 +0300 +Subject: gpio: tqmx86: remove unneeded call to platform_set_drvdata() + +From: Andrei Coardos + +[ 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 +Signed-off-by: Andrei Coardos +Reviewed-by: Andy Shevchenko +Signed-off-by: Bartosz Golaszewski +Stable-dep-of: 9d6a811b522b ("gpio: tqmx86: introduce shadow register for GPIO output value") +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..642a7064221 --- /dev/null +++ b/queue-5.4/hid-core-remove-unnecessary-warn_on-in-implement.patch @@ -0,0 +1,67 @@ +From 933d5d6d7ace6da46310b1503b2c73b6f4749f1b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 May 2024 07:19:14 -0700 +Subject: HID: core: remove unnecessary WARN_ON() in implement() + +From: Nikita Zhandarovich + +[ 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: + + __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: +Suggested-by: Alan Stern +Signed-off-by: Nikita Zhandarovich +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..d06c5db8499 --- /dev/null +++ b/queue-5.4/hid-logitech-dj-fix-memory-leak-in-logi_dj_recv_swit.patch @@ -0,0 +1,41 @@ +From cec7b0fe4e1e0a5eadcb4e3e2165061cda99cb6e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..23f8eac8e13 --- /dev/null +++ b/queue-5.4/iommu-amd-fix-sysfs-leak-in-iommu-init.patch @@ -0,0 +1,47 @@ +From b8fa99c8234efcb5289dc6f37784fbb4dba6ad05 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 May 2024 08:42:20 +0800 +Subject: iommu/amd: Fix sysfs leak in iommu init + +From: Kun(llfl) + +[ 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) +Reviewed-by: Suravee Suthikulpanit +Link: https://lore.kernel.org/r/c8e0d11c6ab1ee48299c288009cf9c5dae07b42d.1715215003.git.llfl@linux.alibaba.com +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..834c407fd0a --- /dev/null +++ b/queue-5.4/iommu-amd-introduce-pci-segment-structure.patch @@ -0,0 +1,182 @@ +From bb34e2d8534a3f87874fd21e77e09e3c29b5a8d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 Jul 2022 17:07:52 +0530 +Subject: iommu/amd: Introduce pci segment structure + +From: Vasant Hegde + +[ 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 +Signed-off-by: Suravee Suthikulpanit +Signed-off-by: Vasant Hegde +Link: https://lore.kernel.org/r/20220706113825.25582-3-vasant.hegde@amd.com +Signed-off-by: Joerg Roedel +Stable-dep-of: a295ec52c862 ("iommu/amd: Fix sysfs leak in iommu init") +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..9b70ecb729d --- /dev/null +++ b/queue-5.4/iommu-amd-use-4k-page-for-completion-wait-write-back.patch @@ -0,0 +1,166 @@ +From c81f495cf20aa687b1b6817cca5afb50b04032f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 23 Sep 2020 12:13:45 +0000 +Subject: iommu/amd: Use 4K page for completion wait write-back semaphore + +From: Suravee Suthikulpanit + +[ 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 +Cc: Brijesh Singh +Link: https://lore.kernel.org/r/20200923121347.25365-2-suravee.suthikulpanit@amd.com +Signed-off-by: Joerg Roedel +Stable-dep-of: a295ec52c862 ("iommu/amd: Fix sysfs leak in iommu init") +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..74f2ca31aff --- /dev/null +++ b/queue-5.4/iommu-return-right-value-in-iommu_sva_bind_device.patch @@ -0,0 +1,49 @@ +From 1d70dc2be51e677ec2429ab0cb76daefc3850192 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 May 2024 12:25:28 +0800 +Subject: iommu: Return right value in iommu_sva_bind_device() + +From: Lu Baolu + +[ 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 +Reviewed-by: Jean-Philippe Brucker +Reviewed-by: Kevin Tian +Reviewed-by: Vasant Hegde +Link: https://lore.kernel.org/r/20240528042528.71396-1-baolu.lu@linux.intel.com +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..9159496966f --- /dev/null +++ b/queue-5.4/ionic-fix-use-after-netif_napi_del.patch @@ -0,0 +1,97 @@ +From b616851dc0c6f654ce6e271c6e9ba7aca512ce2a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 12 Jun 2024 06:04:46 +0000 +Subject: ionic: fix use after netif_napi_del() + +From: Taehee Yoo + +[ 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 rx 1 tx 1 combined 0 + ethtool -L rx 0 tx 0 combined 1 + ethtool -L 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: + + ? 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 +Reviewed-by: Brett Creeley +Reviewed-by: Shannon Nelson +Link: https://lore.kernel.org/r/20240612060446.1754392-1-ap420073@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..5a366cb70dd --- /dev/null +++ b/queue-5.4/liquidio-adjust-a-null-pointer-handling-path-in-lio_.patch @@ -0,0 +1,69 @@ +From 3d2d4e62644d22682a10f2311b39aa151c0ca9dc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Simon Horman +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..61ba2d411a9 --- /dev/null +++ b/queue-5.4/net-ipv6-fix-the-rt-cache-flush-via-sysctl-using-a-p.patch @@ -0,0 +1,53 @@ +From 9e60a2d65bc7b981cc96a6004572bc452b3c46d6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: David Ahern +Link: https://lore.kernel.org/r/20240607112828.30285-1-petr.pavlu@suse.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..8fc99f45057 --- /dev/null +++ b/queue-5.4/net-mlx5e-fix-features-validation-check-for-tunneled.patch @@ -0,0 +1,53 @@ +From afff2dd18b645d35f4c682c513c7670ce7efced5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Dragos Tatulea +Signed-off-by: Tariq Toukan +Reviewed-by: Wojciech Drewek +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..02b745c87ef --- /dev/null +++ b/queue-5.4/netfilter-ipset-fix-race-between-namespace-cleanup-a.patch @@ -0,0 +1,289 @@ +From c4aff3d38c3241b2bc8b65e898be1e592927e48c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Tested-by: Lion Ackermann +Signed-off-by: Jozsef Kadlecsik +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..2f77918a456 --- /dev/null +++ b/queue-5.4/netfilter-use-flowlabel-flow-key-when-re-routing-man.patch @@ -0,0 +1,41 @@ +From 5f1d40bcae0284f18f12ef76a33ef216281bb3a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Jun 2024 12:23:31 +0200 +Subject: netfilter: Use flowlabel flow key when re-routing mangled packets + +From: Florian Westphal + +[ 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 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.4/series b/queue-5.4/series index 1d6a25b7bd3..4afdcdbeb67 100644 --- a/queue-5.4/series +++ b/queue-5.4/series @@ -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 index 00000000000..fe4336fc025 --- /dev/null +++ b/queue-5.4/sunrpc-return-proper-error-from-gss_wrap_req_priv.patch @@ -0,0 +1,40 @@ +From 76295a60a5aa9b4d724645bbc9af4ed480bc7ded Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 May 2024 16:47:16 +0800 +Subject: SUNRPC: return proper error from gss_wrap_req_priv + +From: Chen Hanxiao + +[ Upstream commit 33c94d7e3cb84f6d130678d6d59ba475a6c489cf ] + +don't return 0 if snd_buf->len really greater than snd_buf->buflen + +Signed-off-by: Chen Hanxiao +Fixes: 0c77668ddb4e ("SUNRPC: Introduce trace points in rpc_auth_gss.ko") +Reviewed-by: Benjamin Coddington +Reviewed-by: Chuck Lever +Signed-off-by: Trond Myklebust +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..40d214c7a2e --- /dev/null +++ b/queue-5.4/tcp-fix-race-in-tcp_v6_syn_recv_sock.patch @@ -0,0 +1,54 @@ +From a2183de305f2f8aca4c26e94d2796888dd3b35e4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Jun 2024 15:46:51 +0000 +Subject: tcp: fix race in tcp_v6_syn_recv_sock() + +From: Eric Dumazet + +[ 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 +Reviewed-by: Simon Horman +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + 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 + -- 2.47.3