diff options
author | Hans de Goede <hdegoede@redhat.com> | 2014-02-22 10:53:30 -0500 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2014-02-22 15:35:41 -0500 |
commit | 039ece38da45f5e6a94be3aa7611cf3634bc2461 (patch) | |
tree | c496379b086ca1c4251b1fd914ecafb68eb22063 /drivers/ata/libahci.c | |
parent | b2a52b6a0a03000d07edb359b4059d4d871a7602 (diff) |
libahci: Allow drivers to override start_engine
Allwinner A10 and A20 ARM SoCs have an AHCI sata controller which needs a
special register to be poked before starting the DMA engine.
This register gets reset on an ahci_stop_engine call, so there is no other
place then ahci_start_engine where this poking can be done.
This commit allows drivers to override ahci_start_engine behavior for use by
the Allwinner AHCI driver (and potentially other drivers in the future).
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'drivers/ata/libahci.c')
-rw-r--r-- | drivers/ata/libahci.c | 26 |
1 files changed, 19 insertions, 7 deletions
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 956851f0d44f..7985ae782679 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c | |||
@@ -393,6 +393,9 @@ static ssize_t ahci_show_em_supported(struct device *dev, | |||
393 | * | 393 | * |
394 | * If inconsistent, config values are fixed up by this function. | 394 | * If inconsistent, config values are fixed up by this function. |
395 | * | 395 | * |
396 | * If it is not set already this function sets hpriv->start_engine to | ||
397 | * ahci_start_engine. | ||
398 | * | ||
396 | * LOCKING: | 399 | * LOCKING: |
397 | * None. | 400 | * None. |
398 | */ | 401 | */ |
@@ -499,6 +502,9 @@ void ahci_save_initial_config(struct device *dev, | |||
499 | hpriv->cap = cap; | 502 | hpriv->cap = cap; |
500 | hpriv->cap2 = cap2; | 503 | hpriv->cap2 = cap2; |
501 | hpriv->port_map = port_map; | 504 | hpriv->port_map = port_map; |
505 | |||
506 | if (!hpriv->start_engine) | ||
507 | hpriv->start_engine = ahci_start_engine; | ||
502 | } | 508 | } |
503 | EXPORT_SYMBOL_GPL(ahci_save_initial_config); | 509 | EXPORT_SYMBOL_GPL(ahci_save_initial_config); |
504 | 510 | ||
@@ -765,7 +771,7 @@ static void ahci_start_port(struct ata_port *ap) | |||
765 | 771 | ||
766 | /* enable DMA */ | 772 | /* enable DMA */ |
767 | if (!(hpriv->flags & AHCI_HFLAG_DELAY_ENGINE)) | 773 | if (!(hpriv->flags & AHCI_HFLAG_DELAY_ENGINE)) |
768 | ahci_start_engine(ap); | 774 | hpriv->start_engine(ap); |
769 | 775 | ||
770 | /* turn on LEDs */ | 776 | /* turn on LEDs */ |
771 | if (ap->flags & ATA_FLAG_EM) { | 777 | if (ap->flags & ATA_FLAG_EM) { |
@@ -1234,7 +1240,7 @@ int ahci_kick_engine(struct ata_port *ap) | |||
1234 | 1240 | ||
1235 | /* restart engine */ | 1241 | /* restart engine */ |
1236 | out_restart: | 1242 | out_restart: |
1237 | ahci_start_engine(ap); | 1243 | hpriv->start_engine(ap); |
1238 | return rc; | 1244 | return rc; |
1239 | } | 1245 | } |
1240 | EXPORT_SYMBOL_GPL(ahci_kick_engine); | 1246 | EXPORT_SYMBOL_GPL(ahci_kick_engine); |
@@ -1426,6 +1432,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class, | |||
1426 | const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); | 1432 | const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); |
1427 | struct ata_port *ap = link->ap; | 1433 | struct ata_port *ap = link->ap; |
1428 | struct ahci_port_priv *pp = ap->private_data; | 1434 | struct ahci_port_priv *pp = ap->private_data; |
1435 | struct ahci_host_priv *hpriv = ap->host->private_data; | ||
1429 | u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; | 1436 | u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; |
1430 | struct ata_taskfile tf; | 1437 | struct ata_taskfile tf; |
1431 | bool online; | 1438 | bool online; |
@@ -1443,7 +1450,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class, | |||
1443 | rc = sata_link_hardreset(link, timing, deadline, &online, | 1450 | rc = sata_link_hardreset(link, timing, deadline, &online, |
1444 | ahci_check_ready); | 1451 | ahci_check_ready); |
1445 | 1452 | ||
1446 | ahci_start_engine(ap); | 1453 | hpriv->start_engine(ap); |
1447 | 1454 | ||
1448 | if (online) | 1455 | if (online) |
1449 | *class = ahci_dev_classify(ap); | 1456 | *class = ahci_dev_classify(ap); |
@@ -2007,10 +2014,12 @@ static void ahci_thaw(struct ata_port *ap) | |||
2007 | 2014 | ||
2008 | void ahci_error_handler(struct ata_port *ap) | 2015 | void ahci_error_handler(struct ata_port *ap) |
2009 | { | 2016 | { |
2017 | struct ahci_host_priv *hpriv = ap->host->private_data; | ||
2018 | |||
2010 | if (!(ap->pflags & ATA_PFLAG_FROZEN)) { | 2019 | if (!(ap->pflags & ATA_PFLAG_FROZEN)) { |
2011 | /* restart engine */ | 2020 | /* restart engine */ |
2012 | ahci_stop_engine(ap); | 2021 | ahci_stop_engine(ap); |
2013 | ahci_start_engine(ap); | 2022 | hpriv->start_engine(ap); |
2014 | } | 2023 | } |
2015 | 2024 | ||
2016 | sata_pmp_error_handler(ap); | 2025 | sata_pmp_error_handler(ap); |
@@ -2031,6 +2040,7 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) | |||
2031 | 2040 | ||
2032 | static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) | 2041 | static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) |
2033 | { | 2042 | { |
2043 | struct ahci_host_priv *hpriv = ap->host->private_data; | ||
2034 | void __iomem *port_mmio = ahci_port_base(ap); | 2044 | void __iomem *port_mmio = ahci_port_base(ap); |
2035 | struct ata_device *dev = ap->link.device; | 2045 | struct ata_device *dev = ap->link.device; |
2036 | u32 devslp, dm, dito, mdat, deto; | 2046 | u32 devslp, dm, dito, mdat, deto; |
@@ -2094,7 +2104,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) | |||
2094 | PORT_DEVSLP_ADSE); | 2104 | PORT_DEVSLP_ADSE); |
2095 | writel(devslp, port_mmio + PORT_DEVSLP); | 2105 | writel(devslp, port_mmio + PORT_DEVSLP); |
2096 | 2106 | ||
2097 | ahci_start_engine(ap); | 2107 | hpriv->start_engine(ap); |
2098 | 2108 | ||
2099 | /* enable device sleep feature for the drive */ | 2109 | /* enable device sleep feature for the drive */ |
2100 | err_mask = ata_dev_set_feature(dev, | 2110 | err_mask = ata_dev_set_feature(dev, |
@@ -2106,6 +2116,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) | |||
2106 | 2116 | ||
2107 | static void ahci_enable_fbs(struct ata_port *ap) | 2117 | static void ahci_enable_fbs(struct ata_port *ap) |
2108 | { | 2118 | { |
2119 | struct ahci_host_priv *hpriv = ap->host->private_data; | ||
2109 | struct ahci_port_priv *pp = ap->private_data; | 2120 | struct ahci_port_priv *pp = ap->private_data; |
2110 | void __iomem *port_mmio = ahci_port_base(ap); | 2121 | void __iomem *port_mmio = ahci_port_base(ap); |
2111 | u32 fbs; | 2122 | u32 fbs; |
@@ -2134,11 +2145,12 @@ static void ahci_enable_fbs(struct ata_port *ap) | |||
2134 | } else | 2145 | } else |
2135 | dev_err(ap->host->dev, "Failed to enable FBS\n"); | 2146 | dev_err(ap->host->dev, "Failed to enable FBS\n"); |
2136 | 2147 | ||
2137 | ahci_start_engine(ap); | 2148 | hpriv->start_engine(ap); |
2138 | } | 2149 | } |
2139 | 2150 | ||
2140 | static void ahci_disable_fbs(struct ata_port *ap) | 2151 | static void ahci_disable_fbs(struct ata_port *ap) |
2141 | { | 2152 | { |
2153 | struct ahci_host_priv *hpriv = ap->host->private_data; | ||
2142 | struct ahci_port_priv *pp = ap->private_data; | 2154 | struct ahci_port_priv *pp = ap->private_data; |
2143 | void __iomem *port_mmio = ahci_port_base(ap); | 2155 | void __iomem *port_mmio = ahci_port_base(ap); |
2144 | u32 fbs; | 2156 | u32 fbs; |
@@ -2166,7 +2178,7 @@ static void ahci_disable_fbs(struct ata_port *ap) | |||
2166 | pp->fbs_enabled = false; | 2178 | pp->fbs_enabled = false; |
2167 | } | 2179 | } |
2168 | 2180 | ||
2169 | ahci_start_engine(ap); | 2181 | hpriv->start_engine(ap); |
2170 | } | 2182 | } |
2171 | 2183 | ||
2172 | static void ahci_pmp_attach(struct ata_port *ap) | 2184 | static void ahci_pmp_attach(struct ata_port *ap) |