* [PATCH v6] crypto: qce - Add runtime PM and interconnect bandwidth scaling support
@ 2026-02-10 6:14 quic_utiwari
2026-02-17 10:42 ` Konrad Dybcio
0 siblings, 1 reply; 4+ messages in thread
From: quic_utiwari @ 2026-02-10 6:14 UTC (permalink / raw)
To: konrad.dybcio, herbert, thara.gopinath, davem
Cc: linux-crypto, linux-arm-msm, linux-kernel, quic_neersoni,
quic_kuldsing
From: Udit Tiwari <quic_utiwari@quicinc.com>
The Qualcomm Crypto Engine (QCE) driver currently lacks support for
runtime power management (PM) and interconnect bandwidth control.
As a result, the hardware remains fully powered and clocks stay
enabled even when the device is idle. Additionally, static
interconnect bandwidth votes are held indefinitely, preventing the
system from reclaiming unused bandwidth.
Address this by enabling runtime PM and dynamic interconnect
bandwidth scaling to allow the system to suspend the device when idle
and scale interconnect usage based on actual demand. Improve overall
system efficiency by reducing power usage and optimizing interconnect
resource allocation.
Make the following changes as part of this integration:
- Add support for pm_runtime APIs to manage device power state
transitions.
- Implement runtime_suspend() and runtime_resume() callbacks to gate
clocks and vote for interconnect bandwidth only when needed.
- Replace devm_clk_get_optional_enabled() with devm_pm_clk_create() +
pm_clk_add() and let the PM core manage device clocks during runtime
PM and system sleep.
- Register dev_pm_ops with the platform driver to hook into the PM
framework.
Tested:
- Verify that ICC votes drop to zero after probe and upon request
completion.
- Confirm that runtime PM usage count increments during active
requests and decrements afterward.
- Observe that the device correctly enters the suspended state when
idle.
Signed-off-by: Udit Tiwari <quic_utiwari@quicinc.com>
---
Changes in v6:
- Adopt ACQUIRE(pm_runtime_active_try, ...) for scoped runtime PM management
in qce_handle_queue(). This removes the need for manual put calls and
goto labels in the error paths, as suggested by Konrad.
Changes in v5:
- Drop Reported-by and Closes tags for kernel test robot W=1 warnings, as
the issue was fixed within the same patch series.
- Fix a minor comment indentation/style issue.
- Link to v5: https://lore.kernel.org/lkml/20251120062443.2016084-1-quic_utiwari@quicinc.com/
Changes in v4:
- Annotate runtime PM callbacks with __maybe_unused to silence W=1 warnings.
- Add Reported-by and Closes tags for kernel test robot warning.
- Link to v4: https://lore.kernel.org/lkml/20251117062737.3946074-1-quic_utiwari@quicinc.com/
Changes in v3:
- Switch from manual clock management to PM clock helpers
(devm_pm_clk_create() + pm_clk_add()); no direct clk_* enable/disable
in runtime callbacks.
- Replace pm_runtime_get_sync() with pm_runtime_resume_and_get(); remove
pm_runtime_put_noidle() on error.
- Define PM ops using helper macros and reuse runtime callbacks for system
sleep via pm_runtime_force_suspend()/pm_runtime_force_resume().
- Link to v2: https://lore.kernel.org/lkml/20250826110917.3383061-1-quic_utiwari@quicinc.com/
Changes in v2:
- Extend suspend/resume support to include runtime PM and ICC scaling.
- Register dev_pm_ops and implement runtime_suspend/resume callbacks.
- Link to v1: https://lore.kernel.org/lkml/20250606105808.2119280-1-quic_utiwari@quicinc.com/
---
drivers/crypto/qce/core.c | 98 +++++++++++++++++++++++++++++++++------
1 file changed, 83 insertions(+), 15 deletions(-)
diff --git a/drivers/crypto/qce/core.c b/drivers/crypto/qce/core.c
index b966f3365b7d..2e1e4db93682 100644
--- a/drivers/crypto/qce/core.c
+++ b/drivers/crypto/qce/core.c
@@ -12,6 +12,9 @@
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_clock.h>
#include <linux/types.h>
#include <crypto/algapi.h>
#include <crypto/internal/hash.h>
@@ -90,6 +93,11 @@ static int qce_handle_queue(struct qce_device *qce,
struct crypto_async_request *async_req, *backlog;
int ret = 0, err;
+ ACQUIRE(pm_runtime_active_try, pm)(qce->dev);
+ ret = ACQUIRE_ERR(pm_runtime_active_auto_try, &pm);
+ if (ret)
+ return ret;
+
scoped_guard(mutex, &qce->lock) {
if (req)
ret = crypto_enqueue_request(&qce->queue, req);
@@ -207,37 +215,47 @@ static int qce_crypto_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
- qce->core = devm_clk_get_optional_enabled(qce->dev, "core");
- if (IS_ERR(qce->core))
- return PTR_ERR(qce->core);
+ /* PM clock helpers: register device clocks */
+ ret = devm_pm_clk_create(dev);
+ if (ret)
+ return ret;
+
+ ret = pm_clk_add(dev, "core");
+ if (ret)
+ return ret;
- qce->iface = devm_clk_get_optional_enabled(qce->dev, "iface");
- if (IS_ERR(qce->iface))
- return PTR_ERR(qce->iface);
+ ret = pm_clk_add(dev, "iface");
+ if (ret)
+ return ret;
- qce->bus = devm_clk_get_optional_enabled(qce->dev, "bus");
- if (IS_ERR(qce->bus))
- return PTR_ERR(qce->bus);
+ ret = pm_clk_add(dev, "bus");
+ if (ret)
+ return ret;
- qce->mem_path = devm_of_icc_get(qce->dev, "memory");
+ qce->mem_path = devm_of_icc_get(dev, "memory");
if (IS_ERR(qce->mem_path))
return PTR_ERR(qce->mem_path);
- ret = icc_set_bw(qce->mem_path, QCE_DEFAULT_MEM_BANDWIDTH, QCE_DEFAULT_MEM_BANDWIDTH);
+ /* Enable runtime PM after clocks and ICC are acquired */
+ ret = devm_pm_runtime_enable(dev);
if (ret)
return ret;
- ret = devm_qce_dma_request(qce->dev, &qce->dma);
+ ret = pm_runtime_resume_and_get(dev);
if (ret)
return ret;
+ ret = devm_qce_dma_request(qce->dev, &qce->dma);
+ if (ret)
+ goto err_pm;
+
ret = qce_check_version(qce);
if (ret)
- return ret;
+ goto err_pm;
ret = devm_mutex_init(qce->dev, &qce->lock);
if (ret)
- return ret;
+ goto err_pm;
INIT_WORK(&qce->done_work, qce_req_done_work);
crypto_init_queue(&qce->queue, QCE_QUEUE_LENGTH);
@@ -245,9 +263,58 @@ static int qce_crypto_probe(struct platform_device *pdev)
qce->async_req_enqueue = qce_async_request_enqueue;
qce->async_req_done = qce_async_request_done;
- return devm_qce_register_algs(qce);
+ ret = devm_qce_register_algs(qce);
+ if (ret)
+ goto err_pm;
+
+ /* Configure autosuspend after successful init */
+ pm_runtime_set_autosuspend_delay(dev, 100);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
+ return 0;
+
+err_pm:
+ pm_runtime_put(dev);
+
+ return ret;
+}
+
+static int __maybe_unused qce_runtime_suspend(struct device *dev)
+{
+ struct qce_device *qce = dev_get_drvdata(dev);
+
+ icc_disable(qce->mem_path);
+
+ return 0;
}
+static int __maybe_unused qce_runtime_resume(struct device *dev)
+{
+ struct qce_device *qce = dev_get_drvdata(dev);
+ int ret = 0;
+
+ ret = icc_enable(qce->mem_path);
+ if (ret)
+ return ret;
+
+ ret = icc_set_bw(qce->mem_path, QCE_DEFAULT_MEM_BANDWIDTH, QCE_DEFAULT_MEM_BANDWIDTH);
+ if (ret)
+ goto err_icc;
+
+ return 0;
+
+err_icc:
+ icc_disable(qce->mem_path);
+ return ret;
+}
+
+static const struct dev_pm_ops qce_crypto_pm_ops = {
+ SET_RUNTIME_PM_OPS(qce_runtime_suspend, qce_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+};
+
static const struct of_device_id qce_crypto_of_match[] = {
{ .compatible = "qcom,crypto-v5.1", },
{ .compatible = "qcom,crypto-v5.4", },
@@ -261,6 +328,7 @@ static struct platform_driver qce_crypto_driver = {
.driver = {
.name = KBUILD_MODNAME,
.of_match_table = qce_crypto_of_match,
+ .pm = &qce_crypto_pm_ops,
},
};
module_platform_driver(qce_crypto_driver);
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH v6] crypto: qce - Add runtime PM and interconnect bandwidth scaling support
2026-02-10 6:14 [PATCH v6] crypto: qce - Add runtime PM and interconnect bandwidth scaling support quic_utiwari
@ 2026-02-17 10:42 ` Konrad Dybcio
2026-02-18 6:02 ` Udit Tiwari
0 siblings, 1 reply; 4+ messages in thread
From: Konrad Dybcio @ 2026-02-17 10:42 UTC (permalink / raw)
To: quic_utiwari, herbert, thara.gopinath, davem
Cc: linux-crypto, linux-arm-msm, linux-kernel, quic_neersoni,
quic_kuldsing
On 2/10/26 7:14 AM, quic_utiwari@quicinc.com wrote:
> From: Udit Tiwari <quic_utiwari@quicinc.com>
>
> The Qualcomm Crypto Engine (QCE) driver currently lacks support for
> runtime power management (PM) and interconnect bandwidth control.
> As a result, the hardware remains fully powered and clocks stay
> enabled even when the device is idle. Additionally, static
> interconnect bandwidth votes are held indefinitely, preventing the
> system from reclaiming unused bandwidth.
>
> Address this by enabling runtime PM and dynamic interconnect
> bandwidth scaling to allow the system to suspend the device when idle
> and scale interconnect usage based on actual demand. Improve overall
> system efficiency by reducing power usage and optimizing interconnect
> resource allocation.
>
[...]
> + ret = pm_runtime_resume_and_get(dev);
> if (ret)
> return ret;
I expected this to use the new helper too, removing the need for gotos
altogether (unless this path needs some other handling which doesn't
immediately jump out to me)
[...]
> +static int __maybe_unused qce_runtime_resume(struct device *dev)
> +{
> + struct qce_device *qce = dev_get_drvdata(dev);
> + int ret = 0;
> +
> + ret = icc_enable(qce->mem_path);
> + if (ret)
> + return ret;
> +
> + ret = icc_set_bw(qce->mem_path, QCE_DEFAULT_MEM_BANDWIDTH, QCE_DEFAULT_MEM_BANDWIDTH);
> + if (ret)
> + goto err_icc;
Just one of these is good - icc_enable() simply calls icc_set_bw() with
the last known rate. Since we're not setting the rate any earlier,
just keeping the set_bw() alone seems like the way to go
Konrad
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH v6] crypto: qce - Add runtime PM and interconnect bandwidth scaling support
2026-02-17 10:42 ` Konrad Dybcio
@ 2026-02-18 6:02 ` Udit Tiwari
2026-02-18 11:12 ` Konrad Dybcio
0 siblings, 1 reply; 4+ messages in thread
From: Udit Tiwari @ 2026-02-18 6:02 UTC (permalink / raw)
To: Konrad Dybcio, herbert, thara.gopinath, davem
Cc: linux-crypto, linux-arm-msm, linux-kernel, quic_neersoni,
quic_kuldsing
Hi Konrad,
Thanks for pointing this out.
I agree with your points regarding the usage of the ACQUIRE guard in
probe to simplify the error paths, as well as the redundancy of
icc_enable in the resume path. I will address both in the next version.
While preparing the fix, I performed a self-review and noticed a
potential issue. Since I am providing my own custom functions for
runtime suspend/resume (to handle the ICC path), the standard clock
helpers are no longer called automatically by the PM framework.
I believe I need to manually call pm_clk_resume(dev) and
pm_clk_suspend(dev) inside my custom functions to ensure the clocks are
actually gated and ungated.
Does this look correct to you? If you agree, I will include this fix in v7.
Best Regards,
Udit Tiwari
On 2/17/2026 4:12 PM, Konrad Dybcio wrote:
> On 2/10/26 7:14 AM, quic_utiwari@quicinc.com wrote:
>> From: Udit Tiwari <quic_utiwari@quicinc.com>
>>
>> The Qualcomm Crypto Engine (QCE) driver currently lacks support for
>> runtime power management (PM) and interconnect bandwidth control.
>> As a result, the hardware remains fully powered and clocks stay
>> enabled even when the device is idle. Additionally, static
>> interconnect bandwidth votes are held indefinitely, preventing the
>> system from reclaiming unused bandwidth.
>>
>> Address this by enabling runtime PM and dynamic interconnect
>> bandwidth scaling to allow the system to suspend the device when idle
>> and scale interconnect usage based on actual demand. Improve overall
>> system efficiency by reducing power usage and optimizing interconnect
>> resource allocation.
>>
>
> [...]
>
>> + ret = pm_runtime_resume_and_get(dev);
>> if (ret)
>> return ret;
>
> I expected this to use the new helper too, removing the need for gotos
> altogether (unless this path needs some other handling which doesn't
> immediately jump out to me)
>
> [...]
>
>> +static int __maybe_unused qce_runtime_resume(struct device *dev)
>> +{
>> + struct qce_device *qce = dev_get_drvdata(dev);
>> + int ret = 0;
>> +
>> + ret = icc_enable(qce->mem_path);
>> + if (ret)
>> + return ret;
>> +
>> + ret = icc_set_bw(qce->mem_path, QCE_DEFAULT_MEM_BANDWIDTH, QCE_DEFAULT_MEM_BANDWIDTH);
>> + if (ret)
>> + goto err_icc;
>
> Just one of these is good - icc_enable() simply calls icc_set_bw() with
> the last known rate. Since we're not setting the rate any earlier,
> just keeping the set_bw() alone seems like the way to go
>
> Konrad
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH v6] crypto: qce - Add runtime PM and interconnect bandwidth scaling support
2026-02-18 6:02 ` Udit Tiwari
@ 2026-02-18 11:12 ` Konrad Dybcio
0 siblings, 0 replies; 4+ messages in thread
From: Konrad Dybcio @ 2026-02-18 11:12 UTC (permalink / raw)
To: Udit Tiwari, herbert, thara.gopinath, davem
Cc: linux-crypto, linux-arm-msm, linux-kernel, quic_neersoni,
quic_kuldsing
On 2/18/26 7:02 AM, Udit Tiwari wrote:
> Hi Konrad,
>
> Thanks for pointing this out.
>
> I agree with your points regarding the usage of the ACQUIRE guard in probe to simplify the error paths, as well as the redundancy of icc_enable in the resume path. I will address both in the next version.
>
> While preparing the fix, I performed a self-review and noticed a potential issue. Since I am providing my own custom functions for runtime suspend/resume (to handle the ICC path), the standard clock helpers are no longer called automatically by the PM framework.
>
> I believe I need to manually call pm_clk_resume(dev) and pm_clk_suspend(dev) inside my custom functions to ensure the clocks are actually gated and ungated.
>
> Does this look correct to you? If you agree, I will include this fix in v7.
I tried to find an answer, but it seems like one of these situations where
it's easier to add some debug prints than to analyze the code ;)
Konrad
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-02-18 11:12 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-10 6:14 [PATCH v6] crypto: qce - Add runtime PM and interconnect bandwidth scaling support quic_utiwari
2026-02-17 10:42 ` Konrad Dybcio
2026-02-18 6:02 ` Udit Tiwari
2026-02-18 11:12 ` Konrad Dybcio
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox