aboutsummaryrefslogtreecommitdiffstats
path: root/meta-amd-bsp/recipes-kernel/linux-5.10/linux-yocto-5.10.47-amdx86/0007-amd-xgbe-improved-KR-training-sequence.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux-5.10/linux-yocto-5.10.47-amdx86/0007-amd-xgbe-improved-KR-training-sequence.patch')
-rw-r--r--meta-amd-bsp/recipes-kernel/linux-5.10/linux-yocto-5.10.47-amdx86/0007-amd-xgbe-improved-KR-training-sequence.patch286
1 files changed, 286 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux-5.10/linux-yocto-5.10.47-amdx86/0007-amd-xgbe-improved-KR-training-sequence.patch b/meta-amd-bsp/recipes-kernel/linux-5.10/linux-yocto-5.10.47-amdx86/0007-amd-xgbe-improved-KR-training-sequence.patch
new file mode 100644
index 00000000..92c253e3
--- /dev/null
+++ b/meta-amd-bsp/recipes-kernel/linux-5.10/linux-yocto-5.10.47-amdx86/0007-amd-xgbe-improved-KR-training-sequence.patch
@@ -0,0 +1,286 @@
+From 1d9082fe8167fe3d2c9db39a22a727b99496d172 Mon Sep 17 00:00:00 2001
+From: Sudheesh Mavila <sudheesh.mavila@amd.com>
+Date: Sat, 9 Jan 2021 12:26:09 +0530
+Subject: [PATCH 07/10] amd-xgbe: improved KR training sequence
+
+amd-xgbe driver handles KR training sequence directly by
+programming the h/w IP registers. This causes KR training
+failure if the h/w blocks are not operated correctly or they are
+not in sync. The new sequence increase the stability of AN process
+in KR mode by making sure that the h/w blocks are in expected
+state when the AN is in progress.
+
+This patch fix the problem of long linkup time due to repeated KR failure
+observed in AMD platforms.
+
+Signed-off-by: Sudheesh Mavila <sudheesh.mavila@amd.com>
+Signed-off-by: Rahul Kumar <rahul.kumar1@amd.com>
+---
+ drivers/net/ethernet/amd/xgbe/xgbe-common.h | 8 +++
+ drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 44 ++++++++++++++--
+ drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c | 56 ++++++++++++++-------
+ drivers/net/ethernet/amd/xgbe/xgbe.h | 5 ++
+ 4 files changed, 92 insertions(+), 21 deletions(-)
+
+diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h
+index b2cd3bdba9f8..ae1d553962dd 100644
+--- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h
++++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h
+@@ -1279,6 +1279,10 @@
+ #define MDIO_PMA_10GBR_FECCTRL 0x00ab
+ #endif
+
++#ifndef MDIO_PMA_RX_CTRL0
++#define MDIO_PMA_RX_CTRL0 0x8050
++#endif
++
+ #ifndef MDIO_PMA_RX_CTRL1
+ #define MDIO_PMA_RX_CTRL1 0x8051
+ #endif
+@@ -1327,6 +1331,10 @@
+ #define MDIO_VEND2_AN_STAT 0x8002
+ #endif
+
++#ifndef MDIO_PMA_RX_EQ_CTRL
++#define MDIO_PMA_RX_EQ_CTRL 0x8009
++#endif
++
+ #ifndef MDIO_VEND2_PMA_CDR_CONTROL
+ #define MDIO_VEND2_PMA_CDR_CONTROL 0x8056
+ #endif
+diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
+index 91397cf3c5ab..f4359407269a 100644
+--- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
++++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
+@@ -402,6 +402,16 @@ static void xgbe_an73_set(struct xgbe_prv_data *pdata, bool enable,
+ reg |= MDIO_AN_CTRL1_RESTART;
+
+ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_CTRL1, reg);
++
++ if (xgbe_in_kr_mode(pdata) && (enable || restart)) {
++ reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
++ reg |= XGBE_KR_TRAINING_ENABLE;
++ reg |= XGBE_KR_TRAINING_START;
++ XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg);
++
++ XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_EQ_CTRL,
++ BIT(15), BIT(15)); /* Disable RX Adapter */
++ }
+ }
+
+ static void xgbe_an73_restart(struct xgbe_prv_data *pdata)
+@@ -409,7 +419,7 @@ static void xgbe_an73_restart(struct xgbe_prv_data *pdata)
+ xgbe_an73_enable_interrupts(pdata);
+ xgbe_an73_set(pdata, true, true);
+
+- netif_dbg(pdata, link, pdata->netdev, "CL73 AN enabled/restarted\n");
++ netif_dbg(pdata, link, pdata->netdev, "CL73 AN enabled/restarted, CL72 started\n");
+ }
+
+ static void xgbe_an73_disable(struct xgbe_prv_data *pdata)
+@@ -489,20 +499,40 @@ static enum xgbe_an xgbe_an73_tx_training(struct xgbe_prv_data *pdata,
+ XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECCTRL, reg);
+
+ /* Start KR training */
++ if (!pdata->phy_if.phy_impl.kr_training_cdroff(pdata))
++ netif_dbg(pdata, link, pdata->netdev, "setting phy_data->phy_cdr_notrack\n");
++
++ pdata->cdr_delay_required = 1;
++
+ if (pdata->phy_if.phy_impl.kr_training_pre)
+ pdata->phy_if.phy_impl.kr_training_pre(pdata);
+
+ reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
+- reg |= XGBE_KR_TRAINING_ENABLE;
+ reg |= XGBE_KR_TRAINING_START;
+ XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg);
+
++ pdata->kr_done = 1;
++
+ netif_dbg(pdata, link, pdata->netdev,
+ "KR training initiated\n");
+
++ /* set RX_EQ_MGMT_MODE to disable RX Adapt Requests */
++ XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_EQ_CTRL, BIT(15), BIT(15));
++ XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_CDR_CONTROL,
++ XGBE_PMA_CDR_TRACK_EN_MASK,
++ XGBE_PMA_CDR_TRACK_EN_OFF);
++ XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_CTRL0, BIT(8), 0);
+ if (pdata->phy_if.phy_impl.kr_training_post)
+ pdata->phy_if.phy_impl.kr_training_post(pdata);
+
++ XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_CTRL0, BIT(8), BIT(8));
++ pdata->cdr_delay_required = 0;
++ udelay(1);
++ XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_RX_EQ_CTRL,
++ BIT(15), 0);
++ if (pdata->phy_if.phy_impl.update_cdr_delay)
++ pdata->phy_if.phy_impl.update_cdr_delay(pdata);
++
+ return XGBE_AN_PAGE_RECEIVED;
+ }
+
+@@ -897,8 +927,6 @@ static void xgbe_an73_state_machine(struct xgbe_prv_data *pdata)
+ pdata->kx_state = XGBE_RX_BPA;
+ pdata->an_start = 0;
+
+- if (pdata->phy_if.phy_impl.an_post)
+- pdata->phy_if.phy_impl.an_post(pdata);
+
+ netif_dbg(pdata, link, pdata->netdev, "CL73 AN result: %s\n",
+ xgbe_state_as_string(pdata->an_result));
+@@ -1243,6 +1271,9 @@ static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata, bool set_mode)
+ /* Re-enable auto-negotiation interrupt */
+ enable_irq(pdata->an_irq);
+
++ if (pdata->phy_if.phy_impl.an_post)
++ pdata->phy_if.phy_impl.an_post(pdata);
++
+ xgbe_an_init(pdata);
+ xgbe_an_restart(pdata);
+
+@@ -1360,6 +1391,10 @@ static void xgbe_phy_status(struct xgbe_prv_data *pdata)
+ clear_bit(XGBE_LINK_INIT, &pdata->dev_state);
+
+ netif_carrier_on(pdata->netdev);
++
++ if (link_aneg && pdata->kr_done)
++ pdata->phy_if.phy_impl.reset_cdr_delay(pdata);
++
+ } else {
+ if (test_bit(XGBE_LINK_INIT, &pdata->dev_state)) {
+ xgbe_check_link_timeout(pdata);
+@@ -1454,6 +1489,7 @@ static int xgbe_phy_start(struct xgbe_prv_data *pdata)
+
+ /* Indicate the PHY is up and running */
+ pdata->phy_started = 1;
++ pdata->an_result = XGBE_AN_NO_LINK;
+
+ xgbe_an_init(pdata);
+ xgbe_an_enable_interrupts(pdata);
+diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
+index 5307f7e6e64b..88663acae8b3 100644
+--- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
++++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
+@@ -2949,13 +2949,16 @@ static void xgbe_phy_cdr_track(struct xgbe_prv_data *pdata)
+ if (!phy_data->phy_cdr_notrack)
+ return;
+
+- usleep_range(phy_data->phy_cdr_delay,
+- phy_data->phy_cdr_delay + 500);
++ /* when there is no link, no need to use the cdr delay, when ever a page is */
++ /* received , pdata->cdr_delay_required is set to 1 */
++ if (pdata->cdr_delay_required) {
++ 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;
+ }
+
+@@ -2972,9 +2975,7 @@ static void xgbe_phy_cdr_notrack(struct xgbe_prv_data *pdata)
+ 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;
+ }
+
+@@ -2984,6 +2985,36 @@ static void xgbe_phy_kr_training_post(struct xgbe_prv_data *pdata)
+ xgbe_phy_cdr_track(pdata);
+ }
+
++static void xgbe_phy_reset_cdr_delay(struct xgbe_prv_data *pdata)
++{
++ struct xgbe_phy_data *phy_data = pdata->phy_data;
++
++ phy_data->phy_cdr_delay = XGBE_CDR_DELAY_INIT;
++ pdata->kr_done = 0;
++}
++
++static void xgbe_phy_update_cdr_delay(struct xgbe_prv_data *pdata)
++{
++ struct xgbe_phy_data *phy_data = pdata->phy_data;
++
++ 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;
++}
++
++static int xgbe_phy_kr_training_cdroff(struct xgbe_prv_data *pdata)
++{
++ int ret;
++ struct xgbe_phy_data *phy_data = pdata->phy_data;
++
++ ret = phy_data->phy_cdr_notrack;
++ if (!phy_data->phy_cdr_notrack)
++ phy_data->phy_cdr_notrack = 1;
++
++ return ret;
++}
++
+ static void xgbe_phy_kr_training_pre(struct xgbe_prv_data *pdata)
+ {
+ if (pdata->debugfs_an_cdr_track_early)
+@@ -3001,18 +3032,6 @@ static void xgbe_phy_an_post(struct xgbe_prv_data *pdata)
+ 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;
+@@ -3451,6 +3470,9 @@ void xgbe_init_function_ptrs_phy_v2(struct xgbe_phy_if *phy_if)
+
+ phy_impl->kr_training_pre = xgbe_phy_kr_training_pre;
+ phy_impl->kr_training_post = xgbe_phy_kr_training_post;
++ phy_impl->kr_training_cdroff = xgbe_phy_kr_training_cdroff;
++ phy_impl->reset_cdr_delay = xgbe_phy_reset_cdr_delay;
++ phy_impl->update_cdr_delay = xgbe_phy_update_cdr_delay;
+
+ phy_impl->module_info = xgbe_phy_module_info;
+ phy_impl->module_eeprom = xgbe_phy_module_eeprom;
+diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h
+index ba8321ec1ee7..c99b34c41f71 100644
+--- a/drivers/net/ethernet/amd/xgbe/xgbe.h
++++ b/drivers/net/ethernet/amd/xgbe/xgbe.h
+@@ -888,6 +888,9 @@ struct xgbe_phy_impl_if {
+ /* Pre/Post KR training enablement support */
+ void (*kr_training_pre)(struct xgbe_prv_data *);
+ void (*kr_training_post)(struct xgbe_prv_data *);
++ int (*kr_training_cdroff)(struct xgbe_prv_data *pdata);
++ void (*reset_cdr_delay)(struct xgbe_prv_data *pdata);
++ void (*update_cdr_delay)(struct xgbe_prv_data *pdata);
+
+ /* SFP module related info */
+ int (*module_info)(struct xgbe_prv_data *pdata,
+@@ -1254,6 +1257,8 @@ struct xgbe_prv_data {
+ unsigned int fec_ability;
+ unsigned long an_start;
+ enum xgbe_an_mode an_mode;
++ unsigned int kr_done;
++ unsigned int cdr_delay_required;
+
+ /* I2C support */
+ struct xgbe_i2c i2c;
+--
+2.17.1
+