Re: [PATCH v4 -tip 3/3] AHCI: Support multiple MSIs

2012-12-03 Thread Jeff Garzik

On 11/19/2012 10:02 AM, Alexander Gordeev wrote:

Take advantage of multiple MSIs implementation on x86 - on systems with
IRQ remapping AHCI ports not only get assigned separate MSI vectors -
but also separate IRQs. As result, interrupts generated by different
ports could be serviced on different CPUs rather than on a single one.

In cases when number of allocated MSIs is less than requested the Sharing
Last MSI mode does not get used, no matter implemented in hardware or not.
Instead, the driver assumes the advantage of multiple MSIs is negated and
falls back to the single MSI mode as if MRSM bit was set (some Intel chips
implement this strategy anyway - MRSM bit gets set even if the number of
allocated MSIs exceeds the number of implemented ports).

Signed-off-by: Alexander Gordeev 
---
  drivers/ata/ahci.c|   93 +--
  drivers/ata/ahci.h|6 +++
  drivers/ata/libahci.c |  118 ++---
  3 files changed, 207 insertions(+), 10 deletions(-)


Acked-by: Jeff Garzik 



--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v4 -tip 3/3] AHCI: Support multiple MSIs

2012-12-03 Thread Jeff Garzik

On 11/19/2012 10:02 AM, Alexander Gordeev wrote:

Take advantage of multiple MSIs implementation on x86 - on systems with
IRQ remapping AHCI ports not only get assigned separate MSI vectors -
but also separate IRQs. As result, interrupts generated by different
ports could be serviced on different CPUs rather than on a single one.

In cases when number of allocated MSIs is less than requested the Sharing
Last MSI mode does not get used, no matter implemented in hardware or not.
Instead, the driver assumes the advantage of multiple MSIs is negated and
falls back to the single MSI mode as if MRSM bit was set (some Intel chips
implement this strategy anyway - MRSM bit gets set even if the number of
allocated MSIs exceeds the number of implemented ports).

Signed-off-by: Alexander Gordeev agord...@redhat.com
---
  drivers/ata/ahci.c|   93 +--
  drivers/ata/ahci.h|6 +++
  drivers/ata/libahci.c |  118 ++---
  3 files changed, 207 insertions(+), 10 deletions(-)


Acked-by: Jeff Garzik jgar...@redhat.com



--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v4 -tip 3/3] AHCI: Support multiple MSIs

2012-11-19 Thread Alexander Gordeev
Take advantage of multiple MSIs implementation on x86 - on systems with
IRQ remapping AHCI ports not only get assigned separate MSI vectors -
but also separate IRQs. As result, interrupts generated by different
ports could be serviced on different CPUs rather than on a single one.

In cases when number of allocated MSIs is less than requested the Sharing
Last MSI mode does not get used, no matter implemented in hardware or not.
Instead, the driver assumes the advantage of multiple MSIs is negated and
falls back to the single MSI mode as if MRSM bit was set (some Intel chips
implement this strategy anyway - MRSM bit gets set even if the number of
allocated MSIs exceeds the number of implemented ports).

Signed-off-by: Alexander Gordeev 
---
 drivers/ata/ahci.c|   93 +--
 drivers/ata/ahci.h|6 +++
 drivers/ata/libahci.c |  118 ++---
 3 files changed, 207 insertions(+), 10 deletions(-)

diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 7862d17..29ed8a8 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1057,6 +1057,86 @@ static inline void ahci_gtf_filter_workaround(struct 
ata_host *host)
 {}
 #endif
 
+int ahci_init_interrupts(struct pci_dev *pdev, struct ahci_host_priv *hpriv)
+{
+   int rc;
+   unsigned int maxvec;
+
+   if (!(hpriv->flags & AHCI_HFLAG_NO_MSI)) {
+   rc = pci_enable_msi_block_auto(pdev, );
+   if (rc > 0) {
+   if ((rc == maxvec) || (rc == 1))
+   return rc;
+   /*
+* Assume that advantage of multipe MSIs is negated,
+* so fallback to single MSI mode to save resources
+*/
+   pci_disable_msi(pdev);
+   if (!pci_enable_msi(pdev))
+   return 1;
+   }
+   }
+
+   pci_intx(pdev, 1);
+   return 0;
+}
+
+/**
+ * ahci_host_activate - start AHCI host, request IRQs and register it
+ * @host: target ATA host
+ * @irq: base IRQ number to request
+ * @n_msis: number of MSIs allocated for this host
+ * @irq_handler: irq_handler used when requesting IRQs
+ * @irq_flags: irq_flags used when requesting IRQs
+ *
+ * Similar to ata_host_activate, but requests IRQs according to AHCI-1.1
+ * when multiple MSIs were allocated. That is one MSI per port, starting
+ * from @irq.
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis)
+{
+   int i, rc;
+
+   /* Sharing Last Message among several ports is not supported */
+   if (n_msis < host->n_ports)
+   return -EINVAL;
+
+   rc = ata_host_start(host);
+   if (rc)
+   return rc;
+
+   for (i = 0; i < host->n_ports; i++) {
+   rc = devm_request_threaded_irq(host->dev,
+   irq + i, ahci_hw_interrupt, ahci_thread_fn, IRQF_SHARED,
+   dev_driver_string(host->dev), host->ports[i]);
+   if (rc)
+   goto out_free_irqs;
+   }
+
+   for (i = 0; i < host->n_ports; i++)
+   ata_port_desc(host->ports[i], "irq %d", irq + i);
+
+   rc = ata_host_register(host, _sht);
+   if (rc)
+   goto out_free_all_irqs;
+
+   return 0;
+
+out_free_all_irqs:
+   i = host->n_ports;
+out_free_irqs:
+   for (i--; i >= 0; i--)
+   devm_free_irq(host->dev, irq + i, host->ports[i]);
+
+   return rc;
+}
+
 static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
unsigned int board_id = ent->driver_data;
@@ -1065,7 +1145,7 @@ static int ahci_init_one(struct pci_dev *pdev, const 
struct pci_device_id *ent)
struct device *dev = >dev;
struct ahci_host_priv *hpriv;
struct ata_host *host;
-   int n_ports, i, rc;
+   int n_ports, n_msis, i, rc;
int ahci_pci_bar = AHCI_PCI_BAR_STANDARD;
 
VPRINTK("ENTER\n");
@@ -1150,11 +1230,12 @@ static int ahci_init_one(struct pci_dev *pdev, const 
struct pci_device_id *ent)
if (ahci_sb600_enable_64bit(pdev))
hpriv->flags &= ~AHCI_HFLAG_32BIT_ONLY;
 
-   if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
-   pci_intx(pdev, 1);
-
hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar];
 
+   n_msis = ahci_init_interrupts(pdev, hpriv);
+   if (n_msis > 1)
+   hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
+
/* save initial config */
ahci_pci_save_initial_config(pdev, hpriv);
 
@@ -1250,6 +1331,10 @@ static int ahci_init_one(struct pci_dev *pdev, const 
struct pci_device_id *ent)
ahci_pci_print_info(host);
 
pci_set_master(pdev);
+
+   

[PATCH v4 -tip 3/3] AHCI: Support multiple MSIs

2012-11-19 Thread Alexander Gordeev
Take advantage of multiple MSIs implementation on x86 - on systems with
IRQ remapping AHCI ports not only get assigned separate MSI vectors -
but also separate IRQs. As result, interrupts generated by different
ports could be serviced on different CPUs rather than on a single one.

In cases when number of allocated MSIs is less than requested the Sharing
Last MSI mode does not get used, no matter implemented in hardware or not.
Instead, the driver assumes the advantage of multiple MSIs is negated and
falls back to the single MSI mode as if MRSM bit was set (some Intel chips
implement this strategy anyway - MRSM bit gets set even if the number of
allocated MSIs exceeds the number of implemented ports).

Signed-off-by: Alexander Gordeev agord...@redhat.com
---
 drivers/ata/ahci.c|   93 +--
 drivers/ata/ahci.h|6 +++
 drivers/ata/libahci.c |  118 ++---
 3 files changed, 207 insertions(+), 10 deletions(-)

diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 7862d17..29ed8a8 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1057,6 +1057,86 @@ static inline void ahci_gtf_filter_workaround(struct 
ata_host *host)
 {}
 #endif
 
+int ahci_init_interrupts(struct pci_dev *pdev, struct ahci_host_priv *hpriv)
+{
+   int rc;
+   unsigned int maxvec;
+
+   if (!(hpriv-flags  AHCI_HFLAG_NO_MSI)) {
+   rc = pci_enable_msi_block_auto(pdev, maxvec);
+   if (rc  0) {
+   if ((rc == maxvec) || (rc == 1))
+   return rc;
+   /*
+* Assume that advantage of multipe MSIs is negated,
+* so fallback to single MSI mode to save resources
+*/
+   pci_disable_msi(pdev);
+   if (!pci_enable_msi(pdev))
+   return 1;
+   }
+   }
+
+   pci_intx(pdev, 1);
+   return 0;
+}
+
+/**
+ * ahci_host_activate - start AHCI host, request IRQs and register it
+ * @host: target ATA host
+ * @irq: base IRQ number to request
+ * @n_msis: number of MSIs allocated for this host
+ * @irq_handler: irq_handler used when requesting IRQs
+ * @irq_flags: irq_flags used when requesting IRQs
+ *
+ * Similar to ata_host_activate, but requests IRQs according to AHCI-1.1
+ * when multiple MSIs were allocated. That is one MSI per port, starting
+ * from @irq.
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis)
+{
+   int i, rc;
+
+   /* Sharing Last Message among several ports is not supported */
+   if (n_msis  host-n_ports)
+   return -EINVAL;
+
+   rc = ata_host_start(host);
+   if (rc)
+   return rc;
+
+   for (i = 0; i  host-n_ports; i++) {
+   rc = devm_request_threaded_irq(host-dev,
+   irq + i, ahci_hw_interrupt, ahci_thread_fn, IRQF_SHARED,
+   dev_driver_string(host-dev), host-ports[i]);
+   if (rc)
+   goto out_free_irqs;
+   }
+
+   for (i = 0; i  host-n_ports; i++)
+   ata_port_desc(host-ports[i], irq %d, irq + i);
+
+   rc = ata_host_register(host, ahci_sht);
+   if (rc)
+   goto out_free_all_irqs;
+
+   return 0;
+
+out_free_all_irqs:
+   i = host-n_ports;
+out_free_irqs:
+   for (i--; i = 0; i--)
+   devm_free_irq(host-dev, irq + i, host-ports[i]);
+
+   return rc;
+}
+
 static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
unsigned int board_id = ent-driver_data;
@@ -1065,7 +1145,7 @@ static int ahci_init_one(struct pci_dev *pdev, const 
struct pci_device_id *ent)
struct device *dev = pdev-dev;
struct ahci_host_priv *hpriv;
struct ata_host *host;
-   int n_ports, i, rc;
+   int n_ports, n_msis, i, rc;
int ahci_pci_bar = AHCI_PCI_BAR_STANDARD;
 
VPRINTK(ENTER\n);
@@ -1150,11 +1230,12 @@ static int ahci_init_one(struct pci_dev *pdev, const 
struct pci_device_id *ent)
if (ahci_sb600_enable_64bit(pdev))
hpriv-flags = ~AHCI_HFLAG_32BIT_ONLY;
 
-   if ((hpriv-flags  AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
-   pci_intx(pdev, 1);
-
hpriv-mmio = pcim_iomap_table(pdev)[ahci_pci_bar];
 
+   n_msis = ahci_init_interrupts(pdev, hpriv);
+   if (n_msis  1)
+   hpriv-flags |= AHCI_HFLAG_MULTI_MSI;
+
/* save initial config */
ahci_pci_save_initial_config(pdev, hpriv);
 
@@ -1250,6 +1331,10 @@ static int ahci_init_one(struct pci_dev *pdev, const 
struct pci_device_id *ent)
ahci_pci_print_info(host);
 
pci_set_master(pdev);
+

Re: [PATCH v4 -tip 3/3] AHCI: Support multiple MSIs

2012-11-09 Thread Alexander Gordeev
On Thu, Oct 25, 2012 at 11:36:26AM +0200, Alexander Gordeev wrote:
> On Thu, Oct 25, 2012 at 11:25:55AM +0200, Alexander Gordeev wrote:
> > On Thu, Oct 25, 2012 at 11:09:57AM +0200, Ingo Molnar wrote:
> > > Has Jeff acked this patch?
> > 
> > Yep,
> > http://lkml.indiana.edu/hypermail/linux/kernel/1210.0/00795.html
> 
> Ah.. sorry - Jeff acked v3, not the recent one.
> Jeff, would you keep your ack for this patch?

Hi Jeff,

Could you please review this patch?

-- 
Regards,
Alexander Gordeev
agord...@redhat.com
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v4 -tip 3/3] AHCI: Support multiple MSIs

2012-11-09 Thread Alexander Gordeev
On Thu, Oct 25, 2012 at 11:36:26AM +0200, Alexander Gordeev wrote:
 On Thu, Oct 25, 2012 at 11:25:55AM +0200, Alexander Gordeev wrote:
  On Thu, Oct 25, 2012 at 11:09:57AM +0200, Ingo Molnar wrote:
   Has Jeff acked this patch?
  
  Yep,
  http://lkml.indiana.edu/hypermail/linux/kernel/1210.0/00795.html
 
 Ah.. sorry - Jeff acked v3, not the recent one.
 Jeff, would you keep your ack for this patch?

Hi Jeff,

Could you please review this patch?

-- 
Regards,
Alexander Gordeev
agord...@redhat.com
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v4 -tip 3/3] AHCI: Support multiple MSIs

2012-10-25 Thread Alexander Gordeev
On Thu, Oct 25, 2012 at 11:25:55AM +0200, Alexander Gordeev wrote:
> On Thu, Oct 25, 2012 at 11:09:57AM +0200, Ingo Molnar wrote:
> > Has Jeff acked this patch?
> 
> Yep,
> http://lkml.indiana.edu/hypermail/linux/kernel/1210.0/00795.html

Ah.. sorry - Jeff acked v3, not the recent one.
Jeff, would you keep your ack for this patch?

-- 
Regards,
Alexander Gordeev
agord...@redhat.com
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v4 -tip 3/3] AHCI: Support multiple MSIs

2012-10-25 Thread Alexander Gordeev
On Thu, Oct 25, 2012 at 11:09:57AM +0200, Ingo Molnar wrote:
> Has Jeff acked this patch?

Yep,
http://lkml.indiana.edu/hypermail/linux/kernel/1210.0/00795.html

-- 
Regards,
Alexander Gordeev
agord...@redhat.com
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v4 -tip 3/3] AHCI: Support multiple MSIs

2012-10-25 Thread Ingo Molnar

* Alexander Gordeev  wrote:

> Take advantage of multiple MSIs implementation on x86 - on systems with
> IRQ remapping AHCI ports not only get assigned separate MSI vectors -
> but also separate IRQs. As result, interrupts generated by different
> ports could be serviced on different CPUs rather than on a single one.
> 
> In cases when number of allocated MSIs is less than requested the Sharing
> Last MSI mode does not get used, no matter implemented in hardware or not.
> Instead, the driver assumes the advantage of multiple MSIs is negated and
> falls back to the single MSI mode as if MRSM bit was set (some Intel chips
> implement this strategy anyway - MRSM bit gets set even if the number of
> allocated MSIs exceeds the number of implemented ports).
> 
> Signed-off-by: Alexander Gordeev 
> ---
>  drivers/ata/ahci.c|   93 +--
>  drivers/ata/ahci.h|6 +++
>  drivers/ata/libahci.c |  118 
> ++---
>  3 files changed, 207 insertions(+), 10 deletions(-)

Has Jeff acked this patch?

Thanks,

Ingo
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v4 -tip 3/3] AHCI: Support multiple MSIs

2012-10-25 Thread Alexander Gordeev
Take advantage of multiple MSIs implementation on x86 - on systems with
IRQ remapping AHCI ports not only get assigned separate MSI vectors -
but also separate IRQs. As result, interrupts generated by different
ports could be serviced on different CPUs rather than on a single one.

In cases when number of allocated MSIs is less than requested the Sharing
Last MSI mode does not get used, no matter implemented in hardware or not.
Instead, the driver assumes the advantage of multiple MSIs is negated and
falls back to the single MSI mode as if MRSM bit was set (some Intel chips
implement this strategy anyway - MRSM bit gets set even if the number of
allocated MSIs exceeds the number of implemented ports).

Signed-off-by: Alexander Gordeev 
---
 drivers/ata/ahci.c|   93 +--
 drivers/ata/ahci.h|6 +++
 drivers/ata/libahci.c |  118 ++---
 3 files changed, 207 insertions(+), 10 deletions(-)

diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 7862d17..29ed8a8 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1057,6 +1057,86 @@ static inline void ahci_gtf_filter_workaround(struct 
ata_host *host)
 {}
 #endif
 
+int ahci_init_interrupts(struct pci_dev *pdev, struct ahci_host_priv *hpriv)
+{
+   int rc;
+   unsigned int maxvec;
+
+   if (!(hpriv->flags & AHCI_HFLAG_NO_MSI)) {
+   rc = pci_enable_msi_block_auto(pdev, );
+   if (rc > 0) {
+   if ((rc == maxvec) || (rc == 1))
+   return rc;
+   /*
+* Assume that advantage of multipe MSIs is negated,
+* so fallback to single MSI mode to save resources
+*/
+   pci_disable_msi(pdev);
+   if (!pci_enable_msi(pdev))
+   return 1;
+   }
+   }
+
+   pci_intx(pdev, 1);
+   return 0;
+}
+
+/**
+ * ahci_host_activate - start AHCI host, request IRQs and register it
+ * @host: target ATA host
+ * @irq: base IRQ number to request
+ * @n_msis: number of MSIs allocated for this host
+ * @irq_handler: irq_handler used when requesting IRQs
+ * @irq_flags: irq_flags used when requesting IRQs
+ *
+ * Similar to ata_host_activate, but requests IRQs according to AHCI-1.1
+ * when multiple MSIs were allocated. That is one MSI per port, starting
+ * from @irq.
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis)
+{
+   int i, rc;
+
+   /* Sharing Last Message among several ports is not supported */
+   if (n_msis < host->n_ports)
+   return -EINVAL;
+
+   rc = ata_host_start(host);
+   if (rc)
+   return rc;
+
+   for (i = 0; i < host->n_ports; i++) {
+   rc = devm_request_threaded_irq(host->dev,
+   irq + i, ahci_hw_interrupt, ahci_thread_fn, IRQF_SHARED,
+   dev_driver_string(host->dev), host->ports[i]);
+   if (rc)
+   goto out_free_irqs;
+   }
+
+   for (i = 0; i < host->n_ports; i++)
+   ata_port_desc(host->ports[i], "irq %d", irq + i);
+
+   rc = ata_host_register(host, _sht);
+   if (rc)
+   goto out_free_all_irqs;
+
+   return 0;
+
+out_free_all_irqs:
+   i = host->n_ports;
+out_free_irqs:
+   for (i--; i >= 0; i--)
+   devm_free_irq(host->dev, irq + i, host->ports[i]);
+
+   return rc;
+}
+
 static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
unsigned int board_id = ent->driver_data;
@@ -1065,7 +1145,7 @@ static int ahci_init_one(struct pci_dev *pdev, const 
struct pci_device_id *ent)
struct device *dev = >dev;
struct ahci_host_priv *hpriv;
struct ata_host *host;
-   int n_ports, i, rc;
+   int n_ports, n_msis, i, rc;
int ahci_pci_bar = AHCI_PCI_BAR_STANDARD;
 
VPRINTK("ENTER\n");
@@ -1150,11 +1230,12 @@ static int ahci_init_one(struct pci_dev *pdev, const 
struct pci_device_id *ent)
if (ahci_sb600_enable_64bit(pdev))
hpriv->flags &= ~AHCI_HFLAG_32BIT_ONLY;
 
-   if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
-   pci_intx(pdev, 1);
-
hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar];
 
+   n_msis = ahci_init_interrupts(pdev, hpriv);
+   if (n_msis > 1)
+   hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
+
/* save initial config */
ahci_pci_save_initial_config(pdev, hpriv);
 
@@ -1250,6 +1331,10 @@ static int ahci_init_one(struct pci_dev *pdev, const 
struct pci_device_id *ent)
ahci_pci_print_info(host);
 
pci_set_master(pdev);
+
+   

[PATCH v4 -tip 3/3] AHCI: Support multiple MSIs

2012-10-25 Thread Alexander Gordeev
Take advantage of multiple MSIs implementation on x86 - on systems with
IRQ remapping AHCI ports not only get assigned separate MSI vectors -
but also separate IRQs. As result, interrupts generated by different
ports could be serviced on different CPUs rather than on a single one.

In cases when number of allocated MSIs is less than requested the Sharing
Last MSI mode does not get used, no matter implemented in hardware or not.
Instead, the driver assumes the advantage of multiple MSIs is negated and
falls back to the single MSI mode as if MRSM bit was set (some Intel chips
implement this strategy anyway - MRSM bit gets set even if the number of
allocated MSIs exceeds the number of implemented ports).

Signed-off-by: Alexander Gordeev agord...@redhat.com
---
 drivers/ata/ahci.c|   93 +--
 drivers/ata/ahci.h|6 +++
 drivers/ata/libahci.c |  118 ++---
 3 files changed, 207 insertions(+), 10 deletions(-)

diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 7862d17..29ed8a8 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1057,6 +1057,86 @@ static inline void ahci_gtf_filter_workaround(struct 
ata_host *host)
 {}
 #endif
 
+int ahci_init_interrupts(struct pci_dev *pdev, struct ahci_host_priv *hpriv)
+{
+   int rc;
+   unsigned int maxvec;
+
+   if (!(hpriv-flags  AHCI_HFLAG_NO_MSI)) {
+   rc = pci_enable_msi_block_auto(pdev, maxvec);
+   if (rc  0) {
+   if ((rc == maxvec) || (rc == 1))
+   return rc;
+   /*
+* Assume that advantage of multipe MSIs is negated,
+* so fallback to single MSI mode to save resources
+*/
+   pci_disable_msi(pdev);
+   if (!pci_enable_msi(pdev))
+   return 1;
+   }
+   }
+
+   pci_intx(pdev, 1);
+   return 0;
+}
+
+/**
+ * ahci_host_activate - start AHCI host, request IRQs and register it
+ * @host: target ATA host
+ * @irq: base IRQ number to request
+ * @n_msis: number of MSIs allocated for this host
+ * @irq_handler: irq_handler used when requesting IRQs
+ * @irq_flags: irq_flags used when requesting IRQs
+ *
+ * Similar to ata_host_activate, but requests IRQs according to AHCI-1.1
+ * when multiple MSIs were allocated. That is one MSI per port, starting
+ * from @irq.
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis)
+{
+   int i, rc;
+
+   /* Sharing Last Message among several ports is not supported */
+   if (n_msis  host-n_ports)
+   return -EINVAL;
+
+   rc = ata_host_start(host);
+   if (rc)
+   return rc;
+
+   for (i = 0; i  host-n_ports; i++) {
+   rc = devm_request_threaded_irq(host-dev,
+   irq + i, ahci_hw_interrupt, ahci_thread_fn, IRQF_SHARED,
+   dev_driver_string(host-dev), host-ports[i]);
+   if (rc)
+   goto out_free_irqs;
+   }
+
+   for (i = 0; i  host-n_ports; i++)
+   ata_port_desc(host-ports[i], irq %d, irq + i);
+
+   rc = ata_host_register(host, ahci_sht);
+   if (rc)
+   goto out_free_all_irqs;
+
+   return 0;
+
+out_free_all_irqs:
+   i = host-n_ports;
+out_free_irqs:
+   for (i--; i = 0; i--)
+   devm_free_irq(host-dev, irq + i, host-ports[i]);
+
+   return rc;
+}
+
 static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
unsigned int board_id = ent-driver_data;
@@ -1065,7 +1145,7 @@ static int ahci_init_one(struct pci_dev *pdev, const 
struct pci_device_id *ent)
struct device *dev = pdev-dev;
struct ahci_host_priv *hpriv;
struct ata_host *host;
-   int n_ports, i, rc;
+   int n_ports, n_msis, i, rc;
int ahci_pci_bar = AHCI_PCI_BAR_STANDARD;
 
VPRINTK(ENTER\n);
@@ -1150,11 +1230,12 @@ static int ahci_init_one(struct pci_dev *pdev, const 
struct pci_device_id *ent)
if (ahci_sb600_enable_64bit(pdev))
hpriv-flags = ~AHCI_HFLAG_32BIT_ONLY;
 
-   if ((hpriv-flags  AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
-   pci_intx(pdev, 1);
-
hpriv-mmio = pcim_iomap_table(pdev)[ahci_pci_bar];
 
+   n_msis = ahci_init_interrupts(pdev, hpriv);
+   if (n_msis  1)
+   hpriv-flags |= AHCI_HFLAG_MULTI_MSI;
+
/* save initial config */
ahci_pci_save_initial_config(pdev, hpriv);
 
@@ -1250,6 +1331,10 @@ static int ahci_init_one(struct pci_dev *pdev, const 
struct pci_device_id *ent)
ahci_pci_print_info(host);
 
pci_set_master(pdev);
+

Re: [PATCH v4 -tip 3/3] AHCI: Support multiple MSIs

2012-10-25 Thread Ingo Molnar

* Alexander Gordeev agord...@redhat.com wrote:

 Take advantage of multiple MSIs implementation on x86 - on systems with
 IRQ remapping AHCI ports not only get assigned separate MSI vectors -
 but also separate IRQs. As result, interrupts generated by different
 ports could be serviced on different CPUs rather than on a single one.
 
 In cases when number of allocated MSIs is less than requested the Sharing
 Last MSI mode does not get used, no matter implemented in hardware or not.
 Instead, the driver assumes the advantage of multiple MSIs is negated and
 falls back to the single MSI mode as if MRSM bit was set (some Intel chips
 implement this strategy anyway - MRSM bit gets set even if the number of
 allocated MSIs exceeds the number of implemented ports).
 
 Signed-off-by: Alexander Gordeev agord...@redhat.com
 ---
  drivers/ata/ahci.c|   93 +--
  drivers/ata/ahci.h|6 +++
  drivers/ata/libahci.c |  118 
 ++---
  3 files changed, 207 insertions(+), 10 deletions(-)

Has Jeff acked this patch?

Thanks,

Ingo
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v4 -tip 3/3] AHCI: Support multiple MSIs

2012-10-25 Thread Alexander Gordeev
On Thu, Oct 25, 2012 at 11:09:57AM +0200, Ingo Molnar wrote:
 Has Jeff acked this patch?

Yep,
http://lkml.indiana.edu/hypermail/linux/kernel/1210.0/00795.html

-- 
Regards,
Alexander Gordeev
agord...@redhat.com
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v4 -tip 3/3] AHCI: Support multiple MSIs

2012-10-25 Thread Alexander Gordeev
On Thu, Oct 25, 2012 at 11:25:55AM +0200, Alexander Gordeev wrote:
 On Thu, Oct 25, 2012 at 11:09:57AM +0200, Ingo Molnar wrote:
  Has Jeff acked this patch?
 
 Yep,
 http://lkml.indiana.edu/hypermail/linux/kernel/1210.0/00795.html

Ah.. sorry - Jeff acked v3, not the recent one.
Jeff, would you keep your ack for this patch?

-- 
Regards,
Alexander Gordeev
agord...@redhat.com
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v4 -tip 3/3] AHCI: Support multiple MSIs

2012-10-06 Thread Alexander Gordeev
Take advantage of multiple MSIs implementation on x86 - on systems with
IRQ remapping AHCI ports not only get assigned separate MSI vectors -
but also separate IRQs. As result, interrupts generated by different
ports could be serviced on different CPUs rather than on a single one.

In cases when number of allocated MSIs is less than requested the Sharing
Last MSI mode does not get used, no matter implemented in hardware or not.
Instead, the driver assumes the advantage of multiple MSIs is negated and
falls back to the single MSI mode as if MRSM bit was set (some Intel chips
implement this strategy anyway - MRSM bit gets set even if the number of
allocated MSIs exceeds the number of implemented ports).

Signed-off-by: Alexander Gordeev 
---
 drivers/ata/ahci.c|   93 +--
 drivers/ata/ahci.h|6 +++
 drivers/ata/libahci.c |  118 ++---
 3 files changed, 207 insertions(+), 10 deletions(-)

diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 7862d17..29ed8a8 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1057,6 +1057,86 @@ static inline void ahci_gtf_filter_workaround(struct 
ata_host *host)
 {}
 #endif
 
+int ahci_init_interrupts(struct pci_dev *pdev, struct ahci_host_priv *hpriv)
+{
+   int rc;
+   unsigned int maxvec;
+
+   if (!(hpriv->flags & AHCI_HFLAG_NO_MSI)) {
+   rc = pci_enable_msi_block_auto(pdev, );
+   if (rc > 0) {
+   if ((rc == maxvec) || (rc == 1))
+   return rc;
+   /*
+* Assume that advantage of multipe MSIs is negated,
+* so fallback to single MSI mode to save resources
+*/
+   pci_disable_msi(pdev);
+   if (!pci_enable_msi(pdev))
+   return 1;
+   }
+   }
+
+   pci_intx(pdev, 1);
+   return 0;
+}
+
+/**
+ * ahci_host_activate - start AHCI host, request IRQs and register it
+ * @host: target ATA host
+ * @irq: base IRQ number to request
+ * @n_msis: number of MSIs allocated for this host
+ * @irq_handler: irq_handler used when requesting IRQs
+ * @irq_flags: irq_flags used when requesting IRQs
+ *
+ * Similar to ata_host_activate, but requests IRQs according to AHCI-1.1
+ * when multiple MSIs were allocated. That is one MSI per port, starting
+ * from @irq.
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis)
+{
+   int i, rc;
+
+   /* Sharing Last Message among several ports is not supported */
+   if (n_msis < host->n_ports)
+   return -EINVAL;
+
+   rc = ata_host_start(host);
+   if (rc)
+   return rc;
+
+   for (i = 0; i < host->n_ports; i++) {
+   rc = devm_request_threaded_irq(host->dev,
+   irq + i, ahci_hw_interrupt, ahci_thread_fn, IRQF_SHARED,
+   dev_driver_string(host->dev), host->ports[i]);
+   if (rc)
+   goto out_free_irqs;
+   }
+
+   for (i = 0; i < host->n_ports; i++)
+   ata_port_desc(host->ports[i], "irq %d", irq + i);
+
+   rc = ata_host_register(host, _sht);
+   if (rc)
+   goto out_free_all_irqs;
+
+   return 0;
+
+out_free_all_irqs:
+   i = host->n_ports;
+out_free_irqs:
+   for (i--; i >= 0; i--)
+   devm_free_irq(host->dev, irq + i, host->ports[i]);
+
+   return rc;
+}
+
 static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
unsigned int board_id = ent->driver_data;
@@ -1065,7 +1145,7 @@ static int ahci_init_one(struct pci_dev *pdev, const 
struct pci_device_id *ent)
struct device *dev = >dev;
struct ahci_host_priv *hpriv;
struct ata_host *host;
-   int n_ports, i, rc;
+   int n_ports, n_msis, i, rc;
int ahci_pci_bar = AHCI_PCI_BAR_STANDARD;
 
VPRINTK("ENTER\n");
@@ -1150,11 +1230,12 @@ static int ahci_init_one(struct pci_dev *pdev, const 
struct pci_device_id *ent)
if (ahci_sb600_enable_64bit(pdev))
hpriv->flags &= ~AHCI_HFLAG_32BIT_ONLY;
 
-   if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
-   pci_intx(pdev, 1);
-
hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar];
 
+   n_msis = ahci_init_interrupts(pdev, hpriv);
+   if (n_msis > 1)
+   hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
+
/* save initial config */
ahci_pci_save_initial_config(pdev, hpriv);
 
@@ -1250,6 +1331,10 @@ static int ahci_init_one(struct pci_dev *pdev, const 
struct pci_device_id *ent)
ahci_pci_print_info(host);
 
pci_set_master(pdev);
+
+   

[PATCH v4 -tip 3/3] AHCI: Support multiple MSIs

2012-10-06 Thread Alexander Gordeev
Take advantage of multiple MSIs implementation on x86 - on systems with
IRQ remapping AHCI ports not only get assigned separate MSI vectors -
but also separate IRQs. As result, interrupts generated by different
ports could be serviced on different CPUs rather than on a single one.

In cases when number of allocated MSIs is less than requested the Sharing
Last MSI mode does not get used, no matter implemented in hardware or not.
Instead, the driver assumes the advantage of multiple MSIs is negated and
falls back to the single MSI mode as if MRSM bit was set (some Intel chips
implement this strategy anyway - MRSM bit gets set even if the number of
allocated MSIs exceeds the number of implemented ports).

Signed-off-by: Alexander Gordeev agord...@redhat.com
---
 drivers/ata/ahci.c|   93 +--
 drivers/ata/ahci.h|6 +++
 drivers/ata/libahci.c |  118 ++---
 3 files changed, 207 insertions(+), 10 deletions(-)

diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 7862d17..29ed8a8 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1057,6 +1057,86 @@ static inline void ahci_gtf_filter_workaround(struct 
ata_host *host)
 {}
 #endif
 
+int ahci_init_interrupts(struct pci_dev *pdev, struct ahci_host_priv *hpriv)
+{
+   int rc;
+   unsigned int maxvec;
+
+   if (!(hpriv-flags  AHCI_HFLAG_NO_MSI)) {
+   rc = pci_enable_msi_block_auto(pdev, maxvec);
+   if (rc  0) {
+   if ((rc == maxvec) || (rc == 1))
+   return rc;
+   /*
+* Assume that advantage of multipe MSIs is negated,
+* so fallback to single MSI mode to save resources
+*/
+   pci_disable_msi(pdev);
+   if (!pci_enable_msi(pdev))
+   return 1;
+   }
+   }
+
+   pci_intx(pdev, 1);
+   return 0;
+}
+
+/**
+ * ahci_host_activate - start AHCI host, request IRQs and register it
+ * @host: target ATA host
+ * @irq: base IRQ number to request
+ * @n_msis: number of MSIs allocated for this host
+ * @irq_handler: irq_handler used when requesting IRQs
+ * @irq_flags: irq_flags used when requesting IRQs
+ *
+ * Similar to ata_host_activate, but requests IRQs according to AHCI-1.1
+ * when multiple MSIs were allocated. That is one MSI per port, starting
+ * from @irq.
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis)
+{
+   int i, rc;
+
+   /* Sharing Last Message among several ports is not supported */
+   if (n_msis  host-n_ports)
+   return -EINVAL;
+
+   rc = ata_host_start(host);
+   if (rc)
+   return rc;
+
+   for (i = 0; i  host-n_ports; i++) {
+   rc = devm_request_threaded_irq(host-dev,
+   irq + i, ahci_hw_interrupt, ahci_thread_fn, IRQF_SHARED,
+   dev_driver_string(host-dev), host-ports[i]);
+   if (rc)
+   goto out_free_irqs;
+   }
+
+   for (i = 0; i  host-n_ports; i++)
+   ata_port_desc(host-ports[i], irq %d, irq + i);
+
+   rc = ata_host_register(host, ahci_sht);
+   if (rc)
+   goto out_free_all_irqs;
+
+   return 0;
+
+out_free_all_irqs:
+   i = host-n_ports;
+out_free_irqs:
+   for (i--; i = 0; i--)
+   devm_free_irq(host-dev, irq + i, host-ports[i]);
+
+   return rc;
+}
+
 static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
unsigned int board_id = ent-driver_data;
@@ -1065,7 +1145,7 @@ static int ahci_init_one(struct pci_dev *pdev, const 
struct pci_device_id *ent)
struct device *dev = pdev-dev;
struct ahci_host_priv *hpriv;
struct ata_host *host;
-   int n_ports, i, rc;
+   int n_ports, n_msis, i, rc;
int ahci_pci_bar = AHCI_PCI_BAR_STANDARD;
 
VPRINTK(ENTER\n);
@@ -1150,11 +1230,12 @@ static int ahci_init_one(struct pci_dev *pdev, const 
struct pci_device_id *ent)
if (ahci_sb600_enable_64bit(pdev))
hpriv-flags = ~AHCI_HFLAG_32BIT_ONLY;
 
-   if ((hpriv-flags  AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
-   pci_intx(pdev, 1);
-
hpriv-mmio = pcim_iomap_table(pdev)[ahci_pci_bar];
 
+   n_msis = ahci_init_interrupts(pdev, hpriv);
+   if (n_msis  1)
+   hpriv-flags |= AHCI_HFLAG_MULTI_MSI;
+
/* save initial config */
ahci_pci_save_initial_config(pdev, hpriv);
 
@@ -1250,6 +1331,10 @@ static int ahci_init_one(struct pci_dev *pdev, const 
struct pci_device_id *ent)
ahci_pci_print_info(host);
 
pci_set_master(pdev);
+