diff options
author | Alexander Gordeev <agordeev@redhat.com> | 2014-09-29 12:26:01 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2014-10-06 11:43:36 -0400 |
commit | 227dfb4dbf109596d76a9b842856c4ff68e4efb2 (patch) | |
tree | 21d347c6ee2f4d53fffd158bab63acecd23d9a39 /drivers/ata/libahci.c | |
parent | 5ee1cfd975518bc9cdcd79e0b76552b5ae5c8c1e (diff) |
AHCI: Do not read HOST_IRQ_STAT reg in multi-MSI mode
As described in AHCI v1.0 specification chapter 10.6.2.2
"Multiple MSI Based Messages" generation of interrupts
is not controlled through the HOST_IRQ_STAT register.
Considering MMIO access is expensive remove unnecessary
reading and writing of HOST_IRQ_STAT register.
Further, serializing access to the host data is no longer
needed and the interrupt service routine can avoid competing
on the host lock.
Signed-off-by: Alexander Gordeev <agordeev@redhat.com>
Suggested-by: "Jiang, Dave" <dave.jiang@intel.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: "Jiang, Dave" <dave.jiang@intel.com>
Cc: linux-ide@vger.kernel.org
Diffstat (limited to 'drivers/ata/libahci.c')
-rw-r--r-- | drivers/ata/libahci.c | 67 |
1 files changed, 8 insertions, 59 deletions
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 48175e5bd001..97683e45ab04 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c | |||
@@ -1794,14 +1794,11 @@ static irqreturn_t ahci_port_thread_fn(int irq, void *dev_instance) | |||
1794 | struct ata_port *ap = dev_instance; | 1794 | struct ata_port *ap = dev_instance; |
1795 | struct ahci_port_priv *pp = ap->private_data; | 1795 | struct ahci_port_priv *pp = ap->private_data; |
1796 | void __iomem *port_mmio = ahci_port_base(ap); | 1796 | void __iomem *port_mmio = ahci_port_base(ap); |
1797 | unsigned long flags; | ||
1798 | u32 status; | 1797 | u32 status; |
1799 | 1798 | ||
1800 | spin_lock_irqsave(&ap->host->lock, flags); | 1799 | status = atomic_xchg(&pp->intr_status, 0); |
1801 | status = pp->intr_status; | 1800 | if (!status) |
1802 | if (status) | 1801 | return IRQ_NONE; |
1803 | pp->intr_status = 0; | ||
1804 | spin_unlock_irqrestore(&ap->host->lock, flags); | ||
1805 | 1802 | ||
1806 | spin_lock_bh(ap->lock); | 1803 | spin_lock_bh(ap->lock); |
1807 | ahci_handle_port_interrupt(ap, port_mmio, status); | 1804 | ahci_handle_port_interrupt(ap, port_mmio, status); |
@@ -1810,67 +1807,19 @@ static irqreturn_t ahci_port_thread_fn(int irq, void *dev_instance) | |||
1810 | return IRQ_HANDLED; | 1807 | return IRQ_HANDLED; |
1811 | } | 1808 | } |
1812 | 1809 | ||
1813 | static void ahci_update_intr_status(struct ata_port *ap) | 1810 | static irqreturn_t ahci_multi_irqs_intr(int irq, void *dev_instance) |
1814 | { | 1811 | { |
1812 | struct ata_port *ap = dev_instance; | ||
1815 | void __iomem *port_mmio = ahci_port_base(ap); | 1813 | void __iomem *port_mmio = ahci_port_base(ap); |
1816 | struct ahci_port_priv *pp = ap->private_data; | 1814 | struct ahci_port_priv *pp = ap->private_data; |
1817 | u32 status; | 1815 | u32 status; |
1818 | 1816 | ||
1819 | status = readl(port_mmio + PORT_IRQ_STAT); | ||
1820 | writel(status, port_mmio + PORT_IRQ_STAT); | ||
1821 | |||
1822 | pp->intr_status |= status; | ||
1823 | } | ||
1824 | |||
1825 | static irqreturn_t ahci_multi_irqs_intr(int irq, void *dev_instance) | ||
1826 | { | ||
1827 | struct ata_port *ap_this = dev_instance; | ||
1828 | struct ahci_port_priv *pp = ap_this->private_data; | ||
1829 | struct ata_host *host = ap_this->host; | ||
1830 | struct ahci_host_priv *hpriv = host->private_data; | ||
1831 | void __iomem *mmio = hpriv->mmio; | ||
1832 | unsigned int i; | ||
1833 | u32 irq_stat, irq_masked; | ||
1834 | |||
1835 | VPRINTK("ENTER\n"); | 1817 | VPRINTK("ENTER\n"); |
1836 | 1818 | ||
1837 | spin_lock(&host->lock); | 1819 | status = readl(port_mmio + PORT_IRQ_STAT); |
1838 | 1820 | writel(status, port_mmio + PORT_IRQ_STAT); | |
1839 | irq_stat = readl(mmio + HOST_IRQ_STAT); | ||
1840 | |||
1841 | if (!irq_stat) { | ||
1842 | u32 status = pp->intr_status; | ||
1843 | |||
1844 | spin_unlock(&host->lock); | ||
1845 | |||
1846 | VPRINTK("EXIT\n"); | ||
1847 | |||
1848 | return status ? IRQ_WAKE_THREAD : IRQ_NONE; | ||
1849 | } | ||
1850 | |||
1851 | irq_masked = irq_stat & hpriv->port_map; | ||
1852 | |||
1853 | for (i = 0; i < host->n_ports; i++) { | ||
1854 | struct ata_port *ap; | ||
1855 | |||
1856 | if (!(irq_masked & (1 << i))) | ||
1857 | continue; | ||
1858 | |||
1859 | ap = host->ports[i]; | ||
1860 | if (ap) { | ||
1861 | ahci_update_intr_status(ap); | ||
1862 | VPRINTK("port %u\n", i); | ||
1863 | } else { | ||
1864 | VPRINTK("port %u (no irq)\n", i); | ||
1865 | if (ata_ratelimit()) | ||
1866 | dev_warn(host->dev, | ||
1867 | "interrupt on disabled port %u\n", i); | ||
1868 | } | ||
1869 | } | ||
1870 | |||
1871 | writel(irq_stat, mmio + HOST_IRQ_STAT); | ||
1872 | 1821 | ||
1873 | spin_unlock(&host->lock); | 1822 | atomic_or(status, &pp->intr_status); |
1874 | 1823 | ||
1875 | VPRINTK("EXIT\n"); | 1824 | VPRINTK("EXIT\n"); |
1876 | 1825 | ||