void *context, int error),
void *context)
{
+ struct talitos_edesc *edesc = container_of(desc, struct talitos_edesc, desc);
struct talitos_private *priv = dev_get_drvdata(dev);
+ dma_addr_t dma_desc, prev_dma_desc;
+ struct talitos_edesc *prev_edesc = NULL;
struct talitos_request *request;
unsigned long flags;
int head;
/* map descriptor and save caller data */
if (is_sec1) {
- desc->hdr1 = desc->hdr;
- request->dma_desc = dma_map_single(dev, &desc->hdr1,
+ while (edesc) {
+ edesc->desc.hdr1 = edesc->desc.hdr;
+
+ dma_desc = dma_map_single(dev, &edesc->desc.hdr1,
+ TALITOS_DESC_SIZE,
+ DMA_BIDIRECTIONAL);
+
+ if (!prev_edesc) {
+ request->dma_desc = dma_desc;
+ goto next;
+ }
+
+ /* Chain in any previous descriptors. */
+
+ prev_edesc->desc.next_desc = cpu_to_be32(dma_desc);
+
+ dma_sync_single_for_device(dev, prev_dma_desc,
TALITOS_DESC_SIZE,
- DMA_BIDIRECTIONAL);
+ DMA_TO_DEVICE);
+
+next:
+ prev_edesc = edesc;
+ prev_dma_desc = dma_desc;
+ edesc = edesc->next_desc;
+ }
} else {
request->dma_desc = dma_map_single(dev, desc,
TALITOS_DESC_SIZE,
struct talitos_request *request, bool is_sec1)
{
struct talitos_edesc *edesc;
+ dma_addr_t dma_desc;
if (!is_sec1) {
dma_sync_single_for_cpu(dev, request->dma_desc,
return request->desc->hdr;
}
- if (!request->desc->next_desc) {
- dma_sync_single_for_cpu(dev, request->dma_desc,
- TALITOS_DESC_SIZE, DMA_BIDIRECTIONAL);
- return request->desc->hdr1;
- } else {
- dma_sync_single_for_cpu(dev,
- be32_to_cpu(request->desc->next_desc),
- TALITOS_DESC_SIZE, DMA_BIDIRECTIONAL);
- edesc = container_of(request->desc, struct talitos_edesc, desc);
-
- return ((struct talitos_desc *)(edesc->buf + edesc->dma_len))
- ->hdr1;
+ edesc = container_of(request->desc, struct talitos_edesc, desc);
+ dma_desc = request->dma_desc;
+ while (edesc->next_desc) {
+ dma_desc = be32_to_cpu(edesc->desc.next_desc);
+ edesc = edesc->next_desc;
}
+
+ dma_sync_single_for_cpu(dev, dma_desc, TALITOS_DESC_SIZE,
+ DMA_BIDIRECTIONAL);
+
+ return edesc->desc.hdr1;
}
/*
{
struct talitos_private *priv = dev_get_drvdata(dev);
struct talitos_request *request, saved_req;
+ struct talitos_edesc *edesc;
unsigned long flags;
int tail, status;
bool is_sec1 = has_ftr_sec1(priv);
else
status = error;
- dma_unmap_single(dev, request->dma_desc,
- TALITOS_DESC_SIZE,
- DMA_BIDIRECTIONAL);
+ if (is_sec1) {
+ dma_unmap_single(dev, request->dma_desc,
+ TALITOS_DESC_SIZE, DMA_BIDIRECTIONAL);
+ edesc = container_of(request->desc,
+ struct talitos_edesc, desc);
+ while (edesc->next_desc) {
+ dma_unmap_single(
+ dev, be32_to_cpu(edesc->desc.next_desc),
+ TALITOS_DESC_SIZE, DMA_BIDIRECTIONAL);
+ edesc = edesc->next_desc;
+ }
+ } else {
+ dma_unmap_single(dev, request->dma_desc,
+ TALITOS_DESC_SIZE,
+ DMA_BIDIRECTIONAL);
+ }
/* copy entries so we can call callback outside lock */
saved_req.desc = request->desc;
static __be32 current_desc_hdr(struct device *dev, int ch)
{
struct talitos_private *priv = dev_get_drvdata(dev);
+ bool is_sec1 = has_ftr_sec1(priv);
+ struct talitos_request *request;
+ struct talitos_edesc *edesc;
int tail, iter;
dma_addr_t cur_desc;
+ __be32 hdr = 0;
cur_desc = ((u64)in_be32(priv->chan[ch].reg + TALITOS_CDPR)) << 32;
cur_desc |= in_be32(priv->chan[ch].reg + TALITOS_CDPR_LO);
}
tail = priv->chan[ch].tail;
-
iter = tail;
- while (priv->chan[ch].fifo[iter].dma_desc != cur_desc &&
- priv->chan[ch].fifo[iter].desc->next_desc != cpu_to_be32(cur_desc)) {
- iter = (iter + 1) & (priv->fifo_len - 1);
- if (iter == tail) {
- dev_err(dev, "couldn't locate current descriptor\n");
- return 0;
+ do {
+ request = &priv->chan[ch].fifo[iter];
+
+ if (request->dma_desc == cur_desc) {
+ hdr = request->desc->hdr;
+ } else if (is_sec1) {
+ edesc = container_of(request->desc,
+ struct talitos_edesc, desc);
+ while (edesc->next_desc) {
+ if (edesc->desc.next_desc ==
+ cpu_to_be32(cur_desc)) {
+ hdr = edesc->next_desc->desc.hdr1;
+ break;
+ }
+ edesc = edesc->next_desc;
+ }
}
- }
- if (priv->chan[ch].fifo[iter].desc->next_desc == cpu_to_be32(cur_desc)) {
- struct talitos_edesc *edesc;
+ if (hdr)
+ break;
- edesc = container_of(priv->chan[ch].fifo[iter].desc,
- struct talitos_edesc, desc);
- return ((struct talitos_desc *)
- (edesc->buf + edesc->dma_len))->hdr;
- }
+ iter = (iter + 1) & (priv->fifo_len - 1);
+ } while (iter != tail);
+
+ if (!hdr)
+ dev_err(dev, "couldn't locate current descriptor\n");
- return priv->chan[ch].fifo[iter].desc->hdr;
+ return hdr;
}
/*
dma_len = 0;
}
alloc_len += icv_stashing ? authsize : 0;
-
- /* if its a ahash, add space for a second desc next to the first one */
- if (is_sec1 && !dst)
- alloc_len += sizeof(struct talitos_desc);
alloc_len += ivsize;
edesc = kmalloc(ALIGN(alloc_len, dma_get_cache_alignment()), flags);
edesc->dst_nents = dst_nents;
edesc->iv_dma = iv_dma;
edesc->dma_len = dma_len;
+ edesc->next_desc = NULL;
if (dma_len)
edesc->dma_link_tbl = dma_map_single(dev, &edesc->link_tbl[0],
edesc->dma_len,
struct talitos_private *priv = dev_get_drvdata(dev);
bool is_sec1 = has_ftr_sec1(priv);
struct talitos_desc *desc = &edesc->desc;
- struct talitos_desc *desc2 = (struct talitos_desc *)
- (edesc->buf + edesc->dma_len);
+ struct talitos_desc *desc2;
+
+ if (desc->next_desc)
+ desc2 = &edesc->next_desc->desc;
unmap_single_talitos_ptr(dev, &desc->ptr[5], DMA_FROM_DEVICE);
if (desc->next_desc &&
if (edesc->dma_len)
dma_unmap_single(dev, edesc->dma_link_tbl, edesc->dma_len,
DMA_BIDIRECTIONAL);
+}
- if (desc->next_desc)
- dma_unmap_single(dev, be32_to_cpu(desc->next_desc),
- TALITOS_DESC_SIZE, DMA_BIDIRECTIONAL);
+static void free_edesc_list_from(struct talitos_edesc *edesc)
+{
+ struct talitos_edesc *next;
+
+ while (edesc) {
+ next = edesc->next_desc;
+ kfree(edesc);
+ edesc = next;
+ }
}
static void ahash_done(struct device *dev,
}
common_nonsnoop_hash_unmap(dev, edesc, areq);
- kfree(edesc);
+ free_edesc_list_from(edesc);
if (err) {
ahash_request_complete(areq, err);
talitos_handle_buggy_hash(ctx, edesc, &desc->ptr[3]);
if (is_sec1 && req_ctx->nbuf && length) {
- struct talitos_desc *desc2 = (struct talitos_desc *)
- (edesc->buf + edesc->dma_len);
- dma_addr_t next_desc;
+ struct talitos_edesc *edesc2;
+ struct talitos_desc *desc2;
+
+ edesc2 = kzalloc(sizeof(*edesc2),
+ areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
+ GFP_KERNEL :
+ GFP_ATOMIC);
+ if (!edesc2) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ edesc->next_desc = edesc2;
+
+ desc2 = &edesc2->desc;
- memset(desc2, 0, sizeof(*desc2));
desc2->hdr = desc->hdr;
desc2->hdr &= ~DESC_HDR_MODE0_MDEU_INIT;
- desc2->hdr1 = desc2->hdr;
desc->hdr &= ~DESC_HDR_MODE0_MDEU_PAD;
desc->hdr |= DESC_HDR_MODE0_MDEU_CONT;
desc->hdr &= ~DESC_HDR_DONE_NOTIFY;
req_ctx->hw_context_size,
req_ctx->hw_context,
DMA_FROM_DEVICE);
-
- next_desc = dma_map_single(dev, &desc2->hdr1, TALITOS_DESC_SIZE,
- DMA_BIDIRECTIONAL);
- desc->next_desc = cpu_to_be32(next_desc);
}
if (sync_needed)
dma_sync_single_for_device(dev, edesc->dma_link_tbl,
edesc->dma_len, DMA_BIDIRECTIONAL);
- ret = talitos_submit(dev, ctx->ch, desc, callback, areq);
- if (ret != -EINPROGRESS) {
- common_nonsnoop_hash_unmap(dev, edesc, areq);
- kfree(edesc);
- }
+ ret = talitos_submit(dev, ctx->ch, desc, callback,
+ areq);
+ if (ret != -EINPROGRESS)
+ goto err;
+
+ return -EINPROGRESS;
+err:
+ common_nonsnoop_hash_unmap(dev, edesc, areq);
+ kfree(edesc);
return ret;
}