Commit 5f079290 authored by Vignesh Raghavendra's avatar Vignesh Raghavendra Committed by Paolo Abeni
Browse files

net: ethernet: ti: am65-cpsw: Fix NAPI registration sequence



Registering the interrupts for TX or RX DMA Channels prior to registering
their respective NAPI callbacks can result in a NULL pointer dereference.
This is seen in practice as a random occurrence since it depends on the
randomness associated with the generation of traffic by Linux and the
reception of traffic from the wire.

Fixes: 681eb2be ("net: ethernet: ti: am65-cpsw: ensure proper channel cleanup in error path")
Signed-off-by: default avatarVignesh Raghavendra <vigneshr@ti.com>
Co-developed-by: default avatarSiddharth Vadapalli <s-vadapalli@ti.com>
Signed-off-by: default avatarSiddharth Vadapalli <s-vadapalli@ti.com>
Reviewed-by: default avatarAlexander Sverdlin <alexander.sverdlin@siemens.com>
Reviewed-by: default avatarRoger Quadros <rogerq@kernel.org>
Link: https://patch.msgid.link/20250311154259.102865-1-s-vadapalli@ti.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 4003c9e7
Loading
Loading
Loading
Loading
+18 −14
Original line number Diff line number Diff line
@@ -2306,14 +2306,18 @@ static void am65_cpsw_nuss_remove_tx_chns(struct am65_cpsw_common *common)
static int am65_cpsw_nuss_ndev_add_tx_napi(struct am65_cpsw_common *common)
{
	struct device *dev = common->dev;
	struct am65_cpsw_tx_chn *tx_chn;
	int i, ret = 0;

	for (i = 0; i < common->tx_ch_num; i++) {
		struct am65_cpsw_tx_chn *tx_chn = &common->tx_chns[i];
		tx_chn = &common->tx_chns[i];

		hrtimer_init(&tx_chn->tx_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
		tx_chn->tx_hrtimer.function = &am65_cpsw_nuss_tx_timer_callback;

		netif_napi_add_tx(common->dma_ndev, &tx_chn->napi_tx,
				  am65_cpsw_nuss_tx_poll);

		ret = devm_request_irq(dev, tx_chn->irq,
				       am65_cpsw_nuss_tx_irq,
				       IRQF_TRIGGER_HIGH,
@@ -2323,19 +2327,16 @@ static int am65_cpsw_nuss_ndev_add_tx_napi(struct am65_cpsw_common *common)
				tx_chn->id, tx_chn->irq, ret);
			goto err;
		}

		netif_napi_add_tx(common->dma_ndev, &tx_chn->napi_tx,
				  am65_cpsw_nuss_tx_poll);
	}

	return 0;

err:
	for (--i ; i >= 0 ; i--) {
		struct am65_cpsw_tx_chn *tx_chn = &common->tx_chns[i];

	netif_napi_del(&tx_chn->napi_tx);
	for (--i; i >= 0; i--) {
		tx_chn = &common->tx_chns[i];
		devm_free_irq(dev, tx_chn->irq, tx_chn);
		netif_napi_del(&tx_chn->napi_tx);
	}

	return ret;
@@ -2569,6 +2570,9 @@ static int am65_cpsw_nuss_init_rx_chns(struct am65_cpsw_common *common)
			     HRTIMER_MODE_REL_PINNED);
		flow->rx_hrtimer.function = &am65_cpsw_nuss_rx_timer_callback;

		netif_napi_add(common->dma_ndev, &flow->napi_rx,
			       am65_cpsw_nuss_rx_poll);

		ret = devm_request_irq(dev, flow->irq,
				       am65_cpsw_nuss_rx_irq,
				       IRQF_TRIGGER_HIGH,
@@ -2577,11 +2581,8 @@ static int am65_cpsw_nuss_init_rx_chns(struct am65_cpsw_common *common)
			dev_err(dev, "failure requesting rx %d irq %u, %d\n",
				i, flow->irq, ret);
			flow->irq = -EINVAL;
			goto err_flow;
			goto err_request_irq;
		}

		netif_napi_add(common->dma_ndev, &flow->napi_rx,
			       am65_cpsw_nuss_rx_poll);
	}

	/* setup classifier to route priorities to flows */
@@ -2589,11 +2590,14 @@ static int am65_cpsw_nuss_init_rx_chns(struct am65_cpsw_common *common)

	return 0;

err_request_irq:
	netif_napi_del(&flow->napi_rx);

err_flow:
	for (--i; i >= 0; i--) {
		flow = &rx_chn->flows[i];
		netif_napi_del(&flow->napi_rx);
		devm_free_irq(dev, flow->irq, flow);
		netif_napi_del(&flow->napi_rx);
	}

err: