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 | |
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')
-rw-r--r-- | drivers/ata/ahci.c | 6 | ||||
-rw-r--r-- | drivers/ata/ahci.h | 6 | ||||
-rw-r--r-- | drivers/ata/libahci.c | 26 | ||||
-rw-r--r-- | drivers/ata/sata_highbank.c | 3 |
4 files changed, 31 insertions, 10 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index b6a49ce71f6e..1d4efe540604 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c | |||
@@ -563,6 +563,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, | |||
563 | unsigned long deadline) | 563 | unsigned long deadline) |
564 | { | 564 | { |
565 | struct ata_port *ap = link->ap; | 565 | struct ata_port *ap = link->ap; |
566 | struct ahci_host_priv *hpriv = ap->host->private_data; | ||
566 | bool online; | 567 | bool online; |
567 | int rc; | 568 | int rc; |
568 | 569 | ||
@@ -573,7 +574,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, | |||
573 | rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), | 574 | rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), |
574 | deadline, &online, NULL); | 575 | deadline, &online, NULL); |
575 | 576 | ||
576 | ahci_start_engine(ap); | 577 | hpriv->start_engine(ap); |
577 | 578 | ||
578 | DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); | 579 | DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); |
579 | 580 | ||
@@ -588,6 +589,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, | |||
588 | { | 589 | { |
589 | struct ata_port *ap = link->ap; | 590 | struct ata_port *ap = link->ap; |
590 | struct ahci_port_priv *pp = ap->private_data; | 591 | struct ahci_port_priv *pp = ap->private_data; |
592 | struct ahci_host_priv *hpriv = ap->host->private_data; | ||
591 | u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; | 593 | u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; |
592 | struct ata_taskfile tf; | 594 | struct ata_taskfile tf; |
593 | bool online; | 595 | bool online; |
@@ -603,7 +605,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, | |||
603 | rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), | 605 | rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), |
604 | deadline, &online, NULL); | 606 | deadline, &online, NULL); |
605 | 607 | ||
606 | ahci_start_engine(ap); | 608 | hpriv->start_engine(ap); |
607 | 609 | ||
608 | /* The pseudo configuration device on SIMG4726 attached to | 610 | /* The pseudo configuration device on SIMG4726 attached to |
609 | * ASUS P5W-DH Deluxe doesn't send signature FIS after | 611 | * ASUS P5W-DH Deluxe doesn't send signature FIS after |
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 2289efdf8203..64d1a99de5e4 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h | |||
@@ -323,6 +323,12 @@ struct ahci_host_priv { | |||
323 | u32 em_msg_type; /* EM message type */ | 323 | u32 em_msg_type; /* EM message type */ |
324 | struct clk *clk; /* Only for platforms supporting clk */ | 324 | struct clk *clk; /* Only for platforms supporting clk */ |
325 | void *plat_data; /* Other platform data */ | 325 | void *plat_data; /* Other platform data */ |
326 | /* | ||
327 | * Optional ahci_start_engine override, if not set this gets set to the | ||
328 | * default ahci_start_engine during ahci_save_initial_config, this can | ||
329 | * be overridden anytime before the host is activated. | ||
330 | */ | ||
331 | void (*start_engine)(struct ata_port *ap); | ||
326 | }; | 332 | }; |
327 | 333 | ||
328 | extern int ahci_ignore_sss; | 334 | extern int ahci_ignore_sss; |
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) |
diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c index 5a68b7b8f491..d4df0bf9a55a 100644 --- a/drivers/ata/sata_highbank.c +++ b/drivers/ata/sata_highbank.c | |||
@@ -402,6 +402,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class, | |||
402 | static const unsigned long timing[] = { 5, 100, 500}; | 402 | static const unsigned long timing[] = { 5, 100, 500}; |
403 | struct ata_port *ap = link->ap; | 403 | struct ata_port *ap = link->ap; |
404 | struct ahci_port_priv *pp = ap->private_data; | 404 | struct ahci_port_priv *pp = ap->private_data; |
405 | struct ahci_host_priv *hpriv = ap->host->private_data; | ||
405 | u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; | 406 | u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; |
406 | struct ata_taskfile tf; | 407 | struct ata_taskfile tf; |
407 | bool online; | 408 | bool online; |
@@ -430,7 +431,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class, | |||
430 | break; | 431 | break; |
431 | } while (!online && retry--); | 432 | } while (!online && retry--); |
432 | 433 | ||
433 | ahci_start_engine(ap); | 434 | hpriv->start_engine(ap); |
434 | 435 | ||
435 | if (online) | 436 | if (online) |
436 | *class = ahci_dev_classify(ap); | 437 | *class = ahci_dev_classify(ap); |