diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-01-11 19:33:59 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-01-11 19:33:59 -0800 |
commit | 8c930204ce76eddeb2e1af66a75f0ab2506c76e2 (patch) | |
tree | cdc3f5ac1b799efd1d54200e08848ccf2bfedb41 /drivers/ata/libahci.c | |
parent | 367262c1be4bbf23938175a93eb573b289a00027 (diff) | |
parent | e39b2bb3b72b999a04e8d295882be3255aca5ade (diff) | |
download | lwn-8c930204ce76eddeb2e1af66a75f0ab2506c76e2.tar.gz lwn-8c930204ce76eddeb2e1af66a75f0ab2506c76e2.zip |
Merge branch 'for-4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata
Pull libata updates from Tejun Heo:
"Mostly low level driver specific changes.
Two changes are somewhat noteworthy. First, Dan's patchset to support
per-port msix interrupt handling for ahci, which was tried last cycle
but had to be backed out due to a couple issues, is back and seems to
be working fine. Second, libata exception handling now uses
usleep_range() instead of msleep() for sleeps < 20ms which can make
things snappier in some corner cases"
* 'for-4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata:
libata: skip debounce delay on link resume
ata: ahci_brcmstb: disable DIPM support
ata: ahci_brcmstb: enable support for ALPM
drivers: libata-core: Use usleep_range() instead of msleep() for short sleeps (<20 ms)
sata_sx4: correctly handling failed allocation
ata: ahci_brcmstb: add support for MIPS-based platforms
ahci: qoriq: Adjust the default register values on ls1021a
ahci: qoriq: Update the default Rx watermark value
ahci: qoriq: Adjust the default register values on ls1043a
ahci: compile out msi/msix infrastructure
ata: core: fix irq description on AHCI single irq systems
ata: ahci_brcmstb: remove unused definitions
ata: ahci_brcmstb: add a quirk for MIPS-based platforms
ata: ahci_brcmstb: disable NCQ for MIPS-based platforms
ata: sata_rcar: Remove obsolete platform_device_id entries
sata_rcar: Add compatible string for r8a7795
ahci: kill 'intr_status'
ahci: switch from 'threaded' to 'hardirq' interrupt handling
ahci: per-port msix support
Diffstat (limited to 'drivers/ata/libahci.c')
-rw-r--r-- | drivers/ata/libahci.c | 46 |
1 files changed, 16 insertions, 30 deletions
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 4665512dae44..d61740e78d6d 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -43,6 +43,7 @@ #include <scsi/scsi_host.h> #include <scsi/scsi_cmnd.h> #include <linux/libata.h> +#include <linux/pci.h> #include "ahci.h" #include "libata.h" @@ -1804,41 +1805,24 @@ static void ahci_port_intr(struct ata_port *ap) ahci_handle_port_interrupt(ap, port_mmio, status); } -static irqreturn_t ahci_port_thread_fn(int irq, void *dev_instance) +static irqreturn_t ahci_multi_irqs_intr_hard(int irq, void *dev_instance) { struct ata_port *ap = dev_instance; - struct ahci_port_priv *pp = ap->private_data; void __iomem *port_mmio = ahci_port_base(ap); u32 status; - status = atomic_xchg(&pp->intr_status, 0); - if (!status) - return IRQ_NONE; - - spin_lock_bh(ap->lock); - ahci_handle_port_interrupt(ap, port_mmio, status); - spin_unlock_bh(ap->lock); - - return IRQ_HANDLED; -} - -static irqreturn_t ahci_multi_irqs_intr(int irq, void *dev_instance) -{ - struct ata_port *ap = dev_instance; - void __iomem *port_mmio = ahci_port_base(ap); - struct ahci_port_priv *pp = ap->private_data; - u32 status; - VPRINTK("ENTER\n"); status = readl(port_mmio + PORT_IRQ_STAT); writel(status, port_mmio + PORT_IRQ_STAT); - atomic_or(status, &pp->intr_status); + spin_lock(ap->lock); + ahci_handle_port_interrupt(ap, port_mmio, status); + spin_unlock(ap->lock); VPRINTK("EXIT\n"); - return IRQ_WAKE_THREAD; + return IRQ_HANDLED; } static u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked) @@ -2479,9 +2463,10 @@ void ahci_set_em_messages(struct ahci_host_priv *hpriv, } EXPORT_SYMBOL_GPL(ahci_set_em_messages); -static int ahci_host_activate_multi_irqs(struct ata_host *host, int irq, +static int ahci_host_activate_multi_irqs(struct ata_host *host, struct scsi_host_template *sht) { + struct ahci_host_priv *hpriv = host->private_data; int i, rc; rc = ata_host_start(host); @@ -2493,6 +2478,7 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host, int irq, */ for (i = 0; i < host->n_ports; i++) { struct ahci_port_priv *pp = host->ports[i]->private_data; + int irq = ahci_irq_vector(hpriv, i); /* Do not receive interrupts sent by dummy ports */ if (!pp) { @@ -2500,14 +2486,14 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host, int irq, continue; } - rc = devm_request_threaded_irq(host->dev, irq + i, - ahci_multi_irqs_intr, - ahci_port_thread_fn, 0, - pp->irq_desc, host->ports[i]); + rc = devm_request_irq(host->dev, irq, ahci_multi_irqs_intr_hard, + 0, pp->irq_desc, host->ports[i]); + if (rc) return rc; - ata_port_desc(host->ports[i], "irq %d", irq + i); + ata_port_desc(host->ports[i], "irq %d", irq); } + return ata_host_register(host, sht); } @@ -2528,8 +2514,8 @@ int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht) int irq = hpriv->irq; int rc; - if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) - rc = ahci_host_activate_multi_irqs(host, irq, sht); + if (hpriv->flags & (AHCI_HFLAG_MULTI_MSI | AHCI_HFLAG_MULTI_MSIX)) + rc = ahci_host_activate_multi_irqs(host, sht); else if (hpriv->flags & AHCI_HFLAG_EDGE_IRQ) rc = ata_host_activate(host, irq, ahci_single_edge_irq_intr, IRQF_SHARED, sht); |