amd-xgbe: Add support for clause 37 auto-negotiation
Add support to be able to use clause 37 auto-negotiation. Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
a64def4161
commit
1bf40ada62
|
@ -1027,6 +1027,10 @@
|
|||
#define MDIO_PMA_10GBR_FECCTRL 0x00ab
|
||||
#endif
|
||||
|
||||
#ifndef MDIO_PCS_DIG_CTRL
|
||||
#define MDIO_PCS_DIG_CTRL 0x8000
|
||||
#endif
|
||||
|
||||
#ifndef MDIO_AN_XNP
|
||||
#define MDIO_AN_XNP 0x0016
|
||||
#endif
|
||||
|
@ -1047,10 +1051,34 @@
|
|||
#define MDIO_AN_INT 0x8002
|
||||
#endif
|
||||
|
||||
#ifndef MDIO_VEND2_AN_ADVERTISE
|
||||
#define MDIO_VEND2_AN_ADVERTISE 0x0004
|
||||
#endif
|
||||
|
||||
#ifndef MDIO_VEND2_AN_LP_ABILITY
|
||||
#define MDIO_VEND2_AN_LP_ABILITY 0x0005
|
||||
#endif
|
||||
|
||||
#ifndef MDIO_VEND2_AN_CTRL
|
||||
#define MDIO_VEND2_AN_CTRL 0x8001
|
||||
#endif
|
||||
|
||||
#ifndef MDIO_VEND2_AN_STAT
|
||||
#define MDIO_VEND2_AN_STAT 0x8002
|
||||
#endif
|
||||
|
||||
#ifndef MDIO_CTRL1_SPEED1G
|
||||
#define MDIO_CTRL1_SPEED1G (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100)
|
||||
#endif
|
||||
|
||||
#ifndef MDIO_VEND2_CTRL1_AN_ENABLE
|
||||
#define MDIO_VEND2_CTRL1_AN_ENABLE BIT(12)
|
||||
#endif
|
||||
|
||||
#ifndef MDIO_VEND2_CTRL1_AN_RESTART
|
||||
#define MDIO_VEND2_CTRL1_AN_RESTART BIT(9)
|
||||
#endif
|
||||
|
||||
/* MDIO mask values */
|
||||
#define XGBE_AN_CL73_INT_CMPLT BIT(0)
|
||||
#define XGBE_AN_CL73_INC_LINK BIT(1)
|
||||
|
@ -1065,6 +1093,19 @@
|
|||
#define XGBE_KR_TRAINING_START BIT(0)
|
||||
#define XGBE_KR_TRAINING_ENABLE BIT(1)
|
||||
|
||||
#define XGBE_PCS_CL37_BP BIT(12)
|
||||
|
||||
#define XGBE_AN_CL37_INT_CMPLT BIT(0)
|
||||
#define XGBE_AN_CL37_INT_MASK 0x01
|
||||
|
||||
#define XGBE_AN_CL37_HD_MASK 0x40
|
||||
#define XGBE_AN_CL37_FD_MASK 0x20
|
||||
|
||||
#define XGBE_AN_CL37_PCS_MODE_MASK 0x06
|
||||
#define XGBE_AN_CL37_PCS_MODE_BASEX 0x00
|
||||
#define XGBE_AN_CL37_PCS_MODE_SGMII 0x04
|
||||
#define XGBE_AN_CL37_TX_CONFIG_MASK 0x08
|
||||
|
||||
/* Bit setting and getting macros
|
||||
* The get macro will extract the current bit field value from within
|
||||
* the variable
|
||||
|
|
|
@ -125,6 +125,41 @@
|
|||
#include "xgbe.h"
|
||||
#include "xgbe-common.h"
|
||||
|
||||
static void xgbe_an37_clear_interrupts(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
int reg;
|
||||
|
||||
reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT);
|
||||
reg &= ~XGBE_AN_CL37_INT_MASK;
|
||||
XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT, reg);
|
||||
}
|
||||
|
||||
static void xgbe_an37_disable_interrupts(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
int reg;
|
||||
|
||||
reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL);
|
||||
reg &= ~XGBE_AN_CL37_INT_MASK;
|
||||
XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg);
|
||||
|
||||
reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL);
|
||||
reg &= ~XGBE_PCS_CL37_BP;
|
||||
XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL, reg);
|
||||
}
|
||||
|
||||
static void xgbe_an37_enable_interrupts(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
int reg;
|
||||
|
||||
reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL);
|
||||
reg |= XGBE_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 |= XGBE_AN_CL37_INT_MASK;
|
||||
XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg);
|
||||
}
|
||||
|
||||
static void xgbe_an73_clear_interrupts(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);
|
||||
|
@ -146,11 +181,21 @@ static void xgbe_an_enable_interrupts(struct xgbe_prv_data *pdata)
|
|||
case XGBE_AN_MODE_CL73:
|
||||
xgbe_an73_enable_interrupts(pdata);
|
||||
break;
|
||||
case XGBE_AN_MODE_CL37:
|
||||
case XGBE_AN_MODE_CL37_SGMII:
|
||||
xgbe_an37_enable_interrupts(pdata);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void xgbe_an_clear_interrupts_all(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
xgbe_an73_clear_interrupts(pdata);
|
||||
xgbe_an37_clear_interrupts(pdata);
|
||||
}
|
||||
|
||||
static void xgbe_an73_enable_kr_training(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
unsigned int reg;
|
||||
|
@ -258,6 +303,39 @@ static bool xgbe_use_mode(struct xgbe_prv_data *pdata,
|
|||
return pdata->phy_if.phy_impl.use_mode(pdata, mode);
|
||||
}
|
||||
|
||||
static void xgbe_an37_set(struct xgbe_prv_data *pdata, bool enable,
|
||||
bool restart)
|
||||
{
|
||||
unsigned int reg;
|
||||
|
||||
reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_CTRL1);
|
||||
reg &= ~MDIO_VEND2_CTRL1_AN_ENABLE;
|
||||
|
||||
if (enable)
|
||||
reg |= MDIO_VEND2_CTRL1_AN_ENABLE;
|
||||
|
||||
if (restart)
|
||||
reg |= MDIO_VEND2_CTRL1_AN_RESTART;
|
||||
|
||||
XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_CTRL1, reg);
|
||||
}
|
||||
|
||||
static void xgbe_an37_restart(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
xgbe_an37_enable_interrupts(pdata);
|
||||
xgbe_an37_set(pdata, true, true);
|
||||
|
||||
netif_dbg(pdata, link, pdata->netdev, "CL37 AN enabled/restarted\n");
|
||||
}
|
||||
|
||||
static void xgbe_an37_disable(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
xgbe_an37_set(pdata, false, false);
|
||||
xgbe_an37_disable_interrupts(pdata);
|
||||
|
||||
netif_dbg(pdata, link, pdata->netdev, "CL37 AN disabled\n");
|
||||
}
|
||||
|
||||
static void xgbe_an73_set(struct xgbe_prv_data *pdata, bool enable,
|
||||
bool restart)
|
||||
{
|
||||
|
@ -297,6 +375,10 @@ static void xgbe_an_restart(struct xgbe_prv_data *pdata)
|
|||
case XGBE_AN_MODE_CL73:
|
||||
xgbe_an73_restart(pdata);
|
||||
break;
|
||||
case XGBE_AN_MODE_CL37:
|
||||
case XGBE_AN_MODE_CL37_SGMII:
|
||||
xgbe_an37_restart(pdata);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -308,11 +390,21 @@ static void xgbe_an_disable(struct xgbe_prv_data *pdata)
|
|||
case XGBE_AN_MODE_CL73:
|
||||
xgbe_an73_disable(pdata);
|
||||
break;
|
||||
case XGBE_AN_MODE_CL37:
|
||||
case XGBE_AN_MODE_CL37_SGMII:
|
||||
xgbe_an37_disable(pdata);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void xgbe_an_disable_all(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
xgbe_an73_disable(pdata);
|
||||
xgbe_an37_disable(pdata);
|
||||
}
|
||||
|
||||
static enum xgbe_an xgbe_an73_tx_training(struct xgbe_prv_data *pdata,
|
||||
enum xgbe_rx *state)
|
||||
{
|
||||
|
@ -484,6 +576,30 @@ static enum xgbe_an xgbe_an73_incompat_link(struct xgbe_prv_data *pdata)
|
|||
return XGBE_AN_INCOMPAT_LINK;
|
||||
}
|
||||
|
||||
static void xgbe_an37_isr(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
unsigned int reg;
|
||||
|
||||
/* Disable AN interrupts */
|
||||
xgbe_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 & XGBE_AN_CL37_INT_MASK;
|
||||
pdata->an_status = reg & ~XGBE_AN_CL37_INT_MASK;
|
||||
|
||||
if (pdata->an_int) {
|
||||
/* Clear the interrupt(s) that fired and process them */
|
||||
reg &= ~XGBE_AN_CL37_INT_MASK;
|
||||
XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT, reg);
|
||||
|
||||
queue_work(pdata->an_workqueue, &pdata->an_irq_work);
|
||||
} else {
|
||||
/* Enable AN interrupts */
|
||||
xgbe_an37_enable_interrupts(pdata);
|
||||
}
|
||||
}
|
||||
|
||||
static void xgbe_an73_isr(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
/* Disable AN interrupts */
|
||||
|
@ -513,6 +629,10 @@ static irqreturn_t xgbe_an_isr(int irq, void *data)
|
|||
case XGBE_AN_MODE_CL73:
|
||||
xgbe_an73_isr(pdata);
|
||||
break;
|
||||
case XGBE_AN_MODE_CL37:
|
||||
case XGBE_AN_MODE_CL37_SGMII:
|
||||
xgbe_an37_isr(pdata);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -553,6 +673,64 @@ static const char *xgbe_state_as_string(enum xgbe_an state)
|
|||
}
|
||||
}
|
||||
|
||||
static void xgbe_an37_state_machine(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
enum xgbe_an cur_state = pdata->an_state;
|
||||
|
||||
if (!pdata->an_int)
|
||||
return;
|
||||
|
||||
if (pdata->an_int & XGBE_AN_CL37_INT_CMPLT) {
|
||||
pdata->an_state = XGBE_AN_COMPLETE;
|
||||
pdata->an_int &= ~XGBE_AN_CL37_INT_CMPLT;
|
||||
|
||||
/* If SGMII is enabled, check the link status */
|
||||
if ((pdata->an_mode == XGBE_AN_MODE_CL37_SGMII) &&
|
||||
!(pdata->an_status & XGBE_SGMII_AN_LINK_STATUS))
|
||||
pdata->an_state = XGBE_AN_NO_LINK;
|
||||
}
|
||||
|
||||
netif_dbg(pdata, link, pdata->netdev, "CL37 AN %s\n",
|
||||
xgbe_state_as_string(pdata->an_state));
|
||||
|
||||
cur_state = pdata->an_state;
|
||||
|
||||
switch (pdata->an_state) {
|
||||
case XGBE_AN_READY:
|
||||
break;
|
||||
|
||||
case XGBE_AN_COMPLETE:
|
||||
netif_dbg(pdata, link, pdata->netdev,
|
||||
"Auto negotiation successful\n");
|
||||
break;
|
||||
|
||||
case XGBE_AN_NO_LINK:
|
||||
break;
|
||||
|
||||
default:
|
||||
pdata->an_state = XGBE_AN_ERROR;
|
||||
}
|
||||
|
||||
if (pdata->an_state == XGBE_AN_ERROR) {
|
||||
netdev_err(pdata->netdev,
|
||||
"error during auto-negotiation, state=%u\n",
|
||||
cur_state);
|
||||
|
||||
pdata->an_int = 0;
|
||||
xgbe_an37_clear_interrupts(pdata);
|
||||
}
|
||||
|
||||
if (pdata->an_state >= XGBE_AN_COMPLETE) {
|
||||
pdata->an_result = pdata->an_state;
|
||||
pdata->an_state = XGBE_AN_READY;
|
||||
|
||||
netif_dbg(pdata, link, pdata->netdev, "CL37 AN result: %s\n",
|
||||
xgbe_state_as_string(pdata->an_result));
|
||||
}
|
||||
|
||||
xgbe_an37_enable_interrupts(pdata);
|
||||
}
|
||||
|
||||
static void xgbe_an73_state_machine(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
enum xgbe_an cur_state = pdata->an_state;
|
||||
|
@ -574,8 +752,6 @@ next_int:
|
|||
pdata->an_state = XGBE_AN_ERROR;
|
||||
}
|
||||
|
||||
pdata->an_result = pdata->an_state;
|
||||
|
||||
again:
|
||||
netif_dbg(pdata, link, pdata->netdev, "CL73 AN %s\n",
|
||||
xgbe_state_as_string(pdata->an_state));
|
||||
|
@ -656,6 +832,10 @@ static void xgbe_an_state_machine(struct work_struct *work)
|
|||
case XGBE_AN_MODE_CL73:
|
||||
xgbe_an73_state_machine(pdata);
|
||||
break;
|
||||
case XGBE_AN_MODE_CL37:
|
||||
case XGBE_AN_MODE_CL37_SGMII:
|
||||
xgbe_an37_state_machine(pdata);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -663,6 +843,50 @@ static void xgbe_an_state_machine(struct work_struct *work)
|
|||
mutex_unlock(&pdata->an_mutex);
|
||||
}
|
||||
|
||||
static void xgbe_an37_init(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
unsigned int reg;
|
||||
|
||||
/* Set up Advertisement register */
|
||||
reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE);
|
||||
if (pdata->phy.advertising & ADVERTISED_Pause)
|
||||
reg |= 0x100;
|
||||
else
|
||||
reg &= ~0x100;
|
||||
|
||||
if (pdata->phy.advertising & ADVERTISED_Asym_Pause)
|
||||
reg |= 0x80;
|
||||
else
|
||||
reg &= ~0x80;
|
||||
|
||||
/* Full duplex, but not half */
|
||||
reg |= XGBE_AN_CL37_FD_MASK;
|
||||
reg &= ~XGBE_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 &= XGBE_AN_CL37_TX_CONFIG_MASK;
|
||||
reg &= XGBE_AN_CL37_PCS_MODE_MASK;
|
||||
|
||||
switch (pdata->an_mode) {
|
||||
case XGBE_AN_MODE_CL37:
|
||||
reg |= XGBE_AN_CL37_PCS_MODE_BASEX;
|
||||
break;
|
||||
case XGBE_AN_MODE_CL37_SGMII:
|
||||
reg |= XGBE_AN_CL37_PCS_MODE_SGMII;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg);
|
||||
|
||||
netif_dbg(pdata, link, pdata->netdev, "CL37 AN (%s) initialized\n",
|
||||
(pdata->an_mode == XGBE_AN_MODE_CL37) ? "BaseX" : "SGMII");
|
||||
}
|
||||
|
||||
static void xgbe_an73_init(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
unsigned int reg;
|
||||
|
@ -719,6 +943,10 @@ static void xgbe_an_init(struct xgbe_prv_data *pdata)
|
|||
case XGBE_AN_MODE_CL73:
|
||||
xgbe_an73_init(pdata);
|
||||
break;
|
||||
case XGBE_AN_MODE_CL37:
|
||||
case XGBE_AN_MODE_CL37_SGMII:
|
||||
xgbe_an37_init(pdata);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -865,10 +1093,10 @@ static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
|
|||
}
|
||||
|
||||
/* Disable and stop any in progress auto-negotiation */
|
||||
xgbe_an_disable(pdata);
|
||||
xgbe_an_disable_all(pdata);
|
||||
|
||||
/* Clear any auto-negotitation interrupts */
|
||||
xgbe_an73_clear_interrupts(pdata);
|
||||
xgbe_an_clear_interrupts_all(pdata);
|
||||
|
||||
pdata->an_result = XGBE_AN_READY;
|
||||
pdata->an_state = XGBE_AN_READY;
|
||||
|
@ -1007,7 +1235,7 @@ static void xgbe_phy_stop(struct xgbe_prv_data *pdata)
|
|||
pdata->phy_started = 0;
|
||||
|
||||
/* Disable auto-negotiation */
|
||||
xgbe_an_disable(pdata);
|
||||
xgbe_an_disable_all(pdata);
|
||||
|
||||
devm_free_irq(pdata->dev, pdata->an_irq, pdata);
|
||||
|
||||
|
@ -1078,10 +1306,10 @@ static int xgbe_phy_reset(struct xgbe_prv_data *pdata)
|
|||
return ret;
|
||||
|
||||
/* Disable auto-negotiation for now */
|
||||
xgbe_an_disable(pdata);
|
||||
xgbe_an_disable_all(pdata);
|
||||
|
||||
/* Clear auto-negotiation interrupts */
|
||||
xgbe_an73_clear_interrupts(pdata);
|
||||
xgbe_an_clear_interrupts_all(pdata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -261,7 +261,13 @@
|
|||
|
||||
/* Auto-negotiation */
|
||||
#define XGBE_AN_MS_TIMEOUT 500
|
||||
#define XGBE_LINK_TIMEOUT 10
|
||||
#define XGBE_LINK_TIMEOUT 5
|
||||
|
||||
#define XGBE_SGMII_AN_LINK_STATUS BIT(1)
|
||||
#define XGBE_SGMII_AN_LINK_SPEED (BIT(2) | BIT(3))
|
||||
#define XGBE_SGMII_AN_LINK_SPEED_100 0x04
|
||||
#define XGBE_SGMII_AN_LINK_SPEED_1000 0x08
|
||||
#define XGBE_SGMII_AN_LINK_DUPLEX BIT(4)
|
||||
|
||||
struct xgbe_prv_data;
|
||||
|
||||
|
@ -467,6 +473,8 @@ enum xgbe_speed {
|
|||
|
||||
enum xgbe_an_mode {
|
||||
XGBE_AN_MODE_CL73 = 0,
|
||||
XGBE_AN_MODE_CL37,
|
||||
XGBE_AN_MODE_CL37_SGMII,
|
||||
XGBE_AN_MODE_NONE,
|
||||
};
|
||||
|
||||
|
@ -961,6 +969,7 @@ struct xgbe_prv_data {
|
|||
|
||||
/* Auto-negotiation state machine support */
|
||||
unsigned int an_int;
|
||||
unsigned int an_status;
|
||||
struct mutex an_mutex;
|
||||
enum xgbe_an an_result;
|
||||
enum xgbe_an an_state;
|
||||
|
|
Loading…
Reference in New Issue