lkml.org 
[lkml]   [2017]   [Dec]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.9 104/148] ibmvnic: Fix overflowing firmware/hardware TX queue
    Date
    4.9-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Thomas Falcon <tlfalcon@linux.vnet.ibm.com>


    [ Upstream commit 142c0ac445792c492579cb01f1cfd4e32e6dfcce ]

    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>
    Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    drivers/net/ethernet/ibm/ibmvnic.c | 27 ++++++++++++++++++++++++++-
    drivers/net/ethernet/ibm/ibmvnic.h | 1 +
    2 files changed, 27 insertions(+), 1 deletion(-)

    --- 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 *
    u8 *hdrs = (u8 *)&adapter->tx_rx_desc_req;
    struct device *dev = &adapter->vdev->dev;
    struct ibmvnic_tx_buff *tx_buff = NULL;
    + struct ibmvnic_sub_crq_queue *tx_scrq;
    struct ibmvnic_tx_pool *tx_pool;
    unsigned int tx_send_failed = 0;
    unsigned int tx_map_failed = 0;
    @@ -724,6 +725,7 @@ static int ibmvnic_xmit(struct sk_buff *
    int ret = 0;

    tx_pool = &adapter->tx_pool[queue_num];
    + tx_scrq = adapter->tx_scrq[queue_num];
    txq = netdev_get_tx_queue(netdev, skb_get_queue_mapping(skb));
    handle_array = (u64 *)((u8 *)(adapter->login_rsp_buf) +
    be32_to_cpu(adapter->login_rsp_buf->
    @@ -826,6 +828,14 @@ static int ibmvnic_xmit(struct sk_buff *
    ret = NETDEV_TX_BUSY;
    goto out;
    }
    +
    + atomic_inc(&tx_scrq->used);
    +
    + if (atomic_read(&tx_scrq->used) >= adapter->req_tx_entries_per_subcrq) {
    + netdev_info(netdev, "Stopping queue %d\n", queue_num);
    + netif_stop_subqueue(netdev, queue_num);
    + }
    +
    tx_packets++;
    tx_bytes += skb->len;
    txq->trans_start = jiffies;
    @@ -1220,6 +1230,7 @@ static struct ibmvnic_sub_crq_queue *ini
    scrq->adapter = adapter;
    scrq->size = 4 * PAGE_SIZE / sizeof(*scrq->msgs);
    scrq->cur = 0;
    + atomic_set(&scrq->used, 0);
    scrq->rx_skb_top = NULL;
    spin_lock_init(&scrq->lock);

    @@ -1368,8 +1379,22 @@ restart_loop:
    DMA_TO_DEVICE);
    }

    - if (txbuff->last_frag)
    + if (txbuff->last_frag) {
    + atomic_dec(&scrq->used);
    +
    + if (atomic_read(&scrq->used) <=
    + (adapter->req_tx_entries_per_subcrq / 2) &&
    + netif_subqueue_stopped(adapter->netdev,
    + txbuff->skb)) {
    + netif_wake_subqueue(adapter->netdev,
    + scrq->pool_index);
    + netdev_dbg(adapter->netdev,
    + "Started queue %d\n",
    + scrq->pool_index);
    + }
    +
    dev_kfree_skb_any(txbuff->skb);
    + }

    adapter->tx_pool[pool].free_map[adapter->tx_pool[pool].
    producer_index] = index;
    --- a/drivers/net/ethernet/ibm/ibmvnic.h
    +++ b/drivers/net/ethernet/ibm/ibmvnic.h
    @@ -863,6 +863,7 @@ struct ibmvnic_sub_crq_queue {
    spinlock_t lock;
    struct sk_buff *rx_skb_top;
    struct ibmvnic_adapter *adapter;
    + atomic_t used;
    };

    struct ibmvnic_long_term_buff {

    \
     
     \ /
      Last update: 2017-12-12 14:14    [W:5.840 / U:0.004 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site