From: Mingming Cao <mmc@linux.ibm.com>
To: netdev@vger.kernel.org
Cc: horms@kernel.org, bjking1@linux.ibm.com, haren@linux.ibm.com,
ricklind@linux.ibm.com, mmc@linux.ibm.com, kuba@kernel.org,
edumazet@google.com, pabeni@redhat.com,
linuxppc-dev@lists.ozlabs.org, maddy@linux.ibm.com,
mpe@ellerman.id.au, Dave Marquardt <davemarq@linux.ibm.com>
Subject: [PATCH net-next v3 07/15] ibmveth: Add RX queue register/deregister helpers for MQ
Date: Mon, 6 Jul 2026 12:35:55 -0700 [thread overview]
Message-ID: <20260706193603.8039-8-mmc@linux.ibm.com> (raw)
In-Reply-To: <20260706193603.8039-1-mmc@linux.ibm.com>
MQ RX replaces a single adapter-level register/free pair with a mixed
PHYP model: queue 0 via h_register_logical_lan*(), subordinates via
H_REG_LOGICAL_LAN_QUEUE. Subordinate registration returns queue handles
and hardware IRQ numbers that must be mapped to Linux virqs and unwound
on failure.
Add queue lifecycle helpers to isolate that control plane:
ibmveth_register_logical_lan_queue()
ibmveth_register_single_rx_queue()
ibmveth_deregister_single_rx_queue()
ibmveth_register_rx_queues()
ibmveth_free_all_queues()
ibmveth_dispose_subordinate_irq_mappings()
These helpers are called only when multi_queue is enabled (patch 11).
Until then open/close still use the legacy register and buffer hcall
path; legacy firmware is unchanged.
When multi_queue is enabled, queue 0 uses
h_register_logical_lan_with_handle() so all queues share the per-queue
buffer hcall path. register_rx_queues() registers with PHYP only;
interrupt delivery is enabled later from ibmveth_setup_rx_interrupts()
after request_irq(). Partial registration failure disposes subordinate virq
mappings before ibmveth_free_all_queues() clears handles;
free_all_queues() clears queue handles only — IRQ mappings are released
by dispose_subordinate_irq_mappings() or cleanup_rx_interrupts().
This commit also centralizes hcall accounting on the register/free paths.
Signed-off-by: Mingming Cao <mmc@linux.ibm.com>
Reviewed-by: Dave Marquardt <davemarq@linux.ibm.com>
---
drivers/net/ethernet/ibm/ibmveth.c | 337 ++++++++++++++++++++++++++++-
1 file changed, 332 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index 63b0184c622a..7fc11a4e1f61 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -21,6 +21,8 @@
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <linux/mm.h>
#include <linux/pm.h>
#include <linux/ethtool.h>
@@ -399,6 +401,28 @@ ibmveth_enable_irq(struct ibmveth_adapter *adapter, int queue_index)
return ibmveth_toggle_irq(adapter, queue_index, true);
}
+/**
+ * ibmveth_dispose_subordinate_irq_mappings - Drop virq mappings for queues 1..N
+ * @adapter: ibmveth adapter structure
+ *
+ * Subordinate queues get mappings from irq_create_mapping() during PHYP
+ * registration. Queue 0 uses netdev->irq from device tree and is left alone.
+ * Call after free_irq() when handlers were installed, or alone when open
+ * fails during register_rx_queues() before request_irq().
+ */
+static void
+ibmveth_dispose_subordinate_irq_mappings(struct ibmveth_adapter *adapter)
+{
+ int i;
+
+ 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;
+ }
+ }
+}
+
/**
* ibmveth_setup_rx_interrupts - Register IRQs and enable NAPI
* @adapter: ibmveth adapter structure
@@ -1082,8 +1106,8 @@ ibmveth_free_tx_resources(struct ibmveth_adapter *adapter)
}
static int ibmveth_register_logical_lan(struct ibmveth_adapter *adapter,
- union ibmveth_buf_desc rxq_desc,
- u64 mac_address)
+ union ibmveth_buf_desc rxq_desc,
+ u64 mac_address)
{
int rc, try_again = 1;
@@ -1093,13 +1117,29 @@ static int ibmveth_register_logical_lan(struct ibmveth_adapter *adapter,
* try again, but only once.
*/
retry:
- rc = h_register_logical_lan(adapter->vdev->unit_address,
- adapter->buffer_list_dma[0], rxq_desc.desc,
- adapter->filter_list_dma, mac_address);
+ /* In multi-queue mode, obtain a queue handle for queue 0 so all RX
+ * queues can use the same per-queue buffer hypercalls.
+ */
+ if (adapter->multi_queue) {
+ rc = h_register_logical_lan_with_handle(adapter->vdev->unit_address,
+ adapter->buffer_list_dma[0],
+ rxq_desc.desc,
+ adapter->filter_list_dma,
+ mac_address,
+ &adapter->queue_handle[0]);
+ } else {
+ rc = h_register_logical_lan(adapter->vdev->unit_address,
+ adapter->buffer_list_dma[0],
+ rxq_desc.desc,
+ adapter->filter_list_dma,
+ mac_address);
+ }
+ adapter->hcall_stats.reg_lan++;
if (rc != H_SUCCESS && try_again) {
do {
rc = h_free_logical_lan(adapter->vdev->unit_address);
+ adapter->hcall_stats.free_lan++;
} while (H_IS_LONG_BUSY(rc) || (rc == H_BUSY));
try_again = 0;
@@ -1136,6 +1176,293 @@ static void __maybe_unused ibmveth_free_rx_qstats(struct ibmveth_adapter *adapte
adapter->rx_qstats = NULL;
}
+/**
+ * ibmveth_register_logical_lan_queue - Register subordinate queue with hypervisor
+ * @adapter: ibmveth adapter structure
+ * @rxq_desc: Receive queue descriptor
+ * @queue_index: RX queue index (1..N for subordinate queues)
+ *
+ * Registers a subordinate receive queue using H_REG_LOGICAL_LAN_QUEUE.
+ * On success, stores the queue handle and virtual IRQ in the adapter.
+ * Retries once if registration fails (handles kexec case). If IRQ mapping
+ * fails after a successful hypervisor registration, the queue is freed
+ * before returning.
+ *
+ * Return: H_SUCCESS on success, negative errno on IRQ mapping failure,
+ * hypervisor error code otherwise
+ */
+static int
+ibmveth_register_logical_lan_queue(struct ibmveth_adapter *adapter,
+ union ibmveth_buf_desc rxq_desc,
+ int queue_index)
+{
+ unsigned long handle, hwirq;
+ unsigned int virq;
+ long lpar_rc;
+ int try_again = 1;
+
+retry:
+ netdev_dbg(adapter->netdev,
+ "Attempting to register queue %d: unit_addr=0x%x buffer_list_dma=0x%llx rxq_desc=0x%llx\n",
+ queue_index, adapter->vdev->unit_address,
+ (unsigned long long)adapter->buffer_list_dma[queue_index],
+ (unsigned long long)rxq_desc.desc);
+
+ lpar_rc = h_reg_logical_lan_queue(adapter->vdev->unit_address,
+ adapter->buffer_list_dma[queue_index],
+ rxq_desc.desc, &handle, &hwirq);
+ adapter->hcall_stats.reg_lan_queue++;
+
+ if (lpar_rc == H_SUCCESS) {
+ virq = irq_create_mapping(NULL, hwirq);
+ if (!virq) {
+ unsigned long free_rc;
+
+ netdev_err(adapter->netdev,
+ "Failed to map IRQ for queue %d (hwirq=%lu)\n",
+ queue_index, hwirq);
+ do {
+ free_rc = h_free_logical_lan_queue(adapter->vdev->unit_address,
+ handle);
+ } while (H_IS_LONG_BUSY(free_rc) || (free_rc == H_BUSY));
+ adapter->hcall_stats.free_lan_queue++;
+ if (free_rc != H_SUCCESS)
+ netdev_err(adapter->netdev,
+ "h_free_logical_lan_queue failed for queue %d after IRQ map failure: rc=0x%lx\n",
+ queue_index, free_rc);
+ return -EINVAL;
+ }
+
+ adapter->queue_handle[queue_index] = handle;
+ adapter->queue_irq[queue_index] = virq;
+
+ netdev_dbg(adapter->netdev,
+ "queue %d registered: handle=0x%llx irq=%u\n",
+ queue_index, adapter->queue_handle[queue_index],
+ adapter->queue_irq[queue_index]);
+ return H_SUCCESS;
+ }
+
+ if (lpar_rc == H_FUNCTION) {
+ if (adapter->multi_queue) {
+ netdev_info(adapter->netdev,
+ "Multi queue mode not supported by firmware, falling back to single queue\n");
+ adapter->multi_queue = 0;
+ } else {
+ netdev_err(adapter->netdev,
+ "Unexpected H_FUNCTION for queue %d registration (MQ mode already disabled)\n",
+ queue_index);
+ }
+ return lpar_rc;
+ }
+
+ if (try_again) {
+ try_again = 0;
+ goto retry;
+ }
+
+ netdev_err(adapter->netdev,
+ "h_reg_logical_lan_queue failed with %ld after retry\n",
+ lpar_rc);
+ netdev_err(adapter->netdev,
+ "queue %d params: unit_addr=0x%x buffer_list_dma=0x%llx rxq_desc=0x%llx\n",
+ queue_index, adapter->vdev->unit_address,
+ (unsigned long long)adapter->buffer_list_dma[queue_index],
+ (unsigned long long)rxq_desc.desc);
+
+ return lpar_rc;
+}
+
+/**
+ * ibmveth_register_single_rx_queue - Register one subordinate RX queue
+ * @adapter: ibmveth adapter structure
+ * @queue_idx: Queue index to register (1..N)
+ * @mac_address: MAC address (unused; reserved for API symmetry)
+ *
+ * Builds the queue descriptor and registers with the hypervisor via
+ * ibmveth_register_logical_lan_queue().
+ *
+ * Return: 0 on success, -EINVAL if @queue_idx is invalid, -EIO on failure
+ */
+static int
+ibmveth_register_single_rx_queue(struct ibmveth_adapter *adapter,
+ int queue_idx, u64 mac_address)
+{
+ struct net_device *netdev = adapter->netdev;
+ union ibmveth_buf_desc rxq_desc;
+ long lpar_rc;
+
+ (void)mac_address;
+
+ if (WARN_ON(queue_idx < 1 || queue_idx >= IBMVETH_MAX_RX_QUEUES))
+ return -EINVAL;
+
+ rxq_desc.fields.flags_len = IBMVETH_BUF_VALID |
+ adapter->rx_queue[queue_idx].queue_len;
+ rxq_desc.fields.address = adapter->rx_queue[queue_idx].queue_dma;
+
+ lpar_rc = ibmveth_register_logical_lan_queue(adapter, rxq_desc,
+ queue_idx);
+ if (lpar_rc != H_SUCCESS) {
+ netdev_err(netdev, "Failed to register queue %d: rc=0x%lx\n",
+ queue_idx, lpar_rc);
+ return -EIO;
+ }
+
+ netdev_dbg(netdev, "Registered queue %d with handle 0x%llx\n",
+ queue_idx, adapter->queue_handle[queue_idx]);
+
+ return 0;
+}
+
+/**
+ * ibmveth_deregister_single_rx_queue - Deregister one subordinate RX queue
+ * @adapter: ibmveth adapter structure
+ * @queue_idx: Queue index to deregister (1..N)
+ *
+ * Deregisters a single queue via H_FREE_LOGICAL_LAN_QUEUE and disposes
+ * the IRQ mapping for subordinate queues. Queue 0 is freed only through
+ * ibmveth_free_all_queues() (H_FREE_LOGICAL_LAN).
+ */
+static void __maybe_unused
+ibmveth_deregister_single_rx_queue(struct ibmveth_adapter *adapter,
+ int queue_idx)
+{
+ unsigned long lpar_rc;
+
+ if (!adapter->queue_handle[queue_idx])
+ return;
+
+ do {
+ lpar_rc = h_free_logical_lan_queue(adapter->vdev->unit_address,
+ adapter->queue_handle[queue_idx]);
+ } while (H_IS_LONG_BUSY(lpar_rc) || (lpar_rc == H_BUSY));
+
+ adapter->hcall_stats.free_lan_queue++;
+
+ if (lpar_rc != H_SUCCESS) {
+ netdev_err(adapter->netdev,
+ "h_free_logical_lan_queue failed for queue %d: rc=0x%lx\n",
+ queue_idx, lpar_rc);
+ }
+
+ adapter->queue_handle[queue_idx] = 0;
+
+ if (queue_idx > 0 && adapter->queue_irq[queue_idx]) {
+ irq_dispose_mapping(adapter->queue_irq[queue_idx]);
+ adapter->queue_irq[queue_idx] = 0;
+ }
+
+ netdev_dbg(adapter->netdev, "Deregistered queue %d\n", queue_idx);
+}
+
+/**
+ * ibmveth_free_all_queues - Free all RX queues at once
+ * @adapter: ibmveth adapter structure
+ *
+ * Uses H_FREE_LOGICAL_LAN to free all queues in one hypercall.
+ * Used during interface close and registration error cleanup.
+ *
+ * Clears queue handles only; queue_irq[] is released by
+ * ibmveth_cleanup_rx_interrupts() on close, or by
+ * ibmveth_dispose_subordinate_irq_mappings() on partial register failure.
+ */
+static void ibmveth_free_all_queues(struct ibmveth_adapter *adapter)
+{
+ unsigned long lpar_rc;
+ int i;
+
+ netdev_dbg(adapter->netdev, "freeing all RX queues at once\n");
+
+ do {
+ lpar_rc = h_free_logical_lan(adapter->vdev->unit_address);
+ adapter->hcall_stats.free_lan++;
+ } while (H_IS_LONG_BUSY(lpar_rc) || (lpar_rc == H_BUSY));
+
+ if (lpar_rc != H_SUCCESS) {
+ netdev_err(adapter->netdev,
+ "h_free_logical_lan failed: %ld\n", lpar_rc);
+ }
+
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ adapter->queue_handle[i] = 0;
+}
+
+/**
+ * ibmveth_register_rx_queues - Register RX queues with hypervisor
+ * @adapter: ibmveth adapter structure
+ * @mac_address: MAC address for device registration
+ *
+ * Registers queue 0 via ibmveth_register_logical_lan(), then subordinate
+ * queues 1..N when multi-queue mode is enabled.
+ *
+ * Return: 0 on success, -ENONET if queue 0 registration fails, -EIO on
+ * subordinate queue registration failure
+ */
+static int
+ibmveth_register_rx_queues(struct ibmveth_adapter *adapter, u64 mac_address)
+{
+ struct net_device *netdev = adapter->netdev;
+ union ibmveth_buf_desc rxq_desc;
+ unsigned long lpar_rc;
+ int i, rc;
+
+ rxq_desc.fields.flags_len = IBMVETH_BUF_VALID |
+ adapter->rx_queue[0].queue_len;
+ rxq_desc.fields.address = adapter->rx_queue[0].queue_dma;
+ adapter->queue_irq[0] = netdev->irq;
+
+ rc = ibmveth_disable_irq(adapter, 0);
+ if (rc != H_SUCCESS)
+ netdev_dbg(netdev,
+ "Failed to disable IRQ for queue 0 before registration, rc=%d\n",
+ rc);
+
+ lpar_rc = ibmveth_register_logical_lan(adapter, rxq_desc, mac_address);
+ if (lpar_rc != H_SUCCESS) {
+ netdev_err(netdev, "h_register_logical_lan failed: %ld\n", lpar_rc);
+ netdev_err(netdev,
+ "buffer TCE:0x%llx filter TCE:0x%llx rxq desc:0x%llx MAC:0x%llx\n",
+ adapter->buffer_list_dma[0],
+ adapter->filter_list_dma,
+ rxq_desc.desc, mac_address);
+ return -ENONET;
+ }
+
+ if (adapter->num_rx_queues == 1 || !adapter->multi_queue) {
+ netdev_dbg(netdev,
+ "registered 1 RX queue with hypervisor (single-queue mode)\n");
+ return 0;
+ }
+
+ netdev_dbg(netdev, "Registering %d subordinate queues (1-%d)\n",
+ adapter->num_rx_queues - 1, adapter->num_rx_queues - 1);
+
+ for (i = 1; i < adapter->num_rx_queues; i++) {
+ rc = ibmveth_register_single_rx_queue(adapter, i, mac_address);
+ if (rc) {
+ if (!adapter->queue_handle[i] || !adapter->queue_irq[i]) {
+ netdev_err(netdev,
+ "Invalid hypervisor return for queue %d: handle=0x%llx irq=%u\n",
+ i, adapter->queue_handle[i],
+ adapter->queue_irq[i]);
+ }
+ goto err_unregister;
+ }
+ }
+
+ netdev_dbg(netdev,
+ "registered %d RX queues with hypervisor (multi-queue mode)\n",
+ adapter->num_rx_queues);
+
+ return 0;
+
+err_unregister:
+ ibmveth_dispose_subordinate_irq_mappings(adapter);
+ ibmveth_free_all_queues(adapter);
+ return rc;
+}
+
static int ibmveth_open(struct net_device *netdev)
{
struct ibmveth_adapter *adapter = netdev_priv(netdev);
--
2.39.3 (Apple Git-146)
next prev parent reply other threads:[~2026-07-06 19:36 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-06 19:35 [PATCH net-next v3 00/15] ibmveth: Add multi-queue RX support Mingming Cao
2026-07-06 19:35 ` [PATCH net-next v3 01/15] ibmveth: Add MQ RX hypercall wrappers and call definitions Mingming Cao
2026-07-06 19:35 ` [PATCH net-next v3 02/15] ibmveth: Prepare MQ RX adapter and statistics structures Mingming Cao
2026-07-06 19:35 ` [PATCH net-next v3 03/15] ibmveth: Refactor RX resource allocation for MQ RX bring-up Mingming Cao
2026-07-06 19:35 ` [PATCH net-next v3 04/15] ibmveth: Refactor buffer pool management for per-queue MQ RX Mingming Cao
2026-07-06 19:35 ` [PATCH net-next v3 05/15] ibmveth: Refactor RX interrupt control for MQ RX queues Mingming Cao
2026-07-06 19:35 ` [PATCH net-next v3 06/15] ibmveth: Refactor TX resource allocation in open/close paths Mingming Cao
2026-07-06 19:35 ` Mingming Cao [this message]
2026-07-06 19:35 ` [PATCH net-next v3 08/15] ibmveth: Refactor open/close into MQ-ready resource pipeline Mingming Cao
2026-07-06 19:35 ` [PATCH net-next v3 09/15] ibmveth: Add queue-aware RX buffer submit helper for MQ Mingming Cao
2026-07-06 19:35 ` [PATCH net-next v3 10/15] ibmveth: Enable multi-queue RX receive path Mingming Cao
2026-07-06 19:35 ` [PATCH net-next v3 11/15] ibmveth: Add per-queue RX and TX statistics collection and reporting Mingming Cao
2026-07-06 19:36 ` [PATCH net-next v3 12/15] ibmveth: Expose per-queue buffer pool details via sysfs Mingming Cao
2026-07-06 19:36 ` [PATCH net-next v3 13/15] ibmveth: Implement incremental MQ RX queue resize Mingming Cao
2026-07-06 19:36 ` [PATCH net-next v3 14/15] ibmveth: Wire ethtool set_channels to " Mingming Cao
2026-07-06 19:36 ` [PATCH net-next v3 15/15] ibmveth: Fix MQ RX poll and shutdown hangs after " Mingming Cao
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260706193603.8039-8-mmc@linux.ibm.com \
--to=mmc@linux.ibm.com \
--cc=bjking1@linux.ibm.com \
--cc=davemarq@linux.ibm.com \
--cc=edumazet@google.com \
--cc=haren@linux.ibm.com \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=maddy@linux.ibm.com \
--cc=mpe@ellerman.id.au \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=ricklind@linux.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.