Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2d706e79 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull crypto fix from Herbert Xu:
 "This fixes a hash corruption bug in the marvell driver"

* 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6:
  crypto: marvell - Copy IVDIG before launching partial DMA ahash requests
parents 8f18e4d0 8759fec4
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -273,7 +273,8 @@ struct mv_cesa_op_ctx {
#define CESA_TDMA_SRC_IN_SRAM			BIT(30)
#define CESA_TDMA_END_OF_REQ			BIT(29)
#define CESA_TDMA_BREAK_CHAIN			BIT(28)
#define CESA_TDMA_TYPE_MSK			GENMASK(27, 0)
#define CESA_TDMA_SET_STATE			BIT(27)
#define CESA_TDMA_TYPE_MSK			GENMASK(26, 0)
#define CESA_TDMA_DUMMY				0
#define CESA_TDMA_DATA				1
#define CESA_TDMA_OP				2
+33 −1
Original line number Diff line number Diff line
@@ -280,13 +280,32 @@ static void mv_cesa_ahash_std_prepare(struct ahash_request *req)
	sreq->offset = 0;
}

static void mv_cesa_ahash_dma_step(struct ahash_request *req)
{
	struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
	struct mv_cesa_req *base = &creq->base;

	/* We must explicitly set the digest state. */
	if (base->chain.first->flags & CESA_TDMA_SET_STATE) {
		struct mv_cesa_engine *engine = base->engine;
		int i;

		/* Set the hash state in the IVDIG regs. */
		for (i = 0; i < ARRAY_SIZE(creq->state); i++)
			writel_relaxed(creq->state[i], engine->regs +
				       CESA_IVDIG(i));
	}

	mv_cesa_dma_step(base);
}

static void mv_cesa_ahash_step(struct crypto_async_request *req)
{
	struct ahash_request *ahashreq = ahash_request_cast(req);
	struct mv_cesa_ahash_req *creq = ahash_request_ctx(ahashreq);

	if (mv_cesa_req_get_type(&creq->base) == CESA_DMA_REQ)
		mv_cesa_dma_step(&creq->base);
		mv_cesa_ahash_dma_step(ahashreq);
	else
		mv_cesa_ahash_std_step(ahashreq);
}
@@ -584,12 +603,16 @@ static int mv_cesa_ahash_dma_req_init(struct ahash_request *req)
	struct mv_cesa_ahash_dma_iter iter;
	struct mv_cesa_op_ctx *op = NULL;
	unsigned int frag_len;
	bool set_state = false;
	int ret;
	u32 type;

	basereq->chain.first = NULL;
	basereq->chain.last = NULL;

	if (!mv_cesa_mac_op_is_first_frag(&creq->op_tmpl))
		set_state = true;

	if (creq->src_nents) {
		ret = dma_map_sg(cesa_dev->dev, req->src, creq->src_nents,
				 DMA_TO_DEVICE);
@@ -683,6 +706,15 @@ static int mv_cesa_ahash_dma_req_init(struct ahash_request *req)
	if (type != CESA_TDMA_RESULT)
		basereq->chain.last->flags |= CESA_TDMA_BREAK_CHAIN;

	if (set_state) {
		/*
		 * Put the CESA_TDMA_SET_STATE flag on the first tdma desc to
		 * let the step logic know that the IVDIG registers should be
		 * explicitly set before launching a TDMA chain.
		 */
		basereq->chain.first->flags |= CESA_TDMA_SET_STATE;
	}

	return 0;

err_free_tdma:
+8 −1
Original line number Diff line number Diff line
@@ -109,7 +109,14 @@ void mv_cesa_tdma_chain(struct mv_cesa_engine *engine,
		last->next = dreq->chain.first;
		engine->chain.last = dreq->chain.last;

		if (!(last->flags & CESA_TDMA_BREAK_CHAIN))
		/*
		 * Break the DMA chain if the CESA_TDMA_BREAK_CHAIN is set on
		 * the last element of the current chain, or if the request
		 * being queued needs the IV regs to be set before lauching
		 * the request.
		 */
		if (!(last->flags & CESA_TDMA_BREAK_CHAIN) &&
		    !(dreq->chain.first->flags & CESA_TDMA_SET_STATE))
			last->next_dma = dreq->chain.first->cur_dma;
	}
}