[PATCH net-next v2 03/15] ibmveth: Refactor RX interrupt control for MQ RX queues
From: Mingming Cao <hidden>
Date: 2026-07-01 22:25:51
Also in:
netdev
Subsystem:
ibm power virtual ethernet device driver, linux for powerpc (32-bit and 64-bit), networking drivers, the rest · Maintainers:
Nick Child, Madhavan Srinivasan, Michael Ellerman, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
Queue 0 and subordinate RX queues use different interrupt control interfaces in PHYP: - queue 0: h_vio_signal() after h_register_logical_lan() - queue N: H_VIOCTL against the queue handle/hwirq mapping The current code is single-queue oriented and cannot safely scale to multiple RX queues in poll completion and open/close IRQ setup. Introduce queue-indexed interrupt helpers: ibmveth_enable_irq(adapter, queue_index) ibmveth_disable_irq(adapter, queue_index) ibmveth_setup_rx_interrupts() ibmveth_cleanup_rx_interrupts() These helpers centralize queue0-vs-subordinate dispatch and make IRQ lifecycle symmetric across open/close and future resize paths. request_irq() is wired with &adapter->napi[i] as dev_id per queue, so interrupt ownership follows the NAPI instance that services that RX queue. Signed-off-by: Mingming Cao <redacted> Reviewed-by: Dave Marquardt <redacted> --- drivers/net/ethernet/ibm/ibmveth.c | 160 +++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+)
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index 95068fb20dba..b5ae979c1f82 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c@@ -315,6 +315,166 @@ static void __maybe_unused ibmveth_cleanup_rx_resources(struct ibmveth_adapter * } } +/** + * ibmveth_toggle_irq - Common helper to enable/disable queue interrupts + * @adapter: ibmveth adapter structure + * @queue_index: Index of the queue (0 for primary, 1+ for subordinate) + * @enable: true to enable, false to disable + * + * For queue 0 (primary), uses h_vio_signal() as it's registered via + * h_register_logical_lan(). For subordinate queues (1+), uses H_VIOCTL + * with H_ENABLE/DISABLE_VIO_INTERRUPT for per-queue interrupt control. + * + * Return: 0 on success, error code otherwise + */ +static int +ibmveth_toggle_irq(struct ibmveth_adapter *adapter, int queue_index, bool enable) +{ + unsigned long rc; + unsigned long irq = adapter->queue_irq[queue_index]; + const char *action = enable ? "enable" : "disable"; + + if (queue_index == 0) { + /* Primary queue: use h_vio_signal() */ + rc = h_vio_signal(adapter->vdev->unit_address, + enable ? VIO_IRQ_ENABLE : VIO_IRQ_DISABLE); + } else { + /* Subordinate queues: use H_VIOCTL with hardware IRQ */ + struct irq_data *irq_data = irq_get_irq_data(irq); + irq_hw_number_t hwirq; + u64 vioctl_cmd = enable ? H_ENABLE_VIO_INTERRUPT : H_DISABLE_VIO_INTERRUPT; + + if (!irq_data) { + netdev_err(adapter->netdev, + "Failed to get IRQ data for queue %d (virq=%lu)\n", + queue_index, irq); + return -EINVAL; + } + + hwirq = irqd_to_hwirq(irq_data); + rc = plpar_hcall_norets(H_VIOCTL, + adapter->vdev->unit_address, + vioctl_cmd, + hwirq, 0, 0); + + if (rc == H_PARAMETER) { + /* H_PARAMETER is non-fatal when IRQ is already in the requested state. */ + netdev_warn_once(adapter->netdev, + "H_VIOCTL %s IRQ returned H_PARAMETER for queue %d (hwirq=%lu)\n", + action, queue_index, hwirq); + return 0; + } + } + + if (rc) + netdev_err(adapter->netdev, + "Failed to %s IRQ for queue %d, rc=%ld\n", + action, queue_index, rc); + return rc; +} + +/** + * ibmveth_disable_irq - Disable interrupt for a specific queue + * @adapter: ibmveth adapter structure + * @queue_index: Index of the queue (0 for primary, 1+ for subordinate) + * + * Return: 0 on success, error code otherwise + */ +static int +ibmveth_disable_irq(struct ibmveth_adapter *adapter, int queue_index) +{ + return ibmveth_toggle_irq(adapter, queue_index, false); +} + +/** + * ibmveth_enable_irq - Enable interrupt for a specific queue + * @adapter: ibmveth adapter structure + * @queue_index: Index of the queue (0 for primary, 1+ for subordinate) + * + * Return: 0 on success, error code otherwise + */ +static int +ibmveth_enable_irq(struct ibmveth_adapter *adapter, int queue_index) +{ + return ibmveth_toggle_irq(adapter, queue_index, true); +} + +/** + * ibmveth_setup_rx_interrupts - Register IRQs and enable NAPI + * @adapter: ibmveth adapter structure + * + * Registers interrupt handlers for all RX queues and enables NAPI polling. + * On error, cleans up any successfully registered IRQs before returning. + * + * Return: 0 on success, negative error code on failure + */ +static int __maybe_unused +ibmveth_setup_rx_interrupts(struct ibmveth_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int i, rc; + + for (i = 0; i < adapter->num_rx_queues; i++) { + if (!adapter->queue_irq[i]) { + netdev_err(netdev, "queue %d has invalid IRQ (0)\n", i); + rc = -EINVAL; + goto err_free_irqs; + } + + rc = request_irq(adapter->queue_irq[i], ibmveth_interrupt, + 0, netdev->name, &adapter->napi[i]); + if (rc) { + netdev_err(netdev, + "request_irq() failed for irq 0x%x queue %d: %d\n", + adapter->queue_irq[i], i, rc); + goto err_free_irqs; + } + } + + for (i = 0; i < adapter->num_rx_queues; i++) + napi_enable(&adapter->napi[i]); + + return 0; + +err_free_irqs: + while (--i >= 0) + free_irq(adapter->queue_irq[i], &adapter->napi[i]); + return rc; +} + +/** + * ibmveth_cleanup_rx_interrupts - Disable NAPI and free IRQs + * @adapter: ibmveth adapter structure + * + * Disables NAPI polling and frees interrupt handlers for all RX queues. + */ +static void +ibmveth_cleanup_rx_interrupts(struct ibmveth_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_rx_queues; i++) + napi_disable(&adapter->napi[i]); + + for (i = 0; i < adapter->num_rx_queues; i++) { + if (adapter->queue_irq[i]) + free_irq(adapter->queue_irq[i], &adapter->napi[i]); + } + + /* Dispose IRQ mappings for subordinate queues (1-15). + * Queue 0 uses netdev->irq from device tree, not irq_create_mapping(). + */ + for (i = 1; i < adapter->num_rx_queues; i++) { + if (adapter->queue_irq[i]) { + irq_dispose_mapping(adapter->queue_irq[i]); + adapter->queue_irq[i] = 0; + } + } + + /* Clear queue 0 IRQ number */ + adapter->queue_irq[0] = 0; +} + /* setup the initial settings for a buffer pool */ static void ibmveth_init_buffer_pool(struct ibmveth_buff_pool *pool, u32 pool_index, u32 pool_size,
--
2.39.3 (Apple Git-146)