Commit 8070274b authored by Jisheng Zhang's avatar Jisheng Zhang Committed by Paolo Abeni
Browse files

net: stmmac: fix incorrect rxq|txq_stats reference



commit 133466c3 ("net: stmmac: use per-queue 64 bit statistics
where necessary") caused one regression as found by Uwe, the backtrace
looks like:

	INFO: trying to register non-static key.
	The code is fine but needs lockdep annotation, or maybe
	you didn't initialize this object before use?
	turning off the locking correctness validator.
	CPU: 0 PID: 1 Comm: swapper/0 Not tainted 6.5.0-rc1-00449-g133466c3bbe1-dirty #21
	Hardware name: STM32 (Device Tree Support)
	 unwind_backtrace from show_stack+0x18/0x1c
	 show_stack from dump_stack_lvl+0x60/0x90
	 dump_stack_lvl from register_lock_class+0x98c/0x99c
	 register_lock_class from __lock_acquire+0x74/0x293c
	 __lock_acquire from lock_acquire+0x134/0x398
	 lock_acquire from stmmac_get_stats64+0x2ac/0x2fc
	 stmmac_get_stats64 from dev_get_stats+0x44/0x130
	 dev_get_stats from rtnl_fill_stats+0x38/0x120
	 rtnl_fill_stats from rtnl_fill_ifinfo+0x834/0x17f4
	 rtnl_fill_ifinfo from rtmsg_ifinfo_build_skb+0xc0/0x144
	 rtmsg_ifinfo_build_skb from rtmsg_ifinfo+0x50/0x88
	 rtmsg_ifinfo from __dev_notify_flags+0xc0/0xec
	 __dev_notify_flags from dev_change_flags+0x50/0x5c
	 dev_change_flags from ip_auto_config+0x2f4/0x1260
	 ip_auto_config from do_one_initcall+0x70/0x35c
	 do_one_initcall from kernel_init_freeable+0x2ac/0x308
	 kernel_init_freeable from kernel_init+0x1c/0x138
	 kernel_init from ret_from_fork+0x14/0x2c

The reason is the rxq|txq_stats structures are not what expected
because stmmac_open() -> __stmmac_open() the structure is overwritten
by "memcpy(&priv->dma_conf, dma_conf, sizeof(*dma_conf));"
This causes the well initialized syncp member of rxq|txq_stats is
overwritten unexpectedly as pointed out by Johannes and Uwe.

Fix this issue by moving rxq|txq_stats back to stmmac_extra_stats. For
SMP cache friendly, we also mark stmmac_txq_stats and stmmac_rxq_stats
as ____cacheline_aligned_in_smp.

Fixes: 133466c3 ("net: stmmac: use per-queue 64 bit statistics where necessary")
Signed-off-by: default avatarJisheng Zhang <jszhang@kernel.org>
Reported-by: default avatarUwe Kleine-König <u.kleine-koenig@pengutronix.de>
Tested-by: default avatarUwe Kleine-König <u.kleine-koenig@pengutronix.de>
Link: https://lore.kernel.org/r/20230917165328.3403-1-jszhang@kernel.org


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 6dab9dd6
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -70,7 +70,7 @@ struct stmmac_txq_stats {
	u64 tx_tso_frames;
	u64 tx_tso_nfrags;
	struct u64_stats_sync syncp;
};
} ____cacheline_aligned_in_smp;

struct stmmac_rxq_stats {
	u64 rx_bytes;
@@ -79,7 +79,7 @@ struct stmmac_rxq_stats {
	u64 rx_normal_irq_n;
	u64 napi_poll;
	struct u64_stats_sync syncp;
};
} ____cacheline_aligned_in_smp;

/* Extra statistic and debug information exposed by ethtool */
struct stmmac_extra_stats {
@@ -202,6 +202,9 @@ struct stmmac_extra_stats {
	unsigned long mtl_est_hlbf;
	unsigned long mtl_est_btre;
	unsigned long mtl_est_btrlm;
	/* per queue statistics */
	struct stmmac_txq_stats txq_stats[MTL_MAX_TX_QUEUES];
	struct stmmac_rxq_stats rxq_stats[MTL_MAX_RX_QUEUES];
	unsigned long rx_dropped;
	unsigned long rx_errors;
	unsigned long tx_dropped;
+8 −8
Original line number Diff line number Diff line
@@ -441,8 +441,8 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv,
				     struct stmmac_extra_stats *x, u32 chan,
				     u32 dir)
{
	struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan];
	struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan];
	struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[chan];
	struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[chan];
	int ret = 0;
	u32 v;

@@ -455,9 +455,9 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv,

	if (v & EMAC_TX_INT) {
		ret |= handle_tx;
		u64_stats_update_begin(&tx_q->txq_stats.syncp);
		tx_q->txq_stats.tx_normal_irq_n++;
		u64_stats_update_end(&tx_q->txq_stats.syncp);
		u64_stats_update_begin(&txq_stats->syncp);
		txq_stats->tx_normal_irq_n++;
		u64_stats_update_end(&txq_stats->syncp);
	}

	if (v & EMAC_TX_DMA_STOP_INT)
@@ -479,9 +479,9 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv,

	if (v & EMAC_RX_INT) {
		ret |= handle_rx;
		u64_stats_update_begin(&rx_q->rxq_stats.syncp);
		rx_q->rxq_stats.rx_normal_irq_n++;
		u64_stats_update_end(&rx_q->rxq_stats.syncp);
		u64_stats_update_begin(&rxq_stats->syncp);
		rxq_stats->rx_normal_irq_n++;
		u64_stats_update_end(&rxq_stats->syncp);
	}

	if (v & EMAC_RX_BUF_UA_INT)
+8 −8
Original line number Diff line number Diff line
@@ -171,8 +171,8 @@ int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
	const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
	u32 intr_status = readl(ioaddr + DMA_CHAN_STATUS(dwmac4_addrs, chan));
	u32 intr_en = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
	struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan];
	struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan];
	struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[chan];
	struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[chan];
	int ret = 0;

	if (dir == DMA_DIR_RX)
@@ -201,15 +201,15 @@ int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
	}
	/* TX/RX NORMAL interrupts */
	if (likely(intr_status & DMA_CHAN_STATUS_RI)) {
		u64_stats_update_begin(&rx_q->rxq_stats.syncp);
		rx_q->rxq_stats.rx_normal_irq_n++;
		u64_stats_update_end(&rx_q->rxq_stats.syncp);
		u64_stats_update_begin(&rxq_stats->syncp);
		rxq_stats->rx_normal_irq_n++;
		u64_stats_update_end(&rxq_stats->syncp);
		ret |= handle_rx;
	}
	if (likely(intr_status & DMA_CHAN_STATUS_TI)) {
		u64_stats_update_begin(&tx_q->txq_stats.syncp);
		tx_q->txq_stats.tx_normal_irq_n++;
		u64_stats_update_end(&tx_q->txq_stats.syncp);
		u64_stats_update_begin(&txq_stats->syncp);
		txq_stats->tx_normal_irq_n++;
		u64_stats_update_end(&txq_stats->syncp);
		ret |= handle_tx;
	}

+8 −8
Original line number Diff line number Diff line
@@ -162,8 +162,8 @@ static void show_rx_process_state(unsigned int status)
int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
			struct stmmac_extra_stats *x, u32 chan, u32 dir)
{
	struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan];
	struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan];
	struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[chan];
	struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[chan];
	int ret = 0;
	/* read the status register (CSR5) */
	u32 intr_status = readl(ioaddr + DMA_STATUS);
@@ -215,16 +215,16 @@ int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
			u32 value = readl(ioaddr + DMA_INTR_ENA);
			/* to schedule NAPI on real RIE event. */
			if (likely(value & DMA_INTR_ENA_RIE)) {
				u64_stats_update_begin(&rx_q->rxq_stats.syncp);
				rx_q->rxq_stats.rx_normal_irq_n++;
				u64_stats_update_end(&rx_q->rxq_stats.syncp);
				u64_stats_update_begin(&rxq_stats->syncp);
				rxq_stats->rx_normal_irq_n++;
				u64_stats_update_end(&rxq_stats->syncp);
				ret |= handle_rx;
			}
		}
		if (likely(intr_status & DMA_STATUS_TI)) {
			u64_stats_update_begin(&tx_q->txq_stats.syncp);
			tx_q->txq_stats.tx_normal_irq_n++;
			u64_stats_update_end(&tx_q->txq_stats.syncp);
			u64_stats_update_begin(&txq_stats->syncp);
			txq_stats->tx_normal_irq_n++;
			u64_stats_update_end(&txq_stats->syncp);
			ret |= handle_tx;
		}
		if (unlikely(intr_status & DMA_STATUS_ERI))
+8 −8
Original line number Diff line number Diff line
@@ -337,8 +337,8 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv,
				  struct stmmac_extra_stats *x, u32 chan,
				  u32 dir)
{
	struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan];
	struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan];
	struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[chan];
	struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[chan];
	u32 intr_status = readl(ioaddr + XGMAC_DMA_CH_STATUS(chan));
	u32 intr_en = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan));
	int ret = 0;
@@ -367,15 +367,15 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv,
	/* TX/RX NORMAL interrupts */
	if (likely(intr_status & XGMAC_NIS)) {
		if (likely(intr_status & XGMAC_RI)) {
			u64_stats_update_begin(&rx_q->rxq_stats.syncp);
			rx_q->rxq_stats.rx_normal_irq_n++;
			u64_stats_update_end(&rx_q->rxq_stats.syncp);
			u64_stats_update_begin(&rxq_stats->syncp);
			rxq_stats->rx_normal_irq_n++;
			u64_stats_update_end(&rxq_stats->syncp);
			ret |= handle_rx;
		}
		if (likely(intr_status & (XGMAC_TI | XGMAC_TBU))) {
			u64_stats_update_begin(&tx_q->txq_stats.syncp);
			tx_q->txq_stats.tx_normal_irq_n++;
			u64_stats_update_end(&tx_q->txq_stats.syncp);
			u64_stats_update_begin(&txq_stats->syncp);
			txq_stats->tx_normal_irq_n++;
			u64_stats_update_end(&txq_stats->syncp);
			ret |= handle_tx;
		}
	}
Loading