summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet
diff options
context:
space:
mode:
authorNathan Fontenot <nfont@linux.vnet.ibm.com>2017-05-03 21:04:56 +0300
committerDavid S. Miller <davem@davemloft.net>2017-05-03 18:33:04 +0300
commitb41b83e9a784576b2bcc33bce447f7ce78fb265d (patch)
tree667d00dfae379529972d955c044913069ac745f2 /drivers/net/ethernet
parente0ebe942f42952fb23bb0596f8775e50bed0b341 (diff)
downloadlinux-b41b83e9a784576b2bcc33bce447f7ce78fb265d.tar.xz
ibmvnic: Clean up tx pools when closing
When closing the ibmvnic driver, most notably during the reset path, the tx pools need to be cleaned to ensure there are no hanging skbs that need to be free'ed. The need for this was found during debugging a loss of network traffic after handling a driver reset. The underlying cause was some skbs in the tx pool that were never free'ed. As a result the upper network layers never tried a re-send since it believed the driver still had the skb. Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet')
-rw-r--r--drivers/net/ethernet/ibm/ibmvnic.c30
1 files changed, 30 insertions, 0 deletions
diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
index bbbd57e272c4..2297cf2390e1 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.c
+++ b/drivers/net/ethernet/ibm/ibmvnic.c
@@ -760,6 +760,34 @@ static void disable_sub_crqs(struct ibmvnic_adapter *adapter)
}
}
+static void clean_tx_pools(struct ibmvnic_adapter *adapter)
+{
+ struct ibmvnic_tx_pool *tx_pool;
+ u64 tx_entries;
+ int tx_scrqs;
+ int i, j;
+
+ if (!adapter->tx_pool)
+ return;
+
+ tx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_txsubm_subcrqs);
+ tx_entries = adapter->req_tx_entries_per_subcrq;
+
+ /* Free any remaining skbs in the tx buffer pools */
+ for (i = 0; i < tx_scrqs; i++) {
+ tx_pool = &adapter->tx_pool[i];
+ if (!tx_pool)
+ continue;
+
+ for (j = 0; j < tx_entries; j++) {
+ if (tx_pool->tx_buff[j].skb) {
+ dev_kfree_skb_any(tx_pool->tx_buff[j].skb);
+ tx_pool->tx_buff[j].skb = NULL;
+ }
+ }
+ }
+}
+
static int __ibmvnic_close(struct net_device *netdev)
{
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
@@ -768,6 +796,8 @@ static int __ibmvnic_close(struct net_device *netdev)
adapter->state = VNIC_CLOSING;
netif_tx_stop_all_queues(netdev);
+
+ clean_tx_pools(adapter);
disable_sub_crqs(adapter);
if (adapter->napi) {