Commit 4b992628 authored by Kim Phillips's avatar Kim Phillips Committed by Herbert Xu

crypto: talitos - align locks on cache lines

align channel access locks onto separate cache lines (for performance
reasons).  This is done by placing per-channel variables into their own
private struct, and using the cacheline_aligned attribute within that
struct.
Signed-off-by: default avatarKim Phillips <kim.phillips@freescale.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent e41256f1
...@@ -86,6 +86,25 @@ struct talitos_request { ...@@ -86,6 +86,25 @@ struct talitos_request {
void *context; void *context;
}; };
/* per-channel fifo management */
struct talitos_channel {
/* request fifo */
struct talitos_request *fifo;
/* number of requests pending in channel h/w fifo */
atomic_t submit_count ____cacheline_aligned;
/* request submission (head) lock */
spinlock_t head_lock ____cacheline_aligned;
/* index to next free descriptor request */
int head;
/* request release (tail) lock */
spinlock_t tail_lock ____cacheline_aligned;
/* index to next in-progress/done descriptor request */
int tail;
};
struct talitos_private { struct talitos_private {
struct device *dev; struct device *dev;
struct of_device *ofdev; struct of_device *ofdev;
...@@ -101,15 +120,6 @@ struct talitos_private { ...@@ -101,15 +120,6 @@ struct talitos_private {
/* SEC Compatibility info */ /* SEC Compatibility info */
unsigned long features; unsigned long features;
/* next channel to be assigned next incoming descriptor */
atomic_t last_chan;
/* per-channel number of requests pending in channel h/w fifo */
atomic_t *submit_count;
/* per-channel request fifo */
struct talitos_request **fifo;
/* /*
* length of the request fifo * length of the request fifo
* fifo_len is chfifo_len rounded up to next power of 2 * fifo_len is chfifo_len rounded up to next power of 2
...@@ -117,15 +127,10 @@ struct talitos_private { ...@@ -117,15 +127,10 @@ struct talitos_private {
*/ */
unsigned int fifo_len; unsigned int fifo_len;
/* per-channel index to next free descriptor request */ struct talitos_channel *chan;
int *head;
/* per-channel index to next in-progress/done descriptor request */
int *tail;
/* per-channel request submission (head) and release (tail) locks */ /* next channel to be assigned next incoming descriptor */
spinlock_t *head_lock; atomic_t last_chan ____cacheline_aligned;
spinlock_t *tail_lock;
/* request callback tasklet */ /* request callback tasklet */
struct tasklet_struct done_task; struct tasklet_struct done_task;
...@@ -282,16 +287,16 @@ static int talitos_submit(struct device *dev, struct talitos_desc *desc, ...@@ -282,16 +287,16 @@ static int talitos_submit(struct device *dev, struct talitos_desc *desc,
/* emulate SEC's round-robin channel fifo polling scheme */ /* emulate SEC's round-robin channel fifo polling scheme */
ch = atomic_inc_return(&priv->last_chan) & (priv->num_channels - 1); ch = atomic_inc_return(&priv->last_chan) & (priv->num_channels - 1);
spin_lock_irqsave(&priv->head_lock[ch], flags); spin_lock_irqsave(&priv->chan[ch].head_lock, flags);
if (!atomic_inc_not_zero(&priv->submit_count[ch])) { if (!atomic_inc_not_zero(&priv->chan[ch].submit_count)) {
/* h/w fifo is full */ /* h/w fifo is full */
spin_unlock_irqrestore(&priv->head_lock[ch], flags); spin_unlock_irqrestore(&priv->chan[ch].head_lock, flags);
return -EAGAIN; return -EAGAIN;
} }
head = priv->head[ch]; head = priv->chan[ch].head;
request = &priv->fifo[ch][head]; request = &priv->chan[ch].fifo[head];
/* map descriptor and save caller data */ /* map descriptor and save caller data */
request->dma_desc = dma_map_single(dev, desc, sizeof(*desc), request->dma_desc = dma_map_single(dev, desc, sizeof(*desc),
...@@ -300,7 +305,7 @@ static int talitos_submit(struct device *dev, struct talitos_desc *desc, ...@@ -300,7 +305,7 @@ static int talitos_submit(struct device *dev, struct talitos_desc *desc,
request->context = context; request->context = context;
/* increment fifo head */ /* increment fifo head */
priv->head[ch] = (priv->head[ch] + 1) & (priv->fifo_len - 1); priv->chan[ch].head = (priv->chan[ch].head + 1) & (priv->fifo_len - 1);
smp_wmb(); smp_wmb();
request->desc = desc; request->desc = desc;
...@@ -309,7 +314,7 @@ static int talitos_submit(struct device *dev, struct talitos_desc *desc, ...@@ -309,7 +314,7 @@ static int talitos_submit(struct device *dev, struct talitos_desc *desc,
wmb(); wmb();
out_be32(priv->reg + TALITOS_FF_LO(ch), request->dma_desc); out_be32(priv->reg + TALITOS_FF_LO(ch), request->dma_desc);
spin_unlock_irqrestore(&priv->head_lock[ch], flags); spin_unlock_irqrestore(&priv->chan[ch].head_lock, flags);
return -EINPROGRESS; return -EINPROGRESS;
} }
...@@ -324,11 +329,11 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch) ...@@ -324,11 +329,11 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch)
unsigned long flags; unsigned long flags;
int tail, status; int tail, status;
spin_lock_irqsave(&priv->tail_lock[ch], flags); spin_lock_irqsave(&priv->chan[ch].tail_lock, flags);
tail = priv->tail[ch]; tail = priv->chan[ch].tail;
while (priv->fifo[ch][tail].desc) { while (priv->chan[ch].fifo[tail].desc) {
request = &priv->fifo[ch][tail]; request = &priv->chan[ch].fifo[tail];
/* descriptors with their done bits set don't get the error */ /* descriptors with their done bits set don't get the error */
rmb(); rmb();
...@@ -354,22 +359,22 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch) ...@@ -354,22 +359,22 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch)
request->desc = NULL; request->desc = NULL;
/* increment fifo tail */ /* increment fifo tail */
priv->tail[ch] = (tail + 1) & (priv->fifo_len - 1); priv->chan[ch].tail = (tail + 1) & (priv->fifo_len - 1);
spin_unlock_irqrestore(&priv->tail_lock[ch], flags); spin_unlock_irqrestore(&priv->chan[ch].tail_lock, flags);
atomic_dec(&priv->submit_count[ch]); atomic_dec(&priv->chan[ch].submit_count);
saved_req.callback(dev, saved_req.desc, saved_req.context, saved_req.callback(dev, saved_req.desc, saved_req.context,
status); status);
/* channel may resume processing in single desc error case */ /* channel may resume processing in single desc error case */
if (error && !reset_ch && status == error) if (error && !reset_ch && status == error)
return; return;
spin_lock_irqsave(&priv->tail_lock[ch], flags); spin_lock_irqsave(&priv->chan[ch].tail_lock, flags);
tail = priv->tail[ch]; tail = priv->chan[ch].tail;
} }
spin_unlock_irqrestore(&priv->tail_lock[ch], flags); spin_unlock_irqrestore(&priv->chan[ch].tail_lock, flags);
} }
/* /*
...@@ -397,20 +402,20 @@ static void talitos_done(unsigned long data) ...@@ -397,20 +402,20 @@ static void talitos_done(unsigned long data)
static struct talitos_desc *current_desc(struct device *dev, int ch) static struct talitos_desc *current_desc(struct device *dev, int ch)
{ {
struct talitos_private *priv = dev_get_drvdata(dev); struct talitos_private *priv = dev_get_drvdata(dev);
int tail = priv->tail[ch]; int tail = priv->chan[ch].tail;
dma_addr_t cur_desc; dma_addr_t cur_desc;
cur_desc = in_be32(priv->reg + TALITOS_CDPR_LO(ch)); cur_desc = in_be32(priv->reg + TALITOS_CDPR_LO(ch));
while (priv->fifo[ch][tail].dma_desc != cur_desc) { while (priv->chan[ch].fifo[tail].dma_desc != cur_desc) {
tail = (tail + 1) & (priv->fifo_len - 1); tail = (tail + 1) & (priv->fifo_len - 1);
if (tail == priv->tail[ch]) { if (tail == priv->chan[ch].tail) {
dev_err(dev, "couldn't locate current descriptor\n"); dev_err(dev, "couldn't locate current descriptor\n");
return NULL; return NULL;
} }
} }
return priv->fifo[ch][tail].desc; return priv->chan[ch].fifo[tail].desc;
} }
/* /*
...@@ -1740,17 +1745,11 @@ static int talitos_remove(struct of_device *ofdev) ...@@ -1740,17 +1745,11 @@ static int talitos_remove(struct of_device *ofdev)
if (hw_supports(dev, DESC_HDR_SEL0_RNG)) if (hw_supports(dev, DESC_HDR_SEL0_RNG))
talitos_unregister_rng(dev); talitos_unregister_rng(dev);
kfree(priv->submit_count); for (i = 0; i < priv->num_channels; i++)
kfree(priv->tail); if (priv->chan[i].fifo)
kfree(priv->head); kfree(priv->chan[i].fifo);
if (priv->fifo)
for (i = 0; i < priv->num_channels; i++)
kfree(priv->fifo[i]);
kfree(priv->fifo); kfree(priv->chan);
kfree(priv->head_lock);
kfree(priv->tail_lock);
if (priv->irq != NO_IRQ) { if (priv->irq != NO_IRQ) {
free_irq(priv->irq, dev); free_irq(priv->irq, dev);
...@@ -1870,58 +1869,34 @@ static int talitos_probe(struct of_device *ofdev, ...@@ -1870,58 +1869,34 @@ static int talitos_probe(struct of_device *ofdev,
if (of_device_is_compatible(np, "fsl,sec2.1")) if (of_device_is_compatible(np, "fsl,sec2.1"))
priv->features |= TALITOS_FTR_HW_AUTH_CHECK; priv->features |= TALITOS_FTR_HW_AUTH_CHECK;
priv->head_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels, priv->chan = kzalloc(sizeof(struct talitos_channel) *
GFP_KERNEL); priv->num_channels, GFP_KERNEL);
priv->tail_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels, if (!priv->chan) {
GFP_KERNEL); dev_err(dev, "failed to allocate channel management space\n");
if (!priv->head_lock || !priv->tail_lock) {
dev_err(dev, "failed to allocate fifo locks\n");
err = -ENOMEM; err = -ENOMEM;
goto err_out; goto err_out;
} }
for (i = 0; i < priv->num_channels; i++) { for (i = 0; i < priv->num_channels; i++) {
spin_lock_init(&priv->head_lock[i]); spin_lock_init(&priv->chan[i].head_lock);
spin_lock_init(&priv->tail_lock[i]); spin_lock_init(&priv->chan[i].tail_lock);
}
priv->fifo = kmalloc(sizeof(struct talitos_request *) *
priv->num_channels, GFP_KERNEL);
if (!priv->fifo) {
dev_err(dev, "failed to allocate request fifo\n");
err = -ENOMEM;
goto err_out;
} }
priv->fifo_len = roundup_pow_of_two(priv->chfifo_len); priv->fifo_len = roundup_pow_of_two(priv->chfifo_len);
for (i = 0; i < priv->num_channels; i++) { for (i = 0; i < priv->num_channels; i++) {
priv->fifo[i] = kzalloc(sizeof(struct talitos_request) * priv->chan[i].fifo = kzalloc(sizeof(struct talitos_request) *
priv->fifo_len, GFP_KERNEL); priv->fifo_len, GFP_KERNEL);
if (!priv->fifo[i]) { if (!priv->chan[i].fifo) {
dev_err(dev, "failed to allocate request fifo %d\n", i); dev_err(dev, "failed to allocate request fifo %d\n", i);
err = -ENOMEM; err = -ENOMEM;
goto err_out; goto err_out;
} }
} }
priv->submit_count = kmalloc(sizeof(atomic_t) * priv->num_channels,
GFP_KERNEL);
if (!priv->submit_count) {
dev_err(dev, "failed to allocate fifo submit count space\n");
err = -ENOMEM;
goto err_out;
}
for (i = 0; i < priv->num_channels; i++) for (i = 0; i < priv->num_channels; i++)
atomic_set(&priv->submit_count[i], -(priv->chfifo_len - 1)); atomic_set(&priv->chan[i].submit_count,
-(priv->chfifo_len - 1));
priv->head = kzalloc(sizeof(int) * priv->num_channels, GFP_KERNEL);
priv->tail = kzalloc(sizeof(int) * priv->num_channels, GFP_KERNEL);
if (!priv->head || !priv->tail) {
dev_err(dev, "failed to allocate request index space\n");
err = -ENOMEM;
goto err_out;
}
/* reset and initialize the h/w */ /* reset and initialize the h/w */
err = init_device(dev); err = init_device(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