From d684a90d38e24dcaf95fdb32c83efe05f80d152a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 11 Nov 2015 16:27:33 -0800 Subject: ahci: per-port msix support Some AHCI controllers support per-port MSI-X vectors. At the same time the Linux AHCI driver needs to support one-off architectures that implement a single MSI-X vector for all ports. The heuristic for enabling AHCI ports becomes, in order of preference: 1/ per-port multi-MSI-X 2/ per-port multi-MSI 3/ single MSI 4/ single MSI-X 5/ legacy INTX This all depends on AHCI implementations with potentially broken MSI-X requesting less vectors than the number of ports. If this assumption is violated we will need to start explicitly white-listing AHCI-MSIX implementations. Reported-by: Ricardo Neri [ricardo: fix struct msix_entry handling] Reported-by: kernel test robot Signed-off-by: Dan Williams Signed-off-by: Tejun Heo --- drivers/ata/libahci.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers/ata/libahci.c') diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 096064cd6c52..0a5645fb02f8 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -43,6 +43,7 @@ #include #include #include +#include #include "ahci.h" #include "libata.h" @@ -2470,9 +2471,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); @@ -2484,6 +2486,12 @@ 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; + + if (hpriv->flags & AHCI_HFLAG_MULTI_MSIX) + irq = hpriv->msix[i].vector; + else + irq = hpriv->irq + i; /* Do not receive interrupts sent by dummy ports */ if (!pp) { @@ -2491,14 +2499,15 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host, int irq, continue; } - rc = devm_request_threaded_irq(host->dev, irq + i, + rc = devm_request_threaded_irq(host->dev, irq, ahci_multi_irqs_intr, ahci_port_thread_fn, 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); } @@ -2519,8 +2528,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); -- cgit v1.2.3