Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 511d63cb authored by Horia Geanta's avatar Horia Geanta Committed by Herbert Xu
Browse files

crypto: talitos - properly lock access to global talitos registers



Access to global talitos registers must be protected for the case when
affinities are configured such that primary and secondary talitos irqs
run on different cpus.

Signed-off-by: default avatarHoria Geanta <horia.geanta@freescale.com>
Signed-off-by: default avatarKim Phillips <kim.phillips@freescale.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 75258723
Loading
Loading
Loading
Loading
+17 −3
Original line number Original line Diff line number Diff line
@@ -124,6 +124,9 @@ struct talitos_private {
	void __iomem *reg;
	void __iomem *reg;
	int irq[2];
	int irq[2];


	/* SEC global registers lock  */
	spinlock_t reg_lock ____cacheline_aligned;

	/* SEC version geometry (from device tree node) */
	/* SEC version geometry (from device tree node) */
	unsigned int num_channels;
	unsigned int num_channels;
	unsigned int chfifo_len;
	unsigned int chfifo_len;
@@ -412,6 +415,7 @@ static void talitos_done_##name(unsigned long data) \
{									\
{									\
	struct device *dev = (struct device *)data;			\
	struct device *dev = (struct device *)data;			\
	struct talitos_private *priv = dev_get_drvdata(dev);		\
	struct talitos_private *priv = dev_get_drvdata(dev);		\
	unsigned long flags;						\
									\
									\
	if (ch_done_mask & 1)						\
	if (ch_done_mask & 1)						\
		flush_channel(dev, 0, 0, 0);				\
		flush_channel(dev, 0, 0, 0);				\
@@ -427,8 +431,10 @@ static void talitos_done_##name(unsigned long data) \
out:									\
out:									\
	/* At this point, all completed channels have been processed */	\
	/* At this point, all completed channels have been processed */	\
	/* Unmask done interrupts for channels completed later on. */	\
	/* Unmask done interrupts for channels completed later on. */	\
	spin_lock_irqsave(&priv->reg_lock, flags);			\
	setbits32(priv->reg + TALITOS_IMR, ch_done_mask);		\
	setbits32(priv->reg + TALITOS_IMR, ch_done_mask);		\
	setbits32(priv->reg + TALITOS_IMR_LO, TALITOS_IMR_LO_INIT);	\
	setbits32(priv->reg + TALITOS_IMR_LO, TALITOS_IMR_LO_INIT);	\
	spin_unlock_irqrestore(&priv->reg_lock, flags);			\
}
}
DEF_TALITOS_DONE(4ch, TALITOS_ISR_4CHDONE)
DEF_TALITOS_DONE(4ch, TALITOS_ISR_4CHDONE)
DEF_TALITOS_DONE(ch0_2, TALITOS_ISR_CH_0_2_DONE)
DEF_TALITOS_DONE(ch0_2, TALITOS_ISR_CH_0_2_DONE)
@@ -619,21 +625,27 @@ static irqreturn_t talitos_interrupt_##name(int irq, void *data) \
	struct device *dev = data;					       \
	struct device *dev = data;					       \
	struct talitos_private *priv = dev_get_drvdata(dev);		       \
	struct talitos_private *priv = dev_get_drvdata(dev);		       \
	u32 isr, isr_lo;						       \
	u32 isr, isr_lo;						       \
	unsigned long flags;						       \
									       \
									       \
	spin_lock_irqsave(&priv->reg_lock, flags);			       \
	isr = in_be32(priv->reg + TALITOS_ISR);				       \
	isr = in_be32(priv->reg + TALITOS_ISR);				       \
	isr_lo = in_be32(priv->reg + TALITOS_ISR_LO);			       \
	isr_lo = in_be32(priv->reg + TALITOS_ISR_LO);			       \
	/* Acknowledge interrupt */					       \
	/* Acknowledge interrupt */					       \
	out_be32(priv->reg + TALITOS_ICR, isr & (ch_done_mask | ch_err_mask)); \
	out_be32(priv->reg + TALITOS_ICR, isr & (ch_done_mask | ch_err_mask)); \
	out_be32(priv->reg + TALITOS_ICR_LO, isr_lo);			       \
	out_be32(priv->reg + TALITOS_ICR_LO, isr_lo);			       \
									       \
									       \
	if (unlikely((isr & ~TALITOS_ISR_4CHDONE) & ch_err_mask || isr_lo))    \
	if (unlikely(isr & ch_err_mask || isr_lo)) {			       \
		talitos_error(dev, isr, isr_lo);			       \
		spin_unlock_irqrestore(&priv->reg_lock, flags);		       \
	else								       \
		talitos_error(dev, isr & ch_err_mask, isr_lo);		       \
	}								       \
	else {								       \
		if (likely(isr & ch_done_mask)) {			       \
		if (likely(isr & ch_done_mask)) {			       \
			/* mask further done interrupts. */		       \
			/* mask further done interrupts. */		       \
			clrbits32(priv->reg + TALITOS_IMR, ch_done_mask);      \
			clrbits32(priv->reg + TALITOS_IMR, ch_done_mask);      \
			/* done_task will unmask done interrupts at exit */    \
			/* done_task will unmask done interrupts at exit */    \
			tasklet_schedule(&priv->done_task[tlet]);	       \
			tasklet_schedule(&priv->done_task[tlet]);	       \
		}							       \
		spin_unlock_irqrestore(&priv->reg_lock, flags);		       \
	}								       \
	}								       \
									       \
									       \
	return (isr & (ch_done_mask | ch_err_mask) || isr_lo) ? IRQ_HANDLED :  \
	return (isr & (ch_done_mask | ch_err_mask) || isr_lo) ? IRQ_HANDLED :  \
@@ -2719,6 +2731,8 @@ static int talitos_probe(struct platform_device *ofdev)


	priv->ofdev = ofdev;
	priv->ofdev = ofdev;


	spin_lock_init(&priv->reg_lock);

	err = talitos_probe_irq(ofdev);
	err = talitos_probe_irq(ofdev);
	if (err)
	if (err)
		goto err_out;
		goto err_out;