Hi Ovidiu,
kernel test robot noticed the following build warnings:
[auto build test WARNING on herbert-cryptodev-2.6/master]
[also build test WARNING on next-20250619]
[cannot apply to sunxi/sunxi/for-next herbert-crypto-2.6/master linus/master v6.16-rc2]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Ovidiu-Panait/crypto-sun8i-ce-remove-channel-timeout-field/20250619-202957
base: https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git master
patch link: https://lore.kernel.org/r/20250619122316.2587236-11-ovidiu.panait.oss%40gmail.com
patch subject: [PATCH 10/10] crypto: sun8i-ce - implement request batching
config: loongarch-allyesconfig (https://download.01.org/0day-ci/archive/20250620/202506201006.eQ2P1PuC-lkp@intel.com/config)
compiler: loongarch64-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250620/202506201006.eQ2P1PuC-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202506201006.eQ2P1PuC-lkp@intel.com/
All warnings (new ones prefixed by >>):
drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c: In function 'sun8i_ce_dump_task_descriptors':
>> drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c:178:52: warning: '%d' directive output may be truncated writing between 1 and 11 bytes into a region of size 7 [-Wformat-truncation=]
178 | snprintf(task, sizeof(task), "TASK %d:", i);
| ^~
drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c:178:46: note: directive argument in the range [-2147483641, 2147483646]
178 | snprintf(task, sizeof(task), "TASK %d:", i);
| ^~~~~~~~~~
drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c:178:17: note: 'snprintf' output between 8 and 18 bytes into a destination of size 12
178 | snprintf(task, sizeof(task), "TASK %d:", i);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
vim +178 drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c
171
172 static void sun8i_ce_dump_task_descriptors(struct sun8i_ce_flow *chan)
173 {
174 for (int i = 0; i < chan->reqs_no; ++i) {
175 struct ce_task *cet = &chan->tl[i];
176 char task[CE_MAX_TASK_DESCR_DUMP_MSG_SIZE];
177
> 178 snprintf(task, sizeof(task), "TASK %d:", i);
179 print_hex_dump(KERN_INFO, task, DUMP_PREFIX_NONE, 16, 4,
180 cet, sizeof(struct ce_task), false);
181 }
182 }
183
@@ -165,7 +165,7 @@ static int sun8i_ce_cipher_prepare(struct skcipher_request *areq,
cet->t_id = cpu_to_le32(rctx->flow);
common = ce->variant->alg_cipher[algt->ce_algo_id];
- common |= rctx->op_dir | CE_COMM_INT;
+ common |= rctx->op_dir;
cet->t_common_ctl = cpu_to_le32(common);
/* CTS and recent CE (H6) need length in bytes, in word otherwise */
if (ce->variant->cipher_t_dlen_in_bytes)
@@ -376,16 +376,15 @@ int sun8i_ce_cipher_do_one(struct crypto_engine *engine, void *areq)
int err;
chan = &ce->chanlist[rctx->flow];
- cet = chan->tl;
+ cet = sun8i_ce_enqueue_one(chan, areq);
+ if (IS_ERR(cet))
+ return PTR_ERR(cet);
err = sun8i_ce_cipher_prepare(req, cet);
- if (err)
+ if (err) {
+ sun8i_ce_dequeue_one(chan);
return err;
-
- err = sun8i_ce_run_task(ce, rctx->flow,
- crypto_tfm_alg_name(req->base.tfm));
-
- sun8i_ce_cipher_finalize_req(areq, cet, err);
+ }
return 0;
}
@@ -10,7 +10,7 @@
* You could find a link for the datasheet in Documentation/arch/arm/sunxi.rst
*/
-#include <crypto/engine.h>
+#include <crypto/internal/engine.h>
#include <crypto/internal/hash.h>
#include <crypto/internal/rng.h>
#include <crypto/internal/skcipher.h>
@@ -171,8 +171,14 @@ static const struct ce_variant ce_r40_variant = {
static void sun8i_ce_dump_task_descriptors(struct sun8i_ce_flow *chan)
{
- print_hex_dump(KERN_INFO, "TASK: ", DUMP_PREFIX_NONE, 16, 4,
- chan->tl, sizeof(struct ce_task), false);
+ for (int i = 0; i < chan->reqs_no; ++i) {
+ struct ce_task *cet = &chan->tl[i];
+ char task[CE_MAX_TASK_DESCR_DUMP_MSG_SIZE];
+
+ snprintf(task, sizeof(task), "TASK %d:", i);
+ print_hex_dump(KERN_INFO, task, DUMP_PREFIX_NONE, 16, 4,
+ cet, sizeof(struct ce_task), false);
+ }
}
/*
@@ -190,10 +196,6 @@ int sun8i_ce_run_task(struct sun8i_ce_dev *ce, int flow, const char *name)
u32 v;
int err = 0;
-#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
- ce->chanlist[flow].stat_req++;
-#endif
-
mutex_lock(&ce->mlock);
v = readl(ce->base + CE_ICR);
@@ -710,12 +712,107 @@ static int sun8i_ce_debugfs_show(struct seq_file *seq, void *v)
DEFINE_SHOW_ATTRIBUTE(sun8i_ce_debugfs);
+static int sun8i_ce_get_flow_from_engine(struct sun8i_ce_dev *ce,
+ struct crypto_engine *engine)
+{
+ for (int i = 0; i < MAXFLOW; ++i)
+ if (ce->chanlist[i].engine == engine)
+ return i;
+
+ return -ENODEV;
+}
+
+static int sun8i_ce_do_batch(struct crypto_engine *engine)
+{
+ struct sun8i_ce_dev *ce;
+ struct sun8i_ce_flow *chan;
+ int err, flow;
+
+ ce = dev_get_drvdata(engine->dev);
+ flow = sun8i_ce_get_flow_from_engine(ce, engine);
+ if (flow < 0)
+ return flow;
+
+ chan = &ce->chanlist[flow];
+
+ if (!chan->reqs_no)
+ return 0;
+
+#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
+ ce->chanlist[flow].stat_req += chan->reqs_no;
+#endif
+
+ for (int i = 0; i < chan->reqs_no - 1; ++i) {
+ struct ce_task *task = &chan->tl[i];
+ dma_addr_t next = chan->t_phy + (i + 1) * sizeof(struct ce_task);
+
+ task->next = desc_addr_val_le32(ce, next);
+ }
+ chan->tl[chan->reqs_no - 1].next = 0;
+ chan->tl[chan->reqs_no - 1].t_common_ctl |= cpu_to_le32(CE_COMM_INT);
+
+ err = sun8i_ce_run_task(ce, flow, "BATCH");
+
+ for (int i = 0; i < chan->reqs_no; ++i) {
+ struct crypto_async_request *areq = chan->reqs[i];
+ u32 req_type = crypto_tfm_alg_type(areq->tfm);
+
+ if (req_type == CRYPTO_ALG_TYPE_SKCIPHER)
+ sun8i_ce_cipher_finalize_req(areq, &chan->tl[i], err);
+
+ if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN8I_CE_HASH) &&
+ (req_type == CRYPTO_ALG_TYPE_AHASH))
+ sun8i_ce_hash_finalize_req(areq, &chan->tl[i], err);
+
+ chan->reqs[i] = NULL;
+ }
+
+ chan->reqs_no = 0;
+
+ return err;
+}
+
+struct ce_task *sun8i_ce_enqueue_one(struct sun8i_ce_flow *chan,
+ struct crypto_async_request *areq)
+{
+ struct ce_task *cet;
+ struct crypto_async_request *prev;
+ u32 alg_type, prev_alg_type;
+
+ if (chan->reqs_no == CE_MAX_REQS_PER_BATCH)
+ return ERR_PTR(-ENOSPC);
+
+ if (chan->reqs_no) {
+ prev = chan->reqs[chan->reqs_no - 1];
+ prev_alg_type = crypto_tfm_alg_type(prev->tfm);
+ alg_type = crypto_tfm_alg_type(areq->tfm);
+
+ if (alg_type != prev_alg_type)
+ return ERR_PTR(-ENOSPC);
+ }
+
+ cet = chan->tl + chan->reqs_no;
+ chan->reqs[chan->reqs_no] = areq;
+ chan->reqs_no++;
+
+ return cet;
+}
+
+void sun8i_ce_dequeue_one(struct sun8i_ce_flow *chan)
+{
+ if (chan->reqs_no) {
+ chan->reqs_no--;
+ chan->reqs[chan->reqs_no] = NULL;
+ }
+}
+
static void sun8i_ce_free_chanlist(struct sun8i_ce_dev *ce, int i)
{
while (i >= 0) {
crypto_engine_exit(ce->chanlist[i].engine);
if (ce->chanlist[i].tl)
- dma_free_coherent(ce->dev, sizeof(struct ce_task),
+ dma_free_coherent(ce->dev,
+ CE_DMA_TASK_DESCR_ALLOC_SIZE,
ce->chanlist[i].tl,
ce->chanlist[i].t_phy);
i--;
@@ -737,7 +834,9 @@ static int sun8i_ce_allocate_chanlist(struct sun8i_ce_dev *ce)
for (i = 0; i < MAXFLOW; i++) {
init_completion(&ce->chanlist[i].complete);
- ce->chanlist[i].engine = crypto_engine_alloc_init(ce->dev, true);
+ ce->chanlist[i].engine = crypto_engine_alloc_init_and_set(
+ ce->dev, true, sun8i_ce_do_batch, true,
+ CE_MAX_REQS_PER_BATCH);
if (!ce->chanlist[i].engine) {
dev_err(ce->dev, "Cannot allocate engine\n");
i--;
@@ -750,9 +849,9 @@ static int sun8i_ce_allocate_chanlist(struct sun8i_ce_dev *ce)
goto error_engine;
}
ce->chanlist[i].tl = dma_alloc_coherent(ce->dev,
- sizeof(struct ce_task),
- &ce->chanlist[i].t_phy,
- GFP_KERNEL);
+ CE_DMA_TASK_DESCR_ALLOC_SIZE,
+ &ce->chanlist[i].t_phy,
+ GFP_KERNEL);
if (!ce->chanlist[i].tl) {
dev_err(ce->dev, "Cannot get DMA memory for task %d\n",
i);
@@ -350,7 +350,6 @@ static int sun8i_ce_hash_prepare(struct ahash_request *areq, struct ce_task *cet
cet->t_id = cpu_to_le32(rctx->flow);
common = ce->variant->alg_hash[algt->ce_algo_id];
- common |= CE_COMM_INT;
cet->t_common_ctl = cpu_to_le32(common);
cet->t_sym_ctl = 0;
@@ -488,15 +487,15 @@ int sun8i_ce_hash_run(struct crypto_engine *engine, void *async_req)
int err;
chan = &ce->chanlist[rctx->flow];
- cet = chan->tl;
+ cet = sun8i_ce_enqueue_one(chan, async_req);
+ if (IS_ERR(cet))
+ return PTR_ERR(cet);
err = sun8i_ce_hash_prepare(areq, cet);
- if (err)
+ if (err) {
+ sun8i_ce_dequeue_one(chan);
return err;
-
- err = sun8i_ce_run_task(ce, rctx->flow, crypto_ahash_alg_name(tfm));
-
- sun8i_ce_hash_finalize_req(async_req, cet, err);
+ }
return 0;
}
@@ -104,6 +104,10 @@
#define CE_DIE_ID_MASK 0x07
#define MAX_SG 8
+#define CE_MAX_REQS_PER_BATCH 10
+#define CE_MAX_TASK_DESCR_DUMP_MSG_SIZE 12
+#define CE_DMA_TASK_DESCR_ALLOC_SIZE \
+ (CE_MAX_REQS_PER_BATCH * sizeof(struct ce_task))
#define CE_MAX_CLOCKS 4
#define CE_DMA_TIMEOUT_MS 3000
@@ -191,6 +195,8 @@ struct ce_task {
* @status: set to 1 by interrupt if task is done
* @t_phy: Physical address of task
* @tl: pointer to the current ce_task for this flow
+ * @reqs: array of requests to be processed in batch
+ * @reqs_no: current number of requests in @reqs
* @stat_req: number of request done by this flow
*/
struct sun8i_ce_flow {
@@ -199,6 +205,8 @@ struct sun8i_ce_flow {
int status;
dma_addr_t t_phy;
struct ce_task *tl;
+ struct crypto_async_request *reqs[CE_MAX_REQS_PER_BATCH];
+ int reqs_no;
#ifdef CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG
unsigned long stat_req;
#endif
@@ -373,6 +381,29 @@ struct sun8i_ce_alg_template {
char fbname[CRYPTO_MAX_ALG_NAME];
};
+/**
+ * sun8i_ce_enqueue_one - add a request to the per-flow batch queue
+ * @chan: engine flow to enqueue the request
+ * @areq: request to be added to the batch queue
+ *
+ * This function adds request @areq to the batch queue in @chan. Should be
+ * called during do_one_request() crypto engine handler.
+ *
+ * @return - on success, task descriptor associated with the request
+ * - on failure, ERR_PTR(-ENOSPC) if the queue was full or if the
+ * request type is different from the requests already queued up
+ */
+struct ce_task *sun8i_ce_enqueue_one(struct sun8i_ce_flow *chan,
+ struct crypto_async_request *areq);
+
+/**
+ * sun8i_ce_dequeue_one - remove head request from the per-flow batch queue
+ * @chan: engine flow to remove the request from
+ *
+ * This function removes the head request from the batch queue in @chan.
+ */
+void sun8i_ce_dequeue_one(struct sun8i_ce_flow *chan);
+
int sun8i_ce_aes_setkey(struct crypto_skcipher *tfm, const u8 *key,
unsigned int keylen);
int sun8i_ce_des3_setkey(struct crypto_skcipher *tfm, const u8 *key,