21
21
#include <linux/spinlock.h>
22
22
#include <linux/workqueue.h>
23
23
24
+ #include "sfp.h"
24
25
#include "swphy.h"
25
26
26
27
#define SUPPORTED_INTERFACES \
32
33
33
34
enum {
34
35
PHYLINK_DISABLE_STOPPED ,
36
+ PHYLINK_DISABLE_LINK ,
35
37
};
36
38
37
39
struct phylink {
@@ -54,6 +56,8 @@ struct phylink {
54
56
struct work_struct resolve ;
55
57
56
58
bool mac_link_dropped ;
59
+
60
+ struct sfp_bus * sfp_bus ;
57
61
};
58
62
59
63
static inline void linkmode_zero (unsigned long * dst )
@@ -466,6 +470,24 @@ static void phylink_run_resolve(struct phylink *pl)
466
470
queue_work (system_power_efficient_wq , & pl -> resolve );
467
471
}
468
472
473
+ static const struct sfp_upstream_ops sfp_phylink_ops ;
474
+
475
+ static int phylink_register_sfp (struct phylink * pl , struct device_node * np )
476
+ {
477
+ struct device_node * sfp_np ;
478
+
479
+ sfp_np = of_parse_phandle (np , "sfp" , 0 );
480
+ if (!sfp_np )
481
+ return 0 ;
482
+
483
+ pl -> sfp_bus = sfp_register_upstream (sfp_np , pl -> netdev , pl ,
484
+ & sfp_phylink_ops );
485
+ if (!pl -> sfp_bus )
486
+ return - ENOMEM ;
487
+
488
+ return 0 ;
489
+ }
490
+
469
491
struct phylink * phylink_create (struct net_device * ndev , struct device_node * np ,
470
492
phy_interface_t iface , const struct phylink_mac_ops * ops )
471
493
{
@@ -507,12 +529,21 @@ struct phylink *phylink_create(struct net_device *ndev, struct device_node *np,
507
529
}
508
530
}
509
531
532
+ ret = phylink_register_sfp (pl , np );
533
+ if (ret < 0 ) {
534
+ kfree (pl );
535
+ return ERR_PTR (ret );
536
+ }
537
+
510
538
return pl ;
511
539
}
512
540
EXPORT_SYMBOL_GPL (phylink_create );
513
541
514
542
void phylink_destroy (struct phylink * pl )
515
543
{
544
+ if (pl -> sfp_bus )
545
+ sfp_unregister_upstream (pl -> sfp_bus );
546
+
516
547
cancel_work_sync (& pl -> resolve );
517
548
kfree (pl );
518
549
}
@@ -706,6 +737,8 @@ void phylink_start(struct phylink *pl)
706
737
clear_bit (PHYLINK_DISABLE_STOPPED , & pl -> phylink_disable_state );
707
738
phylink_run_resolve (pl );
708
739
740
+ if (pl -> sfp_bus )
741
+ sfp_upstream_start (pl -> sfp_bus );
709
742
if (pl -> phydev )
710
743
phy_start (pl -> phydev );
711
744
}
@@ -717,6 +750,8 @@ void phylink_stop(struct phylink *pl)
717
750
718
751
if (pl -> phydev )
719
752
phy_stop (pl -> phydev );
753
+ if (pl -> sfp_bus )
754
+ sfp_upstream_stop (pl -> sfp_bus );
720
755
721
756
set_bit (PHYLINK_DISABLE_STOPPED , & pl -> phylink_disable_state );
722
757
flush_work (& pl -> resolve );
@@ -1166,4 +1201,126 @@ int phylink_mii_ioctl(struct phylink *pl, struct ifreq *ifr, int cmd)
1166
1201
}
1167
1202
EXPORT_SYMBOL_GPL (phylink_mii_ioctl );
1168
1203
1204
+
1205
+
1206
+ static int phylink_sfp_module_insert (void * upstream ,
1207
+ const struct sfp_eeprom_id * id )
1208
+ {
1209
+ struct phylink * pl = upstream ;
1210
+ __ETHTOOL_DECLARE_LINK_MODE_MASK (support ) = { 0 , };
1211
+ struct phylink_link_state config ;
1212
+ phy_interface_t iface ;
1213
+ int mode , ret = 0 ;
1214
+ bool changed ;
1215
+ u8 port ;
1216
+
1217
+ sfp_parse_support (pl -> sfp_bus , id , support );
1218
+ port = sfp_parse_port (pl -> sfp_bus , id , support );
1219
+ iface = sfp_parse_interface (pl -> sfp_bus , id );
1220
+
1221
+ WARN_ON (!lockdep_rtnl_is_held ());
1222
+
1223
+ switch (iface ) {
1224
+ case PHY_INTERFACE_MODE_SGMII :
1225
+ mode = MLO_AN_SGMII ;
1226
+ break ;
1227
+ case PHY_INTERFACE_MODE_1000BASEX :
1228
+ mode = MLO_AN_8023Z ;
1229
+ break ;
1230
+ default :
1231
+ return - EINVAL ;
1232
+ }
1233
+
1234
+ memset (& config , 0 , sizeof (config ));
1235
+ linkmode_copy (config .advertising , support );
1236
+ config .interface = iface ;
1237
+ config .speed = SPEED_UNKNOWN ;
1238
+ config .duplex = DUPLEX_UNKNOWN ;
1239
+ config .pause = MLO_PAUSE_AN ;
1240
+ config .an_enabled = pl -> link_config .an_enabled ;
1241
+
1242
+ /* Ignore errors if we're expecting a PHY to attach later */
1243
+ ret = phylink_validate (pl , support , & config );
1244
+ if (ret ) {
1245
+ netdev_err (pl -> netdev , "validation of %s/%s with support %*pb failed: %d\n" ,
1246
+ phylink_an_mode_str (mode ), phy_modes (config .interface ),
1247
+ __ETHTOOL_LINK_MODE_MASK_NBITS , support , ret );
1248
+ return ret ;
1249
+ }
1250
+
1251
+ netdev_dbg (pl -> netdev , "requesting link mode %s/%s with support %*pb\n" ,
1252
+ phylink_an_mode_str (mode ), phy_modes (config .interface ),
1253
+ __ETHTOOL_LINK_MODE_MASK_NBITS , support );
1254
+
1255
+ if (mode == MLO_AN_8023Z && pl -> phydev )
1256
+ return - EINVAL ;
1257
+
1258
+ changed = !bitmap_equal (pl -> supported , support ,
1259
+ __ETHTOOL_LINK_MODE_MASK_NBITS );
1260
+ if (changed ) {
1261
+ linkmode_copy (pl -> supported , support );
1262
+ linkmode_copy (pl -> link_config .advertising , config .advertising );
1263
+ }
1264
+
1265
+ if (pl -> link_an_mode != mode ||
1266
+ pl -> link_config .interface != config .interface ) {
1267
+ pl -> link_config .interface = config .interface ;
1268
+ pl -> link_an_mode = mode ;
1269
+
1270
+ changed = true;
1271
+
1272
+ netdev_info (pl -> netdev , "switched to %s/%s link mode\n" ,
1273
+ phylink_an_mode_str (mode ),
1274
+ phy_modes (config .interface ));
1275
+ }
1276
+
1277
+ pl -> link_port = port ;
1278
+
1279
+ if (changed && !test_bit (PHYLINK_DISABLE_STOPPED ,
1280
+ & pl -> phylink_disable_state ))
1281
+ phylink_mac_config (pl , & pl -> link_config );
1282
+
1283
+ return ret ;
1284
+ }
1285
+
1286
+ static void phylink_sfp_link_down (void * upstream )
1287
+ {
1288
+ struct phylink * pl = upstream ;
1289
+
1290
+ WARN_ON (!lockdep_rtnl_is_held ());
1291
+
1292
+ set_bit (PHYLINK_DISABLE_LINK , & pl -> phylink_disable_state );
1293
+ flush_work (& pl -> resolve );
1294
+
1295
+ netif_carrier_off (pl -> netdev );
1296
+ }
1297
+
1298
+ static void phylink_sfp_link_up (void * upstream )
1299
+ {
1300
+ struct phylink * pl = upstream ;
1301
+
1302
+ WARN_ON (!lockdep_rtnl_is_held ());
1303
+
1304
+ clear_bit (PHYLINK_DISABLE_LINK , & pl -> phylink_disable_state );
1305
+ phylink_run_resolve (pl );
1306
+ }
1307
+
1308
+ static int phylink_sfp_connect_phy (void * upstream , struct phy_device * phy )
1309
+ {
1310
+ return phylink_connect_phy (upstream , phy );
1311
+ }
1312
+
1313
+ static void phylink_sfp_disconnect_phy (void * upstream )
1314
+ {
1315
+ phylink_disconnect_phy (upstream );
1316
+ }
1317
+
1318
+ static const struct sfp_upstream_ops sfp_phylink_ops = {
1319
+ .module_insert = phylink_sfp_module_insert ,
1320
+ .link_up = phylink_sfp_link_up ,
1321
+ .link_down = phylink_sfp_link_down ,
1322
+ .connect_phy = phylink_sfp_connect_phy ,
1323
+ .disconnect_phy = phylink_sfp_disconnect_phy ,
1324
+ };
1325
+
1169
1326
MODULE_LICENSE ("GPL" );
0 commit comments