06b3cb54284cd0b12c5f68eb0c84594bada9d1cb
[oweals/openwrt.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 @@ -47,6 +47,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 @@ -69,6 +70,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 @@ -1358,37 +1360,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 @@ -1484,7 +1483,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 @@ -1529,13 +1528,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 @@ -1547,26 +1555,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;