From: Kendall Willis k-willis@ti.com
[ Upstream commit 0fdd3240fe5a9bf4785e40506bf86b7e16546b83 ]
The PM co-processor (device manager or DM) adds the ability to abort entry to a low power mode by clearing the mode selection in the latest version of its firmware (11.01.09) [1].
Enable the ti_sci driver to support the LPM abort call which clears the low power mode selection of the DM. This fixes an issue where failed system suspend attempts would cause subsequent suspends to fail.
After system suspend completes, regardless of if system suspend succeeds or fails, the ->complete() hook in TI SCI will be called. In the ->complete() hook, a message will be sent to the DM to clear the current low power mode selection. Clearing the low power mode selection unconditionally will not cause any error in the DM.
[1] https://software-dl.ti.com/tisci/esd/latest/2_tisci_msgs/pm/lpm.html
Signed-off-by: Kendall Willis k-willis@ti.com Reviewed-by: Ulf Hansson ulf.hansson@linaro.org Link: https://patch.msgid.link/20250819195453.1094520-1-k-willis@ti.com Signed-off-by: Nishanth Menon nm@ti.com Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
Based on my comprehensive analysis of this commit, here is my assessment:
**YES** - This commit should be backported to stable kernel trees (specifically 6.13+ stable trees).
## Detailed Analysis
### Bug Fix Classification
This commit fixes a **real, user-impacting bug** where failed system suspend attempts cause subsequent suspend attempts to fail on TI AM62 family SoCs. The commit message explicitly states: "This fixes an issue where failed system suspend attempts would cause subsequent suspends to fail."
**Impact**: Without this fix, users would need to reboot their system to recover suspend functionality after a failed suspend attempt - a significant usability problem for power management.
### Code Changes Analysis
The changes are **small and well-contained** (58 insertions, 2 deletions across 2 files):
1. **New function `ti_sci_cmd_lpm_abort()` (drivers/firmware/ti_sci.c:2018-2057)**: - Follows the exact same pattern as existing TI SCI command functions (compare with `ti_sci_cmd_core_reboot()` at line 2018) - Sends `TI_SCI_MSG_LPM_ABORT` (0x0311) message to firmware to clear LPM selection - Standard error handling with proper resource cleanup
2. **New PM complete hook `ti_sci_pm_complete()` (drivers/firmware/ti_sci.c:3742)**: ```c if (info->fw_caps & MSG_FLAG_CAPS_LPM_ABORT) { if (ti_sci_cmd_lpm_abort(dev)) dev_err(dev, "LPM clear selection failed.\n"); } ``` - **Critical safety feature**: Only calls abort if firmware capability flag is set - This ensures backward compatibility with older firmware versions - Called unconditionally after suspend completes (success or failure)
3. **New capability flag `MSG_FLAG_CAPS_LPM_ABORT`** (drivers/firmware/ti_sci.h:162): - Added to firmware capability bitmask - Enables runtime detection of firmware support
### PM Framework Integration
My investigation of the PM subsystem confirms the implementation is correct:
- The `->complete()` callback is invoked by `dpm_complete()` after `dpm_resume_end()` (drivers/base/power/main.c:1229) - In `suspend_devices_and_enter()` (kernel/power/suspend.c:532), `dpm_resume_end()` is called **regardless of suspend success or failure** - Even when suspend fails early, execution flows to `Recover_platform` → `Resume_devices` → `dpm_resume_end()` - This confirms the commit message's claim that "the ->complete() hook in TI SCI will be called... regardless of if system suspend succeeds or fails"
### Dependencies and Backporting Constraints
**Dependencies** (both merged in v6.13-rc1): - commit 055b6cfb62f5a: "firmware: ti_sci: Add support for querying the firmware caps" (Oct 2024) - commit ec24643bdd625: "firmware: ti_sci: Add system suspend and resume call" (Oct 2024)
**Backporting scope**: This commit should **only be backported to 6.13+ stable trees**, not older kernels, due to these dependencies.
### Risk Assessment
**Very Low Risk**:
1. **Scope**: Limited to TI SCI firmware driver for AM62 family SoCs only 2. **Backward compatibility**: Firmware capability checking ensures older firmware (< 11.01.09) won't be affected 3. **No architectural changes**: Simply adds a cleanup operation in the PM complete path 4. **Pattern conformance**: Code follows established patterns in the driver 5. **No regressions found**: No subsequent fixes or reverts found in the commit history 6. **Quality indicators**: - Reviewed by Ulf Hansson (PM subsystem maintainer) - No "Fixes:" tag needed (this is a new feature enabling a bugfix) - Already selected by AUTOSEL (commit dd2cd371c3995 by Sasha Levin on Oct 3, 2025)
### Stable Tree Criteria Evaluation
✅ **Fixes important bug**: Yes - broken suspend recovery is a significant usability issue ✅ **Minimal and contained**: Yes - ~60 lines, single subsystem ✅ **No new features**: Borderline - adds new API support, but solely to fix existing bug ✅ **Low regression risk**: Yes - capability checking prevents issues with older firmware ✅ **Clear user benefit**: Yes - restores suspend functionality after failures ✅ **Well-tested**: Yes - tested by multiple parties (Dhruva Gole, Roger Quadros, Kevin Hilman)
### Recommendation
This commit is an **excellent backport candidate for 6.13+ stable trees**. It fixes a real user-facing bug with minimal risk, has proper backward compatibility mechanisms, and follows stable kernel rules. The fact that it was already selected by the AUTOSEL process validates this assessment.
drivers/firmware/ti_sci.c | 57 +++++++++++++++++++++++++++++++++++++-- drivers/firmware/ti_sci.h | 3 +++ 2 files changed, 58 insertions(+), 2 deletions(-)
diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c index ae5fd1936ad32..49fd2ae01055d 100644 --- a/drivers/firmware/ti_sci.c +++ b/drivers/firmware/ti_sci.c @@ -2015,6 +2015,47 @@ static int ti_sci_cmd_set_latency_constraint(const struct ti_sci_handle *handle, return ret; }
+/** + * ti_sci_cmd_lpm_abort() - Abort entry to LPM by clearing selection of LPM to enter + * @dev: Device pointer corresponding to the SCI entity + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_cmd_lpm_abort(struct device *dev) +{ + struct ti_sci_info *info = dev_get_drvdata(dev); + struct ti_sci_msg_hdr *req; + struct ti_sci_msg_hdr *resp; + struct ti_sci_xfer *xfer; + int ret = 0; + + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_LPM_ABORT, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, + sizeof(*req), sizeof(*resp)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(dev, "Message alloc failed(%d)\n", ret); + return ret; + } + req = (struct ti_sci_msg_hdr *)xfer->xfer_buf; + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(dev, "Mbox send fail %d\n", ret); + goto fail; + } + + resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf; + + if (!ti_sci_is_response_ack(resp)) + ret = -ENODEV; + +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + static int ti_sci_cmd_core_reboot(const struct ti_sci_handle *handle) { struct ti_sci_info *info; @@ -3739,11 +3780,22 @@ static int __maybe_unused ti_sci_resume_noirq(struct device *dev) return 0; }
+static void __maybe_unused ti_sci_pm_complete(struct device *dev) +{ + struct ti_sci_info *info = dev_get_drvdata(dev); + + if (info->fw_caps & MSG_FLAG_CAPS_LPM_ABORT) { + if (ti_sci_cmd_lpm_abort(dev)) + dev_err(dev, "LPM clear selection failed.\n"); + } +} + static const struct dev_pm_ops ti_sci_pm_ops = { #ifdef CONFIG_PM_SLEEP .suspend = ti_sci_suspend, .suspend_noirq = ti_sci_suspend_noirq, .resume_noirq = ti_sci_resume_noirq, + .complete = ti_sci_pm_complete, #endif };
@@ -3876,10 +3928,11 @@ static int ti_sci_probe(struct platform_device *pdev) }
ti_sci_msg_cmd_query_fw_caps(&info->handle, &info->fw_caps); - dev_dbg(dev, "Detected firmware capabilities: %s%s%s\n", + dev_dbg(dev, "Detected firmware capabilities: %s%s%s%s\n", info->fw_caps & MSG_FLAG_CAPS_GENERIC ? "Generic" : "", info->fw_caps & MSG_FLAG_CAPS_LPM_PARTIAL_IO ? " Partial-IO" : "", - info->fw_caps & MSG_FLAG_CAPS_LPM_DM_MANAGED ? " DM-Managed" : "" + info->fw_caps & MSG_FLAG_CAPS_LPM_DM_MANAGED ? " DM-Managed" : "", + info->fw_caps & MSG_FLAG_CAPS_LPM_ABORT ? " LPM-Abort" : "" );
ti_sci_setup_ops(info); diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h index 053387d7baa06..701c416b2e78f 100644 --- a/drivers/firmware/ti_sci.h +++ b/drivers/firmware/ti_sci.h @@ -42,6 +42,7 @@ #define TI_SCI_MSG_SET_IO_ISOLATION 0x0307 #define TI_SCI_MSG_LPM_SET_DEVICE_CONSTRAINT 0x0309 #define TI_SCI_MSG_LPM_SET_LATENCY_CONSTRAINT 0x030A +#define TI_SCI_MSG_LPM_ABORT 0x0311
/* Resource Management Requests */ #define TI_SCI_MSG_GET_RESOURCE_RANGE 0x1500 @@ -147,6 +148,7 @@ struct ti_sci_msg_req_reboot { * MSG_FLAG_CAPS_GENERIC: Generic capability (LPM not supported) * MSG_FLAG_CAPS_LPM_PARTIAL_IO: Partial IO in LPM * MSG_FLAG_CAPS_LPM_DM_MANAGED: LPM can be managed by DM + * MSG_FLAG_CAPS_LPM_ABORT: Abort entry to LPM * * Response to a generic message with message type TI_SCI_MSG_QUERY_FW_CAPS * providing currently available SOC/firmware capabilities. SoC that don't @@ -157,6 +159,7 @@ struct ti_sci_msg_resp_query_fw_caps { #define MSG_FLAG_CAPS_GENERIC TI_SCI_MSG_FLAG(0) #define MSG_FLAG_CAPS_LPM_PARTIAL_IO TI_SCI_MSG_FLAG(4) #define MSG_FLAG_CAPS_LPM_DM_MANAGED TI_SCI_MSG_FLAG(5) +#define MSG_FLAG_CAPS_LPM_ABORT TI_SCI_MSG_FLAG(9) #define MSG_MASK_CAPS_LPM GENMASK_ULL(4, 1) u64 fw_caps; } __packed;