Skip to content

Commit 85030c5

Browse files
Romain Perierherbertx
authored andcommitted
crypto: marvell - Add support for chaining crypto requests in TDMA mode
The Cryptographic Engines and Security Accelerators (CESA) supports the Multi-Packet Chain Mode. With this mode enabled, multiple tdma requests can be chained and processed by the hardware without software intervention. This mode was already activated, however the crypto requests were not chained together. By doing so, we reduce significantly the number of IRQs. Instead of being interrupted at the end of each crypto request, we are interrupted at the end of the last cryptographic request processed by the engine. This commits re-factorizes the code, changes the code architecture and adds the required data structures to chain cryptographic requests together before sending them to an engine (stopped or possibly already running). Signed-off-by: Romain Perier <[email protected]> Acked-by: Boris Brezillon <[email protected]> Signed-off-by: Herbert Xu <[email protected]>
1 parent bf8f91e commit 85030c5

File tree

5 files changed

+221
-27
lines changed

5 files changed

+221
-27
lines changed

drivers/crypto/marvell/cesa.c

Lines changed: 90 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,33 @@ MODULE_PARM_DESC(allhwsupport, "Enable support for all hardware (even it if over
4040

4141
struct mv_cesa_dev *cesa_dev;
4242

43-
static void mv_cesa_dequeue_req_locked(struct mv_cesa_engine *engine)
43+
struct crypto_async_request *
44+
mv_cesa_dequeue_req_locked(struct mv_cesa_engine *engine,
45+
struct crypto_async_request **backlog)
4446
{
45-
struct crypto_async_request *req, *backlog;
46-
struct mv_cesa_ctx *ctx;
47+
struct crypto_async_request *req;
4748

48-
backlog = crypto_get_backlog(&engine->queue);
49+
*backlog = crypto_get_backlog(&engine->queue);
4950
req = crypto_dequeue_request(&engine->queue);
50-
engine->req = req;
51+
52+
if (!req)
53+
return NULL;
54+
55+
return req;
56+
}
57+
58+
static void mv_cesa_rearm_engine(struct mv_cesa_engine *engine)
59+
{
60+
struct crypto_async_request *req = NULL, *backlog = NULL;
61+
struct mv_cesa_ctx *ctx;
62+
63+
64+
spin_lock_bh(&engine->lock);
65+
if (!engine->req) {
66+
req = mv_cesa_dequeue_req_locked(engine, &backlog);
67+
engine->req = req;
68+
}
69+
spin_unlock_bh(&engine->lock);
5170

5271
if (!req)
5372
return;
@@ -57,6 +76,46 @@ static void mv_cesa_dequeue_req_locked(struct mv_cesa_engine *engine)
5776

5877
ctx = crypto_tfm_ctx(req->tfm);
5978
ctx->ops->step(req);
79+
80+
return;
81+
}
82+
83+
static int mv_cesa_std_process(struct mv_cesa_engine *engine, u32 status)
84+
{
85+
struct crypto_async_request *req;
86+
struct mv_cesa_ctx *ctx;
87+
int res;
88+
89+
req = engine->req;
90+
ctx = crypto_tfm_ctx(req->tfm);
91+
res = ctx->ops->process(req, status);
92+
93+
if (res == 0) {
94+
ctx->ops->complete(req);
95+
mv_cesa_engine_enqueue_complete_request(engine, req);
96+
} else if (res == -EINPROGRESS) {
97+
ctx->ops->step(req);
98+
}
99+
100+
return res;
101+
}
102+
103+
static int mv_cesa_int_process(struct mv_cesa_engine *engine, u32 status)
104+
{
105+
if (engine->chain.first && engine->chain.last)
106+
return mv_cesa_tdma_process(engine, status);
107+
108+
return mv_cesa_std_process(engine, status);
109+
}
110+
111+
static inline void
112+
mv_cesa_complete_req(struct mv_cesa_ctx *ctx, struct crypto_async_request *req,
113+
int res)
114+
{
115+
ctx->ops->cleanup(req);
116+
local_bh_disable();
117+
req->complete(req, res);
118+
local_bh_enable();
60119
}
61120

62121
static irqreturn_t mv_cesa_int(int irq, void *priv)
@@ -83,26 +142,31 @@ static irqreturn_t mv_cesa_int(int irq, void *priv)
83142
writel(~status, engine->regs + CESA_SA_FPGA_INT_STATUS);
84143
writel(~status, engine->regs + CESA_SA_INT_STATUS);
85144

145+
/* Process fetched requests */
146+
res = mv_cesa_int_process(engine, status & mask);
86147
ret = IRQ_HANDLED;
148+
87149
spin_lock_bh(&engine->lock);
88150
req = engine->req;
151+
if (res != -EINPROGRESS)
152+
engine->req = NULL;
89153
spin_unlock_bh(&engine->lock);
90-
if (req) {
91-
ctx = crypto_tfm_ctx(req->tfm);
92-
res = ctx->ops->process(req, status & mask);
93-
if (res != -EINPROGRESS) {
94-
spin_lock_bh(&engine->lock);
95-
engine->req = NULL;
96-
mv_cesa_dequeue_req_locked(engine);
97-
spin_unlock_bh(&engine->lock);
98-
ctx->ops->complete(req);
99-
ctx->ops->cleanup(req);
100-
local_bh_disable();
101-
req->complete(req, res);
102-
local_bh_enable();
103-
} else {
104-
ctx->ops->step(req);
105-
}
154+
155+
ctx = crypto_tfm_ctx(req->tfm);
156+
157+
if (res && res != -EINPROGRESS)
158+
mv_cesa_complete_req(ctx, req, res);
159+
160+
/* Launch the next pending request */
161+
mv_cesa_rearm_engine(engine);
162+
163+
/* Iterate over the complete queue */
164+
while (true) {
165+
req = mv_cesa_engine_dequeue_complete_request(engine);
166+
if (!req)
167+
break;
168+
169+
mv_cesa_complete_req(ctx, req, 0);
106170
}
107171
}
108172

@@ -116,16 +180,16 @@ int mv_cesa_queue_req(struct crypto_async_request *req,
116180
struct mv_cesa_engine *engine = creq->engine;
117181

118182
spin_lock_bh(&engine->lock);
183+
if (mv_cesa_req_get_type(creq) == CESA_DMA_REQ)
184+
mv_cesa_tdma_chain(engine, creq);
185+
119186
ret = crypto_enqueue_request(&engine->queue, req);
120187
spin_unlock_bh(&engine->lock);
121188

122189
if (ret != -EINPROGRESS)
123190
return ret;
124191

125-
spin_lock_bh(&engine->lock);
126-
if (!engine->req)
127-
mv_cesa_dequeue_req_locked(engine);
128-
spin_unlock_bh(&engine->lock);
192+
mv_cesa_rearm_engine(engine);
129193

130194
return -EINPROGRESS;
131195
}
@@ -496,6 +560,7 @@ static int mv_cesa_probe(struct platform_device *pdev)
496560

497561
crypto_init_queue(&engine->queue, CESA_CRYPTO_DEFAULT_MAX_QLEN);
498562
atomic_set(&engine->load, 0);
563+
INIT_LIST_HEAD(&engine->complete_queue);
499564
}
500565

501566
cesa_dev = cesa;

drivers/crypto/marvell/cesa.h

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,9 @@ struct mv_cesa_op_ctx {
271271
/* TDMA descriptor flags */
272272
#define CESA_TDMA_DST_IN_SRAM BIT(31)
273273
#define CESA_TDMA_SRC_IN_SRAM BIT(30)
274-
#define CESA_TDMA_TYPE_MSK GENMASK(29, 0)
274+
#define CESA_TDMA_END_OF_REQ BIT(29)
275+
#define CESA_TDMA_BREAK_CHAIN BIT(28)
276+
#define CESA_TDMA_TYPE_MSK GENMASK(27, 0)
275277
#define CESA_TDMA_DUMMY 0
276278
#define CESA_TDMA_DATA 1
277279
#define CESA_TDMA_OP 2
@@ -431,6 +433,9 @@ struct mv_cesa_dev {
431433
* SRAM
432434
* @queue: fifo of the pending crypto requests
433435
* @load: engine load counter, useful for load balancing
436+
* @chain: list of the current tdma descriptors being processed
437+
* by this engine.
438+
* @complete_queue: fifo of the processed requests by the engine
434439
*
435440
* Structure storing CESA engine information.
436441
*/
@@ -448,6 +453,8 @@ struct mv_cesa_engine {
448453
struct gen_pool *pool;
449454
struct crypto_queue queue;
450455
atomic_t load;
456+
struct mv_cesa_tdma_chain chain;
457+
struct list_head complete_queue;
451458
};
452459

453460
/**
@@ -608,6 +615,29 @@ struct mv_cesa_ahash_req {
608615

609616
extern struct mv_cesa_dev *cesa_dev;
610617

618+
619+
static inline void
620+
mv_cesa_engine_enqueue_complete_request(struct mv_cesa_engine *engine,
621+
struct crypto_async_request *req)
622+
{
623+
list_add_tail(&req->list, &engine->complete_queue);
624+
}
625+
626+
static inline struct crypto_async_request *
627+
mv_cesa_engine_dequeue_complete_request(struct mv_cesa_engine *engine)
628+
{
629+
struct crypto_async_request *req;
630+
631+
req = list_first_entry_or_null(&engine->complete_queue,
632+
struct crypto_async_request,
633+
list);
634+
if (req)
635+
list_del(&req->list);
636+
637+
return req;
638+
}
639+
640+
611641
static inline enum mv_cesa_req_type
612642
mv_cesa_req_get_type(struct mv_cesa_req *req)
613643
{
@@ -689,6 +719,10 @@ static inline bool mv_cesa_mac_op_is_first_frag(const struct mv_cesa_op_ctx *op)
689719
int mv_cesa_queue_req(struct crypto_async_request *req,
690720
struct mv_cesa_req *creq);
691721

722+
struct crypto_async_request *
723+
mv_cesa_dequeue_req_locked(struct mv_cesa_engine *engine,
724+
struct crypto_async_request **backlog);
725+
692726
static inline struct mv_cesa_engine *mv_cesa_select_engine(int weight)
693727
{
694728
int i;
@@ -794,6 +828,9 @@ static inline int mv_cesa_dma_process(struct mv_cesa_req *dreq,
794828
void mv_cesa_dma_prepare(struct mv_cesa_req *dreq,
795829
struct mv_cesa_engine *engine);
796830
void mv_cesa_dma_cleanup(struct mv_cesa_req *dreq);
831+
void mv_cesa_tdma_chain(struct mv_cesa_engine *engine,
832+
struct mv_cesa_req *dreq);
833+
int mv_cesa_tdma_process(struct mv_cesa_engine *engine, u32 status);
797834

798835

799836
static inline void

drivers/crypto/marvell/cipher.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@ static int mv_cesa_ablkcipher_dma_req_init(struct ablkcipher_request *req,
390390
goto err_free_tdma;
391391

392392
basereq->chain = chain;
393+
basereq->chain.last->flags |= CESA_TDMA_END_OF_REQ;
393394

394395
return 0;
395396

@@ -447,7 +448,6 @@ static int mv_cesa_ablkcipher_req_init(struct ablkcipher_request *req,
447448
mv_cesa_update_op_cfg(tmpl, CESA_SA_DESC_CFG_OP_CRYPT_ONLY,
448449
CESA_SA_DESC_CFG_OP_MSK);
449450

450-
/* TODO: add a threshold for DMA usage */
451451
if (cesa_dev->caps->has_tdma)
452452
ret = mv_cesa_ablkcipher_dma_req_init(req, tmpl);
453453
else

drivers/crypto/marvell/hash.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,9 @@ static void mv_cesa_ahash_std_step(struct ahash_request *req)
172172
for (i = 0; i < digsize / 4; i++)
173173
writel_relaxed(creq->state[i], engine->regs + CESA_IVDIG(i));
174174

175+
mv_cesa_adjust_op(engine, &creq->op_tmpl);
176+
memcpy_toio(engine->sram, &creq->op_tmpl, sizeof(creq->op_tmpl));
177+
175178
if (creq->cache_ptr)
176179
memcpy_toio(engine->sram + CESA_SA_DATA_SRAM_OFFSET,
177180
creq->cache, creq->cache_ptr);
@@ -647,6 +650,9 @@ static int mv_cesa_ahash_dma_req_init(struct ahash_request *req)
647650
else
648651
creq->cache_ptr = 0;
649652

653+
basereq->chain.last->flags |= (CESA_TDMA_END_OF_REQ |
654+
CESA_TDMA_BREAK_CHAIN);
655+
650656
return 0;
651657

652658
err_free_tdma:

drivers/crypto/marvell/tdma.c

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,92 @@ void mv_cesa_dma_prepare(struct mv_cesa_req *dreq,
9999
}
100100
}
101101

102+
void mv_cesa_tdma_chain(struct mv_cesa_engine *engine,
103+
struct mv_cesa_req *dreq)
104+
{
105+
if (engine->chain.first == NULL && engine->chain.last == NULL) {
106+
engine->chain.first = dreq->chain.first;
107+
engine->chain.last = dreq->chain.last;
108+
} else {
109+
struct mv_cesa_tdma_desc *last;
110+
111+
last = engine->chain.last;
112+
last->next = dreq->chain.first;
113+
engine->chain.last = dreq->chain.last;
114+
115+
if (!(last->flags & CESA_TDMA_BREAK_CHAIN))
116+
last->next_dma = dreq->chain.first->cur_dma;
117+
}
118+
}
119+
120+
int mv_cesa_tdma_process(struct mv_cesa_engine *engine, u32 status)
121+
{
122+
struct crypto_async_request *req = NULL;
123+
struct mv_cesa_tdma_desc *tdma = NULL, *next = NULL;
124+
dma_addr_t tdma_cur;
125+
int res = 0;
126+
127+
tdma_cur = readl(engine->regs + CESA_TDMA_CUR);
128+
129+
for (tdma = engine->chain.first; tdma; tdma = next) {
130+
spin_lock_bh(&engine->lock);
131+
next = tdma->next;
132+
spin_unlock_bh(&engine->lock);
133+
134+
if (tdma->flags & CESA_TDMA_END_OF_REQ) {
135+
struct crypto_async_request *backlog = NULL;
136+
struct mv_cesa_ctx *ctx;
137+
u32 current_status;
138+
139+
spin_lock_bh(&engine->lock);
140+
/*
141+
* if req is NULL, this means we're processing the
142+
* request in engine->req.
143+
*/
144+
if (!req)
145+
req = engine->req;
146+
else
147+
req = mv_cesa_dequeue_req_locked(engine,
148+
&backlog);
149+
150+
/* Re-chaining to the next request */
151+
engine->chain.first = tdma->next;
152+
tdma->next = NULL;
153+
154+
/* If this is the last request, clear the chain */
155+
if (engine->chain.first == NULL)
156+
engine->chain.last = NULL;
157+
spin_unlock_bh(&engine->lock);
158+
159+
ctx = crypto_tfm_ctx(req->tfm);
160+
current_status = (tdma->cur_dma == tdma_cur) ?
161+
status : CESA_SA_INT_ACC0_IDMA_DONE;
162+
res = ctx->ops->process(req, current_status);
163+
ctx->ops->complete(req);
164+
165+
if (res == 0)
166+
mv_cesa_engine_enqueue_complete_request(engine,
167+
req);
168+
169+
if (backlog)
170+
backlog->complete(backlog, -EINPROGRESS);
171+
}
172+
173+
if (res || tdma->cur_dma == tdma_cur)
174+
break;
175+
}
176+
177+
/* Save the last request in error to engine->req, so that the core
178+
* knows which request was fautly */
179+
if (res) {
180+
spin_lock_bh(&engine->lock);
181+
engine->req = req;
182+
spin_unlock_bh(&engine->lock);
183+
}
184+
185+
return res;
186+
}
187+
102188
static struct mv_cesa_tdma_desc *
103189
mv_cesa_dma_add_desc(struct mv_cesa_tdma_chain *chain, gfp_t flags)
104190
{

0 commit comments

Comments
 (0)