lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <2s4ckgz2jhmlad3cm3zzvnzkyl6usgsrbhzosou5eso6pov4dd@zvszprtnipoy>
Date: Tue, 26 Aug 2025 19:25:50 +0300
From: Dmitry Baryshkov <dmitry.baryshkov@....qualcomm.com>
To: quic_utiwari@...cinc.com
Cc: herbert@...dor.apana.org.au, thara.gopinath@...il.com, davem@...emloft.net,
        linux-crypto@...r.kernel.org, linux-arm-msm@...r.kernel.org,
        linux-kernel@...r.kernel.org, quic_neersoni@...cinc.com,
        quic_kuldsing@...cinc.com, quic_gaurkash@...cinc.com
Subject: Re: [PATCH v2] crypto: qce - Add runtime PM and interconnect
 bandwidth scaling support

On Tue, Aug 26, 2025 at 04:39:17PM +0530, quic_utiwari@...cinc.com wrote:
> From: Udit Tiwari <quic_utiwari@...cinc.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_clk_get_optional() and move clock enabling to the resume path.
> - 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@...cinc.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 | 120 ++++++++++++++++++++++++++++++++++----
>  1 file changed, 108 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/crypto/qce/core.c b/drivers/crypto/qce/core.c
> index e95e84486d9a..70b9d9e739be 100644
> --- a/drivers/crypto/qce/core.c
> +++ b/drivers/crypto/qce/core.c
> @@ -12,6 +12,7 @@
>  #include <linux/module.h>
>  #include <linux/mod_devicetable.h>
>  #include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
>  #include <linux/types.h>
>  #include <crypto/algapi.h>
>  #include <crypto/internal/hash.h>
> @@ -91,22 +92,28 @@ static int qce_handle_queue(struct qce_device *qce,
>  	struct crypto_async_request *async_req, *backlog;
>  	int ret = 0, err;
>  
> +	ret = pm_runtime_get_sync(qce->dev);

Use pm_runtime_resume_and_get() instead. Drop corresponding
put_noidle()

> +	if (ret < 0) {
> +		pr_err("error with pm_runtime_get_sync");
> +		pm_runtime_put_noidle(qce->dev);
> +		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);
>  		if (async_req)
>  			qce->req = async_req;
>  	}
> -
>  	if (!async_req)
> -		return ret;
> +		goto qce_suspend;
>  
>  	if (backlog) {
>  		scoped_guard(mutex, &qce->lock)
> @@ -119,6 +126,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;
>  }
>  
> @@ -208,37 +217,43 @@ static int qce_crypto_probe(struct platform_device *pdev)
>  	if (ret < 0)
>  		return ret;
>  
> -	qce->core = devm_clk_get_optional_enabled(qce->dev, "core");
> +	qce->core = devm_clk_get_optional(dev, "core");
>  	if (IS_ERR(qce->core))
>  		return PTR_ERR(qce->core);
>  
> -	qce->iface = devm_clk_get_optional_enabled(qce->dev, "iface");
> +	qce->iface = devm_clk_get_optional(dev, "iface");
>  	if (IS_ERR(qce->iface))
>  		return PTR_ERR(qce->iface);
>  
> -	qce->bus = devm_clk_get_optional_enabled(qce->dev, "bus");
> +	qce->bus = devm_clk_get_optional(dev, "bus");
>  	if (IS_ERR(qce->bus))
>  		return PTR_ERR(qce->bus);
>  
> -	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);
> @@ -246,9 +261,89 @@ 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 qce_runtime_suspend(struct device *dev)
> +{
> +	struct qce_device *qce = dev_get_drvdata(dev);
> +
> +	clk_disable_unprepare(qce->bus);
> +	clk_disable_unprepare(qce->iface);
> +	clk_disable_unprepare(qce->core);

Replace with a single clk_bulk ops or maybe it would be even better to
use pm_clk_add() instead of managing clocks manually.

> +	icc_disable(qce->mem_path);
> +
> +	return 0;
> +}
> +
> +static int 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;
> +
> +	ret = clk_prepare_enable(qce->core);
> +	if (ret)
> +		goto err_icc;
> +
> +	ret = clk_prepare_enable(qce->iface);
> +	if (ret)
> +		goto err_core;
> +
> +	ret = clk_prepare_enable(qce->bus);
> +	if (ret)
> +		goto err_iface;
> +
> +	return 0;
> +
> +err_iface:
> +	clk_disable_unprepare(qce->iface);
> +err_core:
> +	clk_disable_unprepare(qce->core);
> +err_icc:
> +	icc_disable(qce->mem_path);
> +	return ret;
>  }
>  
> +static int qce_suspend(struct device *dev)
> +{
> +	return qce_runtime_suspend(dev);
> +}
> +
> +static int qce_resume(struct device *dev)
> +{
> +	return qce_runtime_resume(dev);
> +}
> +
> +static const struct dev_pm_ops qce_crypto_pm_ops = {
> +	.runtime_suspend = qce_runtime_suspend,
> +	.runtime_resume  = qce_runtime_resume,

Please use macros from <linux/pm.h>

> +	.suspend         = qce_suspend,
> +	.resume          = qce_resume,

Any reasons for not using pm_runtime_force_suspend() /
pm_runtime_force_resume() ?

> +};

This whole struct can be defined using DEFINE_RUNTIME_DEV_PM_OPS().

> +
>  static const struct of_device_id qce_crypto_of_match[] = {
>  	{ .compatible = "qcom,crypto-v5.1", },
>  	{ .compatible = "qcom,crypto-v5.4", },
> @@ -262,6 +357,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
> 

-- 
With best wishes
Dmitry

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ