aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIyappan Subramanian <isubramanian@apm.com>2016-07-25 20:12:37 -0400
committerDavid S. Miller <davem@davemloft.net>2016-07-26 00:51:42 -0400
commitcb11c062f9052c6bde6a5fa18cab1f41d81131b3 (patch)
tree8fcb15041b5f2eb544e4501f51fcfb66375e780d
parent9a8c5ddedd9805cf52744ef6bdf591326684f88c (diff)
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>
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_hw.c41
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_hw.h2
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_main.c39
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_main.h2
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c52
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c42
6 files changed, 149 insertions, 29 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)
697 return 0; 697 return 0;
698} 698}
699 699
700static void xgene_enet_clear(struct xgene_enet_pdata *pdata,
701 struct xgene_enet_desc_ring *ring)
702{
703 u32 addr, val, data;
704
705 val = xgene_enet_ring_bufnum(ring->id);
706
707 if (xgene_enet_is_bufpool(ring->id)) {
708 addr = ENET_CFGSSQMIFPRESET_ADDR;
709 data = BIT(val - 0x20);
710 } else {
711 addr = ENET_CFGSSQMIWQRESET_ADDR;
712 data = BIT(val);
713 }
714
715 xgene_enet_wr_ring_if(pdata, addr, data);
716}
717
700static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata) 718static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata)
701{ 719{
720 struct xgene_enet_desc_ring *ring;
721 u32 pb, val;
722 int i;
723
724 pb = 0;
725 for (i = 0; i < pdata->rxq_cnt; i++) {
726 ring = pdata->rx_ring[i]->buf_pool;
727
728 val = xgene_enet_ring_bufnum(ring->id);
729 pb |= BIT(val - 0x20);
730 }
731 xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIFPRESET_ADDR, pb);
732
733 pb = 0;
734 for (i = 0; i < pdata->txq_cnt; i++) {
735 ring = pdata->tx_ring[i];
736
737 val = xgene_enet_ring_bufnum(ring->id);
738 pb |= BIT(val);
739 }
740 xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQRESET_ADDR, pb);
741
702 if (!IS_ERR(pdata->clk)) 742 if (!IS_ERR(pdata->clk))
703 clk_disable_unprepare(pdata->clk); 743 clk_disable_unprepare(pdata->clk);
704} 744}
@@ -901,6 +941,7 @@ const struct xgene_mac_ops xgene_gmac_ops = {
901 941
902const struct xgene_port_ops xgene_gport_ops = { 942const struct xgene_port_ops xgene_gport_ops = {
903 .reset = xgene_enet_reset, 943 .reset = xgene_enet_reset,
944 .clear = xgene_enet_clear,
904 .cle_bypass = xgene_enet_cle_bypass, 945 .cle_bypass = xgene_enet_cle_bypass,
905 .shutdown = xgene_gport_shutdown, 946 .shutdown = xgene_gport_shutdown,
906}; 947};
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h
index e840f9633734..eec55c1d41db 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h
@@ -167,6 +167,8 @@ enum xgene_enet_rm {
167#define TX_DV_GATE_EN0 BIT(2) 167#define TX_DV_GATE_EN0 BIT(2)
168#define RX_DV_GATE_EN0 BIT(1) 168#define RX_DV_GATE_EN0 BIT(1)
169#define RESUME_RX0 BIT(0) 169#define RESUME_RX0 BIT(0)
170#define ENET_CFGSSQMIFPRESET_ADDR 0x14
171#define ENET_CFGSSQMIWQRESET_ADDR 0x1c
170#define ENET_CFGSSQMIWQASSOC_ADDR 0xe0 172#define ENET_CFGSSQMIWQASSOC_ADDR 0xe0
171#define ENET_CFGSSQMIFPQASSOC_ADDR 0xdc 173#define ENET_CFGSSQMIFPQASSOC_ADDR 0xdc
172#define ENET_CFGSSQMIQMLITEFPQASSOC_ADDR 0xf0 174#define ENET_CFGSSQMIQMLITEFPQASSOC_ADDR 0xf0
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
index 8da3860691ee..f79950ab9277 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
@@ -102,25 +102,13 @@ static u8 xgene_enet_hdr_len(const void *data)
102 102
103static void xgene_enet_delete_bufpool(struct xgene_enet_desc_ring *buf_pool) 103static void xgene_enet_delete_bufpool(struct xgene_enet_desc_ring *buf_pool)
104{ 104{
105 struct xgene_enet_pdata *pdata = netdev_priv(buf_pool->ndev); 105 int i;
106 struct xgene_enet_raw_desc16 *raw_desc;
107 u32 slots = buf_pool->slots - 1;
108 u32 tail = buf_pool->tail;
109 u32 userinfo;
110 int i, len;
111
112 len = pdata->ring_ops->len(buf_pool);
113 for (i = 0; i < len; i++) {
114 tail = (tail - 1) & slots;
115 raw_desc = &buf_pool->raw_desc16[tail];
116 106
117 /* Hardware stores descriptor in little endian format */ 107 /* Free up the buffers held by hardware */
118 userinfo = GET_VAL(USERINFO, le64_to_cpu(raw_desc->m0)); 108 for (i = 0; i < buf_pool->slots; i++) {
119 dev_kfree_skb_any(buf_pool->rx_skb[userinfo]); 109 if (buf_pool->rx_skb[i])
110 dev_kfree_skb_any(buf_pool->rx_skb[i]);
120 } 111 }
121
122 pdata->ring_ops->wr_cmd(buf_pool, -len);
123 buf_pool->tail = tail;
124} 112}
125 113
126static irqreturn_t xgene_enet_rx_irq(const int irq, void *data) 114static irqreturn_t xgene_enet_rx_irq(const int irq, void *data)
@@ -481,6 +469,7 @@ static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring,
481 XGENE_ENET_MAX_MTU, DMA_FROM_DEVICE); 469 XGENE_ENET_MAX_MTU, DMA_FROM_DEVICE);
482 skb_index = GET_VAL(USERINFO, le64_to_cpu(raw_desc->m0)); 470 skb_index = GET_VAL(USERINFO, le64_to_cpu(raw_desc->m0));
483 skb = buf_pool->rx_skb[skb_index]; 471 skb = buf_pool->rx_skb[skb_index];
472 buf_pool->rx_skb[skb_index] = NULL;
484 473
485 /* checking for error */ 474 /* checking for error */
486 status = (GET_VAL(ELERR, le64_to_cpu(raw_desc->m0)) << LERR_LEN) || 475 status = (GET_VAL(ELERR, le64_to_cpu(raw_desc->m0)) << LERR_LEN) ||
@@ -720,9 +709,6 @@ static int xgene_enet_open(struct net_device *ndev)
720 if (ret) 709 if (ret)
721 return ret; 710 return ret;
722 711
723 mac_ops->tx_enable(pdata);
724 mac_ops->rx_enable(pdata);
725
726 xgene_enet_napi_enable(pdata); 712 xgene_enet_napi_enable(pdata);
727 ret = xgene_enet_register_irq(ndev); 713 ret = xgene_enet_register_irq(ndev);
728 if (ret) 714 if (ret)
@@ -735,6 +721,8 @@ static int xgene_enet_open(struct net_device *ndev)
735 netif_carrier_off(ndev); 721 netif_carrier_off(ndev);
736 } 722 }
737 723
724 mac_ops->tx_enable(pdata);
725 mac_ops->rx_enable(pdata);
738 netif_start_queue(ndev); 726 netif_start_queue(ndev);
739 727
740 return ret; 728 return ret;
@@ -747,15 +735,14 @@ static int xgene_enet_close(struct net_device *ndev)
747 int i; 735 int i;
748 736
749 netif_stop_queue(ndev); 737 netif_stop_queue(ndev);
738 mac_ops->tx_disable(pdata);
739 mac_ops->rx_disable(pdata);
750 740
751 if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) 741 if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
752 phy_stop(pdata->phy_dev); 742 phy_stop(pdata->phy_dev);
753 else 743 else
754 cancel_delayed_work_sync(&pdata->link_work); 744 cancel_delayed_work_sync(&pdata->link_work);
755 745
756 mac_ops->tx_disable(pdata);
757 mac_ops->rx_disable(pdata);
758
759 xgene_enet_free_irq(ndev); 746 xgene_enet_free_irq(ndev);
760 xgene_enet_napi_disable(pdata); 747 xgene_enet_napi_disable(pdata);
761 for (i = 0; i < pdata->rxq_cnt; i++) 748 for (i = 0; i < pdata->rxq_cnt; i++)
@@ -785,6 +772,9 @@ static void xgene_enet_delete_desc_rings(struct xgene_enet_pdata *pdata)
785 ring = pdata->tx_ring[i]; 772 ring = pdata->tx_ring[i];
786 if (ring) { 773 if (ring) {
787 xgene_enet_delete_ring(ring); 774 xgene_enet_delete_ring(ring);
775 pdata->port_ops->clear(pdata, ring);
776 if (pdata->cq_cnt)
777 xgene_enet_delete_ring(ring->cp_ring);
788 pdata->tx_ring[i] = NULL; 778 pdata->tx_ring[i] = NULL;
789 } 779 }
790 } 780 }
@@ -795,6 +785,7 @@ static void xgene_enet_delete_desc_rings(struct xgene_enet_pdata *pdata)
795 buf_pool = ring->buf_pool; 785 buf_pool = ring->buf_pool;
796 xgene_enet_delete_bufpool(buf_pool); 786 xgene_enet_delete_bufpool(buf_pool);
797 xgene_enet_delete_ring(buf_pool); 787 xgene_enet_delete_ring(buf_pool);
788 pdata->port_ops->clear(pdata, buf_pool);
798 xgene_enet_delete_ring(ring); 789 xgene_enet_delete_ring(ring);
799 pdata->rx_ring[i] = NULL; 790 pdata->rx_ring[i] = NULL;
800 } 791 }
@@ -1682,8 +1673,8 @@ static int xgene_enet_remove(struct platform_device *pdev)
1682 if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) 1673 if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
1683 xgene_enet_mdio_remove(pdata); 1674 xgene_enet_mdio_remove(pdata);
1684 unregister_netdev(ndev); 1675 unregister_netdev(ndev);
1685 xgene_enet_delete_desc_rings(pdata);
1686 pdata->port_ops->shutdown(pdata); 1676 pdata->port_ops->shutdown(pdata);
1677 xgene_enet_delete_desc_rings(pdata);
1687 free_netdev(ndev); 1678 free_netdev(ndev);
1688 1679
1689 return 0; 1680 return 0;
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
index aed9f430e0bc..681a47321fd8 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
@@ -148,6 +148,8 @@ struct xgene_mac_ops {
148 148
149struct xgene_port_ops { 149struct xgene_port_ops {
150 int (*reset)(struct xgene_enet_pdata *pdata); 150 int (*reset)(struct xgene_enet_pdata *pdata);
151 void (*clear)(struct xgene_enet_pdata *pdata,
152 struct xgene_enet_desc_ring *ring);
151 void (*cle_bypass)(struct xgene_enet_pdata *pdata, 153 void (*cle_bypass)(struct xgene_enet_pdata *pdata,
152 u32 dst_ring_num, u16 bufpool_id); 154 u32 dst_ring_num, u16 bufpool_id);
153 void (*shutdown)(struct xgene_enet_pdata *pdata); 155 void (*shutdown)(struct xgene_enet_pdata *pdata);
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c
index a3063fd7681f..f1477d244660 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c
@@ -137,9 +137,17 @@ static u32 xgene_enet_rd_mac(struct xgene_enet_pdata *p, u32 rd_addr)
137static int xgene_enet_ecc_init(struct xgene_enet_pdata *p) 137static int xgene_enet_ecc_init(struct xgene_enet_pdata *p)
138{ 138{
139 struct net_device *ndev = p->ndev; 139 struct net_device *ndev = p->ndev;
140 u32 data; 140 u32 data, shutdown;
141 int i = 0; 141 int i = 0;
142 142
143 shutdown = xgene_enet_rd_diag_csr(p, ENET_CFG_MEM_RAM_SHUTDOWN_ADDR);
144 data = xgene_enet_rd_diag_csr(p, ENET_BLOCK_MEM_RDY_ADDR);
145
146 if (!shutdown && data == ~0U) {
147 netdev_dbg(ndev, "+ ecc_init done, skipping\n");
148 return 0;
149 }
150
143 xgene_enet_wr_diag_csr(p, ENET_CFG_MEM_RAM_SHUTDOWN_ADDR, 0); 151 xgene_enet_wr_diag_csr(p, ENET_CFG_MEM_RAM_SHUTDOWN_ADDR, 0);
144 do { 152 do {
145 usleep_range(100, 110); 153 usleep_range(100, 110);
@@ -464,10 +472,47 @@ static void xgene_enet_cle_bypass(struct xgene_enet_pdata *p,
464 xgene_enet_wr_csr(p, cle_bypass_reg1 + offset, data); 472 xgene_enet_wr_csr(p, cle_bypass_reg1 + offset, data);
465} 473}
466 474
475static void xgene_enet_clear(struct xgene_enet_pdata *pdata,
476 struct xgene_enet_desc_ring *ring)
477{
478 u32 addr, val, data;
479
480 val = xgene_enet_ring_bufnum(ring->id);
481
482 if (xgene_enet_is_bufpool(ring->id)) {
483 addr = ENET_CFGSSQMIFPRESET_ADDR;
484 data = BIT(val - 0x20);
485 } else {
486 addr = ENET_CFGSSQMIWQRESET_ADDR;
487 data = BIT(val);
488 }
489
490 xgene_enet_wr_ring_if(pdata, addr, data);
491}
492
467static void xgene_enet_shutdown(struct xgene_enet_pdata *p) 493static void xgene_enet_shutdown(struct xgene_enet_pdata *p)
468{ 494{
469 if (!IS_ERR(p->clk)) 495 struct xgene_enet_desc_ring *ring;
470 clk_disable_unprepare(p->clk); 496 u32 pb, val;
497 int i;
498
499 pb = 0;
500 for (i = 0; i < p->rxq_cnt; i++) {
501 ring = p->rx_ring[i]->buf_pool;
502
503 val = xgene_enet_ring_bufnum(ring->id);
504 pb |= BIT(val - 0x20);
505 }
506 xgene_enet_wr_ring_if(p, ENET_CFGSSQMIFPRESET_ADDR, pb);
507
508 pb = 0;
509 for (i = 0; i < p->txq_cnt; i++) {
510 ring = p->tx_ring[i];
511
512 val = xgene_enet_ring_bufnum(ring->id);
513 pb |= BIT(val);
514 }
515 xgene_enet_wr_ring_if(p, ENET_CFGSSQMIWQRESET_ADDR, pb);
471} 516}
472 517
473static void xgene_enet_link_state(struct work_struct *work) 518static void xgene_enet_link_state(struct work_struct *work)
@@ -515,6 +560,7 @@ const struct xgene_mac_ops xgene_sgmac_ops = {
515 560
516const struct xgene_port_ops xgene_sgport_ops = { 561const struct xgene_port_ops xgene_sgport_ops = {
517 .reset = xgene_enet_reset, 562 .reset = xgene_enet_reset,
563 .clear = xgene_enet_clear,
518 .cle_bypass = xgene_enet_cle_bypass, 564 .cle_bypass = xgene_enet_cle_bypass,
519 .shutdown = xgene_enet_shutdown 565 .shutdown = xgene_enet_shutdown
520}; 566};
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c
index ba030dc1940b..d0b441934091 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c
@@ -292,8 +292,45 @@ static void xgene_enet_xgcle_bypass(struct xgene_enet_pdata *pdata,
292 292
293static void xgene_enet_shutdown(struct xgene_enet_pdata *pdata) 293static void xgene_enet_shutdown(struct xgene_enet_pdata *pdata)
294{ 294{
295 if (!IS_ERR(pdata->clk)) 295 struct xgene_enet_desc_ring *ring;
296 clk_disable_unprepare(pdata->clk); 296 u32 pb, val;
297 int i;
298
299 pb = 0;
300 for (i = 0; i < pdata->rxq_cnt; i++) {
301 ring = pdata->rx_ring[i]->buf_pool;
302
303 val = xgene_enet_ring_bufnum(ring->id);
304 pb |= BIT(val - 0x20);
305 }
306 xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIFPRESET_ADDR, pb);
307
308 pb = 0;
309 for (i = 0; i < pdata->txq_cnt; i++) {
310 ring = pdata->tx_ring[i];
311
312 val = xgene_enet_ring_bufnum(ring->id);
313 pb |= BIT(val);
314 }
315 xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQRESET_ADDR, pb);
316}
317
318static void xgene_enet_clear(struct xgene_enet_pdata *pdata,
319 struct xgene_enet_desc_ring *ring)
320{
321 u32 addr, val, data;
322
323 val = xgene_enet_ring_bufnum(ring->id);
324
325 if (xgene_enet_is_bufpool(ring->id)) {
326 addr = ENET_CFGSSQMIFPRESET_ADDR;
327 data = BIT(val - 0x20);
328 } else {
329 addr = ENET_CFGSSQMIWQRESET_ADDR;
330 data = BIT(val);
331 }
332
333 xgene_enet_wr_ring_if(pdata, addr, data);
297} 334}
298 335
299static void xgene_enet_link_state(struct work_struct *work) 336static void xgene_enet_link_state(struct work_struct *work)
@@ -340,6 +377,7 @@ const struct xgene_mac_ops xgene_xgmac_ops = {
340 377
341const struct xgene_port_ops xgene_xgport_ops = { 378const struct xgene_port_ops xgene_xgport_ops = {
342 .reset = xgene_enet_reset, 379 .reset = xgene_enet_reset,
380 .clear = xgene_enet_clear,
343 .cle_bypass = xgene_enet_xgcle_bypass, 381 .cle_bypass = xgene_enet_xgcle_bypass,
344 .shutdown = xgene_enet_shutdown, 382 .shutdown = xgene_enet_shutdown,
345}; 383};