Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 283294
b: refs/heads/master
c: c3e337f
h: refs/heads/master
v: v3
  • Loading branch information
Kim Phillips authored and Herbert Xu committed Nov 21, 2011
1 parent 4a4cb6a commit 78649c8
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 73 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: ad42d5fc85383278663ecb58a24f6547ad0ba735
refs/heads/master: c3e337f88a5b3784cb3c806ffd650d06adff1ea5
207 changes: 138 additions & 69 deletions trunk/drivers/crypto/talitos.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ struct talitos_private {
struct device *dev;
struct platform_device *ofdev;
void __iomem *reg;
int irq;
int irq[2];

/* SEC version geometry (from device tree node) */
unsigned int num_channels;
Expand All @@ -146,7 +146,7 @@ struct talitos_private {
atomic_t last_chan ____cacheline_aligned;

/* request callback tasklet */
struct tasklet_struct done_task;
struct tasklet_struct done_task[2];

/* list of registered algorithms */
struct list_head alg_list;
Expand Down Expand Up @@ -226,13 +226,19 @@ static int reset_device(struct device *dev)
{
struct talitos_private *priv = dev_get_drvdata(dev);
unsigned int timeout = TALITOS_TIMEOUT;
u32 mcr = TALITOS_MCR_SWR;

setbits32(priv->reg + TALITOS_MCR, TALITOS_MCR_SWR);
setbits32(priv->reg + TALITOS_MCR, mcr);

while ((in_be32(priv->reg + TALITOS_MCR) & TALITOS_MCR_SWR)
&& --timeout)
cpu_relax();

if (priv->irq[1] != NO_IRQ) {
mcr = TALITOS_MCR_RCA1 | TALITOS_MCR_RCA3;
setbits32(priv->reg + TALITOS_MCR, mcr);
}

if (timeout == 0) {
dev_err(dev, "failed to reset device\n");
return -EIO;
Expand Down Expand Up @@ -401,21 +407,32 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch)
/*
* process completed requests for channels that have done status
*/
static void talitos_done(unsigned long data)
{
struct device *dev = (struct device *)data;
struct talitos_private *priv = dev_get_drvdata(dev);
int ch;

for (ch = 0; ch < priv->num_channels; ch++)
flush_channel(dev, ch, 0, 0);

/* At this point, all completed channels have been processed.
* Unmask done interrupts for channels completed later on.
*/
setbits32(priv->reg + TALITOS_IMR, TALITOS_IMR_INIT);
setbits32(priv->reg + TALITOS_IMR_LO, TALITOS_IMR_LO_INIT);
}
#define DEF_TALITOS_DONE(name, ch_done_mask) \
static void talitos_done_##name(unsigned long data) \
{ \
struct device *dev = (struct device *)data; \
struct talitos_private *priv = dev_get_drvdata(dev); \
\
if (ch_done_mask & 1) \
flush_channel(dev, 0, 0, 0); \
if (priv->num_channels == 1) \
goto out; \
if (ch_done_mask & (1 << 2)) \
flush_channel(dev, 1, 0, 0); \
if (ch_done_mask & (1 << 4)) \
flush_channel(dev, 2, 0, 0); \
if (ch_done_mask & (1 << 6)) \
flush_channel(dev, 3, 0, 0); \
\
out: \
/* At this point, all completed channels have been processed */ \
/* Unmask done interrupts for channels completed later on. */ \
setbits32(priv->reg + TALITOS_IMR, ch_done_mask); \
setbits32(priv->reg + TALITOS_IMR_LO, TALITOS_IMR_LO_INIT); \
}
DEF_TALITOS_DONE(4ch, TALITOS_ISR_4CHDONE)
DEF_TALITOS_DONE(ch0_2, TALITOS_ISR_CH_0_2_DONE)
DEF_TALITOS_DONE(ch1_3, TALITOS_ISR_CH_1_3_DONE)

/*
* locate current (offending) descriptor
Expand Down Expand Up @@ -584,7 +601,7 @@ static void talitos_error(unsigned long data, u32 isr, u32 isr_lo)
}
}
}
if (reset_dev || isr & ~TALITOS_ISR_CHERR || isr_lo) {
if (reset_dev || isr & ~TALITOS_ISR_4CHERR || isr_lo) {
dev_err(dev, "done overflow, internal time out, or rngu error: "
"ISR 0x%08x_%08x\n", isr, isr_lo);

Expand All @@ -597,30 +614,35 @@ static void talitos_error(unsigned long data, u32 isr, u32 isr_lo)
}
}

static irqreturn_t talitos_interrupt(int irq, void *data)
{
struct device *dev = data;
struct talitos_private *priv = dev_get_drvdata(dev);
u32 isr, isr_lo;

isr = in_be32(priv->reg + TALITOS_ISR);
isr_lo = in_be32(priv->reg + TALITOS_ISR_LO);
/* Acknowledge interrupt */
out_be32(priv->reg + TALITOS_ICR, isr);
out_be32(priv->reg + TALITOS_ICR_LO, isr_lo);

if (unlikely((isr & ~TALITOS_ISR_CHDONE) || isr_lo))
talitos_error((unsigned long)data, isr, isr_lo);
else
if (likely(isr & TALITOS_ISR_CHDONE)) {
/* mask further done interrupts. */
clrbits32(priv->reg + TALITOS_IMR, TALITOS_IMR_DONE);
/* done_task will unmask done interrupts at exit */
tasklet_schedule(&priv->done_task);
}

return (isr || isr_lo) ? IRQ_HANDLED : IRQ_NONE;
}
#define DEF_TALITOS_INTERRUPT(name, ch_done_mask, ch_err_mask, tlet) \
static irqreturn_t talitos_interrupt_##name(int irq, void *data) \
{ \
struct device *dev = data; \
struct talitos_private *priv = dev_get_drvdata(dev); \
u32 isr, isr_lo; \
\
isr = in_be32(priv->reg + TALITOS_ISR); \
isr_lo = in_be32(priv->reg + TALITOS_ISR_LO); \
/* Acknowledge interrupt */ \
out_be32(priv->reg + TALITOS_ICR, isr & (ch_done_mask | ch_err_mask)); \
out_be32(priv->reg + TALITOS_ICR_LO, isr_lo); \
\
if (unlikely((isr & ~TALITOS_ISR_4CHDONE) & ch_err_mask || isr_lo)) \
talitos_error((unsigned long)data, isr, isr_lo); \
else \
if (likely(isr & ch_done_mask)) { \
/* mask further done interrupts. */ \
clrbits32(priv->reg + TALITOS_IMR, ch_done_mask); \
/* done_task will unmask done interrupts at exit */ \
tasklet_schedule(&priv->done_task[tlet]); \
} \
\
return (isr & (ch_done_mask | ch_err_mask) || isr_lo) ? IRQ_HANDLED : \
IRQ_NONE; \
}
DEF_TALITOS_INTERRUPT(4ch, TALITOS_ISR_4CHDONE, TALITOS_ISR_4CHERR, 0)
DEF_TALITOS_INTERRUPT(ch0_2, TALITOS_ISR_CH_0_2_DONE, TALITOS_ISR_CH_0_2_ERR, 0)
DEF_TALITOS_INTERRUPT(ch1_3, TALITOS_ISR_CH_1_3_DONE, TALITOS_ISR_CH_1_3_ERR, 1)

/*
* hwrng
Expand Down Expand Up @@ -2558,12 +2580,15 @@ static int talitos_remove(struct platform_device *ofdev)

kfree(priv->chan);

if (priv->irq != NO_IRQ) {
free_irq(priv->irq, dev);
irq_dispose_mapping(priv->irq);
}
for (i = 0; i < 2; i++)
if (priv->irq[i] != NO_IRQ) {
free_irq(priv->irq[i], dev);
irq_dispose_mapping(priv->irq[i]);
}

tasklet_kill(&priv->done_task);
tasklet_kill(&priv->done_task[0]);
if (priv->irq[1] != NO_IRQ)
tasklet_kill(&priv->done_task[1]);

iounmap(priv->reg);

Expand Down Expand Up @@ -2628,6 +2653,54 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev,
return t_alg;
}

static int talitos_probe_irq(struct platform_device *ofdev)
{
struct device *dev = &ofdev->dev;
struct device_node *np = ofdev->dev.of_node;
struct talitos_private *priv = dev_get_drvdata(dev);
int err;

priv->irq[0] = irq_of_parse_and_map(np, 0);
if (priv->irq[0] == NO_IRQ) {
dev_err(dev, "failed to map irq\n");
return -EINVAL;
}

priv->irq[1] = irq_of_parse_and_map(np, 1);

/* get the primary irq line */
if (priv->irq[1] == NO_IRQ) {
err = request_irq(priv->irq[0], talitos_interrupt_4ch, 0,
dev_driver_string(dev), dev);
goto primary_out;
}

err = request_irq(priv->irq[0], talitos_interrupt_ch0_2, 0,
dev_driver_string(dev), dev);
if (err)
goto primary_out;

/* get the secondary irq line */
err = request_irq(priv->irq[1], talitos_interrupt_ch1_3, 0,
dev_driver_string(dev), dev);
if (err) {
dev_err(dev, "failed to request secondary irq\n");
irq_dispose_mapping(priv->irq[1]);
priv->irq[1] = NO_IRQ;
}

return err;

primary_out:
if (err) {
dev_err(dev, "failed to request primary irq\n");
irq_dispose_mapping(priv->irq[0]);
priv->irq[0] = NO_IRQ;
}

return err;
}

static int talitos_probe(struct platform_device *ofdev)
{
struct device *dev = &ofdev->dev;
Expand All @@ -2644,28 +2717,22 @@ static int talitos_probe(struct platform_device *ofdev)

priv->ofdev = ofdev;

tasklet_init(&priv->done_task, talitos_done, (unsigned long)dev);

INIT_LIST_HEAD(&priv->alg_list);

priv->irq = irq_of_parse_and_map(np, 0);

if (priv->irq == NO_IRQ) {
dev_err(dev, "failed to map irq\n");
err = -EINVAL;
err = talitos_probe_irq(ofdev);
if (err)
goto err_out;
}

/* get the irq line */
err = request_irq(priv->irq, talitos_interrupt, 0,
dev_driver_string(dev), dev);
if (err) {
dev_err(dev, "failed to request irq %d\n", priv->irq);
irq_dispose_mapping(priv->irq);
priv->irq = NO_IRQ;
goto err_out;
if (priv->irq[1] == NO_IRQ) {
tasklet_init(&priv->done_task[0], talitos_done_4ch,
(unsigned long)dev);
} else {
tasklet_init(&priv->done_task[0], talitos_done_ch0_2,
(unsigned long)dev);
tasklet_init(&priv->done_task[1], talitos_done_ch1_3,
(unsigned long)dev);
}

INIT_LIST_HEAD(&priv->alg_list);

priv->reg = of_iomap(np, 0);
if (!priv->reg) {
dev_err(dev, "failed to of_iomap\n");
Expand Down Expand Up @@ -2713,9 +2780,11 @@ static int talitos_probe(struct platform_device *ofdev)
goto err_out;
}

for (i = 0; i < priv->num_channels; i++)
priv->chan[i].reg = priv->reg + TALITOS_CH_BASE_OFFSET +
TALITOS_CH_STRIDE * (i + 1);
for (i = 0; i < priv->num_channels; i++) {
priv->chan[i].reg = priv->reg + TALITOS_CH_STRIDE * (i + 1);
if ((priv->irq[1] == NO_IRQ) || !(i & 1))
priv->chan[i].reg += TALITOS_CH_BASE_OFFSET;
}

for (i = 0; i < priv->num_channels; i++) {
spin_lock_init(&priv->chan[i].head_lock);
Expand Down
14 changes: 11 additions & 3 deletions trunk/drivers/crypto/talitos.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,24 @@

/* global register offset addresses */
#define TALITOS_MCR 0x1030 /* master control register */
#define TALITOS_MCR_LO 0x1038
#define TALITOS_MCR_RCA0 (1 << 15) /* remap channel 0 */
#define TALITOS_MCR_RCA1 (1 << 14) /* remap channel 1 */
#define TALITOS_MCR_RCA2 (1 << 13) /* remap channel 2 */
#define TALITOS_MCR_RCA3 (1 << 12) /* remap channel 3 */
#define TALITOS_MCR_SWR 0x1 /* s/w reset */
#define TALITOS_MCR_LO 0x1034
#define TALITOS_IMR 0x1008 /* interrupt mask register */
#define TALITOS_IMR_INIT 0x100ff /* enable channel IRQs */
#define TALITOS_IMR_DONE 0x00055 /* done IRQs */
#define TALITOS_IMR_LO 0x100C
#define TALITOS_IMR_LO_INIT 0x20000 /* allow RNGU error IRQs */
#define TALITOS_ISR 0x1010 /* interrupt status register */
#define TALITOS_ISR_CHERR 0xaa /* channel errors mask */
#define TALITOS_ISR_CHDONE 0x55 /* channel done mask */
#define TALITOS_ISR_4CHERR 0xaa /* 4 channel errors mask */
#define TALITOS_ISR_4CHDONE 0x55 /* 4 channel done mask */
#define TALITOS_ISR_CH_0_2_ERR 0x22 /* channels 0, 2 errors mask */
#define TALITOS_ISR_CH_0_2_DONE 0x11 /* channels 0, 2 done mask */
#define TALITOS_ISR_CH_1_3_ERR 0x88 /* channels 1, 3 errors mask */
#define TALITOS_ISR_CH_1_3_DONE 0x44 /* channels 1, 3 done mask */
#define TALITOS_ISR_LO 0x1014
#define TALITOS_ICR 0x1018 /* interrupt clear register */
#define TALITOS_ICR_LO 0x101C
Expand Down

0 comments on commit 78649c8

Please sign in to comment.