From 1e9265b25231e82789c998b8ee88dc00a1aa5813 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 29 Aug 2024 18:46:40 +0300 Subject: [PATCH 001/118] drm/mm: Mark drm_mm_interval_tree*() functions with __maybe_unused [ Upstream commit 53bd7c1c0077db533472ae32799157758302ef48 ] The INTERVAL_TREE_DEFINE() uncoditionally provides a bunch of helper functions which in some cases may be not used. This, in particular, prevents kernel builds with clang, `make W=1` and CONFIG_WERROR=y: .../drm/drm_mm.c:152:1: error: unused function 'drm_mm_interval_tree_insert' [-Werror,-Wunused-function] 152 | INTERVAL_TREE_DEFINE(struct drm_mm_node, rb, | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 153 | u64, __subtree_last, | ~~~~~~~~~~~~~~~~~~~~ 154 | START, LAST, static inline, drm_mm_interval_tree) | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Fix this by marking drm_mm_interval_tree*() functions with __maybe_unused. See also commit 6863f5643dd7 ("kbuild: allow Clang to find unused static inline functions for W=1 build"). Fixes: 202b52b7fbf7 ("drm: Track drm_mm nodes with an interval tree") Signed-off-by: Andy Shevchenko Reviewed-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20240829154640.1120050-1-andriy.shevchenko@linux.intel.com Signed-off-by: Jani Nikula Signed-off-by: Sasha Levin --- drivers/gpu/drm/drm_mm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 8257f9d4f619..22a373eaffef 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -151,7 +151,7 @@ static void show_leaks(struct drm_mm *mm) { } INTERVAL_TREE_DEFINE(struct drm_mm_node, rb, u64, __subtree_last, - START, LAST, static inline, drm_mm_interval_tree) + START, LAST, static inline __maybe_unused, drm_mm_interval_tree) struct drm_mm_node * __drm_mm_interval_first(const struct drm_mm *mm, u64 start, u64 last) From a5aeb962e44ede74b9db21cd9aad06e773fa02a9 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Fri, 21 Jun 2024 16:20:38 +0100 Subject: [PATCH 002/118] drm/vc4: hvs: Don't write gamma luts on 2711 [ Upstream commit 52efe364d1968ee3e3ed45eb44eb924b63635315 ] The gamma block has changed in 2711, therefore writing the lut in vc4_hvs_lut_load is incorrect. Whilst the gamma property isn't created for 2711, it is called from vc4_hvs_init_channel, so abort if attempted. Fixes: c54619b0bfb3 ("drm/vc4: Add support for the BCM2711 HVS5") Reviewed-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20240621152055.4180873-15-dave.stevenson@raspberrypi.com Signed-off-by: Dave Stevenson Signed-off-by: Sasha Levin --- drivers/gpu/drm/vc4/vc4_hvs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c index 47990ecbfc4d..cf017b59114e 100644 --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -220,6 +220,9 @@ static void vc4_hvs_lut_load(struct vc4_hvs *hvs, if (!drm_dev_enter(drm, &idx)) return; + if (hvs->vc4->is_vc5) + return; + /* The LUT memory is laid out with each HVS channel in order, * each of which takes 256 writes for R, 256 for G, then 256 * for B. From 0ea29bd7d9400d3629683244d609358ed1b12075 Mon Sep 17 00:00:00 2001 From: Dom Cobley Date: Fri, 21 Jun 2024 16:20:40 +0100 Subject: [PATCH 003/118] drm/vc4: hdmi: Avoid hang with debug registers when suspended [ Upstream commit 223ee2567a55e4f80315c768d2969e6a3b9fb23d ] Trying to read /sys/kernel/debug/dri/1/hdmi1_regs when the hdmi is disconnected results in a fatal system hang. This is due to the pm suspend code disabling the dvp clock. That is just a gate of the 108MHz clock in DVP_HT_RPI_MISC_CONFIG, which results in accesses hanging AXI bus. Protect against this. Fixes: 25eb441d55d4 ("drm/vc4: hdmi: Add all the vc5 HDMI registers into the debugfs dumps") Signed-off-by: Dom Cobley Reviewed-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20240621152055.4180873-17-dave.stevenson@raspberrypi.com Signed-off-by: Dave Stevenson Signed-off-by: Sasha Levin --- drivers/gpu/drm/vc4/vc4_hdmi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 971801acbde6..649fd5c03f21 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -170,6 +170,8 @@ static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused) if (!drm_dev_enter(drm, &idx)) return -ENODEV; + WARN_ON(pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev)); + drm_print_regset32(&p, &vc4_hdmi->hdmi_regset); drm_print_regset32(&p, &vc4_hdmi->hd_regset); drm_print_regset32(&p, &vc4_hdmi->cec_regset); @@ -179,6 +181,8 @@ static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused) drm_print_regset32(&p, &vc4_hdmi->ram_regset); drm_print_regset32(&p, &vc4_hdmi->rm_regset); + pm_runtime_put(&vc4_hdmi->pdev->dev); + drm_dev_exit(idx); return 0; From 253ccf145b55f2d8cb7e2701652b95f8303e7b66 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Fri, 21 Jun 2024 16:20:41 +0100 Subject: [PATCH 004/118] drm/vc4: hvs: Fix dlist debug not resetting the next entry pointer [ Upstream commit 6d5f76e0544b04ec5bdd2a09c19d90aeeb2cd479 ] The debug function to display the dlists didn't reset next_entry_start when starting each display, so resulting in not stopping the list at the correct place. Fixes: c6dac00340fc ("drm/vc4: hvs: Add debugfs node that dumps the current display lists") Reviewed-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20240621152055.4180873-18-dave.stevenson@raspberrypi.com Signed-off-by: Dave Stevenson Signed-off-by: Sasha Levin --- drivers/gpu/drm/vc4/vc4_hvs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c index cf017b59114e..a049899a1763 100644 --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -108,7 +108,7 @@ static int vc4_hvs_debugfs_dlist(struct seq_file *m, void *data) struct vc4_dev *vc4 = to_vc4_dev(dev); struct vc4_hvs *hvs = vc4->hvs; struct drm_printer p = drm_seq_file_printer(m); - unsigned int next_entry_start = 0; + unsigned int next_entry_start; unsigned int i, j; u32 dlist_word, dispstat; @@ -122,6 +122,7 @@ static int vc4_hvs_debugfs_dlist(struct seq_file *m, void *data) } drm_printf(&p, "HVS chan %u:\n", i); + next_entry_start = 0; for (j = HVS_READ(SCALER_DISPLISTX(i)); j < 256; j++) { dlist_word = readl((u32 __iomem *)vc4->hvs->dlist + j); From 151bec2fd015af9cd710026c9ed1e1c5c9cf10c1 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Fri, 21 Jun 2024 16:20:42 +0100 Subject: [PATCH 005/118] drm/vc4: hvs: Remove incorrect limit from hvs_dlist debugfs function [ Upstream commit d285bb622ebdfaa84f51df3a1abccb87036157ea ] The debugfs function to dump dlists aborted at 256 bytes, when actually the dlist memory is generally significantly larger but varies based on SoC. We already have the correct limit in __vc4_hvs_alloc, so store it for use in the debugfs dlist function. Fixes: c6dac00340fc ("drm/vc4: hvs: Add debugfs node that dumps the current display lists") Reviewed-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20240621152055.4180873-19-dave.stevenson@raspberrypi.com Signed-off-by: Dave Stevenson Signed-off-by: Sasha Levin --- drivers/gpu/drm/vc4/vc4_drv.h | 1 + drivers/gpu/drm/vc4/vc4_hvs.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 418a8242691f..7700e8dfd5f2 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -323,6 +323,7 @@ struct vc4_hvs { struct platform_device *pdev; void __iomem *regs; u32 __iomem *dlist; + unsigned int dlist_mem_size; struct clk *core_clk; diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c index a049899a1763..44b31d02c8ee 100644 --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -108,6 +108,7 @@ static int vc4_hvs_debugfs_dlist(struct seq_file *m, void *data) struct vc4_dev *vc4 = to_vc4_dev(dev); struct vc4_hvs *hvs = vc4->hvs; struct drm_printer p = drm_seq_file_printer(m); + unsigned int dlist_mem_size = hvs->dlist_mem_size; unsigned int next_entry_start; unsigned int i, j; u32 dlist_word, dispstat; @@ -124,7 +125,7 @@ static int vc4_hvs_debugfs_dlist(struct seq_file *m, void *data) drm_printf(&p, "HVS chan %u:\n", i); next_entry_start = 0; - for (j = HVS_READ(SCALER_DISPLISTX(i)); j < 256; j++) { + for (j = HVS_READ(SCALER_DISPLISTX(i)); j < dlist_mem_size; j++) { dlist_word = readl((u32 __iomem *)vc4->hvs->dlist + j); drm_printf(&p, "dlist: %02d: 0x%08x\n", j, dlist_word); @@ -827,9 +828,10 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) * our 16K), since we don't want to scramble the screen when * transitioning from the firmware's boot setup to runtime. */ + hvs->dlist_mem_size = (SCALER_DLIST_SIZE >> 2) - HVS_BOOTLOADER_DLIST_END; drm_mm_init(&hvs->dlist_mm, HVS_BOOTLOADER_DLIST_END, - (SCALER_DLIST_SIZE >> 2) - HVS_BOOTLOADER_DLIST_END); + hvs->dlist_mem_size); /* Set up the HVS LBM memory manager. We could have some more * complicated data structure that allowed reuse of LBM areas From cd53f82a1da4ebea8241f30f799ad90091ae72cb Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Fri, 21 Jun 2024 16:20:55 +0100 Subject: [PATCH 006/118] drm/vc4: hvs: Correct logic on stopping an HVS channel [ Upstream commit 7ab6512e7942889c0962588355cb92424a690be6 ] When factoring out __vc4_hvs_stop_channel, the logic got inverted from if (condition) // stop channel to if (condition) goto out //stop channel out: and also changed the exact register writes used to stop the channel. Correct the logic so that the channel is actually stopped, and revert to the original register writes. Fixes: 6d01a106b4c8 ("drm/vc4: crtc: Move HVS init and close to a function") Reviewed-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20240621152055.4180873-32-dave.stevenson@raspberrypi.com Signed-off-by: Dave Stevenson Signed-off-by: Sasha Levin --- drivers/gpu/drm/vc4/vc4_hvs.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c index 44b31d02c8ee..82c8eda2d435 100644 --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -418,13 +418,11 @@ void vc4_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int chan) if (!drm_dev_enter(drm, &idx)) return; - if (HVS_READ(SCALER_DISPCTRLX(chan)) & SCALER_DISPCTRLX_ENABLE) + if (!(HVS_READ(SCALER_DISPCTRLX(chan)) & SCALER_DISPCTRLX_ENABLE)) goto out; - HVS_WRITE(SCALER_DISPCTRLX(chan), - HVS_READ(SCALER_DISPCTRLX(chan)) | SCALER_DISPCTRLX_RESET); - HVS_WRITE(SCALER_DISPCTRLX(chan), - HVS_READ(SCALER_DISPCTRLX(chan)) & ~SCALER_DISPCTRLX_ENABLE); + HVS_WRITE(SCALER_DISPCTRLX(chan), SCALER_DISPCTRLX_RESET); + HVS_WRITE(SCALER_DISPCTRLX(chan), 0); /* Once we leave, the scaler should be disabled and its fifo empty. */ WARN_ON_ONCE(HVS_READ(SCALER_DISPCTRLX(chan)) & SCALER_DISPCTRLX_RESET); From 70eae50d2156cb6e078d0d78809b49bf2f4c7540 Mon Sep 17 00:00:00 2001 From: Jeongjun Park Date: Sat, 14 Sep 2024 12:06:03 +0300 Subject: [PATCH 007/118] wifi: ath9k: add range check for conn_rsp_epid in htc_connect_service() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 8619593634cbdf5abf43f5714df49b04e4ef09ab ] I found the following bug in my fuzzer: UBSAN: array-index-out-of-bounds in drivers/net/wireless/ath/ath9k/htc_hst.c:26:51 index 255 is out of range for type 'htc_endpoint [22]' CPU: 0 UID: 0 PID: 8 Comm: kworker/0:0 Not tainted 6.11.0-rc6-dirty #14 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 Workqueue: events request_firmware_work_func Call Trace: dump_stack_lvl+0x180/0x1b0 __ubsan_handle_out_of_bounds+0xd4/0x130 htc_issue_send.constprop.0+0x20c/0x230 ? _raw_spin_unlock_irqrestore+0x3c/0x70 ath9k_wmi_cmd+0x41d/0x610 ? mark_held_locks+0x9f/0xe0 ... Since this bug has been confirmed to be caused by insufficient verification of conn_rsp_epid, I think it would be appropriate to add a range check for conn_rsp_epid to htc_connect_service() to prevent the bug from occurring. Fixes: fb9987d0f748 ("ath9k_htc: Support for AR9271 chipset.") Signed-off-by: Jeongjun Park Acked-by: Toke Høiland-Jørgensen Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240909103855.68006-1-aha310510@gmail.com Signed-off-by: Sasha Levin --- drivers/net/wireless/ath/ath9k/htc_hst.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index 99667aba289d..00dc97ac53b9 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -294,6 +294,9 @@ int htc_connect_service(struct htc_target *target, return -ETIMEDOUT; } + if (target->conn_rsp_epid < 0 || target->conn_rsp_epid >= ENDPOINT_MAX) + return -EINVAL; + *conn_rsp_epid = target->conn_rsp_epid; return 0; err: From 6534234a5f853518dcda8c1878586c1886fa43af Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 6 Aug 2024 16:50:27 +0300 Subject: [PATCH 008/118] drm/omap: Fix possible NULL dereference [ Upstream commit a88fee2d67d9b78c24630a987a88ccf886b2498b ] smatch reports: drivers/gpu/drm/omapdrm/dss/base.c:176 omapdss_device_disconnect() error: we previously assumed 'src' could be null (see line 169) This code is mostly from a time when omapdrm had its own display device model. I can't honestly remember the details, and I don't think it's worth digging in deeply into that for a legacy driver. However, it looks like we only call omapdss_device_disconnect() and omapdss_device_connect() with NULL as the src parameter. We can thus drop the src parameter from both functions, and fix the smatch warning. I don't think omapdss_device_disconnect() ever gets NULL for the dst parameter (if it did, we'd crash soon after returning from the function), but I have kept the !dst check, just in case, but I added a WARN_ON() there. Also, if the dst parameter can be NULL, we can't always get the struct dss_device pointer from dst->dss (which is only used for a debug print). To make sure we can't hit that issue, do it similarly to the omapdss_device_connect() function: add 'struct dss_device *dss' as the first parameter, so that we always have it regardless of the dst. Fixes: 79107f274b2f ("drm/omap: Add support for drm_bridge") Reviewed-by: Sebastian Reichel Signed-off-by: Tomi Valkeinen Link: https://patchwork.freedesktop.org/patch/msgid/20240806-omapdrm-misc-fixes-v1-1-15d31aea0831@ideasonboard.com Signed-off-by: Sasha Levin --- drivers/gpu/drm/omapdrm/dss/base.c | 25 ++++++------------------- drivers/gpu/drm/omapdrm/dss/omapdss.h | 3 +-- drivers/gpu/drm/omapdrm/omap_drv.c | 4 ++-- 3 files changed, 9 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/base.c b/drivers/gpu/drm/omapdrm/dss/base.c index 050ca7eafac5..556e0f9026be 100644 --- a/drivers/gpu/drm/omapdrm/dss/base.c +++ b/drivers/gpu/drm/omapdrm/dss/base.c @@ -139,21 +139,13 @@ static bool omapdss_device_is_connected(struct omap_dss_device *dssdev) } int omapdss_device_connect(struct dss_device *dss, - struct omap_dss_device *src, struct omap_dss_device *dst) { - dev_dbg(&dss->pdev->dev, "connect(%s, %s)\n", - src ? dev_name(src->dev) : "NULL", + dev_dbg(&dss->pdev->dev, "connect(%s)\n", dst ? dev_name(dst->dev) : "NULL"); - if (!dst) { - /* - * The destination is NULL when the source is connected to a - * bridge instead of a DSS device. Stop here, we will attach - * the bridge later when we will have a DRM encoder. - */ - return src && src->bridge ? 0 : -EINVAL; - } + if (!dst) + return -EINVAL; if (omapdss_device_is_connected(dst)) return -EBUSY; @@ -163,19 +155,14 @@ int omapdss_device_connect(struct dss_device *dss, return 0; } -void omapdss_device_disconnect(struct omap_dss_device *src, +void omapdss_device_disconnect(struct dss_device *dss, struct omap_dss_device *dst) { - struct dss_device *dss = src ? src->dss : dst->dss; - - dev_dbg(&dss->pdev->dev, "disconnect(%s, %s)\n", - src ? dev_name(src->dev) : "NULL", + dev_dbg(&dss->pdev->dev, "disconnect(%s)\n", dst ? dev_name(dst->dev) : "NULL"); - if (!dst) { - WARN_ON(!src->bridge); + if (WARN_ON(!dst)) return; - } if (!dst->id && !omapdss_device_is_connected(dst)) { WARN_ON(1); diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index 040d5a3e33d6..4c22c09c93d5 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -242,9 +242,8 @@ struct omap_dss_device *omapdss_device_get(struct omap_dss_device *dssdev); void omapdss_device_put(struct omap_dss_device *dssdev); struct omap_dss_device *omapdss_find_device_by_node(struct device_node *node); int omapdss_device_connect(struct dss_device *dss, - struct omap_dss_device *src, struct omap_dss_device *dst); -void omapdss_device_disconnect(struct omap_dss_device *src, +void omapdss_device_disconnect(struct dss_device *dss, struct omap_dss_device *dst); int omap_dss_get_num_overlay_managers(void); diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index cc3bb0f6435b..b6e461a3f7a2 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -307,7 +307,7 @@ static void omap_disconnect_pipelines(struct drm_device *ddev) for (i = 0; i < priv->num_pipes; i++) { struct omap_drm_pipeline *pipe = &priv->pipes[i]; - omapdss_device_disconnect(NULL, pipe->output); + omapdss_device_disconnect(priv->dss, pipe->output); omapdss_device_put(pipe->output); pipe->output = NULL; @@ -325,7 +325,7 @@ static int omap_connect_pipelines(struct drm_device *ddev) int r; for_each_dss_output(output) { - r = omapdss_device_connect(priv->dss, NULL, output); + r = omapdss_device_connect(priv->dss, output); if (r == -EPROBE_DEFER) { omapdss_device_put(output); return r; From fa4a24f5b30dcefc7dff4352deb97b061a7591e2 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 6 Aug 2024 16:50:29 +0300 Subject: [PATCH 009/118] drm/omap: Fix locking in omap_gem_new_dmabuf() [ Upstream commit e6a1c4037227539373c8cf484ace83833e2ad6a2 ] omap_gem_new_dmabuf() creates the new gem object, and then takes and holds the omap_obj->lock for the rest of the function. This has two issues: - omap_gem_free_object(), which is called in the error paths, also takes the same lock, leading to deadlock - Even if the above wouldn't happen, in the error cases omap_gem_new_dmabuf() still unlocks omap_obj->lock, even after the omap_obj has already been freed. Furthermore, I don't think there's any reason to take the lock at all, as the object was just created and not yet shared with anyone else. To fix all this, drop taking the lock. Fixes: 3cbd0c587b12 ("drm/omap: gem: Replace struct_mutex usage with omap_obj private lock") Reported-by: Dan Carpenter Closes: https://lore.kernel.org/all/511b99d7-aade-4f92-bd3e-63163a13d617@stanley.mountain/ Reviewed-by: Sebastian Reichel Signed-off-by: Tomi Valkeinen Link: https://patchwork.freedesktop.org/patch/msgid/20240806-omapdrm-misc-fixes-v1-3-15d31aea0831@ideasonboard.com Signed-off-by: Sasha Levin --- drivers/gpu/drm/omapdrm/omap_gem.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index cf571796fd26..8fdb12ce2f88 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -1408,8 +1408,6 @@ struct drm_gem_object *omap_gem_new_dmabuf(struct drm_device *dev, size_t size, omap_obj = to_omap_bo(obj); - mutex_lock(&omap_obj->lock); - omap_obj->sgt = sgt; if (sgt->orig_nents == 1) { @@ -1424,21 +1422,17 @@ struct drm_gem_object *omap_gem_new_dmabuf(struct drm_device *dev, size_t size, pages = kcalloc(npages, sizeof(*pages), GFP_KERNEL); if (!pages) { omap_gem_free_object(obj); - obj = ERR_PTR(-ENOMEM); - goto done; + return ERR_PTR(-ENOMEM); } omap_obj->pages = pages; ret = drm_prime_sg_to_page_array(sgt, pages, npages); if (ret) { omap_gem_free_object(obj); - obj = ERR_PTR(-ENOMEM); - goto done; + return ERR_PTR(-ENOMEM); } } -done: - mutex_unlock(&omap_obj->lock); return obj; } From 3496512fe8cb17f214ee65b92f50048b808dc49f Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Tue, 10 Sep 2024 20:43:12 +0800 Subject: [PATCH 010/118] wifi: p54: Use IRQF_NO_AUTOEN flag in request_irq() [ Upstream commit bcd1371bd85e560ccc9159b7747f94bfe43b77a6 ] disable_irq() after request_irq() still has a time gap in which interrupts can come. request_irq() with IRQF_NO_AUTOEN flag will disable IRQ auto-enable when request IRQ. Fixes: cd8d3d321285 ("p54spi: p54spi driver") Signed-off-by: Jinjie Ruan Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240910124314.698896-2-ruanjinjie@huawei.com Signed-off-by: Sasha Levin --- drivers/net/wireless/intersil/p54/p54spi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/intersil/p54/p54spi.c b/drivers/net/wireless/intersil/p54/p54spi.c index 19152fd449ba..6fc694e8b7f8 100644 --- a/drivers/net/wireless/intersil/p54/p54spi.c +++ b/drivers/net/wireless/intersil/p54/p54spi.c @@ -623,7 +623,7 @@ static int p54spi_probe(struct spi_device *spi) gpio_direction_input(p54spi_gpio_irq); ret = request_irq(gpio_to_irq(p54spi_gpio_irq), - p54spi_interrupt, 0, "p54spi", + p54spi_interrupt, IRQF_NO_AUTOEN, "p54spi", priv->spi); if (ret < 0) { dev_err(&priv->spi->dev, "request_irq() failed"); @@ -632,8 +632,6 @@ static int p54spi_probe(struct spi_device *spi) irq_set_irq_type(gpio_to_irq(p54spi_gpio_irq), IRQ_TYPE_EDGE_RISING); - disable_irq(gpio_to_irq(p54spi_gpio_irq)); - INIT_WORK(&priv->work, p54spi_work); init_completion(&priv->fw_comp); INIT_LIST_HEAD(&priv->tx_pending); From 53cbeffdd729fa03ba06bf89d51fd4d0c6be9014 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Tue, 10 Sep 2024 20:43:13 +0800 Subject: [PATCH 011/118] wifi: mwifiex: Use IRQF_NO_AUTOEN flag in request_irq() [ Upstream commit 9a98dd48b6d834d7a3fe5e8e7b8c3a1d006f9685 ] disable_irq() after request_irq() still has a time gap in which interrupts can come. request_irq() with IRQF_NO_AUTOEN flag will disable IRQ auto-enable when request IRQ. Fixes: 853402a00823 ("mwifiex: Enable WoWLAN for both sdio and pcie") Signed-off-by: Jinjie Ruan Acked-by: Brian Norris Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240910124314.698896-3-ruanjinjie@huawei.com Signed-off-by: Sasha Levin --- drivers/net/wireless/marvell/mwifiex/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index da2e6557e684..59225fcacd59 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -1638,7 +1638,8 @@ static void mwifiex_probe_of(struct mwifiex_adapter *adapter) } ret = devm_request_irq(dev, adapter->irq_wakeup, - mwifiex_irq_wakeup_handler, IRQF_TRIGGER_LOW, + mwifiex_irq_wakeup_handler, + IRQF_TRIGGER_LOW | IRQF_NO_AUTOEN, "wifi_wake", adapter); if (ret) { dev_err(dev, "Failed to request irq_wakeup %d (%d)\n", @@ -1646,7 +1647,6 @@ static void mwifiex_probe_of(struct mwifiex_adapter *adapter) goto err_exit; } - disable_irq(adapter->irq_wakeup); if (device_init_wakeup(dev, true)) { dev_err(dev, "fail to init wakeup for mwifiex\n"); goto err_exit; From e6f8ec9cdb81359d4d340e1107b520d288a596fe Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Thu, 12 Sep 2024 16:30:16 +0800 Subject: [PATCH 012/118] drm/imx/dcss: Use IRQF_NO_AUTOEN flag in request_irq() [ Upstream commit 1af01e14db7e0b45ae502d822776a58c86688763 ] disable_irq() after request_irq() still has a time gap in which interrupts can come. request_irq() with IRQF_NO_AUTOEN flag will disable IRQ auto-enable when request IRQ. Fixes: 9021c317b770 ("drm/imx: Add initial support for DCSS on iMX8MQ") Signed-off-by: Jinjie Ruan Reviewed-by: Laurentiu Palcu Link: https://patchwork.freedesktop.org/patch/msgid/20240912083020.3720233-2-ruanjinjie@huawei.com [DB: fixed the subject] Signed-off-by: Dmitry Baryshkov Signed-off-by: Sasha Levin --- drivers/gpu/drm/imx/dcss/dcss-crtc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/imx/dcss/dcss-crtc.c b/drivers/gpu/drm/imx/dcss/dcss-crtc.c index 31267c00782f..af91e45b5d13 100644 --- a/drivers/gpu/drm/imx/dcss/dcss-crtc.c +++ b/drivers/gpu/drm/imx/dcss/dcss-crtc.c @@ -206,15 +206,13 @@ int dcss_crtc_init(struct dcss_crtc *crtc, struct drm_device *drm) if (crtc->irq < 0) return crtc->irq; - ret = request_irq(crtc->irq, dcss_crtc_irq_handler, - 0, "dcss_drm", crtc); + ret = request_irq(crtc->irq, dcss_crtc_irq_handler, IRQF_NO_AUTOEN, + "dcss_drm", crtc); if (ret) { dev_err(dcss->dev, "irq request failed with %d.\n", ret); return ret; } - disable_irq(crtc->irq); - return 0; } From 372e43bdc7c1e5c86a3b8ebbfadf3950fa257c12 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Thu, 12 Sep 2024 16:30:18 +0800 Subject: [PATCH 013/118] drm/imx/ipuv3: Use IRQF_NO_AUTOEN flag in request_irq() [ Upstream commit 40004709a3d3b07041a473a163ca911ef04ab8bd ] disable_irq() after request_irq() still has a time gap in which interrupts can come. request_irq() with IRQF_NO_AUTOEN flag will disable IRQ auto-enable when request IRQ. Fixes: 47b1be5c0f4e ("staging: imx/drm: request irq only after adding the crtc") Reviewed-by: Dmitry Baryshkov Signed-off-by: Jinjie Ruan Reviewed-by: Philipp Zabel Link: https://patchwork.freedesktop.org/patch/msgid/20240912083020.3720233-4-ruanjinjie@huawei.com Signed-off-by: Dmitry Baryshkov Signed-off-by: Sasha Levin --- drivers/gpu/drm/imx/ipuv3-crtc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c index 89585b31b985..5f423a2e0ede 100644 --- a/drivers/gpu/drm/imx/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3-crtc.c @@ -410,14 +410,12 @@ static int ipu_drm_bind(struct device *dev, struct device *master, void *data) } ipu_crtc->irq = ipu_plane_irq(ipu_crtc->plane[0]); - ret = devm_request_irq(ipu_crtc->dev, ipu_crtc->irq, ipu_irq_handler, 0, - "imx_drm", ipu_crtc); + ret = devm_request_irq(ipu_crtc->dev, ipu_crtc->irq, ipu_irq_handler, + IRQF_NO_AUTOEN, "imx_drm", ipu_crtc); if (ret < 0) { dev_err(ipu_crtc->dev, "irq request failed with %d.\n", ret); return ret; } - /* Only enable IRQ when we actually need it to trigger work. */ - disable_irq(ipu_crtc->irq); return 0; } From 1ec51f8404e1fb691e63acdf0a7fa9d6bd10760b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ADra=20Canal?= Date: Mon, 23 Sep 2024 10:55:05 -0300 Subject: [PATCH 014/118] drm/v3d: Address race-condition in MMU flush MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit cf1becb7f996a0a23ea2c270cf6bb0911ec3ca1a ] We must first flush the MMU cache and then, flush the TLB, not the other way around. Currently, we can see a race condition between the MMU cache and the TLB when running multiple rendering processes at the same time. This is evidenced by MMU errors triggered by the IRQ. Fix the MMU flush order by flushing the MMU cache and then the TLB. Also, in order to address the race condition, wait for the MMU cache flush to finish before starting the TLB flush. Fixes: 57692c94dcbe ("drm/v3d: Introduce a new DRM driver for Broadcom V3D V3.x+") Signed-off-by: Maíra Canal Reviewed-by: Iago Toral Quiroga Link: https://patchwork.freedesktop.org/patch/msgid/20240923141348.2422499-2-mcanal@igalia.com Signed-off-by: Sasha Levin --- drivers/gpu/drm/v3d/v3d_mmu.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/v3d/v3d_mmu.c b/drivers/gpu/drm/v3d/v3d_mmu.c index 5a453532901f..166d4a88daee 100644 --- a/drivers/gpu/drm/v3d/v3d_mmu.c +++ b/drivers/gpu/drm/v3d/v3d_mmu.c @@ -34,32 +34,23 @@ static int v3d_mmu_flush_all(struct v3d_dev *v3d) { int ret; - /* Make sure that another flush isn't already running when we - * start this one. - */ - ret = wait_for(!(V3D_READ(V3D_MMU_CTL) & - V3D_MMU_CTL_TLB_CLEARING), 100); - if (ret) - dev_err(v3d->drm.dev, "TLB clear wait idle pre-wait failed\n"); + V3D_WRITE(V3D_MMUC_CONTROL, V3D_MMUC_CONTROL_FLUSH | + V3D_MMUC_CONTROL_ENABLE); + + ret = wait_for(!(V3D_READ(V3D_MMUC_CONTROL) & + V3D_MMUC_CONTROL_FLUSHING), 100); + if (ret) { + dev_err(v3d->drm.dev, "MMUC flush wait idle failed\n"); + return ret; + } V3D_WRITE(V3D_MMU_CTL, V3D_READ(V3D_MMU_CTL) | V3D_MMU_CTL_TLB_CLEAR); - V3D_WRITE(V3D_MMUC_CONTROL, - V3D_MMUC_CONTROL_FLUSH | - V3D_MMUC_CONTROL_ENABLE); - ret = wait_for(!(V3D_READ(V3D_MMU_CTL) & V3D_MMU_CTL_TLB_CLEARING), 100); - if (ret) { - dev_err(v3d->drm.dev, "TLB clear wait idle failed\n"); - return ret; - } - - ret = wait_for(!(V3D_READ(V3D_MMUC_CONTROL) & - V3D_MMUC_CONTROL_FLUSHING), 100); if (ret) - dev_err(v3d->drm.dev, "MMUC flush wait idle failed\n"); + dev_err(v3d->drm.dev, "MMU TLB clear wait idle failed\n"); return ret; } From 266f9d3b7c1d82e487fb74866d19458eea1c414e Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Thu, 11 Jul 2024 10:03:43 +0800 Subject: [PATCH 015/118] wifi: ath10k: fix invalid VHT parameters in supported_vht_mcs_rate_nss1 [ Upstream commit d50886b27850447d90c0cd40c725238097909d1e ] In supported_vht_mcs_rate_nss1, the rate for MCS9 & VHT20 is defined as {780, 867}, this does not align with firmware's definition and therefore fails the verification in ath10k_mac_get_rate_flags_vht(): invalid vht params rate 960 100kbps nss 1 mcs 9 Change it to {865, 960} to align with firmware, so this issue could be fixed. Since ath10k_hw_params::supports_peer_stats_info is enabled only for QCA6174, this change does not affect other chips. Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00309-QCARMSWPZ-1 Fixes: 3344b99d69ab ("ath10k: add bitrate parse for peer stats info") Reported-by: Paul Menzel Closes: https://lore.kernel.org/lkml/fba24cd3-4a1e-4072-8585-8402272788ff@molgen.mpg.de/ Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240711020344.98040-2-quic_bqiang@quicinc.com Signed-off-by: Sasha Levin --- drivers/net/wireless/ath/ath10k/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index ec5c54672dfe..7e2700c0df1c 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -9120,7 +9120,7 @@ static const struct ath10k_index_vht_data_rate_type supported_vht_mcs_rate_nss1[ {6, {2633, 2925}, {1215, 1350}, {585, 650} }, {7, {2925, 3250}, {1350, 1500}, {650, 722} }, {8, {3510, 3900}, {1620, 1800}, {780, 867} }, - {9, {3900, 4333}, {1800, 2000}, {780, 867} } + {9, {3900, 4333}, {1800, 2000}, {865, 960} } }; /*MCS parameters with Nss = 2 */ From ade744bf81b478e78bd1734fcf014bfa5b0d303a Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Thu, 11 Jul 2024 10:03:44 +0800 Subject: [PATCH 016/118] wifi: ath10k: fix invalid VHT parameters in supported_vht_mcs_rate_nss2 [ Upstream commit 52db16ec5bae7bd027804265b968259d1a6c3970 ] In supported_vht_mcs_rate_nss2, the rate for MCS9 & VHT20 is defined as {1560, 1733}, this does not align with firmware's definition and therefore fails the verification in ath10k_mac_get_rate_flags_vht(): invalid vht params rate 1730 100kbps nss 2 mcs 9 and: invalid vht params rate 1920 100kbps nss 2 mcs 9 Change it to {1730, 1920} to align with firmware to fix the issue. Since ath10k_hw_params::supports_peer_stats_info is enabled only for QCA6174, this change does not affect other chips. Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00309-QCARMSWPZ-1 Fixes: 3344b99d69ab ("ath10k: add bitrate parse for peer stats info") Reported-by: Paul Menzel Closes: https://lore.kernel.org/lkml/fba24cd3-4a1e-4072-8585-8402272788ff@molgen.mpg.de/ Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Tested-by: Paul Menzel # Dell XPS 13 9360 Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20240711020344.98040-3-quic_bqiang@quicinc.com Signed-off-by: Sasha Levin --- drivers/net/wireless/ath/ath10k/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 7e2700c0df1c..184c722255c6 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -9135,7 +9135,7 @@ static const struct ath10k_index_vht_data_rate_type supported_vht_mcs_rate_nss2[ {6, {5265, 5850}, {2430, 2700}, {1170, 1300} }, {7, {5850, 6500}, {2700, 3000}, {1300, 1444} }, {8, {7020, 7800}, {3240, 3600}, {1560, 1733} }, - {9, {7800, 8667}, {3600, 4000}, {1560, 1733} } + {9, {7800, 8667}, {3600, 4000}, {1730, 1920} } }; static void ath10k_mac_get_rate_flags_ht(struct ath10k *ar, u32 rate, u8 nss, u8 mcs, From 54ea2e51bb2e267fcab6e45c600865d473f5c086 Mon Sep 17 00:00:00 2001 From: Igor Prusov Date: Wed, 25 Sep 2024 17:52:39 +0300 Subject: [PATCH 017/118] dt-bindings: vendor-prefixes: Add NeoFidelity, Inc [ Upstream commit 5d9e6d6fc1b98c8c22d110ee931b3b233d43cd13 ] Add vendor prefix for NeoFidelity, Inc Signed-off-by: Igor Prusov Acked-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20240925-ntp-amps-8918-8835-v3-1-e2459a8191a6@salutedevices.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 6e323a380294..77e9413cdee0 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -869,6 +869,8 @@ patternProperties: description: National Semiconductor "^nec,.*": description: NEC LCD Technologies, Ltd. + "^neofidelity,.*": + description: Neofidelity Inc. "^neonode,.*": description: Neonode Inc. "^netgear,.*": From 5e6df74efcd46c95f4435d5b4bf35bbc94d49f1a Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 27 Sep 2024 16:00:29 +0800 Subject: [PATCH 018/118] ASoC: fsl_micfil: fix regmap_write_bits usage [ Upstream commit 06df673d20230afb0e383e39235a4fa8b9a62464 ] The last parameter 1 means BIT(0), which should be the correct BIT(X). Fixes: 47a70e6fc9a8 ("ASoC: Add MICFIL SoC Digital Audio Interface driver.") Signed-off-by: Shengjiu Wang Reviewed-by: Daniel Baluta Link: https://patch.msgid.link/1727424031-19551-2-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/fsl/fsl_micfil.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index 3a03f49452fa..6fa900302aa8 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -563,7 +563,7 @@ static irqreturn_t micfil_isr(int irq, void *devid) regmap_write_bits(micfil->regmap, REG_MICFIL_STAT, MICFIL_STAT_CHXF(i), - 1); + MICFIL_STAT_CHXF(i)); } for (i = 0; i < MICFIL_FIFO_NUM; i++) { @@ -598,7 +598,7 @@ static irqreturn_t micfil_err_isr(int irq, void *devid) if (stat_reg & MICFIL_STAT_LOWFREQF) { dev_dbg(&pdev->dev, "isr: ipg_clk_app is too low\n"); regmap_write_bits(micfil->regmap, REG_MICFIL_STAT, - MICFIL_STAT_LOWFREQF, 1); + MICFIL_STAT_LOWFREQF, MICFIL_STAT_LOWFREQF); } return IRQ_HANDLED; From ea6a2cc95e49d05a155e8e53109576ee94712275 Mon Sep 17 00:00:00 2001 From: Macpaul Lin Date: Mon, 30 Sep 2024 15:54:50 +0800 Subject: [PATCH 019/118] ASoC: dt-bindings: mt6359: Update generic node name and dmic-mode [ Upstream commit 4649cbd97fdae5069e9a71cd7669b62b90e03669 ] Some fix and updates in the following items: 1. examples: Update generic node name to 'audio-codec' to comply with the coming change in 'mt6359.dtsi'. This change is necessary to fix the dtbs_check error: pmic: 'mt6359codec' does not match any of the regexes: 'pinctrl-[0-9]+' 2. mediatek,dmic-mode: After inspecting the .dts and .dtsi files using 'mt6359-codec', it was discovered that the definitions of 'two wires' and 'one wire' are inverted compared to the DT schema. For example, the following boards using MT6359 PMIC: - mt8192-asurada.dtsi - mt8195-cherry.dtsi These boards use the same definitions of 'dmic-mode' as other boards using MT6358 PMIC. The meaning of '0' or '1' has been noted as comments in the device trees. Upon examining the code in [1] and [2], it was confirmed that the definitions of 'dmic-mode' are consistent between "MT6359 PMIC" and "MT6358 PMIC". Therefore, the DT Schema should be correct as is. References: [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/sound/soc/codecs/mt6358.c#n1875 [2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/sound/soc/codecs/mt6359.c#L1515 Fixes: 539237d1c609 ("dt-bindings: mediatek: mt6359: add codec document") Signed-off-by: Jiaxin Yu Signed-off-by: Macpaul Lin Reviewed-by: AngeloGioacchino Del Regno Link: https://patch.msgid.link/20240930075451.14196-1-macpaul.lin@mediatek.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- Documentation/devicetree/bindings/sound/mt6359.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/mt6359.yaml b/Documentation/devicetree/bindings/sound/mt6359.yaml index 23d411fc4200..128698630c86 100644 --- a/Documentation/devicetree/bindings/sound/mt6359.yaml +++ b/Documentation/devicetree/bindings/sound/mt6359.yaml @@ -23,8 +23,8 @@ properties: Indicates how many data pins are used to transmit two channels of PDM signal. 0 means two wires, 1 means one wire. Default value is 0. enum: - - 0 # one wire - - 1 # two wires + - 0 # two wires + - 1 # one wire mediatek,mic-type-0: $ref: /schemas/types.yaml#/definitions/uint32 @@ -53,9 +53,9 @@ additionalProperties: false examples: - | - mt6359codec: mt6359codec { - mediatek,dmic-mode = <0>; - mediatek,mic-type-0 = <2>; + mt6359codec: audio-codec { + mediatek,dmic-mode = <0>; + mediatek,mic-type-0 = <2>; }; ... From 1f3288f2bd5e3847553ac09febc9fcb0e97a444b Mon Sep 17 00:00:00 2001 From: Pin-yen Lin Date: Thu, 26 Sep 2024 17:29:08 +0800 Subject: [PATCH 020/118] drm/bridge: anx7625: Drop EDID cache on bridge power off [ Upstream commit 00ae002116a14c2e6a342c4c9ae080cdbb9b4b21 ] The bridge might miss the display change events when it's powered off. This happens when a user changes the external monitor when the system is suspended and the embedded controller doesn't not wake AP up. It's also observed that one DP-to-HDMI bridge doesn't work correctly when there is no EDID read after it is powered on. Drop the cache to force an EDID read after system resume to fix this. Fixes: 8bdfc5dae4e3 ("drm/bridge: anx7625: Add anx7625 MIPI DSI/DPI to DP") Signed-off-by: Pin-yen Lin Reviewed-by: Dmitry Baryshkov Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20240926092931.3870342-2-treapking@chromium.org Signed-off-by: Sasha Levin --- drivers/gpu/drm/bridge/analogix/anx7625.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 193015c75b45..e14c9fdabe2b 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -2567,6 +2567,8 @@ static int __maybe_unused anx7625_runtime_pm_suspend(struct device *dev) mutex_lock(&ctx->lock); anx7625_stop_dp_work(ctx); + if (!ctx->pdata.panel_bridge) + anx7625_remove_edid(ctx); anx7625_power_standby(ctx); mutex_unlock(&ctx->lock); From d0307b1aa0d3f68e289eb2ca93a4ff3a941b81f7 Mon Sep 17 00:00:00 2001 From: Tony Ambardar Date: Mon, 16 Sep 2024 01:37:42 -0700 Subject: [PATCH 021/118] libbpf: Fix output .symtab byte-order during linking [ Upstream commit f896b4a5399e97af0b451fcf04754ed316935674 ] Object linking output data uses the default ELF_T_BYTE type for '.symtab' section data, which disables any libelf-based translation. Explicitly set the ELF_T_SYM type for output to restore libelf's byte-order conversion, noting that input '.symtab' data is already correctly translated. Fixes: faf6ed321cf6 ("libbpf: Add BPF static linker APIs") Signed-off-by: Tony Ambardar Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/87868bfeccf3f51aec61260073f8778e9077050a.1726475448.git.tony.ambardar@gmail.com Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- tools/lib/bpf/linker.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/lib/bpf/linker.c b/tools/lib/bpf/linker.c index 8a7cb830bff1..7d28f21b007f 100644 --- a/tools/lib/bpf/linker.c +++ b/tools/lib/bpf/linker.c @@ -396,6 +396,8 @@ static int init_output_elf(struct bpf_linker *linker, const char *file) pr_warn_elf("failed to create SYMTAB data"); return -EINVAL; } + /* Ensure libelf translates byte-order of symbol records */ + sec->data->d_type = ELF_T_SYM; str_off = strset__add_str(linker->strtab_strs, sec->sec_name); if (str_off < 0) From 79c83dc3c819f23fe37ee0429a367b0bb32f59fd Mon Sep 17 00:00:00 2001 From: Yuan Chen Date: Mon, 30 Sep 2024 10:41:15 +0800 Subject: [PATCH 022/118] bpf: Fix the xdp_adjust_tail sample prog issue [ Upstream commit 4236f114a3ffbbfd217436c08852e94cae372f57 ] During the xdp_adjust_tail test, probabilistic failure occurs and SKB package is discarded by the kernel. After checking the issues by tracking SKB package, it is identified that they were caused by checksum errors. Refer to checksum of the arch/arm64/include/asm/checksum.h for fixing. v2: Based on Alexei Starovoitov's suggestions, it is necessary to keep the code implementation consistent. Fixes: c6ffd1ff7856 (bpf: add bpf_xdp_adjust_tail sample prog) Signed-off-by: Yuan Chen Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20240930024115.52841-1-chenyuan_fl@163.com Signed-off-by: Sasha Levin --- samples/bpf/xdp_adjust_tail_kern.c | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/bpf/xdp_adjust_tail_kern.c b/samples/bpf/xdp_adjust_tail_kern.c index ffdd548627f0..da67bcad1c63 100644 --- a/samples/bpf/xdp_adjust_tail_kern.c +++ b/samples/bpf/xdp_adjust_tail_kern.c @@ -57,6 +57,7 @@ static __always_inline void swap_mac(void *data, struct ethhdr *orig_eth) static __always_inline __u16 csum_fold_helper(__u32 csum) { + csum = (csum & 0xffff) + (csum >> 16); return ~((csum & 0xffff) + (csum >> 16)); } From 6a75c14af69a18729a0401ec3ece8b0163b91189 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 27 Nov 2023 11:03:16 -0800 Subject: [PATCH 023/118] selftests/bpf: Add csum helpers [ Upstream commit f6642de0c3e94d3ef6f44e127d11fcf4138873f7 ] Checksum helpers will be used to calculate pseudo-header checksum in AF_XDP metadata selftests. The helpers are mirroring existing kernel ones: - csum_tcpudp_magic : IPv4 pseudo header csum - csum_ipv6_magic : IPv6 pseudo header csum - csum_fold : fold csum and do one's complement Signed-off-by: Stanislav Fomichev Link: https://lore.kernel.org/r/20231127190319.1190813-11-sdf@google.com Signed-off-by: Alexei Starovoitov Stable-dep-of: 5bf1557e3d6a ("selftests/bpf: Fix backtrace printing for selftests crashes") Signed-off-by: Sasha Levin --- tools/testing/selftests/bpf/network_helpers.h | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/tools/testing/selftests/bpf/network_helpers.h b/tools/testing/selftests/bpf/network_helpers.h index f882c691b790..2582ec56dcc5 100644 --- a/tools/testing/selftests/bpf/network_helpers.h +++ b/tools/testing/selftests/bpf/network_helpers.h @@ -66,4 +66,47 @@ struct nstoken; */ struct nstoken *open_netns(const char *name); void close_netns(struct nstoken *token); + +static __u16 csum_fold(__u32 csum) +{ + csum = (csum & 0xffff) + (csum >> 16); + csum = (csum & 0xffff) + (csum >> 16); + + return (__u16)~csum; +} + +static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, + __u32 len, __u8 proto, + __wsum csum) +{ + __u64 s = csum; + + s += (__u32)saddr; + s += (__u32)daddr; + s += htons(proto + len); + s = (s & 0xffffffff) + (s >> 32); + s = (s & 0xffffffff) + (s >> 32); + + return csum_fold((__u32)s); +} + +static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr, + const struct in6_addr *daddr, + __u32 len, __u8 proto, + __wsum csum) +{ + __u64 s = csum; + int i; + + for (i = 0; i < 4; i++) + s += (__u32)saddr->s6_addr32[i]; + for (i = 0; i < 4; i++) + s += (__u32)daddr->s6_addr32[i]; + s += htons(proto + len); + s = (s & 0xffffffff) + (s >> 32); + s = (s & 0xffffffff) + (s >> 32); + + return csum_fold((__u32)s); +} + #endif From 2eda63873b4c3975dc5316dab15c11a4c1558c8d Mon Sep 17 00:00:00 2001 From: Eduard Zingerman Date: Thu, 3 Oct 2024 14:03:07 -0700 Subject: [PATCH 024/118] selftests/bpf: Fix backtrace printing for selftests crashes [ Upstream commit 5bf1557e3d6a69113649d831276ea2f97585fc33 ] test_progs uses glibc specific functions backtrace() and backtrace_symbols_fd() to print backtrace in case of SIGSEGV. Recent commit (see fixes) updated test_progs.c to define stub versions of the same functions with attriubte "weak" in order to allow linking test_progs against musl libc. Unfortunately this broke the backtrace handling for glibc builds. As it turns out, glibc defines backtrace() and backtrace_symbols_fd() as weak: $ llvm-readelf --symbols /lib64/libc.so.6 \ | grep -P '( backtrace_symbols_fd| backtrace)$' 4910: 0000000000126b40 161 FUNC WEAK DEFAULT 16 backtrace 6843: 0000000000126f90 852 FUNC WEAK DEFAULT 16 backtrace_symbols_fd So does test_progs: $ llvm-readelf --symbols test_progs \ | grep -P '( backtrace_symbols_fd| backtrace)$' 2891: 00000000006ad190 15 FUNC WEAK DEFAULT 13 backtrace 11215: 00000000006ad1a0 41 FUNC WEAK DEFAULT 13 backtrace_symbols_fd In such situation dynamic linker is not obliged to favour glibc implementation over the one defined in test_progs. Compiling with the following simple modification to test_progs.c demonstrates the issue: $ git diff ... \--- a/tools/testing/selftests/bpf/test_progs.c \+++ b/tools/testing/selftests/bpf/test_progs.c \@@ -1817,6 +1817,7 @@ int main(int argc, char **argv) if (err) return err; + *(int *)0xdeadbeef = 42; err = cd_flavor_subdir(argv[0]); if (err) return err; $ ./test_progs [0]: Caught signal #11! Stack trace: Segmentation fault (core dumped) Resolve this by hiding stub definitions behind __GLIBC__ macro check instead of using "weak" attribute. Fixes: c9a83e76b5a9 ("selftests/bpf: Fix compile if backtrace support missing in libc") Signed-off-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Tested-by: Tony Ambardar Reviewed-by: Tony Ambardar Acked-by: Daniel Xu Link: https://lore.kernel.org/bpf/20241003210307.3847907-1-eddyz87@gmail.com Signed-off-by: Sasha Levin --- tools/testing/selftests/bpf/test_progs.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c index 11d4c51c7d21..6068f5bde8fd 100644 --- a/tools/testing/selftests/bpf/test_progs.c +++ b/tools/testing/selftests/bpf/test_progs.c @@ -16,11 +16,13 @@ #include #include +/* backtrace() and backtrace_symbols_fd() are glibc specific, + * use header file when glibc is available and provide stub + * implementations when another libc implementation is used. + */ #ifdef __GLIBC__ #include /* backtrace */ -#endif - -/* Default backtrace funcs if missing at link */ +#else __weak int backtrace(void **buffer, int size) { return 0; @@ -30,6 +32,7 @@ __weak void backtrace_symbols_fd(void *const *buffer, int size, int fd) { dprintf(fd, "\n"); } +#endif /*__GLIBC__ */ static bool verbose(void) { From b15f3d26c4d7221dfd7984e5efa3d568a5f6b923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Lothor=C3=A9=20=28eBPF=20Foundation=29?= Date: Tue, 8 Oct 2024 16:50:57 +0200 Subject: [PATCH 025/118] selftests/bpf: add missing header include for htons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit bc9b3fb827fceec4e05564d6e668280f4470ab5b ] Including the network_helpers.h header in tests can lead to the following build error: ./network_helpers.h: In function ‘csum_tcpudp_magic’: ./network_helpers.h:116:14: error: implicit declaration of function \ ‘htons’ [-Werror=implicit-function-declaration] 116 | s += htons(proto + len); The error is avoided in many cases thanks to some other headers included earlier and bringing in arpa/inet.h (ie: test_progs.h). Make sure that test_progs build success does not depend on header ordering by adding the missing header include in network_helpers.h Fixes: f6642de0c3e9 ("selftests/bpf: Add csum helpers") Signed-off-by: Alexis Lothoré (eBPF Foundation) Link: https://lore.kernel.org/r/20241008-network_helpers_fix-v1-1-2c2ae03df7ef@bootlin.com Signed-off-by: Martin KaFai Lau Signed-off-by: Sasha Levin --- tools/testing/selftests/bpf/network_helpers.h | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/bpf/network_helpers.h b/tools/testing/selftests/bpf/network_helpers.h index 2582ec56dcc5..535b72623dd4 100644 --- a/tools/testing/selftests/bpf/network_helpers.h +++ b/tools/testing/selftests/bpf/network_helpers.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ #ifndef __NETWORK_HELPERS_H #define __NETWORK_HELPERS_H +#include #include #include #include From da508bb398ebfaf6cda4378cb9cc412a2657727b Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 8 Oct 2024 18:15:54 -0700 Subject: [PATCH 026/118] libbpf: fix sym_is_subprog() logic for weak global subprogs [ Upstream commit 4073213488be542f563eb4b2457ab4cbcfc2b738 ] sym_is_subprog() is incorrectly rejecting relocations against *weak* global subprogs. Fix that by realizing that STB_WEAK is also a global function. While it seems like verifier doesn't support taking an address of non-static subprog right now, it's still best to fix support for it on libbpf side, otherwise users will get a very confusing error during BPF skeleton generation or static linking due to misinterpreted relocation: libbpf: prog 'handle_tp': bad map relo against 'foo' in section '.text' Error: failed to open BPF object file: Relocation failed It's clearly not a map relocation, but is treated and reported as such without this fix. Fixes: 53eddb5e04ac ("libbpf: Support subprog address relocation") Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20241009011554.880168-1-andrii@kernel.org Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- tools/lib/bpf/libbpf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 878f05a42421..d8b5304eac8c 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -3501,7 +3501,7 @@ static bool sym_is_subprog(const Elf64_Sym *sym, int text_shndx) return true; /* global function */ - return bind == STB_GLOBAL && type == STT_FUNC; + return (bind == STB_GLOBAL || bind == STB_WEAK) && type == STT_FUNC; } static int find_extern_btf_id(const struct btf *btf, const char *ext_name) From 241aef4f88e35234b2f7d27ffb34ce296389b38b Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 10 Oct 2024 14:17:30 -0700 Subject: [PATCH 027/118] libbpf: never interpret subprogs in .text as entry programs [ Upstream commit db089c9158c1d535a36dfc010e5db37fccea2561 ] Libbpf pre-1.0 had a legacy logic of allowing singular non-annotated (i.e., not having explicit SEC() annotation) function to be treated as sole entry BPF program (unless there were other explicit entry programs). This behavior was dropped during libbpf 1.0 transition period (unless LIBBPF_STRICT_SEC_NAME flag was unset in libbpf_mode). When 1.0 was released and all the legacy behavior was removed, the bug slipped through leaving this legacy behavior around. Fix this for good, as it actually causes very confusing behavior if BPF object file only has subprograms, but no entry programs. Fixes: bd054102a8c7 ("libbpf: enforce strict libbpf 1.0 behaviors") Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20241010211731.4121837-1-andrii@kernel.org Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- tools/lib/bpf/libbpf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index d8b5304eac8c..a0fb50718dae 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -3896,7 +3896,7 @@ static int bpf_object__collect_externs(struct bpf_object *obj) static bool prog_is_subprog(const struct bpf_object *obj, const struct bpf_program *prog) { - return prog->sec_idx == obj->efile.text_shndx && obj->nr_programs > 1; + return prog->sec_idx == obj->efile.text_shndx; } struct bpf_program * From b3a9001123797ad5e100aa66ff720d085bb12890 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Thu, 10 Oct 2024 04:00:26 +0000 Subject: [PATCH 028/118] netdevsim: copy addresses for both in and out paths [ Upstream commit 2cf567f421dbfe7e53b7e5ddee9400da10efb75d ] The current code only copies the address for the in path, leaving the out path address set to 0. This patch corrects the issue by copying the addresses for both the in and out paths. Before this patch: # cat /sys/kernel/debug/netdevsim/netdevsim0/ports/0/ipsec SA count=2 tx=20 sa[0] tx ipaddr=0.0.0.0 sa[0] spi=0x00000100 proto=0x32 salt=0x0adecc3a crypt=1 sa[0] key=0x3167608a ca4f1397 43565909 941fa627 sa[1] rx ipaddr=192.168.0.1 sa[1] spi=0x00000101 proto=0x32 salt=0x0adecc3a crypt=1 sa[1] key=0x3167608a ca4f1397 43565909 941fa627 After this patch: = cat /sys/kernel/debug/netdevsim/netdevsim0/ports/0/ipsec SA count=2 tx=20 sa[0] tx ipaddr=192.168.0.2 sa[0] spi=0x00000100 proto=0x32 salt=0x0adecc3a crypt=1 sa[0] key=0x3167608a ca4f1397 43565909 941fa627 sa[1] rx ipaddr=192.168.0.1 sa[1] spi=0x00000101 proto=0x32 salt=0x0adecc3a crypt=1 sa[1] key=0x3167608a ca4f1397 43565909 941fa627 Fixes: 7699353da875 ("netdevsim: add ipsec offload testing") Reviewed-by: Simon Horman Signed-off-by: Hangbin Liu Link: https://patch.msgid.link/20241010040027.21440-3-liuhangbin@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/netdevsim/ipsec.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/net/netdevsim/ipsec.c b/drivers/net/netdevsim/ipsec.c index 386336a38f34..feca55eef993 100644 --- a/drivers/net/netdevsim/ipsec.c +++ b/drivers/net/netdevsim/ipsec.c @@ -171,14 +171,13 @@ static int nsim_ipsec_add_sa(struct xfrm_state *xs) return ret; } - if (xs->xso.dir == XFRM_DEV_OFFLOAD_IN) { + if (xs->xso.dir == XFRM_DEV_OFFLOAD_IN) sa.rx = true; - if (xs->props.family == AF_INET6) - memcpy(sa.ipaddr, &xs->id.daddr.a6, 16); - else - memcpy(&sa.ipaddr[3], &xs->id.daddr.a4, 4); - } + if (xs->props.family == AF_INET6) + memcpy(sa.ipaddr, &xs->id.daddr.a6, 16); + else + memcpy(&sa.ipaddr[3], &xs->id.daddr.a4, 4); /* the preparations worked, so save the info */ memcpy(&ipsec->sa[sa_idx], &sa, sizeof(sa)); From df3554b221507fc100fec8a5486dd7e606678a65 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 8 Nov 2023 13:27:23 +0200 Subject: [PATCH 029/118] drm/bridge: tc358767: Fix link properties discovery [ Upstream commit 2d343723c7e1f9f6d64f721f07cfdfc2993758d1 ] When a display controller driver uses DRM_BRIDGE_ATTACH_NO_CONNECTOR, tc358767 will behave properly and skip the creation of the connector. However, tc_get_display_props(), which is used to find out about the DP monitor and link, is only called from two places: .atomic_enable() and tc_connector_get_modes(). The latter is only used when tc358767 creates its own connector, i.e. when DRM_BRIDGE_ATTACH_NO_CONNECTOR is _not_ set. Thus, the driver never finds out the link properties before get_edid() is called. With num_lanes of 0 and link_rate of 0 there are not many valid modes... Fix this by adding tc_get_display_props() call at the beginning of get_edid(), so that we have up to date information before looking at the modes. Reported-by: Jan Kiszka Closes: https://lore.kernel.org/all/24282420-b4dd-45b3-bb1c-fc37fe4a8205@siemens.com/ Fixes: de5e6c027ae6 ("drm/bridge: tc358767: add drm_panel_bridge support") Reviewed-by: Aradhya Bhatia Tested-by: Jan Kiszka Signed-off-by: Tomi Valkeinen Link: https://patchwork.freedesktop.org/patch/msgid/20231108-tc358767-v2-2-25c5f70a2159@ideasonboard.com Signed-off-by: Dmitry Baryshkov Signed-off-by: Sasha Levin --- drivers/gpu/drm/bridge/tc358767.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 0af2bd8706e4..a6b3af902642 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -1579,6 +1579,13 @@ static struct edid *tc_get_edid(struct drm_bridge *bridge, struct drm_connector *connector) { struct tc_data *tc = bridge_to_tc(bridge); + int ret; + + ret = tc_get_display_props(tc); + if (ret < 0) { + dev_err(tc->dev, "failed to read display props: %d\n", ret); + return 0; + } return drm_get_edid(connector, &tc->aux.ddc); } From a315b5b672bf3efe3b217fc8cd220b156bf0aafc Mon Sep 17 00:00:00 2001 From: Zijian Zhang Date: Sat, 12 Oct 2024 20:37:30 +0000 Subject: [PATCH 030/118] selftests/bpf: Fix msg_verify_data in test_sockmap [ Upstream commit ee9b352ce4650ffc0d8ca0ac373d7c009c7e561e ] Function msg_verify_data should have context of bytes_cnt and k instead of assuming they are zero. Otherwise, test_sockmap with data integrity test will report some errors. I also fix the logic related to size and index j 1/ 6 sockmap::txmsg test passthrough:FAIL 2/ 6 sockmap::txmsg test redirect:FAIL 7/12 sockmap::txmsg test apply:FAIL 10/11 sockmap::txmsg test push_data:FAIL 11/17 sockmap::txmsg test pull-data:FAIL 12/ 9 sockmap::txmsg test pop-data:FAIL 13/ 1 sockmap::txmsg test push/pop data:FAIL ... Pass: 24 Fail: 52 After applying this patch, some of the errors are solved, but for push, pull and pop, we may need more fixes to msg_verify_data, added a TODO 10/11 sockmap::txmsg test push_data:FAIL 11/17 sockmap::txmsg test pull-data:FAIL 12/ 9 sockmap::txmsg test pop-data:FAIL ... Pass: 37 Fail: 15 Besides, added a custom errno EDATAINTEGRITY for msg_verify_data, we shall not ignore the error in txmsg_cork case. Fixes: 753fb2ee0934 ("bpf: sockmap, add msg_peek tests to test_sockmap") Fixes: 16edddfe3c5d ("selftests/bpf: test_sockmap, check test failure") Acked-by: John Fastabend Signed-off-by: Zijian Zhang Link: https://lore.kernel.org/r/20241012203731.1248619-2-zijianzhang@bytedance.com Signed-off-by: Martin KaFai Lau Signed-off-by: Sasha Levin --- tools/testing/selftests/bpf/test_sockmap.c | 30 ++++++++++++++-------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/bpf/test_sockmap.c b/tools/testing/selftests/bpf/test_sockmap.c index 25da05cad8f6..72023e1b894d 100644 --- a/tools/testing/selftests/bpf/test_sockmap.c +++ b/tools/testing/selftests/bpf/test_sockmap.c @@ -56,6 +56,8 @@ static void running_handler(int a); #define BPF_SOCKHASH_FILENAME "test_sockhash_kern.bpf.o" #define CG_PATH "/sockmap" +#define EDATAINTEGRITY 2001 + /* global sockets */ int s1, s2, c1, c2, p1, p2; int test_cnt; @@ -509,23 +511,25 @@ unwind_iov: return -ENOMEM; } -static int msg_verify_data(struct msghdr *msg, int size, int chunk_sz) +/* TODO: Add verification logic for push, pull and pop data */ +static int msg_verify_data(struct msghdr *msg, int size, int chunk_sz, + unsigned char *k_p, int *bytes_cnt_p) { - int i, j = 0, bytes_cnt = 0; - unsigned char k = 0; + int i, j, bytes_cnt = *bytes_cnt_p; + unsigned char k = *k_p; - for (i = 0; i < msg->msg_iovlen; i++) { + for (i = 0, j = 0; i < msg->msg_iovlen && size; i++, j = 0) { unsigned char *d = msg->msg_iov[i].iov_base; /* Special case test for skb ingress + ktls */ if (i == 0 && txmsg_ktls_skb) { if (msg->msg_iov[i].iov_len < 4) - return -EIO; + return -EDATAINTEGRITY; if (memcmp(d, "PASS", 4) != 0) { fprintf(stderr, "detected skb data error with skb ingress update @iov[%i]:%i \"%02x %02x %02x %02x\" != \"PASS\"\n", i, 0, d[0], d[1], d[2], d[3]); - return -EIO; + return -EDATAINTEGRITY; } j = 4; /* advance index past PASS header */ } @@ -535,7 +539,7 @@ static int msg_verify_data(struct msghdr *msg, int size, int chunk_sz) fprintf(stderr, "detected data corruption @iov[%i]:%i %02x != %02x, %02x ?= %02x\n", i, j, d[j], k - 1, d[j+1], k); - return -EIO; + return -EDATAINTEGRITY; } bytes_cnt++; if (bytes_cnt == chunk_sz) { @@ -545,6 +549,8 @@ static int msg_verify_data(struct msghdr *msg, int size, int chunk_sz) size--; } } + *k_p = k; + *bytes_cnt_p = bytes_cnt; return 0; } @@ -601,6 +607,8 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt, float total_bytes, txmsg_pop_total; int fd_flags = O_NONBLOCK; struct timeval timeout; + unsigned char k = 0; + int bytes_cnt = 0; fd_set w; fcntl(fd, fd_flags); @@ -695,7 +703,7 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt, iov_length * cnt : iov_length * iov_count; - errno = msg_verify_data(&msg, recv, chunk_sz); + errno = msg_verify_data(&msg, recv, chunk_sz, &k, &bytes_cnt); if (errno) { perror("data verify msg failed"); goto out_errno; @@ -703,7 +711,9 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt, if (recvp) { errno = msg_verify_data(&msg_peek, recvp, - chunk_sz); + chunk_sz, + &k, + &bytes_cnt); if (errno) { perror("data verify msg_peek failed"); goto out_errno; @@ -811,7 +821,7 @@ static int sendmsg_test(struct sockmap_options *opt) s.bytes_sent, sent_Bps, sent_Bps/giga, s.bytes_recvd, recvd_Bps, recvd_Bps/giga, peek_flag ? "(peek_msg)" : ""); - if (err && txmsg_cork) + if (err && err != -EDATAINTEGRITY && txmsg_cork) err = 0; exit(err ? 1 : 0); } else if (rxpid == -1) { From 861cebee260a6e4efcb4ca9be14af350b9c37c81 Mon Sep 17 00:00:00 2001 From: Zijian Zhang Date: Sat, 12 Oct 2024 20:37:31 +0000 Subject: [PATCH 031/118] selftests/bpf: Fix txmsg_redir of test_txmsg_pull in test_sockmap [ Upstream commit b29e231d66303c12b7b8ac3ac2a057df06b161e8 ] txmsg_redir in "Test pull + redirect" case of test_txmsg_pull should be 1 instead of 0. Fixes: 328aa08a081b ("bpf: Selftests, break down test_sockmap into subtests") Acked-by: John Fastabend Signed-off-by: Zijian Zhang Link: https://lore.kernel.org/r/20241012203731.1248619-3-zijianzhang@bytedance.com Signed-off-by: Martin KaFai Lau Signed-off-by: Sasha Levin --- tools/testing/selftests/bpf/test_sockmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/test_sockmap.c b/tools/testing/selftests/bpf/test_sockmap.c index 72023e1b894d..1954c2aeb7a9 100644 --- a/tools/testing/selftests/bpf/test_sockmap.c +++ b/tools/testing/selftests/bpf/test_sockmap.c @@ -1609,7 +1609,7 @@ static void test_txmsg_pull(int cgrp, struct sockmap_options *opt) test_send_large(opt, cgrp); /* Test pull + redirect */ - txmsg_redir = 0; + txmsg_redir = 1; txmsg_start = 1; txmsg_end = 2; test_send(opt, cgrp); From b466746cfb6be43f9a1457bbee52ade397fb23ea Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Tue, 8 Oct 2024 01:20:54 +0300 Subject: [PATCH 032/118] wifi: mwifiex: Fix memcpy() field-spanning write warning in mwifiex_config_scan() [ Upstream commit d241a139c2e9f8a479f25c75ebd5391e6a448500 ] Replace one-element array with a flexible-array member in `struct mwifiex_ie_types_wildcard_ssid_params` to fix the following warning on a MT8173 Chromebook (mt8173-elm-hana): [ 356.775250] ------------[ cut here ]------------ [ 356.784543] memcpy: detected field-spanning write (size 6) of single field "wildcard_ssid_tlv->ssid" at drivers/net/wireless/marvell/mwifiex/scan.c:904 (size 1) [ 356.813403] WARNING: CPU: 3 PID: 742 at drivers/net/wireless/marvell/mwifiex/scan.c:904 mwifiex_scan_networks+0x4fc/0xf28 [mwifiex] The "(size 6)" above is exactly the length of the SSID of the network this device was connected to. The source of the warning looks like: ssid_len = user_scan_in->ssid_list[i].ssid_len; [...] memcpy(wildcard_ssid_tlv->ssid, user_scan_in->ssid_list[i].ssid, ssid_len); There is a #define WILDCARD_SSID_TLV_MAX_SIZE that uses sizeof() on this struct, but it already didn't account for the size of the one-element array, so it doesn't need to be changed. Fixes: 5e6e3a92b9a4 ("wireless: mwifiex: initial commit for Marvell mwifiex driver") Signed-off-by: Alper Nebi Yasak Acked-by: Brian Norris Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241007222301.24154-1-alpernebiyasak@gmail.com Signed-off-by: Sasha Levin --- drivers/net/wireless/marvell/mwifiex/fw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h index 26979013ca52..9c9fe5757b29 100644 --- a/drivers/net/wireless/marvell/mwifiex/fw.h +++ b/drivers/net/wireless/marvell/mwifiex/fw.h @@ -842,7 +842,7 @@ struct mwifiex_ietypes_chanstats { struct mwifiex_ie_types_wildcard_ssid_params { struct mwifiex_ie_types_header header; u8 max_ssid_length; - u8 ssid[1]; + u8 ssid[]; } __packed; #define TSF_DATA_SIZE 8 From 2bea5fa60162c9f63ad99820658f8fd10f7727aa Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Thu, 26 Sep 2024 07:55:51 +0200 Subject: [PATCH 033/118] drm: fsl-dcu: enable PIXCLK on LS1021A [ Upstream commit ffcde9e44d3e18fde3d18bfff8d9318935413bfd ] The PIXCLK needs to be enabled in SCFG before accessing certain DCU registers, or the access will hang. For simplicity, the PIXCLK is enabled unconditionally, resulting in increased power consumption. Signed-off-by: Matthias Schiffer Signed-off-by: Alexander Stein Fixes: 109eee2f2a18 ("drm/layerscape: Add Freescale DCU DRM driver") Acked-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20240926055552.1632448-2-alexander.stein@ew.tq-group.com Signed-off-by: Dmitry Baryshkov Signed-off-by: Sasha Levin --- drivers/gpu/drm/fsl-dcu/Kconfig | 1 + drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c | 15 +++++++++++++++ drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h | 3 +++ 3 files changed, 19 insertions(+) diff --git a/drivers/gpu/drm/fsl-dcu/Kconfig b/drivers/gpu/drm/fsl-dcu/Kconfig index 5ca71ef87325..c9ee98693b48 100644 --- a/drivers/gpu/drm/fsl-dcu/Kconfig +++ b/drivers/gpu/drm/fsl-dcu/Kconfig @@ -8,6 +8,7 @@ config DRM_FSL_DCU select DRM_PANEL select REGMAP_MMIO select VIDEOMODE_HELPERS + select MFD_SYSCON if SOC_LS1021A help Choose this option if you have an Freescale DCU chipset. If M is selected the module will be called fsl-dcu-drm. diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c index b4acc3422ba4..063a5e5bb737 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c @@ -100,6 +100,7 @@ static void fsl_dcu_irq_uninstall(struct drm_device *dev) static int fsl_dcu_load(struct drm_device *dev, unsigned long flags) { struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; + struct regmap *scfg; int ret; ret = fsl_dcu_drm_modeset_init(fsl_dev); @@ -108,6 +109,20 @@ static int fsl_dcu_load(struct drm_device *dev, unsigned long flags) return ret; } + scfg = syscon_regmap_lookup_by_compatible("fsl,ls1021a-scfg"); + if (PTR_ERR(scfg) != -ENODEV) { + /* + * For simplicity, enable the PIXCLK unconditionally, + * resulting in increased power consumption. Disabling + * the clock in PM or on unload could be implemented as + * a future improvement. + */ + ret = regmap_update_bits(scfg, SCFG_PIXCLKCR, SCFG_PIXCLKCR_PXCEN, + SCFG_PIXCLKCR_PXCEN); + if (ret < 0) + return dev_err_probe(dev->dev, ret, "failed to enable pixclk\n"); + } + ret = drm_vblank_init(dev, dev->mode_config.num_crtc); if (ret < 0) { dev_err(dev->dev, "failed to initialize vblank\n"); diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h index e2049a0e8a92..566396013c04 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h @@ -160,6 +160,9 @@ #define FSL_DCU_ARGB4444 12 #define FSL_DCU_YUV422 14 +#define SCFG_PIXCLKCR 0x28 +#define SCFG_PIXCLKCR_PXCEN BIT(31) + #define VF610_LAYER_REG_NUM 9 #define LS1021A_LAYER_REG_NUM 10 From 9265b6ee754226f61bd122ec57141a781d4e0dcb Mon Sep 17 00:00:00 2001 From: Dipendra Khadka Date: Thu, 17 Oct 2024 18:56:33 +0000 Subject: [PATCH 034/118] octeontx2-pf: handle otx2_mbox_get_rsp errors in otx2_common.c [ Upstream commit 0fbc7a5027c6f7f2c785adae3dcec22b2f2b69b3 ] Add error pointer check after calling otx2_mbox_get_rsp(). Fixes: ab58a416c93f ("octeontx2-pf: cn10k: Get max mtu supported from admin function") Signed-off-by: Dipendra Khadka Reviewed-by: Simon Horman Signed-off-by: Andrew Lunn Signed-off-by: Sasha Levin --- drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c index c00d6d67db51..d05f91f97a9a 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c @@ -1786,6 +1786,10 @@ u16 otx2_get_max_mtu(struct otx2_nic *pfvf) if (!rc) { rsp = (struct nix_hw_info *) otx2_mbox_get_rsp(&pfvf->mbox.mbox, 0, &req->hdr); + if (IS_ERR(rsp)) { + rc = PTR_ERR(rsp); + goto out; + } /* HW counts VLAN insertion bytes (8 for double tag) * irrespective of whether SQE is requesting to insert VLAN From 05a6ce174c0c724e5914e1e5efd826bab8f382b4 Mon Sep 17 00:00:00 2001 From: Dipendra Khadka Date: Thu, 17 Oct 2024 19:02:29 +0000 Subject: [PATCH 035/118] octeontx2-pf: handle otx2_mbox_get_rsp errors in otx2_ethtool.c [ Upstream commit e26f8eac6bb20b20fdb8f7dc695711ebce4c7c5c ] Add error pointer check after calling otx2_mbox_get_rsp(). Fixes: 75f36270990c ("octeontx2-pf: Support to enable/disable pause frames via ethtool") Fixes: d0cf9503e908 ("octeontx2-pf: ethtool fec mode support") Signed-off-by: Dipendra Khadka Reviewed-by: Simon Horman Signed-off-by: Andrew Lunn Signed-off-by: Sasha Levin --- .../net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c index af779ae40d3c..2d6f6edb1510 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c @@ -333,6 +333,11 @@ static void otx2_get_pauseparam(struct net_device *netdev, if (!otx2_sync_mbox_msg(&pfvf->mbox)) { rsp = (struct cgx_pause_frm_cfg *) otx2_mbox_get_rsp(&pfvf->mbox.mbox, 0, &req->hdr); + if (IS_ERR(rsp)) { + mutex_unlock(&pfvf->mbox.lock); + return; + } + pause->rx_pause = rsp->rx_pause; pause->tx_pause = rsp->tx_pause; } @@ -1072,6 +1077,11 @@ static int otx2_set_fecparam(struct net_device *netdev, rsp = (struct fec_mode *)otx2_mbox_get_rsp(&pfvf->mbox.mbox, 0, &req->hdr); + if (IS_ERR(rsp)) { + err = PTR_ERR(rsp); + goto end; + } + if (rsp->fec >= 0) pfvf->linfo.fec = rsp->fec; else From 8c9f8b35dc3d4ad8053a72bc0c5a7843591f6b75 Mon Sep 17 00:00:00 2001 From: Dipendra Khadka Date: Thu, 17 Oct 2024 19:08:44 +0000 Subject: [PATCH 036/118] octeontx2-pf: handle otx2_mbox_get_rsp errors in otx2_flows.c [ Upstream commit bd3110bc102ab6292656b8118be819faa0de8dd0 ] Adding error pointer check after calling otx2_mbox_get_rsp(). Fixes: 9917060fc30a ("octeontx2-pf: Cleanup flow rule management") Fixes: f0a1913f8a6f ("octeontx2-pf: Add support for ethtool ntuple filters") Fixes: 674b3e164238 ("octeontx2-pf: Add additional checks while configuring ucast/bcast/mcast rules") Signed-off-by: Dipendra Khadka Reviewed-by: Simon Horman Signed-off-by: Andrew Lunn Signed-off-by: Sasha Levin --- .../net/ethernet/marvell/octeontx2/nic/otx2_flows.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c index 5c757508322b..7c7f8814fb3f 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c @@ -121,6 +121,8 @@ int otx2_alloc_mcam_entries(struct otx2_nic *pfvf, u16 count) rsp = (struct npc_mcam_alloc_entry_rsp *)otx2_mbox_get_rsp (&pfvf->mbox.mbox, 0, &req->hdr); + if (IS_ERR(rsp)) + goto exit; for (ent = 0; ent < rsp->count; ent++) flow_cfg->flow_ent[ent + allocated] = rsp->entry_list[ent]; @@ -199,6 +201,10 @@ static int otx2_mcam_entry_init(struct otx2_nic *pfvf) rsp = (struct npc_mcam_alloc_entry_rsp *)otx2_mbox_get_rsp (&pfvf->mbox.mbox, 0, &req->hdr); + if (IS_ERR(rsp)) { + mutex_unlock(&pfvf->mbox.lock); + return PTR_ERR(rsp); + } if (rsp->count != req->count) { netdev_info(pfvf->netdev, @@ -234,6 +240,10 @@ static int otx2_mcam_entry_init(struct otx2_nic *pfvf) frsp = (struct npc_get_field_status_rsp *)otx2_mbox_get_rsp (&pfvf->mbox.mbox, 0, &freq->hdr); + if (IS_ERR(frsp)) { + mutex_unlock(&pfvf->mbox.lock); + return PTR_ERR(frsp); + } if (frsp->enable) { pfvf->flags |= OTX2_FLAG_RX_VLAN_SUPPORT; From 856ad633e11869729be698df2287ecfe6ec31f27 Mon Sep 17 00:00:00 2001 From: Dipendra Khadka Date: Thu, 17 Oct 2024 19:10:36 +0000 Subject: [PATCH 037/118] octeontx2-pf: handle otx2_mbox_get_rsp errors in cn10k.c [ Upstream commit ac9183023b6a9c09467516abd8aab04f9a2f9564 ] Add error pointer check after calling otx2_mbox_get_rsp(). Fixes: 2ca89a2c3752 ("octeontx2-pf: TC_MATCHALL ingress ratelimiting offload") Signed-off-by: Dipendra Khadka Reviewed-by: Simon Horman Signed-off-by: Andrew Lunn Signed-off-by: Sasha Levin --- drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c index 59d8d1ba15c2..8663bdf014d8 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c @@ -201,6 +201,11 @@ int cn10k_alloc_leaf_profile(struct otx2_nic *pfvf, u16 *leaf) rsp = (struct nix_bandprof_alloc_rsp *) otx2_mbox_get_rsp(&pfvf->mbox.mbox, 0, &req->hdr); + if (IS_ERR(rsp)) { + rc = PTR_ERR(rsp); + goto out; + } + if (!rsp->prof_count[BAND_PROF_LEAF_LAYER]) { rc = -EIO; goto out; From 1611b1ea7cf8d07dff091a45389b10401bb6d5b3 Mon Sep 17 00:00:00 2001 From: Dipendra Khadka Date: Thu, 17 Oct 2024 19:13:54 +0000 Subject: [PATCH 038/118] octeontx2-pf: handle otx2_mbox_get_rsp errors in otx2_dmac_flt.c [ Upstream commit f5b942e6c54b13246ee49d42dcfb71b7f29e3c64 ] Add error pointer checks after calling otx2_mbox_get_rsp(). Fixes: 79d2be385e9e ("octeontx2-pf: offload DMAC filters to CGX/RPM block") Fixes: fa5e0ccb8f3a ("octeontx2-pf: Add support for exact match table.") Signed-off-by: Dipendra Khadka Reviewed-by: Simon Horman Signed-off-by: Andrew Lunn Signed-off-by: Sasha Levin --- .../net/ethernet/marvell/octeontx2/nic/otx2_dmac_flt.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dmac_flt.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dmac_flt.c index 80d853b343f9..2046dd0da00d 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dmac_flt.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dmac_flt.c @@ -28,6 +28,11 @@ static int otx2_dmacflt_do_add(struct otx2_nic *pf, const u8 *mac, if (!err) { rsp = (struct cgx_mac_addr_add_rsp *) otx2_mbox_get_rsp(&pf->mbox.mbox, 0, &req->hdr); + if (IS_ERR(rsp)) { + mutex_unlock(&pf->mbox.lock); + return PTR_ERR(rsp); + } + *dmac_index = rsp->index; } @@ -200,6 +205,10 @@ int otx2_dmacflt_update(struct otx2_nic *pf, u8 *mac, u32 bit_pos) rsp = (struct cgx_mac_addr_update_rsp *) otx2_mbox_get_rsp(&pf->mbox.mbox, 0, &req->hdr); + if (IS_ERR(rsp)) { + rc = PTR_ERR(rsp); + goto out; + } pf->flow_cfg->bmap_to_dmacindex[bit_pos] = rsp->index; From b94052830e3cd3be7141789a5ce6e62cf9f620a4 Mon Sep 17 00:00:00 2001 From: Dipendra Khadka Date: Thu, 17 Oct 2024 19:16:16 +0000 Subject: [PATCH 039/118] octeontx2-pf: handle otx2_mbox_get_rsp errors in otx2_dcbnl.c [ Upstream commit 69297b0d3369488af259e3a7cf53d69157938ea1 ] Add error pointer check after calling otx2_mbox_get_rsp(). Fixes: 8e67558177f8 ("octeontx2-pf: PFC config support with DCBx") Signed-off-by: Dipendra Khadka Reviewed-by: Simon Horman Signed-off-by: Andrew Lunn Signed-off-by: Sasha Levin --- drivers/net/ethernet/marvell/octeontx2/nic/otx2_dcbnl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dcbnl.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dcbnl.c index 28fb643d2917..1a13f003f3db 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dcbnl.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dcbnl.c @@ -311,6 +311,11 @@ int otx2_config_priority_flow_ctrl(struct otx2_nic *pfvf) if (!otx2_sync_mbox_msg(&pfvf->mbox)) { rsp = (struct cgx_pfc_rsp *) otx2_mbox_get_rsp(&pfvf->mbox.mbox, 0, &req->hdr); + if (IS_ERR(rsp)) { + err = PTR_ERR(rsp); + goto unlock; + } + if (req->rx_pause != rsp->rx_pause || req->tx_pause != rsp->tx_pause) { dev_warn(pfvf->dev, "Failed to config PFC\n"); From 8f544cfc96c76893e95ec81992566a9bc514c400 Mon Sep 17 00:00:00 2001 From: Steven Price Date: Fri, 25 Oct 2024 15:00:07 +0100 Subject: [PATCH 040/118] drm/panfrost: Remove unused id_mask from struct panfrost_model [ Upstream commit 581d1f8248550f2b67847e6d84f29fbe3751ea0a ] The id_mask field of struct panfrost_model has never been used. Fixes: f3ba91228e8e ("drm/panfrost: Add initial panfrost driver") Signed-off-by: Steven Price Reviewed-by: Boris Brezillon Link: https://patchwork.freedesktop.org/patch/msgid/20241025140008.385081-1-steven.price@arm.com Signed-off-by: Sasha Levin --- drivers/gpu/drm/panfrost/panfrost_gpu.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c index 40b631445992..62722d9ff8eb 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gpu.c +++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c @@ -157,7 +157,6 @@ static void panfrost_gpu_init_quirks(struct panfrost_device *pfdev) struct panfrost_model { const char *name; u32 id; - u32 id_mask; u64 features; u64 issues; struct { From 9e63fd47e6279df9b91048acafdee21126d8c6fc Mon Sep 17 00:00:00 2001 From: Xu Kuohai Date: Fri, 25 Oct 2024 16:52:20 +0800 Subject: [PATCH 041/118] bpf, arm64: Remove garbage frame for struct_ops trampoline [ Upstream commit 87cb58aebdf7005661a07e9fd5a900f924d48c75 ] The callsite layout for arm64 fentry is: mov x9, lr nop When a bpf prog is attached, the nop instruction is patched to a call to bpf trampoline: mov x9, lr bl So two return addresses are passed to bpf trampoline: the return address for the traced function/prog, stored in x9, and the return address for the bpf trampoline itself, stored in lr. To obtain a full and accurate call stack, the bpf trampoline constructs two fake function frames using x9 and lr. However, struct_ops progs are invoked directly as function callbacks, meaning that x9 is not set as it is in the fentry callsite. In this case, the frame constructed using x9 is garbage. The following stack trace for struct_ops, captured by perf sampling, illustrates this issue, where tcp_ack+0x404 is a garbage frame: ffffffc0801a04b4 bpf_prog_50992e55a0f655a9_bpf_cubic_cong_avoid+0x98 (bpf_prog_50992e55a0f655a9_bpf_cubic_cong_avoid) ffffffc0801a228c [unknown] ([kernel.kallsyms]) // bpf trampoline ffffffd08d362590 tcp_ack+0x798 ([kernel.kallsyms]) // caller for bpf trampoline ffffffd08d3621fc tcp_ack+0x404 ([kernel.kallsyms]) // garbage frame ffffffd08d36452c tcp_rcv_established+0x4ac ([kernel.kallsyms]) ffffffd08d375c58 tcp_v4_do_rcv+0x1f0 ([kernel.kallsyms]) ffffffd08d378630 tcp_v4_rcv+0xeb8 ([kernel.kallsyms]) To fix it, construct only one frame using lr for struct_ops. The above stack trace also indicates that there is no kernel symbol for struct_ops bpf trampoline. This will be addressed in a follow-up patch. Fixes: efc9909fdce0 ("bpf, arm64: Add bpf trampoline for arm64") Signed-off-by: Xu Kuohai Acked-by: Puranjay Mohan Tested-by: Puranjay Mohan Link: https://lore.kernel.org/r/20241025085220.533949-1-xukuohai@huaweicloud.com Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- arch/arm64/net/bpf_jit_comp.c | 47 +++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index afb79209d413..c04ace8f4843 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -1757,6 +1757,12 @@ static void restore_args(struct jit_ctx *ctx, int args_off, int nargs) } } +static bool is_struct_ops_tramp(const struct bpf_tramp_links *fentry_links) +{ + return fentry_links->nr_links == 1 && + fentry_links->links[0]->link.type == BPF_LINK_TYPE_STRUCT_OPS; +} + /* Based on the x86's implementation of arch_prepare_bpf_trampoline(). * * bpf prog and function entry before bpf trampoline hooked: @@ -1786,6 +1792,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, struct bpf_tramp_links *fmod_ret = &tlinks[BPF_TRAMP_MODIFY_RETURN]; bool save_ret; __le32 **branches = NULL; + bool is_struct_ops = is_struct_ops_tramp(fentry); /* trampoline stack layout: * [ parent ip ] @@ -1854,11 +1861,14 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, */ emit_bti(A64_BTI_JC, ctx); - /* frame for parent function */ - emit(A64_PUSH(A64_FP, A64_R(9), A64_SP), ctx); - emit(A64_MOV(1, A64_FP, A64_SP), ctx); + /* x9 is not set for struct_ops */ + if (!is_struct_ops) { + /* frame for parent function */ + emit(A64_PUSH(A64_FP, A64_R(9), A64_SP), ctx); + emit(A64_MOV(1, A64_FP, A64_SP), ctx); + } - /* frame for patched function */ + /* frame for patched function for tracing, or caller for struct_ops */ emit(A64_PUSH(A64_FP, A64_LR, A64_SP), ctx); emit(A64_MOV(1, A64_FP, A64_SP), ctx); @@ -1944,19 +1954,24 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, /* reset SP */ emit(A64_MOV(1, A64_SP, A64_FP), ctx); - /* pop frames */ - emit(A64_POP(A64_FP, A64_LR, A64_SP), ctx); - emit(A64_POP(A64_FP, A64_R(9), A64_SP), ctx); - - if (flags & BPF_TRAMP_F_SKIP_FRAME) { - /* skip patched function, return to parent */ - emit(A64_MOV(1, A64_LR, A64_R(9)), ctx); - emit(A64_RET(A64_R(9)), ctx); + if (is_struct_ops) { + emit(A64_POP(A64_FP, A64_LR, A64_SP), ctx); + emit(A64_RET(A64_LR), ctx); } else { - /* return to patched function */ - emit(A64_MOV(1, A64_R(10), A64_LR), ctx); - emit(A64_MOV(1, A64_LR, A64_R(9)), ctx); - emit(A64_RET(A64_R(10)), ctx); + /* pop frames */ + emit(A64_POP(A64_FP, A64_LR, A64_SP), ctx); + emit(A64_POP(A64_FP, A64_R(9), A64_SP), ctx); + + if (flags & BPF_TRAMP_F_SKIP_FRAME) { + /* skip patched function, return to parent */ + emit(A64_MOV(1, A64_LR, A64_R(9)), ctx); + emit(A64_RET(A64_R(9)), ctx); + } else { + /* return to patched function */ + emit(A64_MOV(1, A64_R(10), A64_LR), ctx); + emit(A64_MOV(1, A64_LR, A64_R(9)), ctx); + emit(A64_RET(A64_R(10)), ctx); + } } if (ctx->image) From 8e57e58ecf48cc2a0c431cde434716c12ad550a2 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Thu, 12 Sep 2024 16:30:20 +0800 Subject: [PATCH 042/118] drm/msm/adreno: Use IRQF_NO_AUTOEN flag in request_irq() [ Upstream commit 394679f322649d06fea3c646ba65f5a0887f52c3 ] disable_irq() after request_irq() still has a time gap in which interrupts can come. request_irq() with IRQF_NO_AUTOEN flag will disable IRQ auto-enable when request IRQ. Fixes: 4b565ca5a2cb ("drm/msm: Add A6XX device support") Reviewed-by: Dmitry Baryshkov Signed-off-by: Jinjie Ruan Patchwork: https://patchwork.freedesktop.org/patch/614075/ Signed-off-by: Rob Clark Signed-off-by: Sasha Levin --- drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index 870252bef23f..ee9b32fbe916 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -1462,15 +1462,13 @@ static int a6xx_gmu_get_irq(struct a6xx_gmu *gmu, struct platform_device *pdev, irq = platform_get_irq_byname(pdev, name); - ret = request_irq(irq, handler, IRQF_TRIGGER_HIGH, name, gmu); + ret = request_irq(irq, handler, IRQF_TRIGGER_HIGH | IRQF_NO_AUTOEN, name, gmu); if (ret) { DRM_DEV_ERROR(&pdev->dev, "Unable to get interrupt %s %d\n", name, ret); return ret; } - disable_irq(irq); - return irq; } From 5d187dcbaa037bd61f3accc5e3a1a315ac937744 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 10 Jan 2023 15:14:42 -0800 Subject: [PATCH 043/118] drm/msm/gpu: Add devfreq tuning debugfs [ Upstream commit 6563f60f14cbb3dcbdc4e1d8469fc0fbaaa80544 ] Make the handful of tuning knobs available visible via debugfs. v2: select DEVFREQ_GOV_SIMPLE_ONDEMAND because for some reason struct devfreq_simple_ondemand_data depends on this Signed-off-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/517784/ Link: https://lore.kernel.org/r/20230110231447.1939101-2-robdclark@gmail.com Reviewed-by: Chia-I Wu Stable-dep-of: 8f32ddd87e49 ("drm/msm/gpu: Check the status of registration to PM QoS") Signed-off-by: Sasha Levin --- drivers/gpu/drm/msm/Kconfig | 1 + drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 2 +- drivers/gpu/drm/msm/msm_debugfs.c | 12 ++++++++++++ drivers/gpu/drm/msm/msm_drv.h | 9 +++++++++ drivers/gpu/drm/msm/msm_gpu.h | 3 --- drivers/gpu/drm/msm/msm_gpu_devfreq.c | 6 ++++-- 6 files changed, 27 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 3c9dfdb0b328..f7abacb4b221 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -23,6 +23,7 @@ config DRM_MSM select SHMEM select TMPFS select QCOM_SCM + select DEVFREQ_GOV_SIMPLE_ONDEMAND select WANT_DEV_COREDUMP select SND_SOC_HDMI_CODEC if SND_SOC select SYNC_FILE diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index d6a810b7cfa2..cdb4665b953c 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -2056,7 +2056,7 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev) * to cause power supply issues: */ if (adreno_is_a618(adreno_gpu) || adreno_is_7c3(adreno_gpu)) - gpu->clamp_to_idle = true; + priv->gpu_clamp_to_idle = true; /* Check if there is a GMU phandle and set it up */ node = of_parse_phandle(pdev->dev.of_node, "qcom,gmu", 0); diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c index 95f4374ae21c..d6ecff0ab618 100644 --- a/drivers/gpu/drm/msm/msm_debugfs.c +++ b/drivers/gpu/drm/msm/msm_debugfs.c @@ -305,6 +305,7 @@ void msm_debugfs_init(struct drm_minor *minor) { struct drm_device *dev = minor->dev; struct msm_drm_private *priv = dev->dev_private; + struct dentry *gpu_devfreq; drm_debugfs_create_files(msm_debugfs_list, ARRAY_SIZE(msm_debugfs_list), @@ -325,6 +326,17 @@ void msm_debugfs_init(struct drm_minor *minor) debugfs_create_file("shrink", S_IRWXU, minor->debugfs_root, dev, &shrink_fops); + gpu_devfreq = debugfs_create_dir("devfreq", minor->debugfs_root); + + debugfs_create_bool("idle_clamp",0600, gpu_devfreq, + &priv->gpu_clamp_to_idle); + + debugfs_create_u32("upthreshold",0600, gpu_devfreq, + &priv->gpu_devfreq_config.upthreshold); + + debugfs_create_u32("downdifferential",0600, gpu_devfreq, + &priv->gpu_devfreq_config.downdifferential); + if (priv->kms && priv->kms->funcs->debugfs_init) priv->kms->funcs->debugfs_init(priv->kms, minor); diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index d4e0ef608950..81deb112ea44 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -233,6 +234,14 @@ struct msm_drm_private { */ unsigned int hangcheck_period; + /** gpu_devfreq_config: Devfreq tuning config for the GPU. */ + struct devfreq_simple_ondemand_data gpu_devfreq_config; + + /** + * gpu_clamp_to_idle: Enable clamping to idle freq when inactive + */ + bool gpu_clamp_to_idle; + /** * disable_err_irq: * diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index b39cd332751d..a326b6d1adbe 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -275,9 +275,6 @@ struct msm_gpu { struct msm_gpu_state *crashstate; - /* Enable clamping to idle freq when inactive: */ - bool clamp_to_idle; - /* True if the hardware supports expanded apriv (a650 and newer) */ bool hw_apriv; diff --git a/drivers/gpu/drm/msm/msm_gpu_devfreq.c b/drivers/gpu/drm/msm/msm_gpu_devfreq.c index 85c443a37e4e..1f4e2dd8e76d 100644 --- a/drivers/gpu/drm/msm/msm_gpu_devfreq.c +++ b/drivers/gpu/drm/msm/msm_gpu_devfreq.c @@ -183,6 +183,7 @@ static bool has_devfreq(struct msm_gpu *gpu) void msm_devfreq_init(struct msm_gpu *gpu) { struct msm_gpu_devfreq *df = &gpu->devfreq; + struct msm_drm_private *priv = gpu->dev->dev_private; /* We need target support to do devfreq */ if (!gpu->funcs->gpu_busy) @@ -209,7 +210,7 @@ void msm_devfreq_init(struct msm_gpu *gpu) df->devfreq = devm_devfreq_add_device(&gpu->pdev->dev, &msm_devfreq_profile, DEVFREQ_GOV_SIMPLE_ONDEMAND, - NULL); + &priv->gpu_devfreq_config); if (IS_ERR(df->devfreq)) { DRM_DEV_ERROR(&gpu->pdev->dev, "Couldn't initialize GPU devfreq\n"); @@ -358,10 +359,11 @@ static void msm_devfreq_idle_work(struct kthread_work *work) struct msm_gpu_devfreq *df = container_of(work, struct msm_gpu_devfreq, idle_work.work); struct msm_gpu *gpu = container_of(df, struct msm_gpu, devfreq); + struct msm_drm_private *priv = gpu->dev->dev_private; df->idle_time = ktime_get(); - if (gpu->clamp_to_idle) + if (priv->gpu_clamp_to_idle) dev_pm_qos_update_request(&df->idle_freq, 0); } From 372f00e22e06e3bf91b25a69cb4bdd312c46add1 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 10 Jan 2023 15:14:43 -0800 Subject: [PATCH 044/118] drm/msm/gpu: Bypass PM QoS constraint for idle clamp [ Upstream commit fadcc3ab1302d4e5baa32c272b658221f0066696 ] Change idle freq clamping back to the direct method, bypassing PM QoS requests. The problem with using PM QoS requests is they call (indirectly) the governors ->get_target_freq() which goes thru a get_dev_status() cycle. The problem comes when the GPU becomes active again and we remove the idle-clamp request, we go through another get_dev_status() cycle for the period that the GPU has been idle, which triggers the governor to lower the target freq excessively. This partially reverts commit 7c0ffcd40b16 ("drm/msm/gpu: Respect PM QoS constraints"), but preserves the use of boost QoS request, so that it will continue to play nicely with other QoS requests such as a cooling device. This also mostly undoes commit 78f815c1cf8f ("drm/msm: return the average load over the polling period") Signed-off-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/517785/ Link: https://lore.kernel.org/r/20230110231447.1939101-3-robdclark@gmail.com Reviewed-by: Chia-I Wu Stable-dep-of: 8f32ddd87e49 ("drm/msm/gpu: Check the status of registration to PM QoS") Signed-off-by: Sasha Levin --- drivers/gpu/drm/msm/msm_gpu.h | 12 ++- drivers/gpu/drm/msm/msm_gpu_devfreq.c | 135 +++++++++++--------------- 2 files changed, 65 insertions(+), 82 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index a326b6d1adbe..5929ecaa1fcd 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -109,11 +109,15 @@ struct msm_gpu_devfreq { struct mutex lock; /** - * idle_constraint: + * idle_freq: * - * A PM QoS constraint to limit max freq while the GPU is idle. + * Shadow frequency used while the GPU is idle. From the PoV of + * the devfreq governor, we are continuing to sample busyness and + * adjust frequency while the GPU is idle, but we use this shadow + * value as the GPU is actually clamped to minimum frequency while + * it is inactive. */ - struct dev_pm_qos_request idle_freq; + unsigned long idle_freq; /** * boost_constraint: @@ -135,8 +139,6 @@ struct msm_gpu_devfreq { /** idle_time: Time of last transition to idle: */ ktime_t idle_time; - struct devfreq_dev_status average_status; - /** * idle_work: * diff --git a/drivers/gpu/drm/msm/msm_gpu_devfreq.c b/drivers/gpu/drm/msm/msm_gpu_devfreq.c index 1f4e2dd8e76d..ae5380e2abf7 100644 --- a/drivers/gpu/drm/msm/msm_gpu_devfreq.c +++ b/drivers/gpu/drm/msm/msm_gpu_devfreq.c @@ -33,6 +33,16 @@ static int msm_devfreq_target(struct device *dev, unsigned long *freq, trace_msm_gpu_freq_change(dev_pm_opp_get_freq(opp)); + /* + * If the GPU is idle, devfreq is not aware, so just stash + * the new target freq (to use when we return to active) + */ + if (df->idle_freq) { + df->idle_freq = *freq; + dev_pm_opp_put(opp); + return 0; + } + if (gpu->funcs->gpu_set_freq) { mutex_lock(&df->lock); gpu->funcs->gpu_set_freq(gpu, opp, df->suspended); @@ -48,15 +58,26 @@ static int msm_devfreq_target(struct device *dev, unsigned long *freq, static unsigned long get_freq(struct msm_gpu *gpu) { + struct msm_gpu_devfreq *df = &gpu->devfreq; + + /* + * If the GPU is idle, use the shadow/saved freq to avoid + * confusing devfreq (which is unaware that we are switching + * to lowest freq until the device is active again) + */ + if (df->idle_freq) + return df->idle_freq; + if (gpu->funcs->gpu_get_freq) return gpu->funcs->gpu_get_freq(gpu); return clk_get_rate(gpu->core_clk); } -static void get_raw_dev_status(struct msm_gpu *gpu, +static int msm_devfreq_get_dev_status(struct device *dev, struct devfreq_dev_status *status) { + struct msm_gpu *gpu = dev_to_gpu(dev); struct msm_gpu_devfreq *df = &gpu->devfreq; u64 busy_cycles, busy_time; unsigned long sample_rate; @@ -72,7 +93,7 @@ static void get_raw_dev_status(struct msm_gpu *gpu, if (df->suspended) { mutex_unlock(&df->lock); status->busy_time = 0; - return; + return 0; } busy_cycles = gpu->funcs->gpu_busy(gpu, &sample_rate); @@ -87,71 +108,6 @@ static void get_raw_dev_status(struct msm_gpu *gpu, busy_time = ~0LU; status->busy_time = busy_time; -} - -static void update_average_dev_status(struct msm_gpu *gpu, - const struct devfreq_dev_status *raw) -{ - struct msm_gpu_devfreq *df = &gpu->devfreq; - const u32 polling_ms = df->devfreq->profile->polling_ms; - const u32 max_history_ms = polling_ms * 11 / 10; - struct devfreq_dev_status *avg = &df->average_status; - u64 avg_freq; - - /* simple_ondemand governor interacts poorly with gpu->clamp_to_idle. - * When we enforce the constraint on idle, it calls get_dev_status - * which would normally reset the stats. When we remove the - * constraint on active, it calls get_dev_status again where busy_time - * would be 0. - * - * To remedy this, we always return the average load over the past - * polling_ms. - */ - - /* raw is longer than polling_ms or avg has no history */ - if (div_u64(raw->total_time, USEC_PER_MSEC) >= polling_ms || - !avg->total_time) { - *avg = *raw; - return; - } - - /* Truncate the oldest history first. - * - * Because we keep the history with a single devfreq_dev_status, - * rather than a list of devfreq_dev_status, we have to assume freq - * and load are the same over avg->total_time. We can scale down - * avg->busy_time and avg->total_time by the same factor to drop - * history. - */ - if (div_u64(avg->total_time + raw->total_time, USEC_PER_MSEC) >= - max_history_ms) { - const u32 new_total_time = polling_ms * USEC_PER_MSEC - - raw->total_time; - avg->busy_time = div_u64( - mul_u32_u32(avg->busy_time, new_total_time), - avg->total_time); - avg->total_time = new_total_time; - } - - /* compute the average freq over avg->total_time + raw->total_time */ - avg_freq = mul_u32_u32(avg->current_frequency, avg->total_time); - avg_freq += mul_u32_u32(raw->current_frequency, raw->total_time); - do_div(avg_freq, avg->total_time + raw->total_time); - - avg->current_frequency = avg_freq; - avg->busy_time += raw->busy_time; - avg->total_time += raw->total_time; -} - -static int msm_devfreq_get_dev_status(struct device *dev, - struct devfreq_dev_status *status) -{ - struct msm_gpu *gpu = dev_to_gpu(dev); - struct devfreq_dev_status raw; - - get_raw_dev_status(gpu, &raw); - update_average_dev_status(gpu, &raw); - *status = gpu->devfreq.average_status; return 0; } @@ -191,9 +147,6 @@ void msm_devfreq_init(struct msm_gpu *gpu) mutex_init(&df->lock); - dev_pm_qos_add_request(&gpu->pdev->dev, &df->idle_freq, - DEV_PM_QOS_MAX_FREQUENCY, - PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE); dev_pm_qos_add_request(&gpu->pdev->dev, &df->boost_freq, DEV_PM_QOS_MIN_FREQUENCY, 0); @@ -214,7 +167,6 @@ void msm_devfreq_init(struct msm_gpu *gpu) if (IS_ERR(df->devfreq)) { DRM_DEV_ERROR(&gpu->pdev->dev, "Couldn't initialize GPU devfreq\n"); - dev_pm_qos_remove_request(&df->idle_freq); dev_pm_qos_remove_request(&df->boost_freq); df->devfreq = NULL; return; @@ -256,7 +208,6 @@ void msm_devfreq_cleanup(struct msm_gpu *gpu) devfreq_cooling_unregister(gpu->cooling); dev_pm_qos_remove_request(&df->boost_freq); - dev_pm_qos_remove_request(&df->idle_freq); } void msm_devfreq_resume(struct msm_gpu *gpu) @@ -329,6 +280,7 @@ void msm_devfreq_active(struct msm_gpu *gpu) { struct msm_gpu_devfreq *df = &gpu->devfreq; unsigned int idle_time; + unsigned long target_freq; if (!has_devfreq(gpu)) return; @@ -338,8 +290,28 @@ void msm_devfreq_active(struct msm_gpu *gpu) */ cancel_idle_work(df); + /* + * Hold devfreq lock to synchronize with get_dev_status()/ + * target() callbacks + */ + mutex_lock(&df->devfreq->lock); + + target_freq = df->idle_freq; + idle_time = ktime_to_ms(ktime_sub(ktime_get(), df->idle_time)); + df->idle_freq = 0; + + /* + * We could have become active again before the idle work had a + * chance to run, in which case the df->idle_freq would have + * still been zero. In this case, no need to change freq. + */ + if (target_freq) + msm_devfreq_target(&gpu->pdev->dev, &target_freq, 0); + + mutex_unlock(&df->devfreq->lock); + /* * If we've been idle for a significant fraction of a polling * interval, then we won't meet the threshold of busyness for @@ -348,9 +320,6 @@ void msm_devfreq_active(struct msm_gpu *gpu) if (idle_time > msm_devfreq_profile.polling_ms) { msm_devfreq_boost(gpu, 2); } - - dev_pm_qos_update_request(&df->idle_freq, - PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE); } @@ -360,11 +329,23 @@ static void msm_devfreq_idle_work(struct kthread_work *work) struct msm_gpu_devfreq, idle_work.work); struct msm_gpu *gpu = container_of(df, struct msm_gpu, devfreq); struct msm_drm_private *priv = gpu->dev->dev_private; + unsigned long idle_freq, target_freq = 0; - df->idle_time = ktime_get(); + /* + * Hold devfreq lock to synchronize with get_dev_status()/ + * target() callbacks + */ + mutex_lock(&df->devfreq->lock); + + idle_freq = get_freq(gpu); if (priv->gpu_clamp_to_idle) - dev_pm_qos_update_request(&df->idle_freq, 0); + msm_devfreq_target(&gpu->pdev->dev, &target_freq, 0); + + df->idle_time = ktime_get(); + df->idle_freq = idle_freq; + + mutex_unlock(&df->devfreq->lock); } void msm_devfreq_idle(struct msm_gpu *gpu) From 1867879b7a47bddaac5db3a140aeb1e338adeb1e Mon Sep 17 00:00:00 2001 From: Lukasz Luba Date: Fri, 18 Oct 2024 12:18:11 +0100 Subject: [PATCH 045/118] drm/msm/gpu: Check the status of registration to PM QoS [ Upstream commit 8f32ddd87e499ba6d2dc74ce30b6932baf1e1fc3 ] There is a need to check the returned value of the registration function. In case of returned error, print that and stop the init process. Fixes: 7c0ffcd40b16 ("drm/msm/gpu: Respect PM QoS constraints") Signed-off-by: Lukasz Luba Patchwork: https://patchwork.freedesktop.org/patch/620336/ Signed-off-by: Rob Clark Signed-off-by: Sasha Levin --- drivers/gpu/drm/msm/msm_gpu_devfreq.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gpu_devfreq.c b/drivers/gpu/drm/msm/msm_gpu_devfreq.c index ae5380e2abf7..4e73b915fe1a 100644 --- a/drivers/gpu/drm/msm/msm_gpu_devfreq.c +++ b/drivers/gpu/drm/msm/msm_gpu_devfreq.c @@ -140,6 +140,7 @@ void msm_devfreq_init(struct msm_gpu *gpu) { struct msm_gpu_devfreq *df = &gpu->devfreq; struct msm_drm_private *priv = gpu->dev->dev_private; + int ret; /* We need target support to do devfreq */ if (!gpu->funcs->gpu_busy) @@ -147,8 +148,12 @@ void msm_devfreq_init(struct msm_gpu *gpu) mutex_init(&df->lock); - dev_pm_qos_add_request(&gpu->pdev->dev, &df->boost_freq, - DEV_PM_QOS_MIN_FREQUENCY, 0); + ret = dev_pm_qos_add_request(&gpu->pdev->dev, &df->boost_freq, + DEV_PM_QOS_MIN_FREQUENCY, 0); + if (ret < 0) { + DRM_DEV_ERROR(&gpu->pdev->dev, "Couldn't initialize QoS\n"); + return; + } msm_devfreq_profile.initial_freq = gpu->fast_rate; From ab96894ade42b2e128f2a20cbffef5f1537f4526 Mon Sep 17 00:00:00 2001 From: Xiaolei Wang Date: Wed, 2 Oct 2024 07:34:30 +0800 Subject: [PATCH 046/118] drm/etnaviv: Request pages from DMA32 zone on addressing_limited [ Upstream commit 13c96ac9a3f0f1c7ba1ff0656ea508e7fa065e7e ] Remove __GFP_HIGHMEM when requesting a page from DMA32 zone, and since all vivante GPUs in the system will share the same DMA constraints, move the check of whether to get a page from DMA32 to etnaviv_bind(). Fixes: b72af445cd38 ("drm/etnaviv: request pages from DMA32 zone when needed") Suggested-by: Sui Jingfeng Signed-off-by: Xiaolei Wang Reviewed-by: Christian Gmeiner Signed-off-by: Lucas Stach Signed-off-by: Sasha Levin --- drivers/gpu/drm/etnaviv/etnaviv_drv.c | 10 ++++++++++ drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 8 -------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c index f29952a55c05..b932a02efccd 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c @@ -519,6 +519,16 @@ static int etnaviv_bind(struct device *dev) priv->num_gpus = 0; priv->shm_gfp_mask = GFP_HIGHUSER | __GFP_RETRY_MAYFAIL | __GFP_NOWARN; + /* + * If the GPU is part of a system with DMA addressing limitations, + * request pages for our SHM backend buffers from the DMA32 zone to + * hopefully avoid performance killing SWIOTLB bounce buffering. + */ + if (dma_addressing_limited(dev)) { + priv->shm_gfp_mask |= GFP_DMA32; + priv->shm_gfp_mask &= ~__GFP_HIGHMEM; + } + priv->cmdbuf_suballoc = etnaviv_cmdbuf_suballoc_new(drm->dev); if (IS_ERR(priv->cmdbuf_suballoc)) { dev_err(drm->dev, "Failed to create cmdbuf suballocator\n"); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index f667e7906d1f..ffac685c2291 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -798,14 +798,6 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu) if (ret) goto fail; - /* - * If the GPU is part of a system with DMA addressing limitations, - * request pages for our SHM backend buffers from the DMA32 zone to - * hopefully avoid performance killing SWIOTLB bounce buffering. - */ - if (dma_addressing_limited(gpu->dev)) - priv->shm_gfp_mask |= GFP_DMA32; - /* Create buffer: */ ret = etnaviv_cmdbuf_init(priv->cmdbuf_suballoc, &gpu->buffer, PAGE_SIZE); From f8cae8a21b2893370127516800f6f1c5f0e8db38 Mon Sep 17 00:00:00 2001 From: Doug Brown Date: Sat, 10 Sep 2022 13:29:39 -0700 Subject: [PATCH 047/118] drm/etnaviv: fix power register offset on GC300 [ Upstream commit 61a6920bb604df3a0e389a2a9479e1e233e4461d ] Older GC300 revisions have their power registers at an offset of 0x200 rather than 0x100. Add new gpu_read_power and gpu_write_power functions to encapsulate accesses to the power addresses and fix the addresses. Signed-off-by: Doug Brown Signed-off-by: Lucas Stach Stable-dep-of: 37dc4737447a ("drm/etnaviv: hold GPU lock across perfmon sampling") Signed-off-by: Sasha Levin --- drivers/gpu/drm/etnaviv/etnaviv_dump.c | 7 ++++++- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 20 ++++++++++---------- drivers/gpu/drm/etnaviv/etnaviv_gpu.h | 21 +++++++++++++++++++++ 3 files changed, 37 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_dump.c b/drivers/gpu/drm/etnaviv/etnaviv_dump.c index 0edcf8ceb4a7..898f84a0fc30 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_dump.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_dump.c @@ -83,10 +83,15 @@ static void etnaviv_core_dump_registers(struct core_dump_iterator *iter, { struct etnaviv_dump_registers *reg = iter->data; unsigned int i; + u32 read_addr; for (i = 0; i < ARRAY_SIZE(etnaviv_dump_registers); i++, reg++) { + read_addr = etnaviv_dump_registers[i]; + if (read_addr >= VIVS_PM_POWER_CONTROLS && + read_addr <= VIVS_PM_PULSE_EATER) + read_addr = gpu_fix_power_address(gpu, read_addr); reg->reg = cpu_to_le32(etnaviv_dump_registers[i]); - reg->value = cpu_to_le32(gpu_read(gpu, etnaviv_dump_registers[i])); + reg->value = cpu_to_le32(gpu_read(gpu, read_addr)); } etnaviv_core_dump_header(iter, ETDUMP_BUF_REG, reg); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index ffac685c2291..6c070411d95f 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -590,7 +590,7 @@ static void etnaviv_gpu_enable_mlcg(struct etnaviv_gpu *gpu) u32 pmc, ppc; /* enable clock gating */ - ppc = gpu_read(gpu, VIVS_PM_POWER_CONTROLS); + ppc = gpu_read_power(gpu, VIVS_PM_POWER_CONTROLS); ppc |= VIVS_PM_POWER_CONTROLS_ENABLE_MODULE_CLOCK_GATING; /* Disable stall module clock gating for 4.3.0.1 and 4.3.0.2 revs */ @@ -598,9 +598,9 @@ static void etnaviv_gpu_enable_mlcg(struct etnaviv_gpu *gpu) gpu->identity.revision == 0x4302) ppc |= VIVS_PM_POWER_CONTROLS_DISABLE_STALL_MODULE_CLOCK_GATING; - gpu_write(gpu, VIVS_PM_POWER_CONTROLS, ppc); + gpu_write_power(gpu, VIVS_PM_POWER_CONTROLS, ppc); - pmc = gpu_read(gpu, VIVS_PM_MODULE_CONTROLS); + pmc = gpu_read_power(gpu, VIVS_PM_MODULE_CONTROLS); /* Disable PA clock gating for GC400+ without bugfix except for GC420 */ if (gpu->identity.model >= chipModel_GC400 && @@ -635,7 +635,7 @@ static void etnaviv_gpu_enable_mlcg(struct etnaviv_gpu *gpu) pmc |= VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_RA_HZ; pmc |= VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_RA_EZ; - gpu_write(gpu, VIVS_PM_MODULE_CONTROLS, pmc); + gpu_write_power(gpu, VIVS_PM_MODULE_CONTROLS, pmc); } void etnaviv_gpu_start_fe(struct etnaviv_gpu *gpu, u32 address, u16 prefetch) @@ -695,11 +695,11 @@ static void etnaviv_gpu_setup_pulse_eater(struct etnaviv_gpu *gpu) (gpu->identity.features & chipFeatures_PIPE_3D)) { /* Performance fix: disable internal DFS */ - pulse_eater = gpu_read(gpu, VIVS_PM_PULSE_EATER); + pulse_eater = gpu_read_power(gpu, VIVS_PM_PULSE_EATER); pulse_eater |= BIT(18); } - gpu_write(gpu, VIVS_PM_PULSE_EATER, pulse_eater); + gpu_write_power(gpu, VIVS_PM_PULSE_EATER, pulse_eater); } static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu) @@ -1293,9 +1293,9 @@ static void sync_point_perfmon_sample_pre(struct etnaviv_gpu *gpu, u32 val; /* disable clock gating */ - val = gpu_read(gpu, VIVS_PM_POWER_CONTROLS); + val = gpu_read_power(gpu, VIVS_PM_POWER_CONTROLS); val &= ~VIVS_PM_POWER_CONTROLS_ENABLE_MODULE_CLOCK_GATING; - gpu_write(gpu, VIVS_PM_POWER_CONTROLS, val); + gpu_write_power(gpu, VIVS_PM_POWER_CONTROLS, val); /* enable debug register */ val = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL); @@ -1326,9 +1326,9 @@ static void sync_point_perfmon_sample_post(struct etnaviv_gpu *gpu, gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, val); /* enable clock gating */ - val = gpu_read(gpu, VIVS_PM_POWER_CONTROLS); + val = gpu_read_power(gpu, VIVS_PM_POWER_CONTROLS); val |= VIVS_PM_POWER_CONTROLS_ENABLE_MODULE_CLOCK_GATING; - gpu_write(gpu, VIVS_PM_POWER_CONTROLS, val); + gpu_write_power(gpu, VIVS_PM_POWER_CONTROLS, val); } diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h index 85eddd492774..39f1e83d3cc7 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h @@ -10,6 +10,7 @@ #include "etnaviv_gem.h" #include "etnaviv_mmu.h" #include "etnaviv_drv.h" +#include "common.xml.h" struct etnaviv_gem_submit; struct etnaviv_vram_mapping; @@ -159,6 +160,26 @@ static inline u32 gpu_read(struct etnaviv_gpu *gpu, u32 reg) return readl(gpu->mmio + reg); } +static inline u32 gpu_fix_power_address(struct etnaviv_gpu *gpu, u32 reg) +{ + /* Power registers in GC300 < 2.0 are offset by 0x100 */ + if (gpu->identity.model == chipModel_GC300 && + gpu->identity.revision < 0x2000) + reg += 0x100; + + return reg; +} + +static inline void gpu_write_power(struct etnaviv_gpu *gpu, u32 reg, u32 data) +{ + writel(data, gpu->mmio + gpu_fix_power_address(gpu, reg)); +} + +static inline u32 gpu_read_power(struct etnaviv_gpu *gpu, u32 reg) +{ + return readl(gpu->mmio + gpu_fix_power_address(gpu, reg)); +} + int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value); int etnaviv_gpu_init(struct etnaviv_gpu *gpu); From 5a8c948d3a5854f1818ae36814966d2f0e6b4db5 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 5 Jul 2024 22:00:09 +0200 Subject: [PATCH 048/118] drm/etnaviv: hold GPU lock across perfmon sampling [ Upstream commit 37dc4737447a7667f8e9ec790dac251da057eb27 ] The perfmon sampling mutates shared GPU state (e.g. VIVS_HI_CLOCK_CONTROL to select the pipe for the perf counter reads). To avoid clashing with other functions mutating the same state (e.g. etnaviv_gpu_update_clock) the perfmon sampling needs to hold the GPU lock. Fixes: 68dc0b295dcb ("drm/etnaviv: use 'sync points' for performance monitor requests") Reviewed-by: Christian Gmeiner Signed-off-by: Lucas Stach Signed-off-by: Sasha Levin --- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index 6c070411d95f..c0410e314dfa 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -1292,6 +1292,8 @@ static void sync_point_perfmon_sample_pre(struct etnaviv_gpu *gpu, { u32 val; + mutex_lock(&gpu->lock); + /* disable clock gating */ val = gpu_read_power(gpu, VIVS_PM_POWER_CONTROLS); val &= ~VIVS_PM_POWER_CONTROLS_ENABLE_MODULE_CLOCK_GATING; @@ -1303,6 +1305,8 @@ static void sync_point_perfmon_sample_pre(struct etnaviv_gpu *gpu, gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, val); sync_point_perfmon_sample(gpu, event, ETNA_PM_PROCESS_PRE); + + mutex_unlock(&gpu->lock); } static void sync_point_perfmon_sample_post(struct etnaviv_gpu *gpu, @@ -1312,14 +1316,10 @@ static void sync_point_perfmon_sample_post(struct etnaviv_gpu *gpu, unsigned int i; u32 val; + mutex_lock(&gpu->lock); + sync_point_perfmon_sample(gpu, event, ETNA_PM_PROCESS_POST); - for (i = 0; i < submit->nr_pmrs; i++) { - const struct etnaviv_perfmon_request *pmr = submit->pmrs + i; - - *pmr->bo_vma = pmr->sequence; - } - /* disable debug register */ val = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL); val |= VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS; @@ -1329,6 +1329,14 @@ static void sync_point_perfmon_sample_post(struct etnaviv_gpu *gpu, val = gpu_read_power(gpu, VIVS_PM_POWER_CONTROLS); val |= VIVS_PM_POWER_CONTROLS_ENABLE_MODULE_CLOCK_GATING; gpu_write_power(gpu, VIVS_PM_POWER_CONTROLS, val); + + mutex_unlock(&gpu->lock); + + for (i = 0; i < submit->nr_pmrs; i++) { + const struct etnaviv_perfmon_request *pmr = submit->pmrs + i; + + *pmr->bo_vma = pmr->sequence; + } } From 27591e2e9116415c9ae9fe7d5d6fa55d25cfc890 Mon Sep 17 00:00:00 2001 From: Yuan Can Date: Tue, 22 Oct 2024 17:04:53 +0800 Subject: [PATCH 049/118] wifi: wfx: Fix error handling in wfx_core_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 3b88a9876779b55478a4dde867e73f7a100ffa23 ] The wfx_core_init() returns without checking the retval from sdio_register_driver(). If the sdio_register_driver() failed, the module failed to install, leaving the wfx_spi_driver not unregistered. Fixes: a7a91ca5a23d ("staging: wfx: add infrastructure for new driver") Signed-off-by: Yuan Can Reviewed-by: Jérôme Pouiller Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241022090453.84679-1-yuancan@huawei.com Signed-off-by: Sasha Levin --- drivers/net/wireless/silabs/wfx/main.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/silabs/wfx/main.c b/drivers/net/wireless/silabs/wfx/main.c index 84d82ddded56..2a3dc7d961ed 100644 --- a/drivers/net/wireless/silabs/wfx/main.c +++ b/drivers/net/wireless/silabs/wfx/main.c @@ -479,10 +479,23 @@ static int __init wfx_core_init(void) { int ret = 0; - if (IS_ENABLED(CONFIG_SPI)) + if (IS_ENABLED(CONFIG_SPI)) { ret = spi_register_driver(&wfx_spi_driver); - if (IS_ENABLED(CONFIG_MMC) && !ret) + if (ret) + goto out; + } + if (IS_ENABLED(CONFIG_MMC)) { ret = sdio_register_driver(&wfx_sdio_driver); + if (ret) + goto unregister_spi; + } + + return 0; + +unregister_spi: + if (IS_ENABLED(CONFIG_SPI)) + spi_unregister_driver(&wfx_spi_driver); +out: return ret; } module_init(wfx_core_init); From 7f6f583be369aed4a848f4dc9241490d1caedfb3 Mon Sep 17 00:00:00 2001 From: Zichen Xie Date: Tue, 29 Oct 2024 14:42:10 -0500 Subject: [PATCH 050/118] drm/msm/dpu: cast crtc_clk calculation to u64 in _dpu_core_perf_calc_clk() [ Upstream commit 20c7b42d9dbd048019bfe0af39229e3014007a98 ] There may be a potential integer overflow issue in _dpu_core_perf_calc_clk(). crtc_clk is defined as u64, while mode->vtotal, mode->hdisplay, and drm_mode_vrefresh(mode) are defined as a smaller data type. The result of the calculation will be limited to "int" in this case without correct casting. In screen with high resolution and high refresh rate, integer overflow may happen. So, we recommend adding an extra cast to prevent potential integer overflow. Fixes: c33b7c0389e1 ("drm/msm/dpu: add support for clk and bw scaling for display") Signed-off-by: Zichen Xie Reviewed-by: Abhinav Kumar Patchwork: https://patchwork.freedesktop.org/patch/622206/ Link: https://lore.kernel.org/r/20241029194209.23684-1-zichenxie0106@gmail.com Signed-off-by: Dmitry Baryshkov Signed-off-by: Sasha Levin --- drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c index 1d9d83d7b99e..72f043732f93 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c @@ -80,7 +80,7 @@ static u64 _dpu_core_perf_calc_clk(struct dpu_kms *kms, mode = &state->adjusted_mode; - crtc_clk = mode->vtotal * mode->hdisplay * drm_mode_vrefresh(mode); + crtc_clk = (u64)mode->vtotal * mode->hdisplay * drm_mode_vrefresh(mode); drm_atomic_crtc_for_each_plane(plane, crtc) { pstate = to_dpu_plane_state(plane->state); From 7703551d0b2dbd53a865e00468c1488578335125 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 5 Mar 2024 09:35:48 +0100 Subject: [PATCH 051/118] netfilter: nf_tables: skip transaction if update object is not implemented [ Upstream commit 84b1a0c0140a9a92ea108576c0002210f224ce59 ] Turn update into noop as a follow up for: 9fedd894b4e1 ("netfilter: nf_tables: fix unexpected EOPNOTSUPP error") instead of adding a transaction object which is simply discarded at a later stage of the commit protocol. Signed-off-by: Pablo Neira Ayuso Stable-dep-of: cddc04275f95 ("netfilter: nf_tables: must hold rcu read lock while iterating object type list") Signed-off-by: Sasha Levin --- net/netfilter/nf_tables_api.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index ed09b1fdda16..d7a628e2c249 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -7313,6 +7313,9 @@ static int nf_tables_newobj(struct sk_buff *skb, const struct nfnl_info *info, if (WARN_ON_ONCE(!type)) return -ENOENT; + if (!obj->ops->update) + return 0; + nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla); return nf_tables_updobj(&ctx, type, nla[NFTA_OBJ_DATA], obj); @@ -8972,9 +8975,10 @@ static void nft_obj_commit_update(struct nft_trans *trans) obj = nft_trans_obj(trans); newobj = nft_trans_obj_newobj(trans); - if (obj->ops->update) - obj->ops->update(obj, newobj); + if (WARN_ON_ONCE(!obj->ops->update)) + return; + obj->ops->update(obj, newobj); nft_obj_destroy(&trans->ctx, newobj); } From 9c49d377079048f4d94e49dfdb67cea00100e4ef Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 4 Nov 2024 10:41:19 +0100 Subject: [PATCH 052/118] netfilter: nf_tables: must hold rcu read lock while iterating object type list [ Upstream commit cddc04275f95ca3b18da5c0fb111705ac173af89 ] Update of stateful object triggers: WARNING: suspicious RCU usage net/netfilter/nf_tables_api.c:7759 RCU-list traversed in non-reader section!! other info that might help us debug this: rcu_scheduler_active = 2, debug_locks = 1 1 lock held by nft/3060: #0: ffff88810f0578c8 (&nft_net->commit_mutex){+.+.}-{4:4}, [..] ... but this list is not protected by the transaction mutex but the nfnl nftables subsystem mutex. Switch to nft_obj_type_get which will acquire rcu read lock, bump refcount, and returns the result. v3: Dan Carpenter points out nft_obj_type_get returns error pointer, not NULL, on error. Fixes: dad3bdeef45f ("netfilter: nf_tables: fix memory leak during stateful obj update"). Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin --- net/netfilter/nf_tables_api.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index d7a628e2c249..07bcf9b7d779 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -7239,9 +7239,7 @@ static int nf_tables_updobj(const struct nft_ctx *ctx, struct nft_trans *trans; int err = -ENOMEM; - if (!try_module_get(type->owner)) - return -ENOENT; - + /* caller must have obtained type->owner reference. */ trans = nft_trans_alloc(ctx, NFT_MSG_NEWOBJ, sizeof(struct nft_trans_obj)); if (!trans) @@ -7309,15 +7307,16 @@ static int nf_tables_newobj(struct sk_buff *skb, const struct nfnl_info *info, if (info->nlh->nlmsg_flags & NLM_F_REPLACE) return -EOPNOTSUPP; - type = __nft_obj_type_get(objtype, family); - if (WARN_ON_ONCE(!type)) - return -ENOENT; - if (!obj->ops->update) return 0; + type = nft_obj_type_get(net, objtype, family); + if (WARN_ON_ONCE(IS_ERR(type))) + return PTR_ERR(type); + nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla); + /* type->owner reference is put when transaction object is released. */ return nf_tables_updobj(&ctx, type, nla[NFTA_OBJ_DATA], obj); } From f500518cc89d51fc1f29dc11784ce1b91ba78c0e Mon Sep 17 00:00:00 2001 From: Maurice Lambert Date: Sun, 3 Nov 2024 23:39:50 +0100 Subject: [PATCH 053/118] netlink: typographical error in nlmsg_type constants definition [ Upstream commit 84bfbfbbd32aee136afea4b6bf82581dce79c305 ] This commit fix a typographical error in netlink nlmsg_type constants definition in the include/uapi/linux/rtnetlink.h at line 177. The definition is RTM_NEWNVLAN RTM_NEWVLAN instead of RTM_NEWVLAN RTM_NEWVLAN. Signed-off-by: Maurice Lambert Fixes: 8dcea187088b ("net: bridge: vlan: add rtm definitions and dump support") Link: https://patch.msgid.link/20241103223950.230300-1-mauricelambert434@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- include/uapi/linux/rtnetlink.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index 51c13cf9c5ae..63a0922937e7 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h @@ -174,7 +174,7 @@ enum { #define RTM_GETLINKPROP RTM_GETLINKPROP RTM_NEWVLAN = 112, -#define RTM_NEWNVLAN RTM_NEWVLAN +#define RTM_NEWVLAN RTM_NEWVLAN RTM_DELVLAN, #define RTM_DELVLAN RTM_DELVLAN RTM_GETVLAN, From a479d22242cf2efc4c00a6c1d7197e4cbbf3b559 Mon Sep 17 00:00:00 2001 From: Zijian Zhang Date: Wed, 6 Nov 2024 22:25:13 +0000 Subject: [PATCH 054/118] selftests/bpf: Add txmsg_pass to pull/push/pop in test_sockmap [ Upstream commit 66c54c20408d994be34be2c070fba08472f69eee ] Add txmsg_pass to test_txmsg_pull/push/pop. If txmsg_pass is missing, tx_prog will be NULL, and no program will be attached to the sockmap. As a result, pull/push/pop are never invoked. Fixes: 328aa08a081b ("bpf: Selftests, break down test_sockmap into subtests") Signed-off-by: Zijian Zhang Reviewed-by: John Fastabend Link: https://lore.kernel.org/r/20241106222520.527076-2-zijianzhang@bytedance.com Signed-off-by: Martin KaFai Lau Signed-off-by: Sasha Levin --- tools/testing/selftests/bpf/test_sockmap.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/testing/selftests/bpf/test_sockmap.c b/tools/testing/selftests/bpf/test_sockmap.c index 1954c2aeb7a9..102a9bafbe6b 100644 --- a/tools/testing/selftests/bpf/test_sockmap.c +++ b/tools/testing/selftests/bpf/test_sockmap.c @@ -1599,11 +1599,13 @@ static void test_txmsg_cork_hangs(int cgrp, struct sockmap_options *opt) static void test_txmsg_pull(int cgrp, struct sockmap_options *opt) { /* Test basic start/end */ + txmsg_pass = 1; txmsg_start = 1; txmsg_end = 2; test_send(opt, cgrp); /* Test >4k pull */ + txmsg_pass = 1; txmsg_start = 4096; txmsg_end = 9182; test_send_large(opt, cgrp); @@ -1632,11 +1634,13 @@ static void test_txmsg_pull(int cgrp, struct sockmap_options *opt) static void test_txmsg_pop(int cgrp, struct sockmap_options *opt) { /* Test basic pop */ + txmsg_pass = 1; txmsg_start_pop = 1; txmsg_pop = 2; test_send_many(opt, cgrp); /* Test pop with >4k */ + txmsg_pass = 1; txmsg_start_pop = 4096; txmsg_pop = 4096; test_send_large(opt, cgrp); @@ -1665,11 +1669,13 @@ static void test_txmsg_pop(int cgrp, struct sockmap_options *opt) static void test_txmsg_push(int cgrp, struct sockmap_options *opt) { /* Test basic push */ + txmsg_pass = 1; txmsg_start_push = 1; txmsg_end_push = 1; test_send(opt, cgrp); /* Test push 4kB >4k */ + txmsg_pass = 1; txmsg_start_push = 4096; txmsg_end_push = 4096; test_send_large(opt, cgrp); @@ -1690,6 +1696,7 @@ static void test_txmsg_push(int cgrp, struct sockmap_options *opt) static void test_txmsg_push_pop(int cgrp, struct sockmap_options *opt) { + txmsg_pass = 1; txmsg_start_push = 1; txmsg_end_push = 10; txmsg_start_pop = 5; From 0bff469c83123e9c1861d14d17194fbb34d1c772 Mon Sep 17 00:00:00 2001 From: Zijian Zhang Date: Wed, 6 Nov 2024 22:25:14 +0000 Subject: [PATCH 055/118] selftests/bpf: Fix SENDPAGE data logic in test_sockmap [ Upstream commit 4095031463d4e99b534d2cd82035a417295764ae ] In the SENDPAGE test, "opt->iov_length * cnt" size of data will be sent cnt times by sendfile. 1. In push/pop tests, they will be invoked cnt times, for the simplicity of msg_verify_data, change chunk_sz to iov_length 2. Change iov_length in test_send_large from 1024 to 8192. We have pop test where txmsg_start_pop is 4096. 4096 > 1024, an error will be returned. Fixes: 328aa08a081b ("bpf: Selftests, break down test_sockmap into subtests") Signed-off-by: Zijian Zhang Reviewed-by: John Fastabend Link: https://lore.kernel.org/r/20241106222520.527076-3-zijianzhang@bytedance.com Signed-off-by: Martin KaFai Lau Signed-off-by: Sasha Levin --- tools/testing/selftests/bpf/test_sockmap.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/bpf/test_sockmap.c b/tools/testing/selftests/bpf/test_sockmap.c index 102a9bafbe6b..07edc88fa9cb 100644 --- a/tools/testing/selftests/bpf/test_sockmap.c +++ b/tools/testing/selftests/bpf/test_sockmap.c @@ -419,16 +419,18 @@ static int msg_loop_sendpage(int fd, int iov_length, int cnt, { bool drop = opt->drop_expected; unsigned char k = 0; + int i, j, fp; FILE *file; - int i, fp; file = tmpfile(); if (!file) { perror("create file for sendpage"); return 1; } - for (i = 0; i < iov_length * cnt; i++, k++) - fwrite(&k, sizeof(char), 1, file); + for (i = 0; i < cnt; i++, k = 0) { + for (j = 0; j < iov_length; j++, k++) + fwrite(&k, sizeof(char), 1, file); + } fflush(file); fseek(file, 0, SEEK_SET); @@ -622,7 +624,9 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt, * This is really only useful for testing edge cases in code * paths. */ - total_bytes = (float)iov_count * (float)iov_length * (float)cnt; + total_bytes = (float)iov_length * (float)cnt; + if (!opt->sendpage) + total_bytes *= (float)iov_count; if (txmsg_apply) txmsg_pop_total = txmsg_pop * (total_bytes / txmsg_apply); else @@ -700,7 +704,7 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt, if (data) { int chunk_sz = opt->sendpage ? - iov_length * cnt : + iov_length : iov_length * iov_count; errno = msg_verify_data(&msg, recv, chunk_sz, &k, &bytes_cnt); @@ -1469,8 +1473,8 @@ static void test_send_many(struct sockmap_options *opt, int cgrp) static void test_send_large(struct sockmap_options *opt, int cgrp) { - opt->iov_length = 256; - opt->iov_count = 1024; + opt->iov_length = 8192; + opt->iov_count = 32; opt->rate = 2; test_exec(cgrp, opt); } From 4a9eebcee47cc3e0232d8d2c696b260e84eef3f6 Mon Sep 17 00:00:00 2001 From: Zijian Zhang Date: Wed, 6 Nov 2024 22:25:15 +0000 Subject: [PATCH 056/118] selftests/bpf: Fix total_bytes in msg_loop_rx in test_sockmap [ Upstream commit 523dffccbadea0cfd65f1ff04944b864c558c4a8 ] total_bytes in msg_loop_rx should also take push into account, otherwise total_bytes will be a smaller value, which makes the msg_loop_rx end early. Besides, total_bytes has already taken pop into account, so we don't need to subtract some bytes from iov_buf in sendmsg_test. The additional subtraction may make total_bytes a negative number, and msg_loop_rx will just end without checking anything. Fixes: 18d4e900a450 ("bpf: Selftests, improve test_sockmap total bytes counter") Fixes: d69672147faa ("selftests, bpf: Add one test for sockmap with strparser") Signed-off-by: Zijian Zhang Reviewed-by: John Fastabend Link: https://lore.kernel.org/r/20241106222520.527076-4-zijianzhang@bytedance.com Signed-off-by: Martin KaFai Lau Signed-off-by: Sasha Levin --- tools/testing/selftests/bpf/test_sockmap.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/bpf/test_sockmap.c b/tools/testing/selftests/bpf/test_sockmap.c index 07edc88fa9cb..0d21c6c752da 100644 --- a/tools/testing/selftests/bpf/test_sockmap.c +++ b/tools/testing/selftests/bpf/test_sockmap.c @@ -605,8 +605,8 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt, } clock_gettime(CLOCK_MONOTONIC, &s->end); } else { + float total_bytes, txmsg_pop_total, txmsg_push_total; int slct, recvp = 0, recv, max_fd = fd; - float total_bytes, txmsg_pop_total; int fd_flags = O_NONBLOCK; struct timeval timeout; unsigned char k = 0; @@ -627,10 +627,14 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt, total_bytes = (float)iov_length * (float)cnt; if (!opt->sendpage) total_bytes *= (float)iov_count; - if (txmsg_apply) + if (txmsg_apply) { + txmsg_push_total = txmsg_end_push * (total_bytes / txmsg_apply); txmsg_pop_total = txmsg_pop * (total_bytes / txmsg_apply); - else + } else { + txmsg_push_total = txmsg_end_push * cnt; txmsg_pop_total = txmsg_pop * cnt; + } + total_bytes += txmsg_push_total; total_bytes -= txmsg_pop_total; err = clock_gettime(CLOCK_MONOTONIC, &s->start); if (err < 0) @@ -799,8 +803,6 @@ static int sendmsg_test(struct sockmap_options *opt) rxpid = fork(); if (rxpid == 0) { - if (txmsg_pop || txmsg_start_pop) - iov_buf -= (txmsg_pop - txmsg_start_pop + 1); if (opt->drop_expected || txmsg_ktls_skb_drop) _exit(0); From 9f5d3dd1421066e419021f1b5c3a60da0fa9c0a2 Mon Sep 17 00:00:00 2001 From: Zijian Zhang Date: Wed, 6 Nov 2024 22:25:16 +0000 Subject: [PATCH 057/118] selftests/bpf: Add push/pop checking for msg_verify_data in test_sockmap [ Upstream commit 862087c3d36219ed44569666eb263efc97f00c9a ] Add push/pop checking for msg_verify_data in test_sockmap, except for pop/push with cork tests, in these tests the logic will be different. 1. With corking, pop/push might not be invoked in each sendmsg, it makes the layout of the received data difficult 2. It makes it hard to calculate the total_bytes in the recvmsg Temporarily skip the data integrity test for these cases now, added a TODO Fixes: ee9b352ce465 ("selftests/bpf: Fix msg_verify_data in test_sockmap") Signed-off-by: Zijian Zhang Reviewed-by: John Fastabend Link: https://lore.kernel.org/r/20241106222520.527076-5-zijianzhang@bytedance.com Signed-off-by: Martin KaFai Lau Signed-off-by: Sasha Levin --- tools/testing/selftests/bpf/test_sockmap.c | 108 +++++++++++++++++++-- 1 file changed, 102 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/bpf/test_sockmap.c b/tools/testing/selftests/bpf/test_sockmap.c index 0d21c6c752da..d0284ef699bb 100644 --- a/tools/testing/selftests/bpf/test_sockmap.c +++ b/tools/testing/selftests/bpf/test_sockmap.c @@ -87,6 +87,10 @@ int ktls; int peek_flag; int skb_use_parser; int txmsg_omit_skb_parser; +int verify_push_start; +int verify_push_len; +int verify_pop_start; +int verify_pop_len; static const struct option long_options[] = { {"help", no_argument, NULL, 'h' }, @@ -513,12 +517,41 @@ unwind_iov: return -ENOMEM; } -/* TODO: Add verification logic for push, pull and pop data */ -static int msg_verify_data(struct msghdr *msg, int size, int chunk_sz, - unsigned char *k_p, int *bytes_cnt_p) +/* In push or pop test, we need to do some calculations for msg_verify_data */ +static void msg_verify_date_prep(void) { - int i, j, bytes_cnt = *bytes_cnt_p; + int push_range_end = txmsg_start_push + txmsg_end_push - 1; + int pop_range_end = txmsg_start_pop + txmsg_pop - 1; + + if (txmsg_end_push && txmsg_pop && + txmsg_start_push <= pop_range_end && txmsg_start_pop <= push_range_end) { + /* The push range and the pop range overlap */ + int overlap_len; + + verify_push_start = txmsg_start_push; + verify_pop_start = txmsg_start_pop; + if (txmsg_start_push < txmsg_start_pop) + overlap_len = min(push_range_end - txmsg_start_pop + 1, txmsg_pop); + else + overlap_len = min(pop_range_end - txmsg_start_push + 1, txmsg_end_push); + verify_push_len = max(txmsg_end_push - overlap_len, 0); + verify_pop_len = max(txmsg_pop - overlap_len, 0); + } else { + /* Otherwise */ + verify_push_start = txmsg_start_push; + verify_pop_start = txmsg_start_pop; + verify_push_len = txmsg_end_push; + verify_pop_len = txmsg_pop; + } +} + +static int msg_verify_data(struct msghdr *msg, int size, int chunk_sz, + unsigned char *k_p, int *bytes_cnt_p, + int *check_cnt_p, int *push_p) +{ + int bytes_cnt = *bytes_cnt_p, check_cnt = *check_cnt_p, push = *push_p; unsigned char k = *k_p; + int i, j; for (i = 0, j = 0; i < msg->msg_iovlen && size; i++, j = 0) { unsigned char *d = msg->msg_iov[i].iov_base; @@ -537,6 +570,37 @@ static int msg_verify_data(struct msghdr *msg, int size, int chunk_sz, } for (; j < msg->msg_iov[i].iov_len && size; j++) { + if (push > 0 && + check_cnt == verify_push_start + verify_push_len - push) { + int skipped; +revisit_push: + skipped = push; + if (j + push >= msg->msg_iov[i].iov_len) + skipped = msg->msg_iov[i].iov_len - j; + push -= skipped; + size -= skipped; + j += skipped - 1; + check_cnt += skipped; + continue; + } + + if (verify_pop_len > 0 && check_cnt == verify_pop_start) { + bytes_cnt += verify_pop_len; + check_cnt += verify_pop_len; + k += verify_pop_len; + + if (bytes_cnt == chunk_sz) { + k = 0; + bytes_cnt = 0; + check_cnt = 0; + push = verify_push_len; + } + + if (push > 0 && + check_cnt == verify_push_start + verify_push_len - push) + goto revisit_push; + } + if (d[j] != k++) { fprintf(stderr, "detected data corruption @iov[%i]:%i %02x != %02x, %02x ?= %02x\n", @@ -544,15 +608,20 @@ static int msg_verify_data(struct msghdr *msg, int size, int chunk_sz, return -EDATAINTEGRITY; } bytes_cnt++; + check_cnt++; if (bytes_cnt == chunk_sz) { k = 0; bytes_cnt = 0; + check_cnt = 0; + push = verify_push_len; } size--; } } *k_p = k; *bytes_cnt_p = bytes_cnt; + *check_cnt_p = check_cnt; + *push_p = push; return 0; } @@ -611,6 +680,8 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt, struct timeval timeout; unsigned char k = 0; int bytes_cnt = 0; + int check_cnt = 0; + int push = 0; fd_set w; fcntl(fd, fd_flags); @@ -636,6 +707,10 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt, } total_bytes += txmsg_push_total; total_bytes -= txmsg_pop_total; + if (data) { + msg_verify_date_prep(); + push = verify_push_len; + } err = clock_gettime(CLOCK_MONOTONIC, &s->start); if (err < 0) perror("recv start time"); @@ -711,7 +786,8 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt, iov_length : iov_length * iov_count; - errno = msg_verify_data(&msg, recv, chunk_sz, &k, &bytes_cnt); + errno = msg_verify_data(&msg, recv, chunk_sz, &k, &bytes_cnt, + &check_cnt, &push); if (errno) { perror("data verify msg failed"); goto out_errno; @@ -721,7 +797,9 @@ static int msg_loop(int fd, int iov_count, int iov_length, int cnt, recvp, chunk_sz, &k, - &bytes_cnt); + &bytes_cnt, + &check_cnt, + &push); if (errno) { perror("data verify msg_peek failed"); goto out_errno; @@ -1639,6 +1717,8 @@ static void test_txmsg_pull(int cgrp, struct sockmap_options *opt) static void test_txmsg_pop(int cgrp, struct sockmap_options *opt) { + bool data = opt->data_test; + /* Test basic pop */ txmsg_pass = 1; txmsg_start_pop = 1; @@ -1657,6 +1737,12 @@ static void test_txmsg_pop(int cgrp, struct sockmap_options *opt) txmsg_pop = 2; test_send_many(opt, cgrp); + /* TODO: Test for pop + cork should be different, + * - It makes the layout of the received data difficult + * - It makes it hard to calculate the total_bytes in the recvmsg + * Temporarily skip the data integrity test for this case now. + */ + opt->data_test = false; /* Test pop + cork */ txmsg_redir = 0; txmsg_cork = 512; @@ -1670,10 +1756,13 @@ static void test_txmsg_pop(int cgrp, struct sockmap_options *opt) txmsg_start_pop = 1; txmsg_pop = 2; test_send_many(opt, cgrp); + opt->data_test = data; } static void test_txmsg_push(int cgrp, struct sockmap_options *opt) { + bool data = opt->data_test; + /* Test basic push */ txmsg_pass = 1; txmsg_start_push = 1; @@ -1692,12 +1781,19 @@ static void test_txmsg_push(int cgrp, struct sockmap_options *opt) txmsg_end_push = 2; test_send_many(opt, cgrp); + /* TODO: Test for push + cork should be different, + * - It makes the layout of the received data difficult + * - It makes it hard to calculate the total_bytes in the recvmsg + * Temporarily skip the data integrity test for this case now. + */ + opt->data_test = false; /* Test push + cork */ txmsg_redir = 0; txmsg_cork = 512; txmsg_start_push = 1; txmsg_end_push = 2; test_send_many(opt, cgrp); + opt->data_test = data; } static void test_txmsg_push_pop(int cgrp, struct sockmap_options *opt) From cadfa4d23f52b0f13e702ad08de92014756fba55 Mon Sep 17 00:00:00 2001 From: Zijian Zhang Date: Wed, 6 Nov 2024 22:25:18 +0000 Subject: [PATCH 058/118] bpf, sockmap: Several fixes to bpf_msg_push_data [ Upstream commit 15ab0548e3107665c34579ae523b2b6e7c22082a ] Several fixes to bpf_msg_push_data, 1. test_sockmap has tests where bpf_msg_push_data is invoked to push some data at the end of a message, but -EINVAL is returned. In this case, in bpf_msg_push_data, after the first loop, i will be set to msg->sg.end, add the logic to handle it. 2. In the code block of "if (start - offset)", it's possible that "i" points to the last of sk_msg_elem. In this case, "sk_msg_iter_next(msg, end)" might still be called twice, another invoking is in "if (!copy)" code block, but actually only one is needed. Add the logic to handle it, and reconstruct the code to make the logic more clear. Fixes: 6fff607e2f14 ("bpf: sk_msg program helper bpf_msg_push_data") Signed-off-by: Zijian Zhang Link: https://lore.kernel.org/r/20241106222520.527076-7-zijianzhang@bytedance.com Signed-off-by: Martin KaFai Lau Signed-off-by: Sasha Levin --- net/core/filter.c | 53 +++++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/net/core/filter.c b/net/core/filter.c index 2f6fef5f5864..b4ed0d917781 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -2768,7 +2768,7 @@ BPF_CALL_4(bpf_msg_push_data, struct sk_msg *, msg, u32, start, sk_msg_iter_var_next(i); } while (i != msg->sg.end); - if (start >= offset + l) + if (start > offset + l) return -EINVAL; space = MAX_MSG_FRAGS - sk_msg_elem_used(msg); @@ -2793,6 +2793,8 @@ BPF_CALL_4(bpf_msg_push_data, struct sk_msg *, msg, u32, start, raw = page_address(page); + if (i == msg->sg.end) + sk_msg_iter_var_prev(i); psge = sk_msg_elem(msg, i); front = start - offset; back = psge->length - front; @@ -2809,7 +2811,13 @@ BPF_CALL_4(bpf_msg_push_data, struct sk_msg *, msg, u32, start, } put_page(sg_page(psge)); - } else if (start - offset) { + new = i; + goto place_new; + } + + if (start - offset) { + if (i == msg->sg.end) + sk_msg_iter_var_prev(i); psge = sk_msg_elem(msg, i); rsge = sk_msg_elem_cpy(msg, i); @@ -2820,39 +2828,44 @@ BPF_CALL_4(bpf_msg_push_data, struct sk_msg *, msg, u32, start, sk_msg_iter_var_next(i); sg_unmark_end(psge); sg_unmark_end(&rsge); - sk_msg_iter_next(msg, end); } /* Slot(s) to place newly allocated data */ + sk_msg_iter_next(msg, end); new = i; + sk_msg_iter_var_next(i); + + if (i == msg->sg.end) { + if (!rsge.length) + goto place_new; + sk_msg_iter_next(msg, end); + goto place_new; + } /* Shift one or two slots as needed */ - if (!copy) { - sge = sk_msg_elem_cpy(msg, i); + sge = sk_msg_elem_cpy(msg, new); + sg_unmark_end(&sge); + nsge = sk_msg_elem_cpy(msg, i); + if (rsge.length) { sk_msg_iter_var_next(i); - sg_unmark_end(&sge); + nnsge = sk_msg_elem_cpy(msg, i); sk_msg_iter_next(msg, end); + } - nsge = sk_msg_elem_cpy(msg, i); + while (i != msg->sg.end) { + msg->sg.data[i] = sge; + sge = nsge; + sk_msg_iter_var_next(i); if (rsge.length) { - sk_msg_iter_var_next(i); + nsge = nnsge; nnsge = sk_msg_elem_cpy(msg, i); - } - - while (i != msg->sg.end) { - msg->sg.data[i] = sge; - sge = nsge; - sk_msg_iter_var_next(i); - if (rsge.length) { - nsge = nnsge; - nnsge = sk_msg_elem_cpy(msg, i); - } else { - nsge = sk_msg_elem_cpy(msg, i); - } + } else { + nsge = sk_msg_elem_cpy(msg, i); } } +place_new: /* Place newly allocated data buffer */ sk_mem_charge(msg->sk, len); msg->sg.size += len; From f58d3aa457e77a3d9b3df2ab081dcf9950f6029f Mon Sep 17 00:00:00 2001 From: Zijian Zhang Date: Wed, 6 Nov 2024 22:25:19 +0000 Subject: [PATCH 059/118] bpf, sockmap: Several fixes to bpf_msg_pop_data [ Upstream commit 5d609ba262475db450ba69b8e8a557bd768ac07a ] Several fixes to bpf_msg_pop_data, 1. In sk_msg_shift_left, we should put_page 2. if (len == 0), return early is better 3. pop the entire sk_msg (last == msg->sg.size) should be supported 4. Fix for the value of variable "a" 5. In sk_msg_shift_left, after shifting, i has already pointed to the next element. Addtional sk_msg_iter_var_next may result in BUG. Fixes: 7246d8ed4dcc ("bpf: helper to pop data from messages") Signed-off-by: Zijian Zhang Reviewed-by: John Fastabend Link: https://lore.kernel.org/r/20241106222520.527076-8-zijianzhang@bytedance.com Signed-off-by: Martin KaFai Lau Signed-off-by: Sasha Levin --- net/core/filter.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/net/core/filter.c b/net/core/filter.c index b4ed0d917781..5174f4d48647 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -2894,8 +2894,10 @@ static const struct bpf_func_proto bpf_msg_push_data_proto = { static void sk_msg_shift_left(struct sk_msg *msg, int i) { + struct scatterlist *sge = sk_msg_elem(msg, i); int prev; + put_page(sg_page(sge)); do { prev = i; sk_msg_iter_var_next(i); @@ -2932,6 +2934,9 @@ BPF_CALL_4(bpf_msg_pop_data, struct sk_msg *, msg, u32, start, if (unlikely(flags)) return -EINVAL; + if (unlikely(len == 0)) + return 0; + /* First find the starting scatterlist element */ i = msg->sg.start; do { @@ -2944,7 +2949,7 @@ BPF_CALL_4(bpf_msg_pop_data, struct sk_msg *, msg, u32, start, } while (i != msg->sg.end); /* Bounds checks: start and pop must be inside message */ - if (start >= offset + l || last >= msg->sg.size) + if (start >= offset + l || last > msg->sg.size) return -EINVAL; space = MAX_MSG_FRAGS - sk_msg_elem_used(msg); @@ -2973,12 +2978,12 @@ BPF_CALL_4(bpf_msg_pop_data, struct sk_msg *, msg, u32, start, */ if (start != offset) { struct scatterlist *nsge, *sge = sk_msg_elem(msg, i); - int a = start; + int a = start - offset; int b = sge->length - pop - a; sk_msg_iter_var_next(i); - if (pop < sge->length - a) { + if (b > 0) { if (space) { sge->length = a; sk_msg_shift_right(msg, i); @@ -2997,7 +3002,6 @@ BPF_CALL_4(bpf_msg_pop_data, struct sk_msg *, msg, u32, start, if (unlikely(!page)) return -ENOMEM; - sge->length = a; orig = sg_page(sge); from = sg_virt(sge); to = page_address(page); @@ -3007,7 +3011,7 @@ BPF_CALL_4(bpf_msg_pop_data, struct sk_msg *, msg, u32, start, put_page(orig); } pop = 0; - } else if (pop >= sge->length - a) { + } else { pop -= (sge->length - a); sge->length = a; } @@ -3041,7 +3045,6 @@ BPF_CALL_4(bpf_msg_pop_data, struct sk_msg *, msg, u32, start, pop -= sge->length; sk_msg_shift_left(msg, i); } - sk_msg_iter_var_next(i); } sk_mem_uncharge(msg->sk, len - pop); From 9610b690335c891e4a6b1e04b39f6594addd6e09 Mon Sep 17 00:00:00 2001 From: Zijian Zhang Date: Wed, 6 Nov 2024 22:25:20 +0000 Subject: [PATCH 060/118] bpf, sockmap: Fix sk_msg_reset_curr [ Upstream commit 955afd57dc4bf7e8c620a0a9e3af3c881c2c6dff ] Found in the test_txmsg_pull in test_sockmap, ``` txmsg_cork = 512; // corking is importrant here opt->iov_length = 3; opt->iov_count = 1; opt->rate = 512; // sendmsg will be invoked 512 times ``` The first sendmsg will send an sk_msg with size 3, and bpf_msg_pull_data will be invoked the first time. sk_msg_reset_curr will reset the copybreak from 3 to 0. In the second sendmsg, since we are in the stage of corking, psock->cork will be reused in func sk_msg_alloc. msg->sg.copybreak is 0 now, the second msg will overwrite the first msg. As a result, we could not pass the data integrity test. The same problem happens in push and pop test. Thus, fix sk_msg_reset_curr to restore the correct copybreak. Fixes: bb9aefde5bba ("bpf: sockmap, updating the sg structure should also update curr") Signed-off-by: Zijian Zhang Link: https://lore.kernel.org/r/20241106222520.527076-9-zijianzhang@bytedance.com Signed-off-by: Martin KaFai Lau Signed-off-by: Sasha Levin --- net/core/filter.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/net/core/filter.c b/net/core/filter.c index 5174f4d48647..4a97c89c9da9 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -2594,18 +2594,16 @@ BPF_CALL_2(bpf_msg_cork_bytes, struct sk_msg *, msg, u32, bytes) static void sk_msg_reset_curr(struct sk_msg *msg) { - u32 i = msg->sg.start; - u32 len = 0; + if (!msg->sg.size) { + msg->sg.curr = msg->sg.start; + msg->sg.copybreak = 0; + } else { + u32 i = msg->sg.end; - do { - len += sk_msg_elem(msg, i)->length; - sk_msg_iter_var_next(i); - if (len >= msg->sg.size) - break; - } while (i != msg->sg.end); - - msg->sg.curr = i; - msg->sg.copybreak = 0; + sk_msg_iter_var_prev(i); + msg->sg.curr = i; + msg->sg.copybreak = msg->sg.data[i].length; + } } static const struct bpf_func_proto bpf_msg_cork_bytes_proto = { From 9c116890ae8b71e4f8e8639a8ca3c01a8c4becc8 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 22 Jan 2024 11:25:59 +0000 Subject: [PATCH 061/118] sock_diag: add module pointer to "struct sock_diag_handler" [ Upstream commit 114b4bb1cc19239b272d52ebbe156053483fe2f8 ] Following patch is going to use RCU instead of sock_diag_table_mutex acquisition. This patch is a preparation, no change of behavior yet. Signed-off-by: Eric Dumazet Reviewed-by: Guillaume Nault Reviewed-by: Kuniyuki Iwashima Reviewed-by: Willem de Bruijn Signed-off-by: Paolo Abeni Stable-dep-of: eb02688c5c45 ("ipv6: release nexthop on device removal") Signed-off-by: Sasha Levin --- include/linux/sock_diag.h | 1 + net/ipv4/inet_diag.c | 2 ++ net/netlink/diag.c | 1 + net/packet/diag.c | 1 + net/smc/smc_diag.c | 1 + net/tipc/diag.c | 1 + net/unix/diag.c | 1 + net/vmw_vsock/diag.c | 1 + net/xdp/xsk_diag.c | 1 + 9 files changed, 10 insertions(+) diff --git a/include/linux/sock_diag.h b/include/linux/sock_diag.h index 0b9ecd8cf979..7c07754d711b 100644 --- a/include/linux/sock_diag.h +++ b/include/linux/sock_diag.h @@ -13,6 +13,7 @@ struct nlmsghdr; struct sock; struct sock_diag_handler { + struct module *owner; __u8 family; int (*dump)(struct sk_buff *skb, struct nlmsghdr *nlh); int (*get_info)(struct sk_buff *skb, struct sock *sk); diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index e4e1999d93f5..a3d0e18885f5 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -1397,6 +1397,7 @@ int inet_diag_handler_get_info(struct sk_buff *skb, struct sock *sk) } static const struct sock_diag_handler inet_diag_handler = { + .owner = THIS_MODULE, .family = AF_INET, .dump = inet_diag_handler_cmd, .get_info = inet_diag_handler_get_info, @@ -1404,6 +1405,7 @@ static const struct sock_diag_handler inet_diag_handler = { }; static const struct sock_diag_handler inet6_diag_handler = { + .owner = THIS_MODULE, .family = AF_INET6, .dump = inet_diag_handler_cmd, .get_info = inet_diag_handler_get_info, diff --git a/net/netlink/diag.c b/net/netlink/diag.c index 9c4f231be275..7b15aa5f7bc2 100644 --- a/net/netlink/diag.c +++ b/net/netlink/diag.c @@ -241,6 +241,7 @@ static int netlink_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) } static const struct sock_diag_handler netlink_diag_handler = { + .owner = THIS_MODULE, .family = AF_NETLINK, .dump = netlink_diag_handler_dump, }; diff --git a/net/packet/diag.c b/net/packet/diag.c index a68a84574c73..057ee37bd076 100644 --- a/net/packet/diag.c +++ b/net/packet/diag.c @@ -245,6 +245,7 @@ static int packet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) } static const struct sock_diag_handler packet_diag_handler = { + .owner = THIS_MODULE, .family = AF_PACKET, .dump = packet_diag_handler_dump, }; diff --git a/net/smc/smc_diag.c b/net/smc/smc_diag.c index 7a907186a33a..2d1cd033398b 100644 --- a/net/smc/smc_diag.c +++ b/net/smc/smc_diag.c @@ -249,6 +249,7 @@ static int smc_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) } static const struct sock_diag_handler smc_diag_handler = { + .owner = THIS_MODULE, .family = AF_SMC, .dump = smc_diag_handler_dump, }; diff --git a/net/tipc/diag.c b/net/tipc/diag.c index 73137f4aeb68..11da9d2ebbf6 100644 --- a/net/tipc/diag.c +++ b/net/tipc/diag.c @@ -95,6 +95,7 @@ static int tipc_sock_diag_handler_dump(struct sk_buff *skb, } static const struct sock_diag_handler tipc_sock_diag_handler = { + .owner = THIS_MODULE, .family = AF_TIPC, .dump = tipc_sock_diag_handler_dump, }; diff --git a/net/unix/diag.c b/net/unix/diag.c index 1de7500b41b6..a6bd861314df 100644 --- a/net/unix/diag.c +++ b/net/unix/diag.c @@ -322,6 +322,7 @@ static int unix_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) } static const struct sock_diag_handler unix_diag_handler = { + .owner = THIS_MODULE, .family = AF_UNIX, .dump = unix_diag_handler_dump, }; diff --git a/net/vmw_vsock/diag.c b/net/vmw_vsock/diag.c index a2823b1c5e28..6efa9eb93336 100644 --- a/net/vmw_vsock/diag.c +++ b/net/vmw_vsock/diag.c @@ -157,6 +157,7 @@ static int vsock_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) } static const struct sock_diag_handler vsock_diag_handler = { + .owner = THIS_MODULE, .family = AF_VSOCK, .dump = vsock_diag_handler_dump, }; diff --git a/net/xdp/xsk_diag.c b/net/xdp/xsk_diag.c index 22b36c8143cf..e1012bfec720 100644 --- a/net/xdp/xsk_diag.c +++ b/net/xdp/xsk_diag.c @@ -194,6 +194,7 @@ static int xsk_diag_handler_dump(struct sk_buff *nlskb, struct nlmsghdr *hdr) } static const struct sock_diag_handler xsk_diag_handler = { + .owner = THIS_MODULE, .family = AF_XDP, .dump = xsk_diag_handler_dump, }; From 916551244aeed179c4613091edc2a8e4539b83e9 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 22 Jan 2024 11:26:00 +0000 Subject: [PATCH 062/118] sock_diag: allow concurrent operations [ Upstream commit 1d55a6974756cf3979efd2cc68bcece611a44053 ] sock_diag_broadcast_destroy_work() and __sock_diag_cmd() are currently using sock_diag_table_mutex to protect against concurrent sock_diag_handlers[] changes. This makes inet_diag dump serialized, thus less scalable than legacy /proc files. It is time to switch to full RCU protection. Signed-off-by: Eric Dumazet Reviewed-by: Guillaume Nault Reviewed-by: Kuniyuki Iwashima Reviewed-by: Willem de Bruijn Signed-off-by: Paolo Abeni Stable-dep-of: eb02688c5c45 ("ipv6: release nexthop on device removal") Signed-off-by: Sasha Levin --- net/core/sock_diag.c | 73 +++++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c index e6ea6764d10a..73b2e36032b3 100644 --- a/net/core/sock_diag.c +++ b/net/core/sock_diag.c @@ -16,7 +16,7 @@ #include #include -static const struct sock_diag_handler *sock_diag_handlers[AF_MAX]; +static const struct sock_diag_handler __rcu *sock_diag_handlers[AF_MAX]; static int (*inet_rcv_compat)(struct sk_buff *skb, struct nlmsghdr *nlh); static DEFINE_MUTEX(sock_diag_table_mutex); static struct workqueue_struct *broadcast_wq; @@ -119,6 +119,24 @@ static size_t sock_diag_nlmsg_size(void) + nla_total_size_64bit(sizeof(struct tcp_info))); /* INET_DIAG_INFO */ } +static const struct sock_diag_handler *sock_diag_lock_handler(int family) +{ + const struct sock_diag_handler *handler; + + rcu_read_lock(); + handler = rcu_dereference(sock_diag_handlers[family]); + if (handler && !try_module_get(handler->owner)) + handler = NULL; + rcu_read_unlock(); + + return handler; +} + +static void sock_diag_unlock_handler(const struct sock_diag_handler *handler) +{ + module_put(handler->owner); +} + static void sock_diag_broadcast_destroy_work(struct work_struct *work) { struct broadcast_sk *bsk = @@ -135,12 +153,12 @@ static void sock_diag_broadcast_destroy_work(struct work_struct *work) if (!skb) goto out; - mutex_lock(&sock_diag_table_mutex); - hndl = sock_diag_handlers[sk->sk_family]; - if (hndl && hndl->get_info) - err = hndl->get_info(skb, sk); - mutex_unlock(&sock_diag_table_mutex); - + hndl = sock_diag_lock_handler(sk->sk_family); + if (hndl) { + if (hndl->get_info) + err = hndl->get_info(skb, sk); + sock_diag_unlock_handler(hndl); + } if (!err) nlmsg_multicast(sock_net(sk)->diag_nlsk, skb, 0, group, GFP_KERNEL); @@ -181,33 +199,26 @@ EXPORT_SYMBOL_GPL(sock_diag_unregister_inet_compat); int sock_diag_register(const struct sock_diag_handler *hndl) { - int err = 0; + int family = hndl->family; - if (hndl->family >= AF_MAX) + if (family >= AF_MAX) return -EINVAL; - mutex_lock(&sock_diag_table_mutex); - if (sock_diag_handlers[hndl->family]) - err = -EBUSY; - else - WRITE_ONCE(sock_diag_handlers[hndl->family], hndl); - mutex_unlock(&sock_diag_table_mutex); - - return err; + return !cmpxchg((const struct sock_diag_handler **) + &sock_diag_handlers[family], + NULL, hndl) ? 0 : -EBUSY; } EXPORT_SYMBOL_GPL(sock_diag_register); -void sock_diag_unregister(const struct sock_diag_handler *hnld) +void sock_diag_unregister(const struct sock_diag_handler *hndl) { - int family = hnld->family; + int family = hndl->family; if (family >= AF_MAX) return; - mutex_lock(&sock_diag_table_mutex); - BUG_ON(sock_diag_handlers[family] != hnld); - WRITE_ONCE(sock_diag_handlers[family], NULL); - mutex_unlock(&sock_diag_table_mutex); + xchg((const struct sock_diag_handler **)&sock_diag_handlers[family], + NULL); } EXPORT_SYMBOL_GPL(sock_diag_unregister); @@ -224,20 +235,20 @@ static int __sock_diag_cmd(struct sk_buff *skb, struct nlmsghdr *nlh) return -EINVAL; req->sdiag_family = array_index_nospec(req->sdiag_family, AF_MAX); - if (READ_ONCE(sock_diag_handlers[req->sdiag_family]) == NULL) + if (!rcu_access_pointer(sock_diag_handlers[req->sdiag_family])) sock_load_diag_module(req->sdiag_family, 0); - mutex_lock(&sock_diag_table_mutex); - hndl = sock_diag_handlers[req->sdiag_family]; + hndl = sock_diag_lock_handler(req->sdiag_family); if (hndl == NULL) - err = -ENOENT; - else if (nlh->nlmsg_type == SOCK_DIAG_BY_FAMILY) + return -ENOENT; + + if (nlh->nlmsg_type == SOCK_DIAG_BY_FAMILY) err = hndl->dump(skb, nlh); else if (nlh->nlmsg_type == SOCK_DESTROY && hndl->destroy) err = hndl->destroy(skb, nlh); else err = -EOPNOTSUPP; - mutex_unlock(&sock_diag_table_mutex); + sock_diag_unlock_handler(hndl); return err; } @@ -283,12 +294,12 @@ static int sock_diag_bind(struct net *net, int group) switch (group) { case SKNLGRP_INET_TCP_DESTROY: case SKNLGRP_INET_UDP_DESTROY: - if (!READ_ONCE(sock_diag_handlers[AF_INET])) + if (!rcu_access_pointer(sock_diag_handlers[AF_INET])) sock_load_diag_module(AF_INET, 0); break; case SKNLGRP_INET6_TCP_DESTROY: case SKNLGRP_INET6_UDP_DESTROY: - if (!READ_ONCE(sock_diag_handlers[AF_INET6])) + if (!rcu_access_pointer(sock_diag_handlers[AF_INET6])) sock_load_diag_module(AF_INET6, 0); break; } From adf86509384a70a4780bc94eee43f15e8d36ce01 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 22 Jan 2024 11:26:01 +0000 Subject: [PATCH 063/118] sock_diag: allow concurrent operation in sock_diag_rcv_msg() [ Upstream commit 86e8921df05c6e9423ab74ab8d41022775d8b83a ] TCPDIAG_GETSOCK and DCCPDIAG_GETSOCK diag are serialized on sock_diag_table_mutex. This is to make sure inet_diag module is not unloaded while diag was ongoing. It is time to get rid of this mutex and use RCU protection, allowing full parallelism. Signed-off-by: Eric Dumazet Reviewed-by: Guillaume Nault Reviewed-by: Kuniyuki Iwashima Reviewed-by: Willem de Bruijn Signed-off-by: Paolo Abeni Stable-dep-of: eb02688c5c45 ("ipv6: release nexthop on device removal") Signed-off-by: Sasha Levin --- include/linux/sock_diag.h | 9 ++++++-- net/core/sock_diag.c | 43 +++++++++++++++++++++++---------------- net/ipv4/inet_diag.c | 9 ++++++-- 3 files changed, 40 insertions(+), 21 deletions(-) diff --git a/include/linux/sock_diag.h b/include/linux/sock_diag.h index 7c07754d711b..110978dc9af1 100644 --- a/include/linux/sock_diag.h +++ b/include/linux/sock_diag.h @@ -23,8 +23,13 @@ struct sock_diag_handler { int sock_diag_register(const struct sock_diag_handler *h); void sock_diag_unregister(const struct sock_diag_handler *h); -void sock_diag_register_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh)); -void sock_diag_unregister_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh)); +struct sock_diag_inet_compat { + struct module *owner; + int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh); +}; + +void sock_diag_register_inet_compat(const struct sock_diag_inet_compat *ptr); +void sock_diag_unregister_inet_compat(const struct sock_diag_inet_compat *ptr); u64 __sock_gen_cookie(struct sock *sk); diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c index 73b2e36032b3..d36beb9a9a92 100644 --- a/net/core/sock_diag.c +++ b/net/core/sock_diag.c @@ -17,8 +17,9 @@ #include static const struct sock_diag_handler __rcu *sock_diag_handlers[AF_MAX]; -static int (*inet_rcv_compat)(struct sk_buff *skb, struct nlmsghdr *nlh); -static DEFINE_MUTEX(sock_diag_table_mutex); + +static struct sock_diag_inet_compat __rcu *inet_rcv_compat; + static struct workqueue_struct *broadcast_wq; DEFINE_COOKIE(sock_cookie); @@ -181,19 +182,20 @@ void sock_diag_broadcast_destroy(struct sock *sk) queue_work(broadcast_wq, &bsk->work); } -void sock_diag_register_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh)) +void sock_diag_register_inet_compat(const struct sock_diag_inet_compat *ptr) { - mutex_lock(&sock_diag_table_mutex); - inet_rcv_compat = fn; - mutex_unlock(&sock_diag_table_mutex); + xchg((__force const struct sock_diag_inet_compat **)&inet_rcv_compat, + ptr); } EXPORT_SYMBOL_GPL(sock_diag_register_inet_compat); -void sock_diag_unregister_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh)) +void sock_diag_unregister_inet_compat(const struct sock_diag_inet_compat *ptr) { - mutex_lock(&sock_diag_table_mutex); - inet_rcv_compat = NULL; - mutex_unlock(&sock_diag_table_mutex); + const struct sock_diag_inet_compat *old; + + old = xchg((__force const struct sock_diag_inet_compat **)&inet_rcv_compat, + NULL); + WARN_ON_ONCE(old != ptr); } EXPORT_SYMBOL_GPL(sock_diag_unregister_inet_compat); @@ -256,20 +258,27 @@ static int __sock_diag_cmd(struct sk_buff *skb, struct nlmsghdr *nlh) static int sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack) { + const struct sock_diag_inet_compat *ptr; int ret; switch (nlh->nlmsg_type) { case TCPDIAG_GETSOCK: case DCCPDIAG_GETSOCK: - if (inet_rcv_compat == NULL) + + if (!rcu_access_pointer(inet_rcv_compat)) sock_load_diag_module(AF_INET, 0); - mutex_lock(&sock_diag_table_mutex); - if (inet_rcv_compat != NULL) - ret = inet_rcv_compat(skb, nlh); - else - ret = -EOPNOTSUPP; - mutex_unlock(&sock_diag_table_mutex); + rcu_read_lock(); + ptr = rcu_dereference(inet_rcv_compat); + if (ptr && !try_module_get(ptr->owner)) + ptr = NULL; + rcu_read_unlock(); + + ret = -EOPNOTSUPP; + if (ptr) { + ret = ptr->fn(skb, nlh); + module_put(ptr->owner); + } return ret; case SOCK_DIAG_BY_FAMILY: diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index a3d0e18885f5..2bd5d0ed7a6f 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -1445,6 +1445,11 @@ void inet_diag_unregister(const struct inet_diag_handler *h) } EXPORT_SYMBOL_GPL(inet_diag_unregister); +static const struct sock_diag_inet_compat inet_diag_compat = { + .owner = THIS_MODULE, + .fn = inet_diag_rcv_msg_compat, +}; + static int __init inet_diag_init(void) { const int inet_diag_table_size = (IPPROTO_MAX * @@ -1463,7 +1468,7 @@ static int __init inet_diag_init(void) if (err) goto out_free_inet; - sock_diag_register_inet_compat(inet_diag_rcv_msg_compat); + sock_diag_register_inet_compat(&inet_diag_compat); out: return err; @@ -1478,7 +1483,7 @@ static void __exit inet_diag_exit(void) { sock_diag_unregister(&inet6_diag_handler); sock_diag_unregister(&inet_diag_handler); - sock_diag_unregister_inet_compat(inet_diag_rcv_msg_compat); + sock_diag_unregister_inet_compat(&inet_diag_compat); kfree(inet_diag_table); } From ad3c88eb3cc53f881cbbf41d584a9451c5d0e7e4 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 4 Jun 2024 11:16:03 +0000 Subject: [PATCH 064/118] net: use unrcu_pointer() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit b4cb4a1391dcdc640c4ade003aaf0ee19cc8d509 ] Toke mentioned unrcu_pointer() existence, allowing to remove some of the ugly casts we have when using xchg() for rcu protected pointers. Also make inet_rcv_compat const. Signed-off-by: Eric Dumazet Cc: Toke Høiland-Jørgensen Reviewed-by: Toke Høiland-Jørgensen Link: https://lore.kernel.org/r/20240604111603.45871-1-edumazet@google.com Signed-off-by: Paolo Abeni Stable-dep-of: eb02688c5c45 ("ipv6: release nexthop on device removal") Signed-off-by: Sasha Levin --- include/net/sock.h | 2 +- net/core/gen_estimator.c | 2 +- net/core/sock_diag.c | 8 +++----- net/ipv4/cipso_ipv4.c | 2 +- net/ipv4/tcp.c | 2 +- net/ipv4/tcp_fastopen.c | 7 ++++--- net/ipv4/udp.c | 2 +- net/ipv6/af_inet6.c | 2 +- net/ipv6/ip6_fib.c | 2 +- net/ipv6/ipv6_sockglue.c | 3 +-- net/ipv6/route.c | 6 +++--- net/sched/act_api.c | 2 +- 12 files changed, 19 insertions(+), 21 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index 1b39b62d44e2..0a06c997b45b 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -2246,7 +2246,7 @@ sk_dst_set(struct sock *sk, struct dst_entry *dst) sk_tx_queue_clear(sk); WRITE_ONCE(sk->sk_dst_pending_confirm, 0); - old_dst = xchg((__force struct dst_entry **)&sk->sk_dst_cache, dst); + old_dst = unrcu_pointer(xchg(&sk->sk_dst_cache, RCU_INITIALIZER(dst))); dst_release(old_dst); } diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c index 4fcbdd71c59f..e0654e3a9286 100644 --- a/net/core/gen_estimator.c +++ b/net/core/gen_estimator.c @@ -206,7 +206,7 @@ void gen_kill_estimator(struct net_rate_estimator __rcu **rate_est) { struct net_rate_estimator *est; - est = xchg((__force struct net_rate_estimator **)rate_est, NULL); + est = unrcu_pointer(xchg(rate_est, NULL)); if (est) { del_timer_sync(&est->timer); kfree_rcu(est, rcu); diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c index d36beb9a9a92..17972558f54a 100644 --- a/net/core/sock_diag.c +++ b/net/core/sock_diag.c @@ -18,7 +18,7 @@ static const struct sock_diag_handler __rcu *sock_diag_handlers[AF_MAX]; -static struct sock_diag_inet_compat __rcu *inet_rcv_compat; +static const struct sock_diag_inet_compat __rcu *inet_rcv_compat; static struct workqueue_struct *broadcast_wq; @@ -184,8 +184,7 @@ void sock_diag_broadcast_destroy(struct sock *sk) void sock_diag_register_inet_compat(const struct sock_diag_inet_compat *ptr) { - xchg((__force const struct sock_diag_inet_compat **)&inet_rcv_compat, - ptr); + xchg(&inet_rcv_compat, RCU_INITIALIZER(ptr)); } EXPORT_SYMBOL_GPL(sock_diag_register_inet_compat); @@ -193,8 +192,7 @@ void sock_diag_unregister_inet_compat(const struct sock_diag_inet_compat *ptr) { const struct sock_diag_inet_compat *old; - old = xchg((__force const struct sock_diag_inet_compat **)&inet_rcv_compat, - NULL); + old = unrcu_pointer(xchg(&inet_rcv_compat, NULL)); WARN_ON_ONCE(old != ptr); } EXPORT_SYMBOL_GPL(sock_diag_unregister_inet_compat); diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 2b56cabe4da9..fd139daf9dfb 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -1955,7 +1955,7 @@ int cipso_v4_req_setattr(struct request_sock *req, buf = NULL; req_inet = inet_rsk(req); - opt = xchg((__force struct ip_options_rcu **)&req_inet->ireq_opt, opt); + opt = unrcu_pointer(xchg(&req_inet->ireq_opt, RCU_INITIALIZER(opt))); if (opt) kfree_rcu(opt, rcu); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index cb79919323a6..e27a9a9bb162 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -3184,7 +3184,7 @@ int tcp_disconnect(struct sock *sk, int flags) icsk->icsk_ack.rcv_mss = TCP_MIN_MSS; memset(&tp->rx_opt, 0, sizeof(tp->rx_opt)); __sk_dst_reset(sk); - dst_release(xchg((__force struct dst_entry **)&sk->sk_rx_dst, NULL)); + dst_release(unrcu_pointer(xchg(&sk->sk_rx_dst, NULL))); tcp_saved_syn_free(tp); tp->compressed_ack = 0; tp->segs_in = 0; diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c index 85e4953f1182..d0b7ded591bd 100644 --- a/net/ipv4/tcp_fastopen.c +++ b/net/ipv4/tcp_fastopen.c @@ -49,7 +49,7 @@ void tcp_fastopen_ctx_destroy(struct net *net) { struct tcp_fastopen_context *ctxt; - ctxt = xchg((__force struct tcp_fastopen_context **)&net->ipv4.tcp_fastopen_ctx, NULL); + ctxt = unrcu_pointer(xchg(&net->ipv4.tcp_fastopen_ctx, NULL)); if (ctxt) call_rcu(&ctxt->rcu, tcp_fastopen_ctx_free); @@ -80,9 +80,10 @@ int tcp_fastopen_reset_cipher(struct net *net, struct sock *sk, if (sk) { q = &inet_csk(sk)->icsk_accept_queue.fastopenq; - octx = xchg((__force struct tcp_fastopen_context **)&q->ctx, ctx); + octx = unrcu_pointer(xchg(&q->ctx, RCU_INITIALIZER(ctx))); } else { - octx = xchg((__force struct tcp_fastopen_context **)&net->ipv4.tcp_fastopen_ctx, ctx); + octx = unrcu_pointer(xchg(&net->ipv4.tcp_fastopen_ctx, + RCU_INITIALIZER(ctx))); } if (octx) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 53267566808c..3f9c4b74fdc0 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -2252,7 +2252,7 @@ bool udp_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst) struct dst_entry *old; if (dst_hold_safe(dst)) { - old = xchg((__force struct dst_entry **)&sk->sk_rx_dst, dst); + old = unrcu_pointer(xchg(&sk->sk_rx_dst, RCU_INITIALIZER(dst))); dst_release(old); return old != dst; } diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 62247621cea5..ea16c40cfb21 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -513,7 +513,7 @@ void inet6_destroy_sock(struct sock *sk) /* Free tx options */ - opt = xchg((__force struct ipv6_txoptions **)&np->opt, NULL); + opt = unrcu_pointer(xchg(&np->opt, NULL)); if (opt) { atomic_sub(opt->tot_len, &sk->sk_omem_alloc); txopt_put(opt); diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 1123594ad2be..0b45ef8b7ee2 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -983,7 +983,7 @@ static void __fib6_drop_pcpu_from(struct fib6_nh *fib6_nh, if (pcpu_rt && rcu_access_pointer(pcpu_rt->from) == match) { struct fib6_info *from; - from = xchg((__force struct fib6_info **)&pcpu_rt->from, NULL); + from = unrcu_pointer(xchg(&pcpu_rt->from, NULL)); fib6_info_release(from); } } diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 532f4478c884..2924aa45adbc 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -111,8 +111,7 @@ struct ipv6_txoptions *ipv6_update_options(struct sock *sk, icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie); } } - opt = xchg((__force struct ipv6_txoptions **)&inet6_sk(sk)->opt, - opt); + opt = unrcu_pointer(xchg(&inet6_sk(sk)->opt, RCU_INITIALIZER(opt))); sk_dst_reset(sk); return opt; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 6a227edf8a8a..10e7517d126d 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -369,7 +369,7 @@ static void ip6_dst_destroy(struct dst_entry *dst) in6_dev_put(idev); } - from = xchg((__force struct fib6_info **)&rt->from, NULL); + from = unrcu_pointer(xchg(&rt->from, NULL)); fib6_info_release(from); } @@ -1432,7 +1432,7 @@ static struct rt6_info *rt6_make_pcpu_route(struct net *net, if (res->f6i->fib6_destroying) { struct fib6_info *from; - from = xchg((__force struct fib6_info **)&pcpu_rt->from, NULL); + from = unrcu_pointer(xchg(&pcpu_rt->from, NULL)); fib6_info_release(from); } @@ -1461,7 +1461,7 @@ static void rt6_remove_exception(struct rt6_exception_bucket *bucket, /* purge completely the exception to allow releasing the held resources: * some [sk] cache may keep the dst around for unlimited time */ - from = xchg((__force struct fib6_info **)&rt6_ex->rt6i->from, NULL); + from = unrcu_pointer(xchg(&rt6_ex->rt6i->from, NULL)); fib6_info_release(from); dst_dev_put(&rt6_ex->rt6i->dst); diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 05bd1e9bca36..b75e22756c4b 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -61,7 +61,7 @@ static void tcf_set_action_cookie(struct tc_cookie __rcu **old_cookie, { struct tc_cookie *old; - old = xchg((__force struct tc_cookie **)old_cookie, new_cookie); + old = unrcu_pointer(xchg(old_cookie, RCU_INITIALIZER(new_cookie))); if (old) call_rcu(&old->rcu, tcf_free_cookie_rcu); } From b2f26a27ea3f72f75d18330f76f5d1007c791848 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Tue, 5 Nov 2024 19:23:50 +0100 Subject: [PATCH 065/118] ipv6: release nexthop on device removal [ Upstream commit eb02688c5c45c3e7af7e71f036a7144f5639cbfe ] The CI is hitting some aperiodic hangup at device removal time in the pmtu.sh self-test: unregister_netdevice: waiting for veth_A-R1 to become free. Usage count = 6 ref_tracker: veth_A-R1@ffff888013df15d8 has 1/5 users at dst_init+0x84/0x4a0 dst_alloc+0x97/0x150 ip6_dst_alloc+0x23/0x90 ip6_rt_pcpu_alloc+0x1e6/0x520 ip6_pol_route+0x56f/0x840 fib6_rule_lookup+0x334/0x630 ip6_route_output_flags+0x259/0x480 ip6_dst_lookup_tail.constprop.0+0x5c2/0x940 ip6_dst_lookup_flow+0x88/0x190 udp_tunnel6_dst_lookup+0x2a7/0x4c0 vxlan_xmit_one+0xbde/0x4a50 [vxlan] vxlan_xmit+0x9ad/0xf20 [vxlan] dev_hard_start_xmit+0x10e/0x360 __dev_queue_xmit+0xf95/0x18c0 arp_solicit+0x4a2/0xe00 neigh_probe+0xaa/0xf0 While the first suspect is the dst_cache, explicitly tracking the dst owing the last device reference via probes proved such dst is held by the nexthop in the originating fib6_info. Similar to commit f5b51fe804ec ("ipv6: route: purge exception on removal"), we need to explicitly release the originating fib info when disconnecting a to-be-removed device from a live ipv6 dst: move the fib6_info cleanup into ip6_dst_ifdown(). Tested running: ./pmtu.sh cleanup_ipv6_exception in a tight loop for more than 400 iterations with no spat, running an unpatched kernel I observed a splat every ~10 iterations. Fixes: f88d8ea67fbd ("ipv6: Plumb support for nexthop object in a fib6_info") Signed-off-by: Paolo Abeni Reviewed-by: Eric Dumazet Reviewed-by: David Ahern Link: https://patch.msgid.link/604c45c188c609b732286b47ac2a451a40f6cf6d.1730828007.git.pabeni@redhat.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/ipv6/route.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 10e7517d126d..5da0c83a3ee8 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -378,6 +378,7 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, { struct rt6_info *rt = (struct rt6_info *)dst; struct inet6_dev *idev = rt->rt6i_idev; + struct fib6_info *from; if (idev && idev->dev != blackhole_netdev) { struct inet6_dev *blackhole_idev = in6_dev_get(blackhole_netdev); @@ -387,6 +388,8 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, in6_dev_put(idev); } } + from = unrcu_pointer(xchg(&rt->from, NULL)); + fib6_info_release(from); } static bool __rt6_check_expired(const struct rt6_info *rt) @@ -1449,7 +1452,6 @@ static DEFINE_SPINLOCK(rt6_exception_lock); static void rt6_remove_exception(struct rt6_exception_bucket *bucket, struct rt6_exception *rt6_ex) { - struct fib6_info *from; struct net *net; if (!bucket || !rt6_ex) @@ -1461,8 +1463,6 @@ static void rt6_remove_exception(struct rt6_exception_bucket *bucket, /* purge completely the exception to allow releasing the held resources: * some [sk] cache may keep the dst around for unlimited time */ - from = unrcu_pointer(xchg(&rt6_ex->rt6i->from, NULL)); - fib6_info_release(from); dst_dev_put(&rt6_ex->rt6i->dst); hlist_del_rcu(&rt6_ex->hlist); From e636d87d12e9401d43d8e5ba739940b870b2c96c Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Tue, 5 Nov 2024 19:23:51 +0100 Subject: [PATCH 066/118] selftests: net: really check for bg process completion [ Upstream commit 52ed077aa6336dbef83a2d6d21c52d1706fb7f16 ] A recent refactor transformed the check for process completion in a true statement, due to a typo. As a result, the relevant test-case is unable to catch the regression it was supposed to detect. Restore the correct condition. Fixes: 691bb4e49c98 ("selftests: net: avoid just another constant wait") Signed-off-by: Paolo Abeni Reviewed-by: David Ahern Link: https://patch.msgid.link/0e6f213811f8e93a235307e683af8225cc6277ae.1730828007.git.pabeni@redhat.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- tools/testing/selftests/net/pmtu.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index 00ab4c6e4044..dbfa56173d29 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -1932,7 +1932,7 @@ check_running() { pid=${1} cmd=${2} - [ "$(cat /proc/${pid}/cmdline 2>/dev/null | tr -d '\0')" = "{cmd}" ] + [ "$(cat /proc/${pid}/cmdline 2>/dev/null | tr -d '\0')" = "${cmd}" ] } test_cleanup_vxlanX_exception() { From c01c0b270d474c6f9d94f037eda23e6519b711cb Mon Sep 17 00:00:00 2001 From: Yuan Can Date: Wed, 6 Nov 2024 09:35:41 +0800 Subject: [PATCH 067/118] drm/amdkfd: Fix wrong usage of INIT_WORK() [ Upstream commit 21cae8debc6a1d243f64fa82cd1b41cb612b5c61 ] In kfd_procfs_show(), the sdma_activity_work_handler is a local variable and the sdma_activity_work_handler.sdma_activity_work should initialize with INIT_WORK_ONSTACK() instead of INIT_WORK(). Fixes: 32cb59f31362 ("drm/amdkfd: Track SDMA utilization per process") Signed-off-by: Yuan Can Signed-off-by: Felix Kuehling Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher Signed-off-by: Sasha Levin --- drivers/gpu/drm/amd/amdkfd/kfd_process.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index 9582c9449fff..99e2aef52ef2 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -314,8 +314,8 @@ static ssize_t kfd_procfs_show(struct kobject *kobj, struct attribute *attr, attr_sdma); struct kfd_sdma_activity_handler_workarea sdma_activity_work_handler; - INIT_WORK(&sdma_activity_work_handler.sdma_activity_work, - kfd_sdma_activity_worker); + INIT_WORK_ONSTACK(&sdma_activity_work_handler.sdma_activity_work, + kfd_sdma_activity_worker); sdma_activity_work_handler.pdd = pdd; sdma_activity_work_handler.sdma_activity_counter = 0; @@ -323,6 +323,7 @@ static ssize_t kfd_procfs_show(struct kobject *kobj, struct attribute *attr, schedule_work(&sdma_activity_work_handler.sdma_activity_work); flush_work(&sdma_activity_work_handler.sdma_activity_work); + destroy_work_on_stack(&sdma_activity_work_handler.sdma_activity_work); return snprintf(buffer, PAGE_SIZE, "%llu\n", (sdma_activity_work_handler.sdma_activity_counter)/ From f61b836ce94fc5642073cfa3f2e07b822a0ef641 Mon Sep 17 00:00:00 2001 From: Mingwei Zheng Date: Fri, 8 Nov 2024 14:53:41 -0500 Subject: [PATCH 068/118] net: rfkill: gpio: Add check for clk_enable() [ Upstream commit 8251e7621b25ccdb689f1dd9553b8789e3745ea1 ] Add check for the return value of clk_enable() to catch the potential error. Fixes: 7176ba23f8b5 ("net: rfkill: add generic gpio rfkill driver") Signed-off-by: Mingwei Zheng Signed-off-by: Jiasheng Jiang Link: https://patch.msgid.link/20241108195341.1853080-1-zmw12306@gmail.com Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- net/rfkill/rfkill-gpio.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c index f74baefd855d..2df5bf240b64 100644 --- a/net/rfkill/rfkill-gpio.c +++ b/net/rfkill/rfkill-gpio.c @@ -30,8 +30,12 @@ static int rfkill_gpio_set_power(void *data, bool blocked) { struct rfkill_gpio_data *rfkill = data; - if (!blocked && !IS_ERR(rfkill->clk) && !rfkill->clk_enabled) - clk_enable(rfkill->clk); + if (!blocked && !IS_ERR(rfkill->clk) && !rfkill->clk_enabled) { + int ret = clk_enable(rfkill->clk); + + if (ret) + return ret; + } gpiod_set_value_cansleep(rfkill->shutdown_gpio, !blocked); gpiod_set_value_cansleep(rfkill->reset_gpio, !blocked); From 7bd8838c0ea886679a32834fdcacab296d072fbe Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 13 Nov 2024 12:10:35 +0100 Subject: [PATCH 069/118] ALSA: usx2y: Use snd_card_free_when_closed() at disconnection [ Upstream commit dafb28f02be407e07a6f679e922a626592b481b0 ] The USB disconnect callback is supposed to be short and not too-long waiting. OTOH, the current code uses snd_card_free() at disconnection, but this waits for the close of all used fds, hence it can take long. It eventually blocks the upper layer USB ioctls, which may trigger a soft lockup. An easy workaround is to replace snd_card_free() with snd_card_free_when_closed(). This variant returns immediately while the release of resources is done asynchronously by the card device release at the last close. Fixes: 230cd5e24853 ("[ALSA] prevent oops & dead keyboard on usb unplugging while the device is be ing used") Reported-by: syzbot+73582d08864d8268b6fd@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=73582d08864d8268b6fd Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20241113111042.15058-2-tiwai@suse.de Signed-off-by: Sasha Levin --- sound/usb/usx2y/usbusx2y.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index 52f4e6652407..4c4ce0319d62 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -423,7 +423,7 @@ static void snd_usx2y_disconnect(struct usb_interface *intf) } if (usx2y->us428ctls_sharedmem) wake_up(&usx2y->us428ctls_wait_queue_head); - snd_card_free(card); + snd_card_free_when_closed(card); } static int snd_usx2y_probe(struct usb_interface *intf, From bc778ad3e495333eebda36fe91d5b2c93109cc16 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 13 Nov 2024 12:10:36 +0100 Subject: [PATCH 070/118] ALSA: us122l: Use snd_card_free_when_closed() at disconnection [ Upstream commit b7df09bb348016943f56b09dcaafe221e3f73947 ] The USB disconnect callback is supposed to be short and not too-long waiting. OTOH, the current code uses snd_card_free() at disconnection, but this waits for the close of all used fds, hence it can take long. It eventually blocks the upper layer USB ioctls, which may trigger a soft lockup. An easy workaround is to replace snd_card_free() with snd_card_free_when_closed(). This variant returns immediately while the release of resources is done asynchronously by the card device release at the last close. The loop of us122l->mmap_count check is dropped as well. The check is useless for the asynchronous operation with *_when_closed(). Fixes: 030a07e44129 ("ALSA: Add USB US122L driver") Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20241113111042.15058-3-tiwai@suse.de Signed-off-by: Sasha Levin --- sound/usb/usx2y/us122l.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index e558931cce16..23d7d542a3de 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c @@ -617,10 +617,7 @@ static void snd_us122l_disconnect(struct usb_interface *intf) usb_put_intf(usb_ifnum_to_if(us122l->dev, 1)); usb_put_dev(us122l->dev); - while (atomic_read(&us122l->mmap_count)) - msleep(500); - - snd_card_free(card); + snd_card_free_when_closed(card); } static int snd_us122l_suspend(struct usb_interface *intf, pm_message_t message) From 237f3faf0177bdde728fa3106d730d806436aa4d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 13 Nov 2024 12:10:38 +0100 Subject: [PATCH 071/118] ALSA: caiaq: Use snd_card_free_when_closed() at disconnection [ Upstream commit b04dcbb7f7b1908806b7dc22671cdbe78ff2b82c ] The USB disconnect callback is supposed to be short and not too-long waiting. OTOH, the current code uses snd_card_free() at disconnection, but this waits for the close of all used fds, hence it can take long. It eventually blocks the upper layer USB ioctls, which may trigger a soft lockup. An easy workaround is to replace snd_card_free() with snd_card_free_when_closed(). This variant returns immediately while the release of resources is done asynchronously by the card device release at the last close. This patch also splits the code to the disconnect and the free phases; the former is called immediately at the USB disconnect callback while the latter is called from the card destructor. Fixes: 523f1dce3743 ("[ALSA] Add Native Instrument usb audio device support") Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20241113111042.15058-5-tiwai@suse.de Signed-off-by: Sasha Levin --- sound/usb/caiaq/audio.c | 10 ++++++++-- sound/usb/caiaq/audio.h | 1 + sound/usb/caiaq/device.c | 19 +++++++++++++++---- sound/usb/caiaq/input.c | 12 +++++++++--- sound/usb/caiaq/input.h | 1 + 5 files changed, 34 insertions(+), 9 deletions(-) diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c index 4981753652a7..7a89872aa0cb 100644 --- a/sound/usb/caiaq/audio.c +++ b/sound/usb/caiaq/audio.c @@ -869,14 +869,20 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev) return 0; } -void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *cdev) +void snd_usb_caiaq_audio_disconnect(struct snd_usb_caiaqdev *cdev) { struct device *dev = caiaqdev_to_dev(cdev); dev_dbg(dev, "%s(%p)\n", __func__, cdev); stream_stop(cdev); +} + +void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *cdev) +{ + struct device *dev = caiaqdev_to_dev(cdev); + + dev_dbg(dev, "%s(%p)\n", __func__, cdev); free_urbs(cdev->data_urbs_in); free_urbs(cdev->data_urbs_out); kfree(cdev->data_cb_info); } - diff --git a/sound/usb/caiaq/audio.h b/sound/usb/caiaq/audio.h index 869bf6264d6a..07f5d064456c 100644 --- a/sound/usb/caiaq/audio.h +++ b/sound/usb/caiaq/audio.h @@ -3,6 +3,7 @@ #define CAIAQ_AUDIO_H int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev); +void snd_usb_caiaq_audio_disconnect(struct snd_usb_caiaqdev *cdev); void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *cdev); #endif /* CAIAQ_AUDIO_H */ diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c index 49f63f878e6f..d5c01d3f126e 100644 --- a/sound/usb/caiaq/device.c +++ b/sound/usb/caiaq/device.c @@ -376,6 +376,17 @@ static void setup_card(struct snd_usb_caiaqdev *cdev) dev_err(dev, "Unable to set up control system (ret=%d)\n", ret); } +static void card_free(struct snd_card *card) +{ + struct snd_usb_caiaqdev *cdev = caiaqdev(card); + +#ifdef CONFIG_SND_USB_CAIAQ_INPUT + snd_usb_caiaq_input_free(cdev); +#endif + snd_usb_caiaq_audio_free(cdev); + usb_reset_device(cdev->chip.dev); +} + static int create_card(struct usb_device *usb_dev, struct usb_interface *intf, struct snd_card **cardp) @@ -489,6 +500,7 @@ static int init_card(struct snd_usb_caiaqdev *cdev) cdev->vendor_name, cdev->product_name, usbpath); setup_card(cdev); + card->private_free = card_free; return 0; err_kill_urb: @@ -534,15 +546,14 @@ static void snd_disconnect(struct usb_interface *intf) snd_card_disconnect(card); #ifdef CONFIG_SND_USB_CAIAQ_INPUT - snd_usb_caiaq_input_free(cdev); + snd_usb_caiaq_input_disconnect(cdev); #endif - snd_usb_caiaq_audio_free(cdev); + snd_usb_caiaq_audio_disconnect(cdev); usb_kill_urb(&cdev->ep1_in_urb); usb_kill_urb(&cdev->midi_out_urb); - snd_card_free(card); - usb_reset_device(interface_to_usbdev(intf)); + snd_card_free_when_closed(card); } diff --git a/sound/usb/caiaq/input.c b/sound/usb/caiaq/input.c index 84f26dce7f5d..a9130891bb69 100644 --- a/sound/usb/caiaq/input.c +++ b/sound/usb/caiaq/input.c @@ -829,15 +829,21 @@ exit_free_idev: return ret; } -void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *cdev) +void snd_usb_caiaq_input_disconnect(struct snd_usb_caiaqdev *cdev) { if (!cdev || !cdev->input_dev) return; usb_kill_urb(cdev->ep4_in_urb); + input_unregister_device(cdev->input_dev); +} + +void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *cdev) +{ + if (!cdev || !cdev->input_dev) + return; + usb_free_urb(cdev->ep4_in_urb); cdev->ep4_in_urb = NULL; - - input_unregister_device(cdev->input_dev); cdev->input_dev = NULL; } diff --git a/sound/usb/caiaq/input.h b/sound/usb/caiaq/input.h index c42891e7be88..fbe267f85d02 100644 --- a/sound/usb/caiaq/input.h +++ b/sound/usb/caiaq/input.h @@ -4,6 +4,7 @@ void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *cdev, char *buf, unsigned int len); int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *cdev); +void snd_usb_caiaq_input_disconnect(struct snd_usb_caiaqdev *cdev); void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *cdev); #endif From ea8cc56db659cf0ae57073e32a4735ead7bd7ee3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 13 Nov 2024 12:10:39 +0100 Subject: [PATCH 072/118] ALSA: 6fire: Release resources at card release [ Upstream commit a0810c3d6dd2d29a9b92604d682eacd2902ce947 ] The current 6fire code tries to release the resources right after the call of usb6fire_chip_abort(). But at this moment, the card object might be still in use (as we're calling snd_card_free_when_closed()). For avoid potential UAFs, move the release of resources to the card's private_free instead of the manual call of usb6fire_chip_destroy() at the USB disconnect callback. Fixes: c6d43ba816d1 ("ALSA: usb/6fire - Driver for TerraTec DMX 6Fire USB") Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/20241113111042.15058-6-tiwai@suse.de Signed-off-by: Sasha Levin --- sound/usb/6fire/chip.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/usb/6fire/chip.c b/sound/usb/6fire/chip.c index 33e962178c93..d562a30b087f 100644 --- a/sound/usb/6fire/chip.c +++ b/sound/usb/6fire/chip.c @@ -61,8 +61,10 @@ static void usb6fire_chip_abort(struct sfire_chip *chip) } } -static void usb6fire_chip_destroy(struct sfire_chip *chip) +static void usb6fire_card_free(struct snd_card *card) { + struct sfire_chip *chip = card->private_data; + if (chip) { if (chip->pcm) usb6fire_pcm_destroy(chip); @@ -72,8 +74,6 @@ static void usb6fire_chip_destroy(struct sfire_chip *chip) usb6fire_comm_destroy(chip); if (chip->control) usb6fire_control_destroy(chip); - if (chip->card) - snd_card_free(chip->card); } } @@ -136,6 +136,7 @@ static int usb6fire_chip_probe(struct usb_interface *intf, chip->regidx = regidx; chip->intf_count = 1; chip->card = card; + card->private_free = usb6fire_card_free; ret = usb6fire_comm_init(chip); if (ret < 0) @@ -162,7 +163,7 @@ static int usb6fire_chip_probe(struct usb_interface *intf, return 0; destroy_chip: - usb6fire_chip_destroy(chip); + snd_card_free(card); return ret; } @@ -181,7 +182,6 @@ static void usb6fire_chip_disconnect(struct usb_interface *intf) chip->shutdown = true; usb6fire_chip_abort(chip); - usb6fire_chip_destroy(chip); } } } From 0f67ca2a80acf8b207240405b7f72d660665d3df Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Fri, 1 Nov 2024 14:44:10 +0300 Subject: [PATCH 073/118] Bluetooth: fix use-after-free in device_for_each_child() [ Upstream commit 27aabf27fd014ae037cc179c61b0bee7cff55b3d ] Syzbot has reported the following KASAN splat: BUG: KASAN: slab-use-after-free in device_for_each_child+0x18f/0x1a0 Read of size 8 at addr ffff88801f605308 by task kbnepd bnep0/4980 CPU: 0 UID: 0 PID: 4980 Comm: kbnepd bnep0 Not tainted 6.12.0-rc4-00161-gae90f6a6170d #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-2.fc40 04/01/2014 Call Trace: dump_stack_lvl+0x100/0x190 ? device_for_each_child+0x18f/0x1a0 print_report+0x13a/0x4cb ? __virt_addr_valid+0x5e/0x590 ? __phys_addr+0xc6/0x150 ? device_for_each_child+0x18f/0x1a0 kasan_report+0xda/0x110 ? device_for_each_child+0x18f/0x1a0 ? __pfx_dev_memalloc_noio+0x10/0x10 device_for_each_child+0x18f/0x1a0 ? __pfx_device_for_each_child+0x10/0x10 pm_runtime_set_memalloc_noio+0xf2/0x180 netdev_unregister_kobject+0x1ed/0x270 unregister_netdevice_many_notify+0x123c/0x1d80 ? __mutex_trylock_common+0xde/0x250 ? __pfx_unregister_netdevice_many_notify+0x10/0x10 ? trace_contention_end+0xe6/0x140 ? __mutex_lock+0x4e7/0x8f0 ? __pfx_lock_acquire.part.0+0x10/0x10 ? rcu_is_watching+0x12/0xc0 ? unregister_netdev+0x12/0x30 unregister_netdevice_queue+0x30d/0x3f0 ? __pfx_unregister_netdevice_queue+0x10/0x10 ? __pfx_down_write+0x10/0x10 unregister_netdev+0x1c/0x30 bnep_session+0x1fb3/0x2ab0 ? __pfx_bnep_session+0x10/0x10 ? __pfx_lock_release+0x10/0x10 ? __pfx_woken_wake_function+0x10/0x10 ? __kthread_parkme+0x132/0x200 ? __pfx_bnep_session+0x10/0x10 ? kthread+0x13a/0x370 ? __pfx_bnep_session+0x10/0x10 kthread+0x2b7/0x370 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x48/0x80 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 Allocated by task 4974: kasan_save_stack+0x30/0x50 kasan_save_track+0x14/0x30 __kasan_kmalloc+0xaa/0xb0 __kmalloc_noprof+0x1d1/0x440 hci_alloc_dev_priv+0x1d/0x2820 __vhci_create_device+0xef/0x7d0 vhci_write+0x2c7/0x480 vfs_write+0x6a0/0xfc0 ksys_write+0x12f/0x260 do_syscall_64+0xc7/0x250 entry_SYSCALL_64_after_hwframe+0x77/0x7f Freed by task 4979: kasan_save_stack+0x30/0x50 kasan_save_track+0x14/0x30 kasan_save_free_info+0x3b/0x60 __kasan_slab_free+0x4f/0x70 kfree+0x141/0x490 hci_release_dev+0x4d9/0x600 bt_host_release+0x6a/0xb0 device_release+0xa4/0x240 kobject_put+0x1ec/0x5a0 put_device+0x1f/0x30 vhci_release+0x81/0xf0 __fput+0x3f6/0xb30 task_work_run+0x151/0x250 do_exit+0xa79/0x2c30 do_group_exit+0xd5/0x2a0 get_signal+0x1fcd/0x2210 arch_do_signal_or_restart+0x93/0x780 syscall_exit_to_user_mode+0x140/0x290 do_syscall_64+0xd4/0x250 entry_SYSCALL_64_after_hwframe+0x77/0x7f In 'hci_conn_del_sysfs()', 'device_unregister()' may be called when an underlying (kobject) reference counter is greater than 1. This means that reparenting (happened when the device is actually freed) is delayed and, during that delay, parent controller device (hciX) may be deleted. Since the latter may create a dangling pointer to freed parent, avoid that scenario by reparenting to NULL explicitly. Reported-by: syzbot+6cf5652d3df49fae2e3f@syzkaller.appspotmail.com Tested-by: syzbot+6cf5652d3df49fae2e3f@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=6cf5652d3df49fae2e3f Fixes: a85fb91e3d72 ("Bluetooth: Fix double free in hci_conn_cleanup") Signed-off-by: Dmitry Antipov Signed-off-by: Luiz Augusto von Dentz Signed-off-by: Sasha Levin --- net/bluetooth/hci_sysfs.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 633b82d54272..cc7d4a8ed8ce 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -19,16 +19,6 @@ static const struct device_type bt_link = { .release = bt_link_release, }; -/* - * The rfcomm tty device will possibly retain even when conn - * is down, and sysfs doesn't support move zombie device, - * so we should move the device before conn device is destroyed. - */ -static int __match_tty(struct device *dev, void *data) -{ - return !strncmp(dev_name(dev), "rfcomm", 6); -} - void hci_conn_init_sysfs(struct hci_conn *conn) { struct hci_dev *hdev = conn->hdev; @@ -71,10 +61,13 @@ void hci_conn_del_sysfs(struct hci_conn *conn) return; } + /* If there are devices using the connection as parent reset it to NULL + * before unregistering the device. + */ while (1) { struct device *dev; - dev = device_find_child(&conn->dev, NULL, __match_tty); + dev = device_find_any_child(&conn->dev); if (!dev) break; device_move(dev, NULL, DPM_ORDER_DEV_LAST); From 7cd5b42796d363538e1ca808621f38b4048bb1a3 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Mon, 18 Nov 2024 03:15:18 -0800 Subject: [PATCH 074/118] netpoll: Use rcu_access_pointer() in netpoll_poll_lock [ Upstream commit a57d5a72f8dec7db8a79d0016fb0a3bdecc82b56 ] The ndev->npinfo pointer in netpoll_poll_lock() is RCU-protected but is being accessed directly for a NULL check. While no RCU read lock is held in this context, we should still use proper RCU primitives for consistency and correctness. Replace the direct NULL check with rcu_access_pointer(), which is the appropriate primitive when only checking for NULL without dereferencing the pointer. This function provides the necessary ordering guarantees without requiring RCU read-side protection. Fixes: bea3348eef27 ("[NET]: Make NAPI polling independent of struct net_device objects.") Signed-off-by: Breno Leitao Reviewed-by: Michal Kubiak Link: https://patch.msgid.link/20241118-netpoll_rcu-v1-2-a1888dcb4a02@debian.org Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- include/linux/netpoll.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index bd19c4b91e31..3ddf205b7e2c 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h @@ -71,7 +71,7 @@ static inline void *netpoll_poll_lock(struct napi_struct *napi) { struct net_device *dev = napi->dev; - if (dev && dev->npinfo) { + if (dev && rcu_access_pointer(dev->npinfo)) { int owner = smp_processor_id(); while (cmpxchg(&napi->poll_owner, -1, owner) != -1) From a628d40d2866482a17cd5029fae92db011e68e9f Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Sun, 17 Nov 2024 22:20:29 +0100 Subject: [PATCH 075/118] wireguard: selftests: load nf_conntrack if not present [ Upstream commit 0290abc9860917f1ee8b58309c2bbd740a39ee8e ] Some distros may not load nf_conntrack by default, which will cause subsequent nf_conntrack sets to fail. Load this module if it is not already loaded. Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") Signed-off-by: Hangbin Liu Reviewed-by: Simon Horman [ Jason: add [[ -e ... ]] check so this works in the qemu harness. ] Signed-off-by: Jason A. Donenfeld Link: https://patch.msgid.link/20241117212030.629159-4-Jason@zx2c4.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- tools/testing/selftests/wireguard/netns.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/wireguard/netns.sh b/tools/testing/selftests/wireguard/netns.sh index 405ff262ca93..55500f901fbc 100755 --- a/tools/testing/selftests/wireguard/netns.sh +++ b/tools/testing/selftests/wireguard/netns.sh @@ -332,6 +332,7 @@ waitiface $netns1 vethc waitiface $netns2 veths n0 bash -c 'printf 1 > /proc/sys/net/ipv4/ip_forward' +[[ -e /proc/sys/net/netfilter/nf_conntrack_udp_timeout ]] || modprobe nf_conntrack n0 bash -c 'printf 2 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout' n0 bash -c 'printf 2 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout_stream' n0 iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 10.0.0.0/24 -j SNAT --to 10.0.0.1 From 386efa339e08563dd33e83bc951aea5d407fe578 Mon Sep 17 00:00:00 2001 From: Jiayuan Chen Date: Mon, 18 Nov 2024 11:09:09 +0800 Subject: [PATCH 076/118] bpf: fix recursive lock when verdict program return SK_PASS [ Upstream commit 8ca2a1eeadf09862190b2810697702d803ceef2d ] When the stream_verdict program returns SK_PASS, it places the received skb into its own receive queue, but a recursive lock eventually occurs, leading to an operating system deadlock. This issue has been present since v6.9. ''' sk_psock_strp_data_ready write_lock_bh(&sk->sk_callback_lock) strp_data_ready strp_read_sock read_sock -> tcp_read_sock strp_recv cb.rcv_msg -> sk_psock_strp_read # now stream_verdict return SK_PASS without peer sock assign __SK_PASS = sk_psock_map_verd(SK_PASS, NULL) sk_psock_verdict_apply sk_psock_skb_ingress_self sk_psock_skb_ingress_enqueue sk_psock_data_ready read_lock_bh(&sk->sk_callback_lock) <= dead lock ''' This topic has been discussed before, but it has not been fixed. Previous discussion: https://lore.kernel.org/all/6684a5864ec86_403d20898@john.notmuch Fixes: 6648e613226e ("bpf, skmsg: Fix NULL pointer dereference in sk_psock_skb_ingress_enqueue") Reported-by: Vincent Whitchurch Signed-off-by: Jiayuan Chen Signed-off-by: John Fastabend Acked-by: Martin KaFai Lau Link: https://patch.msgid.link/20241118030910.36230-2-mrpre@163.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/core/skmsg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/core/skmsg.c b/net/core/skmsg.c index 746d950de0e1..584516387fda 100644 --- a/net/core/skmsg.c +++ b/net/core/skmsg.c @@ -1114,9 +1114,9 @@ static void sk_psock_strp_data_ready(struct sock *sk) if (tls_sw_has_ctx_rx(sk)) { psock->saved_data_ready(sk); } else { - write_lock_bh(&sk->sk_callback_lock); + read_lock_bh(&sk->sk_callback_lock); strp_data_ready(&psock->strp); - write_unlock_bh(&sk->sk_callback_lock); + read_unlock_bh(&sk->sk_callback_lock); } } rcu_read_unlock(); From 4387cef540f36c2c9297460758cc2438305a24a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Almeida?= Date: Mon, 2 Sep 2024 19:55:03 -0300 Subject: [PATCH 077/118] unicode: Fix utf8_load() error path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 156bb2c569cd869583c593d27a5bd69e7b2a4264 ] utf8_load() requests the symbol "utf8_data_table" and then checks if the requested UTF-8 version is supported. If it's unsupported, it tries to put the data table using symbol_put(). If an unsupported version is requested, symbol_put() fails like this: kernel BUG at kernel/module/main.c:786! RIP: 0010:__symbol_put+0x93/0xb0 Call Trace: ? __die_body.cold+0x19/0x27 ? die+0x2e/0x50 ? do_trap+0xca/0x110 ? do_error_trap+0x65/0x80 ? __symbol_put+0x93/0xb0 ? exc_invalid_op+0x51/0x70 ? __symbol_put+0x93/0xb0 ? asm_exc_invalid_op+0x1a/0x20 ? __pfx_cmp_name+0x10/0x10 ? __symbol_put+0x93/0xb0 ? __symbol_put+0x62/0xb0 utf8_load+0xf8/0x150 That happens because symbol_put() expects the unique string that identify the symbol, instead of a pointer to the loaded symbol. Fix that by using such string. Fixes: 2b3d04787012 ("unicode: Add utf8-data module") Signed-off-by: André Almeida Reviewed-by: Theodore Ts'o Link: https://lore.kernel.org/r/20240902225511.757831-2-andrealmeid@igalia.com Signed-off-by: Gabriel Krisman Bertazi Signed-off-by: Sasha Levin --- fs/unicode/utf8-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/unicode/utf8-core.c b/fs/unicode/utf8-core.c index 67aaadc3ab07..c887edc4f527 100644 --- a/fs/unicode/utf8-core.c +++ b/fs/unicode/utf8-core.c @@ -198,7 +198,7 @@ struct unicode_map *utf8_load(unsigned int version) return um; out_symbol_put: - symbol_put(um->tables); + symbol_put(utf8_data_table); out_free_um: kfree(um); return ERR_PTR(-EINVAL); From cc344fdd0e6803e4b5bebe474bc78abab478693d Mon Sep 17 00:00:00 2001 From: Levi Yun Date: Fri, 13 Sep 2024 03:13:47 +0100 Subject: [PATCH 078/118] trace/trace_event_perf: remove duplicate samples on the first tracepoint event [ Upstream commit afe5960dc208fe069ddaaeb0994d857b24ac19d1 ] When a tracepoint event is created with attr.freq = 1, 'hwc->period_left' is not initialized correctly. As a result, in the perf_swevent_overflow() function, when the first time the event occurs, it calculates the event overflow and the perf_swevent_set_period() returns 3, this leads to the event are recorded for three duplicate times. Step to reproduce: 1. Enable the tracepoint event & starting tracing $ echo 1 > /sys/kernel/tracing/events/module/module_free $ echo 1 > /sys/kernel/tracing/tracing_on 2. Record with perf $ perf record -a --strict-freq -F 1 -e "module:module_free" 3. Trigger module_free event. $ modprobe -i sunrpc $ modprobe -r sunrpc Result: - Trace pipe result: $ cat trace_pipe modprobe-174509 [003] ..... 6504.868896: module_free: sunrpc - perf sample: modprobe 174509 [003] 6504.868980: module:module_free: sunrpc modprobe 174509 [003] 6504.868980: module:module_free: sunrpc modprobe 174509 [003] 6504.868980: module:module_free: sunrpc By setting period_left via perf_swevent_set_period() as other sw_event did, This problem could be solved. After patch: - Trace pipe result: $ cat trace_pipe modprobe 1153096 [068] 613468.867774: module:module_free: xfs - perf sample modprobe 1153096 [068] 613468.867794: module:module_free: xfs Link: https://lore.kernel.org/20240913021347.595330-1-yeoreum.yun@arm.com Fixes: bd2b5b12849a ("perf_counter: More aggressive frequency adjustment") Signed-off-by: Levi Yun Acked-by: Namhyung Kim Signed-off-by: Steven Rostedt (Google) Signed-off-by: Sasha Levin --- kernel/trace/trace_event_perf.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c index 61e3a2620fa3..f2000cf2b3bb 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c @@ -356,10 +356,16 @@ void perf_uprobe_destroy(struct perf_event *p_event) int perf_trace_add(struct perf_event *p_event, int flags) { struct trace_event_call *tp_event = p_event->tp_event; + struct hw_perf_event *hwc = &p_event->hw; if (!(flags & PERF_EF_START)) p_event->hw.state = PERF_HES_STOPPED; + if (is_sampling_event(p_event)) { + hwc->last_period = hwc->sample_period; + perf_swevent_set_period(p_event); + } + /* * If TRACE_REG_PERF_ADD returns false; no custom action was performed * and we need to take the default action of enqueueing our event on From 3887bc73d4257dd167d9c054a10e942a488a07a6 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 10 Oct 2024 10:04:32 +0200 Subject: [PATCH 079/118] pinctrl: zynqmp: drop excess struct member description [ Upstream commit 2a85fc7044987d751f27d7f1e4423eebbcecc2c6 ] The 'node' member has never been part of this structure so drop its description. Fixes: 8b242ca700f8 ("pinctrl: Add Xilinx ZynqMP pinctrl driver support") Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/20241010080432.7781-1-brgl@bgdev.pl Signed-off-by: Linus Walleij Signed-off-by: Sasha Levin --- drivers/pinctrl/pinctrl-zynqmp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pinctrl/pinctrl-zynqmp.c b/drivers/pinctrl/pinctrl-zynqmp.c index c98f35ad8921..5a6be66c1a0b 100644 --- a/drivers/pinctrl/pinctrl-zynqmp.c +++ b/drivers/pinctrl/pinctrl-zynqmp.c @@ -45,7 +45,6 @@ * @name: Name of the pin mux function * @groups: List of pin groups for this function * @ngroups: Number of entries in @groups - * @node: Firmware node matching with the function * * This structure holds information about pin control function * and function group names supporting that function. From ccfbcc7d555d7a1b91d0c1b11af692af8c3c7b40 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Thu, 10 Oct 2024 00:17:57 +0200 Subject: [PATCH 080/118] powerpc/vdso: Flag VDSO64 entry points as functions [ Upstream commit 0161bd38c24312853ed5ae9a425a1c41c4ac674a ] On powerpc64 as shown below by readelf, vDSO functions symbols have type NOTYPE. $ powerpc64-linux-gnu-readelf -a arch/powerpc/kernel/vdso/vdso64.so.dbg ELF Header: Magic: 7f 45 4c 46 02 02 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, big endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: DYN (Shared object file) Machine: PowerPC64 Version: 0x1 ... Symbol table '.dynsym' contains 12 entries: Num: Value Size Type Bind Vis Ndx Name ... 1: 0000000000000524 84 NOTYPE GLOBAL DEFAULT 8 __[...]@@LINUX_2.6.15 ... 4: 0000000000000000 0 OBJECT GLOBAL DEFAULT ABS LINUX_2.6.15 5: 00000000000006c0 48 NOTYPE GLOBAL DEFAULT 8 __[...]@@LINUX_2.6.15 Symbol table '.symtab' contains 56 entries: Num: Value Size Type Bind Vis Ndx Name ... 45: 0000000000000000 0 OBJECT GLOBAL DEFAULT ABS LINUX_2.6.15 46: 00000000000006c0 48 NOTYPE GLOBAL DEFAULT 8 __kernel_getcpu 47: 0000000000000524 84 NOTYPE GLOBAL DEFAULT 8 __kernel_clock_getres To overcome that, commit ba83b3239e65 ("selftests: vDSO: fix vDSO symbols lookup for powerpc64") was applied to have selftests also look for NOTYPE symbols, but the correct fix should be to flag VDSO entry points as functions. The original commit that brought VDSO support into powerpc/64 has the following explanation: Note that the symbols exposed by the vDSO aren't "normal" function symbols, apps can't be expected to link against them directly, the vDSO's are both seen as if they were linked at 0 and the symbols just contain offsets to the various functions. This is done on purpose to avoid a relocation step (ppc64 functions normally have descriptors with abs addresses in them). When glibc uses those functions, it's expected to use it's own trampolines that know how to reach them. The descriptors it's talking about are the OPD function descriptors used on ABI v1 (big endian). But it would be more correct for a text symbol to have type function, even if there's no function descriptor for it. glibc has a special case already for handling the VDSO symbols which creates a fake opd pointing at the kernel symbol. So changing the VDSO symbol type to function shouldn't affect that. For ABI v2, there is no function descriptors and VDSO functions can safely have function type. So lets flag VDSO entry points as functions and revert the selftest change. Link: https://github.com/mpe/linux-fullhistory/commit/5f2dd691b62da9d9cc54b938f8b29c22c93cb805 Fixes: ba83b3239e65 ("selftests: vDSO: fix vDSO symbols lookup for powerpc64") Signed-off-by: Christophe Leroy Reviewed-By: Segher Boessenkool Signed-off-by: Michael Ellerman Link: https://patch.msgid.link/b6ad2f1ee9887af3ca5ecade2a56f4acda517a85.1728512263.git.christophe.leroy@csgroup.eu Signed-off-by: Sasha Levin --- arch/powerpc/include/asm/vdso.h | 1 + tools/testing/selftests/vDSO/parse_vdso.c | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/include/asm/vdso.h b/arch/powerpc/include/asm/vdso.h index 7650b6ce14c8..8d972bc98b55 100644 --- a/arch/powerpc/include/asm/vdso.h +++ b/arch/powerpc/include/asm/vdso.h @@ -25,6 +25,7 @@ int vdso_getcpu_init(void); #ifdef __VDSO64__ #define V_FUNCTION_BEGIN(name) \ .globl name; \ + .type name,@function; \ name: \ #define V_FUNCTION_END(name) \ diff --git a/tools/testing/selftests/vDSO/parse_vdso.c b/tools/testing/selftests/vDSO/parse_vdso.c index 7dd5668ea8a6..28f35620c499 100644 --- a/tools/testing/selftests/vDSO/parse_vdso.c +++ b/tools/testing/selftests/vDSO/parse_vdso.c @@ -222,8 +222,7 @@ void *vdso_sym(const char *version, const char *name) ELF(Sym) *sym = &vdso_info.symtab[chain]; /* Check for a defined global or weak function w/ right name. */ - if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC && - ELF64_ST_TYPE(sym->st_info) != STT_NOTYPE) + if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC) continue; if (ELF64_ST_BIND(sym->st_info) != STB_GLOBAL && ELF64_ST_BIND(sym->st_info) != STB_WEAK) From c9294079187fc8e67c04374a06b0fd61728b4485 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Thu, 12 Sep 2024 11:15:30 +0800 Subject: [PATCH 081/118] mfd: tps65010: Use IRQF_NO_AUTOEN flag in request_irq() to fix race [ Upstream commit 2174f9a8c9db50f74df769edd5a4ab822c73b6d2 ] As the comment said, disable_irq() after request_irq() still has a time gap in which interrupts can come. request_irq() with IRQF_NO_AUTOEN flag will disable IRQ auto-enable when request IRQ. Fixes: 72cd799544f2 ("[PATCH] I2C: add i2c driver for TPS6501x") Signed-off-by: Jinjie Ruan Link: https://lore.kernel.org/r/20240912031530.2211654-1-ruanjinjie@huawei.com Signed-off-by: Lee Jones Signed-off-by: Sasha Levin --- drivers/mfd/tps65010.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c index c2afa2e69f42..35ddffb96ba1 100644 --- a/drivers/mfd/tps65010.c +++ b/drivers/mfd/tps65010.c @@ -548,17 +548,13 @@ static int tps65010_probe(struct i2c_client *client, */ if (client->irq > 0) { status = request_irq(client->irq, tps65010_irq, - IRQF_TRIGGER_FALLING, DRIVER_NAME, tps); + IRQF_TRIGGER_FALLING | IRQF_NO_AUTOEN, + DRIVER_NAME, tps); if (status < 0) { dev_dbg(&client->dev, "can't get IRQ %d, err %d\n", client->irq, status); return status; } - /* annoying race here, ideally we'd have an option - * to claim the irq now and enable it later. - * FIXME genirq IRQF_NOAUTOEN now solves that ... - */ - disable_irq(client->irq); set_bit(FLAG_IRQ_ENABLE, &tps->flags); } else dev_warn(&client->dev, "IRQ not configured!\n"); From 50952a6ff5fa399c4d8a8ec517d1e8f4e0494fb0 Mon Sep 17 00:00:00 2001 From: Marcus Folkesson Date: Wed, 25 Sep 2024 12:19:53 +0200 Subject: [PATCH 082/118] mfd: da9052-spi: Change read-mask to write-mask [ Upstream commit 2e3378f6c79a1b3f7855ded1ef306ea4406352ed ] Driver has mixed up the R/W bit. The LSB bit is set on write rather than read. Change it to avoid nasty things to happen. Fixes: e9e9d3973594 ("mfd: da9052: Avoid setting read_flag_mask for da9052-i2c driver") Signed-off-by: Marcus Folkesson Link: https://lore.kernel.org/r/20240925-da9052-v2-1-f243e4505b07@gmail.com Signed-off-by: Lee Jones Signed-off-by: Sasha Levin --- drivers/mfd/da9052-spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/da9052-spi.c b/drivers/mfd/da9052-spi.c index b79a57b45c1e..458f919de4cb 100644 --- a/drivers/mfd/da9052-spi.c +++ b/drivers/mfd/da9052-spi.c @@ -37,7 +37,7 @@ static int da9052_spi_probe(struct spi_device *spi) spi_set_drvdata(spi, da9052); config = da9052_regmap_config; - config.read_flag_mask = 1; + config.write_flag_mask = 1; config.reg_bits = 7; config.pad_bits = 1; config.val_bits = 8; From c310e6916c0b297011d0fec03f168a6b24e9e984 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sat, 5 Oct 2024 22:27:04 +0300 Subject: [PATCH 083/118] mfd: intel_soc_pmic_bxtwc: Use IRQ domain for USB Type-C device [ Upstream commit 686fb77712a4bc94b76a0c5ae74c60118b7a0d79 ] While design wise the idea of converting the driver to use the hierarchy of the IRQ chips is correct, the implementation has (inherited) flaws. This was unveiled when platform_get_irq() had started WARN() on IRQ 0 that is supposed to be a Linux IRQ number (also known as vIRQ). Rework the driver to respect IRQ domain when creating each MFD device separately, as the domain is not the same for all of them. Fixes: 9c6235c86332 ("mfd: intel_soc_pmic_bxtwc: Add bxt_wcove_usbc device") Fixes: d2061f9cc32d ("usb: typec: add driver for Intel Whiskey Cove PMIC USB Type-C PHY") Fixes: 57129044f504 ("mfd: intel_soc_pmic_bxtwc: Use chained IRQs for second level IRQ chips") Reported-by: Zhang Ning Closes: https://lore.kernel.org/r/TY2PR01MB3322FEDCDC048B7D3794F922CDBA2@TY2PR01MB3322.jpnprd01.prod.outlook.com Tested-by: Zhang Ning Signed-off-by: Andy Shevchenko Acked-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20241005193029.1929139-2-andriy.shevchenko@linux.intel.com Signed-off-by: Lee Jones Signed-off-by: Sasha Levin --- drivers/mfd/intel_soc_pmic_bxtwc.c | 57 +++++++++++++++++++++--------- drivers/usb/typec/tcpm/wcove.c | 4 --- 2 files changed, 40 insertions(+), 21 deletions(-) diff --git a/drivers/mfd/intel_soc_pmic_bxtwc.c b/drivers/mfd/intel_soc_pmic_bxtwc.c index 8dac0d41f64f..6ea98321bbf2 100644 --- a/drivers/mfd/intel_soc_pmic_bxtwc.c +++ b/drivers/mfd/intel_soc_pmic_bxtwc.c @@ -241,16 +241,6 @@ static struct mfd_cell bxt_wc_dev[] = { .num_resources = ARRAY_SIZE(thermal_resources), .resources = thermal_resources, }, - { - .name = "bxt_wcove_usbc", - .num_resources = ARRAY_SIZE(usbc_resources), - .resources = usbc_resources, - }, - { - .name = "bxt_wcove_ext_charger", - .num_resources = ARRAY_SIZE(charger_resources), - .resources = charger_resources, - }, { .name = "bxt_wcove_bcu", .num_resources = ARRAY_SIZE(bcu_resources), @@ -272,6 +262,19 @@ static struct mfd_cell bxt_wc_dev[] = { }, }; +static struct mfd_cell bxt_wc_chgr_dev[] = { + { + .name = "bxt_wcove_usbc", + .num_resources = ARRAY_SIZE(usbc_resources), + .resources = usbc_resources, + }, + { + .name = "bxt_wcove_ext_charger", + .num_resources = ARRAY_SIZE(charger_resources), + .resources = charger_resources, + }, +}; + static int regmap_ipc_byte_reg_read(void *context, unsigned int reg, unsigned int *val) { @@ -426,6 +429,26 @@ static int bxtwc_add_chained_irq_chip(struct intel_soc_pmic *pmic, 0, chip, data); } +static int bxtwc_add_chained_devices(struct intel_soc_pmic *pmic, + const struct mfd_cell *cells, int n_devs, + struct regmap_irq_chip_data *pdata, + int pirq, int irq_flags, + const struct regmap_irq_chip *chip, + struct regmap_irq_chip_data **data) +{ + struct device *dev = pmic->dev; + struct irq_domain *domain; + int ret; + + ret = bxtwc_add_chained_irq_chip(pmic, pdata, pirq, irq_flags, chip, data); + if (ret) + return dev_err_probe(dev, ret, "Failed to add %s IRQ chip\n", chip->name); + + domain = regmap_irq_get_domain(*data); + + return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, cells, n_devs, NULL, 0, domain); +} + static int bxtwc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -501,14 +524,14 @@ static int bxtwc_probe(struct platform_device *pdev) if (ret) return dev_err_probe(dev, ret, "Failed to add ADC IRQ chip\n"); - /* Add chained IRQ handler for CHGR IRQs */ - ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, - BXTWC_CHGR_LVL1_IRQ, - IRQF_ONESHOT, - &bxtwc_regmap_irq_chip_chgr, - &pmic->irq_chip_data_chgr); + ret = bxtwc_add_chained_devices(pmic, bxt_wc_chgr_dev, ARRAY_SIZE(bxt_wc_chgr_dev), + pmic->irq_chip_data, + BXTWC_CHGR_LVL1_IRQ, + IRQF_ONESHOT, + &bxtwc_regmap_irq_chip_chgr, + &pmic->irq_chip_data_chgr); if (ret) - return dev_err_probe(dev, ret, "Failed to add CHGR IRQ chip\n"); + return ret; /* Add chained IRQ handler for CRIT IRQs */ ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, diff --git a/drivers/usb/typec/tcpm/wcove.c b/drivers/usb/typec/tcpm/wcove.c index 20917d85d6f4..5d34466a0abf 100644 --- a/drivers/usb/typec/tcpm/wcove.c +++ b/drivers/usb/typec/tcpm/wcove.c @@ -621,10 +621,6 @@ static int wcove_typec_probe(struct platform_device *pdev) if (irq < 0) return irq; - irq = regmap_irq_get_virq(pmic->irq_chip_data_chgr, irq); - if (irq < 0) - return irq; - ret = guid_parse(WCOVE_DSM_UUID, &wcove->guid); if (ret) return ret; From 56acf415772ee7e10e448b371f52b249aa2d0f7b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sat, 5 Oct 2024 22:27:05 +0300 Subject: [PATCH 084/118] mfd: intel_soc_pmic_bxtwc: Use IRQ domain for TMU device [ Upstream commit 9b79d59e6b2b515eb9a22bc469ef7b8f0904fc73 ] While design wise the idea of converting the driver to use the hierarchy of the IRQ chips is correct, the implementation has (inherited) flaws. This was unveiled when platform_get_irq() had started WARN() on IRQ 0 that is supposed to be a Linux IRQ number (also known as vIRQ). Rework the driver to respect IRQ domain when creating each MFD device separately, as the domain is not the same for all of them. Fixes: 957ae5098185 ("platform/x86: Add Whiskey Cove PMIC TMU support") Fixes: 57129044f504 ("mfd: intel_soc_pmic_bxtwc: Use chained IRQs for second level IRQ chips") Reported-by: Zhang Ning Closes: https://lore.kernel.org/r/TY2PR01MB3322FEDCDC048B7D3794F922CDBA2@TY2PR01MB3322.jpnprd01.prod.outlook.com Tested-by: Zhang Ning Acked-by: Hans de Goede Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20241005193029.1929139-3-andriy.shevchenko@linux.intel.com Signed-off-by: Lee Jones Signed-off-by: Sasha Levin --- drivers/mfd/intel_soc_pmic_bxtwc.c | 31 ++++++++++++++------------ drivers/platform/x86/intel/bxtwc_tmu.c | 22 +++++------------- 2 files changed, 23 insertions(+), 30 deletions(-) diff --git a/drivers/mfd/intel_soc_pmic_bxtwc.c b/drivers/mfd/intel_soc_pmic_bxtwc.c index 6ea98321bbf2..5fc9d3aa6142 100644 --- a/drivers/mfd/intel_soc_pmic_bxtwc.c +++ b/drivers/mfd/intel_soc_pmic_bxtwc.c @@ -246,12 +246,6 @@ static struct mfd_cell bxt_wc_dev[] = { .num_resources = ARRAY_SIZE(bcu_resources), .resources = bcu_resources, }, - { - .name = "bxt_wcove_tmu", - .num_resources = ARRAY_SIZE(tmu_resources), - .resources = tmu_resources, - }, - { .name = "bxt_wcove_gpio", .num_resources = ARRAY_SIZE(gpio_resources), @@ -262,6 +256,14 @@ static struct mfd_cell bxt_wc_dev[] = { }, }; +static const struct mfd_cell bxt_wc_tmu_dev[] = { + { + .name = "bxt_wcove_tmu", + .num_resources = ARRAY_SIZE(tmu_resources), + .resources = tmu_resources, + }, +}; + static struct mfd_cell bxt_wc_chgr_dev[] = { { .name = "bxt_wcove_usbc", @@ -490,6 +492,15 @@ static int bxtwc_probe(struct platform_device *pdev) if (ret) return dev_err_probe(dev, ret, "Failed to add IRQ chip\n"); + ret = bxtwc_add_chained_devices(pmic, bxt_wc_tmu_dev, ARRAY_SIZE(bxt_wc_tmu_dev), + pmic->irq_chip_data, + BXTWC_TMU_LVL1_IRQ, + IRQF_ONESHOT, + &bxtwc_regmap_irq_chip_tmu, + &pmic->irq_chip_data_tmu); + if (ret) + return ret; + ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, BXTWC_PWRBTN_LVL1_IRQ, IRQF_ONESHOT, @@ -498,14 +509,6 @@ static int bxtwc_probe(struct platform_device *pdev) if (ret) return dev_err_probe(dev, ret, "Failed to add PWRBTN IRQ chip\n"); - ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, - BXTWC_TMU_LVL1_IRQ, - IRQF_ONESHOT, - &bxtwc_regmap_irq_chip_tmu, - &pmic->irq_chip_data_tmu); - if (ret) - return dev_err_probe(dev, ret, "Failed to add TMU IRQ chip\n"); - /* Add chained IRQ handler for BCU IRQs */ ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, BXTWC_BCU_LVL1_IRQ, diff --git a/drivers/platform/x86/intel/bxtwc_tmu.c b/drivers/platform/x86/intel/bxtwc_tmu.c index 7ccf583649e6..3c9778366d93 100644 --- a/drivers/platform/x86/intel/bxtwc_tmu.c +++ b/drivers/platform/x86/intel/bxtwc_tmu.c @@ -48,9 +48,8 @@ static irqreturn_t bxt_wcove_tmu_irq_handler(int irq, void *data) static int bxt_wcove_tmu_probe(struct platform_device *pdev) { struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent); - struct regmap_irq_chip_data *regmap_irq_chip; struct wcove_tmu *wctmu; - int ret, virq, irq; + int ret; wctmu = devm_kzalloc(&pdev->dev, sizeof(*wctmu), GFP_KERNEL); if (!wctmu) @@ -59,27 +58,18 @@ static int bxt_wcove_tmu_probe(struct platform_device *pdev) wctmu->dev = &pdev->dev; wctmu->regmap = pmic->regmap; - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; + wctmu->irq = platform_get_irq(pdev, 0); + if (wctmu->irq < 0) + return wctmu->irq; - regmap_irq_chip = pmic->irq_chip_data_tmu; - virq = regmap_irq_get_virq(regmap_irq_chip, irq); - if (virq < 0) { - dev_err(&pdev->dev, - "failed to get virtual interrupt=%d\n", irq); - return virq; - } - - ret = devm_request_threaded_irq(&pdev->dev, virq, + ret = devm_request_threaded_irq(&pdev->dev, wctmu->irq, NULL, bxt_wcove_tmu_irq_handler, IRQF_ONESHOT, "bxt_wcove_tmu", wctmu); if (ret) { dev_err(&pdev->dev, "request irq failed: %d,virq: %d\n", - ret, virq); + ret, wctmu->irq); return ret; } - wctmu->irq = virq; /* Unmask TMU second level Wake & System alarm */ regmap_update_bits(wctmu->regmap, BXTWC_MTMUIRQ_REG, From 7ba45b8bc62e64da524d45532107ae93eb33c93c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sat, 5 Oct 2024 22:27:06 +0300 Subject: [PATCH 085/118] mfd: intel_soc_pmic_bxtwc: Use IRQ domain for PMIC devices [ Upstream commit 0350d783ab888cb1cb48ced36cc28b372723f1a4 ] While design wise the idea of converting the driver to use the hierarchy of the IRQ chips is correct, the implementation has (inherited) flaws. This was unveiled when platform_get_irq() had started WARN() on IRQ 0 that is supposed to be a Linux IRQ number (also known as vIRQ). Rework the driver to respect IRQ domain when creating each MFD device separately, as the domain is not the same for all of them. Fixes: 57129044f504 ("mfd: intel_soc_pmic_bxtwc: Use chained IRQs for second level IRQ chips") Tested-by: Zhang Ning Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20241005193029.1929139-4-andriy.shevchenko@linux.intel.com Signed-off-by: Lee Jones Signed-off-by: Sasha Levin --- drivers/mfd/intel_soc_pmic_bxtwc.c | 54 +++++++++++++++++------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/drivers/mfd/intel_soc_pmic_bxtwc.c b/drivers/mfd/intel_soc_pmic_bxtwc.c index 5fc9d3aa6142..3aa7857271da 100644 --- a/drivers/mfd/intel_soc_pmic_bxtwc.c +++ b/drivers/mfd/intel_soc_pmic_bxtwc.c @@ -231,21 +231,11 @@ static const struct resource tmu_resources[] = { }; static struct mfd_cell bxt_wc_dev[] = { - { - .name = "bxt_wcove_gpadc", - .num_resources = ARRAY_SIZE(adc_resources), - .resources = adc_resources, - }, { .name = "bxt_wcove_thermal", .num_resources = ARRAY_SIZE(thermal_resources), .resources = thermal_resources, }, - { - .name = "bxt_wcove_bcu", - .num_resources = ARRAY_SIZE(bcu_resources), - .resources = bcu_resources, - }, { .name = "bxt_wcove_gpio", .num_resources = ARRAY_SIZE(gpio_resources), @@ -264,6 +254,22 @@ static const struct mfd_cell bxt_wc_tmu_dev[] = { }, }; +static const struct mfd_cell bxt_wc_bcu_dev[] = { + { + .name = "bxt_wcove_bcu", + .num_resources = ARRAY_SIZE(bcu_resources), + .resources = bcu_resources, + }, +}; + +static const struct mfd_cell bxt_wc_adc_dev[] = { + { + .name = "bxt_wcove_gpadc", + .num_resources = ARRAY_SIZE(adc_resources), + .resources = adc_resources, + }, +}; + static struct mfd_cell bxt_wc_chgr_dev[] = { { .name = "bxt_wcove_usbc", @@ -509,23 +515,23 @@ static int bxtwc_probe(struct platform_device *pdev) if (ret) return dev_err_probe(dev, ret, "Failed to add PWRBTN IRQ chip\n"); - /* Add chained IRQ handler for BCU IRQs */ - ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, - BXTWC_BCU_LVL1_IRQ, - IRQF_ONESHOT, - &bxtwc_regmap_irq_chip_bcu, - &pmic->irq_chip_data_bcu); + ret = bxtwc_add_chained_devices(pmic, bxt_wc_bcu_dev, ARRAY_SIZE(bxt_wc_bcu_dev), + pmic->irq_chip_data, + BXTWC_BCU_LVL1_IRQ, + IRQF_ONESHOT, + &bxtwc_regmap_irq_chip_bcu, + &pmic->irq_chip_data_bcu); if (ret) - return dev_err_probe(dev, ret, "Failed to add BUC IRQ chip\n"); + return ret; - /* Add chained IRQ handler for ADC IRQs */ - ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, - BXTWC_ADC_LVL1_IRQ, - IRQF_ONESHOT, - &bxtwc_regmap_irq_chip_adc, - &pmic->irq_chip_data_adc); + ret = bxtwc_add_chained_devices(pmic, bxt_wc_adc_dev, ARRAY_SIZE(bxt_wc_adc_dev), + pmic->irq_chip_data, + BXTWC_ADC_LVL1_IRQ, + IRQF_ONESHOT, + &bxtwc_regmap_irq_chip_adc, + &pmic->irq_chip_data_adc); if (ret) - return dev_err_probe(dev, ret, "Failed to add ADC IRQ chip\n"); + return ret; ret = bxtwc_add_chained_devices(pmic, bxt_wc_chgr_dev, ARRAY_SIZE(bxt_wc_chgr_dev), pmic->irq_chip_data, From dd6383dd6ae01bf4bcc92ec90f6bf5f667142822 Mon Sep 17 00:00:00 2001 From: Yuan Can Date: Wed, 16 Oct 2024 17:06:15 +0800 Subject: [PATCH 086/118] cpufreq: loongson2: Unregister platform_driver on failure [ Upstream commit 5f856d71ccdf89b4bac0ff70ebb0bb582e7f7f18 ] When cpufreq_register_driver() returns error, the cpufreq_init() returns without unregister platform_driver, fix by add missing platform_driver_unregister() when cpufreq_register_driver() failed. Fixes: f8ede0f700f5 ("MIPS: Loongson 2F: Add CPU frequency scaling support") Signed-off-by: Yuan Can Signed-off-by: Viresh Kumar Signed-off-by: Sasha Levin --- drivers/cpufreq/loongson2_cpufreq.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c index afc59b292153..63cae4037deb 100644 --- a/drivers/cpufreq/loongson2_cpufreq.c +++ b/drivers/cpufreq/loongson2_cpufreq.c @@ -154,7 +154,9 @@ static int __init cpufreq_init(void) ret = cpufreq_register_driver(&loongson2_cpufreq_driver); - if (!ret && !nowait) { + if (ret) { + platform_driver_unregister(&platform_driver); + } else if (!nowait) { saved_cpu_wait = cpu_wait; cpu_wait = loongson2_cpu_wait; } From 6ffdb03366a9dfdf4b0fc2d239a04e5886a64bae Mon Sep 17 00:00:00 2001 From: "Ritesh Harjani (IBM)" Date: Fri, 18 Oct 2024 21:47:55 +0530 Subject: [PATCH 087/118] powerpc/fadump: Refactor and prepare fadump_cma_init for late init [ Upstream commit adfaec30ffaceecd565e06adae367aa944acc3c9 ] We anyway don't use any return values from fadump_cma_init(). Since fadump_reserve_mem() from where fadump_cma_init() gets called today, already has the required checks. This patch makes this function return type as void. Let's also handle extra cases like return if fadump_supported is false or dump_active, so that in later patches we can call fadump_cma_init() separately from setup_arch(). Acked-by: Hari Bathini Reviewed-by: Madhavan Srinivasan Signed-off-by: Ritesh Harjani (IBM) Signed-off-by: Michael Ellerman Link: https://patch.msgid.link/a2afc3d6481a87a305e89cfc4a3f3d2a0b8ceab3.1729146153.git.ritesh.list@gmail.com Stable-dep-of: 05b94cae1c47 ("powerpc/fadump: Move fadump_cma_init to setup_arch() after initmem_init()") Signed-off-by: Sasha Levin --- arch/powerpc/kernel/fadump.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c index 3ff2da7b120b..4722a9e606e6 100644 --- a/arch/powerpc/kernel/fadump.c +++ b/arch/powerpc/kernel/fadump.c @@ -80,27 +80,23 @@ static struct cma *fadump_cma; * But for some reason even if it fails we still have the memory reservation * with us and we can still continue doing fadump. */ -static int __init fadump_cma_init(void) +static void __init fadump_cma_init(void) { unsigned long long base, size; int rc; - if (!fw_dump.fadump_enabled) - return 0; - + if (!fw_dump.fadump_supported || !fw_dump.fadump_enabled || + fw_dump.dump_active) + return; /* * Do not use CMA if user has provided fadump=nocma kernel parameter. - * Return 1 to continue with fadump old behaviour. */ - if (fw_dump.nocma) - return 1; + if (fw_dump.nocma || !fw_dump.boot_memory_size) + return; base = fw_dump.reserve_dump_area_start; size = fw_dump.boot_memory_size; - if (!size) - return 0; - rc = cma_init_reserved_mem(base, size, 0, "fadump_cma", &fadump_cma); if (rc) { pr_err("Failed to init cma area for firmware-assisted dump,%d\n", rc); @@ -110,7 +106,7 @@ static int __init fadump_cma_init(void) * blocked from production system usage. Hence return 1, * so that we can continue with fadump. */ - return 1; + return; } /* @@ -127,10 +123,9 @@ static int __init fadump_cma_init(void) cma_get_size(fadump_cma), (unsigned long)cma_get_base(fadump_cma) >> 20, fw_dump.reserve_dump_area_size); - return 1; } #else -static int __init fadump_cma_init(void) { return 1; } +static void __init fadump_cma_init(void) { } #endif /* CONFIG_CMA */ /* Scan the Firmware Assisted dump configuration details. */ @@ -648,7 +643,7 @@ int __init fadump_reserve_mem(void) pr_info("Reserved %lldMB of memory at %#016llx (System RAM: %lldMB)\n", (size >> 20), base, (memblock_phys_mem_size() >> 20)); - ret = fadump_cma_init(); + fadump_cma_init(); } return ret; From aabef6301dcf410dfd2b8759cd413b2a003c7e3f Mon Sep 17 00:00:00 2001 From: "Ritesh Harjani (IBM)" Date: Fri, 18 Oct 2024 21:47:57 +0530 Subject: [PATCH 088/118] powerpc/fadump: Move fadump_cma_init to setup_arch() after initmem_init() [ Upstream commit 05b94cae1c47f94588c3e7096963c1007c4d9c1d ] During early init CMA_MIN_ALIGNMENT_BYTES can be PAGE_SIZE, since pageblock_order is still zero and it gets initialized later during initmem_init() e.g. setup_arch() -> initmem_init() -> sparse_init() -> set_pageblock_order() One such use case where this causes issue is - early_setup() -> early_init_devtree() -> fadump_reserve_mem() -> fadump_cma_init() This causes CMA memory alignment check to be bypassed in cma_init_reserved_mem(). Then later cma_activate_area() can hit a VM_BUG_ON_PAGE(pfn & ((1 << order) - 1)) if the reserved memory area was not pageblock_order aligned. Fix it by moving the fadump_cma_init() after initmem_init(), where other such cma reservations also gets called. ============== page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x10010 flags: 0x13ffff800000000(node=1|zone=0|lastcpupid=0x7ffff) CMA raw: 013ffff800000000 5deadbeef0000100 5deadbeef0000122 0000000000000000 raw: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000000 page dumped because: VM_BUG_ON_PAGE(pfn & ((1 << order) - 1)) ------------[ cut here ]------------ kernel BUG at mm/page_alloc.c:778! Call Trace: __free_one_page+0x57c/0x7b0 (unreliable) free_pcppages_bulk+0x1a8/0x2c8 free_unref_page_commit+0x3d4/0x4e4 free_unref_page+0x458/0x6d0 init_cma_reserved_pageblock+0x114/0x198 cma_init_reserved_areas+0x270/0x3e0 do_one_initcall+0x80/0x2f8 kernel_init_freeable+0x33c/0x530 kernel_init+0x34/0x26c ret_from_kernel_user_thread+0x14/0x1c Fixes: 11ac3e87ce09 ("mm: cma: use pageblock_order as the single alignment") Suggested-by: David Hildenbrand Reported-by: Sachin P Bappalige Acked-by: Hari Bathini Reviewed-by: Madhavan Srinivasan Signed-off-by: Ritesh Harjani (IBM) Signed-off-by: Michael Ellerman Link: https://patch.msgid.link/3ae208e48c0d9cefe53d2dc4f593388067405b7d.1729146153.git.ritesh.list@gmail.com Signed-off-by: Sasha Levin --- arch/powerpc/include/asm/fadump.h | 7 +++++++ arch/powerpc/kernel/fadump.c | 6 +----- arch/powerpc/kernel/setup-common.c | 6 ++++-- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/include/asm/fadump.h b/arch/powerpc/include/asm/fadump.h index 526a6a647312..daa44b2ef35a 100644 --- a/arch/powerpc/include/asm/fadump.h +++ b/arch/powerpc/include/asm/fadump.h @@ -32,4 +32,11 @@ extern int early_init_dt_scan_fw_dump(unsigned long node, const char *uname, int depth, void *data); extern int fadump_reserve_mem(void); #endif + +#if defined(CONFIG_FA_DUMP) && defined(CONFIG_CMA) +void fadump_cma_init(void); +#else +static inline void fadump_cma_init(void) { } +#endif + #endif /* _ASM_POWERPC_FADUMP_H */ diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c index 4722a9e606e6..1866bac23400 100644 --- a/arch/powerpc/kernel/fadump.c +++ b/arch/powerpc/kernel/fadump.c @@ -80,7 +80,7 @@ static struct cma *fadump_cma; * But for some reason even if it fails we still have the memory reservation * with us and we can still continue doing fadump. */ -static void __init fadump_cma_init(void) +void __init fadump_cma_init(void) { unsigned long long base, size; int rc; @@ -124,8 +124,6 @@ static void __init fadump_cma_init(void) (unsigned long)cma_get_base(fadump_cma) >> 20, fw_dump.reserve_dump_area_size); } -#else -static void __init fadump_cma_init(void) { } #endif /* CONFIG_CMA */ /* Scan the Firmware Assisted dump configuration details. */ @@ -642,8 +640,6 @@ int __init fadump_reserve_mem(void) pr_info("Reserved %lldMB of memory at %#016llx (System RAM: %lldMB)\n", (size >> 20), base, (memblock_phys_mem_size() >> 20)); - - fadump_cma_init(); } return ret; diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 56f6b958926d..41c03c8e41b4 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -982,9 +982,11 @@ void __init setup_arch(char **cmdline_p) initmem_init(); /* - * Reserve large chunks of memory for use by CMA for KVM and hugetlb. These must - * be called after initmem_init(), so that pageblock_order is initialised. + * Reserve large chunks of memory for use by CMA for fadump, KVM and + * hugetlb. These must be called after initmem_init(), so that + * pageblock_order is initialised. */ + fadump_cma_init(); kvm_cma_reserve(); gigantic_hugetlb_cma_reserve(); From f7ef1b97ce09d79653b2e19a7d679178e062db05 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 23 Nov 2022 15:41:20 +0100 Subject: [PATCH 089/118] memory: renesas-rpc-if: Improve Runtime PM handling [ Upstream commit bb0b025d72d22b8617df920b61f5ae1e23d1b593 ] Convert from the deprecated pm_runtime_get_sync() to the new pm_runtime_resume_and_get(), and add error checking. Signed-off-by: Geert Uytterhoeven Acked-by: Wolfram Sang Link: https://lore.kernel.org/r/6f2bd3b2b3d98c5bed541d969900b2ad04f93943.1669213027.git.geert+renesas@glider.be Signed-off-by: Krzysztof Kozlowski Stable-dep-of: 7d189579a287 ("mtd: hyperbus: rpc-if: Add missing MODULE_DEVICE_TABLE") Signed-off-by: Sasha Levin --- drivers/memory/renesas-rpc-if.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c index 7343dbb79c9f..6991185caa7b 100644 --- a/drivers/memory/renesas-rpc-if.c +++ b/drivers/memory/renesas-rpc-if.c @@ -303,12 +303,13 @@ int rpcif_hw_init(struct rpcif *rpcif, bool hyperflash) { struct rpcif_priv *rpc = dev_get_drvdata(rpcif->dev); u32 dummy; + int ret; - pm_runtime_get_sync(rpc->dev); + ret = pm_runtime_resume_and_get(rpc->dev); + if (ret) + return ret; if (rpc->type == RPCIF_RZ_G2L) { - int ret; - ret = reset_control_reset(rpc->rstc); if (ret) return ret; @@ -478,7 +479,9 @@ int rpcif_manual_xfer(struct rpcif *rpcif) u32 smenr, smcr, pos = 0, max = rpc->bus_size == 2 ? 8 : 4; int ret = 0; - pm_runtime_get_sync(rpc->dev); + ret = pm_runtime_resume_and_get(rpc->dev); + if (ret < 0) + return ret; regmap_update_bits(rpc->regmap, RPCIF_PHYCNT, RPCIF_PHYCNT_CAL, RPCIF_PHYCNT_CAL); @@ -646,11 +649,14 @@ ssize_t rpcif_dirmap_read(struct rpcif *rpcif, u64 offs, size_t len, void *buf) struct rpcif_priv *rpc = dev_get_drvdata(rpcif->dev); loff_t from = offs & (rpc->size - 1); size_t size = rpc->size - from; + int ret; if (len > size) len = size; - pm_runtime_get_sync(rpc->dev); + ret = pm_runtime_resume_and_get(rpc->dev); + if (ret < 0) + return ret; regmap_update_bits(rpc->regmap, RPCIF_CMNCR, RPCIF_CMNCR_MD, 0); regmap_write(rpc->regmap, RPCIF_DRCR, 0); From f025336fd88403d0ff078acb28dffe7c52ba0f69 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 23 Nov 2022 15:41:21 +0100 Subject: [PATCH 090/118] memory: renesas-rpc-if: Pass device instead of rpcif to rpcif_*() [ Upstream commit a198fcd1d53cbaf616d94822921c77910b94edb7 ] Most rpcif_*() API functions do not need access to any other fields in the rpcif structure than the device pointer. Simplify dependencies by passing the device pointer instead. Signed-off-by: Geert Uytterhoeven Acked-by: Miquel Raynal Acked-by: Mark Brown Acked-by: Wolfram Sang Link: https://lore.kernel.org/r/0460fe82ba348cedec7a9a75a8eff762c50e817b.1669213027.git.geert+renesas@glider.be Signed-off-by: Krzysztof Kozlowski Stable-dep-of: 7d189579a287 ("mtd: hyperbus: rpc-if: Add missing MODULE_DEVICE_TABLE") Signed-off-by: Sasha Levin --- drivers/memory/renesas-rpc-if.c | 32 ++++++++++++++++---------------- drivers/mtd/hyperbus/rpc-if.c | 18 +++++++++--------- drivers/spi/spi-rpc-if.c | 14 +++++++------- include/memory/renesas-rpc-if.h | 16 ++++++++-------- 4 files changed, 40 insertions(+), 40 deletions(-) diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c index 6991185caa7b..6a2b3c256599 100644 --- a/drivers/memory/renesas-rpc-if.c +++ b/drivers/memory/renesas-rpc-if.c @@ -299,13 +299,13 @@ static void rpcif_rzg2l_timing_adjust_sdr(struct rpcif_priv *rpc) regmap_write(rpc->regmap, RPCIF_PHYADD, 0x80000032); } -int rpcif_hw_init(struct rpcif *rpcif, bool hyperflash) +int rpcif_hw_init(struct device *dev, bool hyperflash) { - struct rpcif_priv *rpc = dev_get_drvdata(rpcif->dev); + struct rpcif_priv *rpc = dev_get_drvdata(dev); u32 dummy; int ret; - ret = pm_runtime_resume_and_get(rpc->dev); + ret = pm_runtime_resume_and_get(dev); if (ret) return ret; @@ -355,7 +355,7 @@ int rpcif_hw_init(struct rpcif *rpcif, bool hyperflash) regmap_write(rpc->regmap, RPCIF_SSLDR, RPCIF_SSLDR_SPNDL(7) | RPCIF_SSLDR_SLNDL(7) | RPCIF_SSLDR_SCKDL(7)); - pm_runtime_put(rpc->dev); + pm_runtime_put(dev); rpc->bus_size = hyperflash ? 2 : 1; @@ -385,10 +385,10 @@ static u8 rpcif_bit_size(u8 buswidth) return buswidth > 4 ? 2 : ilog2(buswidth); } -void rpcif_prepare(struct rpcif *rpcif, const struct rpcif_op *op, u64 *offs, +void rpcif_prepare(struct device *dev, const struct rpcif_op *op, u64 *offs, size_t *len) { - struct rpcif_priv *rpc = dev_get_drvdata(rpcif->dev); + struct rpcif_priv *rpc = dev_get_drvdata(dev); rpc->smcr = 0; rpc->smadr = 0; @@ -473,13 +473,13 @@ void rpcif_prepare(struct rpcif *rpcif, const struct rpcif_op *op, u64 *offs, } EXPORT_SYMBOL(rpcif_prepare); -int rpcif_manual_xfer(struct rpcif *rpcif) +int rpcif_manual_xfer(struct device *dev) { - struct rpcif_priv *rpc = dev_get_drvdata(rpcif->dev); + struct rpcif_priv *rpc = dev_get_drvdata(dev); u32 smenr, smcr, pos = 0, max = rpc->bus_size == 2 ? 8 : 4; int ret = 0; - ret = pm_runtime_resume_and_get(rpc->dev); + ret = pm_runtime_resume_and_get(dev); if (ret < 0) return ret; @@ -591,13 +591,13 @@ int rpcif_manual_xfer(struct rpcif *rpcif) } exit: - pm_runtime_put(rpc->dev); + pm_runtime_put(dev); return ret; err_out: if (reset_control_reset(rpc->rstc)) - dev_err(rpc->dev, "Failed to reset HW\n"); - rpcif_hw_init(rpcif, rpc->bus_size == 2); + dev_err(dev, "Failed to reset HW\n"); + rpcif_hw_init(dev, rpc->bus_size == 2); goto exit; } EXPORT_SYMBOL(rpcif_manual_xfer); @@ -644,9 +644,9 @@ static void memcpy_fromio_readw(void *to, } } -ssize_t rpcif_dirmap_read(struct rpcif *rpcif, u64 offs, size_t len, void *buf) +ssize_t rpcif_dirmap_read(struct device *dev, u64 offs, size_t len, void *buf) { - struct rpcif_priv *rpc = dev_get_drvdata(rpcif->dev); + struct rpcif_priv *rpc = dev_get_drvdata(dev); loff_t from = offs & (rpc->size - 1); size_t size = rpc->size - from; int ret; @@ -654,7 +654,7 @@ ssize_t rpcif_dirmap_read(struct rpcif *rpcif, u64 offs, size_t len, void *buf) if (len > size) len = size; - ret = pm_runtime_resume_and_get(rpc->dev); + ret = pm_runtime_resume_and_get(dev); if (ret < 0) return ret; @@ -674,7 +674,7 @@ ssize_t rpcif_dirmap_read(struct rpcif *rpcif, u64 offs, size_t len, void *buf) else memcpy_fromio(buf, rpc->dirmap + from, len); - pm_runtime_put(rpc->dev); + pm_runtime_put(dev); return len; } diff --git a/drivers/mtd/hyperbus/rpc-if.c b/drivers/mtd/hyperbus/rpc-if.c index d00d30243403..41734e337ac0 100644 --- a/drivers/mtd/hyperbus/rpc-if.c +++ b/drivers/mtd/hyperbus/rpc-if.c @@ -56,7 +56,7 @@ static void rpcif_hb_prepare_read(struct rpcif *rpc, void *to, op.data.nbytes = len; op.data.buf.in = to; - rpcif_prepare(rpc, &op, NULL, NULL); + rpcif_prepare(rpc->dev, &op, NULL, NULL); } static void rpcif_hb_prepare_write(struct rpcif *rpc, unsigned long to, @@ -70,7 +70,7 @@ static void rpcif_hb_prepare_write(struct rpcif *rpc, unsigned long to, op.data.nbytes = len; op.data.buf.out = from; - rpcif_prepare(rpc, &op, NULL, NULL); + rpcif_prepare(rpc->dev, &op, NULL, NULL); } static u16 rpcif_hb_read16(struct hyperbus_device *hbdev, unsigned long addr) @@ -81,7 +81,7 @@ static u16 rpcif_hb_read16(struct hyperbus_device *hbdev, unsigned long addr) rpcif_hb_prepare_read(&hyperbus->rpc, &data, addr, 2); - rpcif_manual_xfer(&hyperbus->rpc); + rpcif_manual_xfer(hyperbus->rpc.dev); return data.x[0]; } @@ -94,7 +94,7 @@ static void rpcif_hb_write16(struct hyperbus_device *hbdev, unsigned long addr, rpcif_hb_prepare_write(&hyperbus->rpc, addr, &data, 2); - rpcif_manual_xfer(&hyperbus->rpc); + rpcif_manual_xfer(hyperbus->rpc.dev); } static void rpcif_hb_copy_from(struct hyperbus_device *hbdev, void *to, @@ -105,7 +105,7 @@ static void rpcif_hb_copy_from(struct hyperbus_device *hbdev, void *to, rpcif_hb_prepare_read(&hyperbus->rpc, to, from, len); - rpcif_dirmap_read(&hyperbus->rpc, from, len, to); + rpcif_dirmap_read(hyperbus->rpc.dev, from, len, to); } static const struct hyperbus_ops rpcif_hb_ops = { @@ -130,9 +130,9 @@ static int rpcif_hb_probe(struct platform_device *pdev) platform_set_drvdata(pdev, hyperbus); - rpcif_enable_rpm(&hyperbus->rpc); + rpcif_enable_rpm(hyperbus->rpc.dev); - error = rpcif_hw_init(&hyperbus->rpc, true); + error = rpcif_hw_init(hyperbus->rpc.dev, true); if (error) goto out_disable_rpm; @@ -150,7 +150,7 @@ static int rpcif_hb_probe(struct platform_device *pdev) return 0; out_disable_rpm: - rpcif_disable_rpm(&hyperbus->rpc); + rpcif_disable_rpm(hyperbus->rpc.dev); return error; } @@ -160,7 +160,7 @@ static int rpcif_hb_remove(struct platform_device *pdev) hyperbus_unregister_device(&hyperbus->hbdev); - rpcif_disable_rpm(&hyperbus->rpc); + rpcif_disable_rpm(hyperbus->rpc.dev); return 0; } diff --git a/drivers/spi/spi-rpc-if.c b/drivers/spi/spi-rpc-if.c index 24ec1c83f379..5063587d2c72 100644 --- a/drivers/spi/spi-rpc-if.c +++ b/drivers/spi/spi-rpc-if.c @@ -58,7 +58,7 @@ static void rpcif_spi_mem_prepare(struct spi_device *spi_dev, rpc_op.data.dir = RPCIF_NO_DATA; } - rpcif_prepare(rpc, &rpc_op, offs, len); + rpcif_prepare(rpc->dev, &rpc_op, offs, len); } static bool rpcif_spi_mem_supports_op(struct spi_mem *mem, @@ -86,7 +86,7 @@ static ssize_t rpcif_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc, rpcif_spi_mem_prepare(desc->mem->spi, &desc->info.op_tmpl, &offs, &len); - return rpcif_dirmap_read(rpc, offs, len, buf); + return rpcif_dirmap_read(rpc->dev, offs, len, buf); } static int rpcif_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc) @@ -117,7 +117,7 @@ static int rpcif_spi_mem_exec_op(struct spi_mem *mem, rpcif_spi_mem_prepare(mem->spi, op, NULL, NULL); - return rpcif_manual_xfer(rpc); + return rpcif_manual_xfer(rpc->dev); } static const struct spi_controller_mem_ops rpcif_spi_mem_ops = { @@ -147,7 +147,7 @@ static int rpcif_spi_probe(struct platform_device *pdev) ctlr->dev.of_node = parent->of_node; - rpcif_enable_rpm(rpc); + rpcif_enable_rpm(rpc->dev); ctlr->num_chipselect = 1; ctlr->mem_ops = &rpcif_spi_mem_ops; @@ -156,7 +156,7 @@ static int rpcif_spi_probe(struct platform_device *pdev) ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_QUAD | SPI_RX_QUAD; ctlr->flags = SPI_CONTROLLER_HALF_DUPLEX; - error = rpcif_hw_init(rpc, false); + error = rpcif_hw_init(rpc->dev, false); if (error) goto out_disable_rpm; @@ -169,7 +169,7 @@ static int rpcif_spi_probe(struct platform_device *pdev) return 0; out_disable_rpm: - rpcif_disable_rpm(rpc); + rpcif_disable_rpm(rpc->dev); return error; } @@ -179,7 +179,7 @@ static int rpcif_spi_remove(struct platform_device *pdev) struct rpcif *rpc = spi_controller_get_devdata(ctlr); spi_unregister_controller(ctlr); - rpcif_disable_rpm(rpc); + rpcif_disable_rpm(rpc->dev); return 0; } diff --git a/include/memory/renesas-rpc-if.h b/include/memory/renesas-rpc-if.h index ddf94356752d..d2130c2c8c82 100644 --- a/include/memory/renesas-rpc-if.h +++ b/include/memory/renesas-rpc-if.h @@ -69,20 +69,20 @@ struct rpcif { }; int rpcif_sw_init(struct rpcif *rpc, struct device *dev); -int rpcif_hw_init(struct rpcif *rpc, bool hyperflash); -void rpcif_prepare(struct rpcif *rpc, const struct rpcif_op *op, u64 *offs, +int rpcif_hw_init(struct device *dev, bool hyperflash); +void rpcif_prepare(struct device *dev, const struct rpcif_op *op, u64 *offs, size_t *len); -int rpcif_manual_xfer(struct rpcif *rpc); -ssize_t rpcif_dirmap_read(struct rpcif *rpc, u64 offs, size_t len, void *buf); +int rpcif_manual_xfer(struct device *dev); +ssize_t rpcif_dirmap_read(struct device *dev, u64 offs, size_t len, void *buf); -static inline void rpcif_enable_rpm(struct rpcif *rpc) +static inline void rpcif_enable_rpm(struct device *dev) { - pm_runtime_enable(rpc->dev); + pm_runtime_enable(dev); } -static inline void rpcif_disable_rpm(struct rpcif *rpc) +static inline void rpcif_disable_rpm(struct device *dev) { - pm_runtime_disable(rpc->dev); + pm_runtime_disable(dev); } #endif // __RENESAS_RPC_IF_H From a0222dbbf645c91e50a26495c729f4e2f3cf12ec Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 23 Nov 2022 15:41:22 +0100 Subject: [PATCH 091/118] memory: renesas-rpc-if: Remove Runtime PM wrappers [ Upstream commit 27e5f98c30d73cdb8c8baeaf7d0af19af5266d3a ] Now the rpcif_{en,dis}able_rpm() wrappers just take a pointer to a device structure, there is no point in keeping them. Remove them, and update the callers to call Runtime PM directly. Signed-off-by: Geert Uytterhoeven Acked-by: Wolfram Sang Link: https://lore.kernel.org/r/d87aa5d7e4a39b18f7e2e0649fee0a45b45d371f.1669213027.git.geert+renesas@glider.be Signed-off-by: Krzysztof Kozlowski Stable-dep-of: 7d189579a287 ("mtd: hyperbus: rpc-if: Add missing MODULE_DEVICE_TABLE") Signed-off-by: Sasha Levin --- drivers/mtd/hyperbus/rpc-if.c | 6 +++--- drivers/spi/spi-rpc-if.c | 6 +++--- include/memory/renesas-rpc-if.h | 10 ---------- 3 files changed, 6 insertions(+), 16 deletions(-) diff --git a/drivers/mtd/hyperbus/rpc-if.c b/drivers/mtd/hyperbus/rpc-if.c index 41734e337ac0..ef32fca5f785 100644 --- a/drivers/mtd/hyperbus/rpc-if.c +++ b/drivers/mtd/hyperbus/rpc-if.c @@ -130,7 +130,7 @@ static int rpcif_hb_probe(struct platform_device *pdev) platform_set_drvdata(pdev, hyperbus); - rpcif_enable_rpm(hyperbus->rpc.dev); + pm_runtime_enable(hyperbus->rpc.dev); error = rpcif_hw_init(hyperbus->rpc.dev, true); if (error) @@ -150,7 +150,7 @@ static int rpcif_hb_probe(struct platform_device *pdev) return 0; out_disable_rpm: - rpcif_disable_rpm(hyperbus->rpc.dev); + pm_runtime_disable(hyperbus->rpc.dev); return error; } @@ -160,7 +160,7 @@ static int rpcif_hb_remove(struct platform_device *pdev) hyperbus_unregister_device(&hyperbus->hbdev); - rpcif_disable_rpm(hyperbus->rpc.dev); + pm_runtime_disable(hyperbus->rpc.dev); return 0; } diff --git a/drivers/spi/spi-rpc-if.c b/drivers/spi/spi-rpc-if.c index 5063587d2c72..ec0904faf3a1 100644 --- a/drivers/spi/spi-rpc-if.c +++ b/drivers/spi/spi-rpc-if.c @@ -147,7 +147,7 @@ static int rpcif_spi_probe(struct platform_device *pdev) ctlr->dev.of_node = parent->of_node; - rpcif_enable_rpm(rpc->dev); + pm_runtime_enable(rpc->dev); ctlr->num_chipselect = 1; ctlr->mem_ops = &rpcif_spi_mem_ops; @@ -169,7 +169,7 @@ static int rpcif_spi_probe(struct platform_device *pdev) return 0; out_disable_rpm: - rpcif_disable_rpm(rpc->dev); + pm_runtime_disable(rpc->dev); return error; } @@ -179,7 +179,7 @@ static int rpcif_spi_remove(struct platform_device *pdev) struct rpcif *rpc = spi_controller_get_devdata(ctlr); spi_unregister_controller(ctlr); - rpcif_disable_rpm(rpc->dev); + pm_runtime_disable(rpc->dev); return 0; } diff --git a/include/memory/renesas-rpc-if.h b/include/memory/renesas-rpc-if.h index d2130c2c8c82..b1b6d9126b03 100644 --- a/include/memory/renesas-rpc-if.h +++ b/include/memory/renesas-rpc-if.h @@ -75,14 +75,4 @@ void rpcif_prepare(struct device *dev, const struct rpcif_op *op, u64 *offs, int rpcif_manual_xfer(struct device *dev); ssize_t rpcif_dirmap_read(struct device *dev, u64 offs, size_t len, void *buf); -static inline void rpcif_enable_rpm(struct device *dev) -{ - pm_runtime_enable(dev); -} - -static inline void rpcif_disable_rpm(struct device *dev) -{ - pm_runtime_disable(dev); -} - #endif // __RENESAS_RPC_IF_H From dff61d85bc979b12dfd6a7cf78d06a80472ec9de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 8 Oct 2023 22:01:33 +0200 Subject: [PATCH 092/118] mtd: hyperbus: rpc-if: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit baaa90c1c923ff2412fae0162eb66d036fd3be6b ] The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Miquel Raynal Acked-by: Tudor Ambarus Link: https://lore.kernel.org/linux-mtd/20231008200143.196369-11-u.kleine-koenig@pengutronix.de Stable-dep-of: 7d189579a287 ("mtd: hyperbus: rpc-if: Add missing MODULE_DEVICE_TABLE") Signed-off-by: Sasha Levin --- drivers/mtd/hyperbus/rpc-if.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/hyperbus/rpc-if.c b/drivers/mtd/hyperbus/rpc-if.c index ef32fca5f785..b22aa57119f2 100644 --- a/drivers/mtd/hyperbus/rpc-if.c +++ b/drivers/mtd/hyperbus/rpc-if.c @@ -154,20 +154,18 @@ out_disable_rpm: return error; } -static int rpcif_hb_remove(struct platform_device *pdev) +static void rpcif_hb_remove(struct platform_device *pdev) { struct rpcif_hyperbus *hyperbus = platform_get_drvdata(pdev); hyperbus_unregister_device(&hyperbus->hbdev); pm_runtime_disable(hyperbus->rpc.dev); - - return 0; } static struct platform_driver rpcif_platform_driver = { .probe = rpcif_hb_probe, - .remove = rpcif_hb_remove, + .remove_new = rpcif_hb_remove, .driver = { .name = "rpc-if-hyperflash", }, From 57d385c07fd410a9631cd87b6b73e0dc1f3cab87 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Wed, 31 Jul 2024 09:08:40 +0100 Subject: [PATCH 093/118] mtd: hyperbus: rpc-if: Add missing MODULE_DEVICE_TABLE [ Upstream commit 7d189579a287d5c568db623c5fc2344cce98a887 ] The rpc-if-hyperflash driver can be compiled as a module, but lacks MODULE_DEVICE_TABLE() and will therefore not be loaded automatically. Fix this. Fixes: 5de15b610f78 ("mtd: hyperbus: add Renesas RPC-IF driver") Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Reviewed-by: Vignesh Raghavendra Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20240731080846.257139-1-biju.das.jz@bp.renesas.com Signed-off-by: Sasha Levin --- drivers/mtd/hyperbus/rpc-if.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/mtd/hyperbus/rpc-if.c b/drivers/mtd/hyperbus/rpc-if.c index b22aa57119f2..e7a28f3316c3 100644 --- a/drivers/mtd/hyperbus/rpc-if.c +++ b/drivers/mtd/hyperbus/rpc-if.c @@ -163,9 +163,16 @@ static void rpcif_hb_remove(struct platform_device *pdev) pm_runtime_disable(hyperbus->rpc.dev); } +static const struct platform_device_id rpc_if_hyperflash_id_table[] = { + { .name = "rpc-if-hyperflash" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, rpc_if_hyperflash_id_table); + static struct platform_driver rpcif_platform_driver = { .probe = rpcif_hb_probe, .remove_new = rpcif_hb_remove, + .id_table = rpc_if_hyperflash_id_table, .driver = { .name = "rpc-if-hyperflash", }, From 24cbc37e837fd9e31e5024480b779207d1d99f1d Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 1 Oct 2024 22:31:49 +0200 Subject: [PATCH 094/118] mtd: rawnand: atmel: Fix possible memory leak [ Upstream commit 6d734f1bfc336aaea91313a5632f2f197608fadd ] The pmecc "user" structure is allocated in atmel_pmecc_create_user() and was supposed to be freed with atmel_pmecc_destroy_user(), but this other helper is never called. One solution would be to find the proper location to call the destructor, but the trend today is to switch to device managed allocations, which in this case fits pretty well. Replace kzalloc() by devm_kzalloc() and drop the destructor entirely. Reported-by: "Dr. David Alan Gilbert" Closes: https://lore.kernel.org/all/ZvmIvRJCf6VhHvpo@gallifrey/ Fixes: f88fc122cc34 ("mtd: nand: Cleanup/rework the atmel_nand driver") Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20241001203149.387655-1-miquel.raynal@bootlin.com Signed-off-by: Sasha Levin --- drivers/mtd/nand/raw/atmel/pmecc.c | 8 +------- drivers/mtd/nand/raw/atmel/pmecc.h | 2 -- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/mtd/nand/raw/atmel/pmecc.c b/drivers/mtd/nand/raw/atmel/pmecc.c index 4d7dc8a9c373..a22aab4ed4e8 100644 --- a/drivers/mtd/nand/raw/atmel/pmecc.c +++ b/drivers/mtd/nand/raw/atmel/pmecc.c @@ -362,7 +362,7 @@ atmel_pmecc_create_user(struct atmel_pmecc *pmecc, size = ALIGN(size, sizeof(s32)); size += (req->ecc.strength + 1) * sizeof(s32) * 3; - user = kzalloc(size, GFP_KERNEL); + user = devm_kzalloc(pmecc->dev, size, GFP_KERNEL); if (!user) return ERR_PTR(-ENOMEM); @@ -408,12 +408,6 @@ atmel_pmecc_create_user(struct atmel_pmecc *pmecc, } EXPORT_SYMBOL_GPL(atmel_pmecc_create_user); -void atmel_pmecc_destroy_user(struct atmel_pmecc_user *user) -{ - kfree(user); -} -EXPORT_SYMBOL_GPL(atmel_pmecc_destroy_user); - static int get_strength(struct atmel_pmecc_user *user) { const int *strengths = user->pmecc->caps->strengths; diff --git a/drivers/mtd/nand/raw/atmel/pmecc.h b/drivers/mtd/nand/raw/atmel/pmecc.h index 7851c05126cf..cc0c5af1f4f1 100644 --- a/drivers/mtd/nand/raw/atmel/pmecc.h +++ b/drivers/mtd/nand/raw/atmel/pmecc.h @@ -55,8 +55,6 @@ struct atmel_pmecc *devm_atmel_pmecc_get(struct device *dev); struct atmel_pmecc_user * atmel_pmecc_create_user(struct atmel_pmecc *pmecc, struct atmel_pmecc_user_req *req); -void atmel_pmecc_destroy_user(struct atmel_pmecc_user *user); - void atmel_pmecc_reset(struct atmel_pmecc *pmecc); int atmel_pmecc_enable(struct atmel_pmecc_user *user, int op); void atmel_pmecc_disable(struct atmel_pmecc_user *user); From 4d2655754e94741b159aa807b72ea85518a65fd5 Mon Sep 17 00:00:00 2001 From: "Ritesh Harjani (IBM)" Date: Fri, 18 Oct 2024 22:59:42 +0530 Subject: [PATCH 095/118] powerpc/mm/fault: Fix kfence page fault reporting [ Upstream commit 06dbbb4d5f7126b6307ab807cbf04ecfc459b933 ] copy_from_kernel_nofault() can be called when doing read of /proc/kcore. /proc/kcore can have some unmapped kfence objects which when read via copy_from_kernel_nofault() can cause page faults. Since *_nofault() functions define their own fixup table for handling fault, use that instead of asking kfence to handle such faults. Hence we search the exception tables for the nip which generated the fault. If there is an entry then we let the fixup table handler handle the page fault by returning an error from within ___do_page_fault(). This can be easily triggered if someone tries to do dd from /proc/kcore. eg. dd if=/proc/kcore of=/dev/null bs=1M Some example false negatives: =============================== BUG: KFENCE: invalid read in copy_from_kernel_nofault+0x9c/0x1a0 Invalid read at 0xc0000000fdff0000: copy_from_kernel_nofault+0x9c/0x1a0 0xc00000000665f950 read_kcore_iter+0x57c/0xa04 proc_reg_read_iter+0xe4/0x16c vfs_read+0x320/0x3ec ksys_read+0x90/0x154 system_call_exception+0x120/0x310 system_call_vectored_common+0x15c/0x2ec BUG: KFENCE: use-after-free read in copy_from_kernel_nofault+0x9c/0x1a0 Use-after-free read at 0xc0000000fe050000 (in kfence-#2): copy_from_kernel_nofault+0x9c/0x1a0 0xc00000000665f950 read_kcore_iter+0x57c/0xa04 proc_reg_read_iter+0xe4/0x16c vfs_read+0x320/0x3ec ksys_read+0x90/0x154 system_call_exception+0x120/0x310 system_call_vectored_common+0x15c/0x2ec Fixes: 90cbac0e995d ("powerpc: Enable KFENCE for PPC32") Suggested-by: Christophe Leroy Reported-by: Disha Goel Signed-off-by: Ritesh Harjani (IBM) Reviewed-by: Christophe Leroy Signed-off-by: Michael Ellerman Link: https://patch.msgid.link/a411788081d50e3b136c6270471e35aba3dfafa3.1729271995.git.ritesh.list@gmail.com Signed-off-by: Sasha Levin --- arch/powerpc/mm/fault.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 644e4ec6ce99..4b59315cb820 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -431,10 +431,16 @@ static int ___do_page_fault(struct pt_regs *regs, unsigned long address, /* * The kernel should never take an execute fault nor should it * take a page fault to a kernel address or a page fault to a user - * address outside of dedicated places + * address outside of dedicated places. + * + * Rather than kfence directly reporting false negatives, search whether + * the NIP belongs to the fixup table for cases where fault could come + * from functions like copy_from_kernel_nofault(). */ if (unlikely(!is_user && bad_kernel_fault(regs, error_code, address, is_write))) { - if (kfence_handle_page_fault(address, is_write, regs)) + if (is_kfence_address((void *)address) && + !search_exception_tables(instruction_pointer(regs)) && + kfence_handle_page_fault(address, is_write, regs)) return 0; return SIGSEGV; From fa5b5ea257135e771b489c83a2e93b5935d0108e Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 19 Aug 2024 22:24:01 +1000 Subject: [PATCH 096/118] powerpc/pseries: Fix dtl_access_lock to be a rw_semaphore [ Upstream commit cadae3a45d23aa4f6485938a67cbc47aaaa25e38 ] The dtl_access_lock needs to be a rw_sempahore, a sleeping lock, because the code calls kmalloc() while holding it, which can sleep: # echo 1 > /proc/powerpc/vcpudispatch_stats BUG: sleeping function called from invalid context at include/linux/sched/mm.h:337 in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 199, name: sh preempt_count: 1, expected: 0 3 locks held by sh/199: #0: c00000000a0743f8 (sb_writers#3){.+.+}-{0:0}, at: vfs_write+0x324/0x438 #1: c0000000028c7058 (dtl_enable_mutex){+.+.}-{3:3}, at: vcpudispatch_stats_write+0xd4/0x5f4 #2: c0000000028c70b8 (dtl_access_lock){+.+.}-{2:2}, at: vcpudispatch_stats_write+0x220/0x5f4 CPU: 0 PID: 199 Comm: sh Not tainted 6.10.0-rc4 #152 Hardware name: IBM pSeries (emulated by qemu) POWER9 (raw) 0x4e1202 0xf000005 of:SLOF,HEAD hv:linux,kvm pSeries Call Trace: dump_stack_lvl+0x130/0x148 (unreliable) __might_resched+0x174/0x410 kmem_cache_alloc_noprof+0x340/0x3d0 alloc_dtl_buffers+0x124/0x1ac vcpudispatch_stats_write+0x2a8/0x5f4 proc_reg_write+0xf4/0x150 vfs_write+0xfc/0x438 ksys_write+0x88/0x148 system_call_exception+0x1c4/0x5a0 system_call_common+0xf4/0x258 Fixes: 06220d78f24a ("powerpc/pseries: Introduce rwlock to gatekeep DTLB usage") Tested-by: Kajol Jain Reviewed-by: Nysal Jan K.A Reviewed-by: Kajol Jain Signed-off-by: Michael Ellerman Link: https://patch.msgid.link/20240819122401.513203-1-mpe@ellerman.id.au Signed-off-by: Sasha Levin --- arch/powerpc/include/asm/dtl.h | 4 ++-- arch/powerpc/platforms/pseries/dtl.c | 8 ++++---- arch/powerpc/platforms/pseries/lpar.c | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/include/asm/dtl.h b/arch/powerpc/include/asm/dtl.h index 4bcb9f9ac764..859af5de3c2f 100644 --- a/arch/powerpc/include/asm/dtl.h +++ b/arch/powerpc/include/asm/dtl.h @@ -1,8 +1,8 @@ #ifndef _ASM_POWERPC_DTL_H #define _ASM_POWERPC_DTL_H +#include #include -#include /* * Layout of entries in the hypervisor's dispatch trace log buffer. @@ -35,7 +35,7 @@ struct dtl_entry { #define DTL_LOG_ALL (DTL_LOG_CEDE | DTL_LOG_PREEMPT | DTL_LOG_FAULT) extern struct kmem_cache *dtl_cache; -extern rwlock_t dtl_access_lock; +extern struct rw_semaphore dtl_access_lock; extern void register_dtl_buffer(int cpu); extern void alloc_dtl_buffers(unsigned long *time_limit); diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c index 3f1cdccebc9c..ecc04ef8c53e 100644 --- a/arch/powerpc/platforms/pseries/dtl.c +++ b/arch/powerpc/platforms/pseries/dtl.c @@ -191,7 +191,7 @@ static int dtl_enable(struct dtl *dtl) return -EBUSY; /* ensure there are no other conflicting dtl users */ - if (!read_trylock(&dtl_access_lock)) + if (!down_read_trylock(&dtl_access_lock)) return -EBUSY; n_entries = dtl_buf_entries; @@ -199,7 +199,7 @@ static int dtl_enable(struct dtl *dtl) if (!buf) { printk(KERN_WARNING "%s: buffer alloc failed for cpu %d\n", __func__, dtl->cpu); - read_unlock(&dtl_access_lock); + up_read(&dtl_access_lock); return -ENOMEM; } @@ -217,7 +217,7 @@ static int dtl_enable(struct dtl *dtl) spin_unlock(&dtl->lock); if (rc) { - read_unlock(&dtl_access_lock); + up_read(&dtl_access_lock); kmem_cache_free(dtl_cache, buf); } @@ -232,7 +232,7 @@ static void dtl_disable(struct dtl *dtl) dtl->buf = NULL; dtl->buf_entries = 0; spin_unlock(&dtl->lock); - read_unlock(&dtl_access_lock); + up_read(&dtl_access_lock); } /* file interface */ diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 29d235b02f06..98f8e0a39eb2 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -167,7 +167,7 @@ struct vcpu_dispatch_data { */ #define NR_CPUS_H NR_CPUS -DEFINE_RWLOCK(dtl_access_lock); +DECLARE_RWSEM(dtl_access_lock); static DEFINE_PER_CPU(struct vcpu_dispatch_data, vcpu_disp_data); static DEFINE_PER_CPU(u64, dtl_entry_ridx); static DEFINE_PER_CPU(struct dtl_worker, dtl_workers); @@ -461,7 +461,7 @@ static int dtl_worker_enable(unsigned long *time_limit) { int rc = 0, state; - if (!write_trylock(&dtl_access_lock)) { + if (!down_write_trylock(&dtl_access_lock)) { rc = -EBUSY; goto out; } @@ -477,7 +477,7 @@ static int dtl_worker_enable(unsigned long *time_limit) pr_err("vcpudispatch_stats: unable to setup workqueue for DTL processing\n"); free_dtl_buffers(time_limit); reset_global_dtl_mask(); - write_unlock(&dtl_access_lock); + up_write(&dtl_access_lock); rc = -EINVAL; goto out; } @@ -492,7 +492,7 @@ static void dtl_worker_disable(unsigned long *time_limit) cpuhp_remove_state(dtl_worker_state); free_dtl_buffers(time_limit); reset_global_dtl_mask(); - write_unlock(&dtl_access_lock); + up_write(&dtl_access_lock); } static ssize_t vcpudispatch_stats_write(struct file *file, const char __user *p, From a357b63fd21e4b2791008c2175ba7a8c235ebce1 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Wed, 30 Oct 2024 09:20:19 +0800 Subject: [PATCH 097/118] cpufreq: CPPC: Fix possible null-ptr-deref for cpufreq_cpu_get_raw() [ Upstream commit a78e7207564258db6e373e86294a85f9d646d35a ] cpufreq_cpu_get_raw() may return NULL if the cpu is not in policy->cpus cpu mask and it will cause null pointer dereference. Fixes: 740fcdc2c20e ("cpufreq: CPPC: Register EM based on efficiency class information") Signed-off-by: Jinjie Ruan Signed-off-by: Viresh Kumar Signed-off-by: Sasha Levin --- drivers/cpufreq/cppc_cpufreq.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index 0050242d382e..d8c8363167a7 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -422,6 +422,9 @@ static int cppc_get_cpu_power(struct device *cpu_dev, struct cppc_cpudata *cpu_data; policy = cpufreq_cpu_get_raw(cpu_dev->id); + if (!policy) + return 0; + cpu_data = policy->driver_data; perf_caps = &cpu_data->perf_caps; max_cap = arch_scale_cpu_capacity(cpu_dev->id); From 1975b481f644f8f841d9c188e3c214fce187f18b Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Wed, 30 Oct 2024 16:24:49 +0800 Subject: [PATCH 098/118] cpufreq: CPPC: Fix possible null-ptr-deref for cppc_get_cpu_cost() [ Upstream commit 1a1374bb8c5926674973d849feed500bc61ad535 ] cpufreq_cpu_get_raw() may return NULL if the cpu is not in policy->cpus cpu mask and it will cause null pointer dereference, so check NULL for cppc_get_cpu_cost(). Fixes: 740fcdc2c20e ("cpufreq: CPPC: Register EM based on efficiency class information") Signed-off-by: Jinjie Ruan Signed-off-by: Viresh Kumar Signed-off-by: Sasha Levin --- drivers/cpufreq/cppc_cpufreq.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index d8c8363167a7..0a2c21d5bc1c 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -492,6 +492,9 @@ static int cppc_get_cpu_cost(struct device *cpu_dev, unsigned long KHz, int step; policy = cpufreq_cpu_get_raw(cpu_dev->id); + if (!policy) + return 0; + cpu_data = policy->driver_data; perf_caps = &cpu_data->perf_caps; max_cap = arch_scale_cpu_capacity(cpu_dev->id); From 503d9576795466b1f376ae2e8315278b732e31d4 Mon Sep 17 00:00:00 2001 From: wenglianfa Date: Thu, 24 Oct 2024 20:39:56 +0800 Subject: [PATCH 099/118] RDMA/hns: Fix an AEQE overflow error caused by untimely update of eq_db_ci [ Upstream commit 571e4ab8a45e530623ab129803f090a844dd3fe9 ] eq_db_ci is updated only after all AEQEs are processed in the AEQ interrupt handler, which is not timely enough and may result in AEQ overflow. Two optimization methods are proposed: 1. Set an upper limit for AEQE processing. 2. Move time-consuming operations such as printings to the bottom half of the interrupt. cmd events and flush_cqe events are still fully processed in the top half to ensure timely handling. Fixes: a5073d6054f7 ("RDMA/hns: Add eq support of hip08") Signed-off-by: wenglianfa Signed-off-by: Junxian Huang Link: https://patch.msgid.link/20241024124000.2931869-2-huangjunxian6@hisilicon.com Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/hns/hns_roce_device.h | 1 + drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 75 ++++++++++++++------- drivers/infiniband/hw/hns/hns_roce_hw_v2.h | 5 ++ drivers/infiniband/hw/hns/hns_roce_qp.c | 56 +++++++++------ 4 files changed, 92 insertions(+), 45 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index a2bdfa026c56..5b8b68b2d69c 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -1228,6 +1228,7 @@ void hns_roce_cq_completion(struct hns_roce_dev *hr_dev, u32 cqn); void hns_roce_cq_event(struct hns_roce_dev *hr_dev, u32 cqn, int event_type); void flush_cqe(struct hns_roce_dev *dev, struct hns_roce_qp *qp); void hns_roce_qp_event(struct hns_roce_dev *hr_dev, u32 qpn, int event_type); +void hns_roce_flush_cqe(struct hns_roce_dev *hr_dev, u32 qpn); void hns_roce_srq_event(struct hns_roce_dev *hr_dev, u32 srqn, int event_type); u8 hns_get_gid_index(struct hns_roce_dev *hr_dev, u32 port, int gid_index); void hns_roce_handle_device_err(struct hns_roce_dev *hr_dev); diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 56c0e87c494e..8b371d6ecbac 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -5977,11 +5977,10 @@ err_mailbox: return ret; } -static void hns_roce_irq_work_handle(struct work_struct *work) +static void dump_aeqe_log(struct hns_roce_work *irq_work) { - struct hns_roce_work *irq_work = - container_of(work, struct hns_roce_work, work); - struct ib_device *ibdev = &irq_work->hr_dev->ib_dev; + struct hns_roce_dev *hr_dev = irq_work->hr_dev; + struct ib_device *ibdev = &hr_dev->ib_dev; switch (irq_work->event_type) { case HNS_ROCE_EVENT_TYPE_PATH_MIG: @@ -6025,6 +6024,8 @@ static void hns_roce_irq_work_handle(struct work_struct *work) case HNS_ROCE_EVENT_TYPE_DB_OVERFLOW: ibdev_warn(ibdev, "DB overflow.\n"); break; + case HNS_ROCE_EVENT_TYPE_MB: + break; case HNS_ROCE_EVENT_TYPE_FLR: ibdev_warn(ibdev, "function level reset.\n"); break; @@ -6035,8 +6036,46 @@ static void hns_roce_irq_work_handle(struct work_struct *work) ibdev_err(ibdev, "invalid xrceth error.\n"); break; default: + ibdev_info(ibdev, "Undefined event %d.\n", + irq_work->event_type); break; } +} + +static void hns_roce_irq_work_handle(struct work_struct *work) +{ + struct hns_roce_work *irq_work = + container_of(work, struct hns_roce_work, work); + struct hns_roce_dev *hr_dev = irq_work->hr_dev; + int event_type = irq_work->event_type; + u32 queue_num = irq_work->queue_num; + + switch (event_type) { + case HNS_ROCE_EVENT_TYPE_PATH_MIG: + case HNS_ROCE_EVENT_TYPE_PATH_MIG_FAILED: + case HNS_ROCE_EVENT_TYPE_COMM_EST: + case HNS_ROCE_EVENT_TYPE_SQ_DRAINED: + case HNS_ROCE_EVENT_TYPE_WQ_CATAS_ERROR: + case HNS_ROCE_EVENT_TYPE_SRQ_LAST_WQE_REACH: + case HNS_ROCE_EVENT_TYPE_INV_REQ_LOCAL_WQ_ERROR: + case HNS_ROCE_EVENT_TYPE_LOCAL_WQ_ACCESS_ERROR: + case HNS_ROCE_EVENT_TYPE_XRCD_VIOLATION: + case HNS_ROCE_EVENT_TYPE_INVALID_XRCETH: + hns_roce_qp_event(hr_dev, queue_num, event_type); + break; + case HNS_ROCE_EVENT_TYPE_SRQ_LIMIT_REACH: + case HNS_ROCE_EVENT_TYPE_SRQ_CATAS_ERROR: + hns_roce_srq_event(hr_dev, queue_num, event_type); + break; + case HNS_ROCE_EVENT_TYPE_CQ_ACCESS_ERROR: + case HNS_ROCE_EVENT_TYPE_CQ_OVERFLOW: + hns_roce_cq_event(hr_dev, queue_num, event_type); + break; + default: + break; + } + + dump_aeqe_log(irq_work); kfree(irq_work); } @@ -6097,14 +6136,14 @@ static struct hns_roce_aeqe *next_aeqe_sw_v2(struct hns_roce_eq *eq) static irqreturn_t hns_roce_v2_aeq_int(struct hns_roce_dev *hr_dev, struct hns_roce_eq *eq) { - struct device *dev = hr_dev->dev; struct hns_roce_aeqe *aeqe = next_aeqe_sw_v2(eq); irqreturn_t aeqe_found = IRQ_NONE; + int num_aeqes = 0; int event_type; u32 queue_num; int sub_type; - while (aeqe) { + while (aeqe && num_aeqes < HNS_AEQ_POLLING_BUDGET) { /* Make sure we read AEQ entry after we have checked the * ownership bit */ @@ -6115,25 +6154,12 @@ static irqreturn_t hns_roce_v2_aeq_int(struct hns_roce_dev *hr_dev, queue_num = hr_reg_read(aeqe, AEQE_EVENT_QUEUE_NUM); switch (event_type) { - case HNS_ROCE_EVENT_TYPE_PATH_MIG: - case HNS_ROCE_EVENT_TYPE_PATH_MIG_FAILED: - case HNS_ROCE_EVENT_TYPE_COMM_EST: - case HNS_ROCE_EVENT_TYPE_SQ_DRAINED: case HNS_ROCE_EVENT_TYPE_WQ_CATAS_ERROR: - case HNS_ROCE_EVENT_TYPE_SRQ_LAST_WQE_REACH: case HNS_ROCE_EVENT_TYPE_INV_REQ_LOCAL_WQ_ERROR: case HNS_ROCE_EVENT_TYPE_LOCAL_WQ_ACCESS_ERROR: case HNS_ROCE_EVENT_TYPE_XRCD_VIOLATION: case HNS_ROCE_EVENT_TYPE_INVALID_XRCETH: - hns_roce_qp_event(hr_dev, queue_num, event_type); - break; - case HNS_ROCE_EVENT_TYPE_SRQ_LIMIT_REACH: - case HNS_ROCE_EVENT_TYPE_SRQ_CATAS_ERROR: - hns_roce_srq_event(hr_dev, queue_num, event_type); - break; - case HNS_ROCE_EVENT_TYPE_CQ_ACCESS_ERROR: - case HNS_ROCE_EVENT_TYPE_CQ_OVERFLOW: - hns_roce_cq_event(hr_dev, queue_num, event_type); + hns_roce_flush_cqe(hr_dev, queue_num); break; case HNS_ROCE_EVENT_TYPE_MB: hns_roce_cmd_event(hr_dev, @@ -6141,12 +6167,7 @@ static irqreturn_t hns_roce_v2_aeq_int(struct hns_roce_dev *hr_dev, aeqe->event.cmd.status, le64_to_cpu(aeqe->event.cmd.out_param)); break; - case HNS_ROCE_EVENT_TYPE_DB_OVERFLOW: - case HNS_ROCE_EVENT_TYPE_FLR: - break; default: - dev_err(dev, "unhandled event %d on EQ %d at idx %u.\n", - event_type, eq->eqn, eq->cons_index); break; } @@ -6158,6 +6179,7 @@ static irqreturn_t hns_roce_v2_aeq_int(struct hns_roce_dev *hr_dev, hns_roce_v2_init_irq_work(hr_dev, eq, queue_num); aeqe = next_aeqe_sw_v2(eq); + ++num_aeqes; } update_eq_db(eq); @@ -6687,6 +6709,9 @@ static int hns_roce_v2_init_eq_table(struct hns_roce_dev *hr_dev) int ret; int i; + if (hr_dev->caps.aeqe_depth < HNS_AEQ_POLLING_BUDGET) + return -EINVAL; + other_num = hr_dev->caps.num_other_vectors; comp_num = hr_dev->caps.num_comp_vectors; aeq_num = hr_dev->caps.num_aeq_vectors; diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h index 2b4dbbb06eb5..e24ddbcafe0f 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h @@ -114,6 +114,11 @@ #define HNS_ROCE_V2_TABLE_CHUNK_SIZE (1 << 18) +/* budget must be smaller than aeqe_depth to guarantee that we update + * the ci before we polled all the entries in the EQ. + */ +#define HNS_AEQ_POLLING_BUDGET 64 + enum { HNS_ROCE_CMD_FLAG_IN = BIT(0), HNS_ROCE_CMD_FLAG_OUT = BIT(1), diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c index e158ed9e6c83..7af663176104 100644 --- a/drivers/infiniband/hw/hns/hns_roce_qp.c +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c @@ -39,6 +39,25 @@ #include "hns_roce_device.h" #include "hns_roce_hem.h" +static struct hns_roce_qp *hns_roce_qp_lookup(struct hns_roce_dev *hr_dev, + u32 qpn) +{ + struct device *dev = hr_dev->dev; + struct hns_roce_qp *qp; + unsigned long flags; + + xa_lock_irqsave(&hr_dev->qp_table_xa, flags); + qp = __hns_roce_qp_lookup(hr_dev, qpn); + if (qp) + refcount_inc(&qp->refcount); + xa_unlock_irqrestore(&hr_dev->qp_table_xa, flags); + + if (!qp) + dev_warn(dev, "async event for bogus QP %08x\n", qpn); + + return qp; +} + static void flush_work_handle(struct work_struct *work) { struct hns_roce_work *flush_work = container_of(work, @@ -95,29 +114,11 @@ void flush_cqe(struct hns_roce_dev *dev, struct hns_roce_qp *qp) void hns_roce_qp_event(struct hns_roce_dev *hr_dev, u32 qpn, int event_type) { - struct device *dev = hr_dev->dev; struct hns_roce_qp *qp; - xa_lock(&hr_dev->qp_table_xa); - qp = __hns_roce_qp_lookup(hr_dev, qpn); - if (qp) - refcount_inc(&qp->refcount); - xa_unlock(&hr_dev->qp_table_xa); - - if (!qp) { - dev_warn(dev, "async event for bogus QP %08x\n", qpn); + qp = hns_roce_qp_lookup(hr_dev, qpn); + if (!qp) return; - } - - if (event_type == HNS_ROCE_EVENT_TYPE_WQ_CATAS_ERROR || - event_type == HNS_ROCE_EVENT_TYPE_INV_REQ_LOCAL_WQ_ERROR || - event_type == HNS_ROCE_EVENT_TYPE_LOCAL_WQ_ACCESS_ERROR || - event_type == HNS_ROCE_EVENT_TYPE_XRCD_VIOLATION || - event_type == HNS_ROCE_EVENT_TYPE_INVALID_XRCETH) { - qp->state = IB_QPS_ERR; - - flush_cqe(hr_dev, qp); - } qp->event(qp, (enum hns_roce_event)event_type); @@ -125,6 +126,21 @@ void hns_roce_qp_event(struct hns_roce_dev *hr_dev, u32 qpn, int event_type) complete(&qp->free); } +void hns_roce_flush_cqe(struct hns_roce_dev *hr_dev, u32 qpn) +{ + struct hns_roce_qp *qp; + + qp = hns_roce_qp_lookup(hr_dev, qpn); + if (!qp) + return; + + qp->state = IB_QPS_ERR; + flush_cqe(hr_dev, qp); + + if (refcount_dec_and_test(&qp->refcount)) + complete(&qp->free); +} + static void hns_roce_ib_qp_event(struct hns_roce_qp *hr_qp, enum hns_roce_event type) { From 9f42b87d0f5bb560515aa11707552395bae01957 Mon Sep 17 00:00:00 2001 From: Chengchang Tang Date: Tue, 23 May 2023 20:16:41 +0800 Subject: [PATCH 100/118] RDMA/hns: Add clear_hem return value to log [ Upstream commit a519a612a71848b69b70b18b4d14d165b2d8aaf7 ] Log return value of clear_hem() to help diagnose. Link: https://lore.kernel.org/r/20230523121641.3132102-4-huangjunxian6@hisilicon.com Signed-off-by: Chengchang Tang Signed-off-by: Junxian Huang Signed-off-by: Jason Gunthorpe Stable-dep-of: d81fb6511abf ("RDMA/hns: Use dev_* printings in hem code instead of ibdev_*") Signed-off-by: Sasha Levin --- drivers/infiniband/hw/hns/hns_roce_hem.c | 42 ++++++++++++++++-------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hem.c b/drivers/infiniband/hw/hns/hns_roce_hem.c index 2c8f0fd9557d..d0f338ff78df 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hem.c +++ b/drivers/infiniband/hw/hns/hns_roce_hem.c @@ -619,6 +619,7 @@ static void clear_mhop_hem(struct hns_roce_dev *hr_dev, u32 hop_num = mhop->hop_num; u32 chunk_ba_num; u32 step_idx; + int ret; index->inited = HEM_INDEX_BUF; chunk_ba_num = mhop->bt_chunk_size / BA_BYTE_LEN; @@ -642,16 +643,24 @@ static void clear_mhop_hem(struct hns_roce_dev *hr_dev, else step_idx = hop_num; - if (hr_dev->hw->clear_hem(hr_dev, table, obj, step_idx)) - ibdev_warn(ibdev, "failed to clear hop%u HEM.\n", hop_num); + ret = hr_dev->hw->clear_hem(hr_dev, table, obj, step_idx); + if (ret) + ibdev_warn(ibdev, "failed to clear hop%u HEM, ret = %d.\n", + hop_num, ret); - if (index->inited & HEM_INDEX_L1) - if (hr_dev->hw->clear_hem(hr_dev, table, obj, 1)) - ibdev_warn(ibdev, "failed to clear HEM step 1.\n"); + if (index->inited & HEM_INDEX_L1) { + ret = hr_dev->hw->clear_hem(hr_dev, table, obj, 1); + if (ret) + ibdev_warn(ibdev, "failed to clear HEM step 1, ret = %d.\n", + ret); + } - if (index->inited & HEM_INDEX_L0) - if (hr_dev->hw->clear_hem(hr_dev, table, obj, 0)) - ibdev_warn(ibdev, "failed to clear HEM step 0.\n"); + if (index->inited & HEM_INDEX_L0) { + ret = hr_dev->hw->clear_hem(hr_dev, table, obj, 0); + if (ret) + ibdev_warn(ibdev, "failed to clear HEM step 0, ret = %d.\n", + ret); + } } } @@ -688,6 +697,7 @@ void hns_roce_table_put(struct hns_roce_dev *hr_dev, { struct device *dev = hr_dev->dev; unsigned long i; + int ret; if (hns_roce_check_whether_mhop(hr_dev, table->type)) { hns_roce_table_mhop_put(hr_dev, table, obj, 1); @@ -700,8 +710,10 @@ void hns_roce_table_put(struct hns_roce_dev *hr_dev, &table->mutex)) return; - if (hr_dev->hw->clear_hem(hr_dev, table, obj, HEM_HOP_STEP_DIRECT)) - dev_warn(dev, "failed to clear HEM base address.\n"); + ret = hr_dev->hw->clear_hem(hr_dev, table, obj, HEM_HOP_STEP_DIRECT); + if (ret) + dev_warn(dev, "failed to clear HEM base address, ret = %d.\n", + ret); hns_roce_free_hem(hr_dev, table->hem[i]); table->hem[i] = NULL; @@ -917,6 +929,8 @@ void hns_roce_cleanup_hem_table(struct hns_roce_dev *hr_dev, { struct device *dev = hr_dev->dev; unsigned long i; + int obj; + int ret; if (hns_roce_check_whether_mhop(hr_dev, table->type)) { hns_roce_cleanup_mhop_hem_table(hr_dev, table); @@ -925,9 +939,11 @@ void hns_roce_cleanup_hem_table(struct hns_roce_dev *hr_dev, for (i = 0; i < table->num_hem; ++i) if (table->hem[i]) { - if (hr_dev->hw->clear_hem(hr_dev, table, - i * table->table_chunk_size / table->obj_size, 0)) - dev_err(dev, "clear HEM base address failed.\n"); + obj = i * table->table_chunk_size / table->obj_size; + ret = hr_dev->hw->clear_hem(hr_dev, table, obj, 0); + if (ret) + dev_err(dev, "clear HEM base address failed, ret = %d.\n", + ret); hns_roce_free_hem(hr_dev, table->hem[i]); } From 7519e81df8f0e26896704c7ada82429f1c0d062d Mon Sep 17 00:00:00 2001 From: Junxian Huang Date: Thu, 24 Oct 2024 20:39:59 +0800 Subject: [PATCH 101/118] RDMA/hns: Use dev_* printings in hem code instead of ibdev_* [ Upstream commit d81fb6511abf18591befaa5f4a972ffc838690ec ] The hem code is executed before ib_dev is registered, so use dev_* printing instead of ibdev_* to avoid log like this: (null): set HEM address to HW failed! Fixes: 2f49de21f3e9 ("RDMA/hns: Optimize mhop get flow for multi-hop addressing") Signed-off-by: Junxian Huang Link: https://patch.msgid.link/20241024124000.2931869-5-huangjunxian6@hisilicon.com Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/hns/hns_roce_hem.c | 44 ++++++++++++------------ 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hem.c b/drivers/infiniband/hw/hns/hns_roce_hem.c index d0f338ff78df..d1b00bb389d9 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hem.c +++ b/drivers/infiniband/hw/hns/hns_roce_hem.c @@ -337,7 +337,7 @@ static int calc_hem_config(struct hns_roce_dev *hr_dev, struct hns_roce_hem_mhop *mhop, struct hns_roce_hem_index *index) { - struct ib_device *ibdev = &hr_dev->ib_dev; + struct device *dev = hr_dev->dev; unsigned long mhop_obj = obj; u32 l0_idx, l1_idx, l2_idx; u32 chunk_ba_num; @@ -368,14 +368,14 @@ static int calc_hem_config(struct hns_roce_dev *hr_dev, index->buf = l0_idx; break; default: - ibdev_err(ibdev, "table %u not support mhop.hop_num = %u!\n", - table->type, mhop->hop_num); + dev_err(dev, "table %u not support mhop.hop_num = %u!\n", + table->type, mhop->hop_num); return -EINVAL; } if (unlikely(index->buf >= table->num_hem)) { - ibdev_err(ibdev, "table %u exceed hem limt idx %llu, max %lu!\n", - table->type, index->buf, table->num_hem); + dev_err(dev, "table %u exceed hem limt idx %llu, max %lu!\n", + table->type, index->buf, table->num_hem); return -EINVAL; } @@ -487,14 +487,14 @@ static int set_mhop_hem(struct hns_roce_dev *hr_dev, struct hns_roce_hem_mhop *mhop, struct hns_roce_hem_index *index) { - struct ib_device *ibdev = &hr_dev->ib_dev; + struct device *dev = hr_dev->dev; u32 step_idx; int ret = 0; if (index->inited & HEM_INDEX_L0) { ret = hr_dev->hw->set_hem(hr_dev, table, obj, 0); if (ret) { - ibdev_err(ibdev, "set HEM step 0 failed!\n"); + dev_err(dev, "set HEM step 0 failed!\n"); goto out; } } @@ -502,7 +502,7 @@ static int set_mhop_hem(struct hns_roce_dev *hr_dev, if (index->inited & HEM_INDEX_L1) { ret = hr_dev->hw->set_hem(hr_dev, table, obj, 1); if (ret) { - ibdev_err(ibdev, "set HEM step 1 failed!\n"); + dev_err(dev, "set HEM step 1 failed!\n"); goto out; } } @@ -514,7 +514,7 @@ static int set_mhop_hem(struct hns_roce_dev *hr_dev, step_idx = mhop->hop_num; ret = hr_dev->hw->set_hem(hr_dev, table, obj, step_idx); if (ret) - ibdev_err(ibdev, "set HEM step last failed!\n"); + dev_err(dev, "set HEM step last failed!\n"); } out: return ret; @@ -524,14 +524,14 @@ static int hns_roce_table_mhop_get(struct hns_roce_dev *hr_dev, struct hns_roce_hem_table *table, unsigned long obj) { - struct ib_device *ibdev = &hr_dev->ib_dev; struct hns_roce_hem_index index = {}; struct hns_roce_hem_mhop mhop = {}; + struct device *dev = hr_dev->dev; int ret; ret = calc_hem_config(hr_dev, table, obj, &mhop, &index); if (ret) { - ibdev_err(ibdev, "calc hem config failed!\n"); + dev_err(dev, "calc hem config failed!\n"); return ret; } @@ -543,7 +543,7 @@ static int hns_roce_table_mhop_get(struct hns_roce_dev *hr_dev, ret = alloc_mhop_hem(hr_dev, table, &mhop, &index); if (ret) { - ibdev_err(ibdev, "alloc mhop hem failed!\n"); + dev_err(dev, "alloc mhop hem failed!\n"); goto out; } @@ -551,7 +551,7 @@ static int hns_roce_table_mhop_get(struct hns_roce_dev *hr_dev, if (table->type < HEM_TYPE_MTT) { ret = set_mhop_hem(hr_dev, table, obj, &mhop, &index); if (ret) { - ibdev_err(ibdev, "set HEM address to HW failed!\n"); + dev_err(dev, "set HEM address to HW failed!\n"); goto err_alloc; } } @@ -615,7 +615,7 @@ static void clear_mhop_hem(struct hns_roce_dev *hr_dev, struct hns_roce_hem_mhop *mhop, struct hns_roce_hem_index *index) { - struct ib_device *ibdev = &hr_dev->ib_dev; + struct device *dev = hr_dev->dev; u32 hop_num = mhop->hop_num; u32 chunk_ba_num; u32 step_idx; @@ -645,21 +645,21 @@ static void clear_mhop_hem(struct hns_roce_dev *hr_dev, ret = hr_dev->hw->clear_hem(hr_dev, table, obj, step_idx); if (ret) - ibdev_warn(ibdev, "failed to clear hop%u HEM, ret = %d.\n", - hop_num, ret); + dev_warn(dev, "failed to clear hop%u HEM, ret = %d.\n", + hop_num, ret); if (index->inited & HEM_INDEX_L1) { ret = hr_dev->hw->clear_hem(hr_dev, table, obj, 1); if (ret) - ibdev_warn(ibdev, "failed to clear HEM step 1, ret = %d.\n", - ret); + dev_warn(dev, "failed to clear HEM step 1, ret = %d.\n", + ret); } if (index->inited & HEM_INDEX_L0) { ret = hr_dev->hw->clear_hem(hr_dev, table, obj, 0); if (ret) - ibdev_warn(ibdev, "failed to clear HEM step 0, ret = %d.\n", - ret); + dev_warn(dev, "failed to clear HEM step 0, ret = %d.\n", + ret); } } } @@ -669,14 +669,14 @@ static void hns_roce_table_mhop_put(struct hns_roce_dev *hr_dev, unsigned long obj, int check_refcount) { - struct ib_device *ibdev = &hr_dev->ib_dev; struct hns_roce_hem_index index = {}; struct hns_roce_hem_mhop mhop = {}; + struct device *dev = hr_dev->dev; int ret; ret = calc_hem_config(hr_dev, table, obj, &mhop, &index); if (ret) { - ibdev_err(ibdev, "calc hem config failed!\n"); + dev_err(dev, "calc hem config failed!\n"); return; } From 284a8650dfde5d4ae4e14698d6bcb633e27ab449 Mon Sep 17 00:00:00 2001 From: Junxian Huang Date: Tue, 23 May 2023 20:16:39 +0800 Subject: [PATCH 102/118] RDMA/hns: Remove unnecessary QP type checks [ Upstream commit b9989ab3f61ec459cbaf0a492fea3168bbfa4c7a ] It is not necessary to check the type of the queue on IO path because unsupported QP type cannot be created. Link: https://lore.kernel.org/r/20230523121641.3132102-2-huangjunxian6@hisilicon.com Signed-off-by: Chengchang Tang Signed-off-by: Junxian Huang Signed-off-by: Jason Gunthorpe Stable-dep-of: 323275ac2ff1 ("RDMA/hns: Fix cpu stuck caused by printings during reset") Signed-off-by: Sasha Levin --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 24 +++------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 8b371d6ecbac..b190e0cd86b4 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -373,17 +373,10 @@ static int check_send_valid(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp) { struct ib_device *ibdev = &hr_dev->ib_dev; - struct ib_qp *ibqp = &hr_qp->ibqp; - if (unlikely(ibqp->qp_type != IB_QPT_RC && - ibqp->qp_type != IB_QPT_GSI && - ibqp->qp_type != IB_QPT_UD)) { - ibdev_err(ibdev, "not supported QP(0x%x)type!\n", - ibqp->qp_type); - return -EOPNOTSUPP; - } else if (unlikely(hr_qp->state == IB_QPS_RESET || - hr_qp->state == IB_QPS_INIT || - hr_qp->state == IB_QPS_RTR)) { + if (unlikely(hr_qp->state == IB_QPS_RESET || + hr_qp->state == IB_QPS_INIT || + hr_qp->state == IB_QPS_RTR)) { ibdev_err(ibdev, "failed to post WQE, QP state %u!\n", hr_qp->state); return -EINVAL; @@ -777,17 +770,6 @@ out: static int check_recv_valid(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp) { - struct ib_device *ibdev = &hr_dev->ib_dev; - struct ib_qp *ibqp = &hr_qp->ibqp; - - if (unlikely(ibqp->qp_type != IB_QPT_RC && - ibqp->qp_type != IB_QPT_GSI && - ibqp->qp_type != IB_QPT_UD)) { - ibdev_err(ibdev, "unsupported qp type, qp_type = %d.\n", - ibqp->qp_type); - return -EOPNOTSUPP; - } - if (unlikely(hr_dev->state >= HNS_ROCE_DEVICE_STATE_RST_DOWN)) return -EIO; From 31c6fe9b79ed42440094f2367897aea0c0ce96ec Mon Sep 17 00:00:00 2001 From: wenglianfa Date: Thu, 24 Oct 2024 20:40:00 +0800 Subject: [PATCH 103/118] RDMA/hns: Fix cpu stuck caused by printings during reset [ Upstream commit 323275ac2ff15b2b7b3eac391ae5d8c5a3c3a999 ] During reset, cmd to destroy resources such as qp, cq, and mr may fail, and error logs will be printed. When a large number of resources are destroyed, there will be lots of printings, and it may lead to a cpu stuck. Delete some unnecessary printings and replace other printing functions in these paths with the ratelimited version. Fixes: 9a4435375cd1 ("IB/hns: Add driver files for hns RoCE driver") Fixes: c7bcb13442e1 ("RDMA/hns: Add SRQ support for hip08 kernel mode") Fixes: 70f92521584f ("RDMA/hns: Use the reserved loopback QPs to free MR before destroying MPT") Fixes: 926a01dc000d ("RDMA/hns: Add QP operations support for hip08 SoC") Signed-off-by: wenglianfa Signed-off-by: Junxian Huang Link: https://patch.msgid.link/20241024124000.2931869-6-huangjunxian6@hisilicon.com Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/hns/hns_roce_cq.c | 4 +- drivers/infiniband/hw/hns/hns_roce_hem.c | 4 +- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 73 ++++++++++------------ drivers/infiniband/hw/hns/hns_roce_mr.c | 4 +- drivers/infiniband/hw/hns/hns_roce_srq.c | 4 +- 5 files changed, 41 insertions(+), 48 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_cq.c b/drivers/infiniband/hw/hns/hns_roce_cq.c index ff177466de9b..9b91731a6207 100644 --- a/drivers/infiniband/hw/hns/hns_roce_cq.c +++ b/drivers/infiniband/hw/hns/hns_roce_cq.c @@ -180,8 +180,8 @@ static void free_cqc(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq) ret = hns_roce_destroy_hw_ctx(hr_dev, HNS_ROCE_CMD_DESTROY_CQC, hr_cq->cqn); if (ret) - dev_err(dev, "DESTROY_CQ failed (%d) for CQN %06lx\n", ret, - hr_cq->cqn); + dev_err_ratelimited(dev, "DESTROY_CQ failed (%d) for CQN %06lx\n", + ret, hr_cq->cqn); xa_erase_irq(&cq_table->array, hr_cq->cqn); diff --git a/drivers/infiniband/hw/hns/hns_roce_hem.c b/drivers/infiniband/hw/hns/hns_roce_hem.c index d1b00bb389d9..f605eb8fd13a 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hem.c +++ b/drivers/infiniband/hw/hns/hns_roce_hem.c @@ -712,8 +712,8 @@ void hns_roce_table_put(struct hns_roce_dev *hr_dev, ret = hr_dev->hw->clear_hem(hr_dev, table, obj, HEM_HOP_STEP_DIRECT); if (ret) - dev_warn(dev, "failed to clear HEM base address, ret = %d.\n", - ret); + dev_warn_ratelimited(dev, "failed to clear HEM base address, ret = %d.\n", + ret); hns_roce_free_hem(hr_dev, table->hem[i]); table->hem[i] = NULL; diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index b190e0cd86b4..d0846d2c97cc 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -372,19 +372,12 @@ static int set_rwqe_data_seg(struct ib_qp *ibqp, const struct ib_send_wr *wr, static int check_send_valid(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp) { - struct ib_device *ibdev = &hr_dev->ib_dev; - if (unlikely(hr_qp->state == IB_QPS_RESET || hr_qp->state == IB_QPS_INIT || - hr_qp->state == IB_QPS_RTR)) { - ibdev_err(ibdev, "failed to post WQE, QP state %u!\n", - hr_qp->state); + hr_qp->state == IB_QPS_RTR)) return -EINVAL; - } else if (unlikely(hr_dev->state >= HNS_ROCE_DEVICE_STATE_RST_DOWN)) { - ibdev_err(ibdev, "failed to post WQE, dev state %d!\n", - hr_dev->state); + else if (unlikely(hr_dev->state >= HNS_ROCE_DEVICE_STATE_RST_DOWN)) return -EIO; - } return 0; } @@ -2845,8 +2838,8 @@ static int free_mr_modify_rsv_qp(struct hns_roce_dev *hr_dev, ret = hr_dev->hw->modify_qp(&hr_qp->ibqp, attr, mask, IB_QPS_INIT, IB_QPS_INIT); if (ret) { - ibdev_err(ibdev, "failed to modify qp to init, ret = %d.\n", - ret); + ibdev_err_ratelimited(ibdev, "failed to modify qp to init, ret = %d.\n", + ret); return ret; } @@ -3492,8 +3485,8 @@ static int free_mr_post_send_lp_wqe(struct hns_roce_qp *hr_qp) ret = hns_roce_v2_post_send(&hr_qp->ibqp, send_wr, &bad_wr); if (ret) { - ibdev_err(ibdev, "failed to post wqe for free mr, ret = %d.\n", - ret); + ibdev_err_ratelimited(ibdev, "failed to post wqe for free mr, ret = %d.\n", + ret); return ret; } @@ -3532,9 +3525,9 @@ static void free_mr_send_cmd_to_hw(struct hns_roce_dev *hr_dev) ret = free_mr_post_send_lp_wqe(hr_qp); if (ret) { - ibdev_err(ibdev, - "failed to send wqe (qp:0x%lx) for free mr, ret = %d.\n", - hr_qp->qpn, ret); + ibdev_err_ratelimited(ibdev, + "failed to send wqe (qp:0x%lx) for free mr, ret = %d.\n", + hr_qp->qpn, ret); break; } @@ -3545,16 +3538,16 @@ static void free_mr_send_cmd_to_hw(struct hns_roce_dev *hr_dev) while (cqe_cnt) { npolled = hns_roce_v2_poll_cq(&free_mr->rsv_cq->ib_cq, cqe_cnt, wc); if (npolled < 0) { - ibdev_err(ibdev, - "failed to poll cqe for free mr, remain %d cqe.\n", - cqe_cnt); + ibdev_err_ratelimited(ibdev, + "failed to poll cqe for free mr, remain %d cqe.\n", + cqe_cnt); goto out; } if (time_after(jiffies, end)) { - ibdev_err(ibdev, - "failed to poll cqe for free mr and timeout, remain %d cqe.\n", - cqe_cnt); + ibdev_err_ratelimited(ibdev, + "failed to poll cqe for free mr and timeout, remain %d cqe.\n", + cqe_cnt); goto out; } cqe_cnt -= npolled; @@ -5125,10 +5118,8 @@ static int hns_roce_v2_set_abs_fields(struct ib_qp *ibqp, struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device); int ret = 0; - if (!check_qp_state(cur_state, new_state)) { - ibdev_err(&hr_dev->ib_dev, "Illegal state for QP!\n"); + if (!check_qp_state(cur_state, new_state)) return -EINVAL; - } if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) { memset(qpc_mask, 0, hr_dev->caps.qpc_sz); @@ -5390,7 +5381,7 @@ static int hns_roce_v2_modify_qp(struct ib_qp *ibqp, /* SW pass context to HW */ ret = hns_roce_v2_qp_modify(hr_dev, context, qpc_mask, hr_qp); if (ret) { - ibdev_err(ibdev, "failed to modify QP, ret = %d.\n", ret); + ibdev_err_ratelimited(ibdev, "failed to modify QP, ret = %d.\n", ret); goto out; } @@ -5480,7 +5471,9 @@ static int hns_roce_v2_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, ret = hns_roce_v2_query_qpc(hr_dev, hr_qp->qpn, &context); if (ret) { - ibdev_err(ibdev, "failed to query QPC, ret = %d.\n", ret); + ibdev_err_ratelimited(ibdev, + "failed to query QPC, ret = %d.\n", + ret); ret = -EINVAL; goto out; } @@ -5488,7 +5481,7 @@ static int hns_roce_v2_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, state = hr_reg_read(&context, QPC_QP_ST); tmp_qp_state = to_ib_qp_st((enum hns_roce_v2_qp_state)state); if (tmp_qp_state == -1) { - ibdev_err(ibdev, "Illegal ib_qp_state\n"); + ibdev_err_ratelimited(ibdev, "Illegal ib_qp_state\n"); ret = -EINVAL; goto out; } @@ -5581,9 +5574,9 @@ static int hns_roce_v2_destroy_qp_common(struct hns_roce_dev *hr_dev, ret = hns_roce_v2_modify_qp(&hr_qp->ibqp, NULL, 0, hr_qp->state, IB_QPS_RESET); if (ret) - ibdev_err(ibdev, - "failed to modify QP to RST, ret = %d.\n", - ret); + ibdev_err_ratelimited(ibdev, + "failed to modify QP to RST, ret = %d.\n", + ret); } send_cq = hr_qp->ibqp.send_cq ? to_hr_cq(hr_qp->ibqp.send_cq) : NULL; @@ -5619,9 +5612,9 @@ int hns_roce_v2_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata) ret = hns_roce_v2_destroy_qp_common(hr_dev, hr_qp, udata); if (ret) - ibdev_err(&hr_dev->ib_dev, - "failed to destroy QP, QPN = 0x%06lx, ret = %d.\n", - hr_qp->qpn, ret); + ibdev_err_ratelimited(&hr_dev->ib_dev, + "failed to destroy QP, QPN = 0x%06lx, ret = %d.\n", + hr_qp->qpn, ret); hns_roce_qp_destroy(hr_dev, hr_qp, udata); @@ -5894,9 +5887,9 @@ static int hns_roce_v2_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period) HNS_ROCE_CMD_MODIFY_CQC, hr_cq->cqn); hns_roce_free_cmd_mailbox(hr_dev, mailbox); if (ret) - ibdev_err(&hr_dev->ib_dev, - "failed to process cmd when modifying CQ, ret = %d.\n", - ret); + ibdev_err_ratelimited(&hr_dev->ib_dev, + "failed to process cmd when modifying CQ, ret = %d.\n", + ret); return ret; } @@ -5916,9 +5909,9 @@ static int hns_roce_v2_query_cqc(struct hns_roce_dev *hr_dev, u32 cqn, ret = hns_roce_cmd_mbox(hr_dev, 0, mailbox->dma, HNS_ROCE_CMD_QUERY_CQC, cqn); if (ret) { - ibdev_err(&hr_dev->ib_dev, - "failed to process cmd when querying CQ, ret = %d.\n", - ret); + ibdev_err_ratelimited(&hr_dev->ib_dev, + "failed to process cmd when querying CQ, ret = %d.\n", + ret); goto err_mailbox; } diff --git a/drivers/infiniband/hw/hns/hns_roce_mr.c b/drivers/infiniband/hw/hns/hns_roce_mr.c index 980261969b0c..b053f2f43dac 100644 --- a/drivers/infiniband/hw/hns/hns_roce_mr.c +++ b/drivers/infiniband/hw/hns/hns_roce_mr.c @@ -130,8 +130,8 @@ static void hns_roce_mr_free(struct hns_roce_dev *hr_dev, struct hns_roce_mr *mr key_to_hw_index(mr->key) & (hr_dev->caps.num_mtpts - 1)); if (ret) - ibdev_warn(ibdev, "failed to destroy mpt, ret = %d.\n", - ret); + ibdev_warn_ratelimited(ibdev, "failed to destroy mpt, ret = %d.\n", + ret); } free_mr_pbl(hr_dev, mr); diff --git a/drivers/infiniband/hw/hns/hns_roce_srq.c b/drivers/infiniband/hw/hns/hns_roce_srq.c index 727f92650071..652508b660a0 100644 --- a/drivers/infiniband/hw/hns/hns_roce_srq.c +++ b/drivers/infiniband/hw/hns/hns_roce_srq.c @@ -150,8 +150,8 @@ static void free_srqc(struct hns_roce_dev *hr_dev, struct hns_roce_srq *srq) ret = hns_roce_destroy_hw_ctx(hr_dev, HNS_ROCE_CMD_DESTROY_SRQ, srq->srqn); if (ret) - dev_err(hr_dev->dev, "DESTROY_SRQ failed (%d) for SRQN %06lx\n", - ret, srq->srqn); + dev_err_ratelimited(hr_dev->dev, "DESTROY_SRQ failed (%d) for SRQN %06lx\n", + ret, srq->srqn); xa_erase_irq(&srq_table->xa, srq->srqn); From 4799f3f8fd1450cf88ca5943d58193470e53c075 Mon Sep 17 00:00:00 2001 From: Kashyap Desai Date: Mon, 28 Oct 2024 03:06:54 -0700 Subject: [PATCH 104/118] RDMA/bnxt_re: Check cqe flags to know imm_data vs inv_irkey [ Upstream commit 808ca6de989c598bc5af1ae0ad971a66077efac0 ] Invalidate rkey is cpu endian and immediate data is in big endian format. Both immediate data and invalidate the remote key returned by HW is in little endian format. While handling the commit in fixes tag, the difference between immediate data and invalidate rkey endianness was not considered. Without changes of this patch, Kernel ULP was failing while processing inv_rkey. dmesg log snippet - nvme nvme0: Bogus remote invalidation for rkey 0x2000019Fix in this patch Do endianness conversion based on completion queue entry flag. Also, the HW completions are already converted to host endianness in bnxt_qplib_cq_process_res_rc and bnxt_qplib_cq_process_res_ud and there is no need to convert it again in bnxt_re_poll_cq. Modified the union to hold the correct data type. Fixes: 95b087f87b78 ("bnxt_re: Fix imm_data endianness") Signed-off-by: Kashyap Desai Signed-off-by: Selvin Xavier Link: https://patch.msgid.link/1730110014-20755-1-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 7 +++++-- drivers/infiniband/hw/bnxt_re/qplib_fp.h | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index 4c34cb1cb786..13102ba93847 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -3340,7 +3340,7 @@ static void bnxt_re_process_res_shadow_qp_wc(struct bnxt_re_qp *gsi_sqp, wc->byte_len = orig_cqe->length; wc->qp = &gsi_qp->ib_qp; - wc->ex.imm_data = cpu_to_be32(le32_to_cpu(orig_cqe->immdata)); + wc->ex.imm_data = cpu_to_be32(orig_cqe->immdata); wc->src_qp = orig_cqe->src_qp; memcpy(wc->smac, orig_cqe->smac, ETH_ALEN); if (bnxt_re_is_vlan_pkt(orig_cqe, &vlan_id, &sl)) { @@ -3476,7 +3476,10 @@ int bnxt_re_poll_cq(struct ib_cq *ib_cq, int num_entries, struct ib_wc *wc) (unsigned long)(cqe->qp_handle), struct bnxt_re_qp, qplib_qp); wc->qp = &qp->ib_qp; - wc->ex.imm_data = cpu_to_be32(le32_to_cpu(cqe->immdata)); + if (cqe->flags & CQ_RES_RC_FLAGS_IMM) + wc->ex.imm_data = cpu_to_be32(cqe->immdata); + else + wc->ex.invalidate_rkey = cqe->invrkey; wc->src_qp = cqe->src_qp; memcpy(wc->smac, cqe->smac, ETH_ALEN); wc->port_num = 1; diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.h b/drivers/infiniband/hw/bnxt_re/qplib_fp.h index 57a3dae87f65..13263ce2309d 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.h @@ -374,7 +374,7 @@ struct bnxt_qplib_cqe { u16 cfa_meta; u64 wr_id; union { - __le32 immdata; + u32 immdata; u32 invrkey; }; u64 qp_handle; From 9bc7ccfbd31e2d8a20035eee1e6a853dec45cc66 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Tue, 1 Oct 2024 11:50:16 +0100 Subject: [PATCH 105/118] clk: sunxi-ng: d1: Fix PLL_AUDIO0 preset [ Upstream commit e0f253a52ccee3cf3eb987e99756e20c68a1aac9 ] To work around a limitation in our clock modelling, we try to force two bits in the AUDIO0 PLL to 0, in the CCU probe routine. However the ~ operator only applies to the first expression, and does not cover the second bit, so we end up clearing only bit 1. Group the bit-ORing with parentheses, to make it both clearer to read and actually correct. Fixes: 35b97bb94111 ("clk: sunxi-ng: Add support for the D1 SoC clocks") Signed-off-by: Andre Przywara Link: https://patch.msgid.link/20241001105016.1068558-1-andre.przywara@arm.com Signed-off-by: Chen-Yu Tsai Signed-off-by: Sasha Levin --- drivers/clk/sunxi-ng/ccu-sun20i-d1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun20i-d1.c b/drivers/clk/sunxi-ng/ccu-sun20i-d1.c index 8ef3cdeb7962..cb4bf038e17f 100644 --- a/drivers/clk/sunxi-ng/ccu-sun20i-d1.c +++ b/drivers/clk/sunxi-ng/ccu-sun20i-d1.c @@ -1360,7 +1360,7 @@ static int sun20i_d1_ccu_probe(struct platform_device *pdev) /* Enforce m1 = 0, m0 = 0 for PLL_AUDIO0 */ val = readl(reg + SUN20I_D1_PLL_AUDIO0_REG); - val &= ~BIT(1) | BIT(0); + val &= ~(BIT(1) | BIT(0)); writel(val, reg + SUN20I_D1_PLL_AUDIO0_REG); /* Force fanout-27M factor N to 0. */ From 1b67ca853a27b09d3e140e9a2cce3c340568f4df Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 24 Oct 2024 14:42:11 +0100 Subject: [PATCH 106/118] clk: renesas: rzg2l: Fix FOUTPOSTDIV clk [ Upstream commit dabf72b85f298970e86891b5218459c17b57b26a ] While computing foutpostdiv_rate, the value of params->pl5_fracin is discarded, which results in the wrong refresh rate. Fix the formula for computing foutpostdiv_rate. Fixes: 1561380ee72f ("clk: renesas: rzg2l: Add FOUTPOSTDIV clk support") Signed-off-by: Hien Huynh Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/20241024134236.315289-1-biju.das.jz@bp.renesas.com Signed-off-by: Geert Uytterhoeven Signed-off-by: Sasha Levin --- drivers/clk/renesas/rzg2l-cpg.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index 473feb36a38f..5617040f307c 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -289,7 +289,7 @@ static unsigned long rzg2l_cpg_get_foutpostdiv_rate(struct rzg2l_pll5_param *params, unsigned long rate) { - unsigned long foutpostdiv_rate; + unsigned long foutpostdiv_rate, foutvco_rate; params->pl5_intin = rate / MEGA; params->pl5_fracin = div_u64(((u64)rate % MEGA) << 24, MEGA); @@ -298,10 +298,11 @@ rzg2l_cpg_get_foutpostdiv_rate(struct rzg2l_pll5_param *params, params->pl5_postdiv2 = 1; params->pl5_spread = 0x16; - foutpostdiv_rate = - EXTAL_FREQ_IN_MEGA_HZ * MEGA / params->pl5_refdiv * - ((((params->pl5_intin << 24) + params->pl5_fracin)) >> 24) / - (params->pl5_postdiv1 * params->pl5_postdiv2); + foutvco_rate = div_u64(mul_u32_u32(EXTAL_FREQ_IN_MEGA_HZ * MEGA, + (params->pl5_intin << 24) + params->pl5_fracin), + params->pl5_refdiv) >> 24; + foutpostdiv_rate = DIV_ROUND_CLOSEST_ULL(foutvco_rate, + params->pl5_postdiv1 * params->pl5_postdiv2); return foutpostdiv_rate; } From c92515247f613a510ed14a77fbdf27a9617b784a Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sun, 27 Oct 2024 20:00:07 +0800 Subject: [PATCH 107/118] clk: imx: lpcg-scu: SW workaround for errata (e10858) [ Upstream commit 5ee063fac85656bea9cfe3570af147ba1701ba18 ] Back-to-back LPCG writes can be ignored by the LPCG register due to a HW bug. The writes need to be separated by at least 4 cycles of the gated clock. See https://www.nxp.com.cn/docs/en/errata/IMX8_1N94W.pdf The workaround is implemented as follows: 1. For clocks running greater than or equal to 24MHz, a read followed by the write will provide sufficient delay. 2. For clocks running below 24MHz, add a delay of 4 clock cylces after the write to the LPCG register. Fixes: 2f77296d3df9 ("clk: imx: add lpcg clock support") Signed-off-by: Peng Fan Reviewed-by: Abel Vesa Link: https://lore.kernel.org/r/20241027-imx-clk-v1-v3-1-89152574d1d7@nxp.com Signed-off-by: Abel Vesa Signed-off-by: Sasha Levin --- drivers/clk/imx/clk-lpcg-scu.c | 37 ++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/drivers/clk/imx/clk-lpcg-scu.c b/drivers/clk/imx/clk-lpcg-scu.c index dd5abd09f3e2..620afdf8dc03 100644 --- a/drivers/clk/imx/clk-lpcg-scu.c +++ b/drivers/clk/imx/clk-lpcg-scu.c @@ -6,10 +6,12 @@ #include #include +#include #include #include #include #include +#include #include "clk-scu.h" @@ -41,6 +43,29 @@ struct clk_lpcg_scu { #define to_clk_lpcg_scu(_hw) container_of(_hw, struct clk_lpcg_scu, hw) +/* e10858 -LPCG clock gating register synchronization errata */ +static void lpcg_e10858_writel(unsigned long rate, void __iomem *reg, u32 val) +{ + writel(val, reg); + + if (rate >= 24 * HZ_PER_MHZ || rate == 0) { + /* + * The time taken to access the LPCG registers from the AP core + * through the interconnect is longer than the minimum delay + * of 4 clock cycles required by the errata. + * Adding a readl will provide sufficient delay to prevent + * back-to-back writes. + */ + readl(reg); + } else { + /* + * For clocks running below 24MHz, wait a minimum of + * 4 clock cycles. + */ + ndelay(4 * (DIV_ROUND_UP(1000 * HZ_PER_MHZ, rate))); + } +} + static int clk_lpcg_scu_enable(struct clk_hw *hw) { struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw); @@ -57,7 +82,8 @@ static int clk_lpcg_scu_enable(struct clk_hw *hw) val |= CLK_GATE_SCU_LPCG_HW_SEL; reg |= val << clk->bit_idx; - writel(reg, clk->reg); + + lpcg_e10858_writel(clk_hw_get_rate(hw), clk->reg, reg); spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags); @@ -74,7 +100,7 @@ static void clk_lpcg_scu_disable(struct clk_hw *hw) reg = readl_relaxed(clk->reg); reg &= ~(CLK_GATE_SCU_LPCG_MASK << clk->bit_idx); - writel(reg, clk->reg); + lpcg_e10858_writel(clk_hw_get_rate(hw), clk->reg, reg); spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags); } @@ -145,13 +171,8 @@ static int __maybe_unused imx_clk_lpcg_scu_resume(struct device *dev) { struct clk_lpcg_scu *clk = dev_get_drvdata(dev); - /* - * FIXME: Sometimes writes don't work unless the CPU issues - * them twice - */ - - writel(clk->state, clk->reg); writel(clk->state, clk->reg); + lpcg_e10858_writel(0, clk->reg, clk->state); dev_dbg(dev, "restore lpcg state 0x%x\n", clk->state); return 0; From f7aee64ed7ca994df8558a45f52532868092827c Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sun, 27 Oct 2024 20:00:08 +0800 Subject: [PATCH 108/118] clk: imx: fracn-gppll: correct PLL initialization flow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 557be501c38e1864b948fc6ccdf4b035d610a2ea ] Per i.MX93 Reference Mannual 22.4 Initialization information 1. Program appropriate value of DIV[ODIV], DIV[RDIV] and DIV[MFI] as per Integer mode. 2. Wait for 5 μs. 3. Program the following field in CTRL register. Set CTRL[POWERUP] to 1'b1 to enable PLL block. 4. Poll PLL_STATUS[PLL_LOCK] register, and wait till PLL_STATUS[PLL_LOCK] is 1'b1 and pll_lock output signal is 1'b1. 5. Set CTRL[CLKMUX_EN] to 1'b1 to enable PLL output clock. So move the CLKMUX_EN operation after PLL locked. Fixes: 1b26cb8a77a4 ("clk: imx: support fracn gppll") Co-developed-by: Jacky Bai Signed-off-by: Jacky Bai Signed-off-by: Peng Fan Reviewed-by: Abel Vesa Link: https://lore.kernel.org/r/20241027-imx-clk-v1-v3-2-89152574d1d7@nxp.com Signed-off-by: Abel Vesa Signed-off-by: Sasha Levin --- drivers/clk/imx/clk-fracn-gppll.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/imx/clk-fracn-gppll.c b/drivers/clk/imx/clk-fracn-gppll.c index 421a78e295ee..281fc62ecd3d 100644 --- a/drivers/clk/imx/clk-fracn-gppll.c +++ b/drivers/clk/imx/clk-fracn-gppll.c @@ -299,13 +299,13 @@ static int clk_fracn_gppll_prepare(struct clk_hw *hw) val |= POWERUP_MASK; writel_relaxed(val, pll->base + PLL_CTRL); - val |= CLKMUX_EN; - writel_relaxed(val, pll->base + PLL_CTRL); - ret = clk_fracn_gppll_wait_lock(pll); if (ret) return ret; + val |= CLKMUX_EN; + writel_relaxed(val, pll->base + PLL_CTRL); + val &= ~CLKMUX_BYPASS; writel_relaxed(val, pll->base + PLL_CTRL); From 882d94d74694205b544b617c0bd88b307f6c0067 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sun, 27 Oct 2024 20:00:09 +0800 Subject: [PATCH 109/118] clk: imx: fracn-gppll: fix pll power up [ Upstream commit ff4279618f0aec350b0fb41b2b35841324fbd96e ] To i.MX93 which features dual Cortex-A55 cores and DSU, when using writel_relaxed to write value to PLL registers, the value might be buffered. To make sure the value has been written into the hardware, using readl to read back the register could achieve the goal. current PLL power up flow can be simplified as below: 1. writel_relaxed to set the PLL POWERUP bit; 2. readl_poll_timeout to check the PLL lock bit: a). timeout = ktime_add_us(ktime_get(), timeout_us); b). readl the pll the lock reg; c). check if the pll lock bit ready d). check if timeout But in some corner cases, both the write in step 1 and read in step 2 will be blocked by other bus transaction in the SoC for a long time, saying the value into real hardware is just before step b). That means the timeout counting has begins for quite sometime since step a), but value still not written into real hardware until bus released just at a point before step b). Then there maybe chances that the pll lock bit is not ready when readl done but the timeout happens. readl_poll_timeout will err return due to timeout. To avoid such unexpected failure, read back the reg to make sure the write has been done in HW reg. So use readl after writel_relaxed to fix the issue. Since we are here, to avoid udelay to run before writel_relaxed, use readl before udelay. Fixes: 1b26cb8a77a4 ("clk: imx: support fracn gppll") Co-developed-by: Jacky Bai Signed-off-by: Jacky Bai Signed-off-by: Peng Fan Reviewed-by: Abel Vesa Link: https://lore.kernel.org/r/20241027-imx-clk-v1-v3-3-89152574d1d7@nxp.com Signed-off-by: Abel Vesa Signed-off-by: Sasha Levin --- drivers/clk/imx/clk-fracn-gppll.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/clk/imx/clk-fracn-gppll.c b/drivers/clk/imx/clk-fracn-gppll.c index 281fc62ecd3d..5f2296bb67a6 100644 --- a/drivers/clk/imx/clk-fracn-gppll.c +++ b/drivers/clk/imx/clk-fracn-gppll.c @@ -250,9 +250,11 @@ static int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate, pll_div = FIELD_PREP(PLL_RDIV_MASK, rate->rdiv) | rate->odiv | FIELD_PREP(PLL_MFI_MASK, rate->mfi); writel_relaxed(pll_div, pll->base + PLL_DIV); + readl(pll->base + PLL_DIV); if (pll->flags & CLK_FRACN_GPPLL_FRACN) { writel_relaxed(rate->mfd, pll->base + PLL_DENOMINATOR); writel_relaxed(FIELD_PREP(PLL_MFN_MASK, rate->mfn), pll->base + PLL_NUMERATOR); + readl(pll->base + PLL_NUMERATOR); } /* Wait for 5us according to fracn mode pll doc */ @@ -261,6 +263,7 @@ static int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate, /* Enable Powerup */ tmp |= POWERUP_MASK; writel_relaxed(tmp, pll->base + PLL_CTRL); + readl(pll->base + PLL_CTRL); /* Wait Lock */ ret = clk_fracn_gppll_wait_lock(pll); @@ -298,6 +301,7 @@ static int clk_fracn_gppll_prepare(struct clk_hw *hw) val |= POWERUP_MASK; writel_relaxed(val, pll->base + PLL_CTRL); + readl(pll->base + PLL_CTRL); ret = clk_fracn_gppll_wait_lock(pll); if (ret) From 6786d623fb01d32dd5635a5cb3a1ae42ae67848a Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Sun, 27 Oct 2024 20:00:10 +0800 Subject: [PATCH 110/118] clk: imx: clk-scu: fix clk enable state save and restore [ Upstream commit e81361f6cf9bf4a1848b0813bc4becb2250870b8 ] The scu clk_ops only inplements prepare() and unprepare() callback. Saving the clock state during suspend by checking clk_hw_is_enabled() is not safe as it's possible that some device drivers may only disable the clocks without unprepare. Then the state retention will not work for such clocks. Fixing it by checking clk_hw_is_prepared() which is more reasonable and safe. Fixes: d0409631f466 ("clk: imx: scu: add suspend/resume support") Reviewed-by: Peng Fan Tested-by: Carlos Song Signed-off-by: Dong Aisheng Link: https://lore.kernel.org/r/20241027-imx-clk-v1-v3-4-89152574d1d7@nxp.com Signed-off-by: Abel Vesa Signed-off-by: Sasha Levin --- drivers/clk/imx/clk-scu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c index db307890e4c1..ec5afc7f2690 100644 --- a/drivers/clk/imx/clk-scu.c +++ b/drivers/clk/imx/clk-scu.c @@ -577,7 +577,7 @@ static int __maybe_unused imx_clk_scu_suspend(struct device *dev) clk->rate = clk_scu_recalc_rate(&clk->hw, 0); else clk->rate = clk_hw_get_rate(&clk->hw); - clk->is_enabled = clk_hw_is_enabled(&clk->hw); + clk->is_enabled = clk_hw_is_prepared(&clk->hw); if (clk->parent) dev_dbg(dev, "save parent %s idx %u\n", clk_hw_get_name(clk->parent), From ef4a6cb5f22ce7f498810cbb784dc5e92414272b Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Mon, 4 Nov 2024 09:40:32 +0800 Subject: [PATCH 111/118] iommu/vt-d: Fix checks and print in dmar_fault_dump_ptes() [ Upstream commit 6ceb93f952f6ca34823ce3650c902c31b8385b40 ] There are some issues in dmar_fault_dump_ptes(): 1. return value of phys_to_virt() is used for checking if an entry is present. 2. dump is confusing, e.g., "pasid table entry is not present", confusing by unpresent pasid table vs. unpresent pasid table entry. Current code means the former. 3. pgtable_walk() is called without checking if page table is present. Fix 1 by checking present bit of an entry before dump a lower level entry. Fix 2 by removing "entry" string, e.g., "pasid table is not present". Fix 3 by checking page table present before walk. Take issue 3 for example, before fix: [ 442.240357] DMAR: pasid dir entry: 0x000000012c83e001 [ 442.246661] DMAR: pasid table entry[0]: 0x0000000000000000 [ 442.253429] DMAR: pasid table entry[1]: 0x0000000000000000 [ 442.260203] DMAR: pasid table entry[2]: 0x0000000000000000 [ 442.266969] DMAR: pasid table entry[3]: 0x0000000000000000 [ 442.273733] DMAR: pasid table entry[4]: 0x0000000000000000 [ 442.280479] DMAR: pasid table entry[5]: 0x0000000000000000 [ 442.287234] DMAR: pasid table entry[6]: 0x0000000000000000 [ 442.293989] DMAR: pasid table entry[7]: 0x0000000000000000 [ 442.300742] DMAR: PTE not present at level 2 After fix: ... [ 357.241214] DMAR: pasid table entry[6]: 0x0000000000000000 [ 357.248022] DMAR: pasid table entry[7]: 0x0000000000000000 [ 357.254824] DMAR: scalable mode page table is not present Fixes: 914ff7719e8a ("iommu/vt-d: Dump DMAR translation structure when DMA fault occurs") Signed-off-by: Zhenzhong Duan Link: https://lore.kernel.org/r/20241024092146.715063-2-zhenzhong.duan@intel.com Signed-off-by: Lu Baolu Signed-off-by: Joerg Roedel Signed-off-by: Sasha Levin --- drivers/iommu/intel/iommu.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index f118c8991130..2bf9157256c5 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -861,11 +861,11 @@ void dmar_fault_dump_ptes(struct intel_iommu *iommu, u16 source_id, pr_info("Dump %s table entries for IOVA 0x%llx\n", iommu->name, addr); /* root entry dump */ - rt_entry = &iommu->root_entry[bus]; - if (!rt_entry) { - pr_info("root table entry is not present\n"); + if (!iommu->root_entry) { + pr_info("root table is not present\n"); return; } + rt_entry = &iommu->root_entry[bus]; if (sm_supported(iommu)) pr_info("scalable mode root entry: hi 0x%016llx, low 0x%016llx\n", @@ -876,7 +876,7 @@ void dmar_fault_dump_ptes(struct intel_iommu *iommu, u16 source_id, /* context entry dump */ ctx_entry = iommu_context_addr(iommu, bus, devfn, 0); if (!ctx_entry) { - pr_info("context table entry is not present\n"); + pr_info("context table is not present\n"); return; } @@ -885,17 +885,23 @@ void dmar_fault_dump_ptes(struct intel_iommu *iommu, u16 source_id, /* legacy mode does not require PASID entries */ if (!sm_supported(iommu)) { + if (!context_present(ctx_entry)) { + pr_info("legacy mode page table is not present\n"); + return; + } level = agaw_to_level(ctx_entry->hi & 7); pgtable = phys_to_virt(ctx_entry->lo & VTD_PAGE_MASK); goto pgtable_walk; } - /* get the pointer to pasid directory entry */ - dir = phys_to_virt(ctx_entry->lo & VTD_PAGE_MASK); - if (!dir) { - pr_info("pasid directory entry is not present\n"); + if (!context_present(ctx_entry)) { + pr_info("pasid directory table is not present\n"); return; } + + /* get the pointer to pasid directory entry */ + dir = phys_to_virt(ctx_entry->lo & VTD_PAGE_MASK); + /* For request-without-pasid, get the pasid from context entry */ if (intel_iommu_sm && pasid == INVALID_IOASID) pasid = PASID_RID2PASID; @@ -907,7 +913,7 @@ void dmar_fault_dump_ptes(struct intel_iommu *iommu, u16 source_id, /* get the pointer to the pasid table entry */ entries = get_pasid_table_from_pde(pde); if (!entries) { - pr_info("pasid table entry is not present\n"); + pr_info("pasid table is not present\n"); return; } index = pasid & PASID_PTE_MASK; @@ -915,6 +921,11 @@ void dmar_fault_dump_ptes(struct intel_iommu *iommu, u16 source_id, for (i = 0; i < ARRAY_SIZE(pte->val); i++) pr_info("pasid table entry[%d]: 0x%016llx\n", i, pte->val[i]); + if (!pasid_pte_is_present(pte)) { + pr_info("scalable mode page table is not present\n"); + return; + } + if (pasid_pte_get_pgtt(pte) == PASID_ENTRY_PGTT_FL_ONLY) { level = pte->val[2] & BIT_ULL(2) ? 5 : 4; pgtable = phys_to_virt(pte->val[2] & VTD_PAGE_MASK); From 23a2a5770d524acce4769d2d8bede02c3c26c42a Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Mon, 4 Nov 2024 09:40:33 +0800 Subject: [PATCH 112/118] iommu/vt-d: Fix checks and print in pgtable_walk() [ Upstream commit f1645676f25d2c846798f0233c3a953efd62aafb ] There are some issues in pgtable_walk(): 1. Super page is dumped as non-present page 2. dma_pte_superpage() should not check against leaf page table entries 3. Pointer pte is never NULL so checking it is meaningless 4. When an entry is not present, it still makes sense to dump the entry content. Fix 1,2 by checking dma_pte_superpage()'s returned value after level check. Fix 3 by removing pte check. Fix 4 by checking present bit after printing. By this chance, change to print "page table not present" instead of "PTE not present" to be clearer. Fixes: 914ff7719e8a ("iommu/vt-d: Dump DMAR translation structure when DMA fault occurs") Signed-off-by: Zhenzhong Duan Link: https://lore.kernel.org/r/20241024092146.715063-3-zhenzhong.duan@intel.com Signed-off-by: Lu Baolu Signed-off-by: Joerg Roedel Signed-off-by: Sasha Levin --- drivers/iommu/intel/iommu.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index 2bf9157256c5..9a1bdfda9a9a 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -831,14 +831,15 @@ static void pgtable_walk(struct intel_iommu *iommu, unsigned long pfn, while (1) { offset = pfn_level_offset(pfn, level); pte = &parent[offset]; - if (!pte || (dma_pte_superpage(pte) || !dma_pte_present(pte))) { - pr_info("PTE not present at level %d\n", level); - break; - } pr_info("pte level: %d, pte value: 0x%016llx\n", level, pte->val); - if (level == 1) + if (!dma_pte_present(pte)) { + pr_info("page table not present at level %d\n", level - 1); + break; + } + + if (level == 1 || dma_pte_superpage(pte)) break; parent = phys_to_virt(dma_pte_addr(pte)); From 7d3b43738589254877482cc445e29f67942819a0 Mon Sep 17 00:00:00 2001 From: Zhang Changzhong Date: Wed, 30 Oct 2024 23:41:06 +0800 Subject: [PATCH 113/118] mfd: rt5033: Fix missing regmap_del_irq_chip() [ Upstream commit d256d612f47529ed0b332298e2d5ea981a4dd5b8 ] Fix missing call to regmap_del_irq_chip() in error handling path by using devm_regmap_add_irq_chip(). Fixes: 0b271258544b ("mfd: rt5033: Add Richtek RT5033 driver core.") Signed-off-by: Zhang Changzhong Link: https://lore.kernel.org/r/1730302867-8391-1-git-send-email-zhangchangzhong@huawei.com Signed-off-by: Lee Jones Signed-off-by: Sasha Levin --- drivers/mfd/rt5033.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mfd/rt5033.c b/drivers/mfd/rt5033.c index df095e91e266..78bafeda5e47 100644 --- a/drivers/mfd/rt5033.c +++ b/drivers/mfd/rt5033.c @@ -82,8 +82,8 @@ static int rt5033_i2c_probe(struct i2c_client *i2c, } dev_info(&i2c->dev, "Device found Device ID: %04x\n", dev_id); - ret = regmap_add_irq_chip(rt5033->regmap, rt5033->irq, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + ret = devm_regmap_add_irq_chip(rt5033->dev, rt5033->regmap, + rt5033->irq, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0, &rt5033_irq_chip, &rt5033->irq_data); if (ret) { dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n", From 41f80bdd5201a2969a47dd05d033a87ecce08c16 Mon Sep 17 00:00:00 2001 From: Mirsad Todorovac Date: Tue, 29 Oct 2024 06:46:52 +0100 Subject: [PATCH 114/118] fs/proc/kcore.c: fix coccinelle reported ERROR instances [ Upstream commit 82e33f249f1126cf3c5f39a31b850d485ac33bc3 ] Coccinelle complains about the nested reuse of the pointer `iter' with different pointer type: ./fs/proc/kcore.c:515:26-30: ERROR: invalid reference to the index variable of the iterator on line 499 ./fs/proc/kcore.c:534:23-27: ERROR: invalid reference to the index variable of the iterator on line 499 ./fs/proc/kcore.c:550:40-44: ERROR: invalid reference to the index variable of the iterator on line 499 ./fs/proc/kcore.c:568:27-31: ERROR: invalid reference to the index variable of the iterator on line 499 ./fs/proc/kcore.c:581:28-32: ERROR: invalid reference to the index variable of the iterator on line 499 ./fs/proc/kcore.c:599:27-31: ERROR: invalid reference to the index variable of the iterator on line 499 ./fs/proc/kcore.c:607:38-42: ERROR: invalid reference to the index variable of the iterator on line 499 ./fs/proc/kcore.c:614:26-30: ERROR: invalid reference to the index variable of the iterator on line 499 Replacing `struct kcore_list *iter' with `struct kcore_list *tmp' doesn't change the scope and the functionality is the same and coccinelle seems happy. NOTE: There was an issue with using `struct kcore_list *pos' as the nested iterator. The build did not work! [akpm@linux-foundation.org: s/tmp/pos/] Link: https://lkml.kernel.org/r/20241029054651.86356-2-mtodorovac69@gmail.com Link: https://lore.kernel.org/all/CAHk-=wgRr_D8CB-D9Kg-c=EHreAsk5SqXPwr9Y7k9sA6cWXJ6w@mail.gmail.com/ [1] Link: https://lkml.kernel.org/r/20220331223700.902556-1-jakobkoschel@gmail.com Fixes: 04d168c6d42d ("fs/proc/kcore.c: remove check of list iterator against head past the loop body") Signed-off-by: Jakob Koschel Signed-off-by: Mirsad Todorovac Cc: Mike Rapoport Cc: David Hildenbrand Cc: Oscar Salvador Cc: "Brian Johannesmeyer" Cc: Cristiano Giuffrida Cc: "Bos, H.J." Cc: Alexey Dobriyan Cc: Andrew Morton Cc: Yang Li Cc: Baoquan He Cc: Hari Bathini Cc: Yan Zhen Cc: Alexander Gordeev Signed-off-by: Andrew Morton Signed-off-by: Sasha Levin --- fs/proc/kcore.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c index a2d430549012..92c7259adfd9 100644 --- a/fs/proc/kcore.c +++ b/fs/proc/kcore.c @@ -496,13 +496,13 @@ read_kcore_iter(struct kiocb *iocb, struct iov_iter *iter) * the previous entry, search for a matching entry. */ if (!m || start < m->addr || start >= m->addr + m->size) { - struct kcore_list *iter; + struct kcore_list *pos; m = NULL; - list_for_each_entry(iter, &kclist_head, list) { - if (start >= iter->addr && - start < iter->addr + iter->size) { - m = iter; + list_for_each_entry(pos, &kclist_head, list) { + if (start >= pos->addr && + start < pos->addr + pos->size) { + m = pos; break; } } From 8f5a97443b547b4c83f876f1d6a11df0f1fd4efb Mon Sep 17 00:00:00 2001 From: Ye Bin Date: Wed, 23 Oct 2024 09:18:09 +0800 Subject: [PATCH 115/118] scsi: bfa: Fix use-after-free in bfad_im_module_exit() [ Upstream commit 178b8f38932d635e90f5f0e9af1986c6f4a89271 ] BUG: KASAN: slab-use-after-free in __lock_acquire+0x2aca/0x3a20 Read of size 8 at addr ffff8881082d80c8 by task modprobe/25303 Call Trace: dump_stack_lvl+0x95/0xe0 print_report+0xcb/0x620 kasan_report+0xbd/0xf0 __lock_acquire+0x2aca/0x3a20 lock_acquire+0x19b/0x520 _raw_spin_lock+0x2b/0x40 attribute_container_unregister+0x30/0x160 fc_release_transport+0x19/0x90 [scsi_transport_fc] bfad_im_module_exit+0x23/0x60 [bfa] bfad_init+0xdb/0xff0 [bfa] do_one_initcall+0xdc/0x550 do_init_module+0x22d/0x6b0 load_module+0x4e96/0x5ff0 init_module_from_file+0xcd/0x130 idempotent_init_module+0x330/0x620 __x64_sys_finit_module+0xb3/0x110 do_syscall_64+0xc1/0x1d0 entry_SYSCALL_64_after_hwframe+0x77/0x7f Allocated by task 25303: kasan_save_stack+0x24/0x50 kasan_save_track+0x14/0x30 __kasan_kmalloc+0x7f/0x90 fc_attach_transport+0x4f/0x4740 [scsi_transport_fc] bfad_im_module_init+0x17/0x80 [bfa] bfad_init+0x23/0xff0 [bfa] do_one_initcall+0xdc/0x550 do_init_module+0x22d/0x6b0 load_module+0x4e96/0x5ff0 init_module_from_file+0xcd/0x130 idempotent_init_module+0x330/0x620 __x64_sys_finit_module+0xb3/0x110 do_syscall_64+0xc1/0x1d0 entry_SYSCALL_64_after_hwframe+0x77/0x7f Freed by task 25303: kasan_save_stack+0x24/0x50 kasan_save_track+0x14/0x30 kasan_save_free_info+0x3b/0x60 __kasan_slab_free+0x38/0x50 kfree+0x212/0x480 bfad_im_module_init+0x7e/0x80 [bfa] bfad_init+0x23/0xff0 [bfa] do_one_initcall+0xdc/0x550 do_init_module+0x22d/0x6b0 load_module+0x4e96/0x5ff0 init_module_from_file+0xcd/0x130 idempotent_init_module+0x330/0x620 __x64_sys_finit_module+0xb3/0x110 do_syscall_64+0xc1/0x1d0 entry_SYSCALL_64_after_hwframe+0x77/0x7f Above issue happens as follows: bfad_init error = bfad_im_module_init() fc_release_transport(bfad_im_scsi_transport_template); if (error) goto ext; ext: bfad_im_module_exit(); fc_release_transport(bfad_im_scsi_transport_template); --> Trigger double release Don't call bfad_im_module_exit() if bfad_im_module_init() failed. Fixes: 7725ccfda597 ("[SCSI] bfa: Brocade BFA FC SCSI driver") Signed-off-by: Ye Bin Link: https://lore.kernel.org/r/20241023011809.63466-1-yebin@huaweicloud.com Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/bfa/bfad.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index e5aa982ffedc..d4455ca3a7dd 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c @@ -1699,9 +1699,8 @@ bfad_init(void) error = bfad_im_module_init(); if (error) { - error = -ENOMEM; printk(KERN_WARNING "bfad_im_module_init failure\n"); - goto ext; + return -ENOMEM; } if (strcmp(FCPI_NAME, " fcpim") == 0) From 31f29289c7eace62a29007bf00e09a6d8339ad7e Mon Sep 17 00:00:00 2001 From: Zeng Heng Date: Thu, 24 Oct 2024 16:44:17 +0800 Subject: [PATCH 116/118] scsi: fusion: Remove unused variable 'rc' [ Upstream commit bd65694223f7ad11c790ab63ad1af87a771192ee ] The return value of scsi_device_reprobe() is currently ignored in _scsih_reprobe_lun(). Fixing the calling code to deal with the potential error is non-trivial, so for now just WARN_ON(). The handling of scsi_device_reprobe()'s return value refers to _scsih_reprobe_lun() and the following link: https://lore.kernel.org/all/094fdbf57487af4f395238c0525b2a560c8f68f0.1469766027.git.calvinowens@fb.com/ Fixes: f99be43b3024 ("[SCSI] fusion: power pc and miscellaneous bug fixs") Signed-off-by: Zeng Heng Link: https://lore.kernel.org/r/20241024084417.154655-1-zengheng4@huawei.com Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/message/fusion/mptsas.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 34901bcd1ce8..452774cf40cb 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -4234,10 +4234,8 @@ mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num, static void mptsas_reprobe_lun(struct scsi_device *sdev, void *data) { - int rc; - sdev->no_uld_attach = data ? 1 : 0; - rc = scsi_device_reprobe(sdev); + WARN_ON(scsi_device_reprobe(sdev)); } static void From b514f45e0fe18d763a1afc34401b1585333cb329 Mon Sep 17 00:00:00 2001 From: Zhen Lei Date: Sat, 26 Oct 2024 20:57:10 +0800 Subject: [PATCH 117/118] scsi: qedf: Fix a possible memory leak in qedf_alloc_and_init_sb() [ Upstream commit c62c30429db3eb4ced35c7fcf6f04a61ce3a01bb ] Hook "qed_ops->common->sb_init = qed_sb_init" does not release the DMA memory sb_virt when it fails. Add dma_free_coherent() to free it. This is the same way as qedr_alloc_mem_sb() and qede_alloc_mem_sb(). Fixes: 61d8658b4a43 ("scsi: qedf: Add QLogic FastLinQ offload FCoE driver framework.") Signed-off-by: Zhen Lei Link: https://lore.kernel.org/r/20241026125711.484-2-thunder.leizhen@huawei.com Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/qedf/qedf_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index 179967774cc8..288c96e7bc39 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -2739,6 +2739,7 @@ static int qedf_alloc_and_init_sb(struct qedf_ctx *qedf, sb_id, QED_SB_TYPE_STORAGE); if (ret) { + dma_free_coherent(&qedf->pdev->dev, sizeof(*sb_virt), sb_virt, sb_phys); QEDF_ERR(&qedf->dbg_ctx, "Status block initialization failed (0x%x) for id = %d.\n", ret, sb_id); From b778b5240485106abf665eb509cc01779ed0cb00 Mon Sep 17 00:00:00 2001 From: Zhen Lei Date: Sat, 26 Oct 2024 20:57:11 +0800 Subject: [PATCH 118/118] scsi: qedi: Fix a possible memory leak in qedi_alloc_and_init_sb() [ Upstream commit 95bbdca4999bc59a72ebab01663d421d6ce5775d ] Hook "qedi_ops->common->sb_init = qed_sb_init" does not release the DMA memory sb_virt when it fails. Add dma_free_coherent() to free it. This is the same way as qedr_alloc_mem_sb() and qede_alloc_mem_sb(). Fixes: ace7f46ba5fd ("scsi: qedi: Add QLogic FastLinQ offload iSCSI driver framework.") Signed-off-by: Zhen Lei Link: https://lore.kernel.org/r/20241026125711.484-3-thunder.leizhen@huawei.com Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/qedi/qedi_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c index 2ee109fb6561..825606c845e1 100644 --- a/drivers/scsi/qedi/qedi_main.c +++ b/drivers/scsi/qedi/qedi_main.c @@ -369,6 +369,7 @@ static int qedi_alloc_and_init_sb(struct qedi_ctx *qedi, ret = qedi_ops->common->sb_init(qedi->cdev, sb_info, sb_virt, sb_phys, sb_id, QED_SB_TYPE_STORAGE); if (ret) { + dma_free_coherent(&qedi->pdev->dev, sizeof(*sb_virt), sb_virt, sb_phys); QEDI_ERR(&qedi->dbg_ctx, "Status block initialization failed for id = %d.\n", sb_id);