public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 net] net: enetc: fix VSI mailbox timeout handling and DMA lifecycle
@ 2026-04-29  8:19 Wei Fang
  2026-04-30 17:09 ` Simon Horman
  2026-05-01  1:20 ` patchwork-bot+netdevbpf
  0 siblings, 2 replies; 4+ messages in thread
From: Wei Fang @ 2026-04-29  8:19 UTC (permalink / raw)
  To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
	davem, edumazet, kuba, pabeni
  Cc: netdev, linux-kernel, imx

In the current VSI mailbox implementation, the VSI allocates a DMA buffer
to store the message sent to the PSI. When the PSI receives the message
request from the VSI, the hardware copies the message data from this DMA
buffer to PSI's DMA buffer for processing.

When enetc_msg_vsi_send() times out, two scenarios can occur:

1) Use-after-free: If the hardware hasn't completed message copying when
   the VSI frees the buffer, the hardware may subsequently copy the data
   from freed memory to PSI's DMA buffer.

2) Message race: If PSI hasn't processed the previous message when the
   next message is sent, the VSI may receive the previous message's
   reply, leading to incorrect handling.

To address these issues, implement the following changes:

- Check the mailbox busy status before sending a new message. If the
  mailbox is in busy state, it indicates the previous message is still
  being processed, so return an error immediately.

- Add the 'msg' field to struct enetc_si to preserve the DMA buffer
  information. The caller of enetc_msg_vsi_send() no longer frees the
  DMA buffer. Instead, defer freeing until it is safe to do so (when
  mailbox is not busy on next send).

- Add cleanup in enetc_vf_remove() to free the last message buffer.

This ensures the DMA buffer remains valid during message copying and
prevents message reply mismatches.

Fixes: beb74ac878c8 ("enetc: Add vf to pf messaging support")
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
v3:
1. Save si->msg after unregister_netdev() to avoid a race between the
local copy and a concurrent ndo callback.
v2:
1. Update commit message
2. Return -EIO instead of -EBUSY when VSIMSGSR_MB bit check fails
3. Move enetc_msg_dma_free() after enetc_pci_remove()
---
 drivers/net/ethernet/freescale/enetc/enetc.h  |  1 +
 .../net/ethernet/freescale/enetc/enetc_vf.c   | 42 +++++++++++++++----
 2 files changed, 35 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index e663bb5e614e..e691144e8756 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -330,6 +330,7 @@ struct enetc_si {
 	struct workqueue_struct *workqueue;
 	struct work_struct rx_mode_task;
 	struct dentry *debugfs_root;
+	struct enetc_msg_swbd msg; /* Only valid for VSI */
 };
 
 #define ENETC_SI_ALIGN	32
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_vf.c b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
index 6c4b374bcb0e..df8e95cc47d0 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_vf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
@@ -17,11 +17,36 @@ static void enetc_msg_vsi_write_msg(struct enetc_hw *hw,
 	enetc_wr(hw, ENETC_VSIMSGSNDAR0, val);
 }
 
+static void enetc_msg_dma_free(struct device *dev, struct enetc_msg_swbd *msg)
+{
+	if (msg->vaddr) {
+		dma_free_coherent(dev, msg->size, msg->vaddr, msg->dma);
+		msg->vaddr = NULL;
+	}
+}
+
 static int enetc_msg_vsi_send(struct enetc_si *si, struct enetc_msg_swbd *msg)
 {
+	struct device *dev = &si->pdev->dev;
 	int timeout = 100;
 	u32 vsimsgsr;
 
+	/* The VSI mailbox may be busy if last message was not yet processed
+	 * by PSI. So need to check the mailbox status before sending.
+	 */
+	vsimsgsr = enetc_rd(&si->hw, ENETC_VSIMSGSR);
+	if (vsimsgsr & ENETC_VSIMSGSR_MB) {
+		/* It is safe to free the DMA buffer here, the caller does
+		 * not access the DMA buffer if enetc_msg_vsi_send() fails.
+		 */
+		enetc_msg_dma_free(dev, msg);
+		dev_err(dev, "VSI mailbox is busy\n");
+		return -EIO;
+	}
+
+	/* Free the DMA buffer of the last message */
+	enetc_msg_dma_free(dev, &si->msg);
+	si->msg = *msg;
 	enetc_msg_vsi_write_msg(&si->hw, msg);
 
 	do {
@@ -32,12 +57,15 @@ static int enetc_msg_vsi_send(struct enetc_si *si, struct enetc_msg_swbd *msg)
 		usleep_range(1000, 2000);
 	} while (--timeout);
 
-	if (!timeout)
+	if (!timeout) {
+		dev_err(dev, "VSI mailbox timeout\n");
+
 		return -ETIMEDOUT;
+	}
 
 	/* check for message delivery error */
 	if (vsimsgsr & ENETC_VSIMSGSR_MS) {
-		dev_err(&si->pdev->dev, "VSI command execute error: %d\n",
+		dev_err(dev, "VSI command execute error: %d\n",
 			ENETC_SIMSGSR_GET_MC(vsimsgsr));
 		return -EIO;
 	}
@@ -50,7 +78,6 @@ static int enetc_msg_vsi_set_primary_mac_addr(struct enetc_ndev_priv *priv,
 {
 	struct enetc_msg_cmd_set_primary_mac *cmd;
 	struct enetc_msg_swbd msg;
-	int err;
 
 	msg.size = ALIGN(sizeof(struct enetc_msg_cmd_set_primary_mac), 64);
 	msg.vaddr = dma_alloc_coherent(priv->dev, msg.size, &msg.dma,
@@ -67,11 +94,7 @@ static int enetc_msg_vsi_set_primary_mac_addr(struct enetc_ndev_priv *priv,
 	memcpy(&cmd->mac, saddr, sizeof(struct sockaddr));
 
 	/* send the command and wait */
-	err = enetc_msg_vsi_send(priv->si, &msg);
-
-	dma_free_coherent(priv->dev, msg.size, msg.vaddr, msg.dma);
-
-	return err;
+	return enetc_msg_vsi_send(priv->si, &msg);
 }
 
 static int enetc_vf_set_mac_addr(struct net_device *ndev, void *addr)
@@ -259,6 +282,7 @@ static void enetc_vf_remove(struct pci_dev *pdev)
 {
 	struct enetc_si *si = pci_get_drvdata(pdev);
 	struct enetc_ndev_priv *priv;
+	struct enetc_msg_swbd msg;
 
 	priv = netdev_priv(si->ndev);
 	unregister_netdev(si->ndev);
@@ -270,7 +294,9 @@ static void enetc_vf_remove(struct pci_dev *pdev)
 
 	free_netdev(si->ndev);
 
+	msg = si->msg;
 	enetc_pci_remove(pdev);
+	enetc_msg_dma_free(&pdev->dev, &msg);
 }
 
 static const struct pci_device_id enetc_vf_id_table[] = {
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v3 net] net: enetc: fix VSI mailbox timeout handling and DMA lifecycle
  2026-04-29  8:19 [PATCH v3 net] net: enetc: fix VSI mailbox timeout handling and DMA lifecycle Wei Fang
@ 2026-04-30 17:09 ` Simon Horman
  2026-05-01  1:16   ` Wei Fang
  2026-05-01  1:20 ` patchwork-bot+netdevbpf
  1 sibling, 1 reply; 4+ messages in thread
From: Simon Horman @ 2026-04-30 17:09 UTC (permalink / raw)
  To: wei.fang
  Cc: 'Simon Horman', claudiu.manoil, vladimir.oltean,
	xiaoning.wang, andrew+netdev, davem, edumazet, kuba, pabeni,
	netdev, linux-kernel, imx

From: 'Simon Horman' <horms@kernel.org>

This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
Full review at: https://sashiko.dev
---
Subject: net: enetc: fix VSI mailbox timeout handling and DMA lifecycle

This commit attempts to fix a use-after-free issue in the VSI mailbox
send path by deferring the freeing of the DMA buffer if the hardware is
still processing the message. The DMA buffer information is stored in the
si structure and freed on the next send or when the driver is removed.

[ ... ]

> diff --git a/drivers/net/ethernet/freescale/enetc/enetc_vf.c b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
> --- a/drivers/net/ethernet/freescale/enetc/enetc_vf.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc_vf.c

[ ... ]

> @@ -259,6 +282,7 @@ static void enetc_vf_remove(struct pci_dev *pdev)
>  {
>  	struct enetc_si *si = pci_get_drvdata(pdev);
>  	struct enetc_ndev_priv *priv;
> +	struct enetc_msg_swbd msg;
>  
>  	priv = netdev_priv(si->ndev);
>  	unregister_netdev(si->ndev);
> @@ -270,7 +294,9 @@ static void enetc_vf_remove(struct pci_dev *pdev)
>  
>  	free_netdev(si->ndev);
>  
> +	msg = si->msg;
>  	enetc_pci_remove(pdev);
> +	enetc_msg_dma_free(&pdev->dev, &msg);

Is it possible for the mailbox to still be busy here?

The commit addresses the use-after-free in the send path by checking the
mailbox busy status before freeing the previous buffer. However, during
driver teardown, enetc_msg_dma_free() is called unconditionally.

If a prior message sent via enetc_msg_vsi_send() times out and the hardware
is still accessing the buffer, and then the driver is unbound, could this
cause the hardware to read from freed DMA memory?

Should the teardown path wait for the mailbox to become idle or ensure the
hardware is safely reset before freeing the buffer?

>  }

^ permalink raw reply	[flat|nested] 4+ messages in thread

* RE: [PATCH v3 net] net: enetc: fix VSI mailbox timeout handling and DMA lifecycle
  2026-04-30 17:09 ` Simon Horman
@ 2026-05-01  1:16   ` Wei Fang
  0 siblings, 0 replies; 4+ messages in thread
From: Wei Fang @ 2026-05-01  1:16 UTC (permalink / raw)
  To: Simon Horman
  Cc: Claudiu Manoil, Vladimir Oltean, Clark Wang,
	andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com,
	kuba@kernel.org, pabeni@redhat.com, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, imx@lists.linux.dev

> > @@ -259,6 +282,7 @@ static void enetc_vf_remove(struct pci_dev *pdev)
> > {
> >  	struct enetc_si *si = pci_get_drvdata(pdev);
> >  	struct enetc_ndev_priv *priv;
> > +	struct enetc_msg_swbd msg;
> >
> >  	priv = netdev_priv(si->ndev);
> >  	unregister_netdev(si->ndev);
> > @@ -270,7 +294,9 @@ static void enetc_vf_remove(struct pci_dev *pdev)
> >
> >  	free_netdev(si->ndev);
> >
> > +	msg = si->msg;
> >  	enetc_pci_remove(pdev);
> > +	enetc_msg_dma_free(&pdev->dev, &msg);
> 
> Is it possible for the mailbox to still be busy here?
> 
> The commit addresses the use-after-free in the send path by checking the
> mailbox busy status before freeing the previous buffer. However, during driver
> teardown, enetc_msg_dma_free() is called unconditionally.
> 
> If a prior message sent via enetc_msg_vsi_send() times out and the hardware is
> still accessing the buffer, and then the driver is unbound, could this cause the
> hardware to read from freed DMA memory?
> 
> Should the teardown path wait for the mailbox to become idle or ensure the
> hardware is safely reset before freeing the buffer?
> 

enetc_msg_dma_free() is called after enetc_pci_remove(), enetc_pci_remove()
will disable the device, so it is safe to free the buffer.


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v3 net] net: enetc: fix VSI mailbox timeout handling and DMA lifecycle
  2026-04-29  8:19 [PATCH v3 net] net: enetc: fix VSI mailbox timeout handling and DMA lifecycle Wei Fang
  2026-04-30 17:09 ` Simon Horman
@ 2026-05-01  1:20 ` patchwork-bot+netdevbpf
  1 sibling, 0 replies; 4+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-05-01  1:20 UTC (permalink / raw)
  To: Wei Fang
  Cc: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
	davem, edumazet, kuba, pabeni, netdev, linux-kernel, imx

Hello:

This patch was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:

On Wed, 29 Apr 2026 16:19:30 +0800 you wrote:
> In the current VSI mailbox implementation, the VSI allocates a DMA buffer
> to store the message sent to the PSI. When the PSI receives the message
> request from the VSI, the hardware copies the message data from this DMA
> buffer to PSI's DMA buffer for processing.
> 
> When enetc_msg_vsi_send() times out, two scenarios can occur:
> 
> [...]

Here is the summary with links:
  - [v3,net] net: enetc: fix VSI mailbox timeout handling and DMA lifecycle
    https://git.kernel.org/netdev/net/c/26ebd12e67bf

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-05-01  1:20 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-29  8:19 [PATCH v3 net] net: enetc: fix VSI mailbox timeout handling and DMA lifecycle Wei Fang
2026-04-30 17:09 ` Simon Horman
2026-05-01  1:16   ` Wei Fang
2026-05-01  1:20 ` patchwork-bot+netdevbpf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox