From: netdev-bot+sashiko@kernel.org
To: illusion.wang@nebula-matrix.com
Cc: dimon.zhao@nebula-matrix.com, alvin.wang@nebula-matrix.com,
sam.chen@nebula-matrix.com, netdev@vger.kernel.org,
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
Subject: Re: [PATCH v27 net-next 05/10] net/nebula-matrix: add intr resource implementation
Date: Fri, 11 Sep 2026 03:41:49 +0000 [thread overview]
Message-ID: <178909810904.219967.6857628941684553135@kernel.org> (raw)
In-Reply-To: <20260907123848.30256-6-illusion.wang@nebula-matrix.com>
Thank you for your contribution! Sashiko AI review found 4 potential
issue(s) to consider:
Critical: 0 · High: 0 · Medium: 1 · Low: 3
- [Medium] Coherent MSI-X map table is released based on a timed guess,
not on proven device quiescence.
- [Low] Two in-tree comments state mutually exclusive ownership models
for the coherent MSI-X tables.
- [Low] The 'Step 1' comment in __nbl_res_intr_destroy_msix_map() says
'mask each MSIX vector in hardware first', but the call it annotates…
- [Low] Reported concern: nbl_intr_mgt_stop() publishes the 'dead' state
with a plain store 'res_mgt->intr_mgt = NULL' outside intr_mgt->lock,…
--
net/nebula-matrix: add intr resource implementation
This adds the nbl_interrupt module which owns the driver-wide global MSI-X
index space and programs the chip-internal MSI-X map/info registers. It
adds cfg_msix_map, destroy_msix_map, set_mailbox_irq and cfg_msix_info,
plus nbl_intr_mgt_start()/nbl_intr_mgt_stop() wired into the leonis
resource layer.
A few questions about the teardown path and about some of the comments
below.
> diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c
> index b4aba4faa555a..4c2e577610230 100644
> --- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c
> +++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_hw_leonis.c
[ ... ]
> @@ -91,6 +115,124 @@ static void nbl_hw_get_fw_eth_map(struct nbl_hw_mgt *hw_mgt, u32 *eth_map)
[ ... ]
> +static void nbl_hw_cfg_msix_info(struct nbl_hw_mgt *hw_mgt, u16 func_id,
> + bool valid, u16 interrupt_id, u8 bus,
> + u8 devid, u8 function, bool msix_mask_en)
> +{
> + u32 host_msix_fid = 0;
> + struct nbl_host_msix_info msix_info;
> +
> + memset(&msix_info, 0, sizeof(msix_info));
> + if (valid) {
> + host_msix_fid =
> + FIELD_PREP(NBL_PCOMPLETER_HOST_MSIX_FID_TABLE_FID_MASK,
> + func_id) |
> + FIELD_PREP(NBL_PCOMPLETER_HOST_MSIX_FID_TABLE_VLD_MASK,
> + 1);
> +
> + msix_info.data[1] =
> + FIELD_PREP(NBL_HOST_MSIX_INFO_FUNCTION_MASK, function) |
> + FIELD_PREP(NBL_HOST_MSIX_INFO_DEVID_MASK, devid) |
> + FIELD_PREP(NBL_HOST_MSIX_INFO_BUS_MASK, bus) |
> + FIELD_PREP(NBL_HOST_MSIX_INFO_VALID_MASK, 1);
> +
> + if (msix_mask_en)
> + msix_info.data[1] |=
> + FIELD_PREP(NBL_HOST_MSIX_INFO_MSIX_MASK_EN_MASK, 1);
> + }
[ ... ]
> diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.c
> index 46180522295a3..c1f10f1f6b775 100644
> --- a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.c
> +++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_hw_leonis/nbl_resource_leonis.c
[ ... ]
> @@ -328,8 +337,24 @@ int nbl_res_init_leonis(struct nbl_adapter *adap)
>
> void nbl_res_remove_leonis(struct nbl_adapter *adap)
> {
> + struct nbl_resource_mgt *res_mgt = adap->core.res_mgt;
> + struct nbl_common_info *common = &adap->common;
> +
> + if (!res_mgt)
> + return;
> +
> + /*
> + * Tear down all MSI-X maps before devres releases the coherent
> + * tables. This is critical on the control PF, which may hold
> + * maps for remote PFs that are still bound.
> + */
> + if (common->has_ctrl && res_mgt->intr_mgt)
> + nbl_intr_mgt_stop(res_mgt);
> +
> /*
> - * No resource release here because all memory uses devm managed
> - * allocation
> + * Note: the per-function interrupts arrays (kcalloc) are freed
> + * by nbl_intr_mgt_stop() above. The coherent MSI-X tables
> + * (dmam_alloc_coherent) and intr_mgt itself (devm_kzalloc) are
> + * released by devres after this function returns.
> */
> }
[Severity: Low]
Is this comment still accurate?
nbl_intr_mgt_stop() loops over every function id and calls
__nbl_res_intr_destroy_msix_map(), which itself calls dmam_free_coherent()
on msix_map_table->base_addr and then sets it to NULL. So by the time
nbl_res_remove_leonis() returns, there should be no devres-managed
coherent MSI-X table left for devres to release.
The kernel-doc on nbl_res_intr_cfg_msix_map() states the opposite
ownership model:
* Old MSIX table memory is explicitly freed inside the locked
* destroy path after a bounded DMA quiesce sleep (best-effort;
* hardware provides no idle status register), so repeated
* reconfiguration does not accumulate devres-managed DMA memory.
The commit message carries the same wording as the comment here, "It is
called from nbl_res_remove_leonis() before devres releases the coherent
tables."
Could these be reconciled so a later change does not drop the explicit
dmam_free_coherent() on the assumption devres still owns the tables?
> diff --git a/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_interrupt.c b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_interrupt.c
> new file mode 100644
> index 0000000000000..fd3b71a05c236
> --- /dev/null
> +++ b/drivers/net/ethernet/nebula-matrix/nbl/nbl_hw/nbl_interrupt.c
> @@ -0,0 +1,544 @@
[ ... ]
> + /* Step 0: disable mailbox IRQ routing before tearing down map */
> + __nbl_res_intr_set_mailbox_irq(res_mgt, func_id, 0, false);
> +
> + /* Step 1: mask each MSIX vector in hardware first */
> + for (i = 0; i < intr_num; i++) {
> + hw_ops->cfg_msix_info(res_mgt->hw_ops_tbl->priv,
> + func_id, false, interrupts[i],
> + 0, 0, 0, false);
> + }
> + hw_ops->flush_write(res_mgt->hw_ops_tbl->priv);
[Severity: Low]
Does this loop actually mask anything?
The call passes valid=false and msix_mask_en=false, and
nbl_hw_cfg_msix_info() starts with:
memset(&msix_info, 0, sizeof(msix_info));
if (valid) {
...
}
so for valid=false both host_msix_fid and msix_info.data[] stay zero and
the writes to NBL_PCOMPLETER_HOST_MSIX_FID_TABLE() and
NBL_PADPT_HOST_MSIX_INFO_REG_ARR() drive
NBL_HOST_MSIX_INFO_MSIX_MASK_EN_MASK (BIT(17)) and
NBL_HOST_MSIX_INFO_VALID_MASK (BIT(16)) to 0 and clear the FID VLD bit.
That invalidates the entry and turns mask-enable off rather than masking
the vector. Would "invalidate each MSIX info entry" describe the step
more accurately? The commit message has the same wording, "Step 1 masks
each vector."
> + /*
> + * Stage 1 tear down: retain valid DMA address, ONLY clear
> + * VALID bit to avoid hardware torn read (VALID=1 & dma_addr=0).
> + */
> + hw_ops->cfg_msix_map(res_mgt->hw_ops_tbl->priv, func_id,
> + false, msix_map_table->dma, 0, 0, 0);
> + hw_ops->flush_write(res_mgt->hw_ops_tbl->priv);
> +
> + /*
> + * Hardware provides no idle status register for the MSIX map
> + * DMA engine. Use a bounded sleep to mitigate the race between
> + * posted MMIO disable writes and an ongoing in-flight table
> + * read DMA.
> + *
> + * This is best-effort, not a guarantee: a table fetch already
> + * issued before the VALID clear was observed can complete after
> + * this sleep. On the normal teardown path the mailbox channel
> + * is stopped before this function runs, so no new interrupts
> + * can trigger table fetches. On the residual cleanup path in
> + * nbl_intr_mgt_stop(), a longer global quiesce is applied
> + * after all functions are torn down.
> + */
> + usleep_range(NBL_MSIX_DMA_SYNC_MIN_US, NBL_MSIX_DMA_SYNC_MAX_US);
> +
> + /* safe to release global vector IDs, pcompler no longer reads table */
> + nbl_intr_release_bitmap(res_mgt, interrupts, intr_num);
> +
> + /*
> + * Stage 2: hardware has quiesced MSIX table DMA access, fully
> + * zero the MSIX map entry safely now.
> + */
> + hw_ops->cfg_msix_map(res_mgt->hw_ops_tbl->priv, func_id,
> + false, 0, 0, 0, 0);
> + hw_ops->flush_write(res_mgt->hw_ops_tbl->priv);
> +
> + /*
> + * Now safe to release the MSIX DMA coherent memory. Hardware
> + * DMA has quiesced after the sleep above, so no IOMMU fault
> + * risk remains.
> + */
> + if (msix_map_table->base_addr) {
> + dmam_free_coherent(dev, msix_map_table->size,
> + msix_map_table->base_addr,
> + msix_map_table->dma);
> + msix_map_table->base_addr = NULL;
> + msix_map_table->dma = 0;
> + msix_map_table->size = 0;
> + }
[Severity: Medium]
Can the coherent table be freed here while the pcompleter still has a
table fetch outstanding?
The two comments in __nbl_res_intr_destroy_msix_map() disagree with each
other. The first says:
* This is best-effort, not a guarantee: a table fetch already
* issued before the VALID clear was observed can complete after
* this sleep.
and a few lines later:
* Hardware DMA has quiesced after the sleep above, so no IOMMU
* fault risk remains.
followed by dmam_free_coherent() on the buffer the device DMA-reads.
If a fetch does land after the free, with an IOMMU the read hits an
unmapped IOVA and produces a DMAR/SMMU fault; without one it reads
recycled memory whose bytes are interpreted as an MSI-X map entry
(NBL_MSIX_MAP_VALID_MASK plus the 13-bit NBL_MSIX_MAP_INDEX_MASK), which
could steer an interrupt to a global vector now owned by a different
function.
The table size does not depend on the request:
tmp_msix_tbl->size =
sizeof(struct nbl_msix_map) * NBL_MSIX_MAP_TABLE_MAX_ENTRIES;
Since the allocation is a fixed 2 KiB regardless of num_net_msix /
num_others_msix, would it be simpler to allocate the table once per
function and rewrite the entries in place, so the free/realloc cycle, the
timed sleeps and the admitted race all go away?
The commit message describes the same mechanism, "sleeps 1 ms to allow
in-flight table fetch DMA to quiesce (best-effort; no idle status register
exists), then zeroes the entry before freeing memory."
[ ... ]
> +void nbl_intr_mgt_stop(struct nbl_resource_mgt *res_mgt)
> +{
> + struct nbl_interrupt_mgt *intr_mgt = res_mgt->intr_mgt;
> + u16 func_id;
> + int ret;
> +
> + if (!intr_mgt)
> + return;
> +
> + mutex_lock(&intr_mgt->lock);
> + for (func_id = 0; func_id < NBL_MAX_FUNC; func_id++) {
> + if (intr_mgt->func_intr_res[func_id].interrupts) {
> + dev_info(res_mgt->common->dev,
> + "intr_mgt_stop: destroying leftover map for func %u\n",
> + func_id);
> + ret = __nbl_res_intr_destroy_msix_map(res_mgt,
> + func_id);
> + if (ret)
> + dev_warn(res_mgt->common->dev,
> + "intr_mgt_stop: destroy map for func %u failed: %d\n",
> + func_id, ret);
> + }
> + }
> + mutex_unlock(&intr_mgt->lock);
> +
> + /*
> + * Global quiesce after all functions are torn down. Each
> + * destroy has an internal 1ms sleep between Stage 1 (clear
> + * VALID) and Stage 2 (zero dma_addr), but Stage 2 itself has
> + * no trailing sleep. This final wait covers the last
> + * function's Stage 2 and any straggler DMA from
> + * concurrently-torndown functions.
> + */
> + usleep_range(NBL_MSIX_DMA_SYNC_MIN_US, NBL_MSIX_DMA_SYNC_MAX_US);
[Severity: Medium]
Does this final usleep_range() still cover anything?
The loop above has already called __nbl_res_intr_destroy_msix_map() for
every func_id, and each of those calls ends with dmam_free_coherent() on
that function's table. By the time this sleep runs there is no coherent
table left that a straggler DMA could safely land in, so the wait appears
to be after the window the comment says it protects.
Should this wait happen before the per-function dmam_free_coherent()
instead, or is it simply not needed?
[ ... ]
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260907123848.30256-1-illusion.wang%40nebula-matrix.com
next prev parent reply other threads:[~2026-09-11 3:41 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-07 12:38 [PATCH v27 net-next 00/10] nbl driver for Nebulamatrix NICs illusion.wang
2026-09-07 12:38 ` [PATCH v27 net-next 01/10] net/nebula-matrix: add minimum nbl build framework illusion.wang
2026-09-11 3:41 ` netdev-bot+sashiko
2026-09-07 12:38 ` [PATCH v27 net-next 02/10] net/nebula-matrix: add core driver architecture and HW layer initialization illusion.wang
2026-09-11 3:41 ` netdev-bot+sashiko
2026-09-07 12:38 ` [PATCH v27 net-next 03/10] net/nebula-matrix: add channel layer illusion.wang
2026-09-11 3:41 ` netdev-bot+sashiko
2026-09-07 12:38 ` [PATCH v27 net-next 04/10] net/nebula-matrix: add common resource implementation illusion.wang
2026-09-11 3:41 ` netdev-bot+sashiko
2026-09-07 12:38 ` [PATCH v27 net-next 05/10] net/nebula-matrix: add intr " illusion.wang
2026-09-11 3:41 ` netdev-bot+sashiko [this message]
2026-09-07 12:38 ` [PATCH v27 net-next 06/10] net/nebula-matrix: add chip-wide hardware init/deinit implementation illusion.wang
2026-09-11 3:41 ` netdev-bot+sashiko
2026-09-07 12:38 ` [PATCH v27 net-next 07/10] net/nebula-matrix: dispatch: add control-level routing core infrastructure illusion.wang
2026-09-07 12:38 ` [PATCH v27 net-next 08/10] net/nebula-matrix: dispatch: implement channel RPC framework and serialize hardware ops illusion.wang
2026-09-11 3:41 ` netdev-bot+sashiko
2026-09-07 12:38 ` [PATCH v27 net-next 09/10] net/nebula-matrix: add common/ctrl dev init/remove operation illusion.wang
2026-09-11 3:41 ` netdev-bot+sashiko
2026-09-07 12:38 ` [PATCH v27 net-next 10/10] net/nebula-matrix: add common dev start/stop operation illusion.wang
2026-09-11 3:41 ` netdev-bot+sashiko
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=178909810904.219967.6857628941684553135@kernel.org \
--to=netdev-bot+sashiko@kernel.org \
--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=illusion.wang@nebula-matrix.com \
--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 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.