Commit d6a10c84 authored by Evgeniy Polyakov's avatar Evgeniy Polyakov Committed by Herbert Xu

crypto: hifn_795x - Fix queue management

Fix queue management. Change ring size and perform its check not
one after another descriptor, but using stored pointers to the last
checked descriptors.
Signed-off-by: default avatarEvgeniy Polyakov <zbr@ioremap.net>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 3ec858de
...@@ -360,14 +360,14 @@ static atomic_t hifn_dev_number; ...@@ -360,14 +360,14 @@ static atomic_t hifn_dev_number;
#define HIFN_NAMESIZE 32 #define HIFN_NAMESIZE 32
#define HIFN_MAX_RESULT_ORDER 5 #define HIFN_MAX_RESULT_ORDER 5
#define HIFN_D_CMD_RSIZE 24*4 #define HIFN_D_CMD_RSIZE 24*1
#define HIFN_D_SRC_RSIZE 80*4 #define HIFN_D_SRC_RSIZE 80*1
#define HIFN_D_DST_RSIZE 80*4 #define HIFN_D_DST_RSIZE 80*1
#define HIFN_D_RES_RSIZE 24*4 #define HIFN_D_RES_RSIZE 24*1
#define HIFN_D_DST_DALIGN 4 #define HIFN_D_DST_DALIGN 4
#define HIFN_QUEUE_LENGTH HIFN_D_CMD_RSIZE-1 #define HIFN_QUEUE_LENGTH (HIFN_D_CMD_RSIZE - 1)
#define AES_MIN_KEY_SIZE 16 #define AES_MIN_KEY_SIZE 16
#define AES_MAX_KEY_SIZE 32 #define AES_MAX_KEY_SIZE 32
...@@ -1256,6 +1256,7 @@ static int hifn_setup_cmd_desc(struct hifn_device *dev, ...@@ -1256,6 +1256,7 @@ static int hifn_setup_cmd_desc(struct hifn_device *dev,
} }
dev->sa[sa_idx] = priv; dev->sa[sa_idx] = priv;
dev->started++;
cmd_len = buf_pos - buf; cmd_len = buf_pos - buf;
dma->cmdr[dma->cmdi].l = __cpu_to_le32(cmd_len | HIFN_D_VALID | dma->cmdr[dma->cmdi].l = __cpu_to_le32(cmd_len | HIFN_D_VALID |
...@@ -1382,9 +1383,6 @@ static int hifn_setup_dma(struct hifn_device *dev, ...@@ -1382,9 +1383,6 @@ static int hifn_setup_dma(struct hifn_device *dev,
soff = src->offset; soff = src->offset;
len = min(src->length, n); len = min(src->length, n);
dprintk("%s: spage: %p, soffset: %u, nbytes: %u, "
"priv: %p, rctx: %p.\n",
dev->name, spage, soff, nbytes, priv, rctx);
hifn_setup_src_desc(dev, spage, soff, len, n - len == 0); hifn_setup_src_desc(dev, spage, soff, len, n - len == 0);
src++; src++;
...@@ -1405,9 +1403,6 @@ static int hifn_setup_dma(struct hifn_device *dev, ...@@ -1405,9 +1403,6 @@ static int hifn_setup_dma(struct hifn_device *dev,
} }
len = min(len, n); len = min(len, n);
dprintk("%s: dpage: %p, doffset: %u, nbytes: %u, "
"priv: %p, rctx: %p.\n",
dev->name, dpage, doff, nbytes, priv, rctx);
hifn_setup_dst_desc(dev, dpage, doff, len, n - len == 0); hifn_setup_dst_desc(dev, dpage, doff, len, n - len == 0);
dst++; dst++;
...@@ -1620,13 +1615,12 @@ static int hifn_setup_session(struct ablkcipher_request *req) ...@@ -1620,13 +1615,12 @@ static int hifn_setup_session(struct ablkcipher_request *req)
goto err_out; goto err_out;
} }
dev->snum++;
dev->started++;
err = hifn_setup_dma(dev, ctx, rctx, req->src, req->dst, req->nbytes, req); err = hifn_setup_dma(dev, ctx, rctx, req->src, req->dst, req->nbytes, req);
if (err) if (err)
goto err_out; goto err_out;
dev->snum++;
dev->active = HIFN_DEFAULT_ACTIVE_NUM; dev->active = HIFN_DEFAULT_ACTIVE_NUM;
spin_unlock_irqrestore(&dev->lock, flags); spin_unlock_irqrestore(&dev->lock, flags);
...@@ -1635,12 +1629,13 @@ static int hifn_setup_session(struct ablkcipher_request *req) ...@@ -1635,12 +1629,13 @@ static int hifn_setup_session(struct ablkcipher_request *req)
err_out: err_out:
spin_unlock_irqrestore(&dev->lock, flags); spin_unlock_irqrestore(&dev->lock, flags);
err_out_exit: err_out_exit:
if (err) if (err) {
dprintk("%s: iv: %p [%d], key: %p [%d], mode: %u, op: %u, " printk("%s: iv: %p [%d], key: %p [%d], mode: %u, op: %u, "
"type: %u, err: %d.\n", "type: %u, err: %d.\n",
dev->name, rctx->iv, rctx->ivsize, dev->name, rctx->iv, rctx->ivsize,
ctx->key, ctx->keysize, ctx->key, ctx->keysize,
rctx->mode, rctx->op, rctx->type, err); rctx->mode, rctx->op, rctx->type, err);
}
return err; return err;
} }
...@@ -1676,6 +1671,7 @@ static int hifn_test(struct hifn_device *dev, int encdec, u8 snum) ...@@ -1676,6 +1671,7 @@ static int hifn_test(struct hifn_device *dev, int encdec, u8 snum)
if (err) if (err)
goto err_out; goto err_out;
dev->started = 0;
msleep(200); msleep(200);
dprintk("%s: decoded: ", dev->name); dprintk("%s: decoded: ", dev->name);
...@@ -1702,6 +1698,7 @@ static int hifn_start_device(struct hifn_device *dev) ...@@ -1702,6 +1698,7 @@ static int hifn_start_device(struct hifn_device *dev)
{ {
int err; int err;
dev->started = dev->active = 0;
hifn_reset_dma(dev, 1); hifn_reset_dma(dev, 1);
err = hifn_enable_crypto(dev); err = hifn_enable_crypto(dev);
...@@ -1755,19 +1752,22 @@ static int ablkcipher_get(void *saddr, unsigned int *srestp, unsigned int offset ...@@ -1755,19 +1752,22 @@ static int ablkcipher_get(void *saddr, unsigned int *srestp, unsigned int offset
return idx; return idx;
} }
static void hifn_process_ready(struct ablkcipher_request *req, int error) static inline void hifn_complete_sa(struct hifn_device *dev, int i)
{ {
struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm); unsigned long flags;
struct hifn_request_context *rctx = ablkcipher_request_ctx(req);
struct hifn_device *dev;
dprintk("%s: req: %p, ctx: %p rctx: %p.\n", __func__, req, ctx, rctx);
dev = ctx->dev; spin_lock_irqsave(&dev->lock, flags);
dprintk("%s: req: %p, started: %d.\n", __func__, req, dev->started); dev->sa[i] = NULL;
dev->started--;
if (dev->started < 0)
printk("%s: started: %d.\n", __func__, dev->started);
spin_unlock_irqrestore(&dev->lock, flags);
BUG_ON(dev->started < 0);
}
if (--dev->started < 0) static void hifn_process_ready(struct ablkcipher_request *req, int error)
BUG(); {
struct hifn_request_context *rctx = ablkcipher_request_ctx(req);
if (rctx->walk.flags & ASYNC_FLAGS_MISALIGNED) { if (rctx->walk.flags & ASYNC_FLAGS_MISALIGNED) {
unsigned int nbytes = req->nbytes; unsigned int nbytes = req->nbytes;
...@@ -1810,33 +1810,7 @@ static void hifn_process_ready(struct ablkcipher_request *req, int error) ...@@ -1810,33 +1810,7 @@ static void hifn_process_ready(struct ablkcipher_request *req, int error)
req->base.complete(&req->base, error); req->base.complete(&req->base, error);
} }
static void hifn_check_for_completion(struct hifn_device *dev, int error) static void hifn_clear_rings(struct hifn_device *dev, int error)
{
int i;
struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
for (i=0; i<HIFN_D_RES_RSIZE; ++i) {
struct hifn_desc *d = &dma->resr[i];
if (!(d->l & __cpu_to_le32(HIFN_D_VALID)) && dev->sa[i]) {
dev->success++;
dev->reset = 0;
hifn_process_ready(dev->sa[i], error);
dev->sa[i] = NULL;
}
if (d->l & __cpu_to_le32(HIFN_D_DESTOVER | HIFN_D_OVER))
if (printk_ratelimit())
printk("%s: overflow detected [d: %u, o: %u] "
"at %d resr: l: %08x, p: %08x.\n",
dev->name,
!!(d->l & __cpu_to_le32(HIFN_D_DESTOVER)),
!!(d->l & __cpu_to_le32(HIFN_D_OVER)),
i, d->l, d->p);
}
}
static void hifn_clear_rings(struct hifn_device *dev)
{ {
struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
int i, u; int i, u;
...@@ -1853,21 +1827,26 @@ static void hifn_clear_rings(struct hifn_device *dev) ...@@ -1853,21 +1827,26 @@ static void hifn_clear_rings(struct hifn_device *dev)
if (dma->resr[i].l & __cpu_to_le32(HIFN_D_VALID)) if (dma->resr[i].l & __cpu_to_le32(HIFN_D_VALID))
break; break;
if (i != HIFN_D_RES_RSIZE) if (dev->sa[i]) {
u--; dev->success++;
dev->reset = 0;
hifn_process_ready(dev->sa[i], error);
hifn_complete_sa(dev, i);
}
if (++i == (HIFN_D_RES_RSIZE + 1)) if (++i == HIFN_D_RES_RSIZE)
i = 0; i = 0;
u--;
} }
dma->resk = i; dma->resu = u; dma->resk = i; dma->resu = u;
i = dma->srck; u = dma->srcu; i = dma->srck; u = dma->srcu;
while (u != 0) { while (u != 0) {
if (i == HIFN_D_SRC_RSIZE)
i = 0;
if (dma->srcr[i].l & __cpu_to_le32(HIFN_D_VALID)) if (dma->srcr[i].l & __cpu_to_le32(HIFN_D_VALID))
break; break;
i++, u--; if (++i == HIFN_D_SRC_RSIZE)
i = 0;
u--;
} }
dma->srck = i; dma->srcu = u; dma->srck = i; dma->srcu = u;
...@@ -1875,20 +1854,19 @@ static void hifn_clear_rings(struct hifn_device *dev) ...@@ -1875,20 +1854,19 @@ static void hifn_clear_rings(struct hifn_device *dev)
while (u != 0) { while (u != 0) {
if (dma->cmdr[i].l & __cpu_to_le32(HIFN_D_VALID)) if (dma->cmdr[i].l & __cpu_to_le32(HIFN_D_VALID))
break; break;
if (i != HIFN_D_CMD_RSIZE) if (++i == HIFN_D_CMD_RSIZE)
u--;
if (++i == (HIFN_D_CMD_RSIZE + 1))
i = 0; i = 0;
u--;
} }
dma->cmdk = i; dma->cmdu = u; dma->cmdk = i; dma->cmdu = u;
i = dma->dstk; u = dma->dstu; i = dma->dstk; u = dma->dstu;
while (u != 0) { while (u != 0) {
if (i == HIFN_D_DST_RSIZE)
i = 0;
if (dma->dstr[i].l & __cpu_to_le32(HIFN_D_VALID)) if (dma->dstr[i].l & __cpu_to_le32(HIFN_D_VALID))
break; break;
i++, u--; if (++i == HIFN_D_DST_RSIZE)
i = 0;
u--;
} }
dma->dstk = i; dma->dstu = u; dma->dstk = i; dma->dstu = u;
...@@ -1933,30 +1911,39 @@ static void hifn_work(struct work_struct *work) ...@@ -1933,30 +1911,39 @@ static void hifn_work(struct work_struct *work)
} else } else
dev->active--; dev->active--;
if (dev->prev_success == dev->success && dev->started) if ((dev->prev_success == dev->success) && dev->started)
reset = 1; reset = 1;
dev->prev_success = dev->success; dev->prev_success = dev->success;
spin_unlock_irqrestore(&dev->lock, flags); spin_unlock_irqrestore(&dev->lock, flags);
if (reset) { if (reset) {
dprintk("%s: r: %08x, active: %d, started: %d, " if (++dev->reset >= 5) {
"success: %lu: reset: %d.\n", int i;
struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
printk("%s: r: %08x, active: %d, started: %d, "
"success: %lu: qlen: %u/%u, reset: %d.\n",
dev->name, r, dev->active, dev->started, dev->name, r, dev->active, dev->started,
dev->success, reset); dev->success, dev->queue.qlen, dev->queue.max_qlen,
reset);
printk("%s: res: ", __func__);
for (i=0; i<HIFN_D_RES_RSIZE; ++i) {
printk("%x.%p ", dma->resr[i].l, dev->sa[i]);
if (dev->sa[i]) {
hifn_process_ready(dev->sa[i], -ENODEV);
hifn_complete_sa(dev, i);
}
}
printk("\n");
if (++dev->reset >= 5) {
dprintk("%s: really hard reset.\n", dev->name);
hifn_reset_dma(dev, 1); hifn_reset_dma(dev, 1);
hifn_stop_device(dev); hifn_stop_device(dev);
hifn_start_device(dev); hifn_start_device(dev);
dev->reset = 0; dev->reset = 0;
} }
spin_lock_irqsave(&dev->lock, flags); tasklet_schedule(&dev->tasklet);
hifn_check_for_completion(dev, -EBUSY);
hifn_clear_rings(dev);
dev->started = 0;
spin_unlock_irqrestore(&dev->lock, flags);
} }
schedule_delayed_work(&dev->work, HZ); schedule_delayed_work(&dev->work, HZ);
...@@ -1973,8 +1960,8 @@ static irqreturn_t hifn_interrupt(int irq, void *data) ...@@ -1973,8 +1960,8 @@ static irqreturn_t hifn_interrupt(int irq, void *data)
dprintk("%s: 1 dmacsr: %08x, dmareg: %08x, res: %08x [%d], " dprintk("%s: 1 dmacsr: %08x, dmareg: %08x, res: %08x [%d], "
"i: %d.%d.%d.%d, u: %d.%d.%d.%d.\n", "i: %d.%d.%d.%d, u: %d.%d.%d.%d.\n",
dev->name, dmacsr, dev->dmareg, dmacsr & dev->dmareg, dma->cmdi, dev->name, dmacsr, dev->dmareg, dmacsr & dev->dmareg, dma->cmdi,
dma->cmdu, dma->srcu, dma->dstu, dma->resu, dma->cmdi, dma->srci, dma->dsti, dma->resi,
dma->cmdi, dma->srci, dma->dsti, dma->resi); dma->cmdu, dma->srcu, dma->dstu, dma->resu);
if ((dmacsr & dev->dmareg) == 0) if ((dmacsr & dev->dmareg) == 0)
return IRQ_NONE; return IRQ_NONE;
...@@ -1991,8 +1978,7 @@ static irqreturn_t hifn_interrupt(int irq, void *data) ...@@ -1991,8 +1978,7 @@ static irqreturn_t hifn_interrupt(int irq, void *data)
if (restart) { if (restart) {
u32 puisr = hifn_read_0(dev, HIFN_0_PUISR); u32 puisr = hifn_read_0(dev, HIFN_0_PUISR);
if (printk_ratelimit()) printk(KERN_WARNING "%s: overflow: r: %d, d: %d, puisr: %08x, d: %u.\n",
printk("%s: overflow: r: %d, d: %d, puisr: %08x, d: %u.\n",
dev->name, !!(dmacsr & HIFN_DMACSR_R_OVER), dev->name, !!(dmacsr & HIFN_DMACSR_R_OVER),
!!(dmacsr & HIFN_DMACSR_D_OVER), !!(dmacsr & HIFN_DMACSR_D_OVER),
puisr, !!(puisr & HIFN_PUISR_DSTOVER)); puisr, !!(puisr & HIFN_PUISR_DSTOVER));
...@@ -2005,8 +1991,7 @@ static irqreturn_t hifn_interrupt(int irq, void *data) ...@@ -2005,8 +1991,7 @@ static irqreturn_t hifn_interrupt(int irq, void *data)
restart = dmacsr & (HIFN_DMACSR_C_ABORT | HIFN_DMACSR_S_ABORT | restart = dmacsr & (HIFN_DMACSR_C_ABORT | HIFN_DMACSR_S_ABORT |
HIFN_DMACSR_D_ABORT | HIFN_DMACSR_R_ABORT); HIFN_DMACSR_D_ABORT | HIFN_DMACSR_R_ABORT);
if (restart) { if (restart) {
if (printk_ratelimit()) printk(KERN_WARNING "%s: abort: c: %d, s: %d, d: %d, r: %d.\n",
printk("%s: abort: c: %d, s: %d, d: %d, r: %d.\n",
dev->name, !!(dmacsr & HIFN_DMACSR_C_ABORT), dev->name, !!(dmacsr & HIFN_DMACSR_C_ABORT),
!!(dmacsr & HIFN_DMACSR_S_ABORT), !!(dmacsr & HIFN_DMACSR_S_ABORT),
!!(dmacsr & HIFN_DMACSR_D_ABORT), !!(dmacsr & HIFN_DMACSR_D_ABORT),
...@@ -2023,7 +2008,6 @@ static irqreturn_t hifn_interrupt(int irq, void *data) ...@@ -2023,7 +2008,6 @@ static irqreturn_t hifn_interrupt(int irq, void *data)
} }
tasklet_schedule(&dev->tasklet); tasklet_schedule(&dev->tasklet);
hifn_clear_rings(dev);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -2037,21 +2021,25 @@ static void hifn_flush(struct hifn_device *dev) ...@@ -2037,21 +2021,25 @@ static void hifn_flush(struct hifn_device *dev)
struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
int i; int i;
spin_lock_irqsave(&dev->lock, flags);
for (i=0; i<HIFN_D_RES_RSIZE; ++i) { for (i=0; i<HIFN_D_RES_RSIZE; ++i) {
struct hifn_desc *d = &dma->resr[i]; struct hifn_desc *d = &dma->resr[i];
if (dev->sa[i]) { if (dev->sa[i]) {
hifn_process_ready(dev->sa[i], hifn_process_ready(dev->sa[i],
(d->l & __cpu_to_le32(HIFN_D_VALID))?-ENODEV:0); (d->l & __cpu_to_le32(HIFN_D_VALID))?-ENODEV:0);
hifn_complete_sa(dev, i);
} }
} }
spin_lock_irqsave(&dev->lock, flags);
while ((async_req = crypto_dequeue_request(&dev->queue))) { while ((async_req = crypto_dequeue_request(&dev->queue))) {
ctx = crypto_tfm_ctx(async_req->tfm); ctx = crypto_tfm_ctx(async_req->tfm);
req = container_of(async_req, struct ablkcipher_request, base); req = container_of(async_req, struct ablkcipher_request, base);
spin_unlock_irqrestore(&dev->lock, flags);
hifn_process_ready(req, -ENODEV); hifn_process_ready(req, -ENODEV);
spin_lock_irqsave(&dev->lock, flags);
} }
spin_unlock_irqrestore(&dev->lock, flags); spin_unlock_irqrestore(&dev->lock, flags);
} }
...@@ -2568,7 +2556,7 @@ static void hifn_tasklet_callback(unsigned long data) ...@@ -2568,7 +2556,7 @@ static void hifn_tasklet_callback(unsigned long data)
* (like dev->success), but they are used in process * (like dev->success), but they are used in process
* context or update is atomic (like setting dev->sa[i] to NULL). * context or update is atomic (like setting dev->sa[i] to NULL).
*/ */
hifn_check_for_completion(dev, 0); hifn_clear_rings(dev, 0);
if (dev->started < HIFN_QUEUE_LENGTH && dev->queue.qlen) if (dev->started < HIFN_QUEUE_LENGTH && dev->queue.qlen)
hifn_process_queue(dev); hifn_process_queue(dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment