static int sahara_sha_process(struct ahash_request *req) { struct sahara_dev *dev = dev_ptr; struct sahara_sha_reqctx *rctx = ahash_request_ctx(req); int ret; unsigned long timeout; ret = sahara_sha_prepare_request(req); if (!ret) return ret; if (rctx->first) { sahara_sha_hw_data_descriptor_create(dev, rctx, req, 0); dev->hw_desc[0]->next = 0; rctx->first = 0; } else { memcpy(dev->context_base, rctx->context, rctx->context_size); sahara_sha_hw_context_descriptor_create(dev, rctx, req, 0); dev->hw_desc[0]->next = dev->hw_phys_desc[1]; sahara_sha_hw_data_descriptor_create(dev, rctx, req, 1); dev->hw_desc[1]->next = 0; } sahara_dump_descriptors(dev); sahara_dump_links(dev); reinit_completion(&dev->dma_completion); sahara_write(dev, dev->hw_phys_desc[0], SAHARA_REG_DAR); timeout = wait_for_completion_timeout(&dev->dma_completion, msecs_to_jiffies(SAHARA_TIMEOUT_MS)); if (!timeout) { dev_err(dev->device, "SHA timeout\n"); return -ETIMEDOUT; } if (rctx->sg_in_idx) sahara_sha_unmap_sg(dev, rctx); memcpy(rctx->context, dev->context_base, rctx->context_size); if (req->result) memcpy(req->result, rctx->context, rctx->digest_size); return 0; }
static int sahara_hw_descriptor_create(struct sahara_dev *dev) { struct sahara_ctx *ctx = dev->ctx; struct scatterlist *sg; int ret; int i, j; /* Copy new key if necessary */ if (ctx->flags & FLAGS_NEW_KEY) { memcpy(dev->key_base, ctx->key, ctx->keylen); ctx->flags &= ~FLAGS_NEW_KEY; if (dev->flags & FLAGS_CBC) { dev->hw_desc[0]->len1 = AES_BLOCK_SIZE; dev->hw_desc[0]->p1 = dev->iv_phys_base; } else { dev->hw_desc[0]->len1 = 0; dev->hw_desc[0]->p1 = 0; } dev->hw_desc[0]->len2 = ctx->keylen; dev->hw_desc[0]->p2 = dev->key_phys_base; dev->hw_desc[0]->next = dev->hw_phys_desc[1]; } dev->hw_desc[0]->hdr = sahara_aes_key_hdr(dev); dev->nb_in_sg = sahara_sg_length(dev->in_sg, dev->total); dev->nb_out_sg = sahara_sg_length(dev->out_sg, dev->total); if ((dev->nb_in_sg + dev->nb_out_sg) > SAHARA_MAX_HW_LINK) { dev_err(dev->device, "not enough hw links (%d)\n", dev->nb_in_sg + dev->nb_out_sg); return -EINVAL; } ret = dma_map_sg(dev->device, dev->in_sg, dev->nb_in_sg, DMA_TO_DEVICE); if (ret != dev->nb_in_sg) { dev_err(dev->device, "couldn't map in sg\n"); goto unmap_in; } ret = dma_map_sg(dev->device, dev->out_sg, dev->nb_out_sg, DMA_FROM_DEVICE); if (ret != dev->nb_out_sg) { dev_err(dev->device, "couldn't map out sg\n"); goto unmap_out; } /* Create input links */ dev->hw_desc[1]->p1 = dev->hw_phys_link[0]; sg = dev->in_sg; for (i = 0; i < dev->nb_in_sg; i++) { dev->hw_link[i]->len = sg->length; dev->hw_link[i]->p = sg->dma_address; if (i == (dev->nb_in_sg - 1)) { dev->hw_link[i]->next = 0; } else { dev->hw_link[i]->next = dev->hw_phys_link[i + 1]; sg = sg_next(sg); } } /* Create output links */ dev->hw_desc[1]->p2 = dev->hw_phys_link[i]; sg = dev->out_sg; for (j = i; j < dev->nb_out_sg + i; j++) { dev->hw_link[j]->len = sg->length; dev->hw_link[j]->p = sg->dma_address; if (j == (dev->nb_out_sg + i - 1)) { dev->hw_link[j]->next = 0; } else { dev->hw_link[j]->next = dev->hw_phys_link[j + 1]; sg = sg_next(sg); } } /* Fill remaining fields of hw_desc[1] */ dev->hw_desc[1]->hdr = sahara_aes_data_link_hdr(dev); dev->hw_desc[1]->len1 = dev->total; dev->hw_desc[1]->len2 = dev->total; dev->hw_desc[1]->next = 0; sahara_dump_descriptors(dev); sahara_dump_links(dev); /* Start processing descriptor chain. */ mod_timer(&dev->watchdog, jiffies + msecs_to_jiffies(SAHARA_TIMEOUT_MS)); sahara_write(dev, dev->hw_phys_desc[0], SAHARA_REG_DAR); return 0; unmap_out: dma_unmap_sg(dev->device, dev->out_sg, dev->nb_out_sg, DMA_TO_DEVICE); unmap_in: dma_unmap_sg(dev->device, dev->in_sg, dev->nb_in_sg, DMA_FROM_DEVICE); return -EINVAL; }