From fa89f53bd7288d6aa7a982841119e7123faf5a53 Mon Sep 17 00:00:00 2001 From: Evan Wang Date: Fri, 13 Apr 2018 12:32:30 +0800 Subject: libahci: Allow drivers to override stop_engine Marvell armada37xx, armada7k and armada8k share the same AHCI sata controller IP, and currently there is an issue (Errata Ref#226)that the SATA can not be detected via SATA Port-MultiPlayer(PMP). After debugging, the reason is found that the value of Port-x FIS-based Switching Control (PxFBS@0x40) became wrong. According to design, the bits[11:8, 0] of register PxFBS are cleared when Port Command and Status (0x18) bit[0] changes its value from 1 to 0, i.e. falling edge of Port Command and Status bit[0] sends PULSE that resets PxFBS bits[11:8; 0]. So it needs save the port PxFBS register before PxCMD ST write and restore the port PxFBS register afterwards in ahci_stop_engine(). This commit allows drivers to override ahci_stop_engine behavior for use by the Marvell AHCI driver(and potentially other drivers in the future). Signed-off-by: Evan Wang Cc: Ofer Heifetz Cc: Tejun Heo Cc: Thomas Petazzoni Signed-off-by: Tejun Heo --- drivers/ata/libahci.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers/ata/libahci.c') diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 7adcf3caabd0..e5d90977caec 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -560,6 +560,9 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv) if (!hpriv->start_engine) hpriv->start_engine = ahci_start_engine; + if (!hpriv->stop_engine) + hpriv->stop_engine = ahci_stop_engine; + if (!hpriv->irq_handler) hpriv->irq_handler = ahci_single_level_irq_intr; } @@ -897,9 +900,10 @@ static void ahci_start_port(struct ata_port *ap) static int ahci_deinit_port(struct ata_port *ap, const char **emsg) { int rc; + struct ahci_host_priv *hpriv = ap->host->private_data; /* disable DMA */ - rc = ahci_stop_engine(ap); + rc = hpriv->stop_engine(ap); if (rc) { *emsg = "failed to stop engine"; return rc; @@ -1310,7 +1314,7 @@ int ahci_kick_engine(struct ata_port *ap) int busy, rc; /* stop engine */ - rc = ahci_stop_engine(ap); + rc = hpriv->stop_engine(ap); if (rc) goto out_restart; @@ -1549,7 +1553,7 @@ int ahci_do_hardreset(struct ata_link *link, unsigned int *class, DPRINTK("ENTER\n"); - ahci_stop_engine(ap); + hpriv->stop_engine(ap); /* clear D2H reception area to properly wait for D2H FIS */ ata_tf_init(link->device, &tf); @@ -2075,14 +2079,14 @@ void ahci_error_handler(struct ata_port *ap) if (!(ap->pflags & ATA_PFLAG_FROZEN)) { /* restart engine */ - ahci_stop_engine(ap); + hpriv->stop_engine(ap); hpriv->start_engine(ap); } sata_pmp_error_handler(ap); if (!ata_dev_enabled(ap->link.device)) - ahci_stop_engine(ap); + hpriv->stop_engine(ap); } EXPORT_SYMBOL_GPL(ahci_error_handler); @@ -2129,7 +2133,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) return; /* set DITO, MDAT, DETO and enable DevSlp, need to stop engine first */ - rc = ahci_stop_engine(ap); + rc = hpriv->stop_engine(ap); if (rc) return; @@ -2189,7 +2193,7 @@ static void ahci_enable_fbs(struct ata_port *ap) return; } - rc = ahci_stop_engine(ap); + rc = hpriv->stop_engine(ap); if (rc) return; @@ -2222,7 +2226,7 @@ static void ahci_disable_fbs(struct ata_port *ap) return; } - rc = ahci_stop_engine(ap); + rc = hpriv->stop_engine(ap); if (rc) return; -- cgit v1.2.3