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 | |
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>
-rw-r--r-- | drivers/ata/ahci.c | 6 | ||||
-rw-r--r-- | drivers/ata/ahci.h | 7 | ||||
-rw-r--r-- | drivers/ata/ahci_qoriq.c | 2 | ||||
-rw-r--r-- | drivers/ata/ahci_xgene.c | 4 | ||||
-rw-r--r-- | drivers/ata/libahci.c | 20 | ||||
-rw-r--r-- | drivers/ata/sata_highbank.c | 2 |
6 files changed, 26 insertions, 15 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 1ff17799769d..6389c88b3500 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c | |||
@@ -698,7 +698,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, | |||
698 | 698 | ||
699 | DPRINTK("ENTER\n"); | 699 | DPRINTK("ENTER\n"); |
700 | 700 | ||
701 | ahci_stop_engine(ap); | 701 | hpriv->stop_engine(ap); |
702 | 702 | ||
703 | rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), | 703 | rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), |
704 | deadline, &online, NULL); | 704 | deadline, &online, NULL); |
@@ -724,7 +724,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, | |||
724 | bool online; | 724 | bool online; |
725 | int rc; | 725 | int rc; |
726 | 726 | ||
727 | ahci_stop_engine(ap); | 727 | hpriv->stop_engine(ap); |
728 | 728 | ||
729 | /* clear D2H reception area to properly wait for D2H FIS */ | 729 | /* clear D2H reception area to properly wait for D2H FIS */ |
730 | ata_tf_init(link->device, &tf); | 730 | ata_tf_init(link->device, &tf); |
@@ -788,7 +788,7 @@ static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class, | |||
788 | 788 | ||
789 | DPRINTK("ENTER\n"); | 789 | DPRINTK("ENTER\n"); |
790 | 790 | ||
791 | ahci_stop_engine(ap); | 791 | hpriv->stop_engine(ap); |
792 | 792 | ||
793 | for (i = 0; i < 2; i++) { | 793 | for (i = 0; i < 2; i++) { |
794 | u16 val; | 794 | u16 val; |
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index a9d996e17d75..824bd399f02e 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h | |||
@@ -365,6 +365,13 @@ struct ahci_host_priv { | |||
365 | * be overridden anytime before the host is activated. | 365 | * be overridden anytime before the host is activated. |
366 | */ | 366 | */ |
367 | void (*start_engine)(struct ata_port *ap); | 367 | void (*start_engine)(struct ata_port *ap); |
368 | /* | ||
369 | * Optional ahci_stop_engine override, if not set this gets set to the | ||
370 | * default ahci_stop_engine during ahci_save_initial_config, this can | ||
371 | * be overridden anytime before the host is activated. | ||
372 | */ | ||
373 | int (*stop_engine)(struct ata_port *ap); | ||
374 | |||
368 | irqreturn_t (*irq_handler)(int irq, void *dev_instance); | 375 | irqreturn_t (*irq_handler)(int irq, void *dev_instance); |
369 | 376 | ||
370 | /* only required for per-port MSI(-X) support */ | 377 | /* only required for per-port MSI(-X) support */ |
diff --git a/drivers/ata/ahci_qoriq.c b/drivers/ata/ahci_qoriq.c index 2685f28160f7..cfdef4d44ae9 100644 --- a/drivers/ata/ahci_qoriq.c +++ b/drivers/ata/ahci_qoriq.c | |||
@@ -96,7 +96,7 @@ static int ahci_qoriq_hardreset(struct ata_link *link, unsigned int *class, | |||
96 | 96 | ||
97 | DPRINTK("ENTER\n"); | 97 | DPRINTK("ENTER\n"); |
98 | 98 | ||
99 | ahci_stop_engine(ap); | 99 | hpriv->stop_engine(ap); |
100 | 100 | ||
101 | /* | 101 | /* |
102 | * There is a errata on ls1021a Rev1.0 and Rev2.0 which is: | 102 | * There is a errata on ls1021a Rev1.0 and Rev2.0 which is: |
diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index c2b5941d9184..ad58da7c9aff 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c | |||
@@ -165,7 +165,7 @@ static int xgene_ahci_restart_engine(struct ata_port *ap) | |||
165 | PORT_CMD_ISSUE, 0x0, 1, 100)) | 165 | PORT_CMD_ISSUE, 0x0, 1, 100)) |
166 | return -EBUSY; | 166 | return -EBUSY; |
167 | 167 | ||
168 | ahci_stop_engine(ap); | 168 | hpriv->stop_engine(ap); |
169 | ahci_start_fis_rx(ap); | 169 | ahci_start_fis_rx(ap); |
170 | 170 | ||
171 | /* | 171 | /* |
@@ -421,7 +421,7 @@ static int xgene_ahci_hardreset(struct ata_link *link, unsigned int *class, | |||
421 | portrxfis_saved = readl(port_mmio + PORT_FIS_ADDR); | 421 | portrxfis_saved = readl(port_mmio + PORT_FIS_ADDR); |
422 | portrxfishi_saved = readl(port_mmio + PORT_FIS_ADDR_HI); | 422 | portrxfishi_saved = readl(port_mmio + PORT_FIS_ADDR_HI); |
423 | 423 | ||
424 | ahci_stop_engine(ap); | 424 | hpriv->stop_engine(ap); |
425 | 425 | ||
426 | rc = xgene_ahci_do_hardreset(link, deadline, &online); | 426 | rc = xgene_ahci_do_hardreset(link, deadline, &online); |
427 | 427 | ||
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 | ||
diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c index aafb8cc03523..e67815b896fc 100644 --- a/drivers/ata/sata_highbank.c +++ b/drivers/ata/sata_highbank.c | |||
@@ -410,7 +410,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class, | |||
410 | int rc; | 410 | int rc; |
411 | int retry = 100; | 411 | int retry = 100; |
412 | 412 | ||
413 | ahci_stop_engine(ap); | 413 | hpriv->stop_engine(ap); |
414 | 414 | ||
415 | /* clear D2H reception area to properly wait for D2H FIS */ | 415 | /* clear D2H reception area to properly wait for D2H FIS */ |
416 | ata_tf_init(link->device, &tf); | 416 | ata_tf_init(link->device, &tf); |