Skip to content

Commit 96f4d43

Browse files
tlendackydavem330
authored andcommitted
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 4d94566 commit 96f4d43

File tree

7 files changed

+160
-4
lines changed

7 files changed

+160
-4
lines changed

drivers/net/ethernet/amd/xgbe/xgbe-common.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,6 +1321,10 @@
13211321
#define MDIO_VEND2_AN_STAT 0x8002
13221322
#endif
13231323

1324+
#ifndef MDIO_VEND2_PMA_CDR_CONTROL
1325+
#define MDIO_VEND2_PMA_CDR_CONTROL 0x8056
1326+
#endif
1327+
13241328
#ifndef MDIO_CTRL1_SPEED1G
13251329
#define MDIO_CTRL1_SPEED1G (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100)
13261330
#endif
@@ -1369,6 +1373,10 @@
13691373
#define XGBE_AN_CL37_TX_CONFIG_MASK 0x08
13701374
#define XGBE_AN_CL37_MII_CTRL_8BIT 0x0100
13711375

1376+
#define XGBE_PMA_CDR_TRACK_EN_MASK 0x01
1377+
#define XGBE_PMA_CDR_TRACK_EN_OFF 0x00
1378+
#define XGBE_PMA_CDR_TRACK_EN_ON 0x01
1379+
13721380
/* Bit setting and getting macros
13731381
* The get macro will extract the current bit field value from within
13741382
* the variable

drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,22 @@ void xgbe_debugfs_init(struct xgbe_prv_data *pdata)
519519
"debugfs_create_file failed\n");
520520
}
521521

522+
if (pdata->vdata->an_cdr_workaround) {
523+
pfile = debugfs_create_bool("an_cdr_workaround", 0600,
524+
pdata->xgbe_debugfs,
525+
&pdata->debugfs_an_cdr_workaround);
526+
if (!pfile)
527+
netdev_err(pdata->netdev,
528+
"debugfs_create_bool failed\n");
529+
530+
pfile = debugfs_create_bool("an_cdr_track_early", 0600,
531+
pdata->xgbe_debugfs,
532+
&pdata->debugfs_an_cdr_track_early);
533+
if (!pfile)
534+
netdev_err(pdata->netdev,
535+
"debugfs_create_bool failed\n");
536+
}
537+
522538
kfree(buf);
523539
}
524540

drivers/net/ethernet/amd/xgbe/xgbe-main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ int xgbe_config_netdev(struct xgbe_prv_data *pdata)
349349
XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, UDP4TE, 1);
350350

351351
/* Call MDIO/PHY initialization routine */
352+
pdata->debugfs_an_cdr_workaround = pdata->vdata->an_cdr_workaround;
352353
ret = pdata->phy_if.phy_init(pdata);
353354
if (ret)
354355
return ret;

drivers/net/ethernet/amd/xgbe/xgbe-mdio.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,8 @@ static void xgbe_an73_disable(struct xgbe_prv_data *pdata)
432432
xgbe_an73_set(pdata, false, false);
433433
xgbe_an73_disable_interrupts(pdata);
434434

435+
pdata->an_start = 0;
436+
435437
netif_dbg(pdata, link, pdata->netdev, "CL73 AN disabled\n");
436438
}
437439

@@ -511,11 +513,11 @@ static enum xgbe_an xgbe_an73_tx_training(struct xgbe_prv_data *pdata,
511513
XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL,
512514
reg);
513515

514-
if (pdata->phy_if.phy_impl.kr_training_post)
515-
pdata->phy_if.phy_impl.kr_training_post(pdata);
516-
517516
netif_dbg(pdata, link, pdata->netdev,
518517
"KR training initiated\n");
518+
519+
if (pdata->phy_if.phy_impl.kr_training_post)
520+
pdata->phy_if.phy_impl.kr_training_post(pdata);
519521
}
520522

521523
return XGBE_AN_PAGE_RECEIVED;

drivers/net/ethernet/amd/xgbe/xgbe-pci.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,7 @@ static const struct xgbe_version_data xgbe_v2a = {
456456
.irq_reissue_support = 1,
457457
.tx_desc_prefetch = 5,
458458
.rx_desc_prefetch = 5,
459+
.an_cdr_workaround = 1,
459460
};
460461

461462
static const struct xgbe_version_data xgbe_v2b = {
@@ -470,6 +471,7 @@ static const struct xgbe_version_data xgbe_v2b = {
470471
.irq_reissue_support = 1,
471472
.tx_desc_prefetch = 5,
472473
.rx_desc_prefetch = 5,
474+
.an_cdr_workaround = 1,
473475
};
474476

475477
static const struct pci_device_id xgbe_pci_table[] = {

drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c

Lines changed: 124 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,14 @@
147147
/* Rate-change complete wait/retry count */
148148
#define XGBE_RATECHANGE_COUNT 500
149149

150+
/* CDR delay values for KR support (in usec) */
151+
#define XGBE_CDR_DELAY_INIT 10000
152+
#define XGBE_CDR_DELAY_INC 10000
153+
#define XGBE_CDR_DELAY_MAX 100000
154+
155+
/* RRC frequency during link status check */
156+
#define XGBE_RRC_FREQUENCY 10
157+
150158
enum xgbe_port_mode {
151159
XGBE_PORT_MODE_RSVD = 0,
152160
XGBE_PORT_MODE_BACKPLANE,
@@ -355,6 +363,10 @@ struct xgbe_phy_data {
355363
unsigned int redrv_addr;
356364
unsigned int redrv_lane;
357365
unsigned int redrv_model;
366+
367+
/* KR AN support */
368+
unsigned int phy_cdr_notrack;
369+
unsigned int phy_cdr_delay;
358370
};
359371

360372
/* 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)
23612373
return 1;
23622374

23632375
/* No link, attempt a receiver reset cycle */
2364-
if (phy_data->rrc_count++) {
2376+
if (phy_data->rrc_count++ > XGBE_RRC_FREQUENCY) {
23652377
phy_data->rrc_count = 0;
23662378
xgbe_phy_rrc(pdata);
23672379
}
@@ -2669,6 +2681,103 @@ static bool xgbe_phy_port_enabled(struct xgbe_prv_data *pdata)
26692681
return true;
26702682
}
26712683

2684+
static void xgbe_phy_cdr_track(struct xgbe_prv_data *pdata)
2685+
{
2686+
struct xgbe_phy_data *phy_data = pdata->phy_data;
2687+
2688+
if (!pdata->debugfs_an_cdr_workaround)
2689+
return;
2690+
2691+
if (!phy_data->phy_cdr_notrack)
2692+
return;
2693+
2694+
usleep_range(phy_data->phy_cdr_delay,
2695+
phy_data->phy_cdr_delay + 500);
2696+
2697+
XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_CDR_CONTROL,
2698+
XGBE_PMA_CDR_TRACK_EN_MASK,
2699+
XGBE_PMA_CDR_TRACK_EN_ON);
2700+
2701+
phy_data->phy_cdr_notrack = 0;
2702+
}
2703+
2704+
static void xgbe_phy_cdr_notrack(struct xgbe_prv_data *pdata)
2705+
{
2706+
struct xgbe_phy_data *phy_data = pdata->phy_data;
2707+
2708+
if (!pdata->debugfs_an_cdr_workaround)
2709+
return;
2710+
2711+
if (phy_data->phy_cdr_notrack)
2712+
return;
2713+
2714+
XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_CDR_CONTROL,
2715+
XGBE_PMA_CDR_TRACK_EN_MASK,
2716+
XGBE_PMA_CDR_TRACK_EN_OFF);
2717+
2718+
xgbe_phy_rrc(pdata);
2719+
2720+
phy_data->phy_cdr_notrack = 1;
2721+
}
2722+
2723+
static void xgbe_phy_kr_training_post(struct xgbe_prv_data *pdata)
2724+
{
2725+
if (!pdata->debugfs_an_cdr_track_early)
2726+
xgbe_phy_cdr_track(pdata);
2727+
}
2728+
2729+
static void xgbe_phy_kr_training_pre(struct xgbe_prv_data *pdata)
2730+
{
2731+
if (pdata->debugfs_an_cdr_track_early)
2732+
xgbe_phy_cdr_track(pdata);
2733+
}
2734+
2735+
static void xgbe_phy_an_post(struct xgbe_prv_data *pdata)
2736+
{
2737+
struct xgbe_phy_data *phy_data = pdata->phy_data;
2738+
2739+
switch (pdata->an_mode) {
2740+
case XGBE_AN_MODE_CL73:
2741+
case XGBE_AN_MODE_CL73_REDRV:
2742+
if (phy_data->cur_mode != XGBE_MODE_KR)
2743+
break;
2744+
2745+
xgbe_phy_cdr_track(pdata);
2746+
2747+
switch (pdata->an_result) {
2748+
case XGBE_AN_READY:
2749+
case XGBE_AN_COMPLETE:
2750+
break;
2751+
default:
2752+
if (phy_data->phy_cdr_delay < XGBE_CDR_DELAY_MAX)
2753+
phy_data->phy_cdr_delay += XGBE_CDR_DELAY_INC;
2754+
else
2755+
phy_data->phy_cdr_delay = XGBE_CDR_DELAY_INIT;
2756+
break;
2757+
}
2758+
break;
2759+
default:
2760+
break;
2761+
}
2762+
}
2763+
2764+
static void xgbe_phy_an_pre(struct xgbe_prv_data *pdata)
2765+
{
2766+
struct xgbe_phy_data *phy_data = pdata->phy_data;
2767+
2768+
switch (pdata->an_mode) {
2769+
case XGBE_AN_MODE_CL73:
2770+
case XGBE_AN_MODE_CL73_REDRV:
2771+
if (phy_data->cur_mode != XGBE_MODE_KR)
2772+
break;
2773+
2774+
xgbe_phy_cdr_notrack(pdata);
2775+
break;
2776+
default:
2777+
break;
2778+
}
2779+
}
2780+
26722781
static void xgbe_phy_stop(struct xgbe_prv_data *pdata)
26732782
{
26742783
struct xgbe_phy_data *phy_data = pdata->phy_data;
@@ -2680,6 +2789,9 @@ static void xgbe_phy_stop(struct xgbe_prv_data *pdata)
26802789
xgbe_phy_sfp_reset(phy_data);
26812790
xgbe_phy_sfp_mod_absent(pdata);
26822791

2792+
/* Reset CDR support */
2793+
xgbe_phy_cdr_track(pdata);
2794+
26832795
/* Power off the PHY */
26842796
xgbe_phy_power_off(pdata);
26852797

@@ -2712,6 +2824,9 @@ static int xgbe_phy_start(struct xgbe_prv_data *pdata)
27122824
/* Start in highest supported mode */
27132825
xgbe_phy_set_mode(pdata, phy_data->start_mode);
27142826

2827+
/* Reset CDR support */
2828+
xgbe_phy_cdr_track(pdata);
2829+
27152830
/* After starting the I2C controller, we can check for an SFP */
27162831
switch (phy_data->port_mode) {
27172832
case XGBE_PORT_MODE_SFP:
@@ -3019,6 +3134,8 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
30193134
}
30203135
}
30213136

3137+
phy_data->phy_cdr_delay = XGBE_CDR_DELAY_INIT;
3138+
30223139
/* Register for driving external PHYs */
30233140
mii = devm_mdiobus_alloc(pdata->dev);
30243141
if (!mii) {
@@ -3071,4 +3188,10 @@ void xgbe_init_function_ptrs_phy_v2(struct xgbe_phy_if *phy_if)
30713188
phy_impl->an_advertising = xgbe_phy_an_advertising;
30723189

30733190
phy_impl->an_outcome = xgbe_phy_an_outcome;
3191+
3192+
phy_impl->an_pre = xgbe_phy_an_pre;
3193+
phy_impl->an_post = xgbe_phy_an_post;
3194+
3195+
phy_impl->kr_training_pre = xgbe_phy_kr_training_pre;
3196+
phy_impl->kr_training_post = xgbe_phy_kr_training_post;
30743197
}

drivers/net/ethernet/amd/xgbe/xgbe.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -994,6 +994,7 @@ struct xgbe_version_data {
994994
unsigned int irq_reissue_support;
995995
unsigned int tx_desc_prefetch;
996996
unsigned int rx_desc_prefetch;
997+
unsigned int an_cdr_workaround;
997998
};
998999

9991000
struct xgbe_vxlan_data {
@@ -1262,6 +1263,9 @@ struct xgbe_prv_data {
12621263
unsigned int debugfs_xprop_reg;
12631264

12641265
unsigned int debugfs_xi2c_reg;
1266+
1267+
bool debugfs_an_cdr_workaround;
1268+
bool debugfs_an_cdr_track_early;
12651269
};
12661270

12671271
/* Function prototypes*/

0 commit comments

Comments
 (0)