]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/net/ethernet/freescale/fec_main.c
net: fec: cache statistics while device is down
[karo-tx-linux.git] / drivers / net / ethernet / freescale / fec_main.c
index 5aa9d4ded214cfd96fe9de816593f76298f2d334..5f77caa59534d7e79f63ea5a718bccef6b61d7ee 100644 (file)
@@ -2313,14 +2313,24 @@ static const struct fec_stat {
        { "IEEE_rx_octets_ok", IEEE_R_OCTETS_OK },
 };
 
-static void fec_enet_get_ethtool_stats(struct net_device *dev,
-       struct ethtool_stats *stats, u64 *data)
+static void fec_enet_update_ethtool_stats(struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
        int i;
 
        for (i = 0; i < ARRAY_SIZE(fec_stats); i++)
-               data[i] = readl(fep->hwp + fec_stats[i].offset);
+               fep->ethtool_stats[i] = readl(fep->hwp + fec_stats[i].offset);
+}
+
+static void fec_enet_get_ethtool_stats(struct net_device *dev,
+                                      struct ethtool_stats *stats, u64 *data)
+{
+       struct fec_enet_private *fep = netdev_priv(dev);
+
+       if (netif_running(dev))
+               fec_enet_update_ethtool_stats(dev);
+
+       memcpy(data, fep->ethtool_stats, ARRAY_SIZE(fec_stats) * sizeof(u64));
 }
 
 static void fec_enet_get_strings(struct net_device *netdev,
@@ -2874,6 +2884,8 @@ fec_enet_close(struct net_device *ndev)
        if (fep->quirks & FEC_QUIRK_ERR006687)
                imx6q_cpuidle_fec_irqs_unused();
 
+       fec_enet_update_ethtool_stats(ndev);
+
        fec_enet_clk_enable(ndev, false);
        pinctrl_pm_select_sleep_state(&fep->pdev->dev);
        pm_runtime_mark_last_busy(&fep->pdev->dev);
@@ -3180,6 +3192,8 @@ static int fec_enet_init(struct net_device *ndev)
 
        fec_restart(ndev);
 
+       fec_enet_update_ethtool_stats(ndev);
+
        return 0;
 }
 
@@ -3278,7 +3292,8 @@ fec_probe(struct platform_device *pdev)
        fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs);
 
        /* Init network device */
-       ndev = alloc_etherdev_mqs(sizeof(struct fec_enet_private),
+       ndev = alloc_etherdev_mqs(sizeof(struct fec_enet_private) +
+                                 ARRAY_SIZE(fec_stats) * sizeof(u64),
                                  num_tx_qs, num_rx_qs);
        if (!ndev)
                return -ENOMEM;
@@ -3475,6 +3490,8 @@ failed_regulator:
 failed_clk_ipg:
        fec_enet_clk_enable(ndev, false);
 failed_clk:
+       if (of_phy_is_fixed_link(np))
+               of_phy_deregister_fixed_link(np);
 failed_phy:
        of_node_put(phy_node);
 failed_ioremap:
@@ -3488,6 +3505,7 @@ fec_drv_remove(struct platform_device *pdev)
 {
        struct net_device *ndev = platform_get_drvdata(pdev);
        struct fec_enet_private *fep = netdev_priv(ndev);
+       struct device_node *np = pdev->dev.of_node;
 
        cancel_work_sync(&fep->tx_timeout_work);
        fec_ptp_stop(pdev);
@@ -3495,6 +3513,8 @@ fec_drv_remove(struct platform_device *pdev)
        fec_enet_mii_remove(fep);
        if (fep->reg_phy)
                regulator_disable(fep->reg_phy);
+       if (of_phy_is_fixed_link(np))
+               of_phy_deregister_fixed_link(np);
        of_node_put(fep->phy_node);
        free_netdev(ndev);