static int sahara_sha_hw_links_create(struct sahara_dev *dev, struct sahara_sha_reqctx *rctx, int start) { struct scatterlist *sg; unsigned int i; int ret; dev->in_sg = rctx->in_sg; dev->nb_in_sg = sahara_sg_length(dev->in_sg, rctx->total); if ((dev->nb_in_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; } if (rctx->in_sg_chained) { i = start; sg = dev->in_sg; while (sg) { ret = dma_map_sg(dev->device, sg, 1, DMA_TO_DEVICE); if (!ret) return -EFAULT; dev->hw_link[i]->len = sg->length; dev->hw_link[i]->p = sg->dma_address; dev->hw_link[i]->next = dev->hw_phys_link[i + 1]; sg = sg_next(sg); i += 1; } dev->hw_link[i-1]->next = 0; } else { sg = dev->in_sg; ret = dma_map_sg(dev->device, dev->in_sg, dev->nb_in_sg, DMA_TO_DEVICE); if (!ret) return -EFAULT; for (i = start; i < dev->nb_in_sg + start; i++) { dev->hw_link[i]->len = sg->length; dev->hw_link[i]->p = sg->dma_address; if (i == (dev->nb_in_sg + start - 1)) { dev->hw_link[i]->next = 0; } else { dev->hw_link[i]->next = dev->hw_phys_link[i + 1]; sg = sg_next(sg); } } } return i; }
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; }