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 <[email protected]>
Reviewed-by: Dave Marquardt <[email protected]>
---
 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)


Reply via email to