2121#include <linux/spinlock.h>
2222#include <linux/workqueue.h>
2323
24+ #include "sfp.h"
2425#include "swphy.h"
2526
2627#define SUPPORTED_INTERFACES \
3233
3334enum {
3435 PHYLINK_DISABLE_STOPPED ,
36+ PHYLINK_DISABLE_LINK ,
3537};
3638
3739struct phylink {
@@ -54,6 +56,8 @@ struct phylink {
5456 struct work_struct resolve ;
5557
5658 bool mac_link_dropped ;
59+
60+ struct sfp_bus * sfp_bus ;
5761};
5862
5963static inline void linkmode_zero (unsigned long * dst )
@@ -466,6 +470,24 @@ static void phylink_run_resolve(struct phylink *pl)
466470 queue_work (system_power_efficient_wq , & pl -> resolve );
467471}
468472
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+
469491struct phylink * phylink_create (struct net_device * ndev , struct device_node * np ,
470492 phy_interface_t iface , const struct phylink_mac_ops * ops )
471493{
@@ -507,12 +529,21 @@ struct phylink *phylink_create(struct net_device *ndev, struct device_node *np,
507529 }
508530 }
509531
532+ ret = phylink_register_sfp (pl , np );
533+ if (ret < 0 ) {
534+ kfree (pl );
535+ return ERR_PTR (ret );
536+ }
537+
510538 return pl ;
511539}
512540EXPORT_SYMBOL_GPL (phylink_create );
513541
514542void phylink_destroy (struct phylink * pl )
515543{
544+ if (pl -> sfp_bus )
545+ sfp_unregister_upstream (pl -> sfp_bus );
546+
516547 cancel_work_sync (& pl -> resolve );
517548 kfree (pl );
518549}
@@ -706,6 +737,8 @@ void phylink_start(struct phylink *pl)
706737 clear_bit (PHYLINK_DISABLE_STOPPED , & pl -> phylink_disable_state );
707738 phylink_run_resolve (pl );
708739
740+ if (pl -> sfp_bus )
741+ sfp_upstream_start (pl -> sfp_bus );
709742 if (pl -> phydev )
710743 phy_start (pl -> phydev );
711744}
@@ -717,6 +750,8 @@ void phylink_stop(struct phylink *pl)
717750
718751 if (pl -> phydev )
719752 phy_stop (pl -> phydev );
753+ if (pl -> sfp_bus )
754+ sfp_upstream_stop (pl -> sfp_bus );
720755
721756 set_bit (PHYLINK_DISABLE_STOPPED , & pl -> phylink_disable_state );
722757 flush_work (& pl -> resolve );
@@ -1166,4 +1201,126 @@ int phylink_mii_ioctl(struct phylink *pl, struct ifreq *ifr, int cmd)
11661201}
11671202EXPORT_SYMBOL_GPL (phylink_mii_ioctl );
11681203
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+
11691326MODULE_LICENSE ("GPL" );
0 commit comments