aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
diff options
context:
space:
mode:
authorIyappan Subramanian <isubramanian@apm.com>2016-07-25 17:12:37 -0700
committerDavid S. Miller <davem@davemloft.net>2016-07-25 21:51:42 -0700
commitcb11c062f9052c6bde6a5fa18cab1f41d81131b3 (patch)
tree8fcb15041b5f2eb544e4501f51fcfb66375e780d /drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
parentdrivers: net: xgene: Separate set_speed from mac_init (diff)
downloadlinux-dev-cb11c062f9052c6bde6a5fa18cab1f41d81131b3.tar.xz
linux-dev-cb11c062f9052c6bde6a5fa18cab1f41d81131b3.zip
drivers: net: xgene: Fix module unload crash - hw resource cleanup
When the driver is configured as kernel module and when it gets unloaded and reloaded, kernel crash was observed. This patch address the hardware resource cleanups by doing the following, - Added mac_ops->clear() to do prefetch buffer clean up - Fixed delete freepool buffers logic - Reordered mac_enable and mac_disable - Added Tx completion ring free - Moved down delete_desc_rings after ring cleanup Signed-off-by: Iyappan Subramanian <isubramanian@apm.com> Tested-by: Fushen Chen <fchen@apm.com> Tested-by: Toan Le <toanle@apm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to '')
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_hw.c41
1 files changed, 41 insertions, 0 deletions
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
index 725109b964c3..009fb8e401d1 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
@@ -697,8 +697,48 @@ static int xgene_enet_reset(struct xgene_enet_pdata *pdata)
return 0;
}
+static void xgene_enet_clear(struct xgene_enet_pdata *pdata,
+ struct xgene_enet_desc_ring *ring)
+{
+ u32 addr, val, data;
+
+ val = xgene_enet_ring_bufnum(ring->id);
+
+ if (xgene_enet_is_bufpool(ring->id)) {
+ addr = ENET_CFGSSQMIFPRESET_ADDR;
+ data = BIT(val - 0x20);
+ } else {
+ addr = ENET_CFGSSQMIWQRESET_ADDR;
+ data = BIT(val);
+ }
+
+ xgene_enet_wr_ring_if(pdata, addr, data);
+}
+
static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata)
{
+ struct xgene_enet_desc_ring *ring;
+ u32 pb, val;
+ int i;
+
+ pb = 0;
+ for (i = 0; i < pdata->rxq_cnt; i++) {
+ ring = pdata->rx_ring[i]->buf_pool;
+
+ val = xgene_enet_ring_bufnum(ring->id);
+ pb |= BIT(val - 0x20);
+ }
+ xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIFPRESET_ADDR, pb);
+
+ pb = 0;
+ for (i = 0; i < pdata->txq_cnt; i++) {
+ ring = pdata->tx_ring[i];
+
+ val = xgene_enet_ring_bufnum(ring->id);
+ pb |= BIT(val);
+ }
+ xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQRESET_ADDR, pb);
+
if (!IS_ERR(pdata->clk))
clk_disable_unprepare(pdata->clk);
}
@@ -901,6 +941,7 @@ const struct xgene_mac_ops xgene_gmac_ops = {
const struct xgene_port_ops xgene_gport_ops = {
.reset = xgene_enet_reset,
+ .clear = xgene_enet_clear,
.cle_bypass = xgene_enet_cle_bypass,
.shutdown = xgene_gport_shutdown,
};