Replenish is the last open-path hypervisor call that still needs
per-queue awareness before MQ receive is enabled. Today
ibmveth_replenish_buffer_pool() calls h_add_logical_lan_buffer() or
h_add_logical_lan_buffers() directly; MQ posts via
H_ADD_LOGICAL_LAN_BUFFERS_QUEUE against adapter->queue_handle[].

Add ibmveth_add_logical_lan_buffers() to pick the hcall:
multi_queue uses h_add_logical_lan_buffers_queue() (up to 12 buffers,
IOBAs packed with odd counts in the upper 32 bits); legacy uses the
existing single- and multi-buffer hcalls. Count add_buf/add_bufs/
add_bufs_queue in hcall_stats.

Thread queue_index through replenish_task() and replenish_buffer_pool()
so they index rx_buff_pool[queue_index][pool]. All callers still pass
queue 0; legacy hcalls remain the live path until MQ probe enables
multi_queue.

Also split H_FUNCTION handling: legacy batch falls back to single-buffer
mode; multi_queue logs an error on unsupported firmware.

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

diff --git a/drivers/net/ethernet/ibm/ibmveth.c 
b/drivers/net/ethernet/ibm/ibmveth.c
index fa2d4777ffc7..b3b3886c3eed 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -597,11 +597,73 @@ static inline void ibmveth_flush_buffer(void *addr, 
unsigned long length)
                asm("dcbf %0,%1,1" :: "b" (addr), "r" (offset));
 }
 
+/**
+ * ibmveth_add_logical_lan_buffers - Add receive buffers to hypervisor
+ * @adapter: ibmveth adapter structure
+ * @descs: array of buffer descriptors to add
+ * @filled: number of valid descriptors in the array
+ * @buff_size: size of each buffer (multi-queue mode only)
+ * @queue_index: RX queue index
+ *
+ * Return: hypervisor return code
+ */
+static long ibmveth_add_logical_lan_buffers(struct ibmveth_adapter *adapter,
+                                           union ibmveth_buf_desc *descs,
+                                           int filled,
+                                           unsigned long buff_size,
+                                           int queue_index)
+{
+       struct vio_dev *vdev = adapter->vdev;
+       unsigned long rc;
+
+       if (adapter->multi_queue) {
+               unsigned long buffersznum = (buff_size << 32) | filled;
+               unsigned long ioba[IBMVETH_MAX_RX_PER_HCALL / 2] = {0};
+               int i;
+
+               /* Pack descriptor addresses into ioba pairs.
+                * Each ioba holds two 32-bit addresses packed into 64 bits:
+                * - Even descriptors (0,2,4...) go in high 32 bits
+                * - Odd descriptors (1,3,5...) go in low 32 bits
+                */
+               for (i = 0; i < filled && i < IBMVETH_MAX_RX_PER_HCALL; i++) {
+                       int pair_idx = i / 2;           /* Which pair: 0-5 */
+                       int is_high = (i % 2 == 0);     /* High or low 32 bits 
*/
+
+                       if (is_high)
+                               ioba[pair_idx] = (unsigned 
long)descs[i].fields.address << 32;
+                       else
+                               ioba[pair_idx] |= descs[i].fields.address;
+               }
+
+               rc = h_add_logical_lan_buffers_queue(vdev->unit_address,
+                                                    
adapter->queue_handle[queue_index],
+                                                    buffersznum,
+                                                    ioba[0], ioba[1], ioba[2],
+                                                    ioba[3], ioba[4], ioba[5]);
+               adapter->hcall_stats.add_bufs_queue++;
+       } else if (filled == 1) {
+               rc = h_add_logical_lan_buffer(vdev->unit_address,
+                                             descs[0].desc);
+               adapter->hcall_stats.add_buf++;
+       } else {
+               rc = h_add_logical_lan_buffers(vdev->unit_address,
+                                              descs[0].desc, descs[1].desc,
+                                              descs[2].desc, descs[3].desc,
+                                              descs[4].desc, descs[5].desc,
+                                              descs[6].desc, descs[7].desc);
+               adapter->hcall_stats.add_bufs++;
+       }
+
+       return rc;
+}
+
 /* replenish the buffers for a pool.  note that we don't need to
  * skb_reserve these since they are used for incoming...
  */
 static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter,
-                                         struct ibmveth_buff_pool *pool)
+                                         struct ibmveth_buff_pool *pool,
+                                         int queue_index)
 {
        union ibmveth_buf_desc descs[IBMVETH_MAX_RX_PER_HCALL] = {0};
        u32 remaining = pool->size - atomic_read(&pool->available);
@@ -687,24 +749,15 @@ static void ibmveth_replenish_buffer_pool(struct 
ibmveth_adapter *adapter,
                if (!filled)
                        break;
 
-               /* single buffer case*/
-               if (filled == 1)
-                       lpar_rc = h_add_logical_lan_buffer(vdev->unit_address,
-                                                          descs[0].desc);
-               else
-                       /* Multi-buffer hcall */
-                       lpar_rc = h_add_logical_lan_buffers(vdev->unit_address,
-                                                           descs[0].desc,
-                                                           descs[1].desc,
-                                                           descs[2].desc,
-                                                           descs[3].desc,
-                                                           descs[4].desc,
-                                                           descs[5].desc,
-                                                           descs[6].desc,
-                                                           descs[7].desc);
+               lpar_rc = ibmveth_add_logical_lan_buffers(adapter, descs,
+                                                         filled,
+                                                         pool->buff_size,
+                                                         queue_index);
+
                if (lpar_rc != H_SUCCESS) {
                        dev_warn_ratelimited(dev,
-                                            "RX h_add_logical_lan failed: 
filled=%u, rc=%lu, batch=%u\n",
+                                            "RX h_add_logical_lan %s failed: 
filled=%u, rc=%lu, batch=%u\n",
+                                            adapter->multi_queue ? "_queue" : 
"",
                                             filled, lpar_rc, batch);
                        goto hcall_failure;
                }
@@ -745,24 +798,19 @@ static void ibmveth_replenish_buffer_pool(struct 
ibmveth_adapter *adapter,
                }
                adapter->replenish_add_buff_failure += filled;
 
-               /*
-                * If multi rx buffers hcall is no longer supported by FW
-                * e.g. in the case of Live Partition Migration
-                */
-               if (batch > 1 && lpar_rc == H_FUNCTION) {
-                       /*
-                        * Instead of retry submit single buffer individually
-                        * here just set the max rx buffer per hcall to 1
-                        * buffers will be respleshed next time
-                        * when ibmveth_replenish_buffer_pool() is called again
-                        * with single-buffer case
-                        */
-                       netdev_info(adapter->netdev,
-                                   "RX Multi buffers not supported by FW, 
rc=%lu\n",
-                                   lpar_rc);
-                       adapter->rx_buffers_per_hcall = 1;
-                       netdev_info(adapter->netdev,
-                                   "Next rx replesh will fall back to 
single-buffer hcall\n");
+               if (lpar_rc == H_FUNCTION) {
+                       if (adapter->multi_queue) {
+                               netdev_err(adapter->netdev,
+                                          "Unexpected H_FUNCTION from 
multi-queue buffer add (queue=%d, batch=%d)\n",
+                                          queue_index, batch);
+                               break;
+                       } else if (batch > 1) {
+                               netdev_warn(adapter->netdev,
+                                           "H_FUNCTION from legacy batch 
buffer add (batch=%d), falling back to single buffer mode\n",
+                                           batch);
+                               adapter->rx_buffers_per_hcall = 1;
+                               continue;
+                       }
                }
                break;
        }
@@ -784,18 +832,24 @@ static void ibmveth_update_rx_no_buffer(struct 
ibmveth_adapter *adapter)
 }
 
 /* replenish routine */
-static void ibmveth_replenish_task(struct ibmveth_adapter *adapter)
+static void ibmveth_replenish_task(struct ibmveth_adapter *adapter,
+                                  int queue_index)
 {
        int i;
 
+       if (queue_index >= adapter->num_rx_queues)
+               return;
+
        adapter->replenish_task_cycles++;
 
        for (i = (IBMVETH_NUM_BUFF_POOLS - 1); i >= 0; i--) {
-               struct ibmveth_buff_pool *pool = &adapter->rx_buff_pool[0][i];
+               struct ibmveth_buff_pool *pool =
+                       &adapter->rx_buff_pool[queue_index][i];
 
                if (pool->active &&
                    (atomic_read(&pool->available) < pool->threshold))
-                       ibmveth_replenish_buffer_pool(adapter, pool);
+                       ibmveth_replenish_buffer_pool(adapter, pool,
+                                                     queue_index);
        }
 
        ibmveth_update_rx_no_buffer(adapter);
@@ -2307,7 +2361,7 @@ static int ibmveth_poll(struct napi_struct *napi, int 
budget)
                }
        }
 
-       ibmveth_replenish_task(adapter);
+       ibmveth_replenish_task(adapter, 0);
 
        if (frames_processed == budget)
                goto out;
@@ -2458,7 +2512,7 @@ static void ibmveth_poll_controller(struct net_device 
*dev)
 {
        struct ibmveth_adapter *adapter = netdev_priv(dev);
 
-       ibmveth_replenish_task(adapter);
+       ibmveth_replenish_task(adapter, 0);
        ibmveth_interrupt(dev->irq, &adapter->napi[0]);
 }
 #endif
-- 
2.39.3 (Apple Git-146)


Reply via email to