Skip to content

Commit 1d96340

Browse files
Damian DybekJeff Kirsher
authored andcommitted
i40e: Add support FEC configuration for Fortville 25G
This patch adds support for setting/getting FEC configuration using ethtool options: set/show-priv-flags rs-fec/base-r-fec set/show-fec off/rs/baser/auto for kernels version >= 4.14 Signed-off-by: Damian Dybek <[email protected]> Tested-by: Andrew Bowers <[email protected]> Signed-off-by: Jeff Kirsher <[email protected]>
1 parent 3647cd6 commit 1d96340

File tree

3 files changed

+256
-2
lines changed

3 files changed

+256
-2
lines changed

drivers/net/ethernet/intel/i40e/i40e.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,8 @@ struct i40e_pf {
524524
#define I40E_FLAG_FD_SB_INACTIVE BIT(22)
525525
#define I40E_FLAG_FD_SB_TO_CLOUD_FILTER BIT(23)
526526
#define I40E_FLAG_DISABLE_FW_LLDP BIT(24)
527+
#define I40E_FLAG_RS_FEC BIT(25)
528+
#define I40E_FLAG_BASE_R_FEC BIT(26)
527529

528530
struct i40e_client_instance *cinst;
529531
bool stat_offsets_loaded;
@@ -1087,6 +1089,8 @@ i40e_status i40e_set_partition_bw_setting(struct i40e_pf *pf);
10871089
i40e_status i40e_commit_partition_bw_setting(struct i40e_pf *pf);
10881090
void i40e_print_link_message(struct i40e_vsi *vsi, bool isup);
10891091

1092+
void i40e_set_fec_in_flags(u8 fec_cfg, u32 *flags);
1093+
10901094
static inline bool i40e_enabled_xdp_vsi(struct i40e_vsi *vsi)
10911095
{
10921096
return !!vsi->xdp_prog;

drivers/net/ethernet/intel/i40e/i40e_ethtool.c

Lines changed: 226 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,8 @@ static const struct i40e_priv_flags i40e_gstrings_priv_flags[] = {
438438
I40E_PRIV_FLAG("disable-source-pruning",
439439
I40E_FLAG_SOURCE_PRUNING_DISABLED, 0),
440440
I40E_PRIV_FLAG("disable-fw-lldp", I40E_FLAG_DISABLE_FW_LLDP, 0),
441+
I40E_PRIV_FLAG("rs-fec", I40E_FLAG_RS_FEC, 0),
442+
I40E_PRIV_FLAG("base-r-fec", I40E_FLAG_BASE_R_FEC, 0),
441443
};
442444

443445
#define I40E_PRIV_FLAGS_STR_LEN ARRAY_SIZE(i40e_gstrings_priv_flags)
@@ -606,6 +608,24 @@ static void i40e_phy_type_to_ethtool(struct i40e_pf *pf,
606608
ethtool_link_ksettings_add_link_mode(ks, advertising,
607609
25000baseCR_Full);
608610
}
611+
if (phy_types & I40E_CAP_PHY_TYPE_25GBASE_KR ||
612+
phy_types & I40E_CAP_PHY_TYPE_25GBASE_CR ||
613+
phy_types & I40E_CAP_PHY_TYPE_25GBASE_SR ||
614+
phy_types & I40E_CAP_PHY_TYPE_25GBASE_LR ||
615+
phy_types & I40E_CAP_PHY_TYPE_25GBASE_AOC ||
616+
phy_types & I40E_CAP_PHY_TYPE_25GBASE_ACC) {
617+
ethtool_link_ksettings_add_link_mode(ks, supported, FEC_NONE);
618+
ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS);
619+
ethtool_link_ksettings_add_link_mode(ks, supported, FEC_BASER);
620+
if (hw_link_info->requested_speeds & I40E_LINK_SPEED_25GB) {
621+
ethtool_link_ksettings_add_link_mode(ks, advertising,
622+
FEC_NONE);
623+
ethtool_link_ksettings_add_link_mode(ks, advertising,
624+
FEC_RS);
625+
ethtool_link_ksettings_add_link_mode(ks, advertising,
626+
FEC_BASER);
627+
}
628+
}
609629
/* need to add new 10G PHY types */
610630
if (phy_types & I40E_CAP_PHY_TYPE_10GBASE_CR1 ||
611631
phy_types & I40E_CAP_PHY_TYPE_10GBASE_CR1_CU) {
@@ -721,6 +741,13 @@ static void i40e_get_settings_link_up(struct i40e_hw *hw,
721741
25000baseSR_Full);
722742
ethtool_link_ksettings_add_link_mode(ks, advertising,
723743
25000baseSR_Full);
744+
ethtool_link_ksettings_add_link_mode(ks, supported, FEC_NONE);
745+
ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS);
746+
ethtool_link_ksettings_add_link_mode(ks, supported, FEC_BASER);
747+
ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_NONE);
748+
ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_RS);
749+
ethtool_link_ksettings_add_link_mode(ks, advertising,
750+
FEC_BASER);
724751
ethtool_link_ksettings_add_link_mode(ks, supported,
725752
10000baseSR_Full);
726753
ethtool_link_ksettings_add_link_mode(ks, advertising,
@@ -825,6 +852,9 @@ static void i40e_get_settings_link_up(struct i40e_hw *hw,
825852
40000baseKR4_Full);
826853
ethtool_link_ksettings_add_link_mode(ks, supported,
827854
25000baseKR_Full);
855+
ethtool_link_ksettings_add_link_mode(ks, supported, FEC_NONE);
856+
ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS);
857+
ethtool_link_ksettings_add_link_mode(ks, supported, FEC_BASER);
828858
ethtool_link_ksettings_add_link_mode(ks, supported,
829859
20000baseKR2_Full);
830860
ethtool_link_ksettings_add_link_mode(ks, supported,
@@ -838,6 +868,10 @@ static void i40e_get_settings_link_up(struct i40e_hw *hw,
838868
40000baseKR4_Full);
839869
ethtool_link_ksettings_add_link_mode(ks, advertising,
840870
25000baseKR_Full);
871+
ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_NONE);
872+
ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_RS);
873+
ethtool_link_ksettings_add_link_mode(ks, advertising,
874+
FEC_BASER);
841875
ethtool_link_ksettings_add_link_mode(ks, advertising,
842876
20000baseKR2_Full);
843877
ethtool_link_ksettings_add_link_mode(ks, advertising,
@@ -855,16 +889,29 @@ static void i40e_get_settings_link_up(struct i40e_hw *hw,
855889
25000baseCR_Full);
856890
ethtool_link_ksettings_add_link_mode(ks, advertising,
857891
25000baseCR_Full);
892+
ethtool_link_ksettings_add_link_mode(ks, supported, FEC_NONE);
893+
ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS);
894+
ethtool_link_ksettings_add_link_mode(ks, supported, FEC_BASER);
895+
ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_NONE);
896+
ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_RS);
897+
ethtool_link_ksettings_add_link_mode(ks, advertising,
898+
FEC_BASER);
858899
break;
859900
case I40E_PHY_TYPE_25GBASE_AOC:
860901
case I40E_PHY_TYPE_25GBASE_ACC:
861902
ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
862903
ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
863904
ethtool_link_ksettings_add_link_mode(ks, supported,
864905
25000baseCR_Full);
865-
866906
ethtool_link_ksettings_add_link_mode(ks, advertising,
867907
25000baseCR_Full);
908+
ethtool_link_ksettings_add_link_mode(ks, supported, FEC_NONE);
909+
ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS);
910+
ethtool_link_ksettings_add_link_mode(ks, supported, FEC_BASER);
911+
ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_NONE);
912+
ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_RS);
913+
ethtool_link_ksettings_add_link_mode(ks, advertising,
914+
FEC_BASER);
868915
ethtool_link_ksettings_add_link_mode(ks, supported,
869916
10000baseCR_Full);
870917
ethtool_link_ksettings_add_link_mode(ks, advertising,
@@ -1261,6 +1308,154 @@ static int i40e_set_link_ksettings(struct net_device *netdev,
12611308
return err;
12621309
}
12631310

1311+
static int i40e_set_fec_cfg(struct net_device *netdev, u8 fec_cfg)
1312+
{
1313+
struct i40e_netdev_priv *np = netdev_priv(netdev);
1314+
struct i40e_aq_get_phy_abilities_resp abilities;
1315+
struct i40e_pf *pf = np->vsi->back;
1316+
struct i40e_hw *hw = &pf->hw;
1317+
i40e_status status = 0;
1318+
u32 flags = 0;
1319+
int err = 0;
1320+
1321+
flags = READ_ONCE(pf->flags);
1322+
i40e_set_fec_in_flags(fec_cfg, &flags);
1323+
1324+
/* Get the current phy config */
1325+
memset(&abilities, 0, sizeof(abilities));
1326+
status = i40e_aq_get_phy_capabilities(hw, false, false, &abilities,
1327+
NULL);
1328+
if (status) {
1329+
err = -EAGAIN;
1330+
goto done;
1331+
}
1332+
1333+
if (abilities.fec_cfg_curr_mod_ext_info != fec_cfg) {
1334+
struct i40e_aq_set_phy_config config;
1335+
1336+
memset(&config, 0, sizeof(config));
1337+
config.phy_type = abilities.phy_type;
1338+
config.abilities = abilities.abilities;
1339+
config.phy_type_ext = abilities.phy_type_ext;
1340+
config.link_speed = abilities.link_speed;
1341+
config.eee_capability = abilities.eee_capability;
1342+
config.eeer = abilities.eeer_val;
1343+
config.low_power_ctrl = abilities.d3_lpan;
1344+
config.fec_config = fec_cfg & I40E_AQ_PHY_FEC_CONFIG_MASK;
1345+
status = i40e_aq_set_phy_config(hw, &config, NULL);
1346+
if (status) {
1347+
netdev_info(netdev,
1348+
"Set phy config failed, err %s aq_err %s\n",
1349+
i40e_stat_str(hw, status),
1350+
i40e_aq_str(hw, hw->aq.asq_last_status));
1351+
err = -EAGAIN;
1352+
goto done;
1353+
}
1354+
pf->flags = flags;
1355+
status = i40e_update_link_info(hw);
1356+
if (status)
1357+
/* debug level message only due to relation to the link
1358+
* itself rather than to the FEC settings
1359+
* (e.g. no physical connection etc.)
1360+
*/
1361+
netdev_dbg(netdev,
1362+
"Updating link info failed with err %s aq_err %s\n",
1363+
i40e_stat_str(hw, status),
1364+
i40e_aq_str(hw, hw->aq.asq_last_status));
1365+
}
1366+
1367+
done:
1368+
return err;
1369+
}
1370+
1371+
static int i40e_get_fec_param(struct net_device *netdev,
1372+
struct ethtool_fecparam *fecparam)
1373+
{
1374+
struct i40e_netdev_priv *np = netdev_priv(netdev);
1375+
struct i40e_aq_get_phy_abilities_resp abilities;
1376+
struct i40e_pf *pf = np->vsi->back;
1377+
struct i40e_hw *hw = &pf->hw;
1378+
i40e_status status = 0;
1379+
int err = 0;
1380+
1381+
/* Get the current phy config */
1382+
memset(&abilities, 0, sizeof(abilities));
1383+
status = i40e_aq_get_phy_capabilities(hw, false, false, &abilities,
1384+
NULL);
1385+
if (status) {
1386+
err = -EAGAIN;
1387+
goto done;
1388+
}
1389+
1390+
fecparam->fec = 0;
1391+
if (abilities.fec_cfg_curr_mod_ext_info & I40E_AQ_SET_FEC_AUTO)
1392+
fecparam->fec |= ETHTOOL_FEC_AUTO;
1393+
if ((abilities.fec_cfg_curr_mod_ext_info &
1394+
I40E_AQ_SET_FEC_REQUEST_RS) ||
1395+
(abilities.fec_cfg_curr_mod_ext_info &
1396+
I40E_AQ_SET_FEC_ABILITY_RS))
1397+
fecparam->fec |= ETHTOOL_FEC_RS;
1398+
if ((abilities.fec_cfg_curr_mod_ext_info &
1399+
I40E_AQ_SET_FEC_REQUEST_KR) ||
1400+
(abilities.fec_cfg_curr_mod_ext_info & I40E_AQ_SET_FEC_ABILITY_KR))
1401+
fecparam->fec |= ETHTOOL_FEC_BASER;
1402+
if (abilities.fec_cfg_curr_mod_ext_info == 0)
1403+
fecparam->fec |= ETHTOOL_FEC_OFF;
1404+
1405+
if (hw->phy.link_info.fec_info & I40E_AQ_CONFIG_FEC_KR_ENA)
1406+
fecparam->active_fec = ETHTOOL_FEC_BASER;
1407+
else if (hw->phy.link_info.fec_info & I40E_AQ_CONFIG_FEC_RS_ENA)
1408+
fecparam->active_fec = ETHTOOL_FEC_RS;
1409+
else
1410+
fecparam->active_fec = ETHTOOL_FEC_OFF;
1411+
done:
1412+
return err;
1413+
}
1414+
1415+
static int i40e_set_fec_param(struct net_device *netdev,
1416+
struct ethtool_fecparam *fecparam)
1417+
{
1418+
struct i40e_netdev_priv *np = netdev_priv(netdev);
1419+
struct i40e_pf *pf = np->vsi->back;
1420+
struct i40e_hw *hw = &pf->hw;
1421+
u8 fec_cfg = 0;
1422+
int err = 0;
1423+
1424+
if (hw->device_id != I40E_DEV_ID_25G_SFP28 &&
1425+
hw->device_id != I40E_DEV_ID_25G_B) {
1426+
err = -EPERM;
1427+
goto done;
1428+
}
1429+
1430+
switch (fecparam->fec) {
1431+
case ETHTOOL_FEC_AUTO:
1432+
fec_cfg = I40E_AQ_SET_FEC_AUTO;
1433+
break;
1434+
case ETHTOOL_FEC_RS:
1435+
fec_cfg = (I40E_AQ_SET_FEC_REQUEST_RS |
1436+
I40E_AQ_SET_FEC_ABILITY_RS);
1437+
break;
1438+
case ETHTOOL_FEC_BASER:
1439+
fec_cfg = (I40E_AQ_SET_FEC_REQUEST_KR |
1440+
I40E_AQ_SET_FEC_ABILITY_KR);
1441+
break;
1442+
case ETHTOOL_FEC_OFF:
1443+
case ETHTOOL_FEC_NONE:
1444+
fec_cfg = 0;
1445+
break;
1446+
default:
1447+
dev_warn(&pf->pdev->dev, "Unsupported FEC mode: %d",
1448+
fecparam->fec);
1449+
err = -EINVAL;
1450+
goto done;
1451+
}
1452+
1453+
err = i40e_set_fec_cfg(netdev, fec_cfg);
1454+
1455+
done:
1456+
return err;
1457+
}
1458+
12641459
static int i40e_nway_reset(struct net_device *netdev)
12651460
{
12661461
/* restart autonegotiation */
@@ -1376,7 +1571,7 @@ static int i40e_set_pauseparam(struct net_device *netdev,
13761571
else if (!pause->rx_pause && !pause->tx_pause)
13771572
hw->fc.requested_mode = I40E_FC_NONE;
13781573
else
1379-
return -EINVAL;
1574+
return -EINVAL;
13801575

13811576
/* Tell the OS link is going down, the link will go back up when fw
13821577
* says it is ready asynchronously
@@ -4676,6 +4871,15 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
46764871
}
46774872
}
46784873

4874+
if (((changed_flags & I40E_FLAG_RS_FEC) ||
4875+
(changed_flags & I40E_FLAG_BASE_R_FEC)) &&
4876+
pf->hw.device_id != I40E_DEV_ID_25G_SFP28 &&
4877+
pf->hw.device_id != I40E_DEV_ID_25G_B) {
4878+
dev_warn(&pf->pdev->dev,
4879+
"Device does not support changing FEC configuration\n");
4880+
return -EOPNOTSUPP;
4881+
}
4882+
46794883
/* Now that we've checked to ensure that the new flags are valid, load
46804884
* them into place. Since we only modify flags either (a) during
46814885
* initialization or (b) while holding the RTNL lock, we don't need
@@ -4714,6 +4918,24 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
47144918
}
47154919
}
47164920

4921+
if ((changed_flags & I40E_FLAG_RS_FEC) ||
4922+
(changed_flags & I40E_FLAG_BASE_R_FEC)) {
4923+
u8 fec_cfg = 0;
4924+
4925+
if (pf->flags & I40E_FLAG_RS_FEC &&
4926+
pf->flags & I40E_FLAG_BASE_R_FEC) {
4927+
fec_cfg = I40E_AQ_SET_FEC_AUTO;
4928+
} else if (pf->flags & I40E_FLAG_RS_FEC) {
4929+
fec_cfg = (I40E_AQ_SET_FEC_REQUEST_RS |
4930+
I40E_AQ_SET_FEC_ABILITY_RS);
4931+
} else if (pf->flags & I40E_FLAG_BASE_R_FEC) {
4932+
fec_cfg = (I40E_AQ_SET_FEC_REQUEST_KR |
4933+
I40E_AQ_SET_FEC_ABILITY_KR);
4934+
}
4935+
if (i40e_set_fec_cfg(dev, fec_cfg))
4936+
dev_warn(&pf->pdev->dev, "Cannot change FEC config\n");
4937+
}
4938+
47174939
if ((changed_flags & pf->flags &
47184940
I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED) &&
47194941
(pf->flags & I40E_FLAG_MFP_ENABLED))
@@ -4948,6 +5170,8 @@ static const struct ethtool_ops i40e_ethtool_ops = {
49485170
.set_per_queue_coalesce = i40e_set_per_queue_coalesce,
49495171
.get_link_ksettings = i40e_get_link_ksettings,
49505172
.set_link_ksettings = i40e_set_link_ksettings,
5173+
.get_fecparam = i40e_get_fec_param,
5174+
.set_fecparam = i40e_set_fec_param,
49515175
};
49525176

49535177
void i40e_set_ethtool_ops(struct net_device *netdev)

drivers/net/ethernet/intel/i40e/i40e_main.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13860,6 +13860,29 @@ static void i40e_get_platform_mac_addr(struct pci_dev *pdev, struct i40e_pf *pf)
1386013860
i40e_get_mac_addr(&pf->hw, pf->hw.mac.addr);
1386113861
}
1386213862

13863+
/**
13864+
* i40e_set_fec_in_flags - helper function for setting FEC options in flags
13865+
* @fec_cfg: FEC option to set in flags
13866+
* @flags: ptr to flags in which we set FEC option
13867+
**/
13868+
void i40e_set_fec_in_flags(u8 fec_cfg, u32 *flags)
13869+
{
13870+
if (fec_cfg & I40E_AQ_SET_FEC_AUTO)
13871+
*flags |= I40E_FLAG_RS_FEC | I40E_FLAG_BASE_R_FEC;
13872+
if ((fec_cfg & I40E_AQ_SET_FEC_REQUEST_RS) ||
13873+
(fec_cfg & I40E_AQ_SET_FEC_ABILITY_RS)) {
13874+
*flags |= I40E_FLAG_RS_FEC;
13875+
*flags &= ~I40E_FLAG_BASE_R_FEC;
13876+
}
13877+
if ((fec_cfg & I40E_AQ_SET_FEC_REQUEST_KR) ||
13878+
(fec_cfg & I40E_AQ_SET_FEC_ABILITY_KR)) {
13879+
*flags |= I40E_FLAG_BASE_R_FEC;
13880+
*flags &= ~I40E_FLAG_RS_FEC;
13881+
}
13882+
if (fec_cfg == 0)
13883+
*flags &= ~(I40E_FLAG_RS_FEC | I40E_FLAG_BASE_R_FEC);
13884+
}
13885+
1386313886
/**
1386413887
* i40e_probe - Device initialization routine
1386513888
* @pdev: PCI device information struct
@@ -14351,6 +14374,9 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
1435114374
i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
1435214375
pf->hw.phy.link_info.requested_speeds = abilities.link_speed;
1435314376

14377+
/* set the FEC config due to the board capabilities */
14378+
i40e_set_fec_in_flags(abilities.fec_cfg_curr_mod_ext_info, &pf->flags);
14379+
1435414380
/* get the supported phy types from the fw */
1435514381
err = i40e_aq_get_phy_capabilities(hw, false, true, &abilities, NULL);
1435614382
if (err)

0 commit comments

Comments
 (0)