aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Falcon <tlfalcon@linux.vnet.ibm.com>2017-03-05 13:18:41 -0500
committerDavid S. Miller <davem@davemloft.net>2017-03-07 17:14:30 -0500
commit142c0ac445792c492579cb01f1cfd4e32e6dfcce (patch)
tree656a3545ab1f3070a77f5bf7fbca80bd400871d9
parent6c4dc75c251721f517e9daeb5370ea606b5b35ce (diff)
ibmvnic: Fix overflowing firmware/hardware TX queue
Use a counter to track the number of outstanding transmissions sent that have not received completions. If the counter reaches the maximum number of queue entries, stop transmissions on that queue. As we receive more completions from firmware, wake the queue once the counter reaches an acceptable level. This patch prevents hardware/firmware TX queue from filling up and and generating errors. Since incorporating this fix, internal testing has reported that these firmware errors have stopped. Signed-off-by: Thomas Falcon <tlfalcon@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/ibm/ibmvnic.c27
-rw-r--r--drivers/net/ethernet/ibm/ibmvnic.h1
2 files changed, 27 insertions, 1 deletions
diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
index 9198e6bd5160..0e87b83f25e2 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.c
+++ b/drivers/net/ethernet/ibm/ibmvnic.c
@@ -705,6 +705,7 @@ static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
705 u8 *hdrs = (u8 *)&adapter->tx_rx_desc_req; 705 u8 *hdrs = (u8 *)&adapter->tx_rx_desc_req;
706 struct device *dev = &adapter->vdev->dev; 706 struct device *dev = &adapter->vdev->dev;
707 struct ibmvnic_tx_buff *tx_buff = NULL; 707 struct ibmvnic_tx_buff *tx_buff = NULL;
708 struct ibmvnic_sub_crq_queue *tx_scrq;
708 struct ibmvnic_tx_pool *tx_pool; 709 struct ibmvnic_tx_pool *tx_pool;
709 unsigned int tx_send_failed = 0; 710 unsigned int tx_send_failed = 0;
710 unsigned int tx_map_failed = 0; 711 unsigned int tx_map_failed = 0;
@@ -724,6 +725,7 @@ static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
724 int ret = 0; 725 int ret = 0;
725 726
726 tx_pool = &adapter->tx_pool[queue_num]; 727 tx_pool = &adapter->tx_pool[queue_num];
728 tx_scrq = adapter->tx_scrq[queue_num];
727 txq = netdev_get_tx_queue(netdev, skb_get_queue_mapping(skb)); 729 txq = netdev_get_tx_queue(netdev, skb_get_queue_mapping(skb));
728 handle_array = (u64 *)((u8 *)(adapter->login_rsp_buf) + 730 handle_array = (u64 *)((u8 *)(adapter->login_rsp_buf) +
729 be32_to_cpu(adapter->login_rsp_buf-> 731 be32_to_cpu(adapter->login_rsp_buf->
@@ -826,6 +828,14 @@ static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
826 ret = NETDEV_TX_BUSY; 828 ret = NETDEV_TX_BUSY;
827 goto out; 829 goto out;
828 } 830 }
831
832 atomic_inc(&tx_scrq->used);
833
834 if (atomic_read(&tx_scrq->used) >= adapter->req_tx_entries_per_subcrq) {
835 netdev_info(netdev, "Stopping queue %d\n", queue_num);
836 netif_stop_subqueue(netdev, queue_num);
837 }
838
829 tx_packets++; 839 tx_packets++;
830 tx_bytes += skb->len; 840 tx_bytes += skb->len;
831 txq->trans_start = jiffies; 841 txq->trans_start = jiffies;
@@ -1213,6 +1223,7 @@ static struct ibmvnic_sub_crq_queue *init_sub_crq_queue(struct ibmvnic_adapter
1213 scrq->adapter = adapter; 1223 scrq->adapter = adapter;
1214 scrq->size = 4 * PAGE_SIZE / sizeof(*scrq->msgs); 1224 scrq->size = 4 * PAGE_SIZE / sizeof(*scrq->msgs);
1215 scrq->cur = 0; 1225 scrq->cur = 0;
1226 atomic_set(&scrq->used, 0);
1216 scrq->rx_skb_top = NULL; 1227 scrq->rx_skb_top = NULL;
1217 spin_lock_init(&scrq->lock); 1228 spin_lock_init(&scrq->lock);
1218 1229
@@ -1355,8 +1366,22 @@ restart_loop:
1355 DMA_TO_DEVICE); 1366 DMA_TO_DEVICE);
1356 } 1367 }
1357 1368
1358 if (txbuff->last_frag) 1369 if (txbuff->last_frag) {
1370 atomic_dec(&scrq->used);
1371
1372 if (atomic_read(&scrq->used) <=
1373 (adapter->req_tx_entries_per_subcrq / 2) &&
1374 netif_subqueue_stopped(adapter->netdev,
1375 txbuff->skb)) {
1376 netif_wake_subqueue(adapter->netdev,
1377 scrq->pool_index);
1378 netdev_dbg(adapter->netdev,
1379 "Started queue %d\n",
1380 scrq->pool_index);
1381 }
1382
1359 dev_kfree_skb_any(txbuff->skb); 1383 dev_kfree_skb_any(txbuff->skb);
1384 }
1360 1385
1361 adapter->tx_pool[pool].free_map[adapter->tx_pool[pool]. 1386 adapter->tx_pool[pool].free_map[adapter->tx_pool[pool].
1362 producer_index] = index; 1387 producer_index] = index;
diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h
index 422824f1f42a..1993b42666f7 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.h
+++ b/drivers/net/ethernet/ibm/ibmvnic.h
@@ -863,6 +863,7 @@ struct ibmvnic_sub_crq_queue {
863 spinlock_t lock; 863 spinlock_t lock;
864 struct sk_buff *rx_skb_top; 864 struct sk_buff *rx_skb_top;
865 struct ibmvnic_adapter *adapter; 865 struct ibmvnic_adapter *adapter;
866 atomic_t used;
866}; 867};
867 868
868struct ibmvnic_long_term_buff { 869struct ibmvnic_long_term_buff {