From e2f8d555ec04a0beb965ea76e3a150993e8f0436 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 22 Feb 2013 06:40:45 +0000 Subject: [PATCH] net: fec: Fix division by zero commit 7f7d6c282 (net: fec: Ensure that initialization is done prior to request_irq()) placed fec_ptp_init() into a point that ptp clock was not available, which causes a division by zero in fec_ptp_start_cyclecounter(): [ 17.895723] Division by zero in kernel. [ 17.899571] Backtrace: [ 17.902094] [<80012564>] (dump_backtrace+0x0/0x10c) from [<8056deec>] (dump_stack+0x18/0x1c) [ 17.910539] r6:bfba8500 r5:8075c950 r4:bfba8000 r3:bfbd0000 [ 17.916284] [<8056ded4>] (dump_stack+0x0/0x1c) from [<80012688>] (__div0+0x18/0x20) [ 17.923968] [<80012670>] (__div0+0x0/0x20) from [<802829c4>] (Ldiv0+0x8/0x10) [ 17.931140] [<80398534>] (fec_ptp_start_cyclecounter+0x0/0x110) from [<80394f64>] (fec_restart+0x6c8/0x754) [ 17.940898] [<8039489c>] (fec_restart+0x0/0x754) from [<803969a0>] (fec_enet_adjust_link+0xdc/0x108) [ 17.950046] [<803968c4>] (fec_enet_adjust_link+0x0/0x108) from [<80390bc4>] (phy_state_machine+0x178/0x534) ... Fix this by rearraging the code so that fec_ptp_init() is called only after the clocks have been properly acquired. Tested on both mx53 and mx6 platforms. Reported-by: Jim Baxter Signed-off-by: Fabio Estevam Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec.c | 96 ++++++++++++++-------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c index 2dbb36c985c7..fccc3bf2141d 100644 --- a/drivers/net/ethernet/freescale/fec.c +++ b/drivers/net/ethernet/freescale/fec.c @@ -1782,8 +1782,49 @@ fec_probe(struct platform_device *pdev) fep->phy_interface = ret; } + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(pinctrl)) { + ret = PTR_ERR(pinctrl); + goto failed_pin; + } + + fep->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(fep->clk_ipg)) { + ret = PTR_ERR(fep->clk_ipg); + goto failed_clk; + } + + fep->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); + if (IS_ERR(fep->clk_ahb)) { + ret = PTR_ERR(fep->clk_ahb); + goto failed_clk; + } + + fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp"); fep->bufdesc_ex = pdev->id_entry->driver_data & FEC_QUIRK_HAS_BUFDESC_EX; + if (IS_ERR(fep->clk_ptp)) { + ret = PTR_ERR(fep->clk_ptp); + fep->bufdesc_ex = 0; + } + + clk_prepare_enable(fep->clk_ahb); + clk_prepare_enable(fep->clk_ipg); + if (!IS_ERR(fep->clk_ptp)) + clk_prepare_enable(fep->clk_ptp); + + reg_phy = devm_regulator_get(&pdev->dev, "phy"); + if (!IS_ERR(reg_phy)) { + ret = regulator_enable(reg_phy); + if (ret) { + dev_err(&pdev->dev, + "Failed to enable phy regulator: %d\n", ret); + goto failed_regulator; + } + } + + fec_reset_phy(pdev); + if (fep->bufdesc_ex) fec_ptp_init(ndev, pdev); @@ -1809,47 +1850,6 @@ fec_probe(struct platform_device *pdev) } } - pinctrl = devm_pinctrl_get_select_default(&pdev->dev); - if (IS_ERR(pinctrl)) { - ret = PTR_ERR(pinctrl); - goto failed_pin; - } - - fep->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); - if (IS_ERR(fep->clk_ipg)) { - ret = PTR_ERR(fep->clk_ipg); - goto failed_clk; - } - - fep->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); - if (IS_ERR(fep->clk_ahb)) { - ret = PTR_ERR(fep->clk_ahb); - goto failed_clk; - } - - fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp"); - if (IS_ERR(fep->clk_ptp)) { - ret = PTR_ERR(fep->clk_ptp); - fep->bufdesc_ex = 0; - } - - clk_prepare_enable(fep->clk_ahb); - clk_prepare_enable(fep->clk_ipg); - if (!IS_ERR(fep->clk_ptp)) - clk_prepare_enable(fep->clk_ptp); - - reg_phy = devm_regulator_get(&pdev->dev, "phy"); - if (!IS_ERR(reg_phy)) { - ret = regulator_enable(reg_phy); - if (ret) { - dev_err(&pdev->dev, - "Failed to enable phy regulator: %d\n", ret); - goto failed_regulator; - } - } - - fec_reset_phy(pdev); - ret = fec_enet_mii_init(pdev); if (ret) goto failed_mii_init; @@ -1866,6 +1866,13 @@ fec_probe(struct platform_device *pdev) failed_register: fec_enet_mii_remove(fep); failed_mii_init: +failed_init: + for (i = 0; i < FEC_IRQ_NUM; i++) { + irq = platform_get_irq(pdev, i); + if (irq > 0) + free_irq(irq, ndev); + } +failed_irq: failed_regulator: clk_disable_unprepare(fep->clk_ahb); clk_disable_unprepare(fep->clk_ipg); @@ -1873,14 +1880,7 @@ failed_regulator: clk_disable_unprepare(fep->clk_ptp); failed_pin: failed_clk: - for (i = 0; i < FEC_IRQ_NUM; i++) { - irq = platform_get_irq(pdev, i); - if (irq > 0) - free_irq(irq, ndev); - } -failed_irq: iounmap(fep->hwp); -failed_init: failed_ioremap: free_netdev(ndev); failed_alloc_etherdev: