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);
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;
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);
{
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:
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;
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:
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;
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);
}
pdata->kx_state = AXGBE_RX_BPA;
pdata->an_start = rte_get_timer_cycles();
+
+ PMD_DRV_LOG(NOTICE,
+ "CL73 AN timed out, resetting state\n");
}
}
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;
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;
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)
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 */
/* 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 */
}
}
+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:
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;
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;
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)
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;
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;
{
enum axgbe_mode mode;
+ PMD_DRV_LOG(DEBUG, "fixed PHY configuration\n");
+
/* Disable auto-negotiation */
axgbe_an_disable(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 */
/* 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;
/* 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);
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)
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;
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))
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 */
{
int ret;
+ PMD_DRV_LOG(DEBUG, "starting PHY\n");
+
ret = pdata->phy_if.phy_impl.start(pdata);
if (ret)
return ret;