From d71e8a7f01cdb348369ca2b9fb985245474a8ebd Mon Sep 17 00:00:00 2001 From: Udit Tiwari Date: Thu, 12 Feb 2026 16:37:14 +0530 Subject: [PATCH] FROMLIST: crypto: qce - Add runtime PM and interconnect bandwidth scaling support 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 Signed-off-by: Abhinaba Rakshit --- drivers/crypto/qce/core.c | 105 +++++++++++++++++++++++++++++++------- 1 file changed, 87 insertions(+), 18 deletions(-) diff --git a/drivers/crypto/qce/core.c b/drivers/crypto/qce/core.c index e486d366c0d63..ae5beed600d32 100644 --- a/drivers/crypto/qce/core.c +++ b/drivers/crypto/qce/core.c @@ -12,6 +12,9 @@ #include #include #include +#include +#include +#include #include #include @@ -90,13 +93,17 @@ static int qce_handle_queue(struct qce_device *qce, struct crypto_async_request *async_req, *backlog; int ret = 0, err; + ret = pm_runtime_resume_and_get(qce->dev); + if (ret < 0) + return ret; + scoped_guard(mutex, &qce->lock) { if (req) ret = crypto_enqueue_request(&qce->queue, req); /* busy, do not dequeue request */ if (qce->req) - return ret; + goto qce_suspend; backlog = crypto_get_backlog(&qce->queue); async_req = crypto_dequeue_request(&qce->queue); @@ -105,7 +112,7 @@ static int qce_handle_queue(struct qce_device *qce, } if (!async_req) - return ret; + goto qce_suspend; if (backlog) { scoped_guard(mutex, &qce->lock) @@ -118,6 +125,8 @@ static int qce_handle_queue(struct qce_device *qce, schedule_work(&qce->done_work); } +qce_suspend: + pm_runtime_put_autosuspend(qce->dev); return ret; } @@ -216,37 +225,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; - 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, "core"); + 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, "iface"); + if (ret) + return ret; - qce->mem_path = devm_of_icc_get(qce->dev, "memory"); + ret = pm_clk_add(dev, "bus"); + if (ret) + return ret; + + 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); + ret = pm_runtime_resume_and_get(dev); if (ret) return ret; + ret = devm_qce_dma_request(qce); + 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); @@ -256,19 +275,68 @@ static int qce_crypto_probe(struct platform_device *pdev) ret = devm_qce_register_algs(qce); if (ret) - return ret; + goto err_pm; qce->dma_size = resource_size(res); qce->base_dma = dma_map_resource(dev, res->start, qce->dma_size, DMA_BIDIRECTIONAL, 0); qce->base_phys = res->start; ret = dma_mapping_error(dev, qce->base_dma); + if (ret) + goto err_pm; + + ret = devm_add_action_or_reset(qce->dev, qce_crypto_unmap_dma, 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; - return devm_add_action_or_reset(qce->dev, qce_crypto_unmap_dma, qce); + 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", }, @@ -282,6 +350,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);