diff options
author | Lars Persson <lars.persson@axis.com> | 2016-09-08 07:24:21 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-09-09 22:20:21 -0400 |
commit | 47b02f7294a483387772a46931da942b2ca9d845 (patch) | |
tree | 0058445575d9b9c2d4aec5b703e40ec8c2a4e7ec | |
parent | 7303a1475008bee5c3e82a06a282568415690d72 (diff) |
dwc_eth_qos: do not register semi-initialized device
We move register_netdev() to the end of dwceqos_probe() to close any
races where the netdev callbacks are called before the initialization
has finished.
Reported-by: Pavel Andrianov <andrianov@ispras.ru>
Signed-off-by: Lars Persson <larper@axis.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/synopsys/dwc_eth_qos.c | 38 |
1 files changed, 18 insertions, 20 deletions
diff --git a/drivers/net/ethernet/synopsys/dwc_eth_qos.c b/drivers/net/ethernet/synopsys/dwc_eth_qos.c index 5a3941bf250f..4490ebaed127 100644 --- a/drivers/net/ethernet/synopsys/dwc_eth_qos.c +++ b/drivers/net/ethernet/synopsys/dwc_eth_qos.c | |||
@@ -1246,7 +1246,7 @@ static int dwceqos_mii_init(struct net_local *lp) | |||
1246 | lp->mii_bus->read = &dwceqos_mdio_read; | 1246 | lp->mii_bus->read = &dwceqos_mdio_read; |
1247 | lp->mii_bus->write = &dwceqos_mdio_write; | 1247 | lp->mii_bus->write = &dwceqos_mdio_write; |
1248 | lp->mii_bus->priv = lp; | 1248 | lp->mii_bus->priv = lp; |
1249 | lp->mii_bus->parent = &lp->ndev->dev; | 1249 | lp->mii_bus->parent = &lp->pdev->dev; |
1250 | 1250 | ||
1251 | of_address_to_resource(lp->pdev->dev.of_node, 0, &res); | 1251 | of_address_to_resource(lp->pdev->dev.of_node, 0, &res); |
1252 | snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%.8llx", | 1252 | snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%.8llx", |
@@ -2853,25 +2853,17 @@ static int dwceqos_probe(struct platform_device *pdev) | |||
2853 | 2853 | ||
2854 | ndev->features = ndev->hw_features; | 2854 | ndev->features = ndev->hw_features; |
2855 | 2855 | ||
2856 | netif_napi_add(ndev, &lp->napi, dwceqos_rx_poll, NAPI_POLL_WEIGHT); | ||
2857 | |||
2858 | ret = register_netdev(ndev); | ||
2859 | if (ret) { | ||
2860 | dev_err(&pdev->dev, "Cannot register net device, aborting.\n"); | ||
2861 | goto err_out_clk_dis_aper; | ||
2862 | } | ||
2863 | |||
2864 | lp->phy_ref_clk = devm_clk_get(&pdev->dev, "phy_ref_clk"); | 2856 | lp->phy_ref_clk = devm_clk_get(&pdev->dev, "phy_ref_clk"); |
2865 | if (IS_ERR(lp->phy_ref_clk)) { | 2857 | if (IS_ERR(lp->phy_ref_clk)) { |
2866 | dev_err(&pdev->dev, "phy_ref_clk clock not found.\n"); | 2858 | dev_err(&pdev->dev, "phy_ref_clk clock not found.\n"); |
2867 | ret = PTR_ERR(lp->phy_ref_clk); | 2859 | ret = PTR_ERR(lp->phy_ref_clk); |
2868 | goto err_out_unregister_netdev; | 2860 | goto err_out_clk_dis_aper; |
2869 | } | 2861 | } |
2870 | 2862 | ||
2871 | ret = clk_prepare_enable(lp->phy_ref_clk); | 2863 | ret = clk_prepare_enable(lp->phy_ref_clk); |
2872 | if (ret) { | 2864 | if (ret) { |
2873 | dev_err(&pdev->dev, "Unable to enable device clock.\n"); | 2865 | dev_err(&pdev->dev, "Unable to enable device clock.\n"); |
2874 | goto err_out_unregister_netdev; | 2866 | goto err_out_clk_dis_aper; |
2875 | } | 2867 | } |
2876 | 2868 | ||
2877 | lp->phy_node = of_parse_phandle(lp->pdev->dev.of_node, | 2869 | lp->phy_node = of_parse_phandle(lp->pdev->dev.of_node, |
@@ -2880,7 +2872,7 @@ static int dwceqos_probe(struct platform_device *pdev) | |||
2880 | ret = of_phy_register_fixed_link(lp->pdev->dev.of_node); | 2872 | ret = of_phy_register_fixed_link(lp->pdev->dev.of_node); |
2881 | if (ret < 0) { | 2873 | if (ret < 0) { |
2882 | dev_err(&pdev->dev, "invalid fixed-link"); | 2874 | dev_err(&pdev->dev, "invalid fixed-link"); |
2883 | goto err_out_unregister_clk_notifier; | 2875 | goto err_out_clk_dis_phy; |
2884 | } | 2876 | } |
2885 | 2877 | ||
2886 | lp->phy_node = of_node_get(lp->pdev->dev.of_node); | 2878 | lp->phy_node = of_node_get(lp->pdev->dev.of_node); |
@@ -2889,7 +2881,7 @@ static int dwceqos_probe(struct platform_device *pdev) | |||
2889 | ret = of_get_phy_mode(lp->pdev->dev.of_node); | 2881 | ret = of_get_phy_mode(lp->pdev->dev.of_node); |
2890 | if (ret < 0) { | 2882 | if (ret < 0) { |
2891 | dev_err(&lp->pdev->dev, "error in getting phy i/f\n"); | 2883 | dev_err(&lp->pdev->dev, "error in getting phy i/f\n"); |
2892 | goto err_out_unregister_clk_notifier; | 2884 | goto err_out_clk_dis_phy; |
2893 | } | 2885 | } |
2894 | 2886 | ||
2895 | lp->phy_interface = ret; | 2887 | lp->phy_interface = ret; |
@@ -2897,14 +2889,14 @@ static int dwceqos_probe(struct platform_device *pdev) | |||
2897 | ret = dwceqos_mii_init(lp); | 2889 | ret = dwceqos_mii_init(lp); |
2898 | if (ret) { | 2890 | if (ret) { |
2899 | dev_err(&lp->pdev->dev, "error in dwceqos_mii_init\n"); | 2891 | dev_err(&lp->pdev->dev, "error in dwceqos_mii_init\n"); |
2900 | goto err_out_unregister_clk_notifier; | 2892 | goto err_out_clk_dis_phy; |
2901 | } | 2893 | } |
2902 | 2894 | ||
2903 | ret = dwceqos_mii_probe(ndev); | 2895 | ret = dwceqos_mii_probe(ndev); |
2904 | if (ret != 0) { | 2896 | if (ret != 0) { |
2905 | netdev_err(ndev, "mii_probe fail.\n"); | 2897 | netdev_err(ndev, "mii_probe fail.\n"); |
2906 | ret = -ENXIO; | 2898 | ret = -ENXIO; |
2907 | goto err_out_unregister_clk_notifier; | 2899 | goto err_out_clk_dis_phy; |
2908 | } | 2900 | } |
2909 | 2901 | ||
2910 | dwceqos_set_umac_addr(lp, lp->ndev->dev_addr, 0); | 2902 | dwceqos_set_umac_addr(lp, lp->ndev->dev_addr, 0); |
@@ -2922,7 +2914,7 @@ static int dwceqos_probe(struct platform_device *pdev) | |||
2922 | if (ret) { | 2914 | if (ret) { |
2923 | dev_err(&lp->pdev->dev, "Unable to retrieve DT, error %d\n", | 2915 | dev_err(&lp->pdev->dev, "Unable to retrieve DT, error %d\n", |
2924 | ret); | 2916 | ret); |
2925 | goto err_out_unregister_clk_notifier; | 2917 | goto err_out_clk_dis_phy; |
2926 | } | 2918 | } |
2927 | dev_info(&lp->pdev->dev, "pdev->id %d, baseaddr 0x%08lx, irq %d\n", | 2919 | dev_info(&lp->pdev->dev, "pdev->id %d, baseaddr 0x%08lx, irq %d\n", |
2928 | pdev->id, ndev->base_addr, ndev->irq); | 2920 | pdev->id, ndev->base_addr, ndev->irq); |
@@ -2932,18 +2924,24 @@ static int dwceqos_probe(struct platform_device *pdev) | |||
2932 | if (ret) { | 2924 | if (ret) { |
2933 | dev_err(&lp->pdev->dev, "Unable to request IRQ %d, error %d\n", | 2925 | dev_err(&lp->pdev->dev, "Unable to request IRQ %d, error %d\n", |
2934 | ndev->irq, ret); | 2926 | ndev->irq, ret); |
2935 | goto err_out_unregister_clk_notifier; | 2927 | goto err_out_clk_dis_phy; |
2936 | } | 2928 | } |
2937 | 2929 | ||
2938 | if (netif_msg_probe(lp)) | 2930 | if (netif_msg_probe(lp)) |
2939 | netdev_dbg(ndev, "net_local@%p\n", lp); | 2931 | netdev_dbg(ndev, "net_local@%p\n", lp); |
2940 | 2932 | ||
2933 | netif_napi_add(ndev, &lp->napi, dwceqos_rx_poll, NAPI_POLL_WEIGHT); | ||
2934 | |||
2935 | ret = register_netdev(ndev); | ||
2936 | if (ret) { | ||
2937 | dev_err(&pdev->dev, "Cannot register net device, aborting.\n"); | ||
2938 | goto err_out_clk_dis_phy; | ||
2939 | } | ||
2940 | |||
2941 | return 0; | 2941 | return 0; |
2942 | 2942 | ||
2943 | err_out_unregister_clk_notifier: | 2943 | err_out_clk_dis_phy: |
2944 | clk_disable_unprepare(lp->phy_ref_clk); | 2944 | clk_disable_unprepare(lp->phy_ref_clk); |
2945 | err_out_unregister_netdev: | ||
2946 | unregister_netdev(ndev); | ||
2947 | err_out_clk_dis_aper: | 2945 | err_out_clk_dis_aper: |
2948 | clk_disable_unprepare(lp->apb_pclk); | 2946 | clk_disable_unprepare(lp->apb_pclk); |
2949 | err_out_free_netdev: | 2947 | err_out_free_netdev: |