diff options
author | Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> | 2013-05-31 18:38:35 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2013-06-02 03:54:45 -0400 |
commit | 52a2a1087b5924de00484f35ef5e2a73f61dbd22 (patch) | |
tree | b1887001bdf51e25024fc288552d6bead78b6f1e /drivers/ata | |
parent | fcce9a35f8faaa1f52236c554ef1b15d99a7537e (diff) |
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
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/sata_rcar.c | 23 |
1 files changed, 11 insertions, 12 deletions
diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c index a8e091aafdde..249c8a289bfd 100644 --- a/drivers/ata/sata_rcar.c +++ b/drivers/ata/sata_rcar.c | |||
@@ -619,17 +619,16 @@ static struct ata_port_operations sata_rcar_port_ops = { | |||
619 | .bmdma_status = sata_rcar_bmdma_status, | 619 | .bmdma_status = sata_rcar_bmdma_status, |
620 | }; | 620 | }; |
621 | 621 | ||
622 | static int sata_rcar_serr_interrupt(struct ata_port *ap) | 622 | static void sata_rcar_serr_interrupt(struct ata_port *ap) |
623 | { | 623 | { |
624 | struct sata_rcar_priv *priv = ap->host->private_data; | 624 | struct sata_rcar_priv *priv = ap->host->private_data; |
625 | struct ata_eh_info *ehi = &ap->link.eh_info; | 625 | struct ata_eh_info *ehi = &ap->link.eh_info; |
626 | int freeze = 0; | 626 | int freeze = 0; |
627 | int handled = 0; | ||
628 | u32 serror; | 627 | u32 serror; |
629 | 628 | ||
630 | serror = ioread32(priv->base + SCRSERR_REG); | 629 | serror = ioread32(priv->base + SCRSERR_REG); |
631 | if (!serror) | 630 | if (!serror) |
632 | return 0; | 631 | return; |
633 | 632 | ||
634 | DPRINTK("SError @host_intr: 0x%x\n", serror); | 633 | DPRINTK("SError @host_intr: 0x%x\n", serror); |
635 | 634 | ||
@@ -642,7 +641,6 @@ static int sata_rcar_serr_interrupt(struct ata_port *ap) | |||
642 | ata_ehi_push_desc(ehi, "%s", "hotplug"); | 641 | ata_ehi_push_desc(ehi, "%s", "hotplug"); |
643 | 642 | ||
644 | freeze = serror & SERR_COMM_WAKE ? 0 : 1; | 643 | freeze = serror & SERR_COMM_WAKE ? 0 : 1; |
645 | handled = 1; | ||
646 | } | 644 | } |
647 | 645 | ||
648 | /* freeze or abort */ | 646 | /* freeze or abort */ |
@@ -650,11 +648,9 @@ static int sata_rcar_serr_interrupt(struct ata_port *ap) | |||
650 | ata_port_freeze(ap); | 648 | ata_port_freeze(ap); |
651 | else | 649 | else |
652 | ata_port_abort(ap); | 650 | ata_port_abort(ap); |
653 | |||
654 | return handled; | ||
655 | } | 651 | } |
656 | 652 | ||
657 | static int sata_rcar_ata_interrupt(struct ata_port *ap) | 653 | static void sata_rcar_ata_interrupt(struct ata_port *ap) |
658 | { | 654 | { |
659 | struct ata_queued_cmd *qc; | 655 | struct ata_queued_cmd *qc; |
660 | int handled = 0; | 656 | int handled = 0; |
@@ -663,7 +659,9 @@ static int sata_rcar_ata_interrupt(struct ata_port *ap) | |||
663 | if (qc) | 659 | if (qc) |
664 | handled |= ata_bmdma_port_intr(ap, qc); | 660 | handled |= ata_bmdma_port_intr(ap, qc); |
665 | 661 | ||
666 | return handled; | 662 | /* be sure to clear ATA interrupt */ |
663 | if (!handled) | ||
664 | sata_rcar_check_status(ap); | ||
667 | } | 665 | } |
668 | 666 | ||
669 | static irqreturn_t sata_rcar_interrupt(int irq, void *dev_instance) | 667 | 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) | |||
678 | spin_lock_irqsave(&host->lock, flags); | 676 | spin_lock_irqsave(&host->lock, flags); |
679 | 677 | ||
680 | sataintstat = ioread32(priv->base + SATAINTSTAT_REG); | 678 | sataintstat = ioread32(priv->base + SATAINTSTAT_REG); |
679 | sataintstat &= SATA_RCAR_INT_MASK; | ||
681 | if (!sataintstat) | 680 | if (!sataintstat) |
682 | goto done; | 681 | goto done; |
683 | /* ack */ | 682 | /* ack */ |
684 | iowrite32(sataintstat & ~SATA_RCAR_INT_MASK, | 683 | iowrite32(~sataintstat & 0x7ff, priv->base + SATAINTSTAT_REG); |
685 | priv->base + SATAINTSTAT_REG); | ||
686 | 684 | ||
687 | ap = host->ports[0]; | 685 | ap = host->ports[0]; |
688 | 686 | ||
689 | if (sataintstat & SATAINTSTAT_ATA) | 687 | if (sataintstat & SATAINTSTAT_ATA) |
690 | handled |= sata_rcar_ata_interrupt(ap); | 688 | sata_rcar_ata_interrupt(ap); |
691 | 689 | ||
692 | if (sataintstat & SATAINTSTAT_SERR) | 690 | if (sataintstat & SATAINTSTAT_SERR) |
693 | handled |= sata_rcar_serr_interrupt(ap); | 691 | sata_rcar_serr_interrupt(ap); |
694 | 692 | ||
693 | handled = 1; | ||
695 | done: | 694 | done: |
696 | spin_unlock_irqrestore(&host->lock, flags); | 695 | spin_unlock_irqrestore(&host->lock, flags); |
697 | 696 | ||