| From f137510aa8ae4e0e87c34f20ec29fae6fda13406 Mon Sep 17 00:00:00 2001 |
| From: Ben Dooks <ben.dooks@codethink.co.uk> |
| Date: Fri, 21 Mar 2014 12:09:14 +0100 |
| Subject: sh_eth: ensure pm_runtime cannot suspend the device during init |
| |
| The pm_rumtime work queue is causing the device to be suspended during |
| initialisation, thus the initialisation may not be able to access registers |
| properly. As the code is called from a work queue, it is possible that this |
| is not seen from certain configurations/builds due to the asynchronos |
| nature of the code. |
| |
| Another issue has also been found where the network device registration |
| calls back into the driver thus causing further pm_runtime calls that |
| also caused issues with the MDIO bus code. This has now been checked |
| and is the only place the MDIO can be called without the device open. |
| |
| Use pm_runtime_get_sync() and pm_runtime_put() to ensure that the |
| pm system does not suspend it during the probe() call and remove the |
| now unnecessary pm_runtime_resume() call. Also add a call in the error |
| path to call pm_runtime_disable(). |
| |
| This fixes the external abort that can cause /sbin/init or other such |
| init processed to die. |
| |
| Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk> |
| Tested-by: Geert Uytterhoeven <geert@linux-m68k.org> |
| Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| (cherry picked from commit b5893a08812602de164fa5ac6494f84df8d09a4f) |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| --- |
| drivers/net/ethernet/renesas/sh_eth.c | 8 ++++++-- |
| 1 file changed, 6 insertions(+), 2 deletions(-) |
| |
| diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c |
| index 1043bbb30061..08ed9a30c3a7 100644 |
| --- a/drivers/net/ethernet/renesas/sh_eth.c |
| +++ b/drivers/net/ethernet/renesas/sh_eth.c |
| @@ -2786,6 +2786,9 @@ static int sh_eth_drv_probe(struct platform_device *pdev) |
| if (!ndev) |
| return -ENOMEM; |
| |
| + pm_runtime_enable(&pdev->dev); |
| + pm_runtime_get_sync(&pdev->dev); |
| + |
| /* The sh Ether-specific entries in the device structure. */ |
| ndev->base_addr = res->start; |
| devno = pdev->id; |
| @@ -2813,8 +2816,6 @@ static int sh_eth_drv_probe(struct platform_device *pdev) |
| |
| spin_lock_init(&mdp->lock); |
| mdp->pdev = pdev; |
| - pm_runtime_enable(&pdev->dev); |
| - pm_runtime_resume(&pdev->dev); |
| |
| if (pdev->dev.of_node) |
| pd = sh_eth_parse_dt(&pdev->dev); |
| @@ -2912,6 +2913,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev) |
| netdev_info(ndev, "Base address at 0x%x, %pM, IRQ %d.\n", |
| (u32)ndev->base_addr, ndev->dev_addr, ndev->irq); |
| |
| + pm_runtime_put(&pdev->dev); |
| platform_set_drvdata(pdev, ndev); |
| |
| return ret; |
| @@ -2925,6 +2927,8 @@ out_release: |
| if (ndev) |
| free_netdev(ndev); |
| |
| + pm_runtime_put(&pdev->dev); |
| + pm_runtime_disable(&pdev->dev); |
| return ret; |
| } |
| |
| -- |
| 2.1.2 |
| |