diff options
author | Fabio Estevam <fabio.estevam@freescale.com> | 2013-02-22 01:40:45 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-02-22 15:10:19 -0500 |
commit | e2f8d555ec04a0beb965ea76e3a150993e8f0436 (patch) | |
tree | ac9a470badf6f6577e239353596709e2579c75ef /drivers/net/ethernet/freescale | |
parent | 2bb60cb9b7b997bdbc7fd6c8001dcca02a4ea2e1 (diff) |
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 <jim_baxter@mentor.com>
Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/freescale')
-rw-r--r-- | drivers/net/ethernet/freescale/fec.c | 68 |
1 files changed, 34 insertions, 34 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,33 +1782,6 @@ fec_probe(struct platform_device *pdev) | |||
1782 | fep->phy_interface = ret; | 1782 | fep->phy_interface = ret; |
1783 | } | 1783 | } |
1784 | 1784 | ||
1785 | fep->bufdesc_ex = | ||
1786 | pdev->id_entry->driver_data & FEC_QUIRK_HAS_BUFDESC_EX; | ||
1787 | if (fep->bufdesc_ex) | ||
1788 | fec_ptp_init(ndev, pdev); | ||
1789 | |||
1790 | ret = fec_enet_init(ndev); | ||
1791 | if (ret) | ||
1792 | goto failed_init; | ||
1793 | |||
1794 | for (i = 0; i < FEC_IRQ_NUM; i++) { | ||
1795 | irq = platform_get_irq(pdev, i); | ||
1796 | if (irq < 0) { | ||
1797 | if (i) | ||
1798 | break; | ||
1799 | ret = irq; | ||
1800 | goto failed_irq; | ||
1801 | } | ||
1802 | ret = request_irq(irq, fec_enet_interrupt, IRQF_DISABLED, pdev->name, ndev); | ||
1803 | if (ret) { | ||
1804 | while (--i >= 0) { | ||
1805 | irq = platform_get_irq(pdev, i); | ||
1806 | free_irq(irq, ndev); | ||
1807 | } | ||
1808 | goto failed_irq; | ||
1809 | } | ||
1810 | } | ||
1811 | |||
1812 | pinctrl = devm_pinctrl_get_select_default(&pdev->dev); | 1785 | pinctrl = devm_pinctrl_get_select_default(&pdev->dev); |
1813 | if (IS_ERR(pinctrl)) { | 1786 | if (IS_ERR(pinctrl)) { |
1814 | ret = PTR_ERR(pinctrl); | 1787 | ret = PTR_ERR(pinctrl); |
@@ -1828,6 +1801,8 @@ fec_probe(struct platform_device *pdev) | |||
1828 | } | 1801 | } |
1829 | 1802 | ||
1830 | fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp"); | 1803 | fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp"); |
1804 | fep->bufdesc_ex = | ||
1805 | pdev->id_entry->driver_data & FEC_QUIRK_HAS_BUFDESC_EX; | ||
1831 | if (IS_ERR(fep->clk_ptp)) { | 1806 | if (IS_ERR(fep->clk_ptp)) { |
1832 | ret = PTR_ERR(fep->clk_ptp); | 1807 | ret = PTR_ERR(fep->clk_ptp); |
1833 | fep->bufdesc_ex = 0; | 1808 | fep->bufdesc_ex = 0; |
@@ -1850,6 +1825,31 @@ fec_probe(struct platform_device *pdev) | |||
1850 | 1825 | ||
1851 | fec_reset_phy(pdev); | 1826 | fec_reset_phy(pdev); |
1852 | 1827 | ||
1828 | if (fep->bufdesc_ex) | ||
1829 | fec_ptp_init(ndev, pdev); | ||
1830 | |||
1831 | ret = fec_enet_init(ndev); | ||
1832 | if (ret) | ||
1833 | goto failed_init; | ||
1834 | |||
1835 | for (i = 0; i < FEC_IRQ_NUM; i++) { | ||
1836 | irq = platform_get_irq(pdev, i); | ||
1837 | if (irq < 0) { | ||
1838 | if (i) | ||
1839 | break; | ||
1840 | ret = irq; | ||
1841 | goto failed_irq; | ||
1842 | } | ||
1843 | ret = request_irq(irq, fec_enet_interrupt, IRQF_DISABLED, pdev->name, ndev); | ||
1844 | if (ret) { | ||
1845 | while (--i >= 0) { | ||
1846 | irq = platform_get_irq(pdev, i); | ||
1847 | free_irq(irq, ndev); | ||
1848 | } | ||
1849 | goto failed_irq; | ||
1850 | } | ||
1851 | } | ||
1852 | |||
1853 | ret = fec_enet_mii_init(pdev); | 1853 | ret = fec_enet_mii_init(pdev); |
1854 | if (ret) | 1854 | if (ret) |
1855 | goto failed_mii_init; | 1855 | goto failed_mii_init; |
@@ -1866,6 +1866,13 @@ fec_probe(struct platform_device *pdev) | |||
1866 | failed_register: | 1866 | failed_register: |
1867 | fec_enet_mii_remove(fep); | 1867 | fec_enet_mii_remove(fep); |
1868 | failed_mii_init: | 1868 | failed_mii_init: |
1869 | failed_init: | ||
1870 | for (i = 0; i < FEC_IRQ_NUM; i++) { | ||
1871 | irq = platform_get_irq(pdev, i); | ||
1872 | if (irq > 0) | ||
1873 | free_irq(irq, ndev); | ||
1874 | } | ||
1875 | failed_irq: | ||
1869 | failed_regulator: | 1876 | failed_regulator: |
1870 | clk_disable_unprepare(fep->clk_ahb); | 1877 | clk_disable_unprepare(fep->clk_ahb); |
1871 | clk_disable_unprepare(fep->clk_ipg); | 1878 | clk_disable_unprepare(fep->clk_ipg); |
@@ -1873,14 +1880,7 @@ failed_regulator: | |||
1873 | clk_disable_unprepare(fep->clk_ptp); | 1880 | clk_disable_unprepare(fep->clk_ptp); |
1874 | failed_pin: | 1881 | failed_pin: |
1875 | failed_clk: | 1882 | failed_clk: |
1876 | for (i = 0; i < FEC_IRQ_NUM; i++) { | ||
1877 | irq = platform_get_irq(pdev, i); | ||
1878 | if (irq > 0) | ||
1879 | free_irq(irq, ndev); | ||
1880 | } | ||
1881 | failed_irq: | ||
1882 | iounmap(fep->hwp); | 1883 | iounmap(fep->hwp); |
1883 | failed_init: | ||
1884 | failed_ioremap: | 1884 | failed_ioremap: |
1885 | free_netdev(ndev); | 1885 | free_netdev(ndev); |
1886 | failed_alloc_etherdev: | 1886 | failed_alloc_etherdev: |