diff options
author | Reece R. Pollack | 2015-02-16 13:35:36 -0600 |
---|---|---|
committer | Reece R. Pollack | 2015-02-16 16:30:35 -0600 |
commit | 1cd9632166b2863dfe5bebe8f19ce085cf9fb754 (patch) | |
tree | 5e6478c40765c124b9bd3f73d702d7ae3a8e2867 /drivers/net/ethernet/ti/keystone_ethss2.c | |
parent | 760a81522f9b37745a9fde6afd21a727c8f3cbbd (diff) | |
download | linux-1cd9632166b2863dfe5bebe8f19ce085cf9fb754.tar.gz linux-1cd9632166b2863dfe5bebe8f19ce085cf9fb754.tar.xz linux-1cd9632166b2863dfe5bebe8f19ce085cf9fb754.zip |
net: keystone: Fix memory leak in CPSW ALE configuration
Prior to this patch, the CPSW ALE context was created when the first
interface on a device was opened, but it was not destroyed when the
last interface was closed (it was stopped instead). This resulted in
a memory leak. This patch corrects this.
Also, the ALE Slaves were being shut down after the ALE context was
being destroyed. This could result in a NULL pointer reference. This
patch fixes this too.
Finally, the ALE reference count in keystone_xgess.c was a non-atomic
integer, while the other modules used an atomic. This patch fixes this
and includes some minor restructuring so the code looks more like the
other two modules.
Signed-off-by: Reece R. Pollack <x0183204@ti.com>
Diffstat (limited to 'drivers/net/ethernet/ti/keystone_ethss2.c')
-rw-r--r-- | drivers/net/ethernet/ti/keystone_ethss2.c | 10 |
1 files changed, 5 insertions, 5 deletions
diff --git a/drivers/net/ethernet/ti/keystone_ethss2.c b/drivers/net/ethernet/ti/keystone_ethss2.c index f334bdb3ab5..5560d6e2c00 100644 --- a/drivers/net/ethernet/ti/keystone_ethss2.c +++ b/drivers/net/ethernet/ti/keystone_ethss2.c | |||
@@ -3510,11 +3510,13 @@ static int cpsw2_close(void *intf_priv, struct net_device *ndev) | |||
3510 | 3510 | ||
3511 | del_timer_sync(&cpsw_intf->timer); | 3511 | del_timer_sync(&cpsw_intf->timer); |
3512 | 3512 | ||
3513 | if (atomic_dec_return(&cpsw_dev->ale_refcnt) == 0) | ||
3514 | cpsw_ale_stop(cpsw_dev->ale); | ||
3515 | |||
3516 | for_each_slave(cpsw_intf, cpsw2_slave_stop, cpsw_intf); | 3513 | for_each_slave(cpsw_intf, cpsw2_slave_stop, cpsw_intf); |
3517 | 3514 | ||
3515 | if (atomic_dec_return(&cpsw_dev->ale_refcnt) == 0) { | ||
3516 | cpsw_ale_destroy(cpsw_dev->ale); | ||
3517 | cpsw_dev->ale = NULL; | ||
3518 | } | ||
3519 | |||
3518 | if (!cpsw_dev->force_no_hwtstamp) | 3520 | if (!cpsw_dev->force_no_hwtstamp) |
3519 | netcp_unregister_rxhook(netcp, CPSW2_RXHOOK_ORDER, | 3521 | netcp_unregister_rxhook(netcp, CPSW2_RXHOOK_ORDER, |
3520 | cpsw2_rx_hook, cpsw_intf); | 3522 | cpsw2_rx_hook, cpsw_intf); |
@@ -3538,8 +3540,6 @@ static int cpsw2_remove(struct netcp_device *netcp_device, void *inst_priv) | |||
3538 | 3540 | ||
3539 | of_node_put(cpsw_dev->interfaces); | 3541 | of_node_put(cpsw_dev->interfaces); |
3540 | 3542 | ||
3541 | cpsw_ale_destroy(cpsw_dev->ale); | ||
3542 | |||
3543 | list_for_each_entry_safe(cpsw_intf, tmp, &cpsw_dev->cpsw_intf_head, | 3543 | list_for_each_entry_safe(cpsw_intf, tmp, &cpsw_dev->cpsw_intf_head, |
3544 | cpsw_intf_list) { | 3544 | cpsw_intf_list) { |
3545 | netcp_delete_interface(netcp_device, cpsw_intf->ndev); | 3545 | netcp_delete_interface(netcp_device, cpsw_intf->ndev); |