From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Robert Richter <rrichter@redhat.com>
Date: Thu, 7 Jun 2018 22:59:33 -0400
Subject: [PATCH] ahci: thunderx2: Fix for errata that affects stop engine

Message-id: <1528412373-19128-3-git-send-email-rrichter@redhat.com>
Patchwork-id: 220952
O-Subject: [RHEL-8.0 BZ 1563590 v2 2/2] ahci: thunderx2: Fix for errata that affects stop engine
Bugzilla: 1563590
RH-Acked-by: Dean Nelson <dnelson@redhat.com>
RH-Acked-by: Mark Langsdorf <mlangsdo@redhat.com>
RH-Acked-by: Mark Salter <msalter@redhat.com>

From: Jayachandran C <jnair@caviumnetworks.com>

Apply workaround for this errata:
  Synopsis: Resetting PxCMD.ST may hang the SATA device

  Description: An internal ping-pong buffer state is not reset
  correctly for an PxCMD.ST=0 command for a SATA channel. This
  may cause the SATA interface to hang when a PxCMD.ST=0 command
  is received.

  Workaround: A SATA_BIU_CORE_ENABLE.sw_init_bsi must be asserted
  by the driver whenever the PxCMD.ST needs to be de-asserted. This
  will reset both the ports. So, it may not always work in a 2
  channel SATA system.

  Resolution: Fix in B0.

Add the code to ahci_stop_engine() to do this. It is not easy to
stop the other "port" since it is associated with a different AHCI
interface. Please note that with this fix, SATA reset does not
hang any more, but it can cause failures on the other interface
if that is in active use.

Unfortunately, we have nothing other the the CPU ID to check if the
SATA block has this issue.

RHEL-only:

Both patches are in RHEL-7.6 also. Inclusion of the patches into RHEL-8
was discussed. Since there are partners with Ax system configurations it
was decided to carry them in RHEL8 too. See:

 https://bugzilla.redhat.com/show_bug.cgi?id=1563590#c1

[v3 with new delays]
Signed-off-by: Jayachandran C <jnair@caviumnetworks.com>

Upstream Status: RHEL only
Signed-off-by: Robert Richter <rrichter@redhat.com>
Signed-off-by: Herton R. Krzesinski <herton@redhat.com>
---
 drivers/ata/libahci.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index ea5bf5f4cbed..71c55cae27ac 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -666,6 +666,24 @@ int ahci_stop_engine(struct ata_port *ap)
 	tmp &= ~PORT_CMD_START;
 	writel(tmp, port_mmio + PORT_CMD);

+#ifdef CONFIG_ARM64
+	/* Rev Ax of Cavium CN99XX needs a hack for port stop */
+	if (dev_is_pci(ap->host->dev) &&
+	    to_pci_dev(ap->host->dev)->vendor == 0x14e4 &&
+	    to_pci_dev(ap->host->dev)->device == 0x9027 &&
+	    midr_is_cpu_model_range(read_cpuid_id(),
+			MIDR_CPU_MODEL(ARM_CPU_IMP_BRCM, BRCM_CPU_PART_VULCAN),
+			MIDR_CPU_VAR_REV(0, 0),
+			MIDR_CPU_VAR_REV(0, MIDR_REVISION_MASK))) {
+		tmp = readl(hpriv->mmio + 0x8000);
+		udelay(100);
+		writel(tmp | (1 << 26), hpriv->mmio + 0x8000);
+		udelay(100);
+		writel(tmp & ~(1 << 26), hpriv->mmio + 0x8000);
+		dev_warn(ap->host->dev, "CN99XX SATA reset workaround applied\n");
+	}
+#endif
+
 	/* wait for engine to stop. This could be as long as 500 msec */
 	tmp = ata_wait_register(ap, port_mmio + PORT_CMD,
 				PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
-- 
2.26.2

