Skip to content

Commit

Permalink
sata_rcar: fix interrupt handling
Browse files Browse the repository at this point in the history
The driver's interrupt handling code is too picky in deciding whether it should
handle an interrupt or not which causes completely unneeded spurious interrupts.
Thus make sata_rcar_{ata|serr}_interrupt() *void*; add ATA status register read
to sata_rcar_ata_interrupt() to clear an unexpected ATA interrupt -- it doesn't
get cleared by writing to the SATAINTSTAT register in the interrupt mode we use.

Also, in sata_rcar_ata_interrupt() we should check SATAINTSTAT register only for
enabled interrupts and we should clear  only those interrupts  that we have read
as active first time around, because else we have  a  race and risk clearing  an
interrupt that  can  occur between read  and write of the  SATAINTSTAT  register
and never registering it...

Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: stable@vger.kernel.org
  • Loading branch information
Sergei Shtylyov authored and Tejun Heo committed Jun 2, 2013
1 parent fcce9a3 commit 52a2a10
Showing 1 changed file with 11 additions and 12 deletions.
23 changes: 11 additions & 12 deletions drivers/ata/sata_rcar.c
Original file line number Diff line number Diff line change
Expand Up @@ -619,17 +619,16 @@ static struct ata_port_operations sata_rcar_port_ops = {
.bmdma_status = sata_rcar_bmdma_status,
};

static int sata_rcar_serr_interrupt(struct ata_port *ap)
static void sata_rcar_serr_interrupt(struct ata_port *ap)
{
struct sata_rcar_priv *priv = ap->host->private_data;
struct ata_eh_info *ehi = &ap->link.eh_info;
int freeze = 0;
int handled = 0;
u32 serror;

serror = ioread32(priv->base + SCRSERR_REG);
if (!serror)
return 0;
return;

DPRINTK("SError @host_intr: 0x%x\n", serror);

Expand All @@ -642,19 +641,16 @@ static int sata_rcar_serr_interrupt(struct ata_port *ap)
ata_ehi_push_desc(ehi, "%s", "hotplug");

freeze = serror & SERR_COMM_WAKE ? 0 : 1;
handled = 1;
}

/* freeze or abort */
if (freeze)
ata_port_freeze(ap);
else
ata_port_abort(ap);

return handled;
}

static int sata_rcar_ata_interrupt(struct ata_port *ap)
static void sata_rcar_ata_interrupt(struct ata_port *ap)
{
struct ata_queued_cmd *qc;
int handled = 0;
Expand All @@ -663,7 +659,9 @@ static int sata_rcar_ata_interrupt(struct ata_port *ap)
if (qc)
handled |= ata_bmdma_port_intr(ap, qc);

return handled;
/* be sure to clear ATA interrupt */
if (!handled)
sata_rcar_check_status(ap);
}

static irqreturn_t sata_rcar_interrupt(int irq, void *dev_instance)
Expand All @@ -678,20 +676,21 @@ static irqreturn_t sata_rcar_interrupt(int irq, void *dev_instance)
spin_lock_irqsave(&host->lock, flags);

sataintstat = ioread32(priv->base + SATAINTSTAT_REG);
sataintstat &= SATA_RCAR_INT_MASK;
if (!sataintstat)
goto done;
/* ack */
iowrite32(sataintstat & ~SATA_RCAR_INT_MASK,
priv->base + SATAINTSTAT_REG);
iowrite32(~sataintstat & 0x7ff, priv->base + SATAINTSTAT_REG);

ap = host->ports[0];

if (sataintstat & SATAINTSTAT_ATA)
handled |= sata_rcar_ata_interrupt(ap);
sata_rcar_ata_interrupt(ap);

if (sataintstat & SATAINTSTAT_SERR)
handled |= sata_rcar_serr_interrupt(ap);
sata_rcar_serr_interrupt(ap);

handled = 1;
done:
spin_unlock_irqrestore(&host->lock, flags);

Expand Down

0 comments on commit 52a2a10

Please sign in to comment.