After aggressive ethtool -L cycling, PHYP can leave a VALID RX descriptor
with a correlator that no longer matches the per-queue buffer pools. Poll
treated this as fatal: ibmveth_rxq_get_buffer() WARNed and returned NULL
without advancing the ring, then restart_poll retried the same slot forever.

Advance past bad correlators instead of spinning: validate correlators
without WARN_ON, skip invalid slots in poll (count as invalid_buffers),
and advance the RX ring when remove_buffer_from_pool cannot map the
correlator. Rate-limit the bad correlator message.

Complete NAPI when the interface is down or napi_disable is pending so
ibmveth_cleanup_rx_interrupts() can finish. Do not restart_poll in that
window. Close keeps hypervisor IRQ disable before napi_disable (via
cleanup_rx_interrupts()).

Signed-off-by: Mingming Cao <[email protected]>
Reviewed-by: Dave Marquardt <[email protected]>
---
 drivers/net/ethernet/ibm/ibmveth.c | 76 ++++++++++++++++++++++--------
 1 file changed, 57 insertions(+), 19 deletions(-)

diff --git a/drivers/net/ethernet/ibm/ibmveth.c 
b/drivers/net/ethernet/ibm/ibmveth.c
index 50a332ab83fd..d7bf01271161 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -158,6 +158,25 @@ static inline int ibmveth_rxq_frame_length(struct 
ibmveth_adapter *adapter,
        return be32_to_cpu(rxq->queue_addr[rxq->index].length);
 }
 
+static inline bool
+ibmveth_rxq_correlator_valid(struct ibmveth_adapter *adapter, int queue_index,
+                            u64 correlator)
+{
+       unsigned int pool = correlator >> 32;
+       unsigned int index = correlator & 0xffffffffUL;
+
+       return pool < IBMVETH_NUM_BUFF_POOLS &&
+              index < adapter->rx_buff_pool[queue_index][pool].size;
+}
+
+static inline void ibmveth_rxq_advance(struct ibmveth_rx_q *rxq)
+{
+       if (++rxq->index == rxq->num_slots) {
+               rxq->index = 0;
+               rxq->toggle = !rxq->toggle;
+       }
+}
+
 static inline int ibmveth_rxq_csum_good(struct ibmveth_adapter *adapter,
                                        int queue_index)
 {
@@ -1284,17 +1303,12 @@ static int ibmveth_remove_buffer_from_pool(struct 
ibmveth_adapter *adapter,
        unsigned int free_index;
        struct sk_buff *skb;
 
-       if (WARN_ON(pool >= IBMVETH_NUM_BUFF_POOLS) ||
-           WARN_ON(index >= adapter->rx_buff_pool[queue_index][pool].size)) {
-               schedule_work(&adapter->work);
+       if (!ibmveth_rxq_correlator_valid(adapter, queue_index, correlator))
                return -EINVAL;
-       }
 
        skb = adapter->rx_buff_pool[queue_index][pool].skbuff[index];
-       if (WARN_ON(!skb)) {
-               schedule_work(&adapter->work);
+       if (!skb)
                return -EFAULT;
-       }
 
        /* if we are going to reuse the buffer then keep the pointers around
         * but mark index as available. replenish will see the skb pointer and
@@ -1335,11 +1349,8 @@ static inline struct sk_buff 
*ibmveth_rxq_get_buffer(struct ibmveth_adapter *ada
        unsigned int pool = correlator >> 32;
        unsigned int index = correlator & 0xffffffffUL;
 
-       if (WARN_ON(pool >= IBMVETH_NUM_BUFF_POOLS) ||
-           WARN_ON(index >= adapter->rx_buff_pool[queue_index][pool].size)) {
-               schedule_work(&adapter->work);
+       if (!ibmveth_rxq_correlator_valid(adapter, queue_index, correlator))
                return NULL;
-       }
 
        return adapter->rx_buff_pool[queue_index][pool].skbuff[index];
 }
@@ -1365,14 +1376,15 @@ static int ibmveth_rxq_harvest_buffer(struct 
ibmveth_adapter *adapter,
 
        cor = rxq->queue_addr[rxq->index].correlator;
        rc = ibmveth_remove_buffer_from_pool(adapter, cor, queue_index, reuse);
-       if (unlikely(rc))
+       if (unlikely(rc)) {
+               if (rc == -EINVAL || rc == -EFAULT)
+                       goto advance;
                return rc;
-
-       if (++rxq->index == rxq->num_slots) {
-               rxq->index = 0;
-               rxq->toggle = !rxq->toggle;
        }
 
+advance:
+       ibmveth_rxq_advance(rxq);
+
        return 0;
 }
 
@@ -2931,11 +2943,19 @@ static int ibmveth_poll(struct napi_struct *napi, int 
budget)
        if (WARN_ON(queue_index < 0 || queue_index >= adapter->num_rx_queues))
                return 0;
 
+       if (!netif_running(netdev) || napi_disable_pending(napi)) {
+               napi_complete_done(napi, 0);
+               return 0;
+       }
+
        if (adapter->rx_qstats)
                adapter->rx_qstats[queue_index].polls++;
 
 restart_poll:
        while (frames_processed < budget) {
+               if (!netif_running(netdev) || napi_disable_pending(napi))
+                       break;
+
                if (!ibmveth_rxq_pending_buffer(adapter, queue_index))
                        break;
 
@@ -2959,8 +2979,21 @@ static int ibmveth_poll(struct napi_struct *napi, int 
budget)
                        __sum16 iph_check = 0;
 
                        skb = ibmveth_rxq_get_buffer(adapter, queue_index);
-                       if (unlikely(!skb))
-                               break;
+                       if (unlikely(!skb)) {
+                               if (net_ratelimit())
+                                       netdev_err(netdev,
+                                                  "bad correlator on queue %d, 
skipping slot\n",
+                                                  queue_index);
+                               if (adapter->rx_qstats)
+                                       
adapter->rx_qstats[queue_index].invalid_buffers++;
+                               else
+                                       adapter->rx_invalid_buffer++;
+                               rc = ibmveth_rxq_harvest_buffer(adapter, 
queue_index,
+                                                               true);
+                               if (unlikely(rc))
+                                       break;
+                               continue;
+                       }
 
                        /* if the large packet bit is set in the rx queue
                         * descriptor, the mss will be written by PHYP eight
@@ -3034,8 +3067,11 @@ static int ibmveth_poll(struct napi_struct *napi, int 
budget)
 
        ibmveth_replenish_task(adapter, queue_index);
 
-       if (frames_processed == budget)
+       if (frames_processed == budget) {
+               if (!netif_running(netdev) || napi_disable_pending(napi))
+                       napi_complete_done(napi, frames_processed);
                goto out;
+       }
 
        if (!napi_complete_done(napi, frames_processed))
                goto out;
@@ -3053,6 +3089,8 @@ static int ibmveth_poll(struct napi_struct *napi, int 
budget)
        }
 
        if (ibmveth_rxq_pending_buffer(adapter, queue_index) &&
+           netif_running(netdev) &&
+           !napi_disable_pending(napi) &&
            napi_schedule(napi)) {
                lpar_rc = ibmveth_disable_irq(adapter, queue_index);
                WARN_ON(lpar_rc != H_SUCCESS);
-- 
2.39.3 (Apple Git-146)


Reply via email to