diff mbox series

net: xilinx: axienet: Fix race in axienet_stop

Message ID 20240910144607.1441863-1-sean.anderson@linux.dev (mailing list archive)
State Not Applicable
Delegated to: Netdev Maintainers
Headers show
Series net: xilinx: axienet: Fix race in axienet_stop | expand

Checks

Context Check Description
netdev/tree_selection success Guessing tree name failed - patch did not apply

Commit Message

Sean Anderson Sept. 10, 2024, 2:46 p.m. UTC
[ Upstream commit 858430db28a5f5a11f8faa3a6fa805438e6f0851 ]

axienet_dma_err_handler can race with axienet_stop in the following
manner:

CPU 1                       CPU 2
======================      ==================
axienet_stop()
    napi_disable()
    axienet_dma_stop()
                            axienet_dma_err_handler()
                                napi_disable()
                                axienet_dma_stop()
                                axienet_dma_start()
                                napi_enable()
    cancel_work_sync()
    free_irq()

Fix this by setting a flag in axienet_stop telling
axienet_dma_err_handler not to bother doing anything. I chose not to use
disable_work_sync to allow for easier backporting.

Signed-off-by: Sean Anderson <sean.anderson@linux.dev>
Fixes: 8a3b7a252dca ("drivers/net/ethernet/xilinx: added Xilinx AXI Ethernet driver")
Link: https://patch.msgid.link/20240903175141.4132898-1-sean.anderson@linux.dev
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
[ Adjusted to apply before dmaengine support ]
Signed-off-by: Sean Anderson <sean.anderson@linux.dev>
---
This patch is adjusted to apply to v6.6 kernels and earlier, which do
not contain commit 6a91b846af85 ("net: axienet: Introduce dmaengine
support").

 drivers/net/ethernet/xilinx/xilinx_axienet.h      | 3 +++
 drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 8 ++++++++
 2 files changed, 11 insertions(+)

Comments

'Greg Kroah-Hartman' Sept. 13, 2024, 12:49 p.m. UTC | #1
On Tue, Sep 10, 2024 at 10:46:07AM -0400, Sean Anderson wrote:
> [ Upstream commit 858430db28a5f5a11f8faa3a6fa805438e6f0851 ]
> 
> axienet_dma_err_handler can race with axienet_stop in the following
> manner:
> 
> CPU 1                       CPU 2
> ======================      ==================
> axienet_stop()
>     napi_disable()
>     axienet_dma_stop()
>                             axienet_dma_err_handler()
>                                 napi_disable()
>                                 axienet_dma_stop()
>                                 axienet_dma_start()
>                                 napi_enable()
>     cancel_work_sync()
>     free_irq()
> 
> Fix this by setting a flag in axienet_stop telling
> axienet_dma_err_handler not to bother doing anything. I chose not to use
> disable_work_sync to allow for easier backporting.
> 
> Signed-off-by: Sean Anderson <sean.anderson@linux.dev>
> Fixes: 8a3b7a252dca ("drivers/net/ethernet/xilinx: added Xilinx AXI Ethernet driver")
> Link: https://patch.msgid.link/20240903175141.4132898-1-sean.anderson@linux.dev
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> [ Adjusted to apply before dmaengine support ]
> Signed-off-by: Sean Anderson <sean.anderson@linux.dev>
> ---
> This patch is adjusted to apply to v6.6 kernels and earlier, which do
> not contain commit 6a91b846af85 ("net: axienet: Introduce dmaengine
> support").

Applied to 6.6.y and 6.1.y, but nothing older as it didn't apply to
5.15.y :(

thanks,

greg k-h
diff mbox series

Patch

diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index f09f10f17d7e..2facbdfbb319 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -419,6 +419,8 @@  struct axidma_bd {
  * @tx_bytes:	TX byte count for statistics
  * @tx_stat_sync: Synchronization object for TX stats
  * @dma_err_task: Work structure to process Axi DMA errors
+ * @stopping:   Set when @dma_err_task shouldn't do anything because we are
+ *              about to stop the device.
  * @tx_irq:	Axidma TX IRQ number
  * @rx_irq:	Axidma RX IRQ number
  * @eth_irq:	Ethernet core IRQ number
@@ -481,6 +483,7 @@  struct axienet_local {
 	struct u64_stats_sync tx_stat_sync;
 
 	struct work_struct dma_err_task;
+	bool stopping;
 
 	int tx_irq;
 	int rx_irq;
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 144feb7a2fda..65d7aaad43fe 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -1162,6 +1162,7 @@  static int axienet_open(struct net_device *ndev)
 	phylink_start(lp->phylink);
 
 	/* Enable worker thread for Axi DMA error handling */
+	lp->stopping = false;
 	INIT_WORK(&lp->dma_err_task, axienet_dma_err_handler);
 
 	napi_enable(&lp->napi_rx);
@@ -1217,6 +1218,9 @@  static int axienet_stop(struct net_device *ndev)
 
 	dev_dbg(&ndev->dev, "axienet_close()\n");
 
+	WRITE_ONCE(lp->stopping, true);
+	flush_work(&lp->dma_err_task);
+
 	napi_disable(&lp->napi_tx);
 	napi_disable(&lp->napi_rx);
 
@@ -1761,6 +1765,10 @@  static void axienet_dma_err_handler(struct work_struct *work)
 						dma_err_task);
 	struct net_device *ndev = lp->ndev;
 
+	/* Don't bother if we are going to stop anyway */
+	if (READ_ONCE(lp->stopping))
+		return;
+
 	napi_disable(&lp->napi_tx);
 	napi_disable(&lp->napi_rx);