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)
