mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 12:13:51 -04:00
crypto: cesa - manage SRAM teardown with devm
mv_cesa_put_sram() is called explicitly from both the probe error path and mv_cesa_remove(). The non-pool ioremap is already devm-managed, but dma_map_resource() and gen_pool_dma_alloc() have no devm helpers, so the mapping is released by hand. This is error-prone: the error path iterates over every engine and can dma_unmap_resource() an uninitialized/zero address for engines that were never set up. Convert the teardown into a devm_add_action_or_reset() callback registered only after a mapping is successfully established. The callback fires automatically on probe failure (devres rollback) and on device detach, after mv_cesa_remove() has already stopped the engine and freed the IRQ, so the unmap still happens in a safe order. This deletes the explicit mv_cesa_put_sram() calls and the uninitialized-engine bug at once. Add a struct mv_cesa_dev back-pointer to struct mv_cesa_engine so the callback can reach cesa->dev and cesa->sram_size from the engine alone. Assisted-by: opencode:hy3-free Signed-off-by: Rosen Penev <rosenp@gmail.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
@@ -366,6 +366,8 @@ static int mv_cesa_dev_dma_init(struct mv_cesa_dev *cesa)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mv_cesa_release_sram(void *data);
|
||||
|
||||
static int mv_cesa_get_sram(struct platform_device *pdev, int idx)
|
||||
{
|
||||
struct mv_cesa_dev *cesa = platform_get_drvdata(pdev);
|
||||
@@ -378,11 +380,13 @@ static int mv_cesa_get_sram(struct platform_device *pdev, int idx)
|
||||
engine->sram_pool = gen_pool_dma_alloc(engine->pool,
|
||||
cesa->sram_size,
|
||||
&engine->sram_dma);
|
||||
if (engine->sram_pool)
|
||||
return 0;
|
||||
if (!engine->sram_pool) {
|
||||
engine->pool = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
engine->pool = NULL;
|
||||
return -ENOMEM;
|
||||
return devm_add_action_or_reset(cesa->dev, mv_cesa_release_sram,
|
||||
engine);
|
||||
}
|
||||
|
||||
engine->sram = devm_platform_get_and_ioremap_resource(pdev, idx, &res);
|
||||
@@ -395,13 +399,13 @@ static int mv_cesa_get_sram(struct platform_device *pdev, int idx)
|
||||
if (dma_mapping_error(cesa->dev, engine->sram_dma))
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
return devm_add_action_or_reset(cesa->dev, mv_cesa_release_sram, engine);
|
||||
}
|
||||
|
||||
static void mv_cesa_put_sram(struct platform_device *pdev, int idx)
|
||||
static void mv_cesa_release_sram(void *data)
|
||||
{
|
||||
struct mv_cesa_dev *cesa = platform_get_drvdata(pdev);
|
||||
struct mv_cesa_engine *engine = &cesa->engines[idx];
|
||||
struct mv_cesa_engine *engine = data;
|
||||
struct mv_cesa_dev *cesa = engine->cesa;
|
||||
|
||||
if (engine->pool)
|
||||
gen_pool_free(engine->pool, (unsigned long)engine->sram_pool,
|
||||
@@ -465,17 +469,16 @@ static int mv_cesa_probe(struct platform_device *pdev)
|
||||
char res_name[16];
|
||||
|
||||
engine->id = i;
|
||||
engine->cesa = cesa;
|
||||
spin_lock_init(&engine->lock);
|
||||
|
||||
ret = mv_cesa_get_sram(pdev, i);
|
||||
if (ret)
|
||||
goto err_cleanup;
|
||||
return ret;
|
||||
|
||||
irq = platform_get_irq(pdev, i);
|
||||
if (irq < 0) {
|
||||
ret = irq;
|
||||
goto err_cleanup;
|
||||
}
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
engine->irq = irq;
|
||||
|
||||
@@ -487,18 +490,14 @@ static int mv_cesa_probe(struct platform_device *pdev)
|
||||
engine->clk = devm_clk_get_optional_enabled(dev, res_name);
|
||||
if (IS_ERR(engine->clk)) {
|
||||
engine->clk = devm_clk_get_optional_enabled(dev, NULL);
|
||||
if (IS_ERR(engine->clk)) {
|
||||
ret = PTR_ERR(engine->clk);
|
||||
goto err_cleanup;
|
||||
}
|
||||
if (IS_ERR(engine->clk))
|
||||
return PTR_ERR(engine->clk);
|
||||
}
|
||||
|
||||
snprintf(res_name, sizeof(res_name), "cesaz%u", i);
|
||||
engine->zclk = devm_clk_get_optional_enabled(dev, res_name);
|
||||
if (IS_ERR(engine->zclk)) {
|
||||
ret = PTR_ERR(engine->zclk);
|
||||
goto err_cleanup;
|
||||
}
|
||||
if (IS_ERR(engine->zclk))
|
||||
return PTR_ERR(engine->zclk);
|
||||
|
||||
engine->regs = cesa->regs + CESA_ENGINE_OFF(i);
|
||||
|
||||
@@ -516,7 +515,7 @@ static int mv_cesa_probe(struct platform_device *pdev)
|
||||
dev_name(&pdev->dev),
|
||||
engine);
|
||||
if (ret)
|
||||
goto err_cleanup;
|
||||
return ret;
|
||||
|
||||
/* Set affinity */
|
||||
cpu = cpumask_local_spread(engine->id, NUMA_NO_NODE);
|
||||
@@ -532,29 +531,19 @@ static int mv_cesa_probe(struct platform_device *pdev)
|
||||
ret = mv_cesa_add_algs(cesa);
|
||||
if (ret) {
|
||||
cesa_dev = NULL;
|
||||
goto err_cleanup;
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_info(dev, "CESA device successfully registered\n");
|
||||
|
||||
return 0;
|
||||
|
||||
err_cleanup:
|
||||
for (i = 0; i < caps->nengines; i++)
|
||||
mv_cesa_put_sram(pdev, i);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mv_cesa_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mv_cesa_dev *cesa = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
|
||||
mv_cesa_remove_algs(cesa);
|
||||
|
||||
for (i = 0; i < cesa->caps->nengines; i++)
|
||||
mv_cesa_put_sram(pdev, i);
|
||||
}
|
||||
|
||||
static const struct platform_device_id mv_cesa_plat_id_table[] = {
|
||||
|
||||
@@ -415,6 +415,7 @@ struct mv_cesa_dev_dma {
|
||||
* @zclk: engine zclk
|
||||
* @max_req_len: maximum chunk length (useful to create the TDMA chain)
|
||||
* @int_mask: interrupt mask cache
|
||||
* @cesa: back-pointer to the parent CESA device
|
||||
* @pool: memory pool pointing to the memory region reserved in
|
||||
* SRAM
|
||||
* @queue: fifo of the pending crypto requests
|
||||
@@ -441,6 +442,7 @@ struct mv_cesa_engine {
|
||||
struct clk *zclk;
|
||||
size_t max_req_len;
|
||||
u32 int_mask;
|
||||
struct mv_cesa_dev *cesa;
|
||||
struct gen_pool *pool;
|
||||
struct crypto_queue queue;
|
||||
atomic_t load;
|
||||
|
||||
Reference in New Issue
Block a user