Skip to contentSkip to conversation

ahci_xgene: Fix the xgene_ahci_restart_engine function to support Port Multiplier for APM X-Gene SoC AHCI SATA host controller driver.

PATCH New Suman Tripathi 3 participants 7 messages Jan 5, 2015 1 message not in the archive

Subsystems (2)
lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

#1 lore raw

PATCH 1/2 ahci_xgene: Fix the xgene_ahci_restart_engine function to support Port Multiplier for APM X-Gene SoC AHCI SATA host controller driver.

This patch implements the function xgene_ahci_poll_reg_val to poll PxCI for multiple IDENTIFY DEVICE commands to finish before restarting the DMA engine in case of Port Multiplier.

---
 drivers/ata/ahci_xgene.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 54 insertions(+), 2 deletions(-)
drivers/ata/ahci_xgene.c +54 -2
index 0f8538f..2180223 100644
@@ -105,17 +105,69 @@ static int xgene_ahci_init_memram(struct xgene_ahci_context *ctx)
 }
 
 /**
+ * xgene_ahci_poll_reg_val- Poll a register on a specific value.
+ * @ap : ATA port of interest.
+ * @reg : Register of interest.
+ * @val : Value to be attained.
+ * @interval : waiting interval for polling.
+ * @timeout : timeout for achieving the value.
+ */
+static int xgene_ahci_poll_reg_val(struct ata_port *ap,
+				   void __iomem *reg, unsigned
+				   int val, unsigned long interval,
+				   unsigned long timeout)
+{
+	unsigned long deadline;
+	unsigned int tmp;
+
+	tmp = ioread32(reg);
+	deadline = ata_deadline(jiffies, timeout);
+
+	while ((tmp != val) && (time_before(jiffies, deadline))) {
+		ata_msleep(ap, interval);
+		tmp = ioread32(reg);
+	}
+
+	return tmp;
+}
+
+/**
  * xgene_ahci_restart_engine - Restart the dma engine.
  * @ap : ATA port of interest
  *
- * Restarts the dma engine inside the controller.
+ * Waits for completion of multiple commands and restarts
+ * the DMA engine inside the controller.
  */
 static int xgene_ahci_restart_engine(struct ata_port *ap)
 {
 	struct ahci_host_priv *hpriv = ap->host->private_data;
+	struct ahci_port_priv *pp = ap->private_data;
+	void __iomem *port_mmio = ahci_port_base(ap);
+	u32 fbs;
+
+	/*
+	 * In case of PMP multiple IDENTIFY DEVICE commands can be
+	 * issued inside PxCI. So need to poll PxCI for the
+	 * completion of outstanding IDENTIFY DEVICE commands before
+	 * we restart the DMA engine.
+	 */
+	if (xgene_ahci_poll_reg_val(ap, port_mmio +
+				    PORT_CMD_ISSUE, 0x0, 1, 100))
+		  return -EBUSY;
 
 	ahci_stop_engine(ap);
 	ahci_start_fis_rx(ap);
+
+	/*
+	 * Enable the PxFBS.FBS_EN bit as it
+	 * gets cleared due to stop engine.
+	 */
+	if (pp->fbs_supported) {
+		fbs = readl(port_mmio + PORT_FBS);
+		writel(fbs | PORT_FBS_EN, port_mmio + PORT_FBS);
+		fbs = readl(port_mmio + PORT_FBS);
+	}
+
 	hpriv->start_engine(ap);
 
 	return 0;
@@ -372,7 +424,7 @@ static struct ata_port_operations xgene_ahci_ops = {
 };
 
 static const struct ata_port_info xgene_ahci_port_info = {
-	.flags = AHCI_FLAG_COMMON,
+	.flags = AHCI_FLAG_COMMON | ATA_FLAG_PMP,
 	.pio_mask = ATA_PIO4,
 	.udma_mask = ATA_UDMA6,
 	.port_ops = &xgene_ahci_ops,

--
1.8.2.1

#2 lore raw

PATCH 1/2 ahci_xgene: Fix the xgene_ahci_restart_engine function to support Port Multiplier for APM X-Gene SoC AHCI SATA host controller driver.

Hello.

On 1/5/2015 1:21 PM, Suman Tripathi wrote:

Your patch summary seems too long.

Quoted 26 lines

This patch implements the function xgene_ahci_poll_reg_val to poll PxCI for multiple IDENTIFY DEVICE commands to finish before restarting the DMA engine in case of Port Multiplier.

---
  drivers/ata/ahci_xgene.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++--
  1 file changed, 54 insertions(+), 2 deletions(-)
drivers/ata/ahci_xgene.c +9 -0
index 0f8538f..2180223 100644
@@ -105,17 +105,69 @@ static int xgene_ahci_init_memram(struct xgene_ahci_context *ctx)
  }
 
  /**
+ * xgene_ahci_poll_reg_val- Poll a register on a specific value.
+ * @ap : ATA port of interest.
+ * @reg : Register of interest.
+ * @val : Value to be attained.
+ * @interval : waiting interval for polling.
+ * @timeout : timeout for achieving the value.
+ */
+static int xgene_ahci_poll_reg_val(struct ata_port *ap,
+				   void __iomem *reg, unsigned

drivers/ata/ahci_xgene.c static int xgene_ahci_init_memram(struct xgene_ahci_context *ctx) · line 126

Quoted 10 lines
drivers/ata/ahci_xgene.c +10 -0
+				   int val, unsigned long interval,
+				   unsigned long timeout)
+{
+	unsigned long deadline;
+	unsigned int tmp;
+
+	tmp = ioread32(reg);
+	deadline = ata_deadline(jiffies, timeout);
+
+	while ((tmp != val) && (time_before(jiffies, deadline))) {

Parens around the operands of && are not needed, especially around the
right one.

Quoted 28 lines
drivers/ata/ahci_xgene.c +20 -1
+		ata_msleep(ap, interval);
+		tmp = ioread32(reg);
+	}
+
+	return tmp;
+}
+
+/**
   * xgene_ahci_restart_engine - Restart the dma engine.
   * @ap : ATA port of interest
   *
- * Restarts the dma engine inside the controller.
+ * Waits for completion of multiple commands and restarts
+ * the DMA engine inside the controller.
   */
  static int xgene_ahci_restart_engine(struct ata_port *ap)
  {
  	struct ahci_host_priv *hpriv = ap->host->private_data;
+	struct ahci_port_priv *pp = ap->private_data;
+	void __iomem *port_mmio = ahci_port_base(ap);
+	u32 fbs;
+
+	/*
+	 * In case of PMP multiple IDENTIFY DEVICE commands can be
+	 * issued inside PxCI. So need to poll PxCI for the
+	 * completion of outstanding IDENTIFY DEVICE commands before
+	 * we restart the DMA engine.
+	 */

drivers/ata/ahci_xgene.c static int xgene_ahci_init_memram(struct xgene_ahci_context *ctx) · line 163

Quoted 10 lines
drivers/ata/ahci_xgene.c +7 -0
+	if (xgene_ahci_poll_reg_val(ap, port_mmio +
+				    PORT_CMD_ISSUE, 0x0, 1, 100))
+		  return -EBUSY;
 
  	ahci_stop_engine(ap);
  	ahci_start_fis_rx(ap);
+
+	/*
+	 * Enable the PxFBS.FBS_EN bit as it
+	 * gets cleared due to stop engine.

s/stop/stopping the/.

[...]

MBR, Sergei

#3 lore raw

PATCH 2/2 ahci_xgene: Implement the workaround to support PMP enumeration and discovery for APM X-Gene SoC AHCI SATA Host Controller driver.

In reply to a message not in the archive

Due to H/W errata, the controller is unable to save the PMP field fetched from command header before sending the H2D FIS. When the device returns the PMP port field in the D2H FIS, there is a mismatch and results in command completion failure. The workaround is to write the pmp value to PxFBS.DEV field before issuing any command to PMP.

---
 drivers/ata/ahci_xgene.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 124 insertions(+)
drivers/ata/ahci_xgene.c +124 -0
index 2180223..a194ddd 100644
@@ -85,6 +85,7 @@ struct xgene_ahci_context {
 	struct ahci_host_priv *hpriv;
 	struct device *dev;
 	u8 last_cmd[MAX_AHCI_CHN_PERCTR]; /* tracking the last command issued*/
+	u32 class[MAX_AHCI_CHN_PERCTR]; /* tracking the class of device */
 	void __iomem *csr_core;		/* Core CSR address of IP */
 	void __iomem *csr_diag;		/* Diag CSR address of IP */
 	void __iomem *csr_axi;		/* AXI CSR address of IP */
@@ -181,6 +182,13 @@ static int xgene_ahci_restart_engine(struct ata_port *ap)
  * clear the BSY bit after receiving the PIO setup FIS. This results in the dma
  * state machine goes into the CMFatalErrorUpdate state and locks up. By
  * restarting the dma engine, it removes the controller out of lock up state.
+ *
+ * Due to H/W errata, the controller is unable to save the PMP
+ * field fetched from command header before sending the H2D FIS.
+ * When the device returns the PMP port field in the D2H FIS, there is
+ * a mismatch and results in command completion failure. The
+ * workaround is to write the pmp value to PxFBS.DEV field before issuing
+ * any command to PMP.
  */
 static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc)
 {
@@ -188,6 +196,19 @@ static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc)
 	struct ahci_host_priv *hpriv = ap->host->private_data;
 	struct xgene_ahci_context *ctx = hpriv->plat_data;
 	int rc = 0;
+	u32 port_fbs;
+	void *port_mmio = ahci_port_base(ap);
+
+	/*
+	 * Write the pmp value to PxFBS.DEV
+	 * for case of Port Mulitplier.
+	 */
+	if (ctx->class[ap->port_no] == ATA_DEV_PMP) {
+		port_fbs = readl(port_mmio + PORT_FBS);
+		port_fbs &= ~PORT_FBS_DEV_MASK;
+		port_fbs |= qc->dev->link->pmp << PORT_FBS_DEV_OFFSET;
+		writel(port_fbs, port_mmio + PORT_FBS);
+	}
 
 	if (unlikely(ctx->last_cmd[ap->port_no] == ATA_CMD_ID_ATA))
 		xgene_ahci_restart_engine(ap);
@@ -415,12 +436,115 @@ static void xgene_ahci_host_stop(struct ata_host *host)
 	ahci_platform_disable_resources(hpriv);
 }
 
+/**
+ * xgene_ahci_pmp_softreset - Issue the softreset to the drives connected
+ *                            to Port Multiplier.
+ * @link: link to reset
+ * @class: Return value to indicate class of device
+ * @deadline: deadline jiffies for the operation
+ *
+ * Due to H/W errata, the controller is unable to save the PMP
+ * field fetched from command header before sending the H2D FIS.
+ * When the device returns the PMP port field in the D2H FIS, there is
+ * a mismatch and results in command completion failure. The workaround
+ * is to write the pmp value to PxFBS.DEV field before issuing any command
+ * to PMP.
+ */
+static int xgene_ahci_pmp_softreset(struct ata_link *link, unsigned int *class,
+			  unsigned long deadline)
+{
+	int pmp = sata_srst_pmp(link);
+	struct ata_port *ap = link->ap;
+	u32 rc;
+	void *port_mmio = ahci_port_base(ap);
+	u32 port_fbs;
+
+	/*
+	 * Set PxFBS.DEV field with pmp
+	 * value.
+	 */
+	port_fbs = readl(port_mmio + PORT_FBS);
+	port_fbs &= ~PORT_FBS_DEV_MASK;
+	port_fbs |= pmp << PORT_FBS_DEV_OFFSET;
+	writel(port_fbs, port_mmio + PORT_FBS);
+
+	rc = ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
+
+	return rc;
+}
+
+/**
+ * xgene_ahci_softreset - Issue the softreset to the drive.
+ * @link: link to reset
+ * @class: Return value to indicate class of device
+ * @deadline: deadline jiffies for the operation
+ *
+ * Due to H/W errata, the controller is unable to save the PMP
+ * field fetched from command header before sending the H2D FIS.
+ * When the device returns the PMP port field in the D2H FIS, there is
+ * a mismatch and results in command completion failure. The workaround
+ * is to write the pmp value to PxFBS.DEV field before issuing any command
+ * to PMP. Here is the algorithm to detect PMP :
+ *
+ * 1. Save the PxFBS value
+ * 2. Program PxFBS.DEV with pmp value send by framework. Framework sends
+ *    0xF for both PMP/NON-PMP initially
+ * 3. Issue softreset
+ * 4. If signature class is PMP goto 6
+ * 5. restore the original PxFBS and goto 3
+ * 6. return
+ */
+static int xgene_ahci_softreset(struct ata_link *link, unsigned int *class,
+			  unsigned long deadline)
+{
+	int pmp = sata_srst_pmp(link);
+	struct ata_port *ap = link->ap;
+	struct ahci_host_priv *hpriv = ap->host->private_data;
+	struct xgene_ahci_context *ctx = hpriv->plat_data;
+	void *port_mmio = ahci_port_base(ap);
+	u32 port_fbs;
+	u32 port_fbs_save;
+	u32 retry = 1;
+	u32 rc;
+
+	port_fbs_save = readl(port_mmio + PORT_FBS);
+
+	/*
+	 * Set PxFBS.DEV field with pmp
+	 * value.
+	 */
+	port_fbs = readl(port_mmio + PORT_FBS);
+	port_fbs &= ~PORT_FBS_DEV_MASK;
+	port_fbs |= pmp << PORT_FBS_DEV_OFFSET;
+	writel(port_fbs, port_mmio + PORT_FBS);
+
+softreset_retry:
+	rc = ahci_do_softreset(link, class, pmp,
+			       deadline, ahci_check_ready);
+
+	ctx->class[ap->port_no] = *class;
+	if (*class != ATA_DEV_PMP) {
+		/*
+		 * Retry for normal drives without
+		 * setting PxFBS.DEV field with pmp value.
+		 */
+		if (retry--) {
+			writel(port_fbs_save, port_mmio + PORT_FBS);
+			goto softreset_retry;
+		}
+	}
+
+	return rc;
+}
+
 static struct ata_port_operations xgene_ahci_ops = {
 	.inherits = &ahci_ops,
 	.host_stop = xgene_ahci_host_stop,
 	.hardreset = xgene_ahci_hardreset,
 	.read_id = xgene_ahci_read_id,
 	.qc_issue = xgene_ahci_qc_issue,
+	.softreset = xgene_ahci_softreset,
+	.pmp_softreset = xgene_ahci_pmp_softreset
 };
 
 static const struct ata_port_info xgene_ahci_port_info = {

--
1.8.2.1

#4 lore raw

PATCH 2/2 ahci_xgene: Implement the workaround to support PMP enumeration and discovery for APM X-Gene SoC AHCI SATA Host Controller driver.

Quoted 8 lines · Suman Tripathi

Due to H/W errata, the controller is unable to save the PMP field fetched from command header before sending the H2D FIS. When the device returns the PMP port field in the D2H FIS, there is a mismatch and results in command completion failure. The workaround is to write the pmp value to PxFBS.DEV field before issuing any command to PMP.

Applied 1-2 to libata/for-3.20.

Thanks.

Signature · 1 line
tejun
#5 lore raw

PATCH 2/2 ahci_xgene: Implement the workaround to support PMP enumeration and discovery for APM X-Gene SoC AHCI SATA Host Controller driver.

Quoted 11 lines · Tejun Heo
Quoted 8 lines · Suman Tripathi

Due to H/W errata, the controller is unable to save the PMP field fetched from command header before sending the H2D FIS. When the device returns the PMP port field in the D2H FIS, there is a mismatch and results in command completion failure. The workaround is to write the pmp value to PxFBS.DEV field before issuing any command to PMP.

Applied 1-2 to libata/for-3.20.

Reverted due to conflicts with the endian fix patches. Please rebase these two on top of them.

Thanks.

Signature · 1 line
tejun
#6 lore raw

PATCH 2/2 ahci_xgene: Implement the workaround to support PMP enumeration and discovery for APM X-Gene SoC AHCI SATA Host Controller driver.

Reverted due to conflicts with the endian fix patches. Please rebase these two on top of them.

Will do that .. I should have wait for the endian patch getting accepted. Sorry for that.

Quoted 20 lines · Tejun Heo
Quoted 11 lines · Tejun Heo
Quoted 8 lines · Suman Tripathi

Due to H/W errata, the controller is unable to save the PMP field fetched from command header before sending the H2D FIS. When the device returns the PMP port field in the D2H FIS, there is a mismatch and results in command completion failure. The workaround is to write the pmp value to PxFBS.DEV field before issuing any command to PMP.

Applied 1-2 to libata/for-3.20.

Reverted due to conflicts with the endian fix patches. Please rebase these two on top of them.

Thanks.

--
tejun

Signature · 10 lines
Thanks,
with regards,
Suman Tripathi
CONFIDENTIALITY NOTICE: This e-mail message, including any attachments, 
is for the sole use of the intended recipient(s) and contains information
that is confidential and proprietary to Applied Micro Circuits Corporation or its subsidiaries. 
It is to be used solely for the purpose of furthering the parties' business relationship. 
All unauthorized review, use, disclosure or distribution is prohibited. 
If you are not the intended recipient, please contact the sender by reply e-mail 
and destroy all copies of the original message.
#7 lore raw

PATCH 2/2 ahci_xgene: Implement the workaround to support PMP enumeration and discovery for APM X-Gene SoC AHCI SATA Host Controller driver.

Quoted 5 lines · Suman Tripathi

Reverted due to conflicts with the endian fix patches. Please rebase these two on top of them.

Will do that .. I should have wait for the endian patch getting accepted. Sorry for that.

Ooh, please don't be sorry. It's completely fine. These things happen.

Thanks.

Signature · 1 line
tejun