mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
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. Signed-off-by: Udit Tiwari <udit.tiwari@oss.qualcomm.com> Tested-by: Pankaj Patil <pankaj.patil@oss.qualcomm.com>
This commit is contained in:
committed by
Konrad Dybcio
parent
d43969b7f6
commit
51231839d5
@@ -11,6 +11,8 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/types.h>
|
||||
#include <crypto/algapi.h>
|
||||
#include <crypto/internal/hash.h>
|
||||
@@ -87,7 +89,12 @@ static int qce_handle_queue(struct qce_device *qce,
|
||||
struct crypto_async_request *req)
|
||||
{
|
||||
struct crypto_async_request *async_req, *backlog;
|
||||
int ret = 0, err;
|
||||
int ret, err;
|
||||
|
||||
PM_RUNTIME_ACQUIRE_AUTOSUSPEND(qce->dev, pm);
|
||||
ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
scoped_guard(mutex, &qce->lock) {
|
||||
if (req)
|
||||
@@ -206,23 +213,33 @@ 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(qce->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(qce->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(qce->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 path are acquired so that
|
||||
* the resume callback can enable clocks and apply the ICC bandwidth
|
||||
* vote before any hardware access takes place.
|
||||
*/
|
||||
ret = devm_pm_runtime_enable(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
|
||||
ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -244,9 +261,76 @@ 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)
|
||||
return ret;
|
||||
|
||||
/* Configure autosuspend after successful init */
|
||||
pm_runtime_set_autosuspend_delay(dev, 100);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qce_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct qce_device *qce = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
clk_disable_unprepare(qce->core);
|
||||
clk_disable_unprepare(qce->iface);
|
||||
clk_disable_unprepare(qce->bus);
|
||||
|
||||
ret = icc_set_bw(qce->mem_path, 0, 0);
|
||||
if (ret) {
|
||||
clk_prepare_enable(qce->bus);
|
||||
clk_prepare_enable(qce->iface);
|
||||
clk_prepare_enable(qce->core);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qce_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct qce_device *qce = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = icc_set_bw(qce->mem_path, QCE_DEFAULT_MEM_BANDWIDTH,
|
||||
QCE_DEFAULT_MEM_BANDWIDTH);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(qce->core);
|
||||
if (ret)
|
||||
goto err_core;
|
||||
|
||||
ret = clk_prepare_enable(qce->iface);
|
||||
if (ret)
|
||||
goto err_iface;
|
||||
|
||||
ret = clk_prepare_enable(qce->bus);
|
||||
if (ret)
|
||||
goto err_bus;
|
||||
|
||||
return 0;
|
||||
|
||||
err_bus:
|
||||
clk_disable_unprepare(qce->iface);
|
||||
err_iface:
|
||||
clk_disable_unprepare(qce->core);
|
||||
err_core:
|
||||
icc_set_bw(qce->mem_path, 0, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops qce_crypto_pm_ops = {
|
||||
RUNTIME_PM_OPS(qce_runtime_suspend, qce_runtime_resume, NULL)
|
||||
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", },
|
||||
@@ -260,6 +344,7 @@ static struct platform_driver qce_crypto_driver = {
|
||||
.driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.of_match_table = qce_crypto_of_match,
|
||||
.pm = pm_ptr(&qce_crypto_pm_ops),
|
||||
},
|
||||
};
|
||||
module_platform_driver(qce_crypto_driver);
|
||||
|
||||
Reference in New Issue
Block a user