@@ -547,6 +547,70 @@ static void ptys2ethtool_adver_link(unsigned long *advertising_modes,
547
547
__ETHTOOL_LINK_MODE_MASK_NBITS );
548
548
}
549
549
550
+ static const u32 pplm_fec_2_ethtool [] = {
551
+ [MLX5E_FEC_NOFEC ] = ETHTOOL_FEC_OFF ,
552
+ [MLX5E_FEC_FIRECODE ] = ETHTOOL_FEC_BASER ,
553
+ [MLX5E_FEC_RS_528_514 ] = ETHTOOL_FEC_RS ,
554
+ };
555
+
556
+ static u32 pplm2ethtool_fec (u_long fec_mode , unsigned long size )
557
+ {
558
+ int mode = 0 ;
559
+
560
+ if (!fec_mode )
561
+ return ETHTOOL_FEC_AUTO ;
562
+
563
+ mode = find_first_bit (& fec_mode , size );
564
+
565
+ if (mode < ARRAY_SIZE (pplm_fec_2_ethtool ))
566
+ return pplm_fec_2_ethtool [mode ];
567
+
568
+ return 0 ;
569
+ }
570
+
571
+ /* we use ETHTOOL_FEC_* offset and apply it to ETHTOOL_LINK_MODE_FEC_*_BIT */
572
+ static u32 ethtool_fec2ethtool_caps (u_long ethtool_fec_code )
573
+ {
574
+ u32 offset ;
575
+
576
+ offset = find_first_bit (& ethtool_fec_code , sizeof (u32 ));
577
+ offset -= ETHTOOL_FEC_OFF_BIT ;
578
+ offset += ETHTOOL_LINK_MODE_FEC_NONE_BIT ;
579
+
580
+ return offset ;
581
+ }
582
+
583
+ static int get_fec_supported_advertised (struct mlx5_core_dev * dev ,
584
+ struct ethtool_link_ksettings * link_ksettings )
585
+ {
586
+ u_long fec_caps = 0 ;
587
+ u32 active_fec = 0 ;
588
+ u32 offset ;
589
+ u32 bitn ;
590
+ int err ;
591
+
592
+ err = mlx5e_get_fec_caps (dev , (u8 * )& fec_caps );
593
+ if (err )
594
+ return (err == - EOPNOTSUPP ) ? 0 : err ;
595
+
596
+ err = mlx5e_get_fec_mode (dev , & active_fec , NULL );
597
+ if (err )
598
+ return err ;
599
+
600
+ for_each_set_bit (bitn , & fec_caps , ARRAY_SIZE (pplm_fec_2_ethtool )) {
601
+ u_long ethtool_bitmask = pplm_fec_2_ethtool [bitn ];
602
+
603
+ offset = ethtool_fec2ethtool_caps (ethtool_bitmask );
604
+ __set_bit (offset , link_ksettings -> link_modes .supported );
605
+ }
606
+
607
+ active_fec = pplm2ethtool_fec (active_fec , sizeof (u32 ) * BITS_PER_BYTE );
608
+ offset = ethtool_fec2ethtool_caps (active_fec );
609
+ __set_bit (offset , link_ksettings -> link_modes .advertising );
610
+
611
+ return 0 ;
612
+ }
613
+
550
614
static void ptys2ethtool_supported_advertised_port (struct ethtool_link_ksettings * link_ksettings ,
551
615
u32 eth_proto_cap ,
552
616
u8 connector_type )
@@ -742,7 +806,7 @@ static int mlx5e_get_link_ksettings(struct net_device *netdev,
742
806
if (err ) {
743
807
netdev_err (netdev , "%s: query port ptys failed: %d\n" ,
744
808
__func__ , err );
745
- goto err_query_ptys ;
809
+ goto err_query_regs ;
746
810
}
747
811
748
812
eth_proto_cap = MLX5_GET (ptys_reg , out , eth_proto_capability );
@@ -778,11 +842,17 @@ static int mlx5e_get_link_ksettings(struct net_device *netdev,
778
842
AUTONEG_ENABLE ;
779
843
ethtool_link_ksettings_add_link_mode (link_ksettings , supported ,
780
844
Autoneg );
845
+
846
+ err = get_fec_supported_advertised (mdev , link_ksettings );
847
+ if (err )
848
+ netdev_dbg (netdev , "%s: FEC caps query failed: %d\n" ,
849
+ __func__ , err );
850
+
781
851
if (!an_disable_admin )
782
852
ethtool_link_ksettings_add_link_mode (link_ksettings ,
783
853
advertising , Autoneg );
784
854
785
- err_query_ptys :
855
+ err_query_regs :
786
856
return err ;
787
857
}
788
858
@@ -1277,6 +1347,58 @@ static int mlx5e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
1277
1347
return mlx5_set_port_wol (mdev , mlx5_wol_mode );
1278
1348
}
1279
1349
1350
+ static int mlx5e_get_fecparam (struct net_device * netdev ,
1351
+ struct ethtool_fecparam * fecparam )
1352
+ {
1353
+ struct mlx5e_priv * priv = netdev_priv (netdev );
1354
+ struct mlx5_core_dev * mdev = priv -> mdev ;
1355
+ u8 fec_configured = 0 ;
1356
+ u32 fec_active = 0 ;
1357
+ int err ;
1358
+
1359
+ err = mlx5e_get_fec_mode (mdev , & fec_active , & fec_configured );
1360
+
1361
+ if (err )
1362
+ return err ;
1363
+
1364
+ fecparam -> active_fec = pplm2ethtool_fec ((u_long )fec_active ,
1365
+ sizeof (u32 ) * BITS_PER_BYTE );
1366
+
1367
+ if (!fecparam -> active_fec )
1368
+ return - EOPNOTSUPP ;
1369
+
1370
+ fecparam -> fec = pplm2ethtool_fec ((u_long )fec_configured ,
1371
+ sizeof (u8 ) * BITS_PER_BYTE );
1372
+
1373
+ return 0 ;
1374
+ }
1375
+
1376
+ static int mlx5e_set_fecparam (struct net_device * netdev ,
1377
+ struct ethtool_fecparam * fecparam )
1378
+ {
1379
+ struct mlx5e_priv * priv = netdev_priv (netdev );
1380
+ struct mlx5_core_dev * mdev = priv -> mdev ;
1381
+ u8 fec_policy = 0 ;
1382
+ int mode ;
1383
+ int err ;
1384
+
1385
+ for (mode = 0 ; mode < ARRAY_SIZE (pplm_fec_2_ethtool ); mode ++ ) {
1386
+ if (!(pplm_fec_2_ethtool [mode ] & fecparam -> fec ))
1387
+ continue ;
1388
+ fec_policy |= (1 << mode );
1389
+ break ;
1390
+ }
1391
+
1392
+ err = mlx5e_set_fec_mode (mdev , fec_policy );
1393
+
1394
+ if (err )
1395
+ return err ;
1396
+
1397
+ mlx5_toggle_port_link (mdev );
1398
+
1399
+ return 0 ;
1400
+ }
1401
+
1280
1402
static u32 mlx5e_get_msglevel (struct net_device * dev )
1281
1403
{
1282
1404
return ((struct mlx5e_priv * )netdev_priv (dev ))-> msglevel ;
@@ -1699,4 +1821,6 @@ const struct ethtool_ops mlx5e_ethtool_ops = {
1699
1821
.self_test = mlx5e_self_test ,
1700
1822
.get_msglevel = mlx5e_get_msglevel ,
1701
1823
.set_msglevel = mlx5e_set_msglevel ,
1824
+ .get_fecparam = mlx5e_get_fecparam ,
1825
+ .set_fecparam = mlx5e_set_fecparam ,
1702
1826
};
0 commit comments