Commit 37e4b8df authored by Jianheng Zhang's avatar Jianheng Zhang Committed by Jakub Kicinski
Browse files

net: stmmac: fix FPE events losing



The status bits of register MAC_FPE_CTRL_STS are clear on read. Using
32-bit read for MAC_FPE_CTRL_STS in dwmac5_fpe_configure() and
dwmac5_fpe_send_mpacket() clear the status bits. Then the stmmac interrupt
handler missing FPE event status and leads to FPE handshaking failure and
retries.
To avoid clear status bits of MAC_FPE_CTRL_STS in dwmac5_fpe_configure()
and dwmac5_fpe_send_mpacket(), add fpe_csr to stmmac_fpe_cfg structure to
cache the control bits of MAC_FPE_CTRL_STS and to avoid reading
MAC_FPE_CTRL_STS in those methods.

Fixes: 5a558611 ("net: stmmac: support FPE link partner hand-shaking procedure")
Reviewed-by: default avatarSerge Semin <fancer.lancer@gmail.com>
Signed-off-by: default avatarJianheng Zhang <Jianheng.Zhang@synopsys.com>
Link: https://lore.kernel.org/r/CY5PR12MB637225A7CF529D5BE0FBE59CBF81A@CY5PR12MB6372.namprd12.prod.outlook.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent adbf100f
Loading
Loading
Loading
Loading
+19 −26
Original line number Diff line number Diff line
@@ -710,28 +710,22 @@ void dwmac5_est_irq_status(void __iomem *ioaddr, struct net_device *dev,
	}
}

void dwmac5_fpe_configure(void __iomem *ioaddr, u32 num_txq, u32 num_rxq,
void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
			  u32 num_txq, u32 num_rxq,
			  bool enable)
{
	u32 value;

	if (!enable) {
		value = readl(ioaddr + MAC_FPE_CTRL_STS);

		value &= ~EFPE;

		writel(value, ioaddr + MAC_FPE_CTRL_STS);
		return;
	}

	if (enable) {
		cfg->fpe_csr = EFPE;
		value = readl(ioaddr + GMAC_RXQ_CTRL1);
		value &= ~GMAC_RXQCTRL_FPRQ;
		value |= (num_rxq - 1) << GMAC_RXQCTRL_FPRQ_SHIFT;
		writel(value, ioaddr + GMAC_RXQ_CTRL1);

	value = readl(ioaddr + MAC_FPE_CTRL_STS);
	value |= EFPE;
	writel(value, ioaddr + MAC_FPE_CTRL_STS);
	} else {
		cfg->fpe_csr = 0;
	}
	writel(cfg->fpe_csr, ioaddr + MAC_FPE_CTRL_STS);
}

int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev)
@@ -741,6 +735,9 @@ int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev)

	status = FPE_EVENT_UNKNOWN;

	/* Reads from the MAC_FPE_CTRL_STS register should only be performed
	 * here, since the status flags of MAC_FPE_CTRL_STS are "clear on read"
	 */
	value = readl(ioaddr + MAC_FPE_CTRL_STS);

	if (value & TRSP) {
@@ -766,19 +763,15 @@ int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev)
	return status;
}

void dwmac5_fpe_send_mpacket(void __iomem *ioaddr, enum stmmac_mpacket_type type)
void dwmac5_fpe_send_mpacket(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
			     enum stmmac_mpacket_type type)
{
	u32 value;
	u32 value = cfg->fpe_csr;

	value = readl(ioaddr + MAC_FPE_CTRL_STS);

	if (type == MPACKET_VERIFY) {
		value &= ~SRSP;
	if (type == MPACKET_VERIFY)
		value |= SVER;
	} else {
		value &= ~SVER;
	else if (type == MPACKET_RESPONSE)
		value |= SRSP;
	}

	writel(value, ioaddr + MAC_FPE_CTRL_STS);
}
+3 −1
Original line number Diff line number Diff line
@@ -153,9 +153,11 @@ int dwmac5_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg,
			 unsigned int ptp_rate);
void dwmac5_est_irq_status(void __iomem *ioaddr, struct net_device *dev,
			   struct stmmac_extra_stats *x, u32 txqcnt);
void dwmac5_fpe_configure(void __iomem *ioaddr, u32 num_txq, u32 num_rxq,
void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
			  u32 num_txq, u32 num_rxq,
			  bool enable);
void dwmac5_fpe_send_mpacket(void __iomem *ioaddr,
			     struct stmmac_fpe_cfg *cfg,
			     enum stmmac_mpacket_type type);
int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev);

+2 −1
Original line number Diff line number Diff line
@@ -1484,7 +1484,8 @@ static int dwxgmac3_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg,
	return 0;
}

static void dwxgmac3_fpe_configure(void __iomem *ioaddr, u32 num_txq,
static void dwxgmac3_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
				   u32 num_txq,
				   u32 num_rxq, bool enable)
{
	u32 value;
+3 −1
Original line number Diff line number Diff line
@@ -412,9 +412,11 @@ struct stmmac_ops {
			     unsigned int ptp_rate);
	void (*est_irq_status)(void __iomem *ioaddr, struct net_device *dev,
			       struct stmmac_extra_stats *x, u32 txqcnt);
	void (*fpe_configure)(void __iomem *ioaddr, u32 num_txq, u32 num_rxq,
	void (*fpe_configure)(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
			      u32 num_txq, u32 num_rxq,
			      bool enable);
	void (*fpe_send_mpacket)(void __iomem *ioaddr,
				 struct stmmac_fpe_cfg *cfg,
				 enum stmmac_mpacket_type type);
	int (*fpe_irq_status)(void __iomem *ioaddr, struct net_device *dev);
};
+7 −1
Original line number Diff line number Diff line
@@ -964,7 +964,8 @@ static void stmmac_fpe_link_state_handle(struct stmmac_priv *priv, bool is_up)
	bool *hs_enable = &fpe_cfg->hs_enable;

	if (is_up && *hs_enable) {
		stmmac_fpe_send_mpacket(priv, priv->ioaddr, MPACKET_VERIFY);
		stmmac_fpe_send_mpacket(priv, priv->ioaddr, fpe_cfg,
					MPACKET_VERIFY);
	} else {
		*lo_state = FPE_STATE_OFF;
		*lp_state = FPE_STATE_OFF;
@@ -5839,6 +5840,7 @@ static void stmmac_fpe_event_status(struct stmmac_priv *priv, int status)
		/* If user has requested FPE enable, quickly response */
		if (*hs_enable)
			stmmac_fpe_send_mpacket(priv, priv->ioaddr,
						fpe_cfg,
						MPACKET_RESPONSE);
	}

@@ -7263,6 +7265,7 @@ static void stmmac_fpe_lp_task(struct work_struct *work)
		if (*lo_state == FPE_STATE_ENTERING_ON &&
		    *lp_state == FPE_STATE_ENTERING_ON) {
			stmmac_fpe_configure(priv, priv->ioaddr,
					     fpe_cfg,
					     priv->plat->tx_queues_to_use,
					     priv->plat->rx_queues_to_use,
					     *enable);
@@ -7281,6 +7284,7 @@ static void stmmac_fpe_lp_task(struct work_struct *work)
			netdev_info(priv->dev, SEND_VERIFY_MPAKCET_FMT,
				    *lo_state, *lp_state);
			stmmac_fpe_send_mpacket(priv, priv->ioaddr,
						fpe_cfg,
						MPACKET_VERIFY);
		}
		/* Sleep then retry */
@@ -7295,6 +7299,7 @@ void stmmac_fpe_handshake(struct stmmac_priv *priv, bool enable)
	if (priv->plat->fpe_cfg->hs_enable != enable) {
		if (enable) {
			stmmac_fpe_send_mpacket(priv, priv->ioaddr,
						priv->plat->fpe_cfg,
						MPACKET_VERIFY);
		} else {
			priv->plat->fpe_cfg->lo_fpe_state = FPE_STATE_OFF;
@@ -7755,6 +7760,7 @@ int stmmac_suspend(struct device *dev)
	if (priv->dma_cap.fpesel) {
		/* Disable FPE */
		stmmac_fpe_configure(priv, priv->ioaddr,
				     priv->plat->fpe_cfg,
				     priv->plat->tx_queues_to_use,
				     priv->plat->rx_queues_to_use, false);

Loading