[ 075/127] sata_rcar: fix interrupt handling

From: Greg Kroah-Hartman
Date: Wed Jun 05 2013 - 17:51:15 EST


3.9-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sergei Shtylyov <sergei.shtylyov@xxxxxxxxxxxxxxxxxx>

commit 52a2a1087b5924de00484f35ef5e2a73f61dbd22 upstream.

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@xxxxxxxxxxxxxxxxxx>
Signed-off-by: Tejun Heo <tj@xxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>

---
drivers/ata/sata_rcar.c | 23 +++++++++++------------
1 file changed, 11 insertions(+), 12 deletions(-)

--- a/drivers/ata/sata_rcar.c
+++ b/drivers/ata/sata_rcar.c
@@ -618,17 +618,16 @@ static struct ata_port_operations sata_r
.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);

@@ -641,7 +640,6 @@ static int sata_rcar_serr_interrupt(stru
ata_ehi_push_desc(ehi, "%s", "hotplug");

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

/* freeze or abort */
@@ -649,11 +647,9 @@ static int sata_rcar_serr_interrupt(stru
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;
@@ -662,7 +658,9 @@ static int sata_rcar_ata_interrupt(struc
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)
@@ -677,20 +675,21 @@ static irqreturn_t sata_rcar_interrupt(i
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);



--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/