// SPDX-License-Identifier: GPL-2.0 /* * sun8i-ss-core.c - hardware cryptographic offloader for * Allwinner A80/A83T SoC * * Copyright (C) 2015-2019 Corentin Labbe <clabbe.montjoie@gmail.com> * * Core file which registers crypto algorithms supported by the SecuritySystem * * You could find a link for the datasheet in Documentation/arch/arm/sunxi.rst
*/
/* * sun8i_ss_get_engine_number() get the next channel slot * This is a simple round-robin way of getting the next channel
*/ int sun8i_ss_get_engine_number(struct sun8i_ss_dev *ss)
{ return atomic_inc_return(&ss->flow) % MAXFLOW;
}
int sun8i_ss_run_task(struct sun8i_ss_dev *ss, struct sun8i_cipher_req_ctx *rctx, constchar *name)
{ int flow = rctx->flow; unsignedint ivlen = rctx->ivlen;
u32 v = SS_START; int i;
for (i = 0; i < MAXFLOW; i++)
seq_printf(seq, "Channel %d: nreq %lu\n", i, #ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG
ss->flows[i].stat_req); #else
0ul); #endif
for (i = 0; i < ARRAY_SIZE(ss_algs); i++) { if (!ss_algs[i].ss) continue; switch (ss_algs[i].type) { case CRYPTO_ALG_TYPE_SKCIPHER:
seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n",
ss_algs[i].alg.skcipher.base.base.cra_driver_name,
ss_algs[i].alg.skcipher.base.base.cra_name,
ss_algs[i].stat_req, ss_algs[i].stat_fb);
seq_printf(seq, "\tLast fallback is: %s\n",
ss_algs[i].fbname);
seq_printf(seq, "\tFallback due to length: %lu\n",
ss_algs[i].stat_fb_len);
seq_printf(seq, "\tFallback due to SG length: %lu\n",
ss_algs[i].stat_fb_sglen);
seq_printf(seq, "\tFallback due to alignment: %lu\n",
ss_algs[i].stat_fb_align);
seq_printf(seq, "\tFallback due to SG numbers: %lu\n",
ss_algs[i].stat_fb_sgnum); break; case CRYPTO_ALG_TYPE_RNG:
seq_printf(seq, "%s %s reqs=%lu tsize=%lu\n",
ss_algs[i].alg.rng.base.cra_driver_name,
ss_algs[i].alg.rng.base.cra_name,
ss_algs[i].stat_req, ss_algs[i].stat_bytes); break; case CRYPTO_ALG_TYPE_AHASH:
seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n",
ss_algs[i].alg.hash.base.halg.base.cra_driver_name,
ss_algs[i].alg.hash.base.halg.base.cra_name,
ss_algs[i].stat_req, ss_algs[i].stat_fb);
seq_printf(seq, "\tLast fallback is: %s\n",
ss_algs[i].fbname);
seq_printf(seq, "\tFallback due to length: %lu\n",
ss_algs[i].stat_fb_len);
seq_printf(seq, "\tFallback due to SG length: %lu\n",
ss_algs[i].stat_fb_sglen);
seq_printf(seq, "\tFallback due to alignment: %lu\n",
ss_algs[i].stat_fb_align);
seq_printf(seq, "\tFallback due to SG numbers: %lu\n",
ss_algs[i].stat_fb_sgnum); break;
}
} return 0;
}
DEFINE_SHOW_ATTRIBUTE(sun8i_ss_debugfs);
staticvoid sun8i_ss_free_flows(struct sun8i_ss_dev *ss, int i)
{ while (i >= 0) {
crypto_engine_exit(ss->flows[i].engine);
i--;
}
}
/* * Allocate the flow list structure
*/ staticint allocate_flows(struct sun8i_ss_dev *ss)
{ int i, j, err;
/* the padding could be up to two block. */
ss->flows[i].pad = devm_kmalloc(ss->dev, MAX_PAD_SIZE,
GFP_KERNEL); if (!ss->flows[i].pad) {
err = -ENOMEM; goto error_engine;
}
ss->flows[i].result =
devm_kmalloc(ss->dev, max(SHA256_DIGEST_SIZE,
dma_get_cache_alignment()),
GFP_KERNEL); if (!ss->flows[i].result) {
err = -ENOMEM; goto error_engine;
}
/* * Power management strategy: The device is suspended unless a TFM exists for * one of the algorithms proposed by this driver.
*/ staticint sun8i_ss_pm_suspend(struct device *dev)
{ struct sun8i_ss_dev *ss = dev_get_drvdata(dev); int i;
reset_control_assert(ss->reset); for (i = 0; i < SS_MAX_CLOCKS; i++)
clk_disable_unprepare(ss->ssclks[i]); return 0;
}
for (i = 0; i < ARRAY_SIZE(ss_algs); i++) { if (!ss_algs[i].ss) continue; switch (ss_algs[i].type) { case CRYPTO_ALG_TYPE_SKCIPHER:
dev_info(ss->dev, "Unregister %d %s\n", i,
ss_algs[i].alg.skcipher.base.base.cra_name);
crypto_engine_unregister_skcipher(&ss_algs[i].alg.skcipher); break; case CRYPTO_ALG_TYPE_RNG:
dev_info(ss->dev, "Unregister %d %s\n", i,
ss_algs[i].alg.rng.base.cra_name);
crypto_unregister_rng(&ss_algs[i].alg.rng); break; case CRYPTO_ALG_TYPE_AHASH:
dev_info(ss->dev, "Unregister %d %s\n", i,
ss_algs[i].alg.hash.base.halg.base.cra_name);
crypto_engine_unregister_ahash(&ss_algs[i].alg.hash); break;
}
}
}
staticint sun8i_ss_get_clks(struct sun8i_ss_dev *ss)
{ unsignedlong cr; int err, i;
for (i = 0; i < SS_MAX_CLOCKS; i++) { if (!ss->variant->ss_clks[i].name) continue;
ss->ssclks[i] = devm_clk_get(ss->dev, ss->variant->ss_clks[i].name); if (IS_ERR(ss->ssclks[i])) {
err = PTR_ERR(ss->ssclks[i]);
dev_err(ss->dev, "Cannot get %s SS clock err=%d\n",
ss->variant->ss_clks[i].name, err); return err;
}
cr = clk_get_rate(ss->ssclks[i]); if (!cr) return -EINVAL; if (ss->variant->ss_clks[i].freq > 0 &&
cr != ss->variant->ss_clks[i].freq) {
dev_info(ss->dev, "Set %s clock to %lu (%lu Mhz) from %lu (%lu Mhz)\n",
ss->variant->ss_clks[i].name,
ss->variant->ss_clks[i].freq,
ss->variant->ss_clks[i].freq / 1000000,
cr, cr / 1000000);
err = clk_set_rate(ss->ssclks[i], ss->variant->ss_clks[i].freq); if (err)
dev_err(ss->dev, "Fail to set %s clk speed to %lu hz\n",
ss->variant->ss_clks[i].name,
ss->variant->ss_clks[i].freq);
} if (ss->variant->ss_clks[i].max_freq > 0 &&
cr > ss->variant->ss_clks[i].max_freq)
dev_warn(ss->dev, "Frequency for %s (%lu hz) is higher than datasheet's recommendation (%lu hz)",
ss->variant->ss_clks[i].name, cr,
ss->variant->ss_clks[i].max_freq);
} return 0;
}
ss->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ss->base)) return PTR_ERR(ss->base);
err = sun8i_ss_get_clks(ss); if (err) return err;
irq = platform_get_irq(pdev, 0); if (irq < 0) return irq;
ss->reset = devm_reset_control_get(&pdev->dev, NULL); if (IS_ERR(ss->reset)) return dev_err_probe(&pdev->dev, PTR_ERR(ss->reset), "No reset control found\n");
mutex_init(&ss->mlock);
err = allocate_flows(ss); if (err) return err;
err = sun8i_ss_pm_init(ss); if (err) goto error_pm;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.