mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-29 18:11:20 +00:00
sata_rcar: fix interrupt handling
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
This commit is contained in:
parent
fcce9a35f8
commit
52a2a1087b
1 changed files with 11 additions and 12 deletions
|
@ -619,17 +619,16 @@ static struct ata_port_operations sata_rcar_port_ops = {
|
||||||
.bmdma_status = sata_rcar_bmdma_status,
|
.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 sata_rcar_priv *priv = ap->host->private_data;
|
||||||
struct ata_eh_info *ehi = &ap->link.eh_info;
|
struct ata_eh_info *ehi = &ap->link.eh_info;
|
||||||
int freeze = 0;
|
int freeze = 0;
|
||||||
int handled = 0;
|
|
||||||
u32 serror;
|
u32 serror;
|
||||||
|
|
||||||
serror = ioread32(priv->base + SCRSERR_REG);
|
serror = ioread32(priv->base + SCRSERR_REG);
|
||||||
if (!serror)
|
if (!serror)
|
||||||
return 0;
|
return;
|
||||||
|
|
||||||
DPRINTK("SError @host_intr: 0x%x\n", serror);
|
DPRINTK("SError @host_intr: 0x%x\n", serror);
|
||||||
|
|
||||||
|
@ -642,7 +641,6 @@ static int sata_rcar_serr_interrupt(struct ata_port *ap)
|
||||||
ata_ehi_push_desc(ehi, "%s", "hotplug");
|
ata_ehi_push_desc(ehi, "%s", "hotplug");
|
||||||
|
|
||||||
freeze = serror & SERR_COMM_WAKE ? 0 : 1;
|
freeze = serror & SERR_COMM_WAKE ? 0 : 1;
|
||||||
handled = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* freeze or abort */
|
/* freeze or abort */
|
||||||
|
@ -650,11 +648,9 @@ static int sata_rcar_serr_interrupt(struct ata_port *ap)
|
||||||
ata_port_freeze(ap);
|
ata_port_freeze(ap);
|
||||||
else
|
else
|
||||||
ata_port_abort(ap);
|
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;
|
struct ata_queued_cmd *qc;
|
||||||
int handled = 0;
|
int handled = 0;
|
||||||
|
@ -663,7 +659,9 @@ static int sata_rcar_ata_interrupt(struct ata_port *ap)
|
||||||
if (qc)
|
if (qc)
|
||||||
handled |= ata_bmdma_port_intr(ap, 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)
|
static irqreturn_t sata_rcar_interrupt(int irq, void *dev_instance)
|
||||||
|
@ -678,20 +676,21 @@ static irqreturn_t sata_rcar_interrupt(int irq, void *dev_instance)
|
||||||
spin_lock_irqsave(&host->lock, flags);
|
spin_lock_irqsave(&host->lock, flags);
|
||||||
|
|
||||||
sataintstat = ioread32(priv->base + SATAINTSTAT_REG);
|
sataintstat = ioread32(priv->base + SATAINTSTAT_REG);
|
||||||
|
sataintstat &= SATA_RCAR_INT_MASK;
|
||||||
if (!sataintstat)
|
if (!sataintstat)
|
||||||
goto done;
|
goto done;
|
||||||
/* ack */
|
/* ack */
|
||||||
iowrite32(sataintstat & ~SATA_RCAR_INT_MASK,
|
iowrite32(~sataintstat & 0x7ff, priv->base + SATAINTSTAT_REG);
|
||||||
priv->base + SATAINTSTAT_REG);
|
|
||||||
|
|
||||||
ap = host->ports[0];
|
ap = host->ports[0];
|
||||||
|
|
||||||
if (sataintstat & SATAINTSTAT_ATA)
|
if (sataintstat & SATAINTSTAT_ATA)
|
||||||
handled |= sata_rcar_ata_interrupt(ap);
|
sata_rcar_ata_interrupt(ap);
|
||||||
|
|
||||||
if (sataintstat & SATAINTSTAT_SERR)
|
if (sataintstat & SATAINTSTAT_SERR)
|
||||||
handled |= sata_rcar_serr_interrupt(ap);
|
sata_rcar_serr_interrupt(ap);
|
||||||
|
|
||||||
|
handled = 1;
|
||||||
done:
|
done:
|
||||||
spin_unlock_irqrestore(&host->lock, flags);
|
spin_unlock_irqrestore(&host->lock, flags);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue