diff options
author | Evan Wang <xswang@marvell.com> | 2018-04-13 00:32:30 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2018-04-26 14:25:04 -0400 |
commit | fa89f53bd7288d6aa7a982841119e7123faf5a53 (patch) | |
tree | edcd32381580db6a29a58a681df8ee70dd7d8a68 /drivers/ata/libahci.c | |
parent | fd17ed684b6e33312cdcd9270b1fece9df266103 (diff) |
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 <xswang@marvell.com>
Cc: Ofer Heifetz <oferh@marvell.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'drivers/ata/libahci.c')
-rw-r--r-- | drivers/ata/libahci.c | 20 |
1 files changed, 12 insertions, 8 deletions
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) | |||
560 | if (!hpriv->start_engine) | 560 | if (!hpriv->start_engine) |
561 | hpriv->start_engine = ahci_start_engine; | 561 | hpriv->start_engine = ahci_start_engine; |
562 | 562 | ||
563 | if (!hpriv->stop_engine) | ||
564 | hpriv->stop_engine = ahci_stop_engine; | ||
565 | |||
563 | if (!hpriv->irq_handler) | 566 | if (!hpriv->irq_handler) |
564 | hpriv->irq_handler = ahci_single_level_irq_intr; | 567 | hpriv->irq_handler = ahci_single_level_irq_intr; |
565 | } | 568 | } |
@@ -897,9 +900,10 @@ static void ahci_start_port(struct ata_port *ap) | |||
897 | static int ahci_deinit_port(struct ata_port *ap, const char **emsg) | 900 | static int ahci_deinit_port(struct ata_port *ap, const char **emsg) |
898 | { | 901 | { |
899 | int rc; | 902 | int rc; |
903 | struct ahci_host_priv *hpriv = ap->host->private_data; | ||
900 | 904 | ||
901 | /* disable DMA */ | 905 | /* disable DMA */ |
902 | rc = ahci_stop_engine(ap); | 906 | rc = hpriv->stop_engine(ap); |
903 | if (rc) { | 907 | if (rc) { |
904 | *emsg = "failed to stop engine"; | 908 | *emsg = "failed to stop engine"; |
905 | return rc; | 909 | return rc; |
@@ -1310,7 +1314,7 @@ int ahci_kick_engine(struct ata_port *ap) | |||
1310 | int busy, rc; | 1314 | int busy, rc; |
1311 | 1315 | ||
1312 | /* stop engine */ | 1316 | /* stop engine */ |
1313 | rc = ahci_stop_engine(ap); | 1317 | rc = hpriv->stop_engine(ap); |
1314 | if (rc) | 1318 | if (rc) |
1315 | goto out_restart; | 1319 | goto out_restart; |
1316 | 1320 | ||
@@ -1549,7 +1553,7 @@ int ahci_do_hardreset(struct ata_link *link, unsigned int *class, | |||
1549 | 1553 | ||
1550 | DPRINTK("ENTER\n"); | 1554 | DPRINTK("ENTER\n"); |
1551 | 1555 | ||
1552 | ahci_stop_engine(ap); | 1556 | hpriv->stop_engine(ap); |
1553 | 1557 | ||
1554 | /* clear D2H reception area to properly wait for D2H FIS */ | 1558 | /* clear D2H reception area to properly wait for D2H FIS */ |
1555 | ata_tf_init(link->device, &tf); | 1559 | ata_tf_init(link->device, &tf); |
@@ -2075,14 +2079,14 @@ void ahci_error_handler(struct ata_port *ap) | |||
2075 | 2079 | ||
2076 | if (!(ap->pflags & ATA_PFLAG_FROZEN)) { | 2080 | if (!(ap->pflags & ATA_PFLAG_FROZEN)) { |
2077 | /* restart engine */ | 2081 | /* restart engine */ |
2078 | ahci_stop_engine(ap); | 2082 | hpriv->stop_engine(ap); |
2079 | hpriv->start_engine(ap); | 2083 | hpriv->start_engine(ap); |
2080 | } | 2084 | } |
2081 | 2085 | ||
2082 | sata_pmp_error_handler(ap); | 2086 | sata_pmp_error_handler(ap); |
2083 | 2087 | ||
2084 | if (!ata_dev_enabled(ap->link.device)) | 2088 | if (!ata_dev_enabled(ap->link.device)) |
2085 | ahci_stop_engine(ap); | 2089 | hpriv->stop_engine(ap); |
2086 | } | 2090 | } |
2087 | EXPORT_SYMBOL_GPL(ahci_error_handler); | 2091 | EXPORT_SYMBOL_GPL(ahci_error_handler); |
2088 | 2092 | ||
@@ -2129,7 +2133,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) | |||
2129 | return; | 2133 | return; |
2130 | 2134 | ||
2131 | /* set DITO, MDAT, DETO and enable DevSlp, need to stop engine first */ | 2135 | /* set DITO, MDAT, DETO and enable DevSlp, need to stop engine first */ |
2132 | rc = ahci_stop_engine(ap); | 2136 | rc = hpriv->stop_engine(ap); |
2133 | if (rc) | 2137 | if (rc) |
2134 | return; | 2138 | return; |
2135 | 2139 | ||
@@ -2189,7 +2193,7 @@ static void ahci_enable_fbs(struct ata_port *ap) | |||
2189 | return; | 2193 | return; |
2190 | } | 2194 | } |
2191 | 2195 | ||
2192 | rc = ahci_stop_engine(ap); | 2196 | rc = hpriv->stop_engine(ap); |
2193 | if (rc) | 2197 | if (rc) |
2194 | return; | 2198 | return; |
2195 | 2199 | ||
@@ -2222,7 +2226,7 @@ static void ahci_disable_fbs(struct ata_port *ap) | |||
2222 | return; | 2226 | return; |
2223 | } | 2227 | } |
2224 | 2228 | ||
2225 | rc = ahci_stop_engine(ap); | 2229 | rc = hpriv->stop_engine(ap); |
2226 | if (rc) | 2230 | if (rc) |
2227 | return; | 2231 | return; |
2228 | 2232 | ||