aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPadmanabh Ratnakar <padmanabh.ratnakar@emulex.com>2011-05-10 01:13:57 -0400
committerDavid S. Miller <davem@davemloft.net>2011-05-11 19:10:03 -0400
commit4d586b823acc46c55c889ae1798de236c9d403da (patch)
tree32efa3d399b50b30c0850cc58c00369ee8c30a0f
parentecd0bf0f7b280bac3ac7419ed3aac84cd92878e9 (diff)
be2net: Fix to prevent flooding of TX queue
Start/stop TX queue is controlled by TX queue "used" counter. It is incremented while WRBs are posted to TX queue and decremented when TX completions are received. This counter was getting decremented before HW is informed about processing of TX completions. As used counter is decremented, transmit function posts new WRBs and creates completion queue full scenario in HW. Signed-off-by: Padmanabh Ratnakar <padmanabh.ratnakar@emulex.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/benet/be_main.c20
1 files changed, 12 insertions, 8 deletions
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index babe53af7e86..243172bedfa6 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -1275,7 +1275,7 @@ static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq)
1275 return txcp; 1275 return txcp;
1276} 1276}
1277 1277
1278static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index) 1278static u16 be_tx_compl_process(struct be_adapter *adapter, u16 last_index)
1279{ 1279{
1280 struct be_queue_info *txq = &adapter->tx_obj.q; 1280 struct be_queue_info *txq = &adapter->tx_obj.q;
1281 struct be_eth_wrb *wrb; 1281 struct be_eth_wrb *wrb;
@@ -1302,9 +1302,8 @@ static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index)
1302 queue_tail_inc(txq); 1302 queue_tail_inc(txq);
1303 } while (cur_index != last_index); 1303 } while (cur_index != last_index);
1304 1304
1305 atomic_sub(num_wrbs, &txq->used);
1306
1307 kfree_skb(sent_skb); 1305 kfree_skb(sent_skb);
1306 return num_wrbs;
1308} 1307}
1309 1308
1310static inline struct be_eq_entry *event_get(struct be_eq_obj *eq_obj) 1309static inline struct be_eq_entry *event_get(struct be_eq_obj *eq_obj)
@@ -1387,7 +1386,7 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
1387 struct be_queue_info *tx_cq = &adapter->tx_obj.cq; 1386 struct be_queue_info *tx_cq = &adapter->tx_obj.cq;
1388 struct be_queue_info *txq = &adapter->tx_obj.q; 1387 struct be_queue_info *txq = &adapter->tx_obj.q;
1389 struct be_eth_tx_compl *txcp; 1388 struct be_eth_tx_compl *txcp;
1390 u16 end_idx, cmpl = 0, timeo = 0; 1389 u16 end_idx, cmpl = 0, timeo = 0, num_wrbs = 0;
1391 struct sk_buff **sent_skbs = adapter->tx_obj.sent_skb_list; 1390 struct sk_buff **sent_skbs = adapter->tx_obj.sent_skb_list;
1392 struct sk_buff *sent_skb; 1391 struct sk_buff *sent_skb;
1393 bool dummy_wrb; 1392 bool dummy_wrb;
@@ -1397,12 +1396,14 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
1397 while ((txcp = be_tx_compl_get(tx_cq))) { 1396 while ((txcp = be_tx_compl_get(tx_cq))) {
1398 end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl, 1397 end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl,
1399 wrb_index, txcp); 1398 wrb_index, txcp);
1400 be_tx_compl_process(adapter, end_idx); 1399 num_wrbs += be_tx_compl_process(adapter, end_idx);
1401 cmpl++; 1400 cmpl++;
1402 } 1401 }
1403 if (cmpl) { 1402 if (cmpl) {
1404 be_cq_notify(adapter, tx_cq->id, false, cmpl); 1403 be_cq_notify(adapter, tx_cq->id, false, cmpl);
1404 atomic_sub(num_wrbs, &txq->used);
1405 cmpl = 0; 1405 cmpl = 0;
1406 num_wrbs = 0;
1406 } 1407 }
1407 1408
1408 if (atomic_read(&txq->used) == 0 || ++timeo > 200) 1409 if (atomic_read(&txq->used) == 0 || ++timeo > 200)
@@ -1422,7 +1423,8 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
1422 index_adv(&end_idx, 1423 index_adv(&end_idx,
1423 wrb_cnt_for_skb(adapter, sent_skb, &dummy_wrb) - 1, 1424 wrb_cnt_for_skb(adapter, sent_skb, &dummy_wrb) - 1,
1424 txq->len); 1425 txq->len);
1425 be_tx_compl_process(adapter, end_idx); 1426 num_wrbs = be_tx_compl_process(adapter, end_idx);
1427 atomic_sub(num_wrbs, &txq->used);
1426 } 1428 }
1427} 1429}
1428 1430
@@ -1796,12 +1798,12 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
1796 struct be_queue_info *tx_cq = &adapter->tx_obj.cq; 1798 struct be_queue_info *tx_cq = &adapter->tx_obj.cq;
1797 struct be_eth_tx_compl *txcp; 1799 struct be_eth_tx_compl *txcp;
1798 int tx_compl = 0, mcc_compl, status = 0; 1800 int tx_compl = 0, mcc_compl, status = 0;
1799 u16 end_idx; 1801 u16 end_idx, num_wrbs = 0;
1800 1802
1801 while ((txcp = be_tx_compl_get(tx_cq))) { 1803 while ((txcp = be_tx_compl_get(tx_cq))) {
1802 end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl, 1804 end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl,
1803 wrb_index, txcp); 1805 wrb_index, txcp);
1804 be_tx_compl_process(adapter, end_idx); 1806 num_wrbs += be_tx_compl_process(adapter, end_idx);
1805 tx_compl++; 1807 tx_compl++;
1806 } 1808 }
1807 1809
@@ -1817,6 +1819,8 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
1817 if (tx_compl) { 1819 if (tx_compl) {
1818 be_cq_notify(adapter, adapter->tx_obj.cq.id, true, tx_compl); 1820 be_cq_notify(adapter, adapter->tx_obj.cq.id, true, tx_compl);
1819 1821
1822 atomic_sub(num_wrbs, &txq->used);
1823
1820 /* As Tx wrbs have been freed up, wake up netdev queue if 1824 /* As Tx wrbs have been freed up, wake up netdev queue if
1821 * it was stopped due to lack of tx wrbs. 1825 * it was stopped due to lack of tx wrbs.
1822 */ 1826 */