mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 11:50:43 +09:00
ibmvnic: Fix overflowing firmware/hardware TX queue
[ Upstream commit 142c0ac445 ]
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>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
742e67d2b7
commit
f3b1f93ed2
@@ -705,6 +705,7 @@ static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
|
||||
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 *skb, struct net_device *netdev)
|
||||
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 *skb, struct net_device *netdev)
|
||||
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 *init_sub_crq_queue(struct ibmvnic_adapter
|
||||
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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user