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 | bool enable) | 715 | bool enable) |
| 715 | { | 716 | { |
| 716 | u32 value; | 717 | u32 value; |
| 717 | 718 | ||
| 718 | if (!enable) { | 719 | if (enable) { |
| 719 | value = readl(ioaddr + MAC_FPE_CTRL_STS); | 720 | cfg->fpe_csr = EFPE; |
| 720 | 721 | value = readl(ioaddr + GMAC_RXQ_CTRL1); | |
| 721 | value &= ~EFPE; | 722 | value &= ~GMAC_RXQCTRL_FPRQ; |
| 722 | 723 | value |= (num_rxq - 1) << GMAC_RXQCTRL_FPRQ_SHIFT; | |
| 723 | writel(value, ioaddr + MAC_FPE_CTRL_STS); | 724 | writel(value, ioaddr + GMAC_RXQ_CTRL1); |
| 724 | return; | 725 | } else { |
| 726 | cfg->fpe_csr = 0; | ||
| 725 | } | 727 | } |
| 726 | 728 | writel(cfg->fpe_csr, ioaddr + MAC_FPE_CTRL_STS); | |
| 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); | ||
| 735 | } | 729 | } |
| 736 | 730 | ||
| 737 | int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev) | 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 | status = FPE_EVENT_UNKNOWN; | 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 | value = readl(ioaddr + MAC_FPE_CTRL_STS); | 741 | value = readl(ioaddr + MAC_FPE_CTRL_STS); |
| 745 | 742 | ||
| 746 | if (value & TRSP) { | 743 | if (value & TRSP) { |
| @@ -766,19 +763,15 @@ int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev) · 19 unmodified lines | |||
| 766 | return status; | 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); | 771 | if (type == MPACKET_VERIFY) |
| 774 | |||
| 775 | if (type == MPACKET_VERIFY) { | ||
| 776 | value &= ~SRSP; | ||
| 777 | value |= SVER; | 772 | value |= SVER; |
| 778 | } else { | 773 | else if (type == MPACKET_RESPONSE) |
| 779 | value &= ~SVER; | ||
| 780 | value |= SRSP; | 774 | value |= SRSP; |
| 781 | } | ||
| 782 | 775 | ||
| 783 | writel(value, ioaddr + MAC_FPE_CTRL_STS); | 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 | unsigned int ptp_rate); | 153 | unsigned int ptp_rate); |
| 154 | void dwmac5_est_irq_status(void __iomem *ioaddr, struct net_device *dev, | 154 | void dwmac5_est_irq_status(void __iomem *ioaddr, struct net_device *dev, |
| 155 | struct stmmac_extra_stats *x, u32 txqcnt); | 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 | bool enable); | 158 | bool enable); |
| 158 | void dwmac5_fpe_send_mpacket(void __iomem *ioaddr, | 159 | void dwmac5_fpe_send_mpacket(void __iomem *ioaddr, |
| 160 | struct stmmac_fpe_cfg *cfg, | ||
| 159 | enum stmmac_mpacket_type type); | 161 | enum stmmac_mpacket_type type); |
| 160 | int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev); | 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 | return 0; | 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 | u32 num_rxq, bool enable) | 1489 | u32 num_rxq, bool enable) |
| 1489 | { | 1490 | { |
| 1490 | u32 value; | 1491 | u32 value; |
| @@ -412,9 +412,11 @@ struct stmmac_ops { · 411 unmodified lines | |||
| 412 | unsigned int ptp_rate); | 412 | unsigned int ptp_rate); |
| 413 | void (*est_irq_status)(void __iomem *ioaddr, struct net_device *dev, | 413 | void (*est_irq_status)(void __iomem *ioaddr, struct net_device *dev, |
| 414 | struct stmmac_extra_stats *x, u32 txqcnt); | 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 | bool enable); | 417 | bool enable); |
| 417 | void (*fpe_send_mpacket)(void __iomem *ioaddr, | 418 | void (*fpe_send_mpacket)(void __iomem *ioaddr, |
| 419 | struct stmmac_fpe_cfg *cfg, | ||
| 418 | enum stmmac_mpacket_type type); | 420 | enum stmmac_mpacket_type type); |
| 419 | int (*fpe_irq_status)(void __iomem *ioaddr, struct net_device *dev); | 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 | bool *hs_enable = &fpe_cfg->hs_enable; | 964 | bool *hs_enable = &fpe_cfg->hs_enable; |
| 965 | 965 | ||
| 966 | if (is_up && *hs_enable) { | 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 | } else { | 969 | } else { |
| 969 | *lo_state = FPE_STATE_OFF; | 970 | *lo_state = FPE_STATE_OFF; |
| 970 | *lp_state = FPE_STATE_OFF; | 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 | /* If user has requested FPE enable, quickly response */ | 5840 | /* If user has requested FPE enable, quickly response */ |
| 5840 | if (*hs_enable) | 5841 | if (*hs_enable) |
| 5841 | stmmac_fpe_send_mpacket(priv, priv->ioaddr, | 5842 | stmmac_fpe_send_mpacket(priv, priv->ioaddr, |
| 5843 | fpe_cfg, | ||
| 5842 | MPACKET_RESPONSE); | 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 | if (*lo_state == FPE_STATE_ENTERING_ON && | 7265 | if (*lo_state == FPE_STATE_ENTERING_ON && |
| 7264 | *lp_state == FPE_STATE_ENTERING_ON) { | 7266 | *lp_state == FPE_STATE_ENTERING_ON) { |
| 7265 | stmmac_fpe_configure(priv, priv->ioaddr, | 7267 | stmmac_fpe_configure(priv, priv->ioaddr, |
| 7268 | fpe_cfg, | ||
| 7266 | priv->plat->tx_queues_to_use, | 7269 | priv->plat->tx_queues_to_use, |
| 7267 | priv->plat->rx_queues_to_use, | 7270 | priv->plat->rx_queues_to_use, |
| 7268 | *enable); | 7271 | *enable); |
| @@ -7281,6 +7284,7 @@ static void stmmac_fpe_lp_task(struct work_struct *work) · 12 unmodified lines | |||
| 7281 | netdev_info(priv->dev, SEND_VERIFY_MPAKCET_FMT, | 7284 | netdev_info(priv->dev, SEND_VERIFY_MPAKCET_FMT, |
| 7282 | *lo_state, *lp_state); | 7285 | *lo_state, *lp_state); |
| 7283 | stmmac_fpe_send_mpacket(priv, priv->ioaddr, | 7286 | stmmac_fpe_send_mpacket(priv, priv->ioaddr, |
| 7287 | fpe_cfg, | ||
| 7284 | MPACKET_VERIFY); | 7288 | MPACKET_VERIFY); |
| 7285 | } | 7289 | } |
| 7286 | /* Sleep then retry */ | 7290 | /* Sleep then retry */ |
| @@ -7295,6 +7299,7 @@ void stmmac_fpe_handshake(struct stmmac_priv *priv, bool enable) · 8 unmodified lines | |||
| 7295 | if (priv->plat->fpe_cfg->hs_enable != enable) { | 7299 | if (priv->plat->fpe_cfg->hs_enable != enable) { |
| 7296 | if (enable) { | 7300 | if (enable) { |
| 7297 | stmmac_fpe_send_mpacket(priv, priv->ioaddr, | 7301 | stmmac_fpe_send_mpacket(priv, priv->ioaddr, |
| 7302 | priv->plat->fpe_cfg, | ||
| 7298 | MPACKET_VERIFY); | 7303 | MPACKET_VERIFY); |
| 7299 | } else { | 7304 | } else { |
| 7300 | priv->plat->fpe_cfg->lo_fpe_state = FPE_STATE_OFF; | 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 | if (priv->dma_cap.fpesel) { | 7760 | if (priv->dma_cap.fpesel) { |
| 7756 | /* Disable FPE */ | 7761 | /* Disable FPE */ |
| 7757 | stmmac_fpe_configure(priv, priv->ioaddr, | 7762 | stmmac_fpe_configure(priv, priv->ioaddr, |
| 7763 | priv->plat->fpe_cfg, | ||
| 7758 | priv->plat->tx_queues_to_use, | 7764 | priv->plat->tx_queues_to_use, |
| 7759 | priv->plat->rx_queues_to_use, false); | 7765 | priv->plat->rx_queues_to_use, false); |
| 7760 | 7766 | ||
| @@ -1079,6 +1079,7 @@ disable: · 1078 unmodified lines | |||
| 1079 | 1079 | ||
| 1080 | priv->plat->fpe_cfg->enable = false; | 1080 | priv->plat->fpe_cfg->enable = false; |
| 1081 | stmmac_fpe_configure(priv, priv->ioaddr, | 1081 | stmmac_fpe_configure(priv, priv->ioaddr, |
| 1082 | priv->plat->fpe_cfg, | ||
| 1082 | priv->plat->tx_queues_to_use, | 1083 | priv->plat->tx_queues_to_use, |
| 1083 | priv->plat->rx_queues_to_use, | 1084 | priv->plat->rx_queues_to_use, |
| 1084 | false); | 1085 | false); |
| @@ -175,6 +175,7 @@ struct stmmac_fpe_cfg { · 174 unmodified lines | |||
| 175 | bool hs_enable; /* FPE handshake enable */ | 175 | bool hs_enable; /* FPE handshake enable */ |
| 176 | enum stmmac_fpe_state lp_fpe_state; /* Link Partner FPE state */ | 176 | enum stmmac_fpe_state lp_fpe_state; /* Link Partner FPE state */ |
| 177 | enum stmmac_fpe_state lo_fpe_state; /* Local station FPE state */ | 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 | struct stmmac_safety_feature_cfg { | 181 | struct stmmac_safety_feature_cfg { |