52
52
#define MV_1GBX_PHY_STAT_SPEED100 BIT(14)
53
53
#define MV_1GBX_PHY_STAT_SPEED1000 BIT(15)
54
54
55
+ #define AUTONEG_TIMEOUT 3
56
+
55
57
struct mv2222_data {
56
58
phy_interface_t line_interface ;
57
59
__ETHTOOL_DECLARE_LINK_MODE_MASK (supported );
@@ -173,6 +175,24 @@ static bool mv2222_is_1gbx_capable(struct phy_device *phydev)
173
175
priv -> supported );
174
176
}
175
177
178
+ static bool mv2222_is_sgmii_capable (struct phy_device * phydev )
179
+ {
180
+ struct mv2222_data * priv = phydev -> priv ;
181
+
182
+ return (linkmode_test_bit (ETHTOOL_LINK_MODE_1000baseT_Full_BIT ,
183
+ priv -> supported ) ||
184
+ linkmode_test_bit (ETHTOOL_LINK_MODE_1000baseT_Half_BIT ,
185
+ priv -> supported ) ||
186
+ linkmode_test_bit (ETHTOOL_LINK_MODE_100baseT_Full_BIT ,
187
+ priv -> supported ) ||
188
+ linkmode_test_bit (ETHTOOL_LINK_MODE_100baseT_Half_BIT ,
189
+ priv -> supported ) ||
190
+ linkmode_test_bit (ETHTOOL_LINK_MODE_10baseT_Full_BIT ,
191
+ priv -> supported ) ||
192
+ linkmode_test_bit (ETHTOOL_LINK_MODE_10baseT_Half_BIT ,
193
+ priv -> supported ));
194
+ }
195
+
176
196
static int mv2222_config_line (struct phy_device * phydev )
177
197
{
178
198
struct mv2222_data * priv = phydev -> priv ;
@@ -192,33 +212,32 @@ static int mv2222_config_line(struct phy_device *phydev)
192
212
}
193
213
}
194
214
195
- static int mv2222_setup_forced (struct phy_device * phydev )
215
+ /* Switch between 1G (1000Base-X/SGMII) and 10G (10GBase-R) modes */
216
+ static int mv2222_swap_line_type (struct phy_device * phydev )
196
217
{
197
218
struct mv2222_data * priv = phydev -> priv ;
198
219
bool changed = false;
199
220
int ret ;
200
221
201
222
switch (priv -> line_interface ) {
202
223
case PHY_INTERFACE_MODE_10GBASER :
203
- if (phydev -> speed == SPEED_1000 &&
204
- mv2222_is_1gbx_capable (phydev )) {
224
+ if (mv2222_is_1gbx_capable (phydev )) {
205
225
priv -> line_interface = PHY_INTERFACE_MODE_1000BASEX ;
206
226
changed = true;
207
227
}
208
228
209
- break ;
210
- case PHY_INTERFACE_MODE_1000BASEX :
211
- if (phydev -> speed == SPEED_10000 &&
212
- mv2222_is_10g_capable (phydev )) {
213
- priv -> line_interface = PHY_INTERFACE_MODE_10GBASER ;
229
+ if (mv2222_is_sgmii_capable (phydev )) {
230
+ priv -> line_interface = PHY_INTERFACE_MODE_SGMII ;
214
231
changed = true;
215
232
}
216
233
217
234
break ;
235
+ case PHY_INTERFACE_MODE_1000BASEX :
218
236
case PHY_INTERFACE_MODE_SGMII :
219
- ret = mv2222_set_sgmii_speed (phydev );
220
- if (ret < 0 )
221
- return ret ;
237
+ if (mv2222_is_10g_capable (phydev )) {
238
+ priv -> line_interface = PHY_INTERFACE_MODE_10GBASER ;
239
+ changed = true;
240
+ }
222
241
223
242
break ;
224
243
default :
@@ -231,6 +250,29 @@ static int mv2222_setup_forced(struct phy_device *phydev)
231
250
return ret ;
232
251
}
233
252
253
+ return 0 ;
254
+ }
255
+
256
+ static int mv2222_setup_forced (struct phy_device * phydev )
257
+ {
258
+ struct mv2222_data * priv = phydev -> priv ;
259
+ int ret ;
260
+
261
+ if (priv -> line_interface == PHY_INTERFACE_MODE_10GBASER ) {
262
+ if (phydev -> speed < SPEED_10000 &&
263
+ phydev -> speed != SPEED_UNKNOWN ) {
264
+ ret = mv2222_swap_line_type (phydev );
265
+ if (ret < 0 )
266
+ return ret ;
267
+ }
268
+ }
269
+
270
+ if (priv -> line_interface == PHY_INTERFACE_MODE_SGMII ) {
271
+ ret = mv2222_set_sgmii_speed (phydev );
272
+ if (ret < 0 )
273
+ return ret ;
274
+ }
275
+
234
276
return mv2222_disable_aneg (phydev );
235
277
}
236
278
@@ -244,17 +286,9 @@ static int mv2222_config_aneg(struct phy_device *phydev)
244
286
return 0 ;
245
287
246
288
if (phydev -> autoneg == AUTONEG_DISABLE ||
247
- phydev -> speed == SPEED_10000 )
289
+ priv -> line_interface == PHY_INTERFACE_MODE_10GBASER )
248
290
return mv2222_setup_forced (phydev );
249
291
250
- if (priv -> line_interface == PHY_INTERFACE_MODE_10GBASER &&
251
- mv2222_is_1gbx_capable (phydev )) {
252
- priv -> line_interface = PHY_INTERFACE_MODE_1000BASEX ;
253
- ret = mv2222_config_line (phydev );
254
- if (ret < 0 )
255
- return ret ;
256
- }
257
-
258
292
adv = linkmode_adv_to_mii_adv_x (priv -> supported ,
259
293
ETHTOOL_LINK_MODE_1000baseX_Full_BIT );
260
294
@@ -291,6 +325,7 @@ static int mv2222_aneg_done(struct phy_device *phydev)
291
325
/* Returns negative on error, 0 if link is down, 1 if link is up */
292
326
static int mv2222_read_status_10g (struct phy_device * phydev )
293
327
{
328
+ static int timeout ;
294
329
int val , link = 0 ;
295
330
296
331
val = phy_read_mmd (phydev , MDIO_MMD_PCS , MDIO_STAT1 );
@@ -304,6 +339,20 @@ static int mv2222_read_status_10g(struct phy_device *phydev)
304
339
phydev -> autoneg = AUTONEG_DISABLE ;
305
340
phydev -> speed = SPEED_10000 ;
306
341
phydev -> duplex = DUPLEX_FULL ;
342
+ } else {
343
+ if (phydev -> autoneg == AUTONEG_ENABLE ) {
344
+ timeout ++ ;
345
+
346
+ if (timeout > AUTONEG_TIMEOUT ) {
347
+ timeout = 0 ;
348
+
349
+ val = mv2222_swap_line_type (phydev );
350
+ if (val < 0 )
351
+ return val ;
352
+
353
+ return mv2222_config_aneg (phydev );
354
+ }
355
+ }
307
356
}
308
357
309
358
return link ;
@@ -312,15 +361,31 @@ static int mv2222_read_status_10g(struct phy_device *phydev)
312
361
/* Returns negative on error, 0 if link is down, 1 if link is up */
313
362
static int mv2222_read_status_1g (struct phy_device * phydev )
314
363
{
364
+ static int timeout ;
315
365
int val , link = 0 ;
316
366
317
367
val = phy_read_mmd (phydev , MDIO_MMD_PCS , MV_1GBX_STAT );
318
368
if (val < 0 )
319
369
return val ;
320
370
321
- if (!(val & BMSR_LSTATUS ) ||
322
- (phydev -> autoneg == AUTONEG_ENABLE &&
323
- !(val & BMSR_ANEGCOMPLETE )))
371
+ if (phydev -> autoneg == AUTONEG_ENABLE &&
372
+ !(val & BMSR_ANEGCOMPLETE )) {
373
+ timeout ++ ;
374
+
375
+ if (timeout > AUTONEG_TIMEOUT ) {
376
+ timeout = 0 ;
377
+
378
+ val = mv2222_swap_line_type (phydev );
379
+ if (val < 0 )
380
+ return val ;
381
+
382
+ return mv2222_config_aneg (phydev );
383
+ }
384
+
385
+ return 0 ;
386
+ }
387
+
388
+ if (!(val & BMSR_LSTATUS ))
324
389
return 0 ;
325
390
326
391
link = 1 ;
@@ -447,11 +512,7 @@ static int mv2222_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
447
512
return ret ;
448
513
449
514
if (mutex_trylock (& phydev -> lock )) {
450
- if (priv -> line_interface == PHY_INTERFACE_MODE_10GBASER )
451
- ret = mv2222_setup_forced (phydev );
452
- else
453
- ret = mv2222_config_aneg (phydev );
454
-
515
+ ret = mv2222_config_aneg (phydev );
455
516
mutex_unlock (& phydev -> lock );
456
517
}
457
518
0 commit comments