From: Sasha Levin Date: Sat, 11 May 2024 13:02:56 +0000 (-0400) Subject: Fixes for 6.6 X-Git-Tag: v4.19.314~93 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4aa4c5a300d047553d79687c13b3fa0cf5ced872;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 6.6 Signed-off-by: Sasha Levin --- diff --git a/queue-6.6/dm-amd-pm-fix-problems-with-reboot-shutdown-for-some.patch b/queue-6.6/dm-amd-pm-fix-problems-with-reboot-shutdown-for-some.patch new file mode 100644 index 00000000000..e199a9c1be8 --- /dev/null +++ b/queue-6.6/dm-amd-pm-fix-problems-with-reboot-shutdown-for-some.patch @@ -0,0 +1,40 @@ +From 81a6fdd569309238b07c02fe2ead7ff788dd5a44 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 May 2024 13:32:17 -0500 +Subject: dm/amd/pm: Fix problems with reboot/shutdown for some SMU + 13.0.4/13.0.11 users + +From: Mario Limonciello + +[ Upstream commit cd94d1b182d2986378550c9087571991bfee01d4 ] + +Limit the workaround introduced by commit 31729e8c21ec ("drm/amd/pm: fixes +a random hang in S4 for SMU v13.0.4/11") to only run in the s4 path. + +Cc: Tim Huang +Fixes: 31729e8c21ec ("drm/amd/pm: fixes a random hang in S4 for SMU v13.0.4/11") +Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3351 +Signed-off-by: Mario Limonciello +Acked-by: Alex Deucher +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c +index 1d1917e1b63f4..cd674ef5adb19 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c +@@ -226,7 +226,7 @@ static int smu_v13_0_4_system_features_control(struct smu_context *smu, bool en) + struct amdgpu_device *adev = smu->adev; + int ret = 0; + +- if (!en && !adev->in_s0ix) { ++ if (!en && adev->in_s4) { + /* Adds a GFX reset as workaround just before sending the + * MP1_UNLOAD message to prevent GC/RLC/PMFW from entering + * an invalid state. +-- +2.43.0 + diff --git a/queue-6.6/drm-connector-add-n-to-message-about-demoting-connec.patch b/queue-6.6/drm-connector-add-n-to-message-about-demoting-connec.patch new file mode 100644 index 00000000000..b7ec00e20b6 --- /dev/null +++ b/queue-6.6/drm-connector-add-n-to-message-about-demoting-connec.patch @@ -0,0 +1,39 @@ +From c39e8f393012eb0f928f5ffebac1fd5f2221ad3e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 May 2024 15:32:35 -0700 +Subject: drm/connector: Add \n to message about demoting connector + force-probes + +From: Douglas Anderson + +[ Upstream commit 6897204ea3df808d342c8e4613135728bc538bcd ] + +The debug print clearly lacks a \n at the end. Add it. + +Fixes: 8f86c82aba8b ("drm/connector: demote connector force-probes for non-master clients") +Reviewed-by: Abhinav Kumar +Reviewed-by: Simon Ser +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Douglas Anderson +Link: https://patchwork.freedesktop.org/patch/msgid/20240502153234.1.I2052f01c8d209d9ae9c300b87c6e4f60bd3cc99e@changeid +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/drm_connector.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c +index c44d5bcf12847..309aad5f0c808 100644 +--- a/drivers/gpu/drm/drm_connector.c ++++ b/drivers/gpu/drm/drm_connector.c +@@ -2925,7 +2925,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, + dev->mode_config.max_width, + dev->mode_config.max_height); + else +- drm_dbg_kms(dev, "User-space requested a forced probe on [CONNECTOR:%d:%s] but is not the DRM master, demoting to read-only probe", ++ drm_dbg_kms(dev, "User-space requested a forced probe on [CONNECTOR:%d:%s] but is not the DRM master, demoting to read-only probe\n", + connector->base.id, connector->name); + } + +-- +2.43.0 + diff --git a/queue-6.6/drm-meson-dw-hdmi-add-bandgap-setting-for-g12.patch b/queue-6.6/drm-meson-dw-hdmi-add-bandgap-setting-for-g12.patch new file mode 100644 index 00000000000..a80969186c3 --- /dev/null +++ b/queue-6.6/drm-meson-dw-hdmi-add-bandgap-setting-for-g12.patch @@ -0,0 +1,135 @@ +From 99c1642e623d3e37a6463a50a45380aea3679336 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Apr 2024 18:02:54 +0200 +Subject: drm/meson: dw-hdmi: add bandgap setting for g12 + +From: Jerome Brunet + +[ Upstream commit 08001033121dd92b8297a5b7333636b466c30f13 ] + +When no mode is set, the utility pin appears to be grounded. No signal +is getting through. + +This is problematic because ARC and eARC use this line and may do so even +if no display mode is set. + +This change enable the bandgap setting on g12 chip, which fix the problem +with the utility pin. This is done by restoring init values on PHY init and +disable. + +Fixes: 3b7c1237a72a ("drm/meson: Add G12A support for the DW-HDMI Glue") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://lore.kernel.org/r/20240426160256.3089978-3-jbrunet@baylibre.com +Signed-off-by: Neil Armstrong +Link: https://patchwork.freedesktop.org/patch/msgid/20240426160256.3089978-3-jbrunet@baylibre.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/meson/meson_dw_hdmi.c | 43 ++++++++++++++++----------- + 1 file changed, 26 insertions(+), 17 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c +index a83d93078537d..5565f7777529f 100644 +--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c ++++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c +@@ -106,6 +106,8 @@ + #define HHI_HDMI_CLK_CNTL 0x1cc /* 0x73 */ + #define HHI_HDMI_PHY_CNTL0 0x3a0 /* 0xe8 */ + #define HHI_HDMI_PHY_CNTL1 0x3a4 /* 0xe9 */ ++#define PHY_CNTL1_INIT 0x03900000 ++#define PHY_INVERT BIT(17) + #define HHI_HDMI_PHY_CNTL2 0x3a8 /* 0xea */ + #define HHI_HDMI_PHY_CNTL3 0x3ac /* 0xeb */ + #define HHI_HDMI_PHY_CNTL4 0x3b0 /* 0xec */ +@@ -130,6 +132,8 @@ struct meson_dw_hdmi_data { + unsigned int addr); + void (*dwc_write)(struct meson_dw_hdmi *dw_hdmi, + unsigned int addr, unsigned int data); ++ u32 cntl0_init; ++ u32 cntl1_init; + }; + + struct meson_dw_hdmi { +@@ -458,7 +462,9 @@ static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi, + + DRM_DEBUG_DRIVER("\n"); + +- regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0); ++ /* Fallback to init mode */ ++ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL1, dw_hdmi->data->cntl1_init); ++ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, dw_hdmi->data->cntl0_init); + } + + static enum drm_connector_status dw_hdmi_read_hpd(struct dw_hdmi *hdmi, +@@ -576,11 +582,22 @@ static const struct regmap_config meson_dw_hdmi_regmap_config = { + .fast_io = true, + }; + +-static const struct meson_dw_hdmi_data meson_dw_hdmi_gx_data = { ++static const struct meson_dw_hdmi_data meson_dw_hdmi_gxbb_data = { + .top_read = dw_hdmi_top_read, + .top_write = dw_hdmi_top_write, + .dwc_read = dw_hdmi_dwc_read, + .dwc_write = dw_hdmi_dwc_write, ++ .cntl0_init = 0x0, ++ .cntl1_init = PHY_CNTL1_INIT | PHY_INVERT, ++}; ++ ++static const struct meson_dw_hdmi_data meson_dw_hdmi_gxl_data = { ++ .top_read = dw_hdmi_top_read, ++ .top_write = dw_hdmi_top_write, ++ .dwc_read = dw_hdmi_dwc_read, ++ .dwc_write = dw_hdmi_dwc_write, ++ .cntl0_init = 0x0, ++ .cntl1_init = PHY_CNTL1_INIT, + }; + + static const struct meson_dw_hdmi_data meson_dw_hdmi_g12a_data = { +@@ -588,6 +605,8 @@ static const struct meson_dw_hdmi_data meson_dw_hdmi_g12a_data = { + .top_write = dw_hdmi_g12a_top_write, + .dwc_read = dw_hdmi_g12a_dwc_read, + .dwc_write = dw_hdmi_g12a_dwc_write, ++ .cntl0_init = 0x000b4242, /* Bandgap */ ++ .cntl1_init = PHY_CNTL1_INIT, + }; + + static void meson_dw_hdmi_init(struct meson_dw_hdmi *meson_dw_hdmi) +@@ -626,18 +645,8 @@ static void meson_dw_hdmi_init(struct meson_dw_hdmi *meson_dw_hdmi) + meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12)); + + /* Setup PHY */ +- regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, +- 0xffff << 16, 0x0390 << 16); +- +- /* BIT_INVERT */ +- if (dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxl-dw-hdmi") || +- dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxm-dw-hdmi") || +- dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-g12a-dw-hdmi")) +- regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, +- BIT(17), 0); +- else +- regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, +- BIT(17), BIT(17)); ++ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL1, meson_dw_hdmi->data->cntl1_init); ++ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, meson_dw_hdmi->data->cntl0_init); + + /* Enable HDMI-TX Interrupt */ + meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, +@@ -848,11 +857,11 @@ static const struct dev_pm_ops meson_dw_hdmi_pm_ops = { + + static const struct of_device_id meson_dw_hdmi_of_table[] = { + { .compatible = "amlogic,meson-gxbb-dw-hdmi", +- .data = &meson_dw_hdmi_gx_data }, ++ .data = &meson_dw_hdmi_gxbb_data }, + { .compatible = "amlogic,meson-gxl-dw-hdmi", +- .data = &meson_dw_hdmi_gx_data }, ++ .data = &meson_dw_hdmi_gxl_data }, + { .compatible = "amlogic,meson-gxm-dw-hdmi", +- .data = &meson_dw_hdmi_gx_data }, ++ .data = &meson_dw_hdmi_gxl_data }, + { .compatible = "amlogic,meson-g12a-dw-hdmi", + .data = &meson_dw_hdmi_g12a_data }, + { } +-- +2.43.0 + diff --git a/queue-6.6/drm-meson-dw-hdmi-power-up-phy-on-device-init.patch b/queue-6.6/drm-meson-dw-hdmi-power-up-phy-on-device-init.patch new file mode 100644 index 00000000000..ce272662d10 --- /dev/null +++ b/queue-6.6/drm-meson-dw-hdmi-power-up-phy-on-device-init.patch @@ -0,0 +1,109 @@ +From 78add80f60db6a08a836a3970439cfcf04f70c95 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Apr 2024 18:02:53 +0200 +Subject: drm/meson: dw-hdmi: power up phy on device init + +From: Jerome Brunet + +[ Upstream commit 04703bfd7f99c016a823c74712b97f8b5590ce87 ] + +The phy is not in a useful state right after init. It will become useful, +including for auxiliary function such as CEC or ARC, after the first mode +is set. This is a problem on systems where the display is using another +interface like DSI or CVBS. + +This change refactor the init and mode change callback to power up the PHY +on init and leave only what is necessary for mode changes in the related +function. This is enough to fix CEC operation when HDMI display is not +enabled. + +Fixes: 3f68be7d8e96 ("drm/meson: Add support for HDMI encoder and DW-HDMI bridge + PHY") +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Link: https://lore.kernel.org/r/20240426160256.3089978-2-jbrunet@baylibre.com +Signed-off-by: Neil Armstrong +Link: https://patchwork.freedesktop.org/patch/msgid/20240426160256.3089978-2-jbrunet@baylibre.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/meson/meson_dw_hdmi.c | 51 +++++++++------------------ + 1 file changed, 17 insertions(+), 34 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c +index 5a9538bc0e26f..a83d93078537d 100644 +--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c ++++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c +@@ -384,26 +384,6 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, + dw_hdmi_bus_fmt_is_420(hdmi)) + mode_is_420 = true; + +- /* Enable clocks */ +- regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100); +- +- /* Bring HDMITX MEM output of power down */ +- regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0); +- +- /* Bring out of reset */ +- dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_SW_RESET, 0); +- +- /* Enable internal pixclk, tmds_clk, spdif_clk, i2s_clk, cecclk */ +- dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL, +- 0x3, 0x3); +- +- /* Enable cec_clk and hdcp22_tmdsclk_en */ +- dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL, +- 0x3 << 4, 0x3 << 4); +- +- /* Enable normal output to PHY */ +- dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12)); +- + /* TMDS pattern setup */ + if (mode->clock > 340000 && !mode_is_420) { + dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, +@@ -425,20 +405,6 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, + /* Setup PHY parameters */ + meson_hdmi_phy_setup_mode(dw_hdmi, mode, mode_is_420); + +- /* Setup PHY */ +- regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, +- 0xffff << 16, 0x0390 << 16); +- +- /* BIT_INVERT */ +- if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") || +- dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi") || +- dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-g12a-dw-hdmi")) +- regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, +- BIT(17), 0); +- else +- regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, +- BIT(17), BIT(17)); +- + /* Disable clock, fifo, fifo_wr */ + regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0); + +@@ -656,6 +622,23 @@ static void meson_dw_hdmi_init(struct meson_dw_hdmi *meson_dw_hdmi) + meson_dw_hdmi->data->top_write(meson_dw_hdmi, + HDMITX_TOP_CLK_CNTL, 0xff); + ++ /* Enable normal output to PHY */ ++ meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12)); ++ ++ /* Setup PHY */ ++ regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, ++ 0xffff << 16, 0x0390 << 16); ++ ++ /* BIT_INVERT */ ++ if (dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxl-dw-hdmi") || ++ dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxm-dw-hdmi") || ++ dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-g12a-dw-hdmi")) ++ regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, ++ BIT(17), 0); ++ else ++ regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, ++ BIT(17), BIT(17)); ++ + /* Enable HDMI-TX Interrupt */ + meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, + HDMITX_TOP_INTR_CORE); +-- +2.43.0 + diff --git a/queue-6.6/gpiolib-cdev-fix-uninitialised-kfifo.patch b/queue-6.6/gpiolib-cdev-fix-uninitialised-kfifo.patch new file mode 100644 index 00000000000..dbc7044a093 --- /dev/null +++ b/queue-6.6/gpiolib-cdev-fix-uninitialised-kfifo.patch @@ -0,0 +1,62 @@ +From f99eb326707129e6ad56d8fbd6d96639ce4391c6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 May 2024 14:53:42 +0800 +Subject: gpiolib: cdev: fix uninitialised kfifo + +From: Kent Gibson + +[ Upstream commit ee0166b637a5e376118e9659e5b4148080f1d27e ] + +If a line is requested with debounce, and that results in debouncing +in software, and the line is subsequently reconfigured to enable edge +detection then the allocation of the kfifo to contain edge events is +overlooked. This results in events being written to and read from an +uninitialised kfifo. Read events are returned to userspace. + +Initialise the kfifo in the case where the software debounce is +already active. + +Fixes: 65cff7046406 ("gpiolib: cdev: support setting debounce") +Signed-off-by: Kent Gibson +Link: https://lore.kernel.org/r/20240510065342.36191-1-warthog618@gmail.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpiolib-cdev.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c +index 7037dc47ca0e0..b4b71e68b90de 100644 +--- a/drivers/gpio/gpiolib-cdev.c ++++ b/drivers/gpio/gpiolib-cdev.c +@@ -1243,6 +1243,8 @@ static int edge_detector_update(struct line *line, + struct gpio_v2_line_config *lc, + unsigned int line_idx, u64 edflags) + { ++ u64 eflags; ++ int ret; + u64 active_edflags = READ_ONCE(line->edflags); + unsigned int debounce_period_us = + gpio_v2_line_config_debounce_period(lc, line_idx); +@@ -1254,6 +1256,18 @@ static int edge_detector_update(struct line *line, + /* sw debounced and still will be...*/ + if (debounce_period_us && READ_ONCE(line->sw_debounced)) { + line_set_debounce_period(line, debounce_period_us); ++ /* ++ * ensure event fifo is initialised if edge detection ++ * is now enabled. ++ */ ++ eflags = edflags & GPIO_V2_LINE_EDGE_FLAGS; ++ if (eflags && !kfifo_initialized(&line->req->events)) { ++ ret = kfifo_alloc(&line->req->events, ++ line->req->event_buffer_size, ++ GFP_KERNEL); ++ if (ret) ++ return ret; ++ } + return 0; + } + +-- +2.43.0 + diff --git a/queue-6.6/gpiolib-cdev-fix-use-after-free-in-lineinfo_changed_.patch b/queue-6.6/gpiolib-cdev-fix-use-after-free-in-lineinfo_changed_.patch new file mode 100644 index 00000000000..14abb5ab129 --- /dev/null +++ b/queue-6.6/gpiolib-cdev-fix-use-after-free-in-lineinfo_changed_.patch @@ -0,0 +1,77 @@ +From 84d4033a485f208739ae8a0d083556dc7bc4f867 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 May 2024 22:11:56 +0800 +Subject: gpiolib: cdev: Fix use after free in lineinfo_changed_notify + +From: Zhongqiu Han + +[ Upstream commit 02f6b0e1ec7e0e7d059dddc893645816552039da ] + +The use-after-free issue occurs as follows: when the GPIO chip device file +is being closed by invoking gpio_chrdev_release(), watched_lines is freed +by bitmap_free(), but the unregistration of lineinfo_changed_nb notifier +chain failed due to waiting write rwsem. Additionally, one of the GPIO +chip's lines is also in the release process and holds the notifier chain's +read rwsem. Consequently, a race condition leads to the use-after-free of +watched_lines. + +Here is the typical stack when issue happened: + +[free] +gpio_chrdev_release() + --> bitmap_free(cdev->watched_lines) <-- freed + --> blocking_notifier_chain_unregister() + --> down_write(&nh->rwsem) <-- waiting rwsem + --> __down_write_common() + --> rwsem_down_write_slowpath() + --> schedule_preempt_disabled() + --> schedule() + +[use] +st54spi_gpio_dev_release() + --> gpio_free() + --> gpiod_free() + --> gpiod_free_commit() + --> gpiod_line_state_notify() + --> blocking_notifier_call_chain() + --> down_read(&nh->rwsem); <-- held rwsem + --> notifier_call_chain() + --> lineinfo_changed_notify() + --> test_bit(xxxx, cdev->watched_lines) <-- use after free + +The side effect of the use-after-free issue is that a GPIO line event is +being generated for userspace where it shouldn't. However, since the chrdev +is being closed, userspace won't have the chance to read that event anyway. + +To fix the issue, call the bitmap_free() function after the unregistration +of lineinfo_changed_nb notifier chain. + +Fixes: 51c1064e82e7 ("gpiolib: add new ioctl() for monitoring changes in line info") +Signed-off-by: Zhongqiu Han +Link: https://lore.kernel.org/r/20240505141156.2944912-1-quic_zhonhan@quicinc.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpiolib-cdev.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c +index 84125e55de101..ebf5b8ef3b5dc 100644 +--- a/drivers/gpio/gpiolib-cdev.c ++++ b/drivers/gpio/gpiolib-cdev.c +@@ -2816,11 +2816,11 @@ static int gpio_chrdev_release(struct inode *inode, struct file *file) + struct gpio_chardev_data *cdev = file->private_data; + struct gpio_device *gdev = cdev->gdev; + +- bitmap_free(cdev->watched_lines); + blocking_notifier_chain_unregister(&gdev->device_notifier, + &cdev->device_unregistered_nb); + blocking_notifier_chain_unregister(&gdev->line_state_notifier, + &cdev->lineinfo_changed_nb); ++ bitmap_free(cdev->watched_lines); + gpio_device_put(gdev); + kfree(cdev); + +-- +2.43.0 + diff --git a/queue-6.6/gpiolib-cdev-relocate-debounce_period_us-from-struct.patch b/queue-6.6/gpiolib-cdev-relocate-debounce_period_us-from-struct.patch new file mode 100644 index 00000000000..61700e4404d --- /dev/null +++ b/queue-6.6/gpiolib-cdev-relocate-debounce_period_us-from-struct.patch @@ -0,0 +1,348 @@ +From 6301161ab30eb6f099600071fada6bfc641bdb8d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Dec 2023 08:41:54 +0800 +Subject: gpiolib: cdev: relocate debounce_period_us from struct gpio_desc + +From: Kent Gibson + +[ Upstream commit 9344e34e7992fec95ce6210d95ac01437dd327ab ] + +Store the debounce period for a requested line locally, rather than in +the debounce_period_us field in the gpiolib struct gpio_desc. + +Add a global tree of lines containing supplemental line information +to make the debounce period available to be reported by the +GPIO_V2_GET_LINEINFO_IOCTL and the line change notifier. + +Signed-off-by: Kent Gibson +Reviewed-by: Andy Shevchenko +Signed-off-by: Bartosz Golaszewski +Stable-dep-of: ee0166b637a5 ("gpiolib: cdev: fix uninitialised kfifo") +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpiolib-cdev.c | 165 +++++++++++++++++++++++++++++++----- + 1 file changed, 142 insertions(+), 23 deletions(-) + +diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c +index ebf5b8ef3b5dc..7037dc47ca0e0 100644 +--- a/drivers/gpio/gpiolib-cdev.c ++++ b/drivers/gpio/gpiolib-cdev.c +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -21,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -461,6 +463,7 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) + + /** + * struct line - contains the state of a requested line ++ * @node: to store the object in supinfo_tree if supplemental + * @desc: the GPIO descriptor for this line. + * @req: the corresponding line request + * @irq: the interrupt triggered in response to events on this GPIO +@@ -473,6 +476,7 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) + * @line_seqno: the seqno for the current edge event in the sequence of + * events for this line. + * @work: the worker that implements software debouncing ++ * @debounce_period_us: the debounce period in microseconds + * @sw_debounced: flag indicating if the software debouncer is active + * @level: the current debounced physical level of the line + * @hdesc: the Hardware Timestamp Engine (HTE) descriptor +@@ -481,6 +485,7 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) + * @last_seqno: the last sequence number before debounce period expires + */ + struct line { ++ struct rb_node node; + struct gpio_desc *desc; + /* + * -- edge detector specific fields -- +@@ -514,6 +519,15 @@ struct line { + * -- debouncer specific fields -- + */ + struct delayed_work work; ++ /* ++ * debounce_period_us is accessed by debounce_irq_handler() and ++ * process_hw_ts() which are disabled when modified by ++ * debounce_setup(), edge_detector_setup() or edge_detector_stop() ++ * or can live with a stale version when updated by ++ * edge_detector_update(). ++ * The modifying functions are themselves mutually exclusive. ++ */ ++ unsigned int debounce_period_us; + /* + * sw_debounce is accessed by linereq_set_config(), which is the + * only setter, and linereq_get_values(), which can live with a +@@ -546,6 +560,17 @@ struct line { + #endif /* CONFIG_HTE */ + }; + ++/* ++ * a rbtree of the struct lines containing supplemental info. ++ * Used to populate gpio_v2_line_info with cdev specific fields not contained ++ * in the struct gpio_desc. ++ * A line is determined to contain supplemental information by ++ * line_has_supinfo(). ++ */ ++static struct rb_root supinfo_tree = RB_ROOT; ++/* covers supinfo_tree */ ++static DEFINE_SPINLOCK(supinfo_lock); ++ + /** + * struct linereq - contains the state of a userspace line request + * @gdev: the GPIO device the line request pertains to +@@ -559,7 +584,8 @@ struct line { + * this line request. Note that this is not used when @num_lines is 1, as + * the line_seqno is then the same and is cheaper to calculate. + * @config_mutex: mutex for serializing ioctl() calls to ensure consistency +- * of configuration, particularly multi-step accesses to desc flags. ++ * of configuration, particularly multi-step accesses to desc flags and ++ * changes to supinfo status. + * @lines: the lines held by this line request, with @num_lines elements. + */ + struct linereq { +@@ -575,6 +601,103 @@ struct linereq { + struct line lines[]; + }; + ++static void supinfo_insert(struct line *line) ++{ ++ struct rb_node **new = &(supinfo_tree.rb_node), *parent = NULL; ++ struct line *entry; ++ ++ guard(spinlock)(&supinfo_lock); ++ ++ while (*new) { ++ entry = container_of(*new, struct line, node); ++ ++ parent = *new; ++ if (line->desc < entry->desc) { ++ new = &((*new)->rb_left); ++ } else if (line->desc > entry->desc) { ++ new = &((*new)->rb_right); ++ } else { ++ /* this should never happen */ ++ WARN(1, "duplicate line inserted"); ++ return; ++ } ++ } ++ ++ rb_link_node(&line->node, parent, new); ++ rb_insert_color(&line->node, &supinfo_tree); ++} ++ ++static void supinfo_erase(struct line *line) ++{ ++ guard(spinlock)(&supinfo_lock); ++ ++ rb_erase(&line->node, &supinfo_tree); ++} ++ ++static struct line *supinfo_find(struct gpio_desc *desc) ++{ ++ struct rb_node *node = supinfo_tree.rb_node; ++ struct line *line; ++ ++ while (node) { ++ line = container_of(node, struct line, node); ++ if (desc < line->desc) ++ node = node->rb_left; ++ else if (desc > line->desc) ++ node = node->rb_right; ++ else ++ return line; ++ } ++ return NULL; ++} ++ ++static void supinfo_to_lineinfo(struct gpio_desc *desc, ++ struct gpio_v2_line_info *info) ++{ ++ struct gpio_v2_line_attribute *attr; ++ struct line *line; ++ ++ guard(spinlock)(&supinfo_lock); ++ ++ line = supinfo_find(desc); ++ if (!line) ++ return; ++ ++ attr = &info->attrs[info->num_attrs]; ++ attr->id = GPIO_V2_LINE_ATTR_ID_DEBOUNCE; ++ attr->debounce_period_us = READ_ONCE(line->debounce_period_us); ++ info->num_attrs++; ++} ++ ++static inline bool line_has_supinfo(struct line *line) ++{ ++ return READ_ONCE(line->debounce_period_us); ++} ++ ++/* ++ * Checks line_has_supinfo() before and after the change to avoid unnecessary ++ * supinfo_tree access. ++ * Called indirectly by linereq_create() or linereq_set_config() so line ++ * is already protected from concurrent changes. ++ */ ++static void line_set_debounce_period(struct line *line, ++ unsigned int debounce_period_us) ++{ ++ bool was_suppl = line_has_supinfo(line); ++ ++ WRITE_ONCE(line->debounce_period_us, debounce_period_us); ++ ++ /* if supinfo status is unchanged then we're done */ ++ if (line_has_supinfo(line) == was_suppl) ++ return; ++ ++ /* supinfo status has changed, so update the tree */ ++ if (was_suppl) ++ supinfo_erase(line); ++ else ++ supinfo_insert(line); ++} ++ + #define GPIO_V2_LINE_BIAS_FLAGS \ + (GPIO_V2_LINE_FLAG_BIAS_PULL_UP | \ + GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN | \ +@@ -742,7 +865,7 @@ static enum hte_return process_hw_ts(struct hte_ts_data *ts, void *p) + line->total_discard_seq++; + line->last_seqno = ts->seq; + mod_delayed_work(system_wq, &line->work, +- usecs_to_jiffies(READ_ONCE(line->desc->debounce_period_us))); ++ usecs_to_jiffies(READ_ONCE(line->debounce_period_us))); + } else { + if (unlikely(ts->seq < line->line_seqno)) + return HTE_CB_HANDLED; +@@ -883,7 +1006,7 @@ static irqreturn_t debounce_irq_handler(int irq, void *p) + struct line *line = p; + + mod_delayed_work(system_wq, &line->work, +- usecs_to_jiffies(READ_ONCE(line->desc->debounce_period_us))); ++ usecs_to_jiffies(READ_ONCE(line->debounce_period_us))); + + return IRQ_HANDLED; + } +@@ -966,7 +1089,7 @@ static int debounce_setup(struct line *line, unsigned int debounce_period_us) + /* try hardware */ + ret = gpiod_set_debounce(line->desc, debounce_period_us); + if (!ret) { +- WRITE_ONCE(line->desc->debounce_period_us, debounce_period_us); ++ line_set_debounce_period(line, debounce_period_us); + return ret; + } + if (ret != -ENOTSUPP) +@@ -1051,8 +1174,7 @@ static void edge_detector_stop(struct line *line) + cancel_delayed_work_sync(&line->work); + WRITE_ONCE(line->sw_debounced, 0); + WRITE_ONCE(line->edflags, 0); +- if (line->desc) +- WRITE_ONCE(line->desc->debounce_period_us, 0); ++ line_set_debounce_period(line, 0); + /* do not change line->level - see comment in debounced_value() */ + } + +@@ -1078,7 +1200,7 @@ static int edge_detector_setup(struct line *line, + ret = debounce_setup(line, debounce_period_us); + if (ret) + return ret; +- WRITE_ONCE(line->desc->debounce_period_us, debounce_period_us); ++ line_set_debounce_period(line, debounce_period_us); + } + + /* detection disabled or sw debouncer will provide edge detection */ +@@ -1126,12 +1248,12 @@ static int edge_detector_update(struct line *line, + gpio_v2_line_config_debounce_period(lc, line_idx); + + if ((active_edflags == edflags) && +- (READ_ONCE(line->desc->debounce_period_us) == debounce_period_us)) ++ (READ_ONCE(line->debounce_period_us) == debounce_period_us)) + return 0; + + /* sw debounced and still will be...*/ + if (debounce_period_us && READ_ONCE(line->sw_debounced)) { +- WRITE_ONCE(line->desc->debounce_period_us, debounce_period_us); ++ line_set_debounce_period(line, debounce_period_us); + return 0; + } + +@@ -1606,6 +1728,7 @@ static ssize_t linereq_read(struct file *file, char __user *buf, + + static void linereq_free(struct linereq *lr) + { ++ struct line *line; + unsigned int i; + + if (lr->device_unregistered_nb.notifier_call) +@@ -1613,10 +1736,14 @@ static void linereq_free(struct linereq *lr) + &lr->device_unregistered_nb); + + for (i = 0; i < lr->num_lines; i++) { +- if (lr->lines[i].desc) { +- edge_detector_stop(&lr->lines[i]); +- gpiod_free(lr->lines[i].desc); +- } ++ line = &lr->lines[i]; ++ if (!line->desc) ++ continue; ++ ++ edge_detector_stop(line); ++ if (line_has_supinfo(line)) ++ supinfo_erase(line); ++ gpiod_free(line->desc); + } + kfifo_free(&lr->events); + kfree(lr->label); +@@ -2316,8 +2443,6 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc, + struct gpio_chip *gc = desc->gdev->chip; + bool ok_for_pinctrl; + unsigned long flags; +- u32 debounce_period_us; +- unsigned int num_attrs = 0; + + memset(info, 0, sizeof(*info)); + info->offset = gpio_chip_hwgpio(desc); +@@ -2384,14 +2509,6 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc, + else if (test_bit(FLAG_EVENT_CLOCK_HTE, &desc->flags)) + info->flags |= GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE; + +- debounce_period_us = READ_ONCE(desc->debounce_period_us); +- if (debounce_period_us) { +- info->attrs[num_attrs].id = GPIO_V2_LINE_ATTR_ID_DEBOUNCE; +- info->attrs[num_attrs].debounce_period_us = debounce_period_us; +- num_attrs++; +- } +- info->num_attrs = num_attrs; +- + spin_unlock_irqrestore(&gpio_lock, flags); + } + +@@ -2498,6 +2615,7 @@ static int lineinfo_get(struct gpio_chardev_data *cdev, void __user *ip, + return -EBUSY; + } + gpio_desc_to_lineinfo(desc, &lineinfo); ++ supinfo_to_lineinfo(desc, &lineinfo); + + if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) { + if (watch) +@@ -2596,6 +2714,7 @@ static int lineinfo_changed_notify(struct notifier_block *nb, + chg.event_type = action; + chg.timestamp_ns = ktime_get_ns(); + gpio_desc_to_lineinfo(desc, &chg.info); ++ supinfo_to_lineinfo(desc, &chg.info); + + ret = kfifo_in_spinlocked(&cdev->events, &chg, 1, &cdev->wait.lock); + if (ret) +-- +2.43.0 + diff --git a/queue-6.6/series b/queue-6.6/series index 4965ffffc2f..ce34b1cd666 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -210,3 +210,10 @@ net-hns3-use-appropriate-barrier-function-after-sett.patch net-hns3-fix-port-vlan-filter-not-disabled-issue.patch net-hns3-fix-kernel-crash-when-devlink-reload-during.patch net-dsa-mv88e6xxx-add-phylink_get_caps-for-the-mv88e.patch +drm-meson-dw-hdmi-power-up-phy-on-device-init.patch +drm-meson-dw-hdmi-add-bandgap-setting-for-g12.patch +drm-connector-add-n-to-message-about-demoting-connec.patch +dm-amd-pm-fix-problems-with-reboot-shutdown-for-some.patch +gpiolib-cdev-fix-use-after-free-in-lineinfo_changed_.patch +gpiolib-cdev-relocate-debounce_period_us-from-struct.patch +gpiolib-cdev-fix-uninitialised-kfifo.patch