mirror of
https://github.com/torvalds/linux.git
synced 2024-11-30 08:01:59 +00:00
amd-xgbe: Improve KR auto-negotiation and training
Update xgbe-phy-v2.c to make use of the auto-negotiation (AN) phy hooks to improve the ability to successfully complete Clause 73 AN when running at 10gbps. Hardware can sometimes have issues with CDR lock when the AN DME page exchange is being performed. The AN and KR training hooks are used as follows: - The pre AN hook is used to disable CDR tracking in the PHY so that the DME page exchange can be successfully and consistently completed. - The post KR training hook is used to re-enable the CDR tracking so that KR training can successfully complete. - The post AN hook is used to check for an unsuccessful AN which will increase a CDR tracking enablement delay (up to a maximum value). Add two debugfs entries to allow control over use of the CDR tracking workaround. The debugfs entries allow the CDR tracking workaround to be disabled and determine whether to re-enable CDR tracking before or after link training has been initiated. Also, with these changes the receiver reset cycle that is performed during the link status check can be performed less often. Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
4d945663a6
commit
96f4d430c5
@ -1321,6 +1321,10 @@
|
|||||||
#define MDIO_VEND2_AN_STAT 0x8002
|
#define MDIO_VEND2_AN_STAT 0x8002
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef MDIO_VEND2_PMA_CDR_CONTROL
|
||||||
|
#define MDIO_VEND2_PMA_CDR_CONTROL 0x8056
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef MDIO_CTRL1_SPEED1G
|
#ifndef MDIO_CTRL1_SPEED1G
|
||||||
#define MDIO_CTRL1_SPEED1G (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100)
|
#define MDIO_CTRL1_SPEED1G (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100)
|
||||||
#endif
|
#endif
|
||||||
@ -1369,6 +1373,10 @@
|
|||||||
#define XGBE_AN_CL37_TX_CONFIG_MASK 0x08
|
#define XGBE_AN_CL37_TX_CONFIG_MASK 0x08
|
||||||
#define XGBE_AN_CL37_MII_CTRL_8BIT 0x0100
|
#define XGBE_AN_CL37_MII_CTRL_8BIT 0x0100
|
||||||
|
|
||||||
|
#define XGBE_PMA_CDR_TRACK_EN_MASK 0x01
|
||||||
|
#define XGBE_PMA_CDR_TRACK_EN_OFF 0x00
|
||||||
|
#define XGBE_PMA_CDR_TRACK_EN_ON 0x01
|
||||||
|
|
||||||
/* Bit setting and getting macros
|
/* Bit setting and getting macros
|
||||||
* The get macro will extract the current bit field value from within
|
* The get macro will extract the current bit field value from within
|
||||||
* the variable
|
* the variable
|
||||||
|
@ -519,6 +519,22 @@ void xgbe_debugfs_init(struct xgbe_prv_data *pdata)
|
|||||||
"debugfs_create_file failed\n");
|
"debugfs_create_file failed\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pdata->vdata->an_cdr_workaround) {
|
||||||
|
pfile = debugfs_create_bool("an_cdr_workaround", 0600,
|
||||||
|
pdata->xgbe_debugfs,
|
||||||
|
&pdata->debugfs_an_cdr_workaround);
|
||||||
|
if (!pfile)
|
||||||
|
netdev_err(pdata->netdev,
|
||||||
|
"debugfs_create_bool failed\n");
|
||||||
|
|
||||||
|
pfile = debugfs_create_bool("an_cdr_track_early", 0600,
|
||||||
|
pdata->xgbe_debugfs,
|
||||||
|
&pdata->debugfs_an_cdr_track_early);
|
||||||
|
if (!pfile)
|
||||||
|
netdev_err(pdata->netdev,
|
||||||
|
"debugfs_create_bool failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
kfree(buf);
|
kfree(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,6 +349,7 @@ int xgbe_config_netdev(struct xgbe_prv_data *pdata)
|
|||||||
XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, UDP4TE, 1);
|
XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, UDP4TE, 1);
|
||||||
|
|
||||||
/* Call MDIO/PHY initialization routine */
|
/* Call MDIO/PHY initialization routine */
|
||||||
|
pdata->debugfs_an_cdr_workaround = pdata->vdata->an_cdr_workaround;
|
||||||
ret = pdata->phy_if.phy_init(pdata);
|
ret = pdata->phy_if.phy_init(pdata);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -432,6 +432,8 @@ static void xgbe_an73_disable(struct xgbe_prv_data *pdata)
|
|||||||
xgbe_an73_set(pdata, false, false);
|
xgbe_an73_set(pdata, false, false);
|
||||||
xgbe_an73_disable_interrupts(pdata);
|
xgbe_an73_disable_interrupts(pdata);
|
||||||
|
|
||||||
|
pdata->an_start = 0;
|
||||||
|
|
||||||
netif_dbg(pdata, link, pdata->netdev, "CL73 AN disabled\n");
|
netif_dbg(pdata, link, pdata->netdev, "CL73 AN disabled\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -511,11 +513,11 @@ static enum xgbe_an xgbe_an73_tx_training(struct xgbe_prv_data *pdata,
|
|||||||
XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL,
|
XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL,
|
||||||
reg);
|
reg);
|
||||||
|
|
||||||
if (pdata->phy_if.phy_impl.kr_training_post)
|
|
||||||
pdata->phy_if.phy_impl.kr_training_post(pdata);
|
|
||||||
|
|
||||||
netif_dbg(pdata, link, pdata->netdev,
|
netif_dbg(pdata, link, pdata->netdev,
|
||||||
"KR training initiated\n");
|
"KR training initiated\n");
|
||||||
|
|
||||||
|
if (pdata->phy_if.phy_impl.kr_training_post)
|
||||||
|
pdata->phy_if.phy_impl.kr_training_post(pdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
return XGBE_AN_PAGE_RECEIVED;
|
return XGBE_AN_PAGE_RECEIVED;
|
||||||
|
@ -456,6 +456,7 @@ static const struct xgbe_version_data xgbe_v2a = {
|
|||||||
.irq_reissue_support = 1,
|
.irq_reissue_support = 1,
|
||||||
.tx_desc_prefetch = 5,
|
.tx_desc_prefetch = 5,
|
||||||
.rx_desc_prefetch = 5,
|
.rx_desc_prefetch = 5,
|
||||||
|
.an_cdr_workaround = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct xgbe_version_data xgbe_v2b = {
|
static const struct xgbe_version_data xgbe_v2b = {
|
||||||
@ -470,6 +471,7 @@ static const struct xgbe_version_data xgbe_v2b = {
|
|||||||
.irq_reissue_support = 1,
|
.irq_reissue_support = 1,
|
||||||
.tx_desc_prefetch = 5,
|
.tx_desc_prefetch = 5,
|
||||||
.rx_desc_prefetch = 5,
|
.rx_desc_prefetch = 5,
|
||||||
|
.an_cdr_workaround = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct pci_device_id xgbe_pci_table[] = {
|
static const struct pci_device_id xgbe_pci_table[] = {
|
||||||
|
@ -147,6 +147,14 @@
|
|||||||
/* Rate-change complete wait/retry count */
|
/* Rate-change complete wait/retry count */
|
||||||
#define XGBE_RATECHANGE_COUNT 500
|
#define XGBE_RATECHANGE_COUNT 500
|
||||||
|
|
||||||
|
/* CDR delay values for KR support (in usec) */
|
||||||
|
#define XGBE_CDR_DELAY_INIT 10000
|
||||||
|
#define XGBE_CDR_DELAY_INC 10000
|
||||||
|
#define XGBE_CDR_DELAY_MAX 100000
|
||||||
|
|
||||||
|
/* RRC frequency during link status check */
|
||||||
|
#define XGBE_RRC_FREQUENCY 10
|
||||||
|
|
||||||
enum xgbe_port_mode {
|
enum xgbe_port_mode {
|
||||||
XGBE_PORT_MODE_RSVD = 0,
|
XGBE_PORT_MODE_RSVD = 0,
|
||||||
XGBE_PORT_MODE_BACKPLANE,
|
XGBE_PORT_MODE_BACKPLANE,
|
||||||
@ -355,6 +363,10 @@ struct xgbe_phy_data {
|
|||||||
unsigned int redrv_addr;
|
unsigned int redrv_addr;
|
||||||
unsigned int redrv_lane;
|
unsigned int redrv_lane;
|
||||||
unsigned int redrv_model;
|
unsigned int redrv_model;
|
||||||
|
|
||||||
|
/* KR AN support */
|
||||||
|
unsigned int phy_cdr_notrack;
|
||||||
|
unsigned int phy_cdr_delay;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* I2C, MDIO and GPIO lines are muxed, so only one device at a time */
|
/* I2C, MDIO and GPIO lines are muxed, so only one device at a time */
|
||||||
@ -2361,7 +2373,7 @@ static int xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart)
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* No link, attempt a receiver reset cycle */
|
/* No link, attempt a receiver reset cycle */
|
||||||
if (phy_data->rrc_count++) {
|
if (phy_data->rrc_count++ > XGBE_RRC_FREQUENCY) {
|
||||||
phy_data->rrc_count = 0;
|
phy_data->rrc_count = 0;
|
||||||
xgbe_phy_rrc(pdata);
|
xgbe_phy_rrc(pdata);
|
||||||
}
|
}
|
||||||
@ -2669,6 +2681,103 @@ static bool xgbe_phy_port_enabled(struct xgbe_prv_data *pdata)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void xgbe_phy_cdr_track(struct xgbe_prv_data *pdata)
|
||||||
|
{
|
||||||
|
struct xgbe_phy_data *phy_data = pdata->phy_data;
|
||||||
|
|
||||||
|
if (!pdata->debugfs_an_cdr_workaround)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!phy_data->phy_cdr_notrack)
|
||||||
|
return;
|
||||||
|
|
||||||
|
usleep_range(phy_data->phy_cdr_delay,
|
||||||
|
phy_data->phy_cdr_delay + 500);
|
||||||
|
|
||||||
|
XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_CDR_CONTROL,
|
||||||
|
XGBE_PMA_CDR_TRACK_EN_MASK,
|
||||||
|
XGBE_PMA_CDR_TRACK_EN_ON);
|
||||||
|
|
||||||
|
phy_data->phy_cdr_notrack = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xgbe_phy_cdr_notrack(struct xgbe_prv_data *pdata)
|
||||||
|
{
|
||||||
|
struct xgbe_phy_data *phy_data = pdata->phy_data;
|
||||||
|
|
||||||
|
if (!pdata->debugfs_an_cdr_workaround)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (phy_data->phy_cdr_notrack)
|
||||||
|
return;
|
||||||
|
|
||||||
|
XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_CDR_CONTROL,
|
||||||
|
XGBE_PMA_CDR_TRACK_EN_MASK,
|
||||||
|
XGBE_PMA_CDR_TRACK_EN_OFF);
|
||||||
|
|
||||||
|
xgbe_phy_rrc(pdata);
|
||||||
|
|
||||||
|
phy_data->phy_cdr_notrack = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xgbe_phy_kr_training_post(struct xgbe_prv_data *pdata)
|
||||||
|
{
|
||||||
|
if (!pdata->debugfs_an_cdr_track_early)
|
||||||
|
xgbe_phy_cdr_track(pdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xgbe_phy_kr_training_pre(struct xgbe_prv_data *pdata)
|
||||||
|
{
|
||||||
|
if (pdata->debugfs_an_cdr_track_early)
|
||||||
|
xgbe_phy_cdr_track(pdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xgbe_phy_an_post(struct xgbe_prv_data *pdata)
|
||||||
|
{
|
||||||
|
struct xgbe_phy_data *phy_data = pdata->phy_data;
|
||||||
|
|
||||||
|
switch (pdata->an_mode) {
|
||||||
|
case XGBE_AN_MODE_CL73:
|
||||||
|
case XGBE_AN_MODE_CL73_REDRV:
|
||||||
|
if (phy_data->cur_mode != XGBE_MODE_KR)
|
||||||
|
break;
|
||||||
|
|
||||||
|
xgbe_phy_cdr_track(pdata);
|
||||||
|
|
||||||
|
switch (pdata->an_result) {
|
||||||
|
case XGBE_AN_READY:
|
||||||
|
case XGBE_AN_COMPLETE:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (phy_data->phy_cdr_delay < XGBE_CDR_DELAY_MAX)
|
||||||
|
phy_data->phy_cdr_delay += XGBE_CDR_DELAY_INC;
|
||||||
|
else
|
||||||
|
phy_data->phy_cdr_delay = XGBE_CDR_DELAY_INIT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xgbe_phy_an_pre(struct xgbe_prv_data *pdata)
|
||||||
|
{
|
||||||
|
struct xgbe_phy_data *phy_data = pdata->phy_data;
|
||||||
|
|
||||||
|
switch (pdata->an_mode) {
|
||||||
|
case XGBE_AN_MODE_CL73:
|
||||||
|
case XGBE_AN_MODE_CL73_REDRV:
|
||||||
|
if (phy_data->cur_mode != XGBE_MODE_KR)
|
||||||
|
break;
|
||||||
|
|
||||||
|
xgbe_phy_cdr_notrack(pdata);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void xgbe_phy_stop(struct xgbe_prv_data *pdata)
|
static void xgbe_phy_stop(struct xgbe_prv_data *pdata)
|
||||||
{
|
{
|
||||||
struct xgbe_phy_data *phy_data = pdata->phy_data;
|
struct xgbe_phy_data *phy_data = pdata->phy_data;
|
||||||
@ -2680,6 +2789,9 @@ static void xgbe_phy_stop(struct xgbe_prv_data *pdata)
|
|||||||
xgbe_phy_sfp_reset(phy_data);
|
xgbe_phy_sfp_reset(phy_data);
|
||||||
xgbe_phy_sfp_mod_absent(pdata);
|
xgbe_phy_sfp_mod_absent(pdata);
|
||||||
|
|
||||||
|
/* Reset CDR support */
|
||||||
|
xgbe_phy_cdr_track(pdata);
|
||||||
|
|
||||||
/* Power off the PHY */
|
/* Power off the PHY */
|
||||||
xgbe_phy_power_off(pdata);
|
xgbe_phy_power_off(pdata);
|
||||||
|
|
||||||
@ -2712,6 +2824,9 @@ static int xgbe_phy_start(struct xgbe_prv_data *pdata)
|
|||||||
/* Start in highest supported mode */
|
/* Start in highest supported mode */
|
||||||
xgbe_phy_set_mode(pdata, phy_data->start_mode);
|
xgbe_phy_set_mode(pdata, phy_data->start_mode);
|
||||||
|
|
||||||
|
/* Reset CDR support */
|
||||||
|
xgbe_phy_cdr_track(pdata);
|
||||||
|
|
||||||
/* After starting the I2C controller, we can check for an SFP */
|
/* After starting the I2C controller, we can check for an SFP */
|
||||||
switch (phy_data->port_mode) {
|
switch (phy_data->port_mode) {
|
||||||
case XGBE_PORT_MODE_SFP:
|
case XGBE_PORT_MODE_SFP:
|
||||||
@ -3019,6 +3134,8 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
phy_data->phy_cdr_delay = XGBE_CDR_DELAY_INIT;
|
||||||
|
|
||||||
/* Register for driving external PHYs */
|
/* Register for driving external PHYs */
|
||||||
mii = devm_mdiobus_alloc(pdata->dev);
|
mii = devm_mdiobus_alloc(pdata->dev);
|
||||||
if (!mii) {
|
if (!mii) {
|
||||||
@ -3071,4 +3188,10 @@ void xgbe_init_function_ptrs_phy_v2(struct xgbe_phy_if *phy_if)
|
|||||||
phy_impl->an_advertising = xgbe_phy_an_advertising;
|
phy_impl->an_advertising = xgbe_phy_an_advertising;
|
||||||
|
|
||||||
phy_impl->an_outcome = xgbe_phy_an_outcome;
|
phy_impl->an_outcome = xgbe_phy_an_outcome;
|
||||||
|
|
||||||
|
phy_impl->an_pre = xgbe_phy_an_pre;
|
||||||
|
phy_impl->an_post = xgbe_phy_an_post;
|
||||||
|
|
||||||
|
phy_impl->kr_training_pre = xgbe_phy_kr_training_pre;
|
||||||
|
phy_impl->kr_training_post = xgbe_phy_kr_training_post;
|
||||||
}
|
}
|
||||||
|
@ -994,6 +994,7 @@ struct xgbe_version_data {
|
|||||||
unsigned int irq_reissue_support;
|
unsigned int irq_reissue_support;
|
||||||
unsigned int tx_desc_prefetch;
|
unsigned int tx_desc_prefetch;
|
||||||
unsigned int rx_desc_prefetch;
|
unsigned int rx_desc_prefetch;
|
||||||
|
unsigned int an_cdr_workaround;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xgbe_vxlan_data {
|
struct xgbe_vxlan_data {
|
||||||
@ -1262,6 +1263,9 @@ struct xgbe_prv_data {
|
|||||||
unsigned int debugfs_xprop_reg;
|
unsigned int debugfs_xprop_reg;
|
||||||
|
|
||||||
unsigned int debugfs_xi2c_reg;
|
unsigned int debugfs_xi2c_reg;
|
||||||
|
|
||||||
|
bool debugfs_an_cdr_workaround;
|
||||||
|
bool debugfs_an_cdr_track_early;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Function prototypes*/
|
/* Function prototypes*/
|
||||||
|
Loading…
Reference in New Issue
Block a user