| From foo@baz Sun Jun 17 12:07:33 CEST 2018 |
| From: Evan Wang <xswang@marvell.com> |
| Date: Fri, 13 Apr 2018 12:32:30 +0800 |
| Subject: libahci: Allow drivers to override stop_engine |
| |
| From: Evan Wang <xswang@marvell.com> |
| |
| [ Upstream commit fa89f53bd7288d6aa7a982841119e7123faf5a53 ] |
| |
| 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> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/ata/ahci.c | 6 +++--- |
| drivers/ata/ahci.h | 7 +++++++ |
| drivers/ata/ahci_qoriq.c | 2 +- |
| drivers/ata/ahci_xgene.c | 4 ++-- |
| drivers/ata/libahci.c | 20 ++++++++++++-------- |
| drivers/ata/sata_highbank.c | 2 +- |
| 6 files changed, 26 insertions(+), 15 deletions(-) |
| |
| --- a/drivers/ata/ahci.c |
| +++ b/drivers/ata/ahci.c |
| @@ -699,7 +699,7 @@ static int ahci_vt8251_hardreset(struct |
| |
| DPRINTK("ENTER\n"); |
| |
| - ahci_stop_engine(ap); |
| + hpriv->stop_engine(ap); |
| |
| rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), |
| deadline, &online, NULL); |
| @@ -725,7 +725,7 @@ static int ahci_p5wdh_hardreset(struct a |
| bool online; |
| int rc; |
| |
| - ahci_stop_engine(ap); |
| + hpriv->stop_engine(ap); |
| |
| /* clear D2H reception area to properly wait for D2H FIS */ |
| ata_tf_init(link->device, &tf); |
| @@ -789,7 +789,7 @@ static int ahci_avn_hardreset(struct ata |
| |
| DPRINTK("ENTER\n"); |
| |
| - ahci_stop_engine(ap); |
| + hpriv->stop_engine(ap); |
| |
| for (i = 0; i < 2; i++) { |
| u16 val; |
| --- a/drivers/ata/ahci.h |
| +++ b/drivers/ata/ahci.h |
| @@ -365,6 +365,13 @@ struct ahci_host_priv { |
| * be overridden anytime before the host is activated. |
| */ |
| void (*start_engine)(struct ata_port *ap); |
| + /* |
| + * Optional ahci_stop_engine override, if not set this gets set to the |
| + * default ahci_stop_engine during ahci_save_initial_config, this can |
| + * be overridden anytime before the host is activated. |
| + */ |
| + int (*stop_engine)(struct ata_port *ap); |
| + |
| irqreturn_t (*irq_handler)(int irq, void *dev_instance); |
| |
| /* only required for per-port MSI(-X) support */ |
| --- a/drivers/ata/ahci_qoriq.c |
| +++ b/drivers/ata/ahci_qoriq.c |
| @@ -96,7 +96,7 @@ static int ahci_qoriq_hardreset(struct a |
| |
| DPRINTK("ENTER\n"); |
| |
| - ahci_stop_engine(ap); |
| + hpriv->stop_engine(ap); |
| |
| /* |
| * There is a errata on ls1021a Rev1.0 and Rev2.0 which is: |
| --- a/drivers/ata/ahci_xgene.c |
| +++ b/drivers/ata/ahci_xgene.c |
| @@ -165,7 +165,7 @@ static int xgene_ahci_restart_engine(str |
| PORT_CMD_ISSUE, 0x0, 1, 100)) |
| return -EBUSY; |
| |
| - ahci_stop_engine(ap); |
| + hpriv->stop_engine(ap); |
| ahci_start_fis_rx(ap); |
| |
| /* |
| @@ -421,7 +421,7 @@ static int xgene_ahci_hardreset(struct a |
| portrxfis_saved = readl(port_mmio + PORT_FIS_ADDR); |
| portrxfishi_saved = readl(port_mmio + PORT_FIS_ADDR_HI); |
| |
| - ahci_stop_engine(ap); |
| + hpriv->stop_engine(ap); |
| |
| rc = xgene_ahci_do_hardreset(link, deadline, &online); |
| |
| --- a/drivers/ata/libahci.c |
| +++ b/drivers/ata/libahci.c |
| @@ -560,6 +560,9 @@ void ahci_save_initial_config(struct dev |
| 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_p |
| 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 *l |
| |
| 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 |
| |
| 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(s |
| 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_p |
| 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_ |
| return; |
| } |
| |
| - rc = ahci_stop_engine(ap); |
| + rc = hpriv->stop_engine(ap); |
| if (rc) |
| return; |
| |
| --- a/drivers/ata/sata_highbank.c |
| +++ b/drivers/ata/sata_highbank.c |
| @@ -410,7 +410,7 @@ static int ahci_highbank_hardreset(struc |
| int rc; |
| int retry = 100; |
| |
| - ahci_stop_engine(ap); |
| + hpriv->stop_engine(ap); |
| |
| /* clear D2H reception area to properly wait for D2H FIS */ |
| ata_tf_init(link->device, &tf); |