diff options
| author | Shawn Guo <shawn.guo@freescale.com> | 2014-05-28 11:05:39 -0400 |
|---|---|---|
| committer | Tejun Heo <tj@kernel.org> | 2014-06-19 10:14:58 -0400 |
| commit | e6dd42a917e62d916c6e513dbf87a4dec8cf3a1c (patch) | |
| tree | a520dff64c52c0dea954afcce936b29398ccb3ca /drivers/ata | |
| parent | acbd573354bb7b7b7a3891018a39f4b3976b0c43 (diff) | |
ahci: imx: manage only sata_ref_clk in imx_sata_enable[disable]
Doing suspend/resume on imx6q and imx53 boards with no SATA disk
attached will trigger the following warning.
------------[ cut here ]------------
WARNING: CPU: 0 PID: 661 at drivers/ata/libahci.c:224 ahci_enable_ahci+0x74/0x8)
Modules linked in:
CPU: 0 PID: 661 Comm: sh Tainted: G W 3.15.0-rc5-next-20140521-000027
Backtrace:
[<80011c90>] (dump_backtrace) from [<80011e2c>] (show_stack+0x18/0x1c)
r6:803a22f4 r5:00000000 r4:00000000 r3:00000000
[<80011e14>] (show_stack) from [<80661e60>] (dump_stack+0x88/0xa4)
[<80661dd8>] (dump_stack) from [<80028fdc>] (warn_slowpath_common+0x70/0x94)
r5:00000009 r4:00000000
[<80028f6c>] (warn_slowpath_common) from [<80029024>] (warn_slowpath_null+0x24/)
r8:808f68c4 r7:00000000 r6:00000000 r5:00000000 r4:e0810004
[<80029000>] (warn_slowpath_null) from [<803a22f4>] (ahci_enable_ahci+0x74/0x80)
[<803a2280>] (ahci_enable_ahci) from [<803a2324>] (ahci_reset_controller+0x24/0)
r8:ddcd9410 r7:80351178 r6:ddcd9444 r5:dde8b850 r4:e0810000 r3:ddf35e90
[<803a2300>] (ahci_reset_controller) from [<803a2c68>] (ahci_platform_resume_ho)
r7:80351178 r6:ddcd9444 r5:dde8b850 r4:ddcd9410
[<803a2c30>] (ahci_platform_resume_host) from [<803a38f0>] (imx_ahci_resume+0x2)
r5:00000000 r4:ddcd9410
[<803a38c4>] (imx_ahci_resume) from [<803511ac>] (platform_pm_resume+0x34/0x54)
....
The reason is that the SATA controller has no working clock at this
point, and thus ahci_enable_ahci() fails to enable the controller. In
case that there is no SATA disk attached, the imx_sata_disable() gets
called in ahci_imx_error_handler(), and both sata_clk and sata_ref_clk
will be disabled there. Because all the imx_sata_enable() calls
afterward will return immediately due to imxpriv->no_device check, the
SATA controller working clock sata_clk will never get any chance to be
enabled again.
This is a regression caused by commit 90870d79d4f2 (ahci-imx: Port to
library-ised ahci_platform). Before the commit, only sata_ref_clk is
managed by the driver in enable/disable function. But after the commit,
all the clocks are enabled/disabled in a row by ahci platform helpers
ahci_platform_enable[disable]_clks. Since ahb_clk is a bus clock which
does not have gate at all, and i.MX low-power hardware module already
manages sata_clk across suspend/resume cycle, the only clock that needs
to be managed by software is sata_ref_clk.
So instead of using ahci_platform_enable[disable]_clks to manage all
the clocks in a row from imx_sata_enable[disable], we should manage
only sata_ref_clk in there.
Reported-by: Fabio Estevam <fabio.estevam@freescale.com>
Fixes: 90870d79d4f2 (ahci-imx: Port to library-ised ahci_platform)
Signed-off-by: Shawn Guo <shawn.guo@freescale.com>
Acked-by: Hans de Goede <hdegoede@redhat.com>
Diffstat (limited to 'drivers/ata')
| -rw-r--r-- | drivers/ata/ahci_imx.c | 35 |
1 files changed, 31 insertions, 4 deletions
diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c index 3a901520c62b..4384a7d72133 100644 --- a/drivers/ata/ahci_imx.c +++ b/drivers/ata/ahci_imx.c | |||
| @@ -58,6 +58,8 @@ enum ahci_imx_type { | |||
| 58 | struct imx_ahci_priv { | 58 | struct imx_ahci_priv { |
| 59 | struct platform_device *ahci_pdev; | 59 | struct platform_device *ahci_pdev; |
| 60 | enum ahci_imx_type type; | 60 | enum ahci_imx_type type; |
| 61 | struct clk *sata_clk; | ||
| 62 | struct clk *sata_ref_clk; | ||
| 61 | struct clk *ahb_clk; | 63 | struct clk *ahb_clk; |
| 62 | struct regmap *gpr; | 64 | struct regmap *gpr; |
| 63 | bool no_device; | 65 | bool no_device; |
| @@ -224,7 +226,7 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv) | |||
| 224 | return ret; | 226 | return ret; |
| 225 | } | 227 | } |
| 226 | 228 | ||
| 227 | ret = ahci_platform_enable_clks(hpriv); | 229 | ret = clk_prepare_enable(imxpriv->sata_ref_clk); |
| 228 | if (ret < 0) | 230 | if (ret < 0) |
| 229 | goto disable_regulator; | 231 | goto disable_regulator; |
| 230 | 232 | ||
| @@ -291,7 +293,7 @@ static void imx_sata_disable(struct ahci_host_priv *hpriv) | |||
| 291 | !IMX6Q_GPR13_SATA_MPLL_CLK_EN); | 293 | !IMX6Q_GPR13_SATA_MPLL_CLK_EN); |
| 292 | } | 294 | } |
| 293 | 295 | ||
| 294 | ahci_platform_disable_clks(hpriv); | 296 | clk_disable_unprepare(imxpriv->sata_ref_clk); |
| 295 | 297 | ||
| 296 | if (hpriv->target_pwr) | 298 | if (hpriv->target_pwr) |
| 297 | regulator_disable(hpriv->target_pwr); | 299 | regulator_disable(hpriv->target_pwr); |
| @@ -385,6 +387,19 @@ static int imx_ahci_probe(struct platform_device *pdev) | |||
| 385 | imxpriv->no_device = false; | 387 | imxpriv->no_device = false; |
| 386 | imxpriv->first_time = true; | 388 | imxpriv->first_time = true; |
| 387 | imxpriv->type = (enum ahci_imx_type)of_id->data; | 389 | imxpriv->type = (enum ahci_imx_type)of_id->data; |
| 390 | |||
| 391 | imxpriv->sata_clk = devm_clk_get(dev, "sata"); | ||
| 392 | if (IS_ERR(imxpriv->sata_clk)) { | ||
| 393 | dev_err(dev, "can't get sata clock.\n"); | ||
| 394 | return PTR_ERR(imxpriv->sata_clk); | ||
| 395 | } | ||
| 396 | |||
| 397 | imxpriv->sata_ref_clk = devm_clk_get(dev, "sata_ref"); | ||
| 398 | if (IS_ERR(imxpriv->sata_ref_clk)) { | ||
| 399 | dev_err(dev, "can't get sata_ref clock.\n"); | ||
| 400 | return PTR_ERR(imxpriv->sata_ref_clk); | ||
| 401 | } | ||
| 402 | |||
| 388 | imxpriv->ahb_clk = devm_clk_get(dev, "ahb"); | 403 | imxpriv->ahb_clk = devm_clk_get(dev, "ahb"); |
| 389 | if (IS_ERR(imxpriv->ahb_clk)) { | 404 | if (IS_ERR(imxpriv->ahb_clk)) { |
| 390 | dev_err(dev, "can't get ahb clock.\n"); | 405 | dev_err(dev, "can't get ahb clock.\n"); |
| @@ -407,10 +422,14 @@ static int imx_ahci_probe(struct platform_device *pdev) | |||
| 407 | 422 | ||
| 408 | hpriv->plat_data = imxpriv; | 423 | hpriv->plat_data = imxpriv; |
| 409 | 424 | ||
| 410 | ret = imx_sata_enable(hpriv); | 425 | ret = clk_prepare_enable(imxpriv->sata_clk); |
| 411 | if (ret) | 426 | if (ret) |
| 412 | return ret; | 427 | return ret; |
| 413 | 428 | ||
| 429 | ret = imx_sata_enable(hpriv); | ||
| 430 | if (ret) | ||
| 431 | goto disable_clk; | ||
| 432 | |||
| 414 | /* | 433 | /* |
| 415 | * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL, | 434 | * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL, |
| 416 | * and IP vendor specific register IMX_TIMER1MS. | 435 | * and IP vendor specific register IMX_TIMER1MS. |
| @@ -435,16 +454,24 @@ static int imx_ahci_probe(struct platform_device *pdev) | |||
| 435 | ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info, | 454 | ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info, |
| 436 | 0, 0, 0); | 455 | 0, 0, 0); |
| 437 | if (ret) | 456 | if (ret) |
| 438 | imx_sata_disable(hpriv); | 457 | goto disable_sata; |
| 458 | |||
| 459 | return 0; | ||
| 439 | 460 | ||
| 461 | disable_sata: | ||
| 462 | imx_sata_disable(hpriv); | ||
| 463 | disable_clk: | ||
| 464 | clk_disable_unprepare(imxpriv->sata_clk); | ||
| 440 | return ret; | 465 | return ret; |
| 441 | } | 466 | } |
| 442 | 467 | ||
| 443 | static void ahci_imx_host_stop(struct ata_host *host) | 468 | static void ahci_imx_host_stop(struct ata_host *host) |
| 444 | { | 469 | { |
| 445 | struct ahci_host_priv *hpriv = host->private_data; | 470 | struct ahci_host_priv *hpriv = host->private_data; |
| 471 | struct imx_ahci_priv *imxpriv = hpriv->plat_data; | ||
| 446 | 472 | ||
| 447 | imx_sata_disable(hpriv); | 473 | imx_sata_disable(hpriv); |
| 474 | clk_disable_unprepare(imxpriv->sata_clk); | ||
| 448 | } | 475 | } |
| 449 | 476 | ||
| 450 | #ifdef CONFIG_PM_SLEEP | 477 | #ifdef CONFIG_PM_SLEEP |
