diff options
author | Johan Hovold <johan@kernel.org> | 2016-11-17 11:39:58 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-11-18 13:48:52 -0500 |
commit | c46ab7e08c79be7400f6d59edbc6f26a91941c5a (patch) | |
tree | 1e6ac5331ccbfed283b37c2bf134568b210f47c9 | |
parent | 06ba3b2133dc203e1e9bc36cee7f0839b79a9e8b (diff) |
net: ethernet: ti: cpsw: fix bad register access in probe error path
Make sure to keep the platform device runtime-resumed throughout probe
to avoid accessing the CPSW registers in the error path (e.g. for
deferred probe) with clocks disabled:
Unhandled fault: external abort on non-linefetch (0x1008) at 0xd0872d08
...
[<c04fabcc>] (cpsw_ale_control_set) from [<c04fb8b4>] (cpsw_ale_destroy+0x2c/0x44)
[<c04fb8b4>] (cpsw_ale_destroy) from [<c04fea58>] (cpsw_probe+0xbd0/0x10c4)
[<c04fea58>] (cpsw_probe) from [<c047b2a0>] (platform_drv_probe+0x5c/0xc0)
Fixes: df828598a755 ("netdev: driver: ethernet: Add TI CPSW driver")
Signed-off-by: Johan Hovold <johan@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/ti/cpsw.c | 11 |
1 files changed, 7 insertions, 4 deletions
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index c6cff3d2ff05..f60f8ab7c1e3 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c | |||
@@ -2641,13 +2641,12 @@ static int cpsw_probe(struct platform_device *pdev) | |||
2641 | goto clean_runtime_disable_ret; | 2641 | goto clean_runtime_disable_ret; |
2642 | } | 2642 | } |
2643 | cpsw->version = readl(&cpsw->regs->id_ver); | 2643 | cpsw->version = readl(&cpsw->regs->id_ver); |
2644 | pm_runtime_put_sync(&pdev->dev); | ||
2645 | 2644 | ||
2646 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 2645 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
2647 | cpsw->wr_regs = devm_ioremap_resource(&pdev->dev, res); | 2646 | cpsw->wr_regs = devm_ioremap_resource(&pdev->dev, res); |
2648 | if (IS_ERR(cpsw->wr_regs)) { | 2647 | if (IS_ERR(cpsw->wr_regs)) { |
2649 | ret = PTR_ERR(cpsw->wr_regs); | 2648 | ret = PTR_ERR(cpsw->wr_regs); |
2650 | goto clean_runtime_disable_ret; | 2649 | goto clean_pm_runtime_put_ret; |
2651 | } | 2650 | } |
2652 | 2651 | ||
2653 | memset(&dma_params, 0, sizeof(dma_params)); | 2652 | memset(&dma_params, 0, sizeof(dma_params)); |
@@ -2684,7 +2683,7 @@ static int cpsw_probe(struct platform_device *pdev) | |||
2684 | default: | 2683 | default: |
2685 | dev_err(priv->dev, "unknown version 0x%08x\n", cpsw->version); | 2684 | dev_err(priv->dev, "unknown version 0x%08x\n", cpsw->version); |
2686 | ret = -ENODEV; | 2685 | ret = -ENODEV; |
2687 | goto clean_runtime_disable_ret; | 2686 | goto clean_pm_runtime_put_ret; |
2688 | } | 2687 | } |
2689 | for (i = 0; i < cpsw->data.slaves; i++) { | 2688 | for (i = 0; i < cpsw->data.slaves; i++) { |
2690 | struct cpsw_slave *slave = &cpsw->slaves[i]; | 2689 | struct cpsw_slave *slave = &cpsw->slaves[i]; |
@@ -2713,7 +2712,7 @@ static int cpsw_probe(struct platform_device *pdev) | |||
2713 | if (!cpsw->dma) { | 2712 | if (!cpsw->dma) { |
2714 | dev_err(priv->dev, "error initializing dma\n"); | 2713 | dev_err(priv->dev, "error initializing dma\n"); |
2715 | ret = -ENOMEM; | 2714 | ret = -ENOMEM; |
2716 | goto clean_runtime_disable_ret; | 2715 | goto clean_pm_runtime_put_ret; |
2717 | } | 2716 | } |
2718 | 2717 | ||
2719 | cpsw->txch[0] = cpdma_chan_create(cpsw->dma, 0, cpsw_tx_handler, 0); | 2718 | cpsw->txch[0] = cpdma_chan_create(cpsw->dma, 0, cpsw_tx_handler, 0); |
@@ -2815,12 +2814,16 @@ static int cpsw_probe(struct platform_device *pdev) | |||
2815 | } | 2814 | } |
2816 | } | 2815 | } |
2817 | 2816 | ||
2817 | pm_runtime_put(&pdev->dev); | ||
2818 | |||
2818 | return 0; | 2819 | return 0; |
2819 | 2820 | ||
2820 | clean_ale_ret: | 2821 | clean_ale_ret: |
2821 | cpsw_ale_destroy(cpsw->ale); | 2822 | cpsw_ale_destroy(cpsw->ale); |
2822 | clean_dma_ret: | 2823 | clean_dma_ret: |
2823 | cpdma_ctlr_destroy(cpsw->dma); | 2824 | cpdma_ctlr_destroy(cpsw->dma); |
2825 | clean_pm_runtime_put_ret: | ||
2826 | pm_runtime_put_sync(&pdev->dev); | ||
2824 | clean_runtime_disable_ret: | 2827 | clean_runtime_disable_ret: |
2825 | pm_runtime_disable(&pdev->dev); | 2828 | pm_runtime_disable(&pdev->dev); |
2826 | clean_ndev_ret: | 2829 | clean_ndev_ret: |