From: Sasha Levin Date: Wed, 27 May 2026 19:48:47 +0000 (-0400) Subject: Fixes for all trees X-Git-Tag: v5.10.258~48 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=233bc38a47f8135bb569ab7d22367769699c5293;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for all trees Signed-off-by: Sasha Levin --- diff --git a/queue-5.15/i3c-mipi-i3c-hci-correct-ring_ctrl_abort-handling-in.patch b/queue-5.15/i3c-mipi-i3c-hci-correct-ring_ctrl_abort-handling-in.patch new file mode 100644 index 0000000000..c9281d2318 --- /dev/null +++ b/queue-5.15/i3c-mipi-i3c-hci-correct-ring_ctrl_abort-handling-in.patch @@ -0,0 +1,78 @@ +From 7b32286981d332a4970cd8847bdf3808f229908e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 16:37:47 +0800 +Subject: i3c: mipi-i3c-hci: Correct RING_CTRL_ABORT handling in DMA dequeue + +From: Adrian Hunter + +[ Upstream commit b795e68bf3073d67bebbb5a44d93f49efc5b8cc7 ] + +The logic used to abort the DMA ring contains several flaws: + + 1. The driver unconditionally issues a ring abort even when the ring has + already stopped. + 2. The completion used to wait for abort completion is never + re-initialized, resulting in incorrect wait behavior. + 3. The abort sequence unintentionally clears RING_CTRL_ENABLE, which + resets hardware ring pointers and disrupts the controller state. + 4. If the ring is already stopped, the abort operation should be + considered successful without attempting further action. + +Fix the abort handling by checking whether the ring is running before +issuing an abort, re-initializing the completion when needed, ensuring that +RING_CTRL_ENABLE remains asserted during abort, and treating an already +stopped ring as a successful condition. + +Fixes: 9ad9a52cce282 ("i3c/master: introduce the mipi-i3c-hci driver") +Cc: stable@vger.kernel.org +Signed-off-by: Adrian Hunter +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260306072451.11131-9-adrian.hunter@intel.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Jianqiang kang +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/mipi-i3c-hci/dma.c | 27 +++++++++++++++++---------- + 1 file changed, 17 insertions(+), 10 deletions(-) + +diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c +index 168b21f6cf37c..d6678bee725b6 100644 +--- a/drivers/i3c/master/mipi-i3c-hci/dma.c ++++ b/drivers/i3c/master/mipi-i3c-hci/dma.c +@@ -448,16 +448,23 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci, + struct hci_rh_data *rh = &rings->headers[xfer_list[0].ring_number]; + unsigned int i; + bool did_unqueue = false; +- +- /* stop the ring */ +- rh_reg_write(RING_CONTROL, RING_CTRL_ABORT); +- if (wait_for_completion_timeout(&rh->op_done, HZ) == 0) { +- /* +- * We're deep in it if ever this condition is ever met. +- * Hardware might still be writing to memory, etc. +- */ +- dev_crit(&hci->master.dev, "unable to abort the ring\n"); +- WARN_ON(1); ++ u32 ring_status; ++ ++ ring_status = rh_reg_read(RING_STATUS); ++ if (ring_status & RING_STATUS_RUNNING) { ++ /* stop the ring */ ++ reinit_completion(&rh->op_done); ++ rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE | RING_CTRL_ABORT); ++ wait_for_completion_timeout(&rh->op_done, HZ); ++ ring_status = rh_reg_read(RING_STATUS); ++ if (ring_status & RING_STATUS_RUNNING) { ++ /* ++ * We're deep in it if ever this condition is ever met. ++ * Hardware might still be writing to memory, etc. ++ */ ++ dev_crit(&hci->master.dev, "unable to abort the ring\n"); ++ WARN_ON(1); ++ } + } + + for (i = 0; i < n; i++) { +-- +2.53.0 + diff --git a/queue-5.15/series b/queue-5.15/series index fd27f2b761..a95e4b8776 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -680,3 +680,4 @@ wifi-mac80211-check-tdls-flag-in-ieee80211_tdls_oper.patch kvm-x86-acquire-srcu-in-kvm_get_mp_state-to-protect-.patch revert-s390-cio-fix-device-lifecycle-handling-in-css.patch smb-client-reject-userspace-cifs.spnego-descriptions.patch +i3c-mipi-i3c-hci-correct-ring_ctrl_abort-handling-in.patch diff --git a/queue-6.1/i3c-mipi-i3c-hci-correct-ring_ctrl_abort-handling-in.patch b/queue-6.1/i3c-mipi-i3c-hci-correct-ring_ctrl_abort-handling-in.patch new file mode 100644 index 0000000000..298e5f880f --- /dev/null +++ b/queue-6.1/i3c-mipi-i3c-hci-correct-ring_ctrl_abort-handling-in.patch @@ -0,0 +1,78 @@ +From 65cff8906fcf152c60bf7130fb4004824dc54288 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 14:21:07 +0800 +Subject: i3c: mipi-i3c-hci: Correct RING_CTRL_ABORT handling in DMA dequeue + +From: Adrian Hunter + +[ Upstream commit b795e68bf3073d67bebbb5a44d93f49efc5b8cc7 ] + +The logic used to abort the DMA ring contains several flaws: + + 1. The driver unconditionally issues a ring abort even when the ring has + already stopped. + 2. The completion used to wait for abort completion is never + re-initialized, resulting in incorrect wait behavior. + 3. The abort sequence unintentionally clears RING_CTRL_ENABLE, which + resets hardware ring pointers and disrupts the controller state. + 4. If the ring is already stopped, the abort operation should be + considered successful without attempting further action. + +Fix the abort handling by checking whether the ring is running before +issuing an abort, re-initializing the completion when needed, ensuring that +RING_CTRL_ENABLE remains asserted during abort, and treating an already +stopped ring as a successful condition. + +Fixes: 9ad9a52cce282 ("i3c/master: introduce the mipi-i3c-hci driver") +Cc: stable@vger.kernel.org +Signed-off-by: Adrian Hunter +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260306072451.11131-9-adrian.hunter@intel.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Jianqiang kang +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/mipi-i3c-hci/dma.c | 27 +++++++++++++++++---------- + 1 file changed, 17 insertions(+), 10 deletions(-) + +diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c +index 624d00b853a51..61007167606fd 100644 +--- a/drivers/i3c/master/mipi-i3c-hci/dma.c ++++ b/drivers/i3c/master/mipi-i3c-hci/dma.c +@@ -448,16 +448,23 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci, + struct hci_rh_data *rh = &rings->headers[xfer_list[0].ring_number]; + unsigned int i; + bool did_unqueue = false; +- +- /* stop the ring */ +- rh_reg_write(RING_CONTROL, RING_CTRL_ABORT); +- if (wait_for_completion_timeout(&rh->op_done, HZ) == 0) { +- /* +- * We're deep in it if ever this condition is ever met. +- * Hardware might still be writing to memory, etc. +- */ +- dev_crit(&hci->master.dev, "unable to abort the ring\n"); +- WARN_ON(1); ++ u32 ring_status; ++ ++ ring_status = rh_reg_read(RING_STATUS); ++ if (ring_status & RING_STATUS_RUNNING) { ++ /* stop the ring */ ++ reinit_completion(&rh->op_done); ++ rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE | RING_CTRL_ABORT); ++ wait_for_completion_timeout(&rh->op_done, HZ); ++ ring_status = rh_reg_read(RING_STATUS); ++ if (ring_status & RING_STATUS_RUNNING) { ++ /* ++ * We're deep in it if ever this condition is ever met. ++ * Hardware might still be writing to memory, etc. ++ */ ++ dev_crit(&hci->master.dev, "unable to abort the ring\n"); ++ WARN_ON(1); ++ } + } + + for (i = 0; i < n; i++) { +-- +2.53.0 + diff --git a/queue-6.1/series b/queue-6.1/series index 2c7bbfb56a..e394830c4e 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -836,3 +836,4 @@ wifi-mac80211-check-tdls-flag-in-ieee80211_tdls_oper.patch revert-x86-vdso-fix-output-operand-size-of-rdpid.patch revert-s390-cio-fix-device-lifecycle-handling-in-css.patch smb-client-reject-userspace-cifs.spnego-descriptions.patch +i3c-mipi-i3c-hci-correct-ring_ctrl_abort-handling-in.patch diff --git a/queue-6.12/arm64-kconfig-remove-selecting-replaced-have_functio.patch b/queue-6.12/arm64-kconfig-remove-selecting-replaced-have_functio.patch new file mode 100644 index 0000000000..056df53ee1 --- /dev/null +++ b/queue-6.12/arm64-kconfig-remove-selecting-replaced-have_functio.patch @@ -0,0 +1,44 @@ +From 39bda3851566c41919488aecade3f727e3a3696d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 19:24:40 +0000 +Subject: arm64: Kconfig: Remove selecting replaced HAVE_FUNCTION_GRAPH_RETVAL + +From: Lukas Bulwahn + +commit f458b2165d7ac0f2401fff48f19c8f864e7e1e38 upstream. + +Commit a3ed4157b7d8 ("fgraph: Replace fgraph_ret_regs with ftrace_regs") +replaces the config HAVE_FUNCTION_GRAPH_RETVAL with the config +HAVE_FUNCTION_GRAPH_FREGS, and it replaces all the select commands in the +various architecture Kconfig files. In the arm64 architecture, the commit +adds the 'select HAVE_FUNCTION_GRAPH_FREGS', but misses to remove the +'select HAVE_FUNCTION_GRAPH_RETVAL', i.e., the select on the replaced +config. + +Remove selecting the replaced config. No functional change, just cleanup. + +Fixes: a3ed4157b7d8 ("fgraph: Replace fgraph_ret_regs with ftrace_regs") +Signed-off-by: Lukas Bulwahn +Link: https://lore.kernel.org/r/20250117125522.99071-1-lukas.bulwahn@redhat.com +Signed-off-by: Will Deacon +Signed-off-by: Gyokhan Kochmarla +Signed-off-by: Sasha Levin +--- + arch/arm64/Kconfig | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig +index f487c5e21e2f1..d4ebdc16cdb4f 100644 +--- a/arch/arm64/Kconfig ++++ b/arch/arm64/Kconfig +@@ -219,7 +219,6 @@ config ARM64 + select HAVE_FUNCTION_ERROR_INJECTION + select HAVE_FUNCTION_GRAPH_FREGS + select HAVE_FUNCTION_GRAPH_TRACER +- select HAVE_FUNCTION_GRAPH_RETVAL + select HAVE_GCC_PLUGINS + select HAVE_HARDLOCKUP_DETECTOR_PERF if PERF_EVENTS && \ + HW_PERF_EVENTS && HAVE_PERF_EVENTS_NMI +-- +2.53.0 + diff --git a/queue-6.12/hwmon-pmbus-core-protect-regulator-operations-with-m.patch b/queue-6.12/hwmon-pmbus-core-protect-regulator-operations-with-m.patch new file mode 100644 index 0000000000..d36fa96705 --- /dev/null +++ b/queue-6.12/hwmon-pmbus-core-protect-regulator-operations-with-m.patch @@ -0,0 +1,261 @@ +From b0c77c3a6481a24fcdf012f078666dcff4bf3c00 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 10:22:30 +0800 +Subject: hwmon: (pmbus/core) Protect regulator operations with mutex + +From: Guenter Roeck + +[ Upstream commit 754bd2b4a084b90b5e7b630e1f423061a9b9b761 ] + +The regulator operations pmbus_regulator_get_voltage(), +pmbus_regulator_set_voltage(), and pmbus_regulator_list_voltage() +access PMBus registers and shared data but were not protected by +the update_lock mutex. This could lead to race conditions. + +However, adding mutex protection directly to these functions causes +a deadlock because pmbus_regulator_notify() (which calls +regulator_notifier_call_chain()) is often called with the mutex +already held (e.g., from pmbus_fault_handler()). If a regulator +callback then calls one of the now-protected voltage functions, +it will attempt to acquire the same mutex. + +Rework pmbus_regulator_notify() to utilize a worker function to +send notifications outside of the mutex protection. Events are +stored as atomics in a per-page bitmask and processed by the worker. + +Initialize the worker and its associated data during regulator +registration, and ensure it is cancelled on device removal using +devm_add_action_or_reset(). + +While at it, remove the unnecessary include of linux/of.h. + +Cc: Sanman Pradhan +Fixes: ddbb4db4ced1b ("hwmon: (pmbus) Add regulator support") +Reviewed-by: Sanman Pradhan +Signed-off-by: Guenter Roeck +Signed-off-by: Fang Wang <32840572@qq.com> +Signed-off-by: Sasha Levin +--- + drivers/hwmon/pmbus/pmbus_core.c | 117 ++++++++++++++++++++++++------- + 1 file changed, 91 insertions(+), 26 deletions(-) + +diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c +index 41c66ece5177e..e37fd206510a6 100644 +--- a/drivers/hwmon/pmbus/pmbus_core.c ++++ b/drivers/hwmon/pmbus/pmbus_core.c +@@ -6,6 +6,7 @@ + * Copyright (c) 2012 Guenter Roeck + */ + ++#include + #include + #include + #include +@@ -20,8 +21,8 @@ + #include + #include + #include +-#include + #include ++#include + #include "pmbus.h" + + /* +@@ -102,6 +103,11 @@ struct pmbus_data { + + struct mutex update_lock; + ++#if IS_ENABLED(CONFIG_REGULATOR) ++ atomic_t regulator_events[PMBUS_PAGES]; ++ struct work_struct regulator_notify_work; ++#endif ++ + bool has_status_word; /* device uses STATUS_WORD register */ + int (*read_status)(struct i2c_client *client, int page); + +@@ -3181,12 +3187,19 @@ static int pmbus_regulator_get_voltage(struct regulator_dev *rdev) + .class = PSC_VOLTAGE_OUT, + .convert = true, + }; ++ int ret; + ++ mutex_lock(&data->update_lock); + s.data = _pmbus_read_word_data(client, s.page, 0xff, PMBUS_READ_VOUT); +- if (s.data < 0) +- return s.data; ++ if (s.data < 0) { ++ ret = s.data; ++ goto unlock; ++ } + +- return (int)pmbus_reg2data(data, &s) * 1000; /* unit is uV */ ++ ret = (int)pmbus_reg2data(data, &s) * 1000; /* unit is uV */ ++unlock: ++ mutex_unlock(&data->update_lock); ++ return ret; + } + + static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv, +@@ -3203,16 +3216,22 @@ static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv, + }; + int val = DIV_ROUND_CLOSEST(min_uv, 1000); /* convert to mV */ + int low, high; ++ int ret; + + *selector = 0; + ++ mutex_lock(&data->update_lock); + low = pmbus_regulator_get_low_margin(client, s.page); +- if (low < 0) +- return low; ++ if (low < 0) { ++ ret = low; ++ goto unlock; ++ } + + high = pmbus_regulator_get_high_margin(client, s.page); +- if (high < 0) +- return high; ++ if (high < 0) { ++ ret = high; ++ goto unlock; ++ } + + /* Make sure we are within margins */ + if (low > val) +@@ -3222,7 +3241,10 @@ static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv, + + val = pmbus_data2reg(data, &s, val); + +- return _pmbus_write_word_data(client, s.page, PMBUS_VOUT_COMMAND, (u16)val); ++ ret = _pmbus_write_word_data(client, s.page, PMBUS_VOUT_COMMAND, (u16)val); ++unlock: ++ mutex_unlock(&data->update_lock); ++ return ret; + } + + static int pmbus_regulator_list_voltage(struct regulator_dev *rdev, +@@ -3230,7 +3252,9 @@ static int pmbus_regulator_list_voltage(struct regulator_dev *rdev, + { + struct device *dev = rdev_get_dev(rdev); + struct i2c_client *client = to_i2c_client(dev->parent); ++ struct pmbus_data *data = i2c_get_clientdata(client); + int val, low, high; ++ int ret; + + if (selector >= rdev->desc->n_voltages || + selector < rdev->desc->linear_min_sel) +@@ -3240,18 +3264,29 @@ static int pmbus_regulator_list_voltage(struct regulator_dev *rdev, + val = DIV_ROUND_CLOSEST(rdev->desc->min_uV + + (rdev->desc->uV_step * selector), 1000); /* convert to mV */ + ++ mutex_lock(&data->update_lock); ++ + low = pmbus_regulator_get_low_margin(client, rdev_get_id(rdev)); +- if (low < 0) +- return low; ++ if (low < 0) { ++ ret = low; ++ goto unlock; ++ } + + high = pmbus_regulator_get_high_margin(client, rdev_get_id(rdev)); +- if (high < 0) +- return high; ++ if (high < 0) { ++ ret = high; ++ goto unlock; ++ } + +- if (val >= low && val <= high) +- return val * 1000; /* unit is uV */ ++ if (val >= low && val <= high) { ++ ret = val * 1000; /* unit is uV */ ++ goto unlock; ++ } + +- return 0; ++ ret = 0; ++unlock: ++ mutex_unlock(&data->update_lock); ++ return ret; + } + + const struct regulator_ops pmbus_regulator_ops = { +@@ -3266,12 +3301,42 @@ const struct regulator_ops pmbus_regulator_ops = { + }; + EXPORT_SYMBOL_NS_GPL(pmbus_regulator_ops, PMBUS); + ++static void pmbus_regulator_notify_work_cancel(void *data) ++{ ++ struct pmbus_data *pdata = data; ++ ++ cancel_work_sync(&pdata->regulator_notify_work); ++} ++ ++static void pmbus_regulator_notify_worker(struct work_struct *work) ++{ ++ struct pmbus_data *data = ++ container_of(work, struct pmbus_data, regulator_notify_work); ++ int i, j; ++ ++ for (i = 0; i < data->info->pages; i++) { ++ int event; ++ ++ event = atomic_xchg(&data->regulator_events[i], 0); ++ if (!event) ++ continue; ++ ++ for (j = 0; j < data->info->num_regulators; j++) { ++ if (i == rdev_get_id(data->rdevs[j])) { ++ regulator_notifier_call_chain(data->rdevs[j], ++ event, NULL); ++ break; ++ } ++ } ++ } ++} ++ + static int pmbus_regulator_register(struct pmbus_data *data) + { + struct device *dev = data->dev; + const struct pmbus_driver_info *info = data->info; + const struct pmbus_platform_data *pdata = dev_get_platdata(dev); +- int i; ++ int i, ret; + + data->rdevs = devm_kzalloc(dev, sizeof(struct regulator_dev *) * info->num_regulators, + GFP_KERNEL); +@@ -3295,20 +3360,20 @@ static int pmbus_regulator_register(struct pmbus_data *data) + info->reg_desc[i].name); + } + ++ INIT_WORK(&data->regulator_notify_work, pmbus_regulator_notify_worker); ++ ++ ret = devm_add_action_or_reset(dev, pmbus_regulator_notify_work_cancel, data); ++ if (ret) ++ return ret; ++ + return 0; + } + + static int pmbus_regulator_notify(struct pmbus_data *data, int page, int event) + { +- int j; +- +- for (j = 0; j < data->info->num_regulators; j++) { +- if (page == rdev_get_id(data->rdevs[j])) { +- regulator_notifier_call_chain(data->rdevs[j], event, NULL); +- break; +- } +- } +- return 0; ++ atomic_or(event, &data->regulator_events[page]); ++ schedule_work(&data->regulator_notify_work); ++ return 0; + } + #else + static int pmbus_regulator_register(struct pmbus_data *data) +-- +2.53.0 + diff --git a/queue-6.12/i3c-mipi-i3c-hci-correct-ring_ctrl_abort-handling-in.patch b/queue-6.12/i3c-mipi-i3c-hci-correct-ring_ctrl_abort-handling-in.patch new file mode 100644 index 0000000000..b36c6125b2 --- /dev/null +++ b/queue-6.12/i3c-mipi-i3c-hci-correct-ring_ctrl_abort-handling-in.patch @@ -0,0 +1,78 @@ +From 840018a00e1073ee50daf3f11644707b6c5bc9a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 14:19:33 +0800 +Subject: i3c: mipi-i3c-hci: Correct RING_CTRL_ABORT handling in DMA dequeue + +From: Adrian Hunter + +[ Upstream commit b795e68bf3073d67bebbb5a44d93f49efc5b8cc7 ] + +The logic used to abort the DMA ring contains several flaws: + + 1. The driver unconditionally issues a ring abort even when the ring has + already stopped. + 2. The completion used to wait for abort completion is never + re-initialized, resulting in incorrect wait behavior. + 3. The abort sequence unintentionally clears RING_CTRL_ENABLE, which + resets hardware ring pointers and disrupts the controller state. + 4. If the ring is already stopped, the abort operation should be + considered successful without attempting further action. + +Fix the abort handling by checking whether the ring is running before +issuing an abort, re-initializing the completion when needed, ensuring that +RING_CTRL_ENABLE remains asserted during abort, and treating an already +stopped ring as a successful condition. + +Fixes: 9ad9a52cce282 ("i3c/master: introduce the mipi-i3c-hci driver") +Cc: stable@vger.kernel.org +Signed-off-by: Adrian Hunter +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260306072451.11131-9-adrian.hunter@intel.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Jianqiang kang +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/mipi-i3c-hci/dma.c | 27 +++++++++++++++++---------- + 1 file changed, 17 insertions(+), 10 deletions(-) + +diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c +index b9496e8c4784d..44461f13b54cd 100644 +--- a/drivers/i3c/master/mipi-i3c-hci/dma.c ++++ b/drivers/i3c/master/mipi-i3c-hci/dma.c +@@ -457,16 +457,23 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci, + struct hci_rh_data *rh = &rings->headers[xfer_list[0].ring_number]; + unsigned int i; + bool did_unqueue = false; +- +- /* stop the ring */ +- rh_reg_write(RING_CONTROL, RING_CTRL_ABORT); +- if (wait_for_completion_timeout(&rh->op_done, HZ) == 0) { +- /* +- * We're deep in it if ever this condition is ever met. +- * Hardware might still be writing to memory, etc. +- */ +- dev_crit(&hci->master.dev, "unable to abort the ring\n"); +- WARN_ON(1); ++ u32 ring_status; ++ ++ ring_status = rh_reg_read(RING_STATUS); ++ if (ring_status & RING_STATUS_RUNNING) { ++ /* stop the ring */ ++ reinit_completion(&rh->op_done); ++ rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE | RING_CTRL_ABORT); ++ wait_for_completion_timeout(&rh->op_done, HZ); ++ ring_status = rh_reg_read(RING_STATUS); ++ if (ring_status & RING_STATUS_RUNNING) { ++ /* ++ * We're deep in it if ever this condition is ever met. ++ * Hardware might still be writing to memory, etc. ++ */ ++ dev_crit(&hci->master.dev, "unable to abort the ring\n"); ++ WARN_ON(1); ++ } + } + + for (i = 0; i < n; i++) { +-- +2.53.0 + diff --git a/queue-6.12/iommu-vt-d-draining-prq-in-sva-unbind-path-when-fpd-.patch b/queue-6.12/iommu-vt-d-draining-prq-in-sva-unbind-path-when-fpd-.patch new file mode 100644 index 0000000000..24e61c4651 --- /dev/null +++ b/queue-6.12/iommu-vt-d-draining-prq-in-sva-unbind-path-when-fpd-.patch @@ -0,0 +1,92 @@ +From 4143b816f34d1f9422e57b4c2f0de6445cb720f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 19:24:01 +0000 +Subject: iommu/vt-d: Draining PRQ in sva unbind path when FPD bit set + +From: Lu Baolu + +commit cf08ca81d08a04b3b304e8fb4e052f323a09783d upstream. + +When a device uses a PASID for SVA (Shared Virtual Address), it's possible +that the PASID entry is marked as non-present and FPD bit set before the +device flushes all ongoing DMA requests and removes the SVA domain. This +can occur when an exception happens and the process terminates before the +device driver stops DMA and calls the iommu driver to unbind the PASID. + +There's no need to drain the PRQ in the mm release path. Instead, the PRQ +will be drained in the SVA unbind path. But in such case, +intel_pasid_tear_down_entry() only checks the presence of the pasid entry +and returns directly. + +Add the code to clear the FPD bit and drain the PRQ. + +Fixes: c43e1ccdebf2 ("iommu/vt-d: Drain PRQs when domain removed from RID") +Suggested-by: Kevin Tian +Signed-off-by: Lu Baolu +Reviewed-by: Kevin Tian +Link: https://lore.kernel.org/r/20241217024240.139615-1-baolu.lu@linux.intel.com +Signed-off-by: Joerg Roedel +Signed-off-by: Gyokhan Kochmarla +Signed-off-by: Sasha Levin +--- + drivers/iommu/intel/pasid.c | 22 +++++++++++++++++++++- + drivers/iommu/intel/pasid.h | 6 ++++++ + 2 files changed, 27 insertions(+), 1 deletion(-) + +diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c +index 3d1d43675bf22..74be6b547fc0c 100644 +--- a/drivers/iommu/intel/pasid.c ++++ b/drivers/iommu/intel/pasid.c +@@ -245,11 +245,31 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev, + + spin_lock(&iommu->lock); + pte = intel_pasid_get_entry(dev, pasid); +- if (WARN_ON(!pte) || !pasid_pte_is_present(pte)) { ++ if (WARN_ON(!pte)) { + spin_unlock(&iommu->lock); + return; + } + ++ if (!pasid_pte_is_present(pte)) { ++ if (!pasid_pte_is_fault_disabled(pte)) { ++ WARN_ON(READ_ONCE(pte->val[0]) != 0); ++ spin_unlock(&iommu->lock); ++ return; ++ } ++ ++ /* ++ * When a PASID is used for SVA by a device, it's possible ++ * that the pasid entry is non-present with the Fault ++ * Processing Disabled bit set. Clear the pasid entry and ++ * drain the PRQ for the PASID before return. ++ */ ++ pasid_clear_entry(pte); ++ spin_unlock(&iommu->lock); ++ intel_iommu_drain_pasid_prq(dev, pasid); ++ ++ return; ++ } ++ + did = pasid_get_domain_id(pte); + pgtt = pasid_pte_get_pgtt(pte); + pasid_clear_present(pte); +diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h +index 55cad7bfa294e..8ffb01163f0e6 100644 +--- a/drivers/iommu/intel/pasid.h ++++ b/drivers/iommu/intel/pasid.h +@@ -80,6 +80,12 @@ static inline bool pasid_pte_is_present(struct pasid_entry *pte) + return READ_ONCE(pte->val[0]) & PASID_PTE_PRESENT; + } + ++/* Get FPD(Fault Processing Disable) bit of a PASID table entry */ ++static inline bool pasid_pte_is_fault_disabled(struct pasid_entry *pte) ++{ ++ return READ_ONCE(pte->val[0]) & PASID_PTE_FPD; ++} ++ + /* Get PGTT field of a PASID table entry */ + static inline u16 pasid_pte_get_pgtt(struct pasid_entry *pte) + { +-- +2.53.0 + diff --git a/queue-6.12/net-mlx5e-trigger-neighbor-resolution-for-unresolved.patch b/queue-6.12/net-mlx5e-trigger-neighbor-resolution-for-unresolved.patch new file mode 100644 index 0000000000..2e7fb51e09 --- /dev/null +++ b/queue-6.12/net-mlx5e-trigger-neighbor-resolution-for-unresolved.patch @@ -0,0 +1,61 @@ +From eefae856833005cae6b15cc7bb544820027cf712 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 19:21:20 +0000 +Subject: net/mlx5e: Trigger neighbor resolution for unresolved destinations + +From: Jianbo Liu + +commit 9ab89bde13e5251e1d0507e1cc426edcdfe19142 upstream. + +When initializing the MAC addresses for an outbound IPsec packet offload +rule in mlx5e_ipsec_init_macs, the call to dst_neigh_lookup is used to +find the next-hop neighbor (typically the gateway in tunnel mode). +This call might create a new neighbor entry if one doesn't already +exist. This newly created entry starts in the INCOMPLETE state, as the +kernel hasn't yet sent an ARP or NDISC probe to resolve the MAC +address. In this case, neigh_ha_snapshot will correctly return an +all-zero MAC address. + +IPsec packet offload requires the actual next-hop MAC address to +program the rule correctly. If the neighbor state is INCOMPLETE when +the rule is created, the hardware rule is programmed with an all-zero +destination MAC address. Packets sent using this rule will be +subsequently dropped by the receiving network infrastructure or host. + +This patch adds a check specifically for the outbound offload path. If +neigh_ha_snapshot returns an all-zero MAC address, it proactively +calls neigh_event_send(n, NULL). This ensures the kernel immediately +sends the initial ARP or NDISC probe if one isn't already pending, +accelerating the resolution process. This helps prevent the hardware +rule from being programmed with an invalid MAC address and avoids +packet drops due to unresolved neighbors. + +Fixes: 71670f766b8f ("net/mlx5e: Support routed networks during IPsec MACs initialization") +Signed-off-by: Jianbo Liu +Reviewed-by: Leon Romanovsky +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/1765284977-1363052-8-git-send-email-tariqt@nvidia.com +Signed-off-by: Paolo Abeni +Signed-off-by: Gyokhan Kochmarla +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c +index 486f05112f5a6..e2915d3143e6b 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c +@@ -365,6 +365,9 @@ static void mlx5e_ipsec_init_macs(struct mlx5e_ipsec_sa_entry *sa_entry, + + neigh_ha_snapshot(addr, n, netdev); + ether_addr_copy(dst, addr); ++ if (attrs->dir == XFRM_DEV_OFFLOAD_OUT && ++ is_zero_ether_addr(addr)) ++ neigh_event_send(n, NULL); + dst_release(rt_dst_entry); + neigh_release(n); + return; +-- +2.53.0 + diff --git a/queue-6.12/net-mlx5e-use-ip6_dst_lookup-instead-of-ipv6_dst_loo.patch b/queue-6.12/net-mlx5e-use-ip6_dst_lookup-instead-of-ipv6_dst_loo.patch new file mode 100644 index 0000000000..34715c2dea --- /dev/null +++ b/queue-6.12/net-mlx5e-use-ip6_dst_lookup-instead-of-ipv6_dst_loo.patch @@ -0,0 +1,51 @@ +From e36c6858da13c57ce6af47635049cc0342db4c12 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 19:22:14 +0000 +Subject: net/mlx5e: Use ip6_dst_lookup instead of ipv6_dst_lookup_flow for MAC + init + +From: Jianbo Liu + +commit e35d7da8dd9e55b37c3e8ab548f6793af0c2ab49 upstream. + +Replace ipv6_stub->ipv6_dst_lookup_flow() with ip6_dst_lookup() in +mlx5e_ipsec_init_macs() since IPsec transformations are not needed +during Security Association setup - only basic routing information is +required for nexthop MAC address resolution. + +This resolves an issue where XfrmOutNoStates error counter would be +incremented when xfrm policy is configured before xfrm state, as the +IPsec-aware routing function would attempt policy checks during SA +initialization. + +Fixes: 71670f766b8f ("net/mlx5e: Support routed networks during IPsec MACs initialization") +Signed-off-by: Jianbo Liu +Reviewed-by: Leon Romanovsky +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/1765284977-1363052-7-git-send-email-tariqt@nvidia.com +Signed-off-by: Paolo Abeni +Signed-off-by: Gyokhan Kochmarla +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c +index e2915d3143e6b..c1b6893389fdf 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c +@@ -348,9 +348,8 @@ static void mlx5e_ipsec_init_macs(struct mlx5e_ipsec_sa_entry *sa_entry, + rt_dst_entry = &rt->dst; + break; + case AF_INET6: +- rt_dst_entry = ipv6_stub->ipv6_dst_lookup_flow( +- dev_net(netdev), NULL, &fl6, NULL); +- if (IS_ERR(rt_dst_entry)) ++ if (!IS_ENABLED(CONFIG_IPV6) || ++ ip6_dst_lookup(dev_net(netdev), NULL, &rt_dst_entry, &fl6)) + goto neigh; + break; + default: +-- +2.53.0 + diff --git a/queue-6.12/perf-parse-events-expose-rename-config_term_name.patch b/queue-6.12/perf-parse-events-expose-rename-config_term_name.patch new file mode 100644 index 0000000000..7066fc8dd2 --- /dev/null +++ b/queue-6.12/perf-parse-events-expose-rename-config_term_name.patch @@ -0,0 +1,118 @@ +From 81f79355bf3e5904a5f34f00e759683ba4325e38 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 1 Oct 2024 20:20:06 -0700 +Subject: perf parse-events: Expose/rename config_term_name + +From: Ian Rogers + +[ Upstream commit d2f3ecb0ca2099d13bf8bf69219214c1425dc453 ] + +Expose config_term_name as parse_events__term_type_str so that PMUs not +in pmu.c may access it. + +Signed-off-by: Ian Rogers +Acked-by: Namhyung Kim +Link: https://lore.kernel.org/r/20241002032016.333748-4-irogers@google.com +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/parse-events.c | 20 +++++++++++--------- + tools/perf/util/parse-events.h | 2 ++ + 2 files changed, 13 insertions(+), 9 deletions(-) + +diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c +index fcc4dab618bee..3d221608b13a5 100644 +--- a/tools/perf/util/parse-events.c ++++ b/tools/perf/util/parse-events.c +@@ -801,7 +801,7 @@ static int check_type_val(struct parse_events_term *term, + + static bool config_term_shrinked; + +-static const char *config_term_name(enum parse_events__term_type term_type) ++const char *parse_events__term_type_str(enum parse_events__term_type term_type) + { + /* + * Update according to parse-events.l +@@ -887,7 +887,7 @@ config_term_avail(enum parse_events__term_type term_type, struct parse_events_er + + /* term_type is validated so indexing is safe */ + if (asprintf(&err_str, "'%s' is not usable in 'perf stat'", +- config_term_name(term_type)) >= 0) ++ parse_events__term_type_str(term_type)) >= 0) + parse_events_error__handle(err, -1, err_str, NULL); + return false; + } +@@ -1011,7 +1011,7 @@ do { \ + case PARSE_EVENTS__TERM_TYPE_HARDWARE: + default: + parse_events_error__handle(err, term->err_term, +- strdup(config_term_name(term->type_term)), ++ strdup(parse_events__term_type_str(term->type_term)), + parse_events_formats_error_string(NULL)); + return -EINVAL; + } +@@ -1135,8 +1135,9 @@ static int config_term_tracepoint(struct perf_event_attr *attr, + default: + if (err) { + parse_events_error__handle(err, term->err_term, +- strdup(config_term_name(term->type_term)), +- strdup("valid terms: call-graph,stack-size\n")); ++ strdup(parse_events__term_type_str(term->type_term)), ++ strdup("valid terms: call-graph,stack-size\n") ++ ); + } + return -EINVAL; + } +@@ -2581,7 +2582,7 @@ int parse_events_term__num(struct parse_events_term **term, + struct parse_events_term temp = { + .type_val = PARSE_EVENTS__TERM_TYPE_NUM, + .type_term = type_term, +- .config = config ? : strdup(config_term_name(type_term)), ++ .config = config ? : strdup(parse_events__term_type_str(type_term)), + .no_value = no_value, + .err_term = loc_term ? loc_term->first_column : 0, + .err_val = loc_val ? loc_val->first_column : 0, +@@ -2615,7 +2616,7 @@ int parse_events_term__term(struct parse_events_term **term, + void *loc_term, void *loc_val) + { + return parse_events_term__str(term, term_lhs, NULL, +- strdup(config_term_name(term_rhs)), ++ strdup(parse_events__term_type_str(term_rhs)), + loc_term, loc_val); + } + +@@ -2722,7 +2723,8 @@ int parse_events_terms__to_strbuf(const struct parse_events_terms *terms, struct + if (ret < 0) + return ret; + } else if ((unsigned int)term->type_term < __PARSE_EVENTS__TERM_TYPE_NR) { +- ret = strbuf_addf(sb, "%s=", config_term_name(term->type_term)); ++ ret = strbuf_addf(sb, "%s=", ++ parse_events__term_type_str(term->type_term)); + if (ret < 0) + return ret; + } +@@ -2742,7 +2744,7 @@ static void config_terms_list(char *buf, size_t buf_sz) + + buf[0] = '\0'; + for (i = 0; i < __PARSE_EVENTS__TERM_TYPE_NR; i++) { +- const char *name = config_term_name(i); ++ const char *name = parse_events__term_type_str(i); + + if (!config_term_avail(i, NULL)) + continue; +diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h +index 2b52f8d6aa29a..ac1feaaeb8d5d 100644 +--- a/tools/perf/util/parse-events.h ++++ b/tools/perf/util/parse-events.h +@@ -168,6 +168,8 @@ struct parse_events_state { + bool wild_card_pmus; + }; + ++const char *parse_events__term_type_str(enum parse_events__term_type term_type); ++ + bool parse_events__filter_pmu(const struct parse_events_state *parse_state, + const struct perf_pmu *pmu); + void parse_events__shrink_config_terms(void); +-- +2.53.0 + diff --git a/queue-6.12/revert-ice-fix-double-free-of-tx_buf-skb.patch b/queue-6.12/revert-ice-fix-double-free-of-tx_buf-skb.patch new file mode 100644 index 0000000000..9981d4fbfe --- /dev/null +++ b/queue-6.12/revert-ice-fix-double-free-of-tx_buf-skb.patch @@ -0,0 +1,46 @@ +From 097e408d8dfd97daea39ac7ea757eaa1e084bab9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 12:48:53 -0400 +Subject: Revert "ice: fix double-free of tx_buf skb" + +This reverts commit fd95ef8d0f6dbe2daa95d6488c9e0f8a95a7e048. + +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_txrx.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c +index 48434a79869cb..08d1757f40888 100644 +--- a/drivers/net/ethernet/intel/ice/ice_txrx.c ++++ b/drivers/net/ethernet/intel/ice/ice_txrx.c +@@ -2346,9 +2346,6 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + + ice_trace(xmit_frame_ring, tx_ring, skb); + +- /* record the location of the first descriptor for this packet */ +- first = &tx_ring->tx_buf[tx_ring->next_to_use]; +- + count = ice_xmit_desc_count(skb); + if (ice_chk_linearize(skb, count)) { + if (__skb_linearize(skb)) +@@ -2374,6 +2371,8 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + + offload.tx_ring = tx_ring; + ++ /* record the location of the first descriptor for this packet */ ++ first = &tx_ring->tx_buf[tx_ring->next_to_use]; + first->skb = skb; + first->type = ICE_TX_BUF_SKB; + first->bytecount = max_t(unsigned int, skb->len, ETH_ZLEN); +@@ -2437,7 +2436,6 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + out_drop: + ice_trace(xmit_frame_ring_drop, tx_ring, skb); + dev_kfree_skb_any(skb); +- first->type = ICE_TX_BUF_EMPTY; + return NETDEV_TX_OK; + } + +-- +2.53.0 + diff --git a/queue-6.12/revert-ice-remove-jumbo_remove-step-from-tx-path.patch b/queue-6.12/revert-ice-remove-jumbo_remove-step-from-tx-path.patch new file mode 100644 index 0000000000..9be0b15215 --- /dev/null +++ b/queue-6.12/revert-ice-remove-jumbo_remove-step-from-tx-path.patch @@ -0,0 +1,29 @@ +From a651eade212687e1f5055b5308d1024c67dba31d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 12:48:54 -0400 +Subject: Revert "ice: Remove jumbo_remove step from TX path" + +This reverts commit 7332d208c9d2067546eb7af5339773c966ac5625. + +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_txrx.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c +index 08d1757f40888..431a6ed498a4e 100644 +--- a/drivers/net/ethernet/intel/ice/ice_txrx.c ++++ b/drivers/net/ethernet/intel/ice/ice_txrx.c +@@ -2346,6 +2346,9 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + + ice_trace(xmit_frame_ring, tx_ring, skb); + ++ if (unlikely(ipv6_hopopt_jumbo_remove(skb))) ++ goto out_drop; ++ + count = ice_xmit_desc_count(skb); + if (ice_chk_linearize(skb, count)) { + if (__skb_linearize(skb)) +-- +2.53.0 + diff --git a/queue-6.12/riscv-fgraph-fix-stack-layout-to-match-__arch_ftrace.patch b/queue-6.12/riscv-fgraph-fix-stack-layout-to-match-__arch_ftrace.patch new file mode 100644 index 0000000000..1b2c10049f --- /dev/null +++ b/queue-6.12/riscv-fgraph-fix-stack-layout-to-match-__arch_ftrace.patch @@ -0,0 +1,128 @@ +From d1e3c23c1423204d2f3a13b121ccb3e2e05dce2b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 19:25:17 +0000 +Subject: riscv: fgraph: Fix stack layout to match __arch_ftrace_regs argument + of ftrace_return_to_handler +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Pu Lehui + +commit 67a5ba8f742f247bc83e46dd2313c142b1383276 upstream. + +Naresh Kamboju reported a "Bad frame pointer" kernel warning while +running LTP trace ftrace_stress_test.sh in riscv. We can reproduce the +same issue with the following command: + +``` +$ cd /sys/kernel/debug/tracing +$ echo 'f:myprobe do_nanosleep%return args1=$retval' > dynamic_events +$ echo 1 > events/fprobes/enable +$ echo 1 > tracing_on +$ sleep 1 +``` + +And we can get the following kernel warning: + +[ 127.692888] ------------[ cut here ]------------ +[ 127.693755] Bad frame pointer: expected ff2000000065be50, received ba34c141e9594000 +[ 127.693755] from func do_nanosleep return to ffffffff800ccb16 +[ 127.698699] WARNING: CPU: 1 PID: 129 at kernel/trace/fgraph.c:755 ftrace_return_to_handler+0x1b2/0x1be +[ 127.699894] Modules linked in: +[ 127.700908] CPU: 1 UID: 0 PID: 129 Comm: sleep Not tainted 6.14.0-rc3-g0ab191c74642 #32 +[ 127.701453] Hardware name: riscv-virtio,qemu (DT) +[ 127.701859] epc : ftrace_return_to_handler+0x1b2/0x1be +[ 127.702032] ra : ftrace_return_to_handler+0x1b2/0x1be +[ 127.702151] epc : ffffffff8013b5e0 ra : ffffffff8013b5e0 sp : ff2000000065bd10 +[ 127.702221] gp : ffffffff819c12f8 tp : ff60000080853100 t0 : 6e00000000000000 +[ 127.702284] t1 : 0000000000000020 t2 : 6e7566206d6f7266 s0 : ff2000000065bd80 +[ 127.702346] s1 : ff60000081262000 a0 : 000000000000007b a1 : ffffffff81894f20 +[ 127.702408] a2 : 0000000000000010 a3 : fffffffffffffffe a4 : 0000000000000000 +[ 127.702470] a5 : 0000000000000000 a6 : 0000000000000008 a7 : 0000000000000038 +[ 127.702530] s2 : ba34c141e9594000 s3 : 0000000000000000 s4 : ff2000000065bdd0 +[ 127.702591] s5 : 00007fff8adcf400 s6 : 000055556dc1d8c0 s7 : 0000000000000068 +[ 127.702651] s8 : 00007fff8adf5d10 s9 : 000000000000006d s10: 0000000000000001 +[ 127.702710] s11: 00005555737377c8 t3 : ffffffff819d899e t4 : ffffffff819d899e +[ 127.702769] t5 : ffffffff819d89a0 t6 : ff2000000065bb18 +[ 127.702826] status: 0000000200000120 badaddr: 0000000000000000 cause: 0000000000000003 +[ 127.703292] [] ftrace_return_to_handler+0x1b2/0x1be +[ 127.703760] [] return_to_handler+0x16/0x26 +[ 127.704009] [] return_to_handler+0x0/0x26 +[ 127.704057] [] common_nsleep+0x42/0x54 +[ 127.704117] [] __riscv_sys_clock_nanosleep+0xba/0x10a +[ 127.704176] [] do_trap_ecall_u+0x188/0x218 +[ 127.704295] [] handle_exception+0x14a/0x156 +[ 127.705436] ---[ end trace 0000000000000000 ]--- + +The reason is that the stack layout for constructing argument for the +ftrace_return_to_handler in the return_to_handler does not match the +__arch_ftrace_regs structure of riscv, leading to unexpected results. + +Fixes: a3ed4157b7d8 ("fgraph: Replace fgraph_ret_regs with ftrace_regs") +Reported-by: Linux Kernel Functional Testing +Closes: https://lore.kernel.org/all/CA+G9fYvp_oAxeDFj88Tk2rfEZ7jtYKAKSwfYS66=57Db9TBdyA@mail.gmail.com +Signed-off-by: Pu Lehui +Reviewed-by: Alexandre Ghiti +Tested-by: Björn Töpel +Reviewed-by: Masami Hiramatsu (Google) +Link: https://lore.kernel.org/r/20250317031214.4138436-2-pulehui@huaweicloud.com +Signed-off-by: Alexandre Ghiti +Signed-off-by: Gyokhan Kochmarla +Signed-off-by: Sasha Levin +--- + arch/riscv/kernel/mcount.S | 24 +++++++++++------------- + 1 file changed, 11 insertions(+), 13 deletions(-) + +diff --git a/arch/riscv/kernel/mcount.S b/arch/riscv/kernel/mcount.S +index 068168046e0ef..da4a4000e57ea 100644 +--- a/arch/riscv/kernel/mcount.S ++++ b/arch/riscv/kernel/mcount.S +@@ -12,8 +12,6 @@ + #include + #include + +-#define ABI_SIZE_ON_STACK 80 +- + .text + + .macro SAVE_ABI_STATE +@@ -28,12 +26,12 @@ + * register if a0 was not saved. + */ + .macro SAVE_RET_ABI_STATE +- addi sp, sp, -ABI_SIZE_ON_STACK +- REG_S ra, 1*SZREG(sp) +- REG_S s0, 8*SZREG(sp) +- REG_S a0, 10*SZREG(sp) +- REG_S a1, 11*SZREG(sp) +- addi s0, sp, ABI_SIZE_ON_STACK ++ addi sp, sp, -FREGS_SIZE_ON_STACK ++ REG_S ra, FREGS_RA(sp) ++ REG_S s0, FREGS_S0(sp) ++ REG_S a0, FREGS_A0(sp) ++ REG_S a1, FREGS_A1(sp) ++ addi s0, sp, FREGS_SIZE_ON_STACK + .endm + + .macro RESTORE_ABI_STATE +@@ -43,11 +41,11 @@ + .endm + + .macro RESTORE_RET_ABI_STATE +- REG_L ra, 1*SZREG(sp) +- REG_L s0, 8*SZREG(sp) +- REG_L a0, 10*SZREG(sp) +- REG_L a1, 11*SZREG(sp) +- addi sp, sp, ABI_SIZE_ON_STACK ++ REG_L ra, FREGS_RA(sp) ++ REG_L s0, FREGS_S0(sp) ++ REG_L a0, FREGS_A0(sp) ++ REG_L a1, FREGS_A1(sp) ++ addi sp, sp, FREGS_SIZE_ON_STACK + .endm + + SYM_TYPED_FUNC_START(ftrace_stub) +-- +2.53.0 + diff --git a/queue-6.12/riscv-fgraph-select-have_function_graph_tracer-depen.patch b/queue-6.12/riscv-fgraph-select-have_function_graph_tracer-depen.patch new file mode 100644 index 0000000000..7770049da7 --- /dev/null +++ b/queue-6.12/riscv-fgraph-select-have_function_graph_tracer-depen.patch @@ -0,0 +1,48 @@ +From b8b94d07bdbd6d9b0401fc3054f7a0cd6ddfd21b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 19:26:35 +0000 +Subject: riscv: fgraph: Select HAVE_FUNCTION_GRAPH_TRACER depends on + HAVE_DYNAMIC_FTRACE_WITH_ARGS +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Pu Lehui + +commit e8eb8e1bdae94b9e003f5909519fd311d0936890 upstream. + +Currently, fgraph on riscv relies on the infrastructure of +DYNAMIC_FTRACE_WITH_ARGS. However, DYNAMIC_FTRACE_WITH_ARGS may be +turned off on riscv, which will cause the enabled fgraph to be abnormal. +Therefore, let's select HAVE_FUNCTION_GRAPH_TRACER depends on +HAVE_DYNAMIC_FTRACE_WITH_ARGS. + +Fixes: a3ed4157b7d8 ("fgraph: Replace fgraph_ret_regs with ftrace_regs") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202503160820.dvqMpH0g-lkp@intel.com/ +Signed-off-by: Pu Lehui +Reviewed-by: Björn Töpel +Link: https://lore.kernel.org/r/20250317031214.4138436-1-pulehui@huaweicloud.com +Signed-off-by: Alexandre Ghiti +Signed-off-by: Gyokhan Kochmarla +Signed-off-by: Sasha Levin +--- + arch/riscv/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig +index 9e8667a523d55..1c75758167956 100644 +--- a/arch/riscv/Kconfig ++++ b/arch/riscv/Kconfig +@@ -143,7 +143,7 @@ config RISCV + select HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS + select HAVE_DYNAMIC_FTRACE_WITH_ARGS if HAVE_DYNAMIC_FTRACE + select HAVE_FTRACE_MCOUNT_RECORD if !XIP_KERNEL +- select HAVE_FUNCTION_GRAPH_TRACER ++ select HAVE_FUNCTION_GRAPH_TRACER if HAVE_DYNAMIC_FTRACE_WITH_ARGS + select HAVE_FUNCTION_GRAPH_FREGS + select HAVE_FUNCTION_TRACER if !XIP_KERNEL && !PREEMPTION + select HAVE_EBPF_JIT if MMU +-- +2.53.0 + diff --git a/queue-6.12/series b/queue-6.12/series index cacdfafa3d..44e259ab54 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -26,3 +26,16 @@ ata-libata-scsi-improve-readability-of-ata_scsi_qc_issue.patch ata-libata-scsi-do-not-use-the-deferred-qc-feature-for-ata_defer_port.patch ata-libata-scsi-do-not-use-the-deferred-qc-feature-on-pmps-with-cbs.patch ata-libata-scsi-do-not-needlessly-defer-commands-when-using-pmp-with-fbs.patch +perf-parse-events-expose-rename-config_term_name.patch +revert-ice-fix-double-free-of-tx_buf-skb.patch +revert-ice-remove-jumbo_remove-step-from-tx-path.patch +tracing-fix-the-bug-where-bpf_get_stackid-returns-ef.patch +net-mlx5e-trigger-neighbor-resolution-for-unresolved.patch +net-mlx5e-use-ip6_dst_lookup-instead-of-ipv6_dst_loo.patch +x86-fgraph-fix-return_to_handler-regs.rsp-value.patch +iommu-vt-d-draining-prq-in-sva-unbind-path-when-fpd-.patch +riscv-fgraph-select-have_function_graph_tracer-depen.patch +riscv-fgraph-fix-stack-layout-to-match-__arch_ftrace.patch +hwmon-pmbus-core-protect-regulator-operations-with-m.patch +arm64-kconfig-remove-selecting-replaced-have_functio.patch +i3c-mipi-i3c-hci-correct-ring_ctrl_abort-handling-in.patch diff --git a/queue-6.12/tracing-fix-the-bug-where-bpf_get_stackid-returns-ef.patch b/queue-6.12/tracing-fix-the-bug-where-bpf_get_stackid-returns-ef.patch new file mode 100644 index 0000000000..00a5c08123 --- /dev/null +++ b/queue-6.12/tracing-fix-the-bug-where-bpf_get_stackid-returns-ef.patch @@ -0,0 +1,50 @@ +From b09ae9b26fe5bac4704da61c7a946b391ea35e35 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 19:20:12 +0000 +Subject: tracing: Fix the bug where bpf_get_stackid returns -EFAULT on the + ARM64 + +From: Feng Yang + +commit fd2f74f8f3d3c1a524637caf5bead9757fae4332 upstream. + +When using bpf_program__attach_kprobe_multi_opts on ARM64 to hook a BPF program +that contains the bpf_get_stackid function, the BPF program fails +to obtain the stack trace and returns -EFAULT. + +This is because ftrace_partial_regs omits the configuration of the pstate register, +leaving pstate at the default value of 0. When get_perf_callchain executes, +it uses user_mode(regs) to determine whether it is in kernel mode. +This leads to a misjudgment that the code is in user mode, +so perf_callchain_kernel is not executed and the function returns directly. +As a result, trace->nr becomes 0, and finally -EFAULT is returned. + +Therefore, the assignment of the pstate register is added here. + +Fixes: b9b55c8912ce ("tracing: Add ftrace_partial_regs() for converting ftrace_regs to pt_regs") +Closes: https://lore.kernel.org/bpf/20250919071902.554223-1-yangfeng59949@163.com/ +Signed-off-by: Feng Yang +Tested-by: Jiri Olsa +Acked-by: Masami Hiramatsu (Google) +Signed-off-by: Will Deacon +Signed-off-by: Gyokhan Kochmarla +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/ftrace.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h +index 10e56522122aa..46d4300dd48d3 100644 +--- a/arch/arm64/include/asm/ftrace.h ++++ b/arch/arm64/include/asm/ftrace.h +@@ -145,6 +145,7 @@ ftrace_partial_regs(const struct ftrace_regs *fregs, struct pt_regs *regs) + regs->pc = afregs->pc; + regs->regs[29] = afregs->fp; + regs->regs[30] = afregs->lr; ++ regs->pstate = PSR_MODE_EL1h; + return regs; + } + +-- +2.53.0 + diff --git a/queue-6.12/x86-fgraph-fix-return_to_handler-regs.rsp-value.patch b/queue-6.12/x86-fgraph-fix-return_to_handler-regs.rsp-value.patch new file mode 100644 index 0000000000..7030db8650 --- /dev/null +++ b/queue-6.12/x86-fgraph-fix-return_to_handler-regs.rsp-value.patch @@ -0,0 +1,67 @@ +From f98c446f5e4b7846cf8940726cbc4f76c642e8c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 19:23:24 +0000 +Subject: x86/fgraph: Fix return_to_handler regs.rsp value + +From: Jiri Olsa + +commit 8bc11700e0d23d4fdb7d8d5a73b2e95de427cabc upstream. + +The previous change (Fixes commit) messed up the rsp register value, +which is wrong because it's already adjusted with FRAME_SIZE, we need +the original rsp value. + +This change does not affect fprobe current kernel unwind, the !perf_hw_regs +path perf_callchain_kernel: + + if (perf_hw_regs(regs)) { + if (perf_callchain_store(entry, regs->ip)) + return; + unwind_start(&state, current, regs, NULL); + } else { + unwind_start(&state, current, NULL, (void *)regs->sp); + } + +which uses pt_regs.sp as first_frame boundary (FRAME_SIZE shift makes +no difference, unwind stil stops at the right frame). + +This change fixes the other path when we want to unwind directly from +pt_regs sp/fp/ip state, which is coming in following change. + +Fixes: 20a0bc10272f ("x86/fgraph,bpf: Fix stack ORC unwind from kprobe_multi return probe") +Signed-off-by: Jiri Olsa +Signed-off-by: Andrii Nakryiko +Reviewed-by: Steven Rostedt (Google) +Link: https://lore.kernel.org/bpf/20260126211837.472802-2-jolsa@kernel.org +Signed-off-by: Gyokhan Kochmarla +Signed-off-by: Sasha Levin +--- + arch/x86/kernel/ftrace_64.S | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/kernel/ftrace_64.S b/arch/x86/kernel/ftrace_64.S +index 8a3cff618692c..143fc62bf6f88 100644 +--- a/arch/x86/kernel/ftrace_64.S ++++ b/arch/x86/kernel/ftrace_64.S +@@ -349,6 +349,9 @@ SYM_CODE_START(return_to_handler) + UNWIND_HINT_UNDEFINED + ANNOTATE_NOENDBR + ++ /* Store original rsp for pt_regs.sp value. */ ++ movq %rsp, %rdi ++ + /* Restore return_to_handler value that got eaten by previous ret instruction. */ + subq $8, %rsp + UNWIND_HINT_FUNC +@@ -359,7 +362,7 @@ SYM_CODE_START(return_to_handler) + movq %rax, RAX(%rsp) + movq %rdx, RDX(%rsp) + movq %rbp, RBP(%rsp) +- movq %rsp, RSP(%rsp) ++ movq %rdi, RSP(%rsp) + movq %rsp, %rdi + + call ftrace_return_to_handler +-- +2.53.0 + diff --git a/queue-6.18/drm-atomic-increase-timeout-in-drm_atomic_helper_wai.patch b/queue-6.18/drm-atomic-increase-timeout-in-drm_atomic_helper_wai.patch new file mode 100644 index 0000000000..e47d165544 --- /dev/null +++ b/queue-6.18/drm-atomic-increase-timeout-in-drm_atomic_helper_wai.patch @@ -0,0 +1,50 @@ +From 0328cc6de2e09b3894ef93b56b4708d2420fd0c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 21:31:22 +0800 +Subject: drm/atomic: Increase timeout in drm_atomic_helper_wait_for_vblanks() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Zimmermann + +[ Upstream commit 79ae8510b5b81b9500370f89c619b50ca9c0990f ] + +Increase the timeout for vblank events from 100 ms to 1000 ms. This +is the same fix as in commit f050da08a4ed ("drm/vblank: Increase +timeout in drm_wait_one_vblank()") for another vblank timeout. + +After merging generic DRM vblank timers [1] and converting several +DRM drivers for virtual hardware, these drivers synchronize their +vblank events to the display refresh rate. This can trigger timeouts +within the DRM framework. + +Signed-off-by: Thomas Zimmermann +Link: https://lore.kernel.org/dri-devel/20250904145806.430568-1-tzimmermann@suse.de/ # [1] +Reported-by: syzbot+fcede535e7eb57cf5b43@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/dri-devel/69381d6c.050a0220.4004e.0017.GAE@google.com/ +Reviewed-by: Ville Syrjälä +Fixes: 74afeb812850 ("drm/vblank: Add vblank timer") +Link: https://patch.msgid.link/20251209143325.102056-1-tzimmermann@suse.de +Signed-off-by: Mingyu Wang <25181214217@stu.xidian.edu.cn> +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/drm_atomic_helper.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c +index bbec1c184f652..b06a5cba52958 100644 +--- a/drivers/gpu/drm/drm_atomic_helper.c ++++ b/drivers/gpu/drm/drm_atomic_helper.c +@@ -1913,7 +1913,7 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev, + ret = wait_event_timeout(dev->vblank[i].queue, + state->crtcs[i].last_vblank_count != + drm_crtc_vblank_count(crtc), +- msecs_to_jiffies(100)); ++ msecs_to_jiffies(1000)); + + WARN(!ret, "[CRTC:%d:%s] vblank wait timed out\n", + crtc->base.id, crtc->name); +-- +2.53.0 + diff --git a/queue-6.18/drm-vblank-add-crtc-helpers-for-simple-use-cases.patch b/queue-6.18/drm-vblank-add-crtc-helpers-for-simple-use-cases.patch new file mode 100644 index 0000000000..42c50273f1 --- /dev/null +++ b/queue-6.18/drm-vblank-add-crtc-helpers-for-simple-use-cases.patch @@ -0,0 +1,177 @@ +From b0fe7515c74d5c520f8a3fdb83dc5eaf1747fcc7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 21:31:20 +0800 +Subject: drm/vblank: Add CRTC helpers for simple use cases + +From: Thomas Zimmermann + +[ Upstream commit d54dbb5963bdbdf8559903fe2b2343e871adcb30 ] + +Implement atomic_flush, atomic_enable and atomic_disable of struct +drm_crtc_helper_funcs for vblank handling. Driver with no further +requirements can use these functions instead of adding their own. +Also simplifies the use of vblank timers. + +The code has been adopted from vkms, which added the funtionality +in commit 3a0709928b17 ("drm/vkms: Add vblank events simulated by +hrtimers"). + +v3: +- mention vkms (Javier) +v2: +- fix docs + +Signed-off-by: Thomas Zimmermann +Reviewed-by: Javier Martinez Canillas +Tested-by: Michael Kelley +Link: https://lore.kernel.org/r/20250916083816.30275-3-tzimmermann@suse.de +Signed-off-by: Mingyu Wang <25181214217@stu.xidian.edu.cn> +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/drm_vblank_helper.c | 80 +++++++++++++++++++++++++++++ + include/drm/drm_vblank_helper.h | 23 +++++++++ + 2 files changed, 103 insertions(+) + +diff --git a/drivers/gpu/drm/drm_vblank_helper.c b/drivers/gpu/drm/drm_vblank_helper.c +index f94d1e706191b..a04a6ba1b0ca0 100644 +--- a/drivers/gpu/drm/drm_vblank_helper.c ++++ b/drivers/gpu/drm/drm_vblank_helper.c +@@ -1,5 +1,6 @@ + // SPDX-License-Identifier: MIT + ++#include + #include + #include + #include +@@ -17,6 +18,12 @@ + * Drivers enable support for vblank timers by setting the vblank callbacks + * in struct &drm_crtc_funcs to the helpers provided by this library. The + * initializer macro DRM_CRTC_VBLANK_TIMER_FUNCS does this conveniently. ++ * The driver further has to send the VBLANK event from its atomic_flush ++ * callback and control vblank from the CRTC's atomic_enable and atomic_disable ++ * callbacks. The callbacks are located in struct &drm_crtc_helper_funcs. ++ * The vblank helper library provides implementations of these callbacks ++ * for drivers without further requirements. The initializer macro ++ * DRM_CRTC_HELPER_VBLANK_FUNCS sets them coveniently. + * + * Once the driver enables vblank support with drm_vblank_init(), each + * CRTC's vblank timer fires according to the programmed display mode. By +@@ -25,6 +32,79 @@ + * struct &drm_crtc_helper_funcs.handle_vblank_timeout. + */ + ++/* ++ * VBLANK helpers ++ */ ++ ++/** ++ * drm_crtc_vblank_atomic_flush - ++ * Implements struct &drm_crtc_helper_funcs.atomic_flush ++ * @crtc: The CRTC ++ * @state: The atomic state to apply ++ * ++ * The helper drm_crtc_vblank_atomic_flush() implements atomic_flush of ++ * struct drm_crtc_helper_funcs for CRTCs that only need to send out a ++ * VBLANK event. ++ * ++ * See also struct &drm_crtc_helper_funcs.atomic_flush. ++ */ ++void drm_crtc_vblank_atomic_flush(struct drm_crtc *crtc, ++ struct drm_atomic_state *state) ++{ ++ struct drm_device *dev = crtc->dev; ++ struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); ++ struct drm_pending_vblank_event *event; ++ ++ spin_lock_irq(&dev->event_lock); ++ ++ event = crtc_state->event; ++ crtc_state->event = NULL; ++ ++ if (event) { ++ if (drm_crtc_vblank_get(crtc) == 0) ++ drm_crtc_arm_vblank_event(crtc, event); ++ else ++ drm_crtc_send_vblank_event(crtc, event); ++ } ++ ++ spin_unlock_irq(&dev->event_lock); ++} ++EXPORT_SYMBOL(drm_crtc_vblank_atomic_flush); ++ ++/** ++ * drm_crtc_vblank_atomic_enable - Implements struct &drm_crtc_helper_funcs.atomic_enable ++ * @crtc: The CRTC ++ * @state: The atomic state ++ * ++ * The helper drm_crtc_vblank_atomic_enable() implements atomic_enable ++ * of struct drm_crtc_helper_funcs for CRTCs the only need to enable VBLANKs. ++ * ++ * See also struct &drm_crtc_helper_funcs.atomic_enable. ++ */ ++void drm_crtc_vblank_atomic_enable(struct drm_crtc *crtc, ++ struct drm_atomic_state *state) ++{ ++ drm_crtc_vblank_on(crtc); ++} ++EXPORT_SYMBOL(drm_crtc_vblank_atomic_enable); ++ ++/** ++ * drm_crtc_vblank_atomic_disable - Implements struct &drm_crtc_helper_funcs.atomic_disable ++ * @crtc: The CRTC ++ * @state: The atomic state ++ * ++ * The helper drm_crtc_vblank_atomic_disable() implements atomic_disable ++ * of struct drm_crtc_helper_funcs for CRTCs the only need to disable VBLANKs. ++ * ++ * See also struct &drm_crtc_funcs.atomic_disable. ++ */ ++void drm_crtc_vblank_atomic_disable(struct drm_crtc *crtc, ++ struct drm_atomic_state *state) ++{ ++ drm_crtc_vblank_off(crtc); ++} ++EXPORT_SYMBOL(drm_crtc_vblank_atomic_disable); ++ + /* + * VBLANK timer + */ +diff --git a/include/drm/drm_vblank_helper.h b/include/drm/drm_vblank_helper.h +index 74a971d0cfba0..fcd8a9b358463 100644 +--- a/include/drm/drm_vblank_helper.h ++++ b/include/drm/drm_vblank_helper.h +@@ -6,8 +6,31 @@ + #include + #include + ++struct drm_atomic_state; + struct drm_crtc; + ++/* ++ * VBLANK helpers ++ */ ++ ++void drm_crtc_vblank_atomic_flush(struct drm_crtc *crtc, ++ struct drm_atomic_state *state); ++void drm_crtc_vblank_atomic_enable(struct drm_crtc *crtc, ++ struct drm_atomic_state *state); ++void drm_crtc_vblank_atomic_disable(struct drm_crtc *crtc, ++ struct drm_atomic_state *crtc_state); ++ ++/** ++ * DRM_CRTC_HELPER_VBLANK_FUNCS - Default implementation for VBLANK helpers ++ * ++ * This macro initializes struct &drm_crtc_helper_funcs to default helpers ++ * for VBLANK handling. ++ */ ++#define DRM_CRTC_HELPER_VBLANK_FUNCS \ ++ .atomic_flush = drm_crtc_vblank_atomic_flush, \ ++ .atomic_enable = drm_crtc_vblank_atomic_enable, \ ++ .atomic_disable = drm_crtc_vblank_atomic_disable ++ + /* + * VBLANK timer + */ +-- +2.53.0 + diff --git a/queue-6.18/drm-vblank-add-vblank-timer.patch b/queue-6.18/drm-vblank-add-vblank-timer.patch new file mode 100644 index 0000000000..e4eba95c1c --- /dev/null +++ b/queue-6.18/drm-vblank-add-vblank-timer.patch @@ -0,0 +1,537 @@ +From 6f54e07c43a2d03aa6245613760eb1d1288d3ef0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 21:31:19 +0800 +Subject: drm/vblank: Add vblank timer + +From: Thomas Zimmermann + +[ Upstream commit 74afeb8128502a529041a2566febd26053a7be11 ] + +The vblank timer simulates a vblank interrupt for hardware without +support. Rate-limits the display update frequency. + +DRM drivers for hardware without vblank support apply display updates +ASAP. A vblank event informs DRM clients of the completed update. +Userspace compositors immediately schedule the next update, which +creates significant load on virtualization outputs. Display updates +are usually fast on virtualization outputs, as their framebuffers are +in regular system memory and there's no hardware vblank interrupt to +throttle the update rate. + +The vblank timer is a HR timer that signals the vblank in software. +It limits the update frequency of a DRM driver similar to a hardware +vblank interrupt. The timer is not synchronized to the actual vblank +interval of the display. + +The code has been adopted from vkms, which added the funtionality +in commit 3a0709928b17 ("drm/vkms: Add vblank events simulated by +hrtimers"). + +The new implementation is part of the existing vblank support, +which sets up the timer automatically. Drivers only have to start +and cancel the vblank timer as part of enabling and disabling the +CRTC. The new vblank helper library provides callbacks for struct +drm_crtc_funcs. + +The standard way for handling vblank is to call drm_crtc_handle_vblank(). +Drivers that require additional processing, such as vkms, can init +handle_vblank_timeout in struct drm_crtc_helper_funcs to refer to +their timeout handler. + +There's a possible deadlock between drm_crtc_handle_vblank() and +hrtimer_cancel(). [1] The implementation avoids to call hrtimer_cancel() +directly and instead signals to the timer function to not restart +itself. + +v4: +- fix possible race condition between timeout and atomic commit (Michael) +v3: +- avoid deadlock when cancelling timer (Ville, Lyude) +v2: +- implement vblank timer entirely in vblank helpers +- downgrade overrun warning to debug +- fix docs + +Signed-off-by: Thomas Zimmermann +Tested-by: Louis Chauvet +Reviewed-by: Louis Chauvet +Reviewed-by: Javier Martinez Canillas +Tested-by: Michael Kelley +Link: https://lore.kernel.org/all/20250510094757.4174662-1-zengheng4@huawei.com/ # [1] +Link: https://lore.kernel.org/r/20250916083816.30275-2-tzimmermann@suse.de +Signed-off-by: Mingyu Wang <25181214217@stu.xidian.edu.cn> +Signed-off-by: Sasha Levin +--- + Documentation/gpu/drm-kms-helpers.rst | 12 ++ + drivers/gpu/drm/Makefile | 3 +- + drivers/gpu/drm/drm_vblank.c | 172 ++++++++++++++++++++++- + drivers/gpu/drm/drm_vblank_helper.c | 96 +++++++++++++ + include/drm/drm_modeset_helper_vtables.h | 12 ++ + include/drm/drm_vblank.h | 32 +++++ + include/drm/drm_vblank_helper.h | 33 +++++ + 7 files changed, 357 insertions(+), 3 deletions(-) + create mode 100644 drivers/gpu/drm/drm_vblank_helper.c + create mode 100644 include/drm/drm_vblank_helper.h + +diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst +index 5139705089f20..781129f78b06b 100644 +--- a/Documentation/gpu/drm-kms-helpers.rst ++++ b/Documentation/gpu/drm-kms-helpers.rst +@@ -92,6 +92,18 @@ GEM Atomic Helper Reference + .. kernel-doc:: drivers/gpu/drm/drm_gem_atomic_helper.c + :export: + ++VBLANK Helper Reference ++----------------------- ++ ++.. kernel-doc:: drivers/gpu/drm/drm_vblank_helper.c ++ :doc: overview ++ ++.. kernel-doc:: include/drm/drm_vblank_helper.h ++ :internal: ++ ++.. kernel-doc:: drivers/gpu/drm/drm_vblank_helper.c ++ :export: ++ + Simple KMS Helper Reference + =========================== + +diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile +index 742f0d590c5af..b248e64587ed4 100644 +--- a/drivers/gpu/drm/Makefile ++++ b/drivers/gpu/drm/Makefile +@@ -152,7 +152,8 @@ drm_kms_helper-y := \ + drm_plane_helper.o \ + drm_probe_helper.o \ + drm_self_refresh_helper.o \ +- drm_simple_kms_helper.o ++ drm_simple_kms_helper.o \ ++ drm_vblank_helper.o + drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o + drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o + obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o +diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c +index 46f59883183d9..61e211fd3c9c8 100644 +--- a/drivers/gpu/drm/drm_vblank.c ++++ b/drivers/gpu/drm/drm_vblank.c +@@ -136,8 +136,17 @@ + * vblanks after a timer has expired, which can be configured through the + * ``vblankoffdelay`` module parameter. + * +- * Drivers for hardware without support for vertical-blanking interrupts +- * must not call drm_vblank_init(). For such drivers, atomic helpers will ++ * Drivers for hardware without support for vertical-blanking interrupts can ++ * use DRM vblank timers to send vblank events at the rate of the current ++ * display mode's refresh. While not synchronized to the hardware's ++ * vertical-blanking regions, the timer helps DRM clients and compositors to ++ * adapt their update cycle to the display output. Drivers should set up ++ * vblanking as usual, but call drm_crtc_vblank_start_timer() and ++ * drm_crtc_vblank_cancel_timer() as part of their atomic mode setting. ++ * See also DRM vblank helpers for more information. ++ * ++ * Drivers without support for vertical-blanking interrupts nor timers must ++ * not call drm_vblank_init(). For these drivers, atomic helpers will + * automatically generate fake vblank events as part of the display update. + * This functionality also can be controlled by the driver by enabling and + * disabling struct drm_crtc_state.no_vblank. +@@ -508,6 +517,9 @@ static void drm_vblank_init_release(struct drm_device *dev, void *ptr) + drm_WARN_ON(dev, READ_ONCE(vblank->enabled) && + drm_core_check_feature(dev, DRIVER_MODESET)); + ++ if (vblank->vblank_timer.crtc) ++ hrtimer_cancel(&vblank->vblank_timer.timer); ++ + drm_vblank_destroy_worker(vblank); + timer_delete_sync(&vblank->disable_timer); + } +@@ -2162,3 +2174,159 @@ int drm_crtc_queue_sequence_ioctl(struct drm_device *dev, void *data, + return ret; + } + ++/* ++ * VBLANK timer ++ */ ++ ++static enum hrtimer_restart drm_vblank_timer_function(struct hrtimer *timer) ++{ ++ struct drm_vblank_crtc_timer *vtimer = ++ container_of(timer, struct drm_vblank_crtc_timer, timer); ++ struct drm_crtc *crtc = vtimer->crtc; ++ const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; ++ struct drm_device *dev = crtc->dev; ++ unsigned long flags; ++ ktime_t interval; ++ u64 ret_overrun; ++ bool succ; ++ ++ spin_lock_irqsave(&vtimer->interval_lock, flags); ++ interval = vtimer->interval; ++ spin_unlock_irqrestore(&vtimer->interval_lock, flags); ++ ++ if (!interval) ++ return HRTIMER_NORESTART; ++ ++ ret_overrun = hrtimer_forward_now(&vtimer->timer, interval); ++ if (ret_overrun != 1) ++ drm_dbg_vbl(dev, "vblank timer overrun\n"); ++ ++ if (crtc_funcs->handle_vblank_timeout) ++ succ = crtc_funcs->handle_vblank_timeout(crtc); ++ else ++ succ = drm_crtc_handle_vblank(crtc); ++ if (!succ) ++ return HRTIMER_NORESTART; ++ ++ return HRTIMER_RESTART; ++} ++ ++/** ++ * drm_crtc_vblank_start_timer - Starts the vblank timer on the given CRTC ++ * @crtc: the CRTC ++ * ++ * Drivers should call this function from their CRTC's enable_vblank ++ * function to start a vblank timer. The timer will fire after the duration ++ * of a full frame. drm_crtc_vblank_cancel_timer() disables a running timer. ++ * ++ * Returns: ++ * 0 on success, or a negative errno code otherwise. ++ */ ++int drm_crtc_vblank_start_timer(struct drm_crtc *crtc) ++{ ++ struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); ++ struct drm_vblank_crtc_timer *vtimer = &vblank->vblank_timer; ++ unsigned long flags; ++ ++ if (!vtimer->crtc) { ++ /* ++ * Set up the data structures on the first invocation. ++ */ ++ vtimer->crtc = crtc; ++ spin_lock_init(&vtimer->interval_lock); ++ hrtimer_setup(&vtimer->timer, drm_vblank_timer_function, ++ CLOCK_MONOTONIC, HRTIMER_MODE_REL); ++ } else { ++ /* ++ * Timer should not be active. If it is, wait for the ++ * previous cancel operations to finish. ++ */ ++ while (hrtimer_active(&vtimer->timer)) ++ hrtimer_try_to_cancel(&vtimer->timer); ++ } ++ ++ drm_calc_timestamping_constants(crtc, &crtc->mode); ++ ++ spin_lock_irqsave(&vtimer->interval_lock, flags); ++ vtimer->interval = ns_to_ktime(vblank->framedur_ns); ++ spin_unlock_irqrestore(&vtimer->interval_lock, flags); ++ ++ hrtimer_start(&vtimer->timer, vtimer->interval, HRTIMER_MODE_REL); ++ ++ return 0; ++} ++EXPORT_SYMBOL(drm_crtc_vblank_start_timer); ++ ++/** ++ * drm_crtc_vblank_start_timer - Cancels the given CRTC's vblank timer ++ * @crtc: the CRTC ++ * ++ * Drivers should call this function from their CRTC's disable_vblank ++ * function to stop a vblank timer. ++ */ ++void drm_crtc_vblank_cancel_timer(struct drm_crtc *crtc) ++{ ++ struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); ++ struct drm_vblank_crtc_timer *vtimer = &vblank->vblank_timer; ++ unsigned long flags; ++ ++ /* ++ * Calling hrtimer_cancel() can result in a deadlock with DRM's ++ * vblank_time_lime_lock and hrtimers' softirq_expiry_lock. So ++ * clear interval and indicate cancellation. The timer function ++ * will cancel itself on the next invocation. ++ */ ++ ++ spin_lock_irqsave(&vtimer->interval_lock, flags); ++ vtimer->interval = 0; ++ spin_unlock_irqrestore(&vtimer->interval_lock, flags); ++ ++ hrtimer_try_to_cancel(&vtimer->timer); ++} ++EXPORT_SYMBOL(drm_crtc_vblank_cancel_timer); ++ ++/** ++ * drm_crtc_vblank_get_vblank_timeout - Returns the vblank timeout ++ * @crtc: The CRTC ++ * @vblank_time: Returns the next vblank timestamp ++ * ++ * The helper drm_crtc_vblank_get_vblank_timeout() returns the next vblank ++ * timestamp of the CRTC's vblank timer according to the timer's expiry ++ * time. ++ */ ++void drm_crtc_vblank_get_vblank_timeout(struct drm_crtc *crtc, ktime_t *vblank_time) ++{ ++ struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); ++ struct drm_vblank_crtc_timer *vtimer = &vblank->vblank_timer; ++ u64 cur_count; ++ ktime_t cur_time; ++ ++ if (!READ_ONCE(vblank->enabled)) { ++ *vblank_time = ktime_get(); ++ return; ++ } ++ ++ /* ++ * A concurrent vblank timeout could update the expires field before ++ * we compare it with the vblank time. Hence we'd compare the old ++ * expiry time to the new vblank time; deducing the timer had already ++ * expired. Reread until we get consistent values from both fields. ++ */ ++ do { ++ cur_count = drm_crtc_vblank_count_and_time(crtc, &cur_time); ++ *vblank_time = READ_ONCE(vtimer->timer.node.expires); ++ } while (cur_count != drm_crtc_vblank_count_and_time(crtc, &cur_time)); ++ ++ if (drm_WARN_ON(crtc->dev, !ktime_compare(*vblank_time, cur_time))) ++ return; /* Already expired */ ++ ++ /* ++ * To prevent races we roll the hrtimer forward before we do any ++ * interrupt processing - this is how real hw works (the interrupt ++ * is only generated after all the vblank registers are updated) ++ * and what the vblank core expects. Therefore we need to always ++ * correct the timestamp by one frame. ++ */ ++ *vblank_time = ktime_sub(*vblank_time, vtimer->interval); ++} ++EXPORT_SYMBOL(drm_crtc_vblank_get_vblank_timeout); +diff --git a/drivers/gpu/drm/drm_vblank_helper.c b/drivers/gpu/drm/drm_vblank_helper.c +new file mode 100644 +index 0000000000000..f94d1e706191b +--- /dev/null ++++ b/drivers/gpu/drm/drm_vblank_helper.c +@@ -0,0 +1,96 @@ ++// SPDX-License-Identifier: MIT ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ * DOC: overview ++ * ++ * The vblank helper library provides functions for supporting vertical ++ * blanking in DRM drivers. ++ * ++ * For vblank timers, several callback implementations are available. ++ * Drivers enable support for vblank timers by setting the vblank callbacks ++ * in struct &drm_crtc_funcs to the helpers provided by this library. The ++ * initializer macro DRM_CRTC_VBLANK_TIMER_FUNCS does this conveniently. ++ * ++ * Once the driver enables vblank support with drm_vblank_init(), each ++ * CRTC's vblank timer fires according to the programmed display mode. By ++ * default, the vblank timer invokes drm_crtc_handle_vblank(). Drivers with ++ * more specific requirements can set their own handler function in ++ * struct &drm_crtc_helper_funcs.handle_vblank_timeout. ++ */ ++ ++/* ++ * VBLANK timer ++ */ ++ ++/** ++ * drm_crtc_vblank_helper_enable_vblank_timer - Implements struct &drm_crtc_funcs.enable_vblank ++ * @crtc: The CRTC ++ * ++ * The helper drm_crtc_vblank_helper_enable_vblank_timer() implements ++ * enable_vblank of struct drm_crtc_helper_funcs for CRTCs that require ++ * a VBLANK timer. It sets up the timer on the first invocation. The ++ * started timer expires after the current frame duration. See struct ++ * &drm_vblank_crtc.framedur_ns. ++ * ++ * See also struct &drm_crtc_helper_funcs.enable_vblank. ++ * ++ * Returns: ++ * 0 on success, or a negative errno code otherwise. ++ */ ++int drm_crtc_vblank_helper_enable_vblank_timer(struct drm_crtc *crtc) ++{ ++ return drm_crtc_vblank_start_timer(crtc); ++} ++EXPORT_SYMBOL(drm_crtc_vblank_helper_enable_vblank_timer); ++ ++/** ++ * drm_crtc_vblank_helper_disable_vblank_timer - Implements struct &drm_crtc_funcs.disable_vblank ++ * @crtc: The CRTC ++ * ++ * The helper drm_crtc_vblank_helper_disable_vblank_timer() implements ++ * disable_vblank of struct drm_crtc_funcs for CRTCs that require a ++ * VBLANK timer. ++ * ++ * See also struct &drm_crtc_helper_funcs.disable_vblank. ++ */ ++void drm_crtc_vblank_helper_disable_vblank_timer(struct drm_crtc *crtc) ++{ ++ drm_crtc_vblank_cancel_timer(crtc); ++} ++EXPORT_SYMBOL(drm_crtc_vblank_helper_disable_vblank_timer); ++ ++/** ++ * drm_crtc_vblank_helper_get_vblank_timestamp_from_timer - ++ * Implements struct &drm_crtc_funcs.get_vblank_timestamp ++ * @crtc: The CRTC ++ * @max_error: Maximum acceptable error ++ * @vblank_time: Returns the next vblank timestamp ++ * @in_vblank_irq: True is called from drm_crtc_handle_vblank() ++ * ++ * The helper drm_crtc_helper_get_vblank_timestamp_from_timer() implements ++ * get_vblank_timestamp of struct drm_crtc_funcs for CRTCs that require a ++ * VBLANK timer. It returns the timestamp according to the timer's expiry ++ * time. ++ * ++ * See also struct &drm_crtc_funcs.get_vblank_timestamp. ++ * ++ * Returns: ++ * True on success, or false otherwise. ++ */ ++bool drm_crtc_vblank_helper_get_vblank_timestamp_from_timer(struct drm_crtc *crtc, ++ int *max_error, ++ ktime_t *vblank_time, ++ bool in_vblank_irq) ++{ ++ drm_crtc_vblank_get_vblank_timeout(crtc, vblank_time); ++ ++ return true; ++} ++EXPORT_SYMBOL(drm_crtc_vblank_helper_get_vblank_timestamp_from_timer); +diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h +index ce7c7aeac887b..fe32854b7ffec 100644 +--- a/include/drm/drm_modeset_helper_vtables.h ++++ b/include/drm/drm_modeset_helper_vtables.h +@@ -490,6 +490,18 @@ struct drm_crtc_helper_funcs { + bool in_vblank_irq, int *vpos, int *hpos, + ktime_t *stime, ktime_t *etime, + const struct drm_display_mode *mode); ++ ++ /** ++ * @handle_vblank_timeout: Handles timeouts of the vblank timer. ++ * ++ * Called by CRTC's the vblank timer on each timeout. Semantics is ++ * equivalient to drm_crtc_handle_vblank(). Implementations should ++ * invoke drm_crtc_handle_vblank() as part of processing the timeout. ++ * ++ * This callback is optional. If unset, the vblank timer invokes ++ * drm_crtc_handle_vblank() directly. ++ */ ++ bool (*handle_vblank_timeout)(struct drm_crtc *crtc); + }; + + /** +diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h +index 151ab1e85b1b7..ffa564d796384 100644 +--- a/include/drm/drm_vblank.h ++++ b/include/drm/drm_vblank.h +@@ -25,6 +25,7 @@ + #define _DRM_VBLANK_H_ + + #include ++#include + #include + #include + #include +@@ -103,6 +104,28 @@ struct drm_vblank_crtc_config { + bool disable_immediate; + }; + ++/** ++ * struct drm_vblank_crtc_timer - vblank timer for a CRTC ++ */ ++struct drm_vblank_crtc_timer { ++ /** ++ * @timer: The vblank's high-resolution timer ++ */ ++ struct hrtimer timer; ++ /** ++ * @interval_lock: Protects @interval ++ */ ++ spinlock_t interval_lock; ++ /** ++ * @interval: Duration between two vblanks ++ */ ++ ktime_t interval; ++ /** ++ * @crtc: The timer's CRTC ++ */ ++ struct drm_crtc *crtc; ++}; ++ + /** + * struct drm_vblank_crtc - vblank tracking for a CRTC + * +@@ -254,6 +277,11 @@ struct drm_vblank_crtc { + * cancelled. + */ + wait_queue_head_t work_wait_queue; ++ ++ /** ++ * @vblank_timer: Holds the state of the vblank timer ++ */ ++ struct drm_vblank_crtc_timer vblank_timer; + }; + + struct drm_vblank_crtc *drm_crtc_vblank_crtc(struct drm_crtc *crtc); +@@ -290,6 +318,10 @@ wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc); + void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc, + u32 max_vblank_count); + ++int drm_crtc_vblank_start_timer(struct drm_crtc *crtc); ++void drm_crtc_vblank_cancel_timer(struct drm_crtc *crtc); ++void drm_crtc_vblank_get_vblank_timeout(struct drm_crtc *crtc, ktime_t *vblank_time); ++ + /* + * Helpers for struct drm_crtc_funcs + */ +diff --git a/include/drm/drm_vblank_helper.h b/include/drm/drm_vblank_helper.h +new file mode 100644 +index 0000000000000..74a971d0cfba0 +--- /dev/null ++++ b/include/drm/drm_vblank_helper.h +@@ -0,0 +1,33 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++ ++#ifndef _DRM_VBLANK_HELPER_H_ ++#define _DRM_VBLANK_HELPER_H_ ++ ++#include ++#include ++ ++struct drm_crtc; ++ ++/* ++ * VBLANK timer ++ */ ++ ++int drm_crtc_vblank_helper_enable_vblank_timer(struct drm_crtc *crtc); ++void drm_crtc_vblank_helper_disable_vblank_timer(struct drm_crtc *crtc); ++bool drm_crtc_vblank_helper_get_vblank_timestamp_from_timer(struct drm_crtc *crtc, ++ int *max_error, ++ ktime_t *vblank_time, ++ bool in_vblank_irq); ++ ++/** ++ * DRM_CRTC_VBLANK_TIMER_FUNCS - Default implementation for VBLANK timers ++ * ++ * This macro initializes struct &drm_crtc_funcs to default helpers for ++ * VBLANK timers. ++ */ ++#define DRM_CRTC_VBLANK_TIMER_FUNCS \ ++ .enable_vblank = drm_crtc_vblank_helper_enable_vblank_timer, \ ++ .disable_vblank = drm_crtc_vblank_helper_disable_vblank_timer, \ ++ .get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp_from_timer ++ ++#endif +-- +2.53.0 + diff --git a/queue-6.18/drm-vblank-fix-kernel-docs-for-vblank-timer.patch b/queue-6.18/drm-vblank-fix-kernel-docs-for-vblank-timer.patch new file mode 100644 index 0000000000..2c2e4df21d --- /dev/null +++ b/queue-6.18/drm-vblank-fix-kernel-docs-for-vblank-timer.patch @@ -0,0 +1,48 @@ +From f7b83fd63a3e176b3c85143f712c8a32246b036e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 21:31:23 +0800 +Subject: drm/vblank: Fix kernel docs for vblank timer + +From: Thomas Zimmermann + +[ Upstream commit 3946d3ba99342f3b9996e621f05e7003d4308171 ] + +Fix documentation for drm_crtc_vblank_start_timer(), which referred +to drm_crtc_vblank_cancel_timer(). + +Signed-off-by: Thomas Zimmermann +Reported-by: Stephen Rothwell +Closes: https://lore.kernel.org/dri-devel/20251106152201.6f248c09@canb.auug.org.au/ +Fixes: 74afeb812850 ("drm/vblank: Add vblank timer") +Cc: Thomas Zimmermann +Cc: Louis Chauvet +Cc: Javier Martinez Canillas +Cc: David Airlie +Cc: Simona Vetter +Cc: Maarten Lankhorst +Cc: Maxime Ripard +Cc: dri-devel@lists.freedesktop.org +Reviewed-by: Louis Chauvet +Link: https://patch.msgid.link/20251106073207.11192-1-tzimmermann@suse.de +Signed-off-by: Mingyu Wang <25181214217@stu.xidian.edu.cn> +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/drm_vblank.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c +index 61e211fd3c9c8..451ec96202266 100644 +--- a/drivers/gpu/drm/drm_vblank.c ++++ b/drivers/gpu/drm/drm_vblank.c +@@ -2258,7 +2258,7 @@ int drm_crtc_vblank_start_timer(struct drm_crtc *crtc) + EXPORT_SYMBOL(drm_crtc_vblank_start_timer); + + /** +- * drm_crtc_vblank_start_timer - Cancels the given CRTC's vblank timer ++ * drm_crtc_vblank_cancel_timer - Cancels the given CRTC's vblank timer + * @crtc: the CRTC + * + * Drivers should call this function from their CRTC's disable_vblank +-- +2.53.0 + diff --git a/queue-6.18/drm-vkms-convert-to-drm-s-vblank-timer.patch b/queue-6.18/drm-vkms-convert-to-drm-s-vblank-timer.patch new file mode 100644 index 0000000000..c14ae40e89 --- /dev/null +++ b/queue-6.18/drm-vkms-convert-to-drm-s-vblank-timer.patch @@ -0,0 +1,176 @@ +From 3bc5cf9c4b89d0278f2334a736e18ffca4cd279a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 May 2026 21:31:21 +0800 +Subject: drm/vkms: Convert to DRM's vblank timer + +From: Thomas Zimmermann + +[ Upstream commit 02e2681ffe1addde1fc8c35d05657b16bfa79613 ] + +Replace vkms' vblank timer with the DRM implementation. The DRM +code is identical in concept, but differs in implementation. + +Vblank timers are covered in vblank helpers and initializer macros, +so remove the corresponding hrtimer in struct vkms_output. The +vblank timer calls vkms' custom timeout code via handle_vblank_timeout +in struct drm_crtc_helper_funcs. + +Signed-off-by: Thomas Zimmermann +Tested-by: Louis Chauvet +Reviewed-by: Louis Chauvet +Reviewed-by: Javier Martinez Canillas +Link: https://lore.kernel.org/r/20250916083816.30275-4-tzimmermann@suse.de +Signed-off-by: Mingyu Wang <25181214217@stu.xidian.edu.cn> +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/vkms/vkms_crtc.c | 83 +++----------------------------- + drivers/gpu/drm/vkms/vkms_drv.h | 2 - + 2 files changed, 7 insertions(+), 78 deletions(-) + +diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c +index e60573e0f3e95..bd79f24686dce 100644 +--- a/drivers/gpu/drm/vkms/vkms_crtc.c ++++ b/drivers/gpu/drm/vkms/vkms_crtc.c +@@ -7,25 +7,18 @@ + #include + #include + #include ++#include + + #include "vkms_drv.h" + +-static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer) ++static bool vkms_crtc_handle_vblank_timeout(struct drm_crtc *crtc) + { +- struct vkms_output *output = container_of(timer, struct vkms_output, +- vblank_hrtimer); +- struct drm_crtc *crtc = &output->crtc; ++ struct vkms_output *output = drm_crtc_to_vkms_output(crtc); + struct vkms_crtc_state *state; +- u64 ret_overrun; + bool ret, fence_cookie; + + fence_cookie = dma_fence_begin_signalling(); + +- ret_overrun = hrtimer_forward_now(&output->vblank_hrtimer, +- output->period_ns); +- if (ret_overrun != 1) +- pr_warn("%s: vblank timer overrun\n", __func__); +- + spin_lock(&output->lock); + ret = drm_crtc_handle_vblank(crtc); + if (!ret) +@@ -57,55 +50,6 @@ static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer) + + dma_fence_end_signalling(fence_cookie); + +- return HRTIMER_RESTART; +-} +- +-static int vkms_enable_vblank(struct drm_crtc *crtc) +-{ +- struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); +- struct vkms_output *out = drm_crtc_to_vkms_output(crtc); +- +- hrtimer_setup(&out->vblank_hrtimer, &vkms_vblank_simulate, CLOCK_MONOTONIC, +- HRTIMER_MODE_REL); +- out->period_ns = ktime_set(0, vblank->framedur_ns); +- hrtimer_start(&out->vblank_hrtimer, out->period_ns, HRTIMER_MODE_REL); +- +- return 0; +-} +- +-static void vkms_disable_vblank(struct drm_crtc *crtc) +-{ +- struct vkms_output *out = drm_crtc_to_vkms_output(crtc); +- +- hrtimer_cancel(&out->vblank_hrtimer); +-} +- +-static bool vkms_get_vblank_timestamp(struct drm_crtc *crtc, +- int *max_error, ktime_t *vblank_time, +- bool in_vblank_irq) +-{ +- struct vkms_output *output = drm_crtc_to_vkms_output(crtc); +- struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); +- +- if (!READ_ONCE(vblank->enabled)) { +- *vblank_time = ktime_get(); +- return true; +- } +- +- *vblank_time = READ_ONCE(output->vblank_hrtimer.node.expires); +- +- if (WARN_ON(*vblank_time == vblank->time)) +- return true; +- +- /* +- * To prevent races we roll the hrtimer forward before we do any +- * interrupt processing - this is how real hw works (the interrupt is +- * only generated after all the vblank registers are updated) and what +- * the vblank core expects. Therefore we need to always correct the +- * timestampe by one frame. +- */ +- *vblank_time -= output->period_ns; +- + return true; + } + +@@ -159,9 +103,7 @@ static const struct drm_crtc_funcs vkms_crtc_funcs = { + .reset = vkms_atomic_crtc_reset, + .atomic_duplicate_state = vkms_atomic_crtc_duplicate_state, + .atomic_destroy_state = vkms_atomic_crtc_destroy_state, +- .enable_vblank = vkms_enable_vblank, +- .disable_vblank = vkms_disable_vblank, +- .get_vblank_timestamp = vkms_get_vblank_timestamp, ++ DRM_CRTC_VBLANK_TIMER_FUNCS, + .get_crc_sources = vkms_get_crc_sources, + .set_crc_source = vkms_set_crc_source, + .verify_crc_source = vkms_verify_crc_source, +@@ -213,18 +155,6 @@ static int vkms_crtc_atomic_check(struct drm_crtc *crtc, + return 0; + } + +-static void vkms_crtc_atomic_enable(struct drm_crtc *crtc, +- struct drm_atomic_state *state) +-{ +- drm_crtc_vblank_on(crtc); +-} +- +-static void vkms_crtc_atomic_disable(struct drm_crtc *crtc, +- struct drm_atomic_state *state) +-{ +- drm_crtc_vblank_off(crtc); +-} +- + static void vkms_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_atomic_state *state) + __acquires(&vkms_output->lock) +@@ -265,8 +195,9 @@ static const struct drm_crtc_helper_funcs vkms_crtc_helper_funcs = { + .atomic_check = vkms_crtc_atomic_check, + .atomic_begin = vkms_crtc_atomic_begin, + .atomic_flush = vkms_crtc_atomic_flush, +- .atomic_enable = vkms_crtc_atomic_enable, +- .atomic_disable = vkms_crtc_atomic_disable, ++ .atomic_enable = drm_crtc_vblank_atomic_enable, ++ .atomic_disable = drm_crtc_vblank_atomic_disable, ++ .handle_vblank_timeout = vkms_crtc_handle_vblank_timeout, + }; + + struct vkms_output *vkms_crtc_init(struct drm_device *dev, struct drm_plane *primary, +diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h +index 8013c31efe3b1..fb9711e1c6fbd 100644 +--- a/drivers/gpu/drm/vkms/vkms_drv.h ++++ b/drivers/gpu/drm/vkms/vkms_drv.h +@@ -215,8 +215,6 @@ struct vkms_output { + struct drm_crtc crtc; + struct drm_writeback_connector wb_connector; + struct drm_encoder wb_encoder; +- struct hrtimer vblank_hrtimer; +- ktime_t period_ns; + struct workqueue_struct *composer_workq; + spinlock_t lock; + +-- +2.53.0 + diff --git a/queue-6.18/revert-ice-fix-double-free-of-tx_buf-skb.patch b/queue-6.18/revert-ice-fix-double-free-of-tx_buf-skb.patch new file mode 100644 index 0000000000..bc144a227b --- /dev/null +++ b/queue-6.18/revert-ice-fix-double-free-of-tx_buf-skb.patch @@ -0,0 +1,46 @@ +From cc19b6039a7bfce8697df1337fe7bc53e9de3563 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 12:43:10 -0400 +Subject: Revert "ice: fix double-free of tx_buf skb" + +This reverts commit 7cb19ec8ac087f33bee60f5d6054b284a5b9bb6f. + +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_txrx.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c +index e0774a640955d..90dbe5266ce78 100644 +--- a/drivers/net/ethernet/intel/ice/ice_txrx.c ++++ b/drivers/net/ethernet/intel/ice/ice_txrx.c +@@ -2594,9 +2594,6 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + + ice_trace(xmit_frame_ring, tx_ring, skb); + +- /* record the location of the first descriptor for this packet */ +- first = &tx_ring->tx_buf[tx_ring->next_to_use]; +- + count = ice_xmit_desc_count(skb); + if (ice_chk_linearize(skb, count)) { + if (__skb_linearize(skb)) +@@ -2622,6 +2619,8 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + + offload.tx_ring = tx_ring; + ++ /* record the location of the first descriptor for this packet */ ++ first = &tx_ring->tx_buf[tx_ring->next_to_use]; + first->skb = skb; + first->type = ICE_TX_BUF_SKB; + first->bytecount = max_t(unsigned int, skb->len, ETH_ZLEN); +@@ -2686,7 +2685,6 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + out_drop: + ice_trace(xmit_frame_ring_drop, tx_ring, skb); + dev_kfree_skb_any(skb); +- first->type = ICE_TX_BUF_EMPTY; + return NETDEV_TX_OK; + } + +-- +2.53.0 + diff --git a/queue-6.18/revert-ice-remove-jumbo_remove-step-from-tx-path.patch b/queue-6.18/revert-ice-remove-jumbo_remove-step-from-tx-path.patch new file mode 100644 index 0000000000..147c7bdca4 --- /dev/null +++ b/queue-6.18/revert-ice-remove-jumbo_remove-step-from-tx-path.patch @@ -0,0 +1,29 @@ +From eafbcb9f51dc7061cc6b9f26c2302151d5e35aa2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 12:43:10 -0400 +Subject: Revert "ice: Remove jumbo_remove step from TX path" + +This reverts commit 55500245ec0420df96b2a89444aabf0cff2c60bc. + +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_txrx.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c +index 90dbe5266ce78..73f08d02f9c76 100644 +--- a/drivers/net/ethernet/intel/ice/ice_txrx.c ++++ b/drivers/net/ethernet/intel/ice/ice_txrx.c +@@ -2594,6 +2594,9 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + + ice_trace(xmit_frame_ring, tx_ring, skb); + ++ if (unlikely(ipv6_hopopt_jumbo_remove(skb))) ++ goto out_drop; ++ + count = ice_xmit_desc_count(skb); + if (ice_chk_linearize(skb, count)) { + if (__skb_linearize(skb)) +-- +2.53.0 + diff --git a/queue-6.18/series b/queue-6.18/series index c1613fec99..0aa542dba6 100644 --- a/queue-6.18/series +++ b/queue-6.18/series @@ -16,3 +16,10 @@ ata-libata-scsi-improve-readability-of-ata_scsi_qc_issue.patch ata-libata-scsi-do-not-use-the-deferred-qc-feature-for-ata_defer_port.patch ata-libata-scsi-do-not-use-the-deferred-qc-feature-on-pmps-with-cbs.patch ata-libata-scsi-do-not-needlessly-defer-commands-when-using-pmp-with-fbs.patch +revert-ice-fix-double-free-of-tx_buf-skb.patch +revert-ice-remove-jumbo_remove-step-from-tx-path.patch +drm-vblank-add-vblank-timer.patch +drm-vblank-add-crtc-helpers-for-simple-use-cases.patch +drm-vkms-convert-to-drm-s-vblank-timer.patch +drm-atomic-increase-timeout-in-drm_atomic_helper_wai.patch +drm-vblank-fix-kernel-docs-for-vblank-timer.patch diff --git a/queue-6.6/i3c-mipi-i3c-hci-correct-ring_ctrl_abort-handling-in.patch b/queue-6.6/i3c-mipi-i3c-hci-correct-ring_ctrl_abort-handling-in.patch new file mode 100644 index 0000000000..684a56055a --- /dev/null +++ b/queue-6.6/i3c-mipi-i3c-hci-correct-ring_ctrl_abort-handling-in.patch @@ -0,0 +1,78 @@ +From 05e5798e389f1bc3a815f1eeefd0c0c2641bbbd0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 14:20:39 +0800 +Subject: i3c: mipi-i3c-hci: Correct RING_CTRL_ABORT handling in DMA dequeue + +From: Adrian Hunter + +[ Upstream commit b795e68bf3073d67bebbb5a44d93f49efc5b8cc7 ] + +The logic used to abort the DMA ring contains several flaws: + + 1. The driver unconditionally issues a ring abort even when the ring has + already stopped. + 2. The completion used to wait for abort completion is never + re-initialized, resulting in incorrect wait behavior. + 3. The abort sequence unintentionally clears RING_CTRL_ENABLE, which + resets hardware ring pointers and disrupts the controller state. + 4. If the ring is already stopped, the abort operation should be + considered successful without attempting further action. + +Fix the abort handling by checking whether the ring is running before +issuing an abort, re-initializing the completion when needed, ensuring that +RING_CTRL_ENABLE remains asserted during abort, and treating an already +stopped ring as a successful condition. + +Fixes: 9ad9a52cce282 ("i3c/master: introduce the mipi-i3c-hci driver") +Cc: stable@vger.kernel.org +Signed-off-by: Adrian Hunter +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260306072451.11131-9-adrian.hunter@intel.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Jianqiang kang +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/mipi-i3c-hci/dma.c | 27 +++++++++++++++++---------- + 1 file changed, 17 insertions(+), 10 deletions(-) + +diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c +index 624d00b853a51..61007167606fd 100644 +--- a/drivers/i3c/master/mipi-i3c-hci/dma.c ++++ b/drivers/i3c/master/mipi-i3c-hci/dma.c +@@ -448,16 +448,23 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci, + struct hci_rh_data *rh = &rings->headers[xfer_list[0].ring_number]; + unsigned int i; + bool did_unqueue = false; +- +- /* stop the ring */ +- rh_reg_write(RING_CONTROL, RING_CTRL_ABORT); +- if (wait_for_completion_timeout(&rh->op_done, HZ) == 0) { +- /* +- * We're deep in it if ever this condition is ever met. +- * Hardware might still be writing to memory, etc. +- */ +- dev_crit(&hci->master.dev, "unable to abort the ring\n"); +- WARN_ON(1); ++ u32 ring_status; ++ ++ ring_status = rh_reg_read(RING_STATUS); ++ if (ring_status & RING_STATUS_RUNNING) { ++ /* stop the ring */ ++ reinit_completion(&rh->op_done); ++ rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE | RING_CTRL_ABORT); ++ wait_for_completion_timeout(&rh->op_done, HZ); ++ ring_status = rh_reg_read(RING_STATUS); ++ if (ring_status & RING_STATUS_RUNNING) { ++ /* ++ * We're deep in it if ever this condition is ever met. ++ * Hardware might still be writing to memory, etc. ++ */ ++ dev_crit(&hci->master.dev, "unable to abort the ring\n"); ++ WARN_ON(1); ++ } + } + + for (i = 0; i < n; i++) { +-- +2.53.0 + diff --git a/queue-6.6/revert-af_unix-reject-siocatmark-on-non-stream-socke.patch b/queue-6.6/revert-af_unix-reject-siocatmark-on-non-stream-socke.patch new file mode 100644 index 0000000000..72cbefa4ea --- /dev/null +++ b/queue-6.6/revert-af_unix-reject-siocatmark-on-non-stream-socke.patch @@ -0,0 +1,29 @@ +From 4936aa60494249ff9b7c7521fb9efef33ede4b8b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 13:04:10 -0400 +Subject: Revert "af_unix: Reject SIOCATMARK on non-stream sockets" + +This reverts commit 0d7e7235bc543c6ed7b873e3015db814d8e8c414. + +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index c621f00902752..8f785b2600ae4 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -2809,9 +2809,6 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state, + goto out; + } + +- if (sk->sk_type != SOCK_STREAM) +- return -EOPNOTSUPP; +- + mutex_lock(&u->iolock); + goto redo; + unlock: +-- +2.53.0 + diff --git a/queue-6.6/revert-ice-fix-double-free-of-tx_buf-skb.patch b/queue-6.6/revert-ice-fix-double-free-of-tx_buf-skb.patch new file mode 100644 index 0000000000..c4066b9988 --- /dev/null +++ b/queue-6.6/revert-ice-fix-double-free-of-tx_buf-skb.patch @@ -0,0 +1,46 @@ +From db24f54e9526802a835bd0142be95c76f5e7ade1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 12:55:37 -0400 +Subject: Revert "ice: fix double-free of tx_buf skb" + +This reverts commit ca6f9d9aee5408c47e6c0fac10955cb6825ecd96. + +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_txrx.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c +index 4e110a008a257..66da8a34be0f1 100644 +--- a/drivers/net/ethernet/intel/ice/ice_txrx.c ++++ b/drivers/net/ethernet/intel/ice/ice_txrx.c +@@ -2364,9 +2364,6 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + + ice_trace(xmit_frame_ring, tx_ring, skb); + +- /* record the location of the first descriptor for this packet */ +- first = &tx_ring->tx_buf[tx_ring->next_to_use]; +- + count = ice_xmit_desc_count(skb); + if (ice_chk_linearize(skb, count)) { + if (__skb_linearize(skb)) +@@ -2392,6 +2389,8 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + + offload.tx_ring = tx_ring; + ++ /* record the location of the first descriptor for this packet */ ++ first = &tx_ring->tx_buf[tx_ring->next_to_use]; + first->skb = skb; + first->type = ICE_TX_BUF_SKB; + first->bytecount = max_t(unsigned int, skb->len, ETH_ZLEN); +@@ -2453,7 +2452,6 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + out_drop: + ice_trace(xmit_frame_ring_drop, tx_ring, skb); + dev_kfree_skb_any(skb); +- first->type = ICE_TX_BUF_EMPTY; + return NETDEV_TX_OK; + } + +-- +2.53.0 + diff --git a/queue-6.6/revert-ice-remove-jumbo_remove-step-from-tx-path.patch b/queue-6.6/revert-ice-remove-jumbo_remove-step-from-tx-path.patch new file mode 100644 index 0000000000..853cdfbda3 --- /dev/null +++ b/queue-6.6/revert-ice-remove-jumbo_remove-step-from-tx-path.patch @@ -0,0 +1,29 @@ +From 5120d53452c0531c33ff477f195a7c2b2213affb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 12:55:37 -0400 +Subject: Revert "ice: Remove jumbo_remove step from TX path" + +This reverts commit a753619ffecfe629ee73c821469edd8b37c72d3b. + +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_txrx.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c +index 66da8a34be0f1..eae4376c68595 100644 +--- a/drivers/net/ethernet/intel/ice/ice_txrx.c ++++ b/drivers/net/ethernet/intel/ice/ice_txrx.c +@@ -2364,6 +2364,9 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + + ice_trace(xmit_frame_ring, tx_ring, skb); + ++ if (unlikely(ipv6_hopopt_jumbo_remove(skb))) ++ goto out_drop; ++ + count = ice_xmit_desc_count(skb); + if (ice_chk_linearize(skb, count)) { + if (__skb_linearize(skb)) +-- +2.53.0 + diff --git a/queue-6.6/revert-s390-cio-update-purge-function-to-unregister-.patch b/queue-6.6/revert-s390-cio-update-purge-function-to-unregister-.patch new file mode 100644 index 0000000000..cf575f98df --- /dev/null +++ b/queue-6.6/revert-s390-cio-update-purge-function-to-unregister-.patch @@ -0,0 +1,76 @@ +From 17b1afa05c17845b837c24b5151c8b86b05957f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 13:03:59 -0400 +Subject: Revert "s390/cio: Update purge function to unregister the unused + subchannels" + +This reverts commit c34b09cbd6fc06f0f234182e462a1b010d13a5a6. + +Signed-off-by: Sasha Levin +--- + drivers/s390/cio/device.c | 37 +++++++++++++------------------------ + 1 file changed, 13 insertions(+), 24 deletions(-) + +diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c +index 93307ca75c10b..e623359862ea2 100644 +--- a/drivers/s390/cio/device.c ++++ b/drivers/s390/cio/device.c +@@ -1318,34 +1318,23 @@ void ccw_device_schedule_recovery(void) + spin_unlock_irqrestore(&recovery_lock, flags); + } + +-static int purge_fn(struct subchannel *sch, void *data) ++static int purge_fn(struct device *dev, void *data) + { +- struct ccw_device *cdev; +- +- spin_lock_irq(sch->lock); +- if (sch->st != SUBCHANNEL_TYPE_IO || !sch->schib.pmcw.dnv) +- goto unlock; +- +- if (!is_blacklisted(sch->schid.ssid, sch->schib.pmcw.dev)) +- goto unlock; +- +- cdev = sch_get_cdev(sch); +- if (cdev) { +- if (cdev->private->state != DEV_STATE_OFFLINE) +- goto unlock; ++ struct ccw_device *cdev = to_ccwdev(dev); ++ struct ccw_dev_id *id = &cdev->private->dev_id; ++ struct subchannel *sch = to_subchannel(cdev->dev.parent); + +- if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0) +- goto unlock; ++ spin_lock_irq(cdev->ccwlock); ++ if (is_blacklisted(id->ssid, id->devno) && ++ (cdev->private->state == DEV_STATE_OFFLINE) && ++ (atomic_cmpxchg(&cdev->private->onoff, 0, 1) == 0)) { ++ CIO_MSG_EVENT(3, "ccw: purging 0.%x.%04x\n", id->ssid, ++ id->devno); + ccw_device_sched_todo(cdev, CDEV_TODO_UNREG); ++ css_sched_sch_todo(sch, SCH_TODO_UNREG); + atomic_set(&cdev->private->onoff, 0); + } +- +- css_sched_sch_todo(sch, SCH_TODO_UNREG); +- CIO_MSG_EVENT(3, "ccw: purging 0.%x.%04x%s\n", sch->schid.ssid, +- sch->schib.pmcw.dev, cdev ? "" : " (no cdev)"); +- +-unlock: +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(cdev->ccwlock); + /* Abort loop in case of pending signal. */ + if (signal_pending(current)) + return -EINTR; +@@ -1361,7 +1350,7 @@ static int purge_fn(struct subchannel *sch, void *data) + int ccw_purge_blacklisted(void) + { + CIO_MSG_EVENT(2, "ccw: purging blacklisted devices\n"); +- for_each_subchannel_staged(purge_fn, NULL, NULL); ++ bus_for_each_dev(&ccw_bus_type, NULL, NULL, purge_fn); + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.6/series b/queue-6.6/series index dab275f248..de80bd7178 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -14,3 +14,8 @@ ksmbd-validate-owner-of-durable-handle-on-reconnect.patch ksmbd-close-durable-scavenger-races-against-m_fp_lis.patch af_unix-give-up-gc-if-msg_peek-intervened.patch smb-client-reject-userspace-cifs.spnego-descriptions.patch +revert-ice-fix-double-free-of-tx_buf-skb.patch +revert-ice-remove-jumbo_remove-step-from-tx-path.patch +revert-s390-cio-update-purge-function-to-unregister-.patch +revert-af_unix-reject-siocatmark-on-non-stream-socke.patch +i3c-mipi-i3c-hci-correct-ring_ctrl_abort-handling-in.patch