net/axgbe: support auto-negotiation for 1Gbps

Added CL37 Auto-neg support for 1Gbps interface in axgbe DPDK driver

Signed-off-by: Girish Nandibasappa <girish.nandibasappa@amd.com>
Acked-by: Ravi Kumar <ravi1.kumar@amd.com>
This commit is contained in:
Girish Nandibasappa 2020-01-10 18:30:11 +05:30 committed by Ferruh Yigit
parent 936e294c8e
commit 102b6ec3d5
3 changed files with 219 additions and 11 deletions

View File

@ -1296,6 +1296,7 @@
#define AXGBE_AN_CL37_PCS_MODE_BASEX 0x00
#define AXGBE_AN_CL37_PCS_MODE_SGMII 0x04
#define AXGBE_AN_CL37_TX_CONFIG_MASK 0x08
#define AXGBE_AN_CL37_MII_CTRL_8BIT 0x0100
#define AXGBE_PMA_CDR_TRACK_EN_MASK 0x01
#define AXGBE_PMA_CDR_TRACK_EN_OFF 0x00

View 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);
@ -302,7 +321,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;
@ -321,7 +340,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;
@ -573,6 +592,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 */
@ -580,6 +646,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 */
@ -593,6 +660,29 @@ 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)
{
switch (pdata->an_mode) {
@ -602,7 +692,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;
@ -614,6 +704,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;
@ -673,7 +805,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;
@ -782,9 +914,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;
@ -792,6 +921,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);
@ -875,10 +1005,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;
@ -896,8 +1042,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))

View File

@ -957,6 +957,41 @@ static enum axgbe_mode axgbe_phy_an73_outcome(struct axgbe_port *pdata)
return mode;
}
static enum axgbe_mode axgbe_phy_an37_sgmii_outcome(struct axgbe_port *pdata)
{
enum axgbe_mode mode;
pdata->phy.lp_advertising |= ADVERTISED_Autoneg;
pdata->phy.lp_advertising |= ADVERTISED_1000baseT_Full;
if (pdata->phy.pause_autoneg)
axgbe_phy_phydev_flowctrl(pdata);
switch (pdata->an_status & AXGBE_SGMII_AN_LINK_SPEED) {
case AXGBE_SGMII_AN_LINK_SPEED_100:
if (pdata->an_status & AXGBE_SGMII_AN_LINK_DUPLEX) {
pdata->phy.lp_advertising |= ADVERTISED_100baseT_Full;
mode = AXGBE_MODE_SGMII_100;
} else {
mode = AXGBE_MODE_UNKNOWN;
}
break;
case AXGBE_SGMII_AN_LINK_SPEED_1000:
if (pdata->an_status & AXGBE_SGMII_AN_LINK_DUPLEX) {
pdata->phy.lp_advertising |= ADVERTISED_1000baseT_Full;
mode = AXGBE_MODE_SGMII_1000;
} else {
/* Half-duplex not supported */
mode = AXGBE_MODE_UNKNOWN;
}
break;
default:
mode = AXGBE_MODE_UNKNOWN;
break;
}
return mode;
}
static enum axgbe_mode axgbe_phy_an_outcome(struct axgbe_port *pdata)
{
switch (pdata->an_mode) {
@ -966,6 +1001,7 @@ static enum axgbe_mode axgbe_phy_an_outcome(struct axgbe_port *pdata)
return axgbe_phy_an73_redrv_outcome(pdata);
case AXGBE_AN_MODE_CL37:
case AXGBE_AN_MODE_CL37_SGMII:
return axgbe_phy_an37_sgmii_outcome(pdata);
default:
return AXGBE_MODE_UNKNOWN;
}
@ -1957,6 +1993,7 @@ static int axgbe_phy_start(struct axgbe_port *pdata)
default:
break;
}
pdata->phy.advertising &= axgbe_phy_an_advertising(pdata);
return ret;
}