devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] libahci: Implement the workaround to fix the missing of edge interrupt for HOST_IRQ_STAT
       [not found] ` <1450942289-12660-1-git-send-email-stripathi-qTEPVZfXA3Y@public.gmane.org>
@ 2015-12-24  7:31   ` Suman Tripathi
  0 siblings, 0 replies; 6+ messages in thread
From: Suman Tripathi @ 2015-12-24  7:31 UTC (permalink / raw)
  To: olof-nZhT3qVonbNeoWH0uzbU5w, tj-DgEjT+Ai2ygdnm+yROfE0A,
	arnd-r2nGTMty4D4
  Cc: linux-ide-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	mlangsdo-H+wXaHxf7aLQT0dZR+AlfA, jcm-H+wXaHxf7aLQT0dZR+AlfA,
	patches-qTEPVZfXA3Y, Suman Tripathi

Due to H/W errata, the HOST_IRQ_STAT register misses the edge interrupt
when clearing the HOST_IRQ_STAT register and hardware reporting the
PORT_IRQ_STAT register at the same clock cycle. As such, the
algorithm below outlines the workaround.

1. Read HOST_IRQ_STAT register and save the state.
2. Clear the HOST_IRQ_STAT register.
3. Read back the HOST_IRQ_STAT register.
4. If HOST_IRQ_STAT register equals to zero, then
   traverse the rest of port's PORT_IRQ_STAT register
   to check if an interrupt is triggered at that point else
   go to step 6.
5. If PORT_IRQ_STAT register of rest ports is not equal to zero
   then update the state of HOST_IRQ_STAT saved in step 1.
6. Handle port interrupts.
7. Exit

Signed-off-by: Suman Tripathi <stripathi-qTEPVZfXA3Y@public.gmane.org>
---
 drivers/ata/ahci.h    |    2 ++
 drivers/ata/libahci.c |   45 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+), 0 deletions(-)

diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 45586c1..736f4a5 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -242,6 +242,8 @@ enum {
 	AHCI_HFLAG_NO_FBS		= (1 << 18), /* no FBS */
 	AHCI_HFLAG_EDGE_IRQ		= (1 << 19), /* HOST_IRQ_STAT behaves as
 							Edge Triggered */
+	AHCI_HFLAG_EDGE_IRQ_BROKEN	= (1 << 20), /* HOST_IRQ_STAT miss edge
+							from PORT_IRQ_STAT */

 	/* ap->flags bits */

diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 096064c..02b85c2 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -1832,10 +1832,55 @@ static irqreturn_t ahci_multi_irqs_intr(int irq, void *dev_instance)
 	return IRQ_WAKE_THREAD;
 }

+static void ahci_handle_broken_edge_irq(struct ata_host *host,
+					u32 *irq_masked)
+{
+	struct ahci_host_priv *hpriv = host->private_data;
+	void __iomem *mmio = hpriv->mmio;
+	unsigned int i, temp_irq_masked;
+	struct ata_port *next_ap;
+	void __iomem *port_mmio;
+	int j;
+
+	if (!readl(mmio + HOST_IRQ_STAT)) {
+		temp_irq_masked = *irq_masked;
+
+		for (i = 0; i < __sw_hweight32(hpriv->port_map);
+		     i++) {
+			if (*irq_masked & (1 << i)) {
+				for (j = 0;
+				     j < __sw_hweight32(hpriv->port_map);
+				     j++) {
+					if (i == j)
+						continue;
+
+					next_ap = host->ports[j];
+					port_mmio = ahci_port_base(next_ap);
+					if (readl(port_mmio + PORT_IRQ_STAT))
+						temp_irq_masked |= (1 << j);
+				}
+			}
+		}
+		*irq_masked = temp_irq_masked;
+	}
+
+}
+
 static u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked)
 {
+	struct ahci_host_priv *hpriv = host->private_data;
 	unsigned int i, handled = 0;

+	/*
+	 * For hardware with broken edge trigger latch
+	 * the HOST_IRQ_STAT register misses the edge interrupt
+	 * when clearing of HOST_IRQ_STAT register and hardware
+	 * reporting the PORT_IRQ_STAT register at the
+	 * same clock cycle.
+	 */
+	if (hpriv->flags & AHCI_HFLAG_EDGE_IRQ_BROKEN)
+		ahci_handle_broken_edge_irq(host, &irq_masked);
+
 	for (i = 0; i < host->n_ports; i++) {
 		struct ata_port *ap;

--
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 0/2] ata: Introduce the AHCI_HFLAG_EDGE_IRQ_BROKEN in libahci and enabling it for ahci_xgene driver.
@ 2016-01-11 10:06 Suman Tripathi
  2016-01-11 10:06 ` [PATCH 1/2] libahci: Implement the workaround to fix the missing of edge interrupt for HOST_IRQ_STAT Suman Tripathi
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Suman Tripathi @ 2016-01-11 10:06 UTC (permalink / raw)
  To: olof, tj, arnd
  Cc: linux-ide, devicetree, linux-arm-kernel, mlangsdo, jcm, patches,
	Suman Tripathi

This patch set implements a workaround for an errate in the APM
X-Gene SATA host controller with edge interrupt. The HOST_IRQ_STAT
misses the edge interrupt from the PORT_IRQ_STAT when clearing the
HOST_IRQ_STAT and reporting the PORT_IRQ_STAT happens in same clock
cycle.

Signed-off-by: Suman Tripathi <stripathi@apm.com>

Suman Tripathi (2):
  libahci: Implement the workaround to fix the missing of edge
    interrupt for HOST_IRQ_STAT
  ahci_xgene: Enable AHCI_HFLAG_EDGE_IRQ_BROKEN for APM X-Gen2 SATA
    host controller

 drivers/ata/ahci.h       |    2 ++
 drivers/ata/ahci_xgene.c |    3 ++-
 drivers/ata/libahci.c    |   45 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 49 insertions(+), 1 deletions(-)


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/2] libahci: Implement the workaround to fix the missing of edge interrupt for HOST_IRQ_STAT
  2016-01-11 10:06 [PATCH 0/2] ata: Introduce the AHCI_HFLAG_EDGE_IRQ_BROKEN in libahci and enabling it for ahci_xgene driver Suman Tripathi
@ 2016-01-11 10:06 ` Suman Tripathi
  2016-01-11 16:16   ` Tejun Heo
  2016-01-11 10:06 ` [PATCH 2/2] ahci_xgene: Enable AHCI_HFLAG_EDGE_IRQ_BROKEN for APM X-Gen2 SATA host controller Suman Tripathi
  2016-01-11 16:10 ` [PATCH 0/2] ata: Introduce the AHCI_HFLAG_EDGE_IRQ_BROKEN in libahci and enabling it for ahci_xgene driver Tejun Heo
  2 siblings, 1 reply; 6+ messages in thread
From: Suman Tripathi @ 2016-01-11 10:06 UTC (permalink / raw)
  To: olof, tj, arnd
  Cc: linux-ide, devicetree, linux-arm-kernel, mlangsdo, jcm, patches,
	Suman Tripathi

Due to H/W errata, the HOST_IRQ_STAT register misses the edge interrupt
when clearing the HOST_IRQ_STAT register and hardware reporting the
PORT_IRQ_STAT register at the same clock cycle. As such, the
algorithm below outlines the workaround.

1. Read HOST_IRQ_STAT register and save the state.
2. Clear the HOST_IRQ_STAT register.
3. Read back the HOST_IRQ_STAT register.
4. If HOST_IRQ_STAT register equals to zero, then
   traverse the rest of port's PORT_IRQ_STAT register
   to check if an interrupt is triggered at that point else
   go to step 6.
5. If PORT_IRQ_STAT register of rest ports is not equal to zero
   then update the state of HOST_IRQ_STAT saved in step 1.
6. Handle port interrupts.
7. Exit

Signed-off-by: Suman Tripathi <stripathi@apm.com>
---
 drivers/ata/ahci.h    |    2 ++
 drivers/ata/libahci.c |   45 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+), 0 deletions(-)

diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 45586c1..736f4a5 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -242,6 +242,8 @@ enum {
 	AHCI_HFLAG_NO_FBS		= (1 << 18), /* no FBS */
 	AHCI_HFLAG_EDGE_IRQ		= (1 << 19), /* HOST_IRQ_STAT behaves as
 							Edge Triggered */
+	AHCI_HFLAG_EDGE_IRQ_BROKEN	= (1 << 20), /* HOST_IRQ_STAT miss edge
+							from PORT_IRQ_STAT */

 	/* ap->flags bits */

diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 096064c..02b85c2 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -1832,10 +1832,55 @@ static irqreturn_t ahci_multi_irqs_intr(int irq, void *dev_instance)
 	return IRQ_WAKE_THREAD;
 }

+static void ahci_handle_broken_edge_irq(struct ata_host *host,
+					u32 *irq_masked)
+{
+	struct ahci_host_priv *hpriv = host->private_data;
+	void __iomem *mmio = hpriv->mmio;
+	unsigned int i, temp_irq_masked;
+	struct ata_port *next_ap;
+	void __iomem *port_mmio;
+	int j;
+
+	if (!readl(mmio + HOST_IRQ_STAT)) {
+		temp_irq_masked = *irq_masked;
+
+		for (i = 0; i < __sw_hweight32(hpriv->port_map);
+		     i++) {
+			if (*irq_masked & (1 << i)) {
+				for (j = 0;
+				     j < __sw_hweight32(hpriv->port_map);
+				     j++) {
+					if (i == j)
+						continue;
+
+					next_ap = host->ports[j];
+					port_mmio = ahci_port_base(next_ap);
+					if (readl(port_mmio + PORT_IRQ_STAT))
+						temp_irq_masked |= (1 << j);
+				}
+			}
+		}
+		*irq_masked = temp_irq_masked;
+	}
+
+}
+
 static u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked)
 {
+	struct ahci_host_priv *hpriv = host->private_data;
 	unsigned int i, handled = 0;

+	/*
+	 * For hardware with broken edge trigger latch
+	 * the HOST_IRQ_STAT register misses the edge interrupt
+	 * when clearing of HOST_IRQ_STAT register and hardware
+	 * reporting the PORT_IRQ_STAT register at the
+	 * same clock cycle.
+	 */
+	if (hpriv->flags & AHCI_HFLAG_EDGE_IRQ_BROKEN)
+		ahci_handle_broken_edge_irq(host, &irq_masked);
+
 	for (i = 0; i < host->n_ports; i++) {
 		struct ata_port *ap;

--
1.7.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/2] ahci_xgene: Enable AHCI_HFLAG_EDGE_IRQ_BROKEN for APM X-Gen2 SATA host controller
  2016-01-11 10:06 [PATCH 0/2] ata: Introduce the AHCI_HFLAG_EDGE_IRQ_BROKEN in libahci and enabling it for ahci_xgene driver Suman Tripathi
  2016-01-11 10:06 ` [PATCH 1/2] libahci: Implement the workaround to fix the missing of edge interrupt for HOST_IRQ_STAT Suman Tripathi
@ 2016-01-11 10:06 ` Suman Tripathi
  2016-01-11 16:10 ` [PATCH 0/2] ata: Introduce the AHCI_HFLAG_EDGE_IRQ_BROKEN in libahci and enabling it for ahci_xgene driver Tejun Heo
  2 siblings, 0 replies; 6+ messages in thread
From: Suman Tripathi @ 2016-01-11 10:06 UTC (permalink / raw)
  To: olof, tj, arnd
  Cc: linux-ide, devicetree, linux-arm-kernel, mlangsdo, jcm, patches,
	Suman Tripathi

This patch enables the AHCI_HFLAG_EDGE_IRQ_BROKEN for APM
X-Gene2 AHCI SATA host controller. Due to H/W errata, the
HOST_IRQ_STAT misses the edge interrupt from PORT_IRQ_STAT
when clearing the HOST_IRQ_STAT and reporting the PORT_IRQ_STAT
at the same clock cycle.

Signed-off-by: Suman Tripathi <stripathi@apm.com>
---
 drivers/ata/ahci_xgene.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c
index e2c6d9e..57c8463 100644
--- a/drivers/ata/ahci_xgene.c
+++ b/drivers/ata/ahci_xgene.c
@@ -779,7 +779,8 @@ skip_clk_phy:
 		hpriv->flags = AHCI_HFLAG_NO_NCQ;
 		break;
 	case XGENE_AHCI_V2:
-		hpriv->flags |= AHCI_HFLAG_YES_FBS | AHCI_HFLAG_EDGE_IRQ;
+		hpriv->flags |= AHCI_HFLAG_YES_FBS | AHCI_HFLAG_EDGE_IRQ |
+				AHCI_HFLAG_EDGE_IRQ_BROKEN;
 		break;
 	default:
 		break;
--
1.7.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 0/2] ata: Introduce the AHCI_HFLAG_EDGE_IRQ_BROKEN in libahci and enabling it for ahci_xgene driver.
  2016-01-11 10:06 [PATCH 0/2] ata: Introduce the AHCI_HFLAG_EDGE_IRQ_BROKEN in libahci and enabling it for ahci_xgene driver Suman Tripathi
  2016-01-11 10:06 ` [PATCH 1/2] libahci: Implement the workaround to fix the missing of edge interrupt for HOST_IRQ_STAT Suman Tripathi
  2016-01-11 10:06 ` [PATCH 2/2] ahci_xgene: Enable AHCI_HFLAG_EDGE_IRQ_BROKEN for APM X-Gen2 SATA host controller Suman Tripathi
@ 2016-01-11 16:10 ` Tejun Heo
  2 siblings, 0 replies; 6+ messages in thread
From: Tejun Heo @ 2016-01-11 16:10 UTC (permalink / raw)
  To: Suman Tripathi
  Cc: olof, arnd, linux-ide, devicetree, linux-arm-kernel, mlangsdo,
	jcm, patches

On Mon, Jan 11, 2016 at 03:36:01PM +0530, Suman Tripathi wrote:
> This patch set implements a workaround for an errate in the APM
> X-Gene SATA host controller with edge interrupt. The HOST_IRQ_STAT
> misses the edge interrupt from the PORT_IRQ_STAT when clearing the
> HOST_IRQ_STAT and reporting the PORT_IRQ_STAT happens in same clock
> cycle.

Heh, I don't know why but I had to pull this posting out of spam too.
For some reason, gmail thought these are spams.

-- 
tejun

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] libahci: Implement the workaround to fix the missing of edge interrupt for HOST_IRQ_STAT
  2016-01-11 10:06 ` [PATCH 1/2] libahci: Implement the workaround to fix the missing of edge interrupt for HOST_IRQ_STAT Suman Tripathi
@ 2016-01-11 16:16   ` Tejun Heo
  0 siblings, 0 replies; 6+ messages in thread
From: Tejun Heo @ 2016-01-11 16:16 UTC (permalink / raw)
  To: Suman Tripathi
  Cc: olof, arnd, linux-ide, devicetree, linux-arm-kernel, mlangsdo,
	jcm, patches

Hello,

On Mon, Jan 11, 2016 at 03:36:02PM +0530, Suman Tripathi wrote:
> Due to H/W errata, the HOST_IRQ_STAT register misses the edge interrupt
> when clearing the HOST_IRQ_STAT register and hardware reporting the
> PORT_IRQ_STAT register at the same clock cycle. As such, the
> algorithm below outlines the workaround.
> 
> 1. Read HOST_IRQ_STAT register and save the state.
> 2. Clear the HOST_IRQ_STAT register.
> 3. Read back the HOST_IRQ_STAT register.
> 4. If HOST_IRQ_STAT register equals to zero, then
>    traverse the rest of port's PORT_IRQ_STAT register
>    to check if an interrupt is triggered at that point else
>    go to step 6.
> 5. If PORT_IRQ_STAT register of rest ports is not equal to zero
>    then update the state of HOST_IRQ_STAT saved in step 1.
> 6. Handle port interrupts.
> 7. Exit
...
> +static void ahci_handle_broken_edge_irq(struct ata_host *host,
> +					u32 *irq_masked)
> +{
> +	struct ahci_host_priv *hpriv = host->private_data;
> +	void __iomem *mmio = hpriv->mmio;
> +	unsigned int i, temp_irq_masked;
> +	struct ata_port *next_ap;
> +	void __iomem *port_mmio;
> +	int j;
> +
> +	if (!readl(mmio + HOST_IRQ_STAT)) {
> +		temp_irq_masked = *irq_masked;
> +
> +		for (i = 0; i < __sw_hweight32(hpriv->port_map);
> +		     i++) {
                     ^^^^^^
		     Doesn't this fit on the same line?

> +			if (*irq_masked & (1 << i)) {
> +				for (j = 0;
> +				     j < __sw_hweight32(hpriv->port_map);
> +				     j++) {

Heh, if (!COND) continue; can be your friend.

> +					if (i == j)
> +						continue;
> +
> +					next_ap = host->ports[j];
> +					port_mmio = ahci_port_base(next_ap);
> +					if (readl(port_mmio + PORT_IRQ_STAT))
> +						temp_irq_masked |= (1 << j);
> +				}
> +			}
> +		}
> +		*irq_masked = temp_irq_masked;
> +	}
> +
> +}

So, this is really specific to the controller.

>  static u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked)
>  {
> +	struct ahci_host_priv *hpriv = host->private_data;
>  	unsigned int i, handled = 0;
> 
> +	/*
> +	 * For hardware with broken edge trigger latch
> +	 * the HOST_IRQ_STAT register misses the edge interrupt
> +	 * when clearing of HOST_IRQ_STAT register and hardware
> +	 * reporting the PORT_IRQ_STAT register at the
> +	 * same clock cycle.
> +	 */
> +	if (hpriv->flags & AHCI_HFLAG_EDGE_IRQ_BROKEN)
> +		ahci_handle_broken_edge_irq(host, &irq_masked);
> +

And all it needs is doing some extra processing at the beginning of
port interrupt handling.  I think it'd be better to implement
ahci_xgene specific IRQ handler which does the special processing and
call the generic ahci_handle_port_intr().

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2016-01-11 16:16 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-01-11 10:06 [PATCH 0/2] ata: Introduce the AHCI_HFLAG_EDGE_IRQ_BROKEN in libahci and enabling it for ahci_xgene driver Suman Tripathi
2016-01-11 10:06 ` [PATCH 1/2] libahci: Implement the workaround to fix the missing of edge interrupt for HOST_IRQ_STAT Suman Tripathi
2016-01-11 16:16   ` Tejun Heo
2016-01-11 10:06 ` [PATCH 2/2] ahci_xgene: Enable AHCI_HFLAG_EDGE_IRQ_BROKEN for APM X-Gen2 SATA host controller Suman Tripathi
2016-01-11 16:10 ` [PATCH 0/2] ata: Introduce the AHCI_HFLAG_EDGE_IRQ_BROKEN in libahci and enabling it for ahci_xgene driver Tejun Heo
  -- strict thread matches above, loose matches on Subject: below --
2015-12-24  7:31 Suman Tripathi
     [not found] ` <1450942289-12660-1-git-send-email-stripathi-qTEPVZfXA3Y@public.gmane.org>
2015-12-24  7:31   ` [PATCH 1/2] libahci: Implement the workaround to fix the missing of edge interrupt for HOST_IRQ_STAT Suman Tripathi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).