mediatek: Add support for Xiaomi Redmi Router AX6S
[openwrt/staging/chunkeey.git] / target / linux / generic / backport-5.4 / 733-v5.5-net-sfp-split-power-mode-switching-from-probe.patch
1 From fdff863a4ce3677907f64396e34c45025abb6600 Mon Sep 17 00:00:00 2001
2 From: Russell King <rmk+kernel@armlinux.org.uk>
3 Date: Tue, 5 Nov 2019 12:59:36 +0000
4 Subject: [PATCH 631/660] net: sfp: split power mode switching from probe
5
6 Switch the power mode switching from the probe, so that we don't
7 repeatedly re-probe the SFP device if there is a problem accessing
8 the registers at I2C address 0x51.
9
10 In splitting this out, we can also fix a bug where we leave the module
11 in high-power mode when the upstream device is detached but the module
12 is still inserted.
13
14 Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
15 ---
16 drivers/net/phy/sfp.c | 101 ++++++++++++++++++++++++++----------------
17 1 file changed, 64 insertions(+), 37 deletions(-)
18
19 --- a/drivers/net/phy/sfp.c
20 +++ b/drivers/net/phy/sfp.c
21 @@ -49,6 +49,7 @@ enum {
22 SFP_MOD_EMPTY = 0,
23 SFP_MOD_PROBE,
24 SFP_MOD_HPOWER,
25 + SFP_MOD_WAITPWR,
26 SFP_MOD_PRESENT,
27 SFP_MOD_ERROR,
28
29 @@ -71,6 +72,7 @@ static const char * const mod_state_str
30 [SFP_MOD_EMPTY] = "empty",
31 [SFP_MOD_PROBE] = "probe",
32 [SFP_MOD_HPOWER] = "hpower",
33 + [SFP_MOD_WAITPWR] = "waitpwr",
34 [SFP_MOD_PRESENT] = "present",
35 [SFP_MOD_ERROR] = "error",
36 };
37 @@ -1423,37 +1425,34 @@ static int sfp_module_parse_power(struct
38 return 0;
39 }
40
41 -static int sfp_sm_mod_hpower(struct sfp *sfp)
42 +static int sfp_sm_mod_hpower(struct sfp *sfp, bool enable)
43 {
44 u8 val;
45 int err;
46
47 - if (sfp->module_power_mW <= 1000)
48 - return 0;
49 -
50 err = sfp_read(sfp, true, SFP_EXT_STATUS, &val, sizeof(val));
51 if (err != sizeof(val)) {
52 dev_err(sfp->dev, "Failed to read EEPROM: %d\n", err);
53 - err = -EAGAIN;
54 - goto err;
55 + return -EAGAIN;
56 }
57
58 - val |= BIT(0);
59 + if (enable)
60 + val |= BIT(0);
61 + else
62 + val &= ~BIT(0);
63
64 err = sfp_write(sfp, true, SFP_EXT_STATUS, &val, sizeof(val));
65 if (err != sizeof(val)) {
66 dev_err(sfp->dev, "Failed to write EEPROM: %d\n", err);
67 - err = -EAGAIN;
68 - goto err;
69 + return -EAGAIN;
70 }
71
72 - dev_info(sfp->dev, "Module switched to %u.%uW power level\n",
73 - sfp->module_power_mW / 1000,
74 - (sfp->module_power_mW / 100) % 10);
75 - return T_HPOWER_LEVEL;
76 + if (enable)
77 + dev_info(sfp->dev, "Module switched to %u.%uW power level\n",
78 + sfp->module_power_mW / 1000,
79 + (sfp->module_power_mW / 100) % 10);
80
81 -err:
82 - return err;
83 + return 0;
84 }
85
86 static int sfp_sm_mod_probe(struct sfp *sfp)
87 @@ -1549,7 +1548,7 @@ static int sfp_sm_mod_probe(struct sfp *
88 if (ret < 0)
89 return ret;
90
91 - return sfp_sm_mod_hpower(sfp);
92 + return 0;
93 }
94
95 static void sfp_sm_mod_remove(struct sfp *sfp)
96 @@ -1594,13 +1593,22 @@ static void sfp_sm_device(struct sfp *sf
97 */
98 static void sfp_sm_module(struct sfp *sfp, unsigned int event)
99 {
100 - /* Handle remove event globally, it resets this state machine.
101 - * Also deal with upstream detachment.
102 - */
103 - if (event == SFP_E_REMOVE || sfp->sm_dev_state < SFP_DEV_DOWN) {
104 + int err;
105 +
106 + /* Handle remove event globally, it resets this state machine */
107 + if (event == SFP_E_REMOVE) {
108 if (sfp->sm_mod_state > SFP_MOD_PROBE)
109 sfp_sm_mod_remove(sfp);
110 - if (sfp->sm_mod_state != SFP_MOD_EMPTY)
111 + sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
112 + return;
113 + }
114 +
115 + /* Handle device detach globally */
116 + if (sfp->sm_dev_state < SFP_DEV_DOWN) {
117 + if (sfp->module_power_mW > 1000 &&
118 + sfp->sm_mod_state > SFP_MOD_HPOWER)
119 + sfp_sm_mod_hpower(sfp, false);
120 + if (sfp->sm_mod_state > SFP_MOD_EMPTY)
121 sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
122 return;
123 }
124 @@ -1612,26 +1620,45 @@ static void sfp_sm_module(struct sfp *sf
125 break;
126
127 case SFP_MOD_PROBE:
128 - if (event == SFP_E_TIMEOUT) {
129 - int val = sfp_sm_mod_probe(sfp);
130 + if (event != SFP_E_TIMEOUT)
131 + break;
132
133 - if (val == 0)
134 - sfp_sm_mod_next(sfp, SFP_MOD_PRESENT, 0);
135 - else if (val > 0)
136 - sfp_sm_mod_next(sfp, SFP_MOD_HPOWER, val);
137 - else if (val != -EAGAIN)
138 - sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
139 - else
140 - sfp_sm_set_timer(sfp, T_PROBE_RETRY);
141 + err = sfp_sm_mod_probe(sfp);
142 + if (err == -EAGAIN) {
143 + sfp_sm_set_timer(sfp, T_PROBE_RETRY);
144 + break;
145 }
146 - break;
147 + if (err < 0) {
148 + sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
149 + break;
150 + }
151 +
152 + /* If this is a power level 1 module, we are done */
153 + if (sfp->module_power_mW <= 1000)
154 + goto insert;
155
156 + sfp_sm_mod_next(sfp, SFP_MOD_HPOWER, 0);
157 + /* fall through */
158 case SFP_MOD_HPOWER:
159 - if (event == SFP_E_TIMEOUT) {
160 - sfp_sm_mod_next(sfp, SFP_MOD_PRESENT, 0);
161 + /* Enable high power mode */
162 + err = sfp_sm_mod_hpower(sfp, true);
163 + if (err == 0)
164 + sfp_sm_mod_next(sfp, SFP_MOD_WAITPWR, T_HPOWER_LEVEL);
165 + else if (err != -EAGAIN)
166 + sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
167 + else
168 + sfp_sm_set_timer(sfp, T_PROBE_RETRY);
169 + break;
170 +
171 + case SFP_MOD_WAITPWR:
172 + /* Wait for T_HPOWER_LEVEL to time out */
173 + if (event != SFP_E_TIMEOUT)
174 break;
175 - }
176 - /* fallthrough */
177 +
178 + insert:
179 + sfp_sm_mod_next(sfp, SFP_MOD_PRESENT, 0);
180 + break;
181 +
182 case SFP_MOD_PRESENT:
183 case SFP_MOD_ERROR:
184 break;