From: "illusion.wang" <illusion.wang@nebula-matrix.com>
To: dimon.zhao@nebula-matrix.com, illusion.wang@nebula-matrix.com,
alvin.wang@nebula-matrix.com, sam.chen@nebula-matrix.com,
netdev@vger.kernel.org
Cc: andrew+netdev@lunn.ch, corbet@lwn.net, kuba@kernel.org,
horms@kernel.org, linux-doc@vger.kernel.org, pabeni@redhat.com,
vadim.fedorenko@linux.dev, lukas.bulwahn@redhat.com,
edumazet@google.com, enelsonmoore@gmail.com,
skhan@linuxfoundation.org, hkallweit1@gmail.com,
linux-kernel@vger.kernel.org (open list)
Subject: [PATCH v19 net-next 11/11] net/nebula-matrix: add common dev start/stop operation
Date: Wed, 17 Jun 2026 12:46:56 +0800 [thread overview]
Message-ID: <20260617044702.2439-12-illusion.wang@nebula-matrix.com> (raw)
In-Reply-To: <20260617044702.2439-1-illusion.wang@nebula-matrix.com>
This patch wires up nbl_dev_start() and nbl_dev_stop() to configure
the MSI-X map, allocate vectors, and request/enable the mailbox IRQ.
It also replaces module_pci_driver() with explicit init/exit functions
that additionally create and destroy the driver's workqueue via
nbl_common_create_wq() / nbl_common_destroy_wq(), which is needed
because the new IRQ handler schedules work through
nbl_common_queue_work().
Signed-off-by: illusion.wang <illusion.wang@nebula-matrix.com>
---
.../nebula-matrix/nbl/nbl_common/nbl_common.c | 24 ++
.../nebula-matrix/nbl/nbl_core/nbl_dev.c | 250 +++++++++++++++++-
.../nebula-matrix/nbl/nbl_hw/nbl_resource.c | 2 +-
.../nbl/nbl_include/nbl_def_common.h | 6 +
4 files changed, 280 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_common/nbl_common.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_common/nbl_common.c
index 2954cbbe0f95..bae1a7e401ce 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_common/nbl_common.c
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_common/nbl_common.c
@@ -6,6 +6,30 @@
#include <linux/device.h>
#include "nbl_common.h"
+void nbl_common_queue_work(struct nbl_common_info *common,
+ struct work_struct *task)
+{
+ queue_work(common->wq, task);
+}
+
+void nbl_common_destroy_wq(struct nbl_common_info *common)
+{
+ destroy_workqueue(common->wq);
+}
+
+int nbl_common_create_wq(struct nbl_common_info *common)
+{
+ common->wq = alloc_workqueue("nbl_wq", WQ_UNBOUND, 0);
+ if (!common->wq) {
+ pr_err("Failed to create workqueue nbl_wq\n");
+ goto alloc_wq_failed;
+ }
+
+ return 0;
+alloc_wq_failed:
+ return -ENOMEM;
+}
+
u32 nbl_common_pf_id_subtraction_mgtpf_id(struct nbl_common_info *common,
u32 pf_id)
{
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.c
index 8feae561d0f1..288b2dae8681 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.c
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_core/nbl_dev.c
@@ -6,6 +6,17 @@
#include <linux/pci.h>
#include "nbl_dev.h"
+static void nbl_dev_clean_mailbox_schedule(struct nbl_dev_mgt *dev_mgt);
+
+/* ---------- Interrupt config ---------- */
+static irqreturn_t nbl_dev_clean_mailbox(int __always_unused irq, void *data)
+{
+ struct nbl_dev_mgt *dev_mgt = (struct nbl_dev_mgt *)data;
+
+ nbl_dev_clean_mailbox_schedule(dev_mgt);
+ return IRQ_HANDLED;
+}
+
static void nbl_dev_init_msix_cnt(struct nbl_dev_mgt *dev_mgt)
{
struct nbl_dev_common *dev_common = dev_mgt->common_dev;
@@ -14,6 +25,182 @@ static void nbl_dev_init_msix_cnt(struct nbl_dev_mgt *dev_mgt)
msix_info->serv_info[NBL_MSIX_MAILBOX_TYPE].num = 1;
}
+static int nbl_dev_request_mailbox_irq(struct nbl_dev_mgt *dev_mgt)
+{
+ struct nbl_dev_common *dev_common = dev_mgt->common_dev;
+ struct nbl_msix_info *msix_info = &dev_common->msix_info;
+ struct nbl_common_info *common = dev_mgt->common;
+ u16 local_vec_id;
+ int irq_num;
+ int err;
+
+ if (!msix_info->serv_info[NBL_MSIX_MAILBOX_TYPE].num)
+ return 0;
+
+ local_vec_id =
+ msix_info->serv_info[NBL_MSIX_MAILBOX_TYPE].base_vector_id;
+ irq_num = pci_irq_vector(common->pdev, local_vec_id);
+ if (irq_num < 0) {
+ dev_err(common->dev, "Failed to get mailbox IRQ vector: %d\n",
+ irq_num);
+ return irq_num;
+ }
+
+ snprintf(dev_common->mailbox_name, sizeof(dev_common->mailbox_name),
+ "nbl_mailbox@pci:%s", pci_name(common->pdev));
+ err = request_irq(irq_num, nbl_dev_clean_mailbox, 0,
+ dev_common->mailbox_name, dev_mgt);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static void nbl_dev_free_mailbox_irq(struct nbl_dev_mgt *dev_mgt)
+{
+ struct nbl_dev_common *dev_common = dev_mgt->common_dev;
+ struct nbl_msix_info *msix_info = &dev_common->msix_info;
+ struct nbl_common_info *common = dev_mgt->common;
+ u16 local_vec_id;
+ int irq_num;
+
+ if (!msix_info->serv_info[NBL_MSIX_MAILBOX_TYPE].num)
+ return;
+
+ local_vec_id =
+ msix_info->serv_info[NBL_MSIX_MAILBOX_TYPE].base_vector_id;
+ irq_num = pci_irq_vector(common->pdev, local_vec_id);
+ if (irq_num >= 0)
+ free_irq(irq_num, dev_mgt);
+}
+
+static int nbl_dev_enable_mailbox_irq(struct nbl_dev_mgt *dev_mgt)
+{
+ struct nbl_dispatch_ops *disp_ops = dev_mgt->disp_ops_tbl->ops;
+ struct nbl_channel_ops *chan_ops = dev_mgt->chan_ops_tbl->ops;
+ struct nbl_dev_common *dev_common = dev_mgt->common_dev;
+ struct nbl_msix_info *msix_info = &dev_common->msix_info;
+ u16 local_vec_id;
+
+ if (!msix_info->serv_info[NBL_MSIX_MAILBOX_TYPE].num)
+ return 0;
+
+ local_vec_id =
+ msix_info->serv_info[NBL_MSIX_MAILBOX_TYPE].base_vector_id;
+ chan_ops->set_queue_state(dev_mgt->chan_ops_tbl->priv,
+ NBL_CHAN_INTERRUPT_READY,
+ NBL_CHAN_TYPE_MAILBOX, true);
+
+ return disp_ops->set_mailbox_irq(dev_mgt->disp_ops_tbl->priv,
+ local_vec_id, true);
+}
+
+static int nbl_dev_disable_mailbox_irq(struct nbl_dev_mgt *dev_mgt)
+{
+ struct nbl_dispatch_ops *disp_ops = dev_mgt->disp_ops_tbl->ops;
+ struct nbl_channel_ops *chan_ops = dev_mgt->chan_ops_tbl->ops;
+ struct nbl_dev_common *dev_common = dev_mgt->common_dev;
+ struct nbl_msix_info *msix_info = &dev_common->msix_info;
+ u16 local_vec_id;
+
+ if (!msix_info->serv_info[NBL_MSIX_MAILBOX_TYPE].num)
+ return 0;
+
+ local_vec_id =
+ msix_info->serv_info[NBL_MSIX_MAILBOX_TYPE].base_vector_id;
+ /*
+ * Disable order: software state first, then hardware.
+ *
+ * Review suggested HW-then-state for symmetry with enable, but that
+ * causes "Channel waiting ack failed" errors. The reason: after
+ * set_mailbox_irq(..., false) disables the hardware, the device may
+ * still be sending ACKs for in-flight messages. If we then switch to
+ * polling mode (clear INTERRUPT_READY), the ACK handler won't process
+ * those pending ACKs, leading to "waiting ack failed" and "Skip ack
+ * with invalid status" errors.
+ *
+ * The original state-then-HW order avoids this: we switch to polling
+ * first, so any late interrupts are silently ignored (no ACK expected),
+ * then we disable the hardware. The theoretical window where an
+ * interrupt could fire and be ignored is harmless here because this
+ * function is only called on the error path of nbl_dev_start(),
+ * immediately followed by nbl_dev_free_mailbox_irq() and
+ * cancel_work_sync(&clean_mbx_task). The channel is torn down right
+ * after, so no descriptors can be left stuck.
+ *
+ * Do NOT change to HW-then-state.
+ */
+ chan_ops->set_queue_state(dev_mgt->chan_ops_tbl->priv,
+ NBL_CHAN_INTERRUPT_READY,
+ NBL_CHAN_TYPE_MAILBOX, false);
+
+ return disp_ops->set_mailbox_irq(dev_mgt->disp_ops_tbl->priv,
+ local_vec_id, false);
+}
+
+static int nbl_dev_configure_msix_map(struct nbl_dev_mgt *dev_mgt)
+{
+ struct nbl_dispatch_ops *disp_ops = dev_mgt->disp_ops_tbl->ops;
+ struct nbl_dev_common *dev_common = dev_mgt->common_dev;
+ struct nbl_msix_info *msix_info = &dev_common->msix_info;
+ bool mask_en = msix_info->serv_info[NBL_MSIX_NET_TYPE].hw_self_mask_en;
+ u16 msix_net_num = msix_info->serv_info[NBL_MSIX_NET_TYPE].num;
+ u16 msix_not_net_num = 0;
+ int err, i;
+
+ msix_info->serv_info[NBL_MSIX_VIRTIO_TYPE].base_vector_id = 0;
+ for (i = NBL_MSIX_NET_TYPE; i < NBL_MSIX_TYPE_MAX; i++)
+ msix_info->serv_info[i].base_vector_id =
+ msix_info->serv_info[i - 1].base_vector_id +
+ msix_info->serv_info[i - 1].num;
+
+ for (i = NBL_MSIX_MAILBOX_TYPE; i < NBL_MSIX_TYPE_MAX; i++)
+ msix_not_net_num += msix_info->serv_info[i].num;
+
+ err = disp_ops->configure_msix_map(dev_mgt->disp_ops_tbl->priv,
+ msix_net_num, msix_not_net_num,
+ mask_en);
+
+ return err;
+}
+
+static int nbl_dev_destroy_msix_map(struct nbl_dev_mgt *dev_mgt)
+{
+ struct nbl_dispatch_ops *disp_ops = dev_mgt->disp_ops_tbl->ops;
+
+ return disp_ops->destroy_msix_map(dev_mgt->disp_ops_tbl->priv);
+}
+
+static int nbl_dev_init_interrupt_scheme(struct nbl_dev_mgt *dev_mgt)
+{
+ struct nbl_dev_common *dev_common = dev_mgt->common_dev;
+ struct nbl_msix_info *msix_info = &dev_common->msix_info;
+ struct nbl_common_info *common = dev_mgt->common;
+ int needed = 0;
+ int err;
+ int i;
+
+ for (i = 0; i < NBL_MSIX_TYPE_MAX; i++)
+ needed += msix_info->serv_info[i].num;
+
+ err = pci_alloc_irq_vectors(common->pdev, needed, needed,
+ PCI_IRQ_MSIX | PCI_IRQ_AFFINITY);
+ if (err < 0) {
+ dev_err(common->dev,
+ "pci_alloc_irq_vectors failed, err = %d\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static void nbl_dev_clear_interrupt_scheme(struct nbl_dev_mgt *dev_mgt)
+{
+ struct nbl_common_info *common = dev_mgt->common;
+
+ pci_free_irq_vectors(common->pdev);
+}
+
/* ---------- Channel config ---------- */
static void nbl_dev_setup_chan_qinfo(struct nbl_dev_mgt *dev_mgt, u8 chan_type)
{
@@ -72,6 +259,14 @@ static void nbl_dev_clean_mailbox_task(struct work_struct *work)
NBL_CHAN_TYPE_MAILBOX);
}
+static void nbl_dev_clean_mailbox_schedule(struct nbl_dev_mgt *dev_mgt)
+{
+ struct nbl_dev_common *common_dev = dev_mgt->common_dev;
+ struct nbl_common_info *common = dev_mgt->common;
+
+ nbl_common_queue_work(common, &common_dev->clean_mbx_task);
+}
+
/* ---------- Dev init process ---------- */
static int nbl_dev_setup_common_dev(struct nbl_adapter *adapter)
{
@@ -189,7 +384,7 @@ int nbl_dev_init(struct nbl_adapter *adapter)
dev_mgt->disp_ops_tbl = disp_ops_tbl;
dev_mgt->chan_ops_tbl = chan_ops_tbl;
adapter->core.dev_mgt = dev_mgt;
-
+ ret = nbl_common_create_wq(common);
ret = nbl_dev_setup_common_dev(adapter);
if (ret)
return ret;
@@ -213,14 +408,67 @@ void nbl_dev_remove(struct nbl_adapter *adapter)
if (common->has_ctrl)
nbl_dev_remove_ctrl_dev(adapter);
nbl_dev_remove_common_dev(adapter);
+ nbl_common_destroy_wq(common);
}
/* ---------- Dev start process ---------- */
int nbl_dev_start(struct nbl_adapter *adapter)
{
+ struct nbl_dev_mgt *dev_mgt = adapter->core.dev_mgt;
+ struct nbl_dev_common *common_dev = dev_mgt->common_dev;
+ int cleanup_ret;
+ int ret;
+
+ ret = nbl_dev_configure_msix_map(dev_mgt);
+ if (ret)
+ return ret;
+
+ ret = nbl_dev_init_interrupt_scheme(dev_mgt);
+ if (ret)
+ goto init_interrupt_scheme_err;
+ ret = nbl_dev_request_mailbox_irq(dev_mgt);
+ if (ret)
+ goto mailbox_request_irq_err;
+ ret = nbl_dev_enable_mailbox_irq(dev_mgt);
+ if (ret)
+ goto enable_mailbox_irq_err;
+
return 0;
+enable_mailbox_irq_err:
+ cleanup_ret = nbl_dev_disable_mailbox_irq(dev_mgt);
+ /* just log err*/
+ if (cleanup_ret)
+ dev_err(dev_mgt->common->dev,
+ "Failed to disable mailbox IRQ: %d\n", cleanup_ret);
+ nbl_dev_free_mailbox_irq(dev_mgt);
+ cancel_work_sync(&common_dev->clean_mbx_task);
+mailbox_request_irq_err:
+ nbl_dev_clear_interrupt_scheme(dev_mgt);
+init_interrupt_scheme_err:
+ cleanup_ret = nbl_dev_destroy_msix_map(dev_mgt);
+ /* just log err*/
+ if (cleanup_ret)
+ dev_err(dev_mgt->common->dev,
+ "Failed to destroy MSI-X map: %d\n", cleanup_ret);
+ return ret;
}
void nbl_dev_stop(struct nbl_adapter *adapter)
{
+ struct nbl_dev_mgt *dev_mgt = adapter->core.dev_mgt;
+ struct nbl_dev_common *common_dev = dev_mgt->common_dev;
+ int ret;
+
+ /* just log err*/
+ ret = nbl_dev_disable_mailbox_irq(dev_mgt);
+ if (ret)
+ dev_err(dev_mgt->common->dev,
+ "Failed to disable mailbox IRQ: %d\n", ret);
+ nbl_dev_free_mailbox_irq(dev_mgt);
+ cancel_work_sync(&common_dev->clean_mbx_task);
+ nbl_dev_clear_interrupt_scheme(dev_mgt);
+ ret = nbl_dev_destroy_msix_map(dev_mgt);
+ if (ret)
+ dev_err(dev_mgt->common->dev,
+ "Failed to destroy MSI-X map: %d\n", ret);
}
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_resource.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_resource.c
index 6742da7c6637..e8d43bef8687 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_resource.c
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_resource.c
@@ -112,7 +112,7 @@ int nbl_res_get_eth_id(struct nbl_resource_mgt *res_mgt, u16 func_id,
return -EINVAL;
}
if (abs_pf_id != pfid) {
- dev_err(dev, "invalid pf id %u\n", pfid);
+ dev_err(dev, "invalid pf id %u vsi %u\n", pfid, vsi_id);
return -EINVAL;
}
rel_pf_id = abs_pf_id - common->mgt_pf;
diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_common.h b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_common.h
index bc741b7df7b9..4621b3ce5856 100644
--- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_common.h
+++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_include/nbl_def_common.h
@@ -29,6 +29,7 @@ struct nbl_hash_tbl_mgt;
})
struct nbl_common_info {
+ struct workqueue_struct *wq;
struct pci_dev *pdev;
struct device *dev;
u32 msg_enable;
@@ -61,6 +62,11 @@ struct nbl_hash_tbl_del_key {
void (*action_func)(void *priv, void *key, void *data);
};
+void nbl_common_queue_work(struct nbl_common_info *common,
+ struct work_struct *task);
+
+void nbl_common_destroy_wq(struct nbl_common_info *common);
+int nbl_common_create_wq(struct nbl_common_info *common);
u32 nbl_common_pf_id_subtraction_mgtpf_id(struct nbl_common_info *common,
u32 pf_id);
--
2.47.3
prev parent reply other threads:[~2026-06-17 4:47 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-17 4:46 [PATCH v19 net-next 00/11] nbl driver for Nebulamatrix NICs illusion.wang
2026-06-17 4:46 ` [PATCH v19 net-next 01/11] net/nebula-matrix: add minimum nbl build framework illusion.wang
2026-06-17 4:46 ` [PATCH v19 net-next 02/11] net/nebula-matrix: add our driver architecture illusion.wang
2026-06-17 4:46 ` [PATCH v19 net-next 03/11] net/nebula-matrix: P4 configuration invoked during chip initialization illusion.wang
2026-06-17 4:46 ` [PATCH v19 net-next 04/11] net/nebula-matrix: channel msg value and msg struct illusion.wang
2026-06-17 4:46 ` [PATCH v19 net-next 05/11] net/nebula-matrix: add channel layer illusion.wang
2026-06-17 4:46 ` [PATCH v19 net-next 06/11] net/nebula-matrix: add common resource implementation illusion.wang
2026-06-17 4:46 ` [PATCH v19 net-next 07/11] net/nebula-matrix: add intr " illusion.wang
2026-06-17 4:46 ` [PATCH v19 net-next 08/11] net/nebula-matrix: add vsi " illusion.wang
2026-06-17 4:46 ` [PATCH v19 net-next 09/11] net/nebula-matrix: add Dispatch layer implementation illusion.wang
2026-06-17 4:46 ` [PATCH v19 net-next 10/11] net/nebula-matrix: add common/ctrl dev init/remove operation illusion.wang
2026-06-17 4:46 ` illusion.wang [this message]
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=20260617044702.2439-12-illusion.wang@nebula-matrix.com \
--to=illusion.wang@nebula-matrix.com \
--cc=alvin.wang@nebula-matrix.com \
--cc=andrew+netdev@lunn.ch \
--cc=corbet@lwn.net \
--cc=dimon.zhao@nebula-matrix.com \
--cc=edumazet@google.com \
--cc=enelsonmoore@gmail.com \
--cc=hkallweit1@gmail.com \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=lukas.bulwahn@redhat.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=sam.chen@nebula-matrix.com \
--cc=skhan@linuxfoundation.org \
--cc=vadim.fedorenko@linux.dev \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox