diff options
-rw-r--r-- | drivers/ata/libahci.c | 74 |
1 files changed, 61 insertions, 13 deletions
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 97683e45ab04..3ce3d23e4f97 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c | |||
@@ -1778,15 +1778,16 @@ static void ahci_handle_port_interrupt(struct ata_port *ap, | |||
1778 | } | 1778 | } |
1779 | } | 1779 | } |
1780 | 1780 | ||
1781 | static void ahci_port_intr(struct ata_port *ap) | 1781 | static void ahci_update_intr_status(struct ata_port *ap) |
1782 | { | 1782 | { |
1783 | void __iomem *port_mmio = ahci_port_base(ap); | 1783 | void __iomem *port_mmio = ahci_port_base(ap); |
1784 | struct ahci_port_priv *pp = ap->private_data; | ||
1784 | u32 status; | 1785 | u32 status; |
1785 | 1786 | ||
1786 | status = readl(port_mmio + PORT_IRQ_STAT); | 1787 | status = readl(port_mmio + PORT_IRQ_STAT); |
1787 | writel(status, port_mmio + PORT_IRQ_STAT); | 1788 | writel(status, port_mmio + PORT_IRQ_STAT); |
1788 | 1789 | ||
1789 | ahci_handle_port_interrupt(ap, port_mmio, status); | 1790 | atomic_or(status, &pp->intr_status); |
1790 | } | 1791 | } |
1791 | 1792 | ||
1792 | static irqreturn_t ahci_port_thread_fn(int irq, void *dev_instance) | 1793 | static irqreturn_t ahci_port_thread_fn(int irq, void *dev_instance) |
@@ -1807,6 +1808,34 @@ static irqreturn_t ahci_port_thread_fn(int irq, void *dev_instance) | |||
1807 | return IRQ_HANDLED; | 1808 | return IRQ_HANDLED; |
1808 | } | 1809 | } |
1809 | 1810 | ||
1811 | irqreturn_t ahci_thread_fn(int irq, void *dev_instance) | ||
1812 | { | ||
1813 | struct ata_host *host = dev_instance; | ||
1814 | struct ahci_host_priv *hpriv = host->private_data; | ||
1815 | u32 irq_masked = hpriv->port_map; | ||
1816 | unsigned int i; | ||
1817 | |||
1818 | for (i = 0; i < host->n_ports; i++) { | ||
1819 | struct ata_port *ap; | ||
1820 | |||
1821 | if (!(irq_masked & (1 << i))) | ||
1822 | continue; | ||
1823 | |||
1824 | ap = host->ports[i]; | ||
1825 | if (ap) { | ||
1826 | ahci_port_thread_fn(irq, ap); | ||
1827 | VPRINTK("port %u\n", i); | ||
1828 | } else { | ||
1829 | VPRINTK("port %u (no irq)\n", i); | ||
1830 | if (ata_ratelimit()) | ||
1831 | dev_warn(host->dev, | ||
1832 | "interrupt on disabled port %u\n", i); | ||
1833 | } | ||
1834 | } | ||
1835 | |||
1836 | return IRQ_HANDLED; | ||
1837 | } | ||
1838 | |||
1810 | static irqreturn_t ahci_multi_irqs_intr(int irq, void *dev_instance) | 1839 | static irqreturn_t ahci_multi_irqs_intr(int irq, void *dev_instance) |
1811 | { | 1840 | { |
1812 | struct ata_port *ap = dev_instance; | 1841 | struct ata_port *ap = dev_instance; |
@@ -1856,7 +1885,7 @@ static irqreturn_t ahci_single_irq_intr(int irq, void *dev_instance) | |||
1856 | 1885 | ||
1857 | ap = host->ports[i]; | 1886 | ap = host->ports[i]; |
1858 | if (ap) { | 1887 | if (ap) { |
1859 | ahci_port_intr(ap); | 1888 | ahci_update_intr_status(ap); |
1860 | VPRINTK("port %u\n", i); | 1889 | VPRINTK("port %u\n", i); |
1861 | } else { | 1890 | } else { |
1862 | VPRINTK("port %u (no irq)\n", i); | 1891 | VPRINTK("port %u (no irq)\n", i); |
@@ -1883,7 +1912,7 @@ static irqreturn_t ahci_single_irq_intr(int irq, void *dev_instance) | |||
1883 | 1912 | ||
1884 | VPRINTK("EXIT\n"); | 1913 | VPRINTK("EXIT\n"); |
1885 | 1914 | ||
1886 | return IRQ_RETVAL(handled); | 1915 | return handled ? IRQ_WAKE_THREAD : IRQ_NONE; |
1887 | } | 1916 | } |
1888 | 1917 | ||
1889 | unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) | 1918 | unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) |
@@ -2295,13 +2324,8 @@ static int ahci_port_start(struct ata_port *ap) | |||
2295 | */ | 2324 | */ |
2296 | pp->intr_mask = DEF_PORT_IRQ; | 2325 | pp->intr_mask = DEF_PORT_IRQ; |
2297 | 2326 | ||
2298 | /* | 2327 | spin_lock_init(&pp->lock); |
2299 | * Switch to per-port locking in case each port has its own MSI vector. | 2328 | ap->lock = &pp->lock; |
2300 | */ | ||
2301 | if ((hpriv->flags & AHCI_HFLAG_MULTI_MSI)) { | ||
2302 | spin_lock_init(&pp->lock); | ||
2303 | ap->lock = &pp->lock; | ||
2304 | } | ||
2305 | 2329 | ||
2306 | ap->private_data = pp; | 2330 | ap->private_data = pp; |
2307 | 2331 | ||
@@ -2462,6 +2486,31 @@ out_free_irqs: | |||
2462 | return rc; | 2486 | return rc; |
2463 | } | 2487 | } |
2464 | 2488 | ||
2489 | static int ahci_host_activate_single_irq(struct ata_host *host, int irq, | ||
2490 | struct scsi_host_template *sht) | ||
2491 | { | ||
2492 | int i, rc; | ||
2493 | |||
2494 | rc = ata_host_start(host); | ||
2495 | if (rc) | ||
2496 | return rc; | ||
2497 | |||
2498 | rc = devm_request_threaded_irq(host->dev, irq, ahci_single_irq_intr, | ||
2499 | ahci_thread_fn, IRQF_SHARED, | ||
2500 | dev_driver_string(host->dev), host); | ||
2501 | if (rc) | ||
2502 | return rc; | ||
2503 | |||
2504 | for (i = 0; i < host->n_ports; i++) | ||
2505 | ata_port_desc(host->ports[i], "irq %d", irq); | ||
2506 | |||
2507 | rc = ata_host_register(host, sht); | ||
2508 | if (rc) | ||
2509 | devm_free_irq(host->dev, irq, host); | ||
2510 | |||
2511 | return rc; | ||
2512 | } | ||
2513 | |||
2465 | /** | 2514 | /** |
2466 | * ahci_host_activate - start AHCI host, request IRQs and register it | 2515 | * ahci_host_activate - start AHCI host, request IRQs and register it |
2467 | * @host: target ATA host | 2516 | * @host: target ATA host |
@@ -2487,8 +2536,7 @@ int ahci_host_activate(struct ata_host *host, int irq, | |||
2487 | if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) | 2536 | if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) |
2488 | rc = ahci_host_activate_multi_irqs(host, irq, sht); | 2537 | rc = ahci_host_activate_multi_irqs(host, irq, sht); |
2489 | else | 2538 | else |
2490 | rc = ata_host_activate(host, irq, ahci_single_irq_intr, | 2539 | rc = ahci_host_activate_single_irq(host, irq, sht); |
2491 | IRQF_SHARED, sht); | ||
2492 | return rc; | 2540 | return rc; |
2493 | } | 2541 | } |
2494 | EXPORT_SYMBOL_GPL(ahci_host_activate); | 2542 | EXPORT_SYMBOL_GPL(ahci_host_activate); |