aboutsummaryrefslogtreecommitdiffstats
path: root/meta-amd-bsp/recipes-kernel/linux-5.10/linux-yocto-5.10.47-amdx86/0010-amd-xgbe-synchronization-between-AN-state-machine-an.patch
blob: 8fd1c8b5eeb217e00de518ab4ad1f3bfc4fc894e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
From bff033e9aa3ebf9d7e2bb42be9d635e9c65bcbe0 Mon Sep 17 00:00:00 2001
From: Sudheesh Mavila <sudheesh.mavila@amd.com>
Date: Sat, 9 Jan 2021 23:41:36 +0530
Subject: [PATCH 10/10] amd-xgbe: synchronization between AN state machine and
 status polling timer thread

xgbe driver uses a TIMEOUT to restart AN process if link is down.
This create issue when TIMEOUT comes in between a KR training or RCC
is in process. The patch avoids AN restart if TIMEOUT happens
during KR cycle or RRC.

TIMEOUT value also reduced to 1 sec to enable fast
synchronization between LP.

Signed-off-by: Sudheesh Mavila <sudheesh.mavila@amd.com>
---
 drivers/net/ethernet/amd/xgbe/xgbe-mdio.c   | 29 +++++++++++++++++++--
 drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c |  1 +
 drivers/net/ethernet/amd/xgbe/xgbe.h        |  4 ++-
 3 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
index f4359407269a..c70c38d96020 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
@@ -512,6 +512,7 @@ static enum xgbe_an xgbe_an73_tx_training(struct xgbe_prv_data *pdata,
 	XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg);
 
 	pdata->kr_done = 1;
+	pdata->kr_start_time = jiffies;
 
 	netif_dbg(pdata, link, pdata->netdev,
 		  "KR training initiated\n");
@@ -884,6 +885,8 @@ static void xgbe_an73_state_machine(struct xgbe_prv_data *pdata)
 		break;
 
 	case XGBE_AN_PAGE_RECEIVED:
+		if (xgbe_in_kr_mode(pdata))
+			pdata->an_int = 0;
 		pdata->an_state = xgbe_an73_page_received(pdata);
 		pdata->an_supported++;
 		break;
@@ -1306,11 +1309,34 @@ static bool xgbe_phy_aneg_done(struct xgbe_prv_data *pdata)
 static void xgbe_check_link_timeout(struct xgbe_prv_data *pdata)
 {
 	unsigned long link_timeout;
+	int wait = 200;
+	unsigned long kr_time;
+	unsigned long rrc_time;
 
 	link_timeout = pdata->link_check + (XGBE_LINK_TIMEOUT * HZ);
 	if (time_after(jiffies, link_timeout)) {
 		netif_dbg(pdata, link, pdata->netdev, "AN link timeout\n");
-		xgbe_phy_config_aneg(pdata);
+	/* AN restart should not happen within 500ms of start of RRC or KR tarining */
+	/* This loop ensures no AN restart during RRC window and KR training window */
+		while (wait--) {
+			mutex_lock(&pdata->an_mutex);
+			kr_time = pdata->kr_start_time + msecs_to_jiffies(XGBE_AN_MS_TIMEOUT);
+			rrc_time = pdata->rrc_start_time + msecs_to_jiffies(XGBE_AN_MS_TIMEOUT);
+			mutex_unlock(&pdata->an_mutex);
+			if (time_after(jiffies, kr_time) && time_after(jiffies, rrc_time))
+				break;
+			if (pdata->an_result == XGBE_AN_COMPLETE)
+				break;
+
+			usleep_range(5000, 6000);
+		}
+		/* AN restart is required, if AN result is not COMPLETE */
+		if (pdata->an_result != XGBE_AN_COMPLETE)
+			xgbe_phy_config_aneg(pdata);
+		else if ((pdata->an_result == XGBE_AN_COMPLETE) &&
+			 (xgbe_cur_mode(pdata) == XGBE_MODE_KX_1000))
+			xgbe_phy_config_aneg(pdata);
+
 	}
 }
 
@@ -1489,7 +1515,6 @@ 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 f3566a480f2d..f24b8121db2e 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
@@ -2977,6 +2977,7 @@ static void xgbe_phy_cdr_notrack(struct xgbe_prv_data *pdata)
 			 XGBE_PMA_CDR_TRACK_EN_MASK,
 			 XGBE_PMA_CDR_TRACK_EN_OFF);
 	xgbe_phy_rrc(pdata);
+	pdata->rrc_start_time = jiffies;
 	phy_data->phy_cdr_notrack = 1;
 }
 
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h
index c99b34c41f71..3ed98e2f8695 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe.h
@@ -288,7 +288,7 @@
 
 /* Auto-negotiation */
 #define XGBE_AN_MS_TIMEOUT		500
-#define XGBE_LINK_TIMEOUT		5
+#define XGBE_LINK_TIMEOUT		1
 
 #define XGBE_SGMII_AN_LINK_STATUS	BIT(1)
 #define XGBE_SGMII_AN_LINK_SPEED	(BIT(2) | BIT(3))
@@ -1258,6 +1258,8 @@ struct xgbe_prv_data {
 	unsigned long an_start;
 	enum xgbe_an_mode an_mode;
 	unsigned int kr_done;
+	unsigned long kr_start_time;
+	unsigned long rrc_start_time;
 	unsigned int cdr_delay_required;
 
 	/* I2C support */
-- 
2.17.1