net/axgbe: add debug logs
[dpdk.git] / drivers / net / axgbe / axgbe_mdio.c
index 914f34f..0f226c3 100644 (file)
@@ -29,6 +29,19 @@ static void axgbe_an37_disable_interrupts(struct axgbe_port *pdata)
        XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL, reg);
 }
 
+static void axgbe_an37_enable_interrupts(struct axgbe_port *pdata)
+{
+       unsigned int reg;
+
+       reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL);
+       reg |= AXGBE_PCS_CL37_BP;
+       XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL, reg);
+
+       reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL);
+       reg |= AXGBE_AN_CL37_INT_MASK;
+       XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg);
+}
+
 static void axgbe_an73_clear_interrupts(struct axgbe_port *pdata)
 {
        XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);
@@ -54,7 +67,7 @@ static void axgbe_an_enable_interrupts(struct axgbe_port *pdata)
                break;
        case AXGBE_AN_MODE_CL37:
        case AXGBE_AN_MODE_CL37_SGMII:
-               PMD_DRV_LOG(ERR, "Unsupported AN_MOD_37\n");
+               axgbe_an37_enable_interrupts(pdata);
                break;
        default:
                break;
@@ -254,6 +267,12 @@ static void axgbe_an37_set(struct axgbe_port *pdata, bool enable,
        XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_CTRL1, reg);
 }
 
+static void axgbe_an37_restart(struct axgbe_port *pdata)
+{
+       axgbe_an37_enable_interrupts(pdata);
+       axgbe_an37_set(pdata, true, true);
+}
+
 static void axgbe_an37_disable(struct axgbe_port *pdata)
 {
        axgbe_an37_set(pdata, false, false);
@@ -281,16 +300,24 @@ static void axgbe_an73_restart(struct axgbe_port *pdata)
 {
        axgbe_an73_enable_interrupts(pdata);
        axgbe_an73_set(pdata, true, true);
+
+       PMD_DRV_LOG(DEBUG, "CL73 AN enabled/restarted\n");
 }
 
 static void axgbe_an73_disable(struct axgbe_port *pdata)
 {
        axgbe_an73_set(pdata, false, false);
        axgbe_an73_disable_interrupts(pdata);
+       pdata->an_start = 0;
+
+       PMD_DRV_LOG(DEBUG, "CL73 AN disabled\n");
 }
 
 static void axgbe_an_restart(struct axgbe_port *pdata)
 {
+       if (pdata->phy_if.phy_impl.an_pre)
+               pdata->phy_if.phy_impl.an_pre(pdata);
+
        switch (pdata->an_mode) {
        case AXGBE_AN_MODE_CL73:
        case AXGBE_AN_MODE_CL73_REDRV:
@@ -298,7 +325,7 @@ static void axgbe_an_restart(struct axgbe_port *pdata)
                break;
        case AXGBE_AN_MODE_CL37:
        case AXGBE_AN_MODE_CL37_SGMII:
-               PMD_DRV_LOG(ERR, "Unsupported AN_MODE_CL37\n");
+               axgbe_an37_restart(pdata);
                break;
        default:
                break;
@@ -307,6 +334,9 @@ static void axgbe_an_restart(struct axgbe_port *pdata)
 
 static void axgbe_an_disable(struct axgbe_port *pdata)
 {
+       if (pdata->phy_if.phy_impl.an_post)
+               pdata->phy_if.phy_impl.an_post(pdata);
+
        switch (pdata->an_mode) {
        case AXGBE_AN_MODE_CL73:
        case AXGBE_AN_MODE_CL73_REDRV:
@@ -314,7 +344,7 @@ static void axgbe_an_disable(struct axgbe_port *pdata)
                break;
        case AXGBE_AN_MODE_CL37:
        case AXGBE_AN_MODE_CL37_SGMII:
-               PMD_DRV_LOG(ERR, "Unsupported AN_MODE_CL37\n");
+               axgbe_an37_disable(pdata);
                break;
        default:
                break;
@@ -358,6 +388,8 @@ static enum axgbe_an axgbe_an73_tx_training(struct axgbe_port *pdata,
                XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL,
                            reg);
 
+               PMD_DRV_LOG(DEBUG, "KR training initiated\n");
+
                if (pdata->phy_if.phy_impl.kr_training_post)
                        pdata->phy_if.phy_impl.kr_training_post(pdata);
        }
@@ -440,6 +472,9 @@ static enum axgbe_an axgbe_an73_page_received(struct axgbe_port *pdata)
                        pdata->kx_state = AXGBE_RX_BPA;
 
                        pdata->an_start = rte_get_timer_cycles();
+
+                       PMD_DRV_LOG(NOTICE,
+                                   "CL73 AN timed out, resetting state\n");
                }
        }
 
@@ -482,13 +517,33 @@ static enum axgbe_an axgbe_an73_incompat_link(struct axgbe_port *pdata)
                        return AXGBE_AN_NO_LINK;
        }
 
-       axgbe_an73_disable(pdata);
+       axgbe_an_disable(pdata);
        axgbe_switch_mode(pdata);
-       axgbe_an73_restart(pdata);
+       axgbe_an_restart(pdata);
 
        return AXGBE_AN_INCOMPAT_LINK;
 }
 
+static const char *axgbe_state_as_string(enum axgbe_an state)
+{
+       switch (state) {
+       case AXGBE_AN_READY:
+               return "Ready";
+       case AXGBE_AN_PAGE_RECEIVED:
+               return "Page-Received";
+       case AXGBE_AN_INCOMPAT_LINK:
+               return "Incompatible-Link";
+       case AXGBE_AN_COMPLETE:
+               return "Complete";
+       case AXGBE_AN_NO_LINK:
+               return "No-Link";
+       case AXGBE_AN_ERROR:
+               return "Error";
+       default:
+               return "Undefined";
+       }
+}
+
 static void axgbe_an73_state_machine(struct axgbe_port *pdata)
 {
        enum axgbe_an cur_state = pdata->an_state;
@@ -510,6 +565,9 @@ next_int:
                pdata->an_state = AXGBE_AN_ERROR;
        }
 
+       PMD_DRV_LOG(DEBUG, "CL73 AN : %s\n",
+                   axgbe_state_as_string(pdata->an_state));
+
 again:
        cur_state = pdata->an_state;
 
@@ -553,6 +611,11 @@ again:
                pdata->kr_state = AXGBE_RX_BPA;
                pdata->kx_state = AXGBE_RX_BPA;
                pdata->an_start = 0;
+               if (pdata->phy_if.phy_impl.an_post)
+                       pdata->phy_if.phy_impl.an_post(pdata);
+
+               PMD_DRV_LOG(DEBUG, "CL73 AN result: %s\n",
+                           axgbe_state_as_string(pdata->an_result));
        }
 
        if (cur_state != pdata->an_state)
@@ -564,6 +627,53 @@ again:
        axgbe_an73_enable_interrupts(pdata);
 }
 
+static void axgbe_an37_state_machine(struct axgbe_port *pdata)
+{
+       enum axgbe_an cur_state = pdata->an_state;
+
+       if (!pdata->an_int)
+               return;
+       if (pdata->an_int & AXGBE_AN_CL37_INT_CMPLT) {
+               pdata->an_state = AXGBE_AN_COMPLETE;
+               pdata->an_int &= ~AXGBE_AN_CL37_INT_CMPLT;
+
+       /* If SGMII is enabled, check the link status */
+               if (pdata->an_mode == AXGBE_AN_MODE_CL37_SGMII &&
+                   !(pdata->an_status & AXGBE_SGMII_AN_LINK_STATUS))
+                       pdata->an_state = AXGBE_AN_NO_LINK;
+       }
+
+       cur_state = pdata->an_state;
+
+       switch (pdata->an_state) {
+       case AXGBE_AN_READY:
+               break;
+       case AXGBE_AN_COMPLETE:
+               break;
+       case AXGBE_AN_NO_LINK:
+               break;
+       default:
+               pdata->an_state = AXGBE_AN_ERROR;
+               break;
+       }
+
+       if (pdata->an_state == AXGBE_AN_ERROR) {
+               PMD_DRV_LOG(ERR, "error during auto-negotiation, state=%u\n",
+                           cur_state);
+               pdata->an_int = 0;
+               axgbe_an37_clear_interrupts(pdata);
+       }
+
+       if (pdata->an_state >= AXGBE_AN_COMPLETE) {
+               pdata->an_result = pdata->an_state;
+               pdata->an_state = AXGBE_AN_READY;
+               if (pdata->phy_if.phy_impl.an_post)
+                       pdata->phy_if.phy_impl.an_post(pdata);
+       }
+
+       axgbe_an37_enable_interrupts(pdata);
+}
+
 static void axgbe_an73_isr(struct axgbe_port *pdata)
 {
        /* Disable AN interrupts */
@@ -571,6 +681,7 @@ static void axgbe_an73_isr(struct axgbe_port *pdata)
 
        /* Save the interrupt(s) that fired */
        pdata->an_int = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INT);
+       axgbe_an73_clear_interrupts(pdata);
 
        if (pdata->an_int) {
                /* Clear the interrupt(s) that fired and process them */
@@ -584,8 +695,33 @@ static void axgbe_an73_isr(struct axgbe_port *pdata)
        }
 }
 
+static void axgbe_an37_isr(struct axgbe_port *pdata)
+{
+       unsigned int reg = 0;
+       /* Disable AN interrupts */
+       axgbe_an37_disable_interrupts(pdata);
+
+       /* Save the interrupt(s) that fired */
+       reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT);
+       pdata->an_int = reg & AXGBE_AN_CL37_INT_MASK;
+       pdata->an_status = reg & ~AXGBE_AN_CL37_INT_MASK;
+       axgbe_an37_clear_interrupts(pdata);
+
+       if (pdata->an_int & 0x01) {
+               /* Clear the interrupt(s) that fired and process them */
+               reg &= ~AXGBE_AN_CL37_INT_MASK;
+               XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT, reg);
+               axgbe_an37_state_machine(pdata);
+       } else {
+               /* Enable AN interrupts */
+               axgbe_an37_enable_interrupts(pdata);
+       }
+}
+
 static void axgbe_an_isr(struct axgbe_port *pdata)
 {
+       PMD_DRV_LOG(DEBUG, "AN interrupt received\n");
+
        switch (pdata->an_mode) {
        case AXGBE_AN_MODE_CL73:
        case AXGBE_AN_MODE_CL73_REDRV:
@@ -593,7 +729,7 @@ static void axgbe_an_isr(struct axgbe_port *pdata)
                break;
        case AXGBE_AN_MODE_CL37:
        case AXGBE_AN_MODE_CL37_SGMII:
-               PMD_DRV_LOG(ERR, "AN_MODE_37 not supported\n");
+               axgbe_an37_isr(pdata);
                break;
        default:
                break;
@@ -605,6 +741,48 @@ static void axgbe_an_combined_isr(struct axgbe_port *pdata)
        axgbe_an_isr(pdata);
 }
 
+static void axgbe_an37_init(struct axgbe_port *pdata)
+{
+       unsigned int advertising;
+       unsigned int reg = 0;
+
+       advertising = pdata->phy_if.phy_impl.an_advertising(pdata);
+
+       reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE);
+       if (advertising & ADVERTISED_Pause)
+               reg |= 0x100;
+       else
+               reg &= ~0x100;
+       if (advertising & ADVERTISED_Asym_Pause)
+               reg |= 0x80;
+       else
+               reg &= ~0x80;
+
+       /* Full duplex, but not half */
+       reg |= AXGBE_AN_CL37_FD_MASK;
+       reg &= ~AXGBE_AN_CL37_HD_MASK;
+
+       XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE, reg);
+
+       /* Set up the Control register */
+       reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL);
+       reg &= ~AXGBE_AN_CL37_TX_CONFIG_MASK;
+       reg &= ~AXGBE_AN_CL37_PCS_MODE_MASK;
+
+       switch (pdata->an_mode) {
+       case AXGBE_AN_MODE_CL37:
+               reg |= AXGBE_AN_CL37_PCS_MODE_BASEX;
+               break;
+       case AXGBE_AN_MODE_CL37_SGMII:
+               reg |= AXGBE_AN_CL37_PCS_MODE_SGMII;
+               break;
+       default:
+               break;
+       }
+       reg |= AXGBE_AN_CL37_MII_CTRL_8BIT;
+       XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg);
+}
+
 static void axgbe_an73_init(struct axgbe_port *pdata)
 {
        unsigned int advertising, reg;
@@ -651,6 +829,8 @@ static void axgbe_an73_init(struct axgbe_port *pdata)
        reg &= ~AXGBE_XNP_NP_EXCHANGE;
 
        XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg);
+
+       PMD_DRV_LOG(DEBUG, "CL73 AN initialized\n");
 }
 
 static void axgbe_an_init(struct axgbe_port *pdata)
@@ -664,7 +844,7 @@ static void axgbe_an_init(struct axgbe_port *pdata)
                break;
        case AXGBE_AN_MODE_CL37:
        case AXGBE_AN_MODE_CL37_SGMII:
-               PMD_DRV_LOG(ERR, "Unsupported AN_CL37\n");
+               axgbe_an37_init(pdata);
                break;
        default:
                break;
@@ -674,6 +854,19 @@ static void axgbe_an_init(struct axgbe_port *pdata)
 static void axgbe_phy_adjust_link(struct axgbe_port *pdata)
 {
        if (pdata->phy.link) {
+               /* Flow control support */
+               pdata->pause_autoneg = pdata->phy.pause_autoneg;
+
+               if (pdata->tx_pause != (unsigned int)pdata->phy.tx_pause) {
+                       pdata->hw_if.config_tx_flow_control(pdata);
+                       pdata->tx_pause = pdata->phy.tx_pause;
+               }
+
+               if (pdata->rx_pause != (unsigned int)pdata->phy.rx_pause) {
+                       pdata->hw_if.config_rx_flow_control(pdata);
+                       pdata->rx_pause = pdata->phy.rx_pause;
+               }
+
                /* Speed support */
                if (pdata->phy_speed != pdata->phy.speed)
                        pdata->phy_speed = pdata->phy.speed;
@@ -689,6 +882,8 @@ static int axgbe_phy_config_fixed(struct axgbe_port *pdata)
 {
        enum axgbe_mode mode;
 
+       PMD_DRV_LOG(DEBUG, "fixed PHY configuration\n");
+
        /* Disable auto-negotiation */
        axgbe_an_disable(pdata);
 
@@ -732,6 +927,9 @@ static int __axgbe_phy_config_aneg(struct axgbe_port *pdata)
                ret = axgbe_phy_config_fixed(pdata);
                if (ret || !pdata->kr_redrv)
                        return ret;
+               PMD_DRV_LOG(DEBUG, "AN redriver support\n");
+       } else {
+               PMD_DRV_LOG(DEBUG, "AN PHY configuration\n");
        }
 
        /* Disable auto-negotiation interrupt */
@@ -760,9 +958,6 @@ static int __axgbe_phy_config_aneg(struct axgbe_port *pdata)
        /* Disable and stop any in progress auto-negotiation */
        axgbe_an_disable_all(pdata);
 
-       /* Clear any auto-negotitation interrupts */
-       axgbe_an_clear_interrupts_all(pdata);
-
        pdata->an_result = AXGBE_AN_READY;
        pdata->an_state = AXGBE_AN_READY;
        pdata->kr_state = AXGBE_RX_BPA;
@@ -770,6 +965,7 @@ static int __axgbe_phy_config_aneg(struct axgbe_port *pdata)
 
        /* Re-enable auto-negotiation interrupt */
        rte_intr_enable(&pdata->pci_dev->intr_handle);
+       axgbe_an37_enable_interrupts(pdata);
 
        axgbe_an_init(pdata);
        axgbe_an_restart(pdata);
@@ -807,8 +1003,10 @@ static void axgbe_check_link_timeout(struct axgbe_port *pdata)
        link_timeout = pdata->link_check + (AXGBE_LINK_TIMEOUT *
                                            2 *  rte_get_timer_hz());
        ticks = rte_get_timer_cycles();
-       if (time_after(ticks, link_timeout))
+       if (time_after(ticks, link_timeout)) {
+               PMD_DRV_LOG(NOTICE, "AN link timeout\n");
                axgbe_phy_config_aneg(pdata);
+       }
 }
 
 static enum axgbe_mode axgbe_phy_status_aneg(struct axgbe_port *pdata)
@@ -853,10 +1051,26 @@ static void axgbe_phy_status_result(struct axgbe_port *pdata)
        axgbe_set_mode(pdata, mode);
 }
 
+static int autoneg_time_out(unsigned long autoneg_start_time)
+{
+       unsigned long autoneg_timeout;
+       unsigned long ticks;
+
+       autoneg_timeout = autoneg_start_time + (AXGBE_LINK_TIMEOUT *
+                                               2 *  rte_get_timer_hz());
+       ticks = rte_get_timer_cycles();
+       if (time_after(ticks, autoneg_timeout))
+               return 1;
+       else
+               return 0;
+}
+
 static void axgbe_phy_status(struct axgbe_port *pdata)
 {
        unsigned int link_aneg;
-       int an_restart;
+       int an_restart, ret;
+       unsigned int reg = 0;
+       unsigned long autoneg_start_time;
 
        if (axgbe_test_bit(AXGBE_LINK_ERR, &pdata->dev_state)) {
                pdata->phy.link = 0;
@@ -874,8 +1088,32 @@ static void axgbe_phy_status(struct axgbe_port *pdata)
 
        if (pdata->phy.link) {
                if (link_aneg && !axgbe_phy_aneg_done(pdata)) {
-                       axgbe_check_link_timeout(pdata);
-                       return;
+                       if (axgbe_cur_mode(pdata) == AXGBE_MODE_SGMII_1000) {
+                               /* autoneg not complete, so re-initializing */
+                               /* and restarting it */
+                               axgbe_an_init(pdata);
+                               axgbe_an_restart(pdata);
+                               reg = XMDIO_READ(pdata, MDIO_MMD_VEND2,
+                                                MDIO_VEND2_AN_STAT);
+                               autoneg_start_time = rte_get_timer_cycles();
+                               /* poll for autoneg to complete */
+                               while (!(reg & AXGBE_AN_CL37_INT_CMPLT)) {
+                                       ret =
+                                       autoneg_time_out(autoneg_start_time);
+                                       if (ret)
+                                               break;
+                                       reg = XMDIO_READ(pdata,
+                                                        MDIO_MMD_VEND2,
+                                                        MDIO_VEND2_AN_STAT);
+                                       if (reg & AXGBE_AN_CL37_INT_CMPLT) {
+                                               axgbe_an37_isr(pdata);
+                                               break;
+                                       }
+                               }
+                       } else {
+                               axgbe_check_link_timeout(pdata);
+                               return;
+                       }
                }
                axgbe_phy_status_result(pdata);
                if (axgbe_test_bit(AXGBE_LINK_INIT, &pdata->dev_state))
@@ -896,6 +1134,7 @@ adjust_link:
 
 static void axgbe_phy_stop(struct axgbe_port *pdata)
 {
+       PMD_DRV_LOG(DEBUG, "stopping PHY\n");
        if (!pdata->phy_started)
                return;
        /* Indicate the PHY is down */
@@ -911,6 +1150,8 @@ static int axgbe_phy_start(struct axgbe_port *pdata)
 {
        int ret;
 
+       PMD_DRV_LOG(DEBUG, "starting PHY\n");
+
        ret = pdata->phy_if.phy_impl.start(pdata);
        if (ret)
                return ret;