Skip to content

Commit d71e8a7

Browse files
Udit Tiwariarakshit011
authored andcommitted
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 <quic_utiwari@quicinc.com> Signed-off-by: Abhinaba Rakshit <abhinaba.rakshit@oss.qualcomm.com>
1 parent f7beaa7 commit d71e8a7

File tree

1 file changed

+87
-18
lines changed

1 file changed

+87
-18
lines changed

drivers/crypto/qce/core.c

Lines changed: 87 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
#include <linux/module.h>
1313
#include <linux/mod_devicetable.h>
1414
#include <linux/platform_device.h>
15+
#include <linux/pm.h>
16+
#include <linux/pm_runtime.h>
17+
#include <linux/pm_clock.h>
1518
#include <linux/types.h>
1619
#include <crypto/internal/hash.h>
1720

@@ -90,13 +93,17 @@ static int qce_handle_queue(struct qce_device *qce,
9093
struct crypto_async_request *async_req, *backlog;
9194
int ret = 0, err;
9295

96+
ret = pm_runtime_resume_and_get(qce->dev);
97+
if (ret < 0)
98+
return ret;
99+
93100
scoped_guard(mutex, &qce->lock) {
94101
if (req)
95102
ret = crypto_enqueue_request(&qce->queue, req);
96103

97104
/* busy, do not dequeue request */
98105
if (qce->req)
99-
return ret;
106+
goto qce_suspend;
100107

101108
backlog = crypto_get_backlog(&qce->queue);
102109
async_req = crypto_dequeue_request(&qce->queue);
@@ -105,7 +112,7 @@ static int qce_handle_queue(struct qce_device *qce,
105112
}
106113

107114
if (!async_req)
108-
return ret;
115+
goto qce_suspend;
109116

110117
if (backlog) {
111118
scoped_guard(mutex, &qce->lock)
@@ -118,6 +125,8 @@ static int qce_handle_queue(struct qce_device *qce,
118125
schedule_work(&qce->done_work);
119126
}
120127

128+
qce_suspend:
129+
pm_runtime_put_autosuspend(qce->dev);
121130
return ret;
122131
}
123132

@@ -216,37 +225,47 @@ static int qce_crypto_probe(struct platform_device *pdev)
216225
if (ret < 0)
217226
return ret;
218227

219-
qce->core = devm_clk_get_optional_enabled(qce->dev, "core");
220-
if (IS_ERR(qce->core))
221-
return PTR_ERR(qce->core);
228+
/* PM clock helpers: register device clocks */
229+
ret = devm_pm_clk_create(dev);
230+
if (ret)
231+
return ret;
222232

223-
qce->iface = devm_clk_get_optional_enabled(qce->dev, "iface");
224-
if (IS_ERR(qce->iface))
225-
return PTR_ERR(qce->iface);
233+
ret = pm_clk_add(dev, "core");
234+
if (ret)
235+
return ret;
226236

227-
qce->bus = devm_clk_get_optional_enabled(qce->dev, "bus");
228-
if (IS_ERR(qce->bus))
229-
return PTR_ERR(qce->bus);
237+
ret = pm_clk_add(dev, "iface");
238+
if (ret)
239+
return ret;
230240

231-
qce->mem_path = devm_of_icc_get(qce->dev, "memory");
241+
ret = pm_clk_add(dev, "bus");
242+
if (ret)
243+
return ret;
244+
245+
qce->mem_path = devm_of_icc_get(dev, "memory");
232246
if (IS_ERR(qce->mem_path))
233247
return PTR_ERR(qce->mem_path);
234248

235-
ret = icc_set_bw(qce->mem_path, QCE_DEFAULT_MEM_BANDWIDTH, QCE_DEFAULT_MEM_BANDWIDTH);
249+
/* Enable runtime PM after clocks and ICC are acquired */
250+
ret = devm_pm_runtime_enable(dev);
236251
if (ret)
237252
return ret;
238253

239-
ret = devm_qce_dma_request(qce);
254+
ret = pm_runtime_resume_and_get(dev);
240255
if (ret)
241256
return ret;
242257

258+
ret = devm_qce_dma_request(qce);
259+
if (ret)
260+
goto err_pm;
261+
243262
ret = qce_check_version(qce);
244263
if (ret)
245-
return ret;
264+
goto err_pm;
246265

247266
ret = devm_mutex_init(qce->dev, &qce->lock);
248267
if (ret)
249-
return ret;
268+
goto err_pm;
250269

251270
INIT_WORK(&qce->done_work, qce_req_done_work);
252271
crypto_init_queue(&qce->queue, QCE_QUEUE_LENGTH);
@@ -256,19 +275,68 @@ static int qce_crypto_probe(struct platform_device *pdev)
256275

257276
ret = devm_qce_register_algs(qce);
258277
if (ret)
259-
return ret;
278+
goto err_pm;
260279

261280
qce->dma_size = resource_size(res);
262281
qce->base_dma = dma_map_resource(dev, res->start, qce->dma_size,
263282
DMA_BIDIRECTIONAL, 0);
264283
qce->base_phys = res->start;
265284
ret = dma_mapping_error(dev, qce->base_dma);
285+
if (ret)
286+
goto err_pm;
287+
288+
ret = devm_add_action_or_reset(qce->dev, qce_crypto_unmap_dma, qce);
289+
if (ret)
290+
goto err_pm;
291+
292+
/* Configure autosuspend after successful init */
293+
pm_runtime_set_autosuspend_delay(dev, 100);
294+
pm_runtime_use_autosuspend(dev);
295+
pm_runtime_mark_last_busy(dev);
296+
pm_runtime_put_autosuspend(dev);
297+
298+
return 0;
299+
300+
err_pm:
301+
pm_runtime_put(dev);
302+
303+
return ret;
304+
}
305+
306+
static int __maybe_unused qce_runtime_suspend(struct device *dev)
307+
{
308+
struct qce_device *qce = dev_get_drvdata(dev);
309+
310+
icc_disable(qce->mem_path);
311+
312+
return 0;
313+
}
314+
315+
static int __maybe_unused qce_runtime_resume(struct device *dev)
316+
{
317+
struct qce_device *qce = dev_get_drvdata(dev);
318+
int ret = 0;
319+
320+
ret = icc_enable(qce->mem_path);
266321
if (ret)
267322
return ret;
268323

269-
return devm_add_action_or_reset(qce->dev, qce_crypto_unmap_dma, qce);
324+
ret = icc_set_bw(qce->mem_path, QCE_DEFAULT_MEM_BANDWIDTH, QCE_DEFAULT_MEM_BANDWIDTH);
325+
if (ret)
326+
goto err_icc;
327+
328+
return 0;
329+
330+
err_icc:
331+
icc_disable(qce->mem_path);
332+
return ret;
270333
}
271334

335+
static const struct dev_pm_ops qce_crypto_pm_ops = {
336+
SET_RUNTIME_PM_OPS(qce_runtime_suspend, qce_runtime_resume, NULL)
337+
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
338+
};
339+
272340
static const struct of_device_id qce_crypto_of_match[] = {
273341
{ .compatible = "qcom,crypto-v5.1", },
274342
{ .compatible = "qcom,crypto-v5.4", },
@@ -282,6 +350,7 @@ static struct platform_driver qce_crypto_driver = {
282350
.driver = {
283351
.name = KBUILD_MODNAME,
284352
.of_match_table = qce_crypto_of_match,
353+
.pm = &qce_crypto_pm_ops,
285354
},
286355
};
287356
module_platform_driver(qce_crypto_driver);

0 commit comments

Comments
 (0)