* [PATCH v2 0/2] ahci per-port msix support
@ 2015-11-01 18:43 Dan Williams
2015-11-01 18:43 ` [PATCH v2 1/2] ahci: " Dan Williams
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Dan Williams @ 2015-11-01 18:43 UTC (permalink / raw)
To: tj; +Cc: linux-ide
Changes since v1 [1]:
1/ Clean up "nvec = min(nvec, n_ports);" statement (Tejun)
2/ Drop threaded interrupt handling option for now.
[1]: http://marc.info/?l=linux-ide&m=144623970817213&w=2
---
A series of small fixups for ahci implementations that provide multiple
msi-x vectors. The notable changes are needing to maintain support for
the current single-vector msix implementation and disabling threaded
irqs by default.
---
Dan Williams (2):
ahci: per-port msix support
ahci: switch from 'threaded' to 'hardirq' interrupt handling
drivers/ata/ahci.c | 68 +++++++++++++++++++++++++++++++++----------------
drivers/ata/ahci.h | 2 +
drivers/ata/libahci.c | 44 ++++++++++++++++++++++++++------
3 files changed, 84 insertions(+), 30 deletions(-)
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 1/2] ahci: per-port msix support
2015-11-01 18:43 [PATCH v2 0/2] ahci per-port msix support Dan Williams
@ 2015-11-01 18:43 ` Dan Williams
2015-11-01 18:43 ` [PATCH v2 2/2] ahci: switch from 'threaded' to 'hardirq' interrupt handling Dan Williams
2015-11-02 19:23 ` [PATCH v2 0/2] ahci per-port msix support Tejun Heo
2 siblings, 0 replies; 6+ messages in thread
From: Dan Williams @ 2015-11-01 18:43 UTC (permalink / raw)
To: tj; +Cc: linux-ide
From: Dan Williams <dan.j.williamps@intel.com>
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.neri@intel.com>
[ricardo: fix struct msix_entry handling]
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
drivers/ata/ahci.c | 68 +++++++++++++++++++++++++++++++++----------------
drivers/ata/ahci.h | 2 +
drivers/ata/libahci.c | 19 ++++++++++----
3 files changed, 62 insertions(+), 27 deletions(-)
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index a46660204e3a..bda8ec2d1a20 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1292,15 +1292,14 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host)
#endif
/*
- * ahci_init_msix() only implements single MSI-X support, not multiple
- * MSI-X per-port interrupts. This is needed for host controllers that only
- * have MSI-X support implemented, but no MSI or intx.
+ * ahci_init_msix() - optionally enable per-port MSI-X otherwise defer
+ * to single msi.
*/
static int ahci_init_msix(struct pci_dev *pdev, unsigned int n_ports,
- struct ahci_host_priv *hpriv)
+ struct ahci_host_priv *hpriv, unsigned long flags)
{
- int rc, nvec;
- struct msix_entry entry = {};
+ unsigned int nvec, i;
+ int rc;
/* Do not init MSI-X if MSI is disabled for the device */
if (hpriv->flags & AHCI_HFLAG_NO_MSI)
@@ -1310,22 +1309,39 @@ static int ahci_init_msix(struct pci_dev *pdev, unsigned int n_ports,
if (nvec < 0)
return nvec;
- if (!nvec) {
+ /*
+ * Proper MSI-X implementations will have a vector per-port.
+ * Barring that, we prefer single-MSI over single-MSIX. If this
+ * check fails (not enough MSI-X vectors for all ports) we will
+ * be called again with the flag clear iff ahci_init_msi()
+ * fails.
+ */
+ if (flags & AHCI_HFLAG_MULTI_MSIX) {
+ if (nvec < n_ports)
+ return -ENODEV;
+ nvec = n_ports;
+ } else if (nvec) {
+ nvec = 1;
+ } else {
+ /*
+ * Emit dev_err() since this was the non-legacy irq
+ * method of last resort.
+ */
rc = -ENODEV;
goto fail;
}
- /*
- * There can be more than one vector (e.g. for error detection or
- * hdd hotplug). Only the first vector (entry.entry = 0) is used.
- */
- rc = pci_enable_msix_exact(pdev, &entry, 1);
+ for (i = 0; i < nvec; i++)
+ hpriv->msix[i].entry = i;
+ rc = pci_enable_msix_exact(pdev, hpriv->msix, nvec);
if (rc < 0)
goto fail;
- hpriv->irq = entry.vector;
+ if (nvec > 1)
+ hpriv->flags |= AHCI_HFLAG_MULTI_MSIX;
+ hpriv->irq = hpriv->msix[0].vector; /* for single msi-x */
- return 1;
+ return nvec;
fail:
dev_err(&pdev->dev,
"failed to enable MSI-X with error %d, # of vectors: %d\n",
@@ -1389,20 +1405,25 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
{
int nvec;
+ /*
+ * Try to enable per-port MSI-X. If the host is not capable
+ * fall back to single MSI before finally attempting single
+ * MSI-X.
+ */
+ nvec = ahci_init_msix(pdev, n_ports, hpriv, AHCI_HFLAG_MULTI_MSIX);
+ if (nvec >= 0)
+ return nvec;
+
nvec = ahci_init_msi(pdev, n_ports, hpriv);
if (nvec >= 0)
return nvec;
- /*
- * Currently, MSI-X support only implements single IRQ mode and
- * exists for controllers which can't do other types of IRQ. Only
- * set it up if MSI fails.
- */
- nvec = ahci_init_msix(pdev, n_ports, hpriv);
+ /* try single-msix */
+ nvec = ahci_init_msix(pdev, n_ports, hpriv, 0);
if (nvec >= 0)
return nvec;
- /* lagacy intx interrupts */
+ /* legacy intx interrupts */
pci_intx(pdev, 1);
hpriv->irq = pdev->irq;
@@ -1564,7 +1585,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!host)
return -ENOMEM;
host->private_data = hpriv;
-
+ hpriv->msix = devm_kzalloc(&pdev->dev,
+ sizeof(struct msix_entry) * n_ports, GFP_KERNEL);
+ if (!hpriv->msix)
+ return -ENOMEM;
ahci_init_interrupts(pdev, n_ports, hpriv);
if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 5b8e8a0fab48..5ab9d158c90c 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -240,6 +240,7 @@ enum {
AHCI_HFLAG_NO_FBS = (1 << 18), /* no FBS */
AHCI_HFLAG_EDGE_IRQ = (1 << 19), /* HOST_IRQ_STAT behaves as
Edge Triggered */
+ AHCI_HFLAG_MULTI_MSIX = (1 << 20), /* per-port MSI-X */
/* ap->flags bits */
@@ -341,6 +342,7 @@ struct ahci_host_priv {
* the PHY position in this array.
*/
struct phy **phys;
+ struct msix_entry *msix; /* Optional MSI-X support */
unsigned nports; /* Number of ports */
void *plat_data; /* Other platform data */
unsigned int irq; /* interrupt line */
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 373c7b1602ff..c6f098a0435c 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"
@@ -2463,9 +2464,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);
@@ -2477,6 +2479,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) {
@@ -2484,14 +2492,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);
}
@@ -2512,8 +2521,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);
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v2 2/2] ahci: switch from 'threaded' to 'hardirq' interrupt handling
2015-11-01 18:43 [PATCH v2 0/2] ahci per-port msix support Dan Williams
2015-11-01 18:43 ` [PATCH v2 1/2] ahci: " Dan Williams
@ 2015-11-01 18:43 ` Dan Williams
2015-11-02 19:23 ` [PATCH v2 0/2] ahci per-port msix support Tejun Heo
2 siblings, 0 replies; 6+ messages in thread
From: Dan Williams @ 2015-11-01 18:43 UTC (permalink / raw)
To: tj; +Cc: linux-ide
For high frequency I/O the overhead of threaded interrupts impacts
performance. Add an option to make it configurable, with the default
being hardirq.
A quick out-of-the-box test (i.e. no affinity tuning) shows ~10% random
read performance at ~20% less cpu. The cpu wins appear to be from
reduced lock contention.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
drivers/ata/libahci.c | 27 +++++++++++++++++++++++----
1 file changed, 23 insertions(+), 4 deletions(-)
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index c6f098a0435c..f10a702abfb5 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -1826,6 +1826,26 @@ static irqreturn_t ahci_multi_irqs_intr(int irq, void *dev_instance)
return IRQ_WAKE_THREAD;
}
+static irqreturn_t ahci_multi_irqs_intr_hard(int irq, void *dev_instance)
+{
+ struct ata_port *ap = dev_instance;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 status;
+
+ VPRINTK("ENTER\n");
+
+ status = readl(port_mmio + PORT_IRQ_STAT);
+ writel(status, port_mmio + PORT_IRQ_STAT);
+
+ spin_lock(ap->lock);
+ ahci_handle_port_interrupt(ap, port_mmio, status);
+ spin_unlock(ap->lock);
+
+ VPRINTK("EXIT\n");
+
+ return IRQ_HANDLED;
+}
+
static u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked)
{
unsigned int i, handled = 0;
@@ -2492,10 +2512,9 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host,
continue;
}
- rc = devm_request_threaded_irq(host->dev, irq,
- 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);
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v2 0/2] ahci per-port msix support
2015-11-01 18:43 [PATCH v2 0/2] ahci per-port msix support Dan Williams
2015-11-01 18:43 ` [PATCH v2 1/2] ahci: " Dan Williams
2015-11-01 18:43 ` [PATCH v2 2/2] ahci: switch from 'threaded' to 'hardirq' interrupt handling Dan Williams
@ 2015-11-02 19:23 ` Tejun Heo
2015-11-03 22:32 ` Tejun Heo
2 siblings, 1 reply; 6+ messages in thread
From: Tejun Heo @ 2015-11-02 19:23 UTC (permalink / raw)
To: Dan Williams; +Cc: linux-ide
On Sun, Nov 01, 2015 at 01:43:35PM -0500, Dan Williams wrote:
> Changes since v1 [1]:
>
> 1/ Clean up "nvec = min(nvec, n_ports);" statement (Tejun)
>
> 2/ Drop threaded interrupt handling option for now.
>
> [1]: http://marc.info/?l=linux-ide&m=144623970817213&w=2
Applied to libata/for-4.4.
Thanks.
--
tejun
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2 0/2] ahci per-port msix support
2015-11-02 19:23 ` [PATCH v2 0/2] ahci per-port msix support Tejun Heo
@ 2015-11-03 22:32 ` Tejun Heo
2015-11-03 22:35 ` Dan Williams
0 siblings, 1 reply; 6+ messages in thread
From: Tejun Heo @ 2015-11-03 22:32 UTC (permalink / raw)
To: Dan Williams; +Cc: linux-ide
On Mon, Nov 02, 2015 at 02:23:02PM -0500, Tejun Heo wrote:
> On Sun, Nov 01, 2015 at 01:43:35PM -0500, Dan Williams wrote:
> > Changes since v1 [1]:
> >
> > 1/ Clean up "nvec = min(nvec, n_ports);" statement (Tejun)
> >
> > 2/ Drop threaded interrupt handling option for now.
> >
> > [1]: http://marc.info/?l=linux-ide&m=144623970817213&w=2
>
> Applied to libata/for-4.4.
Dan, I got the following build failures from kbuild and reverted the
two patches from for-4.4. It's too late for this merge window anyway.
Let's try the next one.
tree: https://git.kernel.org/pub/scm/linux/kernel/git/tj/libata for-4.4
head: 3758b0e5028c4b5083f2148ddc06b719d73e7627
commit: 6cb1c51aa65039ab3860c9741f9a190b7ab199cb [19/20] ahci: per-port msix support
config: mips-allyesconfig (attached as .config)
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
git checkout 6cb1c51aa65039ab3860c9741f9a190b7ab199cb
# save the attached .config to linux build tree
make.cross ARCH=mips
All errors (new ones prefixed by >>):
drivers/ata/libahci.c: In function 'ahci_host_activate_multi_irqs':
>> drivers/ata/libahci.c:2492:4: error: invalid use of undefined type 'struct msix_entry'
irq = hpriv->msix[i].vector;
^
>> drivers/ata/libahci.c:2492:21: error: dereferencing pointer to incomplete type 'struct msix_entry'
irq = hpriv->msix[i].vector;
^
vim +2492 drivers/ata/libahci.c
2486 */
2487 for (i = 0; i < host->n_ports; i++) {
2488 struct ahci_port_priv *pp = host->ports[i]->private_data;
2489 int irq;
2490
2491 if (hpriv->flags & AHCI_HFLAG_MULTI_MSIX)
> 2492 irq = hpriv->msix[i].vector;
2493 else
2494 irq = hpriv->irq + i;
2495
--
tejun
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2 0/2] ahci per-port msix support
2015-11-03 22:32 ` Tejun Heo
@ 2015-11-03 22:35 ` Dan Williams
0 siblings, 0 replies; 6+ messages in thread
From: Dan Williams @ 2015-11-03 22:35 UTC (permalink / raw)
To: Tejun Heo; +Cc: IDE/ATA development list
On Tue, Nov 3, 2015 at 2:32 PM, Tejun Heo <tj@kernel.org> wrote:
> On Mon, Nov 02, 2015 at 02:23:02PM -0500, Tejun Heo wrote:
>> On Sun, Nov 01, 2015 at 01:43:35PM -0500, Dan Williams wrote:
>> > Changes since v1 [1]:
>> >
>> > 1/ Clean up "nvec = min(nvec, n_ports);" statement (Tejun)
>> >
>> > 2/ Drop threaded interrupt handling option for now.
>> >
>> > [1]: http://marc.info/?l=linux-ide&m=144623970817213&w=2
>>
>> Applied to libata/for-4.4.
>
> Dan, I got the following build failures from kbuild and reverted the
> two patches from for-4.4. It's too late for this merge window anyway.
> Let's try the next one.
>
Ok, I'll resend after -rc1 is sent out.
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2015-11-03 22:35 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-11-01 18:43 [PATCH v2 0/2] ahci per-port msix support Dan Williams
2015-11-01 18:43 ` [PATCH v2 1/2] ahci: " Dan Williams
2015-11-01 18:43 ` [PATCH v2 2/2] ahci: switch from 'threaded' to 'hardirq' interrupt handling Dan Williams
2015-11-02 19:23 ` [PATCH v2 0/2] ahci per-port msix support Tejun Heo
2015-11-03 22:32 ` Tejun Heo
2015-11-03 22:35 ` Dan Williams
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox