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 | |
| 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
| -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 | ||
