From 966830340302fd79c51e2a3b9bccca9427256dee Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 24 Nov 2016 19:21:29 +0100 Subject: net: fsl/fman: fix phydev reference leak Make sure to drop the reference taken by of_phy_find_device() during initialisation when later freeing the struct fman_mac. Fixes: 57ba4c9b56d8 ("fsl/fman: Add FMan MAC support") Signed-off-by: Johan Hovold Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fman/fman_memac.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/ethernet/freescale') diff --git a/drivers/net/ethernet/freescale/fman/fman_memac.c b/drivers/net/ethernet/freescale/fman/fman_memac.c index 53ef51e3bd9e..71a5ded9d1de 100644 --- a/drivers/net/ethernet/freescale/fman/fman_memac.c +++ b/drivers/net/ethernet/freescale/fman/fman_memac.c @@ -1107,6 +1107,9 @@ int memac_free(struct fman_mac *memac) { free_init_resources(memac); + if (memac->pcsphy) + put_device(&memac->pcsphy->mdio.dev); + kfree(memac->memac_drv_param); kfree(memac); -- cgit v1.2.3 From cb1f3410ff12520b22fa03ccd23892c360de0c26 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 24 Nov 2016 19:21:30 +0100 Subject: net: fsl/fman: fix fixed-link-phydev reference leak Make sure to drop the reference taken by of_phy_find_device() when looking up a fixed-link phydev during probe. Fixes: 57ba4c9b56d8 ("fsl/fman: Add FMan MAC support") Signed-off-by: Johan Hovold Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fman/mac.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/ethernet/freescale') diff --git a/drivers/net/ethernet/freescale/fman/mac.c b/drivers/net/ethernet/freescale/fman/mac.c index 8fe6b3e253fa..736db9d9b0ad 100644 --- a/drivers/net/ethernet/freescale/fman/mac.c +++ b/drivers/net/ethernet/freescale/fman/mac.c @@ -892,6 +892,8 @@ static int mac_probe(struct platform_device *_of_dev) priv->fixed_link->duplex = phy->duplex; priv->fixed_link->pause = phy->pause; priv->fixed_link->asym_pause = phy->asym_pause; + + put_device(&phy->mdio.dev); } err = mac_dev->init(mac_dev); -- cgit v1.2.3 From 82005b1c19b11998ea98532d742c021a19f948d7 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 28 Nov 2016 19:25:00 +0100 Subject: net: ethernet: fec: fix fixed-link phydev leaks Make sure to deregister and free any fixed-link PHY registered using of_phy_register_fixed_link() on probe errors and on driver unbind. Fixes: 407066f8f371 ("net: fec: Support phys probed from devicetree and fixed-link") Signed-off-by: Johan Hovold Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/ethernet/freescale') diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 5aa9d4ded214..74dcdf097348 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -3475,6 +3475,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 +3490,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 +3498,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); -- cgit v1.2.3 From b9755f03728b21c36375a47a6c6366e00b4f2062 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 28 Nov 2016 19:25:01 +0100 Subject: net: ethernet: fs_enet: fix fixed-link phydev leaks Make sure to deregister and free any fixed-link PHY registered using of_phy_register_fixed_link() on probe errors and on driver unbind. Fixes: bb74d9a4a87b ("fs_enet: use the new fixed PHY helpers") Signed-off-by: Johan Hovold Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net/ethernet/freescale') diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c index dc120c148d97..4b86260584a0 100644 --- a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c +++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c @@ -980,7 +980,7 @@ static int fs_enet_probe(struct platform_device *ofdev) err = clk_prepare_enable(clk); if (err) { ret = err; - goto out_free_fpi; + goto out_deregister_fixed_link; } fpi->clk_per = clk; } @@ -1061,6 +1061,9 @@ out_put: of_node_put(fpi->phy_node); if (fpi->clk_per) clk_disable_unprepare(fpi->clk_per); +out_deregister_fixed_link: + if (of_phy_is_fixed_link(ofdev->dev.of_node)) + of_phy_deregister_fixed_link(ofdev->dev.of_node); out_free_fpi: kfree(fpi); return ret; @@ -1079,6 +1082,8 @@ static int fs_enet_remove(struct platform_device *ofdev) of_node_put(fep->fpi->phy_node); if (fep->fpi->clk_per) clk_disable_unprepare(fep->fpi->clk_per); + if (of_phy_is_fixed_link(ofdev->dev.of_node)) + of_phy_deregister_fixed_link(ofdev->dev.of_node); free_netdev(ndev); return 0; } -- cgit v1.2.3 From 42c70042458d74ce049ce4a2ea7702f344a0dc0b Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 28 Nov 2016 19:25:02 +0100 Subject: net: ethernet: gianfar: fix fixed-link phydev leaks Make sure to deregister and free any fixed-link PHY registered using of_phy_register_fixed_link() on probe errors and on driver unbind. Fixes: be40364544bd ("gianfar: use the new fixed PHY helpers") Signed-off-by: Johan Hovold Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/net/ethernet/freescale') diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 4b4f5bc0e279..9061c2f82b9c 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -1312,6 +1312,7 @@ static void gfar_init_addr_hash_table(struct gfar_private *priv) */ static int gfar_probe(struct platform_device *ofdev) { + struct device_node *np = ofdev->dev.of_node; struct net_device *dev = NULL; struct gfar_private *priv = NULL; int err = 0, i; @@ -1462,6 +1463,8 @@ static int gfar_probe(struct platform_device *ofdev) return 0; register_fail: + if (of_phy_is_fixed_link(np)) + of_phy_deregister_fixed_link(np); unmap_group_regs(priv); gfar_free_rx_queues(priv); gfar_free_tx_queues(priv); @@ -1474,11 +1477,16 @@ register_fail: static int gfar_remove(struct platform_device *ofdev) { struct gfar_private *priv = platform_get_drvdata(ofdev); + struct device_node *np = ofdev->dev.of_node; of_node_put(priv->phy_node); of_node_put(priv->tbi_node); unregister_netdev(priv->ndev); + + if (of_phy_is_fixed_link(np)) + of_phy_deregister_fixed_link(np); + unmap_group_regs(priv); gfar_free_rx_queues(priv); gfar_free_tx_queues(priv); -- cgit v1.2.3 From 0807c4ceb8d171a116edc33e34166416876cae5d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 28 Nov 2016 19:25:03 +0100 Subject: net: ethernet: ucc_geth: fix fixed-link phydev leaks Make sure to deregister and free any fixed-link PHY registered using of_phy_register_fixed_link() on probe errors and on driver unbind. Fixes: 87009814cdbb ("ucc_geth: use the new fixed PHY helpers") Signed-off-by: Johan Hovold Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/ucc_geth.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'drivers/net/ethernet/freescale') diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c index 186ef8f16c80..f76d33279454 100644 --- a/drivers/net/ethernet/freescale/ucc_geth.c +++ b/drivers/net/ethernet/freescale/ucc_geth.c @@ -3868,9 +3868,8 @@ static int ucc_geth_probe(struct platform_device* ofdev) dev = alloc_etherdev(sizeof(*ugeth)); if (dev == NULL) { - of_node_put(ug_info->tbi_node); - of_node_put(ug_info->phy_node); - return -ENOMEM; + err = -ENOMEM; + goto err_deregister_fixed_link; } ugeth = netdev_priv(dev); @@ -3907,10 +3906,7 @@ static int ucc_geth_probe(struct platform_device* ofdev) if (netif_msg_probe(ugeth)) pr_err("%s: Cannot register net device, aborting\n", dev->name); - free_netdev(dev); - of_node_put(ug_info->tbi_node); - of_node_put(ug_info->phy_node); - return err; + goto err_free_netdev; } mac_addr = of_get_mac_address(np); @@ -3923,16 +3919,29 @@ static int ucc_geth_probe(struct platform_device* ofdev) ugeth->node = np; return 0; + +err_free_netdev: + free_netdev(dev); +err_deregister_fixed_link: + if (of_phy_is_fixed_link(np)) + of_phy_deregister_fixed_link(np); + of_node_put(ug_info->tbi_node); + of_node_put(ug_info->phy_node); + + return err; } static int ucc_geth_remove(struct platform_device* ofdev) { struct net_device *dev = platform_get_drvdata(ofdev); struct ucc_geth_private *ugeth = netdev_priv(dev); + struct device_node *np = ofdev->dev.of_node; unregister_netdev(dev); free_netdev(dev); ucc_geth_memclean(ugeth); + if (of_phy_is_fixed_link(np)) + of_phy_deregister_fixed_link(np); of_node_put(ugeth->ug_info->tbi_node); of_node_put(ugeth->ug_info->phy_node); -- cgit v1.2.3 From 80cca775cdc4f8555612d2943a2872076b33e0ff Mon Sep 17 00:00:00 2001 From: Nikita Yushchenko Date: Tue, 29 Nov 2016 09:44:51 +0300 Subject: net: fec: cache statistics while device is down Execution 'ethtool -S' on fec device that is down causes OOPS on Vybrid board: Unhandled fault: external abort on non-linefetch (0x1008) at 0xe0898200 pgd = ddecc000 [e0898200] *pgd=9e406811, *pte=400d1653, *ppte=400d1453 Internal error: : 1008 [#1] SMP ARM ... Reason of OOPS is that fec_enet_get_ethtool_stats() accesses fec registers while IPG clock is stopped by PM. Fix that by caching statistics in fec_enet_private. Cache is initialized at device probe time, and updated at statistics request time if device is up, and also just before turning device off on down path. Additional locking is not needed, since cached statistics is accessed either before device is registered, or under rtnl_lock(). Signed-off-by: Nikita Yushchenko Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec.h | 2 ++ drivers/net/ethernet/freescale/fec_main.c | 23 +++++++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) (limited to 'drivers/net/ethernet/freescale') diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index c865135f3cb9..5ea740b4cf14 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -574,6 +574,8 @@ struct fec_enet_private { unsigned int reload_period; int pps_enable; unsigned int next_counter; + + u64 ethtool_stats[0]; }; void fec_ptp_init(struct platform_device *pdev); diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 74dcdf097348..5f77caa59534 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -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; -- cgit v1.2.3