net: amd-xgbe: Reset the PHY rx data path when mailbox command timeout
authorShyam Sundar S K <Shyam-sundar.S-k@amd.com>
Tue, 16 Feb 2021 19:07:07 +0000 (00:37 +0530)
committerDavid S. Miller <davem@davemloft.net>
Tue, 16 Feb 2021 22:09:45 +0000 (14:09 -0800)
Sometimes mailbox commands timeout when the RX data path becomes
unresponsive. This prevents the submission of new mailbox commands to DXIO.
This patch identifies the timeout and resets the RX data path so that the
next message can be submitted properly.

Fixes: 549b32af9f7c ("amd-xgbe: Simplify mailbox interface rate change code")
Co-developed-by: Sudheesh Mavila <sudheesh.mavila@amd.com>
Signed-off-by: Sudheesh Mavila <sudheesh.mavila@amd.com>
Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
Acked-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/amd/xgbe/xgbe-common.h
drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c

index b40d437..b2cd3bd 100644 (file)
 #define MDIO_PMA_10GBR_FECCTRL         0x00ab
 #endif
 
+#ifndef MDIO_PMA_RX_CTRL1
+#define MDIO_PMA_RX_CTRL1              0x8051
+#endif
+
 #ifndef MDIO_PCS_DIG_CTRL
 #define MDIO_PCS_DIG_CTRL              0x8000
 #endif
 
+#ifndef MDIO_PCS_DIGITAL_STAT
+#define MDIO_PCS_DIGITAL_STAT          0x8010
+#endif
+
 #ifndef MDIO_AN_XNP
 #define MDIO_AN_XNP                    0x0016
 #endif
 #define XGBE_KR_TRAINING_ENABLE                BIT(1)
 
 #define XGBE_PCS_CL37_BP               BIT(12)
+#define XGBE_PCS_PSEQ_STATE_MASK       0x1c
+#define XGBE_PCS_PSEQ_STATE_POWER_GOOD 0x10
 
 #define XGBE_AN_CL37_INT_CMPLT         BIT(0)
 #define XGBE_AN_CL37_INT_MASK          0x01
 #define XGBE_PMA_CDR_TRACK_EN_OFF      0x00
 #define XGBE_PMA_CDR_TRACK_EN_ON       0x01
 
+#define XGBE_PMA_RX_RST_0_MASK         BIT(4)
+#define XGBE_PMA_RX_RST_0_RESET_ON     0x10
+#define XGBE_PMA_RX_RST_0_RESET_OFF    0x00
+
 /* Bit setting and getting macros
  *  The get macro will extract the current bit field value from within
  *  the variable
index 859ded0..0879480 100644 (file)
@@ -1953,6 +1953,27 @@ static void xgbe_phy_set_redrv_mode(struct xgbe_prv_data *pdata)
        xgbe_phy_put_comm_ownership(pdata);
 }
 
+static void xgbe_phy_rx_reset(struct xgbe_prv_data *pdata)
+{
+       int reg;
+
+       reg = XMDIO_READ_BITS(pdata, MDIO_MMD_PCS, MDIO_PCS_DIGITAL_STAT,
+                             XGBE_PCS_PSEQ_STATE_MASK);
+       if (reg == XGBE_PCS_PSEQ_STATE_POWER_GOOD) {
+               /* Mailbox command timed out, reset of RX block is required.
+                * This can be done by asseting the reset bit and wait for
+                * its compeletion.
+                */
+               XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_CTRL1,
+                                XGBE_PMA_RX_RST_0_MASK, XGBE_PMA_RX_RST_0_RESET_ON);
+               ndelay(20);
+               XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_CTRL1,
+                                XGBE_PMA_RX_RST_0_MASK, XGBE_PMA_RX_RST_0_RESET_OFF);
+               usleep_range(40, 50);
+               netif_err(pdata, link, pdata->netdev, "firmware mailbox reset performed\n");
+       }
+}
+
 static void xgbe_phy_perform_ratechange(struct xgbe_prv_data *pdata,
                                        unsigned int cmd, unsigned int sub_cmd)
 {
@@ -1960,9 +1981,11 @@ static void xgbe_phy_perform_ratechange(struct xgbe_prv_data *pdata,
        unsigned int wait;
 
        /* Log if a previous command did not complete */
-       if (XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS))
+       if (XP_IOREAD_BITS(pdata, XP_DRIVER_INT_RO, STATUS)) {
                netif_dbg(pdata, link, pdata->netdev,
                          "firmware mailbox not ready for command\n");
+               xgbe_phy_rx_reset(pdata);
+       }
 
        /* Construct the command */
        XP_SET_BITS(s0, XP_DRIVER_SCRATCH_0, COMMAND, cmd);
@@ -1984,6 +2007,9 @@ static void xgbe_phy_perform_ratechange(struct xgbe_prv_data *pdata,
 
        netif_dbg(pdata, link, pdata->netdev,
                  "firmware mailbox command did not complete\n");
+
+       /* Reset on error */
+       xgbe_phy_rx_reset(pdata);
 }
 
 static void xgbe_phy_rrc(struct xgbe_prv_data *pdata)