diff options
| -rw-r--r-- | drivers/ata/sata_mv.c | 107 |
1 files changed, 45 insertions, 62 deletions
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index cee78f9e9d1b..97da46a86fdd 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c | |||
| @@ -1693,50 +1693,48 @@ static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp | |||
| 1693 | * LOCKING: | 1693 | * LOCKING: |
| 1694 | * Inherited from caller. | 1694 | * Inherited from caller. |
| 1695 | */ | 1695 | */ |
| 1696 | static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc) | 1696 | static int mv_host_intr(struct ata_host *host, u32 main_cause) |
| 1697 | { | 1697 | { |
| 1698 | struct mv_host_priv *hpriv = host->private_data; | 1698 | struct mv_host_priv *hpriv = host->private_data; |
| 1699 | void __iomem *mmio = hpriv->base; | 1699 | void __iomem *mmio = hpriv->base, *hc_mmio = NULL; |
| 1700 | void __iomem *hc_mmio = mv_hc_base(mmio, hc); | 1700 | u32 hc_irq_cause = 0; |
| 1701 | u32 hc_irq_cause; | 1701 | unsigned int handled = 0, port; |
| 1702 | int port, port0, last_port; | ||
| 1703 | |||
| 1704 | if (hc == 0) | ||
| 1705 | port0 = 0; | ||
| 1706 | else | ||
| 1707 | port0 = MV_PORTS_PER_HC; | ||
| 1708 | |||
| 1709 | if (HAS_PCI(host)) | ||
| 1710 | last_port = port0 + MV_PORTS_PER_HC; | ||
| 1711 | else | ||
| 1712 | last_port = port0 + hpriv->n_ports; | ||
| 1713 | /* we'll need the HC success int register in most cases */ | ||
| 1714 | hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS); | ||
| 1715 | if (!hc_irq_cause) | ||
| 1716 | return; | ||
| 1717 | |||
| 1718 | writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS); | ||
| 1719 | 1702 | ||
| 1720 | VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n", | 1703 | for (port = 0; port < hpriv->n_ports; port++) { |
| 1721 | hc, relevant, hc_irq_cause); | ||
| 1722 | |||
| 1723 | for (port = port0; port < last_port; port++) { | ||
| 1724 | struct ata_port *ap = host->ports[port]; | 1704 | struct ata_port *ap = host->ports[port]; |
| 1725 | struct mv_port_priv *pp; | 1705 | struct mv_port_priv *pp; |
| 1726 | int have_err_bits, hardport, shift; | 1706 | unsigned int shift, hardport, port_cause; |
| 1727 | 1707 | /* | |
| 1728 | if ((!ap) || (ap->flags & ATA_FLAG_DISABLED)) | 1708 | * When we move to the second hc, flag our cached |
| 1709 | * copies of hc_mmio (and hc_irq_cause) as invalid again. | ||
| 1710 | */ | ||
| 1711 | if (port == MV_PORTS_PER_HC) | ||
| 1712 | hc_mmio = NULL; | ||
| 1713 | /* | ||
| 1714 | * Do nothing if port is not interrupting or is disabled: | ||
| 1715 | */ | ||
| 1716 | MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport); | ||
| 1717 | port_cause = (main_cause >> shift) & (DONE_IRQ | ERR_IRQ); | ||
| 1718 | if (!port_cause || !ap || (ap->flags & ATA_FLAG_DISABLED)) | ||
| 1729 | continue; | 1719 | continue; |
| 1720 | /* | ||
| 1721 | * Each hc within the host has its own hc_irq_cause register. | ||
| 1722 | * We defer reading it until we know we need it, right now: | ||
| 1723 | * | ||
| 1724 | * FIXME later: we don't really need to read this register | ||
| 1725 | * (some logic changes required below if we go that way), | ||
| 1726 | * because it doesn't tell us anything new. But we do need | ||
| 1727 | * to write to it, outside the top of this loop, | ||
| 1728 | * to reset the interrupt triggers for next time. | ||
| 1729 | */ | ||
| 1730 | if (!hc_mmio) { | ||
| 1731 | hc_mmio = mv_hc_base_from_port(mmio, port); | ||
| 1732 | hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS); | ||
| 1733 | writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS); | ||
| 1734 | handled = 1; | ||
| 1735 | } | ||
| 1730 | 1736 | ||
| 1731 | pp = ap->private_data; | 1737 | if (unlikely(port_cause & ERR_IRQ)) { |
| 1732 | |||
| 1733 | shift = port << 1; /* (port * 2) */ | ||
| 1734 | if (port >= MV_PORTS_PER_HC) | ||
| 1735 | shift++; /* skip bit 8 in the HC Main IRQ reg */ | ||
| 1736 | |||
| 1737 | have_err_bits = ((ERR_IRQ << shift) & relevant); | ||
| 1738 | |||
| 1739 | if (unlikely(have_err_bits)) { | ||
| 1740 | struct ata_queued_cmd *qc; | 1738 | struct ata_queued_cmd *qc; |
| 1741 | 1739 | ||
| 1742 | qc = ata_qc_from_tag(ap, ap->link.active_tag); | 1740 | qc = ata_qc_from_tag(ap, ap->link.active_tag); |
| @@ -1747,8 +1745,7 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc) | |||
| 1747 | continue; | 1745 | continue; |
| 1748 | } | 1746 | } |
| 1749 | 1747 | ||
| 1750 | hardport = mv_hardport_from_port(port); /* range 0..3 */ | 1748 | pp = ap->private_data; |
| 1751 | |||
| 1752 | if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) { | 1749 | if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) { |
| 1753 | if ((DMA_IRQ << hardport) & hc_irq_cause) | 1750 | if ((DMA_IRQ << hardport) & hc_irq_cause) |
| 1754 | mv_process_crpb_entries(ap, pp); | 1751 | mv_process_crpb_entries(ap, pp); |
| @@ -1757,10 +1754,10 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc) | |||
| 1757 | mv_intr_pio(ap); | 1754 | mv_intr_pio(ap); |
| 1758 | } | 1755 | } |
| 1759 | } | 1756 | } |
| 1760 | VPRINTK("EXIT\n"); | 1757 | return handled; |
| 1761 | } | 1758 | } |
| 1762 | 1759 | ||
| 1763 | static void mv_pci_error(struct ata_host *host, void __iomem *mmio) | 1760 | static int mv_pci_error(struct ata_host *host, void __iomem *mmio) |
| 1764 | { | 1761 | { |
| 1765 | struct mv_host_priv *hpriv = host->private_data; | 1762 | struct mv_host_priv *hpriv = host->private_data; |
| 1766 | struct ata_port *ap; | 1763 | struct ata_port *ap; |
| @@ -1798,6 +1795,7 @@ static void mv_pci_error(struct ata_host *host, void __iomem *mmio) | |||
| 1798 | ata_port_freeze(ap); | 1795 | ata_port_freeze(ap); |
| 1799 | } | 1796 | } |
| 1800 | } | 1797 | } |
| 1798 | return 1; /* handled */ | ||
| 1801 | } | 1799 | } |
| 1802 | 1800 | ||
| 1803 | /** | 1801 | /** |
| @@ -1818,8 +1816,7 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance) | |||
| 1818 | { | 1816 | { |
| 1819 | struct ata_host *host = dev_instance; | 1817 | struct ata_host *host = dev_instance; |
| 1820 | struct mv_host_priv *hpriv = host->private_data; | 1818 | struct mv_host_priv *hpriv = host->private_data; |
| 1821 | unsigned int hc, handled = 0, n_hcs; | 1819 | unsigned int handled = 0; |
| 1822 | void __iomem *mmio = hpriv->base; | ||
| 1823 | u32 main_cause, main_mask; | 1820 | u32 main_cause, main_mask; |
| 1824 | 1821 | ||
| 1825 | spin_lock(&host->lock); | 1822 | spin_lock(&host->lock); |
| @@ -1829,26 +1826,12 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance) | |||
| 1829 | * Deal with cases where we either have nothing pending, or have read | 1826 | * Deal with cases where we either have nothing pending, or have read |
| 1830 | * a bogus register value which can indicate HW removal or PCI fault. | 1827 | * a bogus register value which can indicate HW removal or PCI fault. |
| 1831 | */ | 1828 | */ |
| 1832 | if (!(main_cause & main_mask) || (main_cause == 0xffffffffU)) | 1829 | if ((main_cause & main_mask) && (main_cause != 0xffffffffU)) { |
| 1833 | goto out_unlock; | 1830 | if (unlikely((main_cause & PCI_ERR) && HAS_PCI(host))) |
| 1834 | 1831 | handled = mv_pci_error(host, hpriv->base); | |
| 1835 | n_hcs = mv_get_hc_count(host->ports[0]->flags); | 1832 | else |
| 1836 | 1833 | handled = mv_host_intr(host, main_cause); | |
| 1837 | if (unlikely((main_cause & PCI_ERR) && HAS_PCI(host))) { | ||
| 1838 | mv_pci_error(host, mmio); | ||
| 1839 | handled = 1; | ||
| 1840 | goto out_unlock; /* skip all other HC irq handling */ | ||
| 1841 | } | ||
| 1842 | |||
| 1843 | for (hc = 0; hc < n_hcs; hc++) { | ||
| 1844 | u32 relevant = main_cause & (HC0_IRQ_PEND << (hc * HC_SHIFT)); | ||
| 1845 | if (relevant) { | ||
| 1846 | mv_host_intr(host, relevant, hc); | ||
| 1847 | handled = 1; | ||
| 1848 | } | ||
| 1849 | } | 1834 | } |
| 1850 | |||
| 1851 | out_unlock: | ||
| 1852 | spin_unlock(&host->lock); | 1835 | spin_unlock(&host->lock); |
| 1853 | return IRQ_RETVAL(handled); | 1836 | return IRQ_RETVAL(handled); |
| 1854 | } | 1837 | } |
