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.
Unified · Split
| @@ -710,28 +710,22 @@ void dwmac5_est_irq_status(void __iomem *ioaddr, struct net_device *dev, · 709 unmodified lines | ||
| 710 | 710 | } |
| 711 | 711 | } |
| 712 | 712 | |
| 713 | −void dwmac5_fpe_configure(void __iomem *ioaddr, u32 num_txq, u32 num_rxq, | |
| 713 | +void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg, | |
| 714 | + u32 num_txq, u32 num_rxq, | |
| 714 | 715 | bool enable) |
| 715 | 716 | { |
| 716 | 717 | u32 value; |
| 717 | 718 | |
| 718 | − if (!enable) { | |
| 719 | − value = readl(ioaddr + MAC_FPE_CTRL_STS); | |
| 720 | − | |
| 721 | − value &= ~EFPE; | |
| 722 | − | |
| 723 | − writel(value, ioaddr + MAC_FPE_CTRL_STS); | |
| 724 | − return; | |
| 719 | + if (enable) { | |
| 720 | + cfg->fpe_csr = EFPE; | |
| 721 | + value = readl(ioaddr + GMAC_RXQ_CTRL1); | |
| 722 | + value &= ~GMAC_RXQCTRL_FPRQ; | |
| 723 | + value |= (num_rxq - 1) << GMAC_RXQCTRL_FPRQ_SHIFT; | |
| 724 | + writel(value, ioaddr + GMAC_RXQ_CTRL1); | |
| 725 | + } else { | |
| 726 | + cfg->fpe_csr = 0; | |
| 725 | 727 | } |
| 726 | − | |
| 727 | − value = readl(ioaddr + GMAC_RXQ_CTRL1); | |
| 728 | − value &= ~GMAC_RXQCTRL_FPRQ; | |
| 729 | − value |= (num_rxq - 1) << GMAC_RXQCTRL_FPRQ_SHIFT; | |
| 730 | − writel(value, ioaddr + GMAC_RXQ_CTRL1); | |
| 731 | − | |
| 732 | − value = readl(ioaddr + MAC_FPE_CTRL_STS); | |
| 733 | − value |= EFPE; | |
| 734 | − writel(value, ioaddr + MAC_FPE_CTRL_STS); | |
| 728 | + writel(cfg->fpe_csr, ioaddr + MAC_FPE_CTRL_STS); | |
| 735 | 729 | } |
| 736 | 730 | |
| 737 | 731 | 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) · 3 unmodified lines | ||
| 741 | 735 | |
| 742 | 736 | status = FPE_EVENT_UNKNOWN; |
| 743 | 737 | |
| 738 | + /* Reads from the MAC_FPE_CTRL_STS register should only be performed | |
| 739 | + * here, since the status flags of MAC_FPE_CTRL_STS are "clear on read" | |
| 740 | + */ | |
| 744 | 741 | value = readl(ioaddr + MAC_FPE_CTRL_STS); |
| 745 | 742 | |
| 746 | 743 | if (value & TRSP) { |
| @@ -766,19 +763,15 @@ int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev) · 19 unmodified lines | ||
| 766 | 763 | return status; |
| 767 | 764 | } |
| 768 | 765 | |
| 769 | −void dwmac5_fpe_send_mpacket(void __iomem *ioaddr, enum stmmac_mpacket_type type) | |
| 766 | +void dwmac5_fpe_send_mpacket(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg, | |
| 767 | + enum stmmac_mpacket_type type) | |
| 770 | 768 | { |
| 771 | − u32 value; | |
| 769 | + u32 value = cfg->fpe_csr; | |
| 772 | 770 | |
| 773 | − value = readl(ioaddr + MAC_FPE_CTRL_STS); | |
| 774 | − | |
| 775 | − if (type == MPACKET_VERIFY) { | |
| 776 | − value &= ~SRSP; | |
| 771 | + if (type == MPACKET_VERIFY) | |
| 777 | 772 | value |= SVER; |
| 778 | − } else { | |
| 779 | − value &= ~SVER; | |
| 773 | + else if (type == MPACKET_RESPONSE) | |
| 780 | 774 | value |= SRSP; |
| 781 | − } | |
| 782 | 775 | |
| 783 | 776 | writel(value, ioaddr + MAC_FPE_CTRL_STS); |
| 784 | 777 | } |
| @@ -153,9 +153,11 @@ int dwmac5_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg, · 152 unmodified lines | ||
| 153 | 153 | unsigned int ptp_rate); |
| 154 | 154 | void dwmac5_est_irq_status(void __iomem *ioaddr, struct net_device *dev, |
| 155 | 155 | struct stmmac_extra_stats *x, u32 txqcnt); |
| 156 | −void dwmac5_fpe_configure(void __iomem *ioaddr, u32 num_txq, u32 num_rxq, | |
| 156 | +void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg, | |
| 157 | + u32 num_txq, u32 num_rxq, | |
| 157 | 158 | bool enable); |
| 158 | 159 | void dwmac5_fpe_send_mpacket(void __iomem *ioaddr, |
| 160 | + struct stmmac_fpe_cfg *cfg, | |
| 159 | 161 | enum stmmac_mpacket_type type); |
| 160 | 162 | int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev); |
| 161 | 163 | |
| @@ -1484,7 +1484,8 @@ static int dwxgmac3_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg, · 1483 unmodified lines | ||
| 1484 | 1484 | return 0; |
| 1485 | 1485 | } |
| 1486 | 1486 | |
| 1487 | −static void dwxgmac3_fpe_configure(void __iomem *ioaddr, u32 num_txq, | |
| 1487 | +static void dwxgmac3_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg, | |
| 1488 | + u32 num_txq, | |
| 1488 | 1489 | u32 num_rxq, bool enable) |
| 1489 | 1490 | { |
| 1490 | 1491 | u32 value; |
| @@ -412,9 +412,11 @@ struct stmmac_ops { · 411 unmodified lines | ||
| 412 | 412 | unsigned int ptp_rate); |
| 413 | 413 | void (*est_irq_status)(void __iomem *ioaddr, struct net_device *dev, |
| 414 | 414 | struct stmmac_extra_stats *x, u32 txqcnt); |
| 415 | − void (*fpe_configure)(void __iomem *ioaddr, u32 num_txq, u32 num_rxq, | |
| 415 | + void (*fpe_configure)(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg, | |
| 416 | + u32 num_txq, u32 num_rxq, | |
| 416 | 417 | bool enable); |
| 417 | 418 | void (*fpe_send_mpacket)(void __iomem *ioaddr, |
| 419 | + struct stmmac_fpe_cfg *cfg, | |
| 418 | 420 | enum stmmac_mpacket_type type); |
| 419 | 421 | int (*fpe_irq_status)(void __iomem *ioaddr, struct net_device *dev); |
| 420 | 422 | }; |
| @@ -964,7 +964,8 @@ static void stmmac_fpe_link_state_handle(struct stmmac_priv *priv, bool is_up) · 963 unmodified lines | ||
| 964 | 964 | bool *hs_enable = &fpe_cfg->hs_enable; |
| 965 | 965 | |
| 966 | 966 | if (is_up && *hs_enable) { |
| 967 | − stmmac_fpe_send_mpacket(priv, priv->ioaddr, MPACKET_VERIFY); | |
| 967 | + stmmac_fpe_send_mpacket(priv, priv->ioaddr, fpe_cfg, | |
| 968 | + MPACKET_VERIFY); | |
| 968 | 969 | } else { |
| 969 | 970 | *lo_state = FPE_STATE_OFF; |
| 970 | 971 | *lp_state = FPE_STATE_OFF; |
| @@ -5839,6 +5840,7 @@ static void stmmac_fpe_event_status(struct stmmac_priv *priv, int status) · 4868 unmodified lines | ||
| 5839 | 5840 | /* If user has requested FPE enable, quickly response */ |
| 5840 | 5841 | if (*hs_enable) |
| 5841 | 5842 | stmmac_fpe_send_mpacket(priv, priv->ioaddr, |
| 5843 | + fpe_cfg, | |
| 5842 | 5844 | MPACKET_RESPONSE); |
| 5843 | 5845 | } |
| 5844 | 5846 | |
| @@ -7263,6 +7265,7 @@ static void stmmac_fpe_lp_task(struct work_struct *work) · 1418 unmodified lines | ||
| 7263 | 7265 | if (*lo_state == FPE_STATE_ENTERING_ON && |
| 7264 | 7266 | *lp_state == FPE_STATE_ENTERING_ON) { |
| 7265 | 7267 | stmmac_fpe_configure(priv, priv->ioaddr, |
| 7268 | + fpe_cfg, | |
| 7266 | 7269 | priv->plat->tx_queues_to_use, |
| 7267 | 7270 | priv->plat->rx_queues_to_use, |
| 7268 | 7271 | *enable); |
| @@ -7281,6 +7284,7 @@ static void stmmac_fpe_lp_task(struct work_struct *work) · 12 unmodified lines | ||
| 7281 | 7284 | netdev_info(priv->dev, SEND_VERIFY_MPAKCET_FMT, |
| 7282 | 7285 | *lo_state, *lp_state); |
| 7283 | 7286 | stmmac_fpe_send_mpacket(priv, priv->ioaddr, |
| 7287 | + fpe_cfg, | |
| 7284 | 7288 | MPACKET_VERIFY); |
| 7285 | 7289 | } |
| 7286 | 7290 | /* Sleep then retry */ |
| @@ -7295,6 +7299,7 @@ void stmmac_fpe_handshake(struct stmmac_priv *priv, bool enable) · 8 unmodified lines | ||
| 7295 | 7299 | if (priv->plat->fpe_cfg->hs_enable != enable) { |
| 7296 | 7300 | if (enable) { |
| 7297 | 7301 | stmmac_fpe_send_mpacket(priv, priv->ioaddr, |
| 7302 | + priv->plat->fpe_cfg, | |
| 7298 | 7303 | MPACKET_VERIFY); |
| 7299 | 7304 | } else { |
| 7300 | 7305 | priv->plat->fpe_cfg->lo_fpe_state = FPE_STATE_OFF; |
| @@ -7755,6 +7760,7 @@ int stmmac_suspend(struct device *dev) · 454 unmodified lines | ||
| 7755 | 7760 | if (priv->dma_cap.fpesel) { |
| 7756 | 7761 | /* Disable FPE */ |
| 7757 | 7762 | stmmac_fpe_configure(priv, priv->ioaddr, |
| 7763 | + priv->plat->fpe_cfg, | |
| 7758 | 7764 | priv->plat->tx_queues_to_use, |
| 7759 | 7765 | priv->plat->rx_queues_to_use, false); |
| 7760 | 7766 | |
| @@ -1079,6 +1079,7 @@ disable: · 1078 unmodified lines | ||
| 1079 | 1079 | |
| 1080 | 1080 | priv->plat->fpe_cfg->enable = false; |
| 1081 | 1081 | stmmac_fpe_configure(priv, priv->ioaddr, |
| 1082 | + priv->plat->fpe_cfg, | |
| 1082 | 1083 | priv->plat->tx_queues_to_use, |
| 1083 | 1084 | priv->plat->rx_queues_to_use, |
| 1084 | 1085 | false); |
| @@ -175,6 +175,7 @@ struct stmmac_fpe_cfg { · 174 unmodified lines | ||
| 175 | 175 | bool hs_enable; /* FPE handshake enable */ |
| 176 | 176 | enum stmmac_fpe_state lp_fpe_state; /* Link Partner FPE state */ |
| 177 | 177 | enum stmmac_fpe_state lo_fpe_state; /* Local station FPE state */ |
| 178 | + u32 fpe_csr; /* MAC_FPE_CTRL_STS reg cache */ | |
| 178 | 179 | }; |
| 179 | 180 | |
| 180 | 181 | struct stmmac_safety_feature_cfg { |