Skip to content

Commit 0413bcf

Browse files
committed
crypto: marvell/cesa - Do not chain submitted requests
This driver tries to chain requests together before submitting them to hardware in order to reduce completion interrupts. However, it even extends chains that have already been submitted to hardware. This is dangerous because there is no way of knowing whether the hardware has already read the DMA memory in question or not. Fix this by splitting the chain list into two. One for submitted requests and one for requests that have not yet been submitted. Only extend the latter. Reported-by: Klaus Kudielka <klaus.kudielka@gmail.com> Fixes: 85030c5 ("crypto: marvell - Add support for chaining crypto requests in TDMA mode") Cc: <stable@vger.kernel.org> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
1 parent bc81690 commit 0413bcf

File tree

3 files changed

+39
-25
lines changed

3 files changed

+39
-25
lines changed

drivers/crypto/marvell/cesa/cesa.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ static int mv_cesa_std_process(struct mv_cesa_engine *engine, u32 status)
9494

9595
static int mv_cesa_int_process(struct mv_cesa_engine *engine, u32 status)
9696
{
97-
if (engine->chain.first && engine->chain.last)
97+
if (engine->chain_hw.first && engine->chain_hw.last)
9898
return mv_cesa_tdma_process(engine, status);
9999

100100
return mv_cesa_std_process(engine, status);

drivers/crypto/marvell/cesa/cesa.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -440,8 +440,10 @@ struct mv_cesa_dev {
440440
* SRAM
441441
* @queue: fifo of the pending crypto requests
442442
* @load: engine load counter, useful for load balancing
443-
* @chain: list of the current tdma descriptors being processed
444-
* by this engine.
443+
* @chain_hw: list of the current tdma descriptors being processed
444+
* by the hardware.
445+
* @chain_sw: list of the current tdma descriptors that will be
446+
* submitted to the hardware.
445447
* @complete_queue: fifo of the processed requests by the engine
446448
*
447449
* Structure storing CESA engine information.
@@ -463,7 +465,8 @@ struct mv_cesa_engine {
463465
struct gen_pool *pool;
464466
struct crypto_queue queue;
465467
atomic_t load;
466-
struct mv_cesa_tdma_chain chain;
468+
struct mv_cesa_tdma_chain chain_hw;
469+
struct mv_cesa_tdma_chain chain_sw;
467470
struct list_head complete_queue;
468471
int irq;
469472
};

drivers/crypto/marvell/cesa/tdma.c

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,15 @@ void mv_cesa_dma_step(struct mv_cesa_req *dreq)
3838
{
3939
struct mv_cesa_engine *engine = dreq->engine;
4040

41+
spin_lock_bh(&engine->lock);
42+
if (engine->chain_sw.first == dreq->chain.first) {
43+
engine->chain_sw.first = NULL;
44+
engine->chain_sw.last = NULL;
45+
}
46+
engine->chain_hw.first = dreq->chain.first;
47+
engine->chain_hw.last = dreq->chain.last;
48+
spin_unlock_bh(&engine->lock);
49+
4150
writel_relaxed(0, engine->regs + CESA_SA_CFG);
4251

4352
mv_cesa_set_int_mask(engine, CESA_SA_INT_ACC0_IDMA_DONE);
@@ -96,25 +105,27 @@ void mv_cesa_dma_prepare(struct mv_cesa_req *dreq,
96105
void mv_cesa_tdma_chain(struct mv_cesa_engine *engine,
97106
struct mv_cesa_req *dreq)
98107
{
99-
if (engine->chain.first == NULL && engine->chain.last == NULL) {
100-
engine->chain.first = dreq->chain.first;
101-
engine->chain.last = dreq->chain.last;
102-
} else {
103-
struct mv_cesa_tdma_desc *last;
108+
struct mv_cesa_tdma_desc *last = engine->chain_sw.last;
104109

105-
last = engine->chain.last;
110+
/*
111+
* Break the DMA chain if the request being queued needs the IV
112+
* regs to be set before lauching the request.
113+
*/
114+
if (!last || dreq->chain.first->flags & CESA_TDMA_SET_STATE)
115+
engine->chain_sw.first = dreq->chain.first;
116+
else {
106117
last->next = dreq->chain.first;
107-
engine->chain.last = dreq->chain.last;
108-
109-
/*
110-
* Break the DMA chain if the CESA_TDMA_BREAK_CHAIN is set on
111-
* the last element of the current chain, or if the request
112-
* being queued needs the IV regs to be set before lauching
113-
* the request.
114-
*/
115-
if (!(last->flags & CESA_TDMA_BREAK_CHAIN) &&
116-
!(dreq->chain.first->flags & CESA_TDMA_SET_STATE))
117-
last->next_dma = cpu_to_le32(dreq->chain.first->cur_dma);
118+
last->next_dma = cpu_to_le32(dreq->chain.first->cur_dma);
119+
}
120+
last = dreq->chain.last;
121+
engine->chain_sw.last = last;
122+
/*
123+
* Break the DMA chain if the CESA_TDMA_BREAK_CHAIN is set on
124+
* the last element of the current chain.
125+
*/
126+
if (last->flags & CESA_TDMA_BREAK_CHAIN) {
127+
engine->chain_sw.first = NULL;
128+
engine->chain_sw.last = NULL;
118129
}
119130
}
120131

@@ -127,7 +138,7 @@ int mv_cesa_tdma_process(struct mv_cesa_engine *engine, u32 status)
127138

128139
tdma_cur = readl(engine->regs + CESA_TDMA_CUR);
129140

130-
for (tdma = engine->chain.first; tdma; tdma = next) {
141+
for (tdma = engine->chain_hw.first; tdma; tdma = next) {
131142
spin_lock_bh(&engine->lock);
132143
next = tdma->next;
133144
spin_unlock_bh(&engine->lock);
@@ -149,12 +160,12 @@ int mv_cesa_tdma_process(struct mv_cesa_engine *engine, u32 status)
149160
&backlog);
150161

151162
/* Re-chaining to the next request */
152-
engine->chain.first = tdma->next;
163+
engine->chain_hw.first = tdma->next;
153164
tdma->next = NULL;
154165

155166
/* If this is the last request, clear the chain */
156-
if (engine->chain.first == NULL)
157-
engine->chain.last = NULL;
167+
if (engine->chain_hw.first == NULL)
168+
engine->chain_hw.last = NULL;
158169
spin_unlock_bh(&engine->lock);
159170

160171
ctx = crypto_tfm_ctx(req->tfm);

0 commit comments

Comments
 (0)