Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6

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

+43 -3
+2 -1
drivers/crypto/marvell/cesa.h
··· 273 273 #define CESA_TDMA_SRC_IN_SRAM BIT(30) 274 274 #define CESA_TDMA_END_OF_REQ BIT(29) 275 275 #define CESA_TDMA_BREAK_CHAIN BIT(28) 276 - #define CESA_TDMA_TYPE_MSK GENMASK(27, 0) 276 + #define CESA_TDMA_SET_STATE BIT(27) 277 + #define CESA_TDMA_TYPE_MSK GENMASK(26, 0) 277 278 #define CESA_TDMA_DUMMY 0 278 279 #define CESA_TDMA_DATA 1 279 280 #define CESA_TDMA_OP 2
+33 -1
drivers/crypto/marvell/hash.c
··· 280 280 sreq->offset = 0; 281 281 } 282 282 283 + static void mv_cesa_ahash_dma_step(struct ahash_request *req) 284 + { 285 + struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); 286 + struct mv_cesa_req *base = &creq->base; 287 + 288 + /* We must explicitly set the digest state. */ 289 + if (base->chain.first->flags & CESA_TDMA_SET_STATE) { 290 + struct mv_cesa_engine *engine = base->engine; 291 + int i; 292 + 293 + /* Set the hash state in the IVDIG regs. */ 294 + for (i = 0; i < ARRAY_SIZE(creq->state); i++) 295 + writel_relaxed(creq->state[i], engine->regs + 296 + CESA_IVDIG(i)); 297 + } 298 + 299 + mv_cesa_dma_step(base); 300 + } 301 + 283 302 static void mv_cesa_ahash_step(struct crypto_async_request *req) 284 303 { 285 304 struct ahash_request *ahashreq = ahash_request_cast(req); 286 305 struct mv_cesa_ahash_req *creq = ahash_request_ctx(ahashreq); 287 306 288 307 if (mv_cesa_req_get_type(&creq->base) == CESA_DMA_REQ) 289 - mv_cesa_dma_step(&creq->base); 308 + mv_cesa_ahash_dma_step(ahashreq); 290 309 else 291 310 mv_cesa_ahash_std_step(ahashreq); 292 311 } ··· 603 584 struct mv_cesa_ahash_dma_iter iter; 604 585 struct mv_cesa_op_ctx *op = NULL; 605 586 unsigned int frag_len; 587 + bool set_state = false; 606 588 int ret; 607 589 u32 type; 608 590 609 591 basereq->chain.first = NULL; 610 592 basereq->chain.last = NULL; 593 + 594 + if (!mv_cesa_mac_op_is_first_frag(&creq->op_tmpl)) 595 + set_state = true; 611 596 612 597 if (creq->src_nents) { 613 598 ret = dma_map_sg(cesa_dev->dev, req->src, creq->src_nents, ··· 705 682 706 683 if (type != CESA_TDMA_RESULT) 707 684 basereq->chain.last->flags |= CESA_TDMA_BREAK_CHAIN; 685 + 686 + if (set_state) { 687 + /* 688 + * Put the CESA_TDMA_SET_STATE flag on the first tdma desc to 689 + * let the step logic know that the IVDIG registers should be 690 + * explicitly set before launching a TDMA chain. 691 + */ 692 + basereq->chain.first->flags |= CESA_TDMA_SET_STATE; 693 + } 708 694 709 695 return 0; 710 696
+8 -1
drivers/crypto/marvell/tdma.c
··· 109 109 last->next = dreq->chain.first; 110 110 engine->chain.last = dreq->chain.last; 111 111 112 - if (!(last->flags & CESA_TDMA_BREAK_CHAIN)) 112 + /* 113 + * Break the DMA chain if the CESA_TDMA_BREAK_CHAIN is set on 114 + * the last element of the current chain, or if the request 115 + * being queued needs the IV regs to be set before lauching 116 + * the request. 117 + */ 118 + if (!(last->flags & CESA_TDMA_BREAK_CHAIN) && 119 + !(dreq->chain.first->flags & CESA_TDMA_SET_STATE)) 113 120 last->next_dma = dreq->chain.first->cur_dma; 114 121 } 115 122 }