|
|
|
@@ -332,58 +332,473 @@ ice_get_ethtool_stats(struct net_device *netdev,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
ice_get_link_ksettings(struct net_device *netdev,
|
|
|
|
|
/**
|
|
|
|
|
* ice_phy_type_to_ethtool - convert the phy_types to ethtool link modes
|
|
|
|
|
* @netdev: network interface device structure
|
|
|
|
|
* @ks: ethtool link ksettings struct to fill out
|
|
|
|
|
*/
|
|
|
|
|
static void ice_phy_type_to_ethtool(struct net_device *netdev,
|
|
|
|
|
struct ethtool_link_ksettings *ks)
|
|
|
|
|
{
|
|
|
|
|
struct ice_netdev_priv *np = netdev_priv(netdev);
|
|
|
|
|
struct ice_link_status *hw_link_info;
|
|
|
|
|
struct ice_vsi *vsi = np->vsi;
|
|
|
|
|
bool link_up;
|
|
|
|
|
u64 phy_types_low;
|
|
|
|
|
|
|
|
|
|
hw_link_info = &vsi->port_info->phy.link_info;
|
|
|
|
|
link_up = hw_link_info->link_info & ICE_AQ_LINK_UP;
|
|
|
|
|
phy_types_low = vsi->port_info->phy.phy_type_low;
|
|
|
|
|
|
|
|
|
|
ethtool_link_ksettings_zero_link_mode(ks, supported);
|
|
|
|
|
ethtool_link_ksettings_zero_link_mode(ks, advertising);
|
|
|
|
|
|
|
|
|
|
if (phy_types_low & ICE_PHY_TYPE_LOW_100BASE_TX ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_100M_SGMII) {
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
100baseT_Full);
|
|
|
|
|
if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_100MB)
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
100baseT_Full);
|
|
|
|
|
}
|
|
|
|
|
if (phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_T ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_1G_SGMII) {
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
1000baseT_Full);
|
|
|
|
|
if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_1000MB)
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
1000baseT_Full);
|
|
|
|
|
}
|
|
|
|
|
if (phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_KX) {
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
1000baseKX_Full);
|
|
|
|
|
if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_1000MB)
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
1000baseKX_Full);
|
|
|
|
|
}
|
|
|
|
|
if (phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_SX ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_LX) {
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
1000baseX_Full);
|
|
|
|
|
if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_1000MB)
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
1000baseX_Full);
|
|
|
|
|
}
|
|
|
|
|
if (phy_types_low & ICE_PHY_TYPE_LOW_2500BASE_T) {
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
2500baseT_Full);
|
|
|
|
|
if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_2500MB)
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
2500baseT_Full);
|
|
|
|
|
}
|
|
|
|
|
if (phy_types_low & ICE_PHY_TYPE_LOW_2500BASE_X ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_2500BASE_KX) {
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
2500baseX_Full);
|
|
|
|
|
if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_2500MB)
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
2500baseX_Full);
|
|
|
|
|
}
|
|
|
|
|
if (phy_types_low & ICE_PHY_TYPE_LOW_5GBASE_T ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_5GBASE_KR) {
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
5000baseT_Full);
|
|
|
|
|
if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_5GB)
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
5000baseT_Full);
|
|
|
|
|
}
|
|
|
|
|
if (phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_T ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_10G_SFI_DA ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_10G_SFI_AOC_ACC ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_10G_SFI_C2C) {
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
10000baseT_Full);
|
|
|
|
|
if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_10GB)
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
10000baseT_Full);
|
|
|
|
|
}
|
|
|
|
|
if (phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_KR_CR1) {
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
10000baseKR_Full);
|
|
|
|
|
if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_10GB)
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
10000baseKR_Full);
|
|
|
|
|
}
|
|
|
|
|
if (phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_SR) {
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
10000baseSR_Full);
|
|
|
|
|
if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_10GB)
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
10000baseSR_Full);
|
|
|
|
|
}
|
|
|
|
|
if (phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_LR) {
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
10000baseLR_Full);
|
|
|
|
|
if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_10GB)
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
10000baseLR_Full);
|
|
|
|
|
}
|
|
|
|
|
if (phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_T ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR_S ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR1 ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_25G_AUI_AOC_ACC ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_25G_AUI_C2C) {
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
25000baseCR_Full);
|
|
|
|
|
if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_25GB)
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
25000baseCR_Full);
|
|
|
|
|
}
|
|
|
|
|
if (phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_SR ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_LR) {
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
25000baseSR_Full);
|
|
|
|
|
if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_25GB)
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
25000baseSR_Full);
|
|
|
|
|
}
|
|
|
|
|
if (phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR_S ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR1) {
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
25000baseKR_Full);
|
|
|
|
|
if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_25GB)
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
25000baseKR_Full);
|
|
|
|
|
}
|
|
|
|
|
if (phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_KR4) {
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
40000baseKR4_Full);
|
|
|
|
|
if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_40GB)
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
40000baseKR4_Full);
|
|
|
|
|
}
|
|
|
|
|
if (phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_CR4 ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_40G_XLAUI_AOC_ACC ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_40G_XLAUI) {
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
40000baseCR4_Full);
|
|
|
|
|
if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_40GB)
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
40000baseCR4_Full);
|
|
|
|
|
}
|
|
|
|
|
if (phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_SR4) {
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
40000baseSR4_Full);
|
|
|
|
|
if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_40GB)
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
40000baseSR4_Full);
|
|
|
|
|
}
|
|
|
|
|
if (phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_LR4) {
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
40000baseLR4_Full);
|
|
|
|
|
if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_40GB)
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
40000baseLR4_Full);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* set speed and duplex */
|
|
|
|
|
if (link_up) {
|
|
|
|
|
switch (hw_link_info->link_speed) {
|
|
|
|
|
case ICE_AQ_LINK_SPEED_100MB:
|
|
|
|
|
ks->base.speed = SPEED_100;
|
|
|
|
|
/* Autoneg PHY types */
|
|
|
|
|
if (phy_types_low & ICE_PHY_TYPE_LOW_100BASE_TX ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_T ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_KX ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_2500BASE_T ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_2500BASE_KX ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_5GBASE_T ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_5GBASE_KR ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_T ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_KR_CR1 ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_T ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR_S ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR1 ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR_S ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR1 ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_CR4 ||
|
|
|
|
|
phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_KR4) {
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
Autoneg);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
Autoneg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define TEST_SET_BITS_TIMEOUT 50
|
|
|
|
|
#define TEST_SET_BITS_SLEEP_MAX 2000
|
|
|
|
|
#define TEST_SET_BITS_SLEEP_MIN 1000
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* ice_get_settings_link_up - Get Link settings for when link is up
|
|
|
|
|
* @ks: ethtool ksettings to fill in
|
|
|
|
|
* @netdev: network interface device structure
|
|
|
|
|
*/
|
|
|
|
|
static void ice_get_settings_link_up(struct ethtool_link_ksettings *ks,
|
|
|
|
|
struct net_device *netdev)
|
|
|
|
|
{
|
|
|
|
|
struct ice_netdev_priv *np = netdev_priv(netdev);
|
|
|
|
|
struct ethtool_link_ksettings cap_ksettings;
|
|
|
|
|
struct ice_link_status *link_info;
|
|
|
|
|
struct ice_vsi *vsi = np->vsi;
|
|
|
|
|
bool unrecog_phy_low = false;
|
|
|
|
|
|
|
|
|
|
link_info = &vsi->port_info->phy.link_info;
|
|
|
|
|
|
|
|
|
|
/* Initialize supported and advertised settings based on phy settings */
|
|
|
|
|
switch (link_info->phy_type_low) {
|
|
|
|
|
case ICE_PHY_TYPE_LOW_100BASE_TX:
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
100baseT_Full);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
100baseT_Full);
|
|
|
|
|
break;
|
|
|
|
|
case ICE_AQ_LINK_SPEED_2500MB:
|
|
|
|
|
ks->base.speed = SPEED_2500;
|
|
|
|
|
case ICE_PHY_TYPE_LOW_100M_SGMII:
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
100baseT_Full);
|
|
|
|
|
break;
|
|
|
|
|
case ICE_AQ_LINK_SPEED_5GB:
|
|
|
|
|
ks->base.speed = SPEED_5000;
|
|
|
|
|
case ICE_PHY_TYPE_LOW_1000BASE_T:
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
1000baseT_Full);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
1000baseT_Full);
|
|
|
|
|
break;
|
|
|
|
|
case ICE_AQ_LINK_SPEED_10GB:
|
|
|
|
|
ks->base.speed = SPEED_10000;
|
|
|
|
|
case ICE_PHY_TYPE_LOW_1G_SGMII:
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
1000baseT_Full);
|
|
|
|
|
break;
|
|
|
|
|
case ICE_PHY_TYPE_LOW_1000BASE_SX:
|
|
|
|
|
case ICE_PHY_TYPE_LOW_1000BASE_LX:
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
1000baseX_Full);
|
|
|
|
|
break;
|
|
|
|
|
case ICE_PHY_TYPE_LOW_1000BASE_KX:
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
1000baseKX_Full);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
1000baseKX_Full);
|
|
|
|
|
break;
|
|
|
|
|
case ICE_PHY_TYPE_LOW_2500BASE_T:
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
2500baseT_Full);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
2500baseT_Full);
|
|
|
|
|
break;
|
|
|
|
|
case ICE_PHY_TYPE_LOW_2500BASE_X:
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
2500baseX_Full);
|
|
|
|
|
break;
|
|
|
|
|
case ICE_PHY_TYPE_LOW_2500BASE_KX:
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
2500baseX_Full);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
2500baseX_Full);
|
|
|
|
|
break;
|
|
|
|
|
case ICE_PHY_TYPE_LOW_5GBASE_T:
|
|
|
|
|
case ICE_PHY_TYPE_LOW_5GBASE_KR:
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
5000baseT_Full);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
5000baseT_Full);
|
|
|
|
|
break;
|
|
|
|
|
case ICE_PHY_TYPE_LOW_10GBASE_T:
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
10000baseT_Full);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
10000baseT_Full);
|
|
|
|
|
break;
|
|
|
|
|
case ICE_PHY_TYPE_LOW_10G_SFI_DA:
|
|
|
|
|
case ICE_PHY_TYPE_LOW_10G_SFI_AOC_ACC:
|
|
|
|
|
case ICE_PHY_TYPE_LOW_10G_SFI_C2C:
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
10000baseT_Full);
|
|
|
|
|
break;
|
|
|
|
|
case ICE_PHY_TYPE_LOW_10GBASE_SR:
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
10000baseSR_Full);
|
|
|
|
|
break;
|
|
|
|
|
case ICE_PHY_TYPE_LOW_10GBASE_LR:
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
10000baseLR_Full);
|
|
|
|
|
break;
|
|
|
|
|
case ICE_PHY_TYPE_LOW_10GBASE_KR_CR1:
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
10000baseKR_Full);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
10000baseKR_Full);
|
|
|
|
|
break;
|
|
|
|
|
case ICE_PHY_TYPE_LOW_25GBASE_T:
|
|
|
|
|
case ICE_PHY_TYPE_LOW_25GBASE_CR:
|
|
|
|
|
case ICE_PHY_TYPE_LOW_25GBASE_CR_S:
|
|
|
|
|
case ICE_PHY_TYPE_LOW_25GBASE_CR1:
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
25000baseCR_Full);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
25000baseCR_Full);
|
|
|
|
|
break;
|
|
|
|
|
case ICE_PHY_TYPE_LOW_25G_AUI_AOC_ACC:
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
25000baseCR_Full);
|
|
|
|
|
break;
|
|
|
|
|
case ICE_PHY_TYPE_LOW_25GBASE_SR:
|
|
|
|
|
case ICE_PHY_TYPE_LOW_25GBASE_LR:
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
25000baseSR_Full);
|
|
|
|
|
break;
|
|
|
|
|
case ICE_PHY_TYPE_LOW_25GBASE_KR:
|
|
|
|
|
case ICE_PHY_TYPE_LOW_25GBASE_KR1:
|
|
|
|
|
case ICE_PHY_TYPE_LOW_25GBASE_KR_S:
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
25000baseKR_Full);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
25000baseKR_Full);
|
|
|
|
|
break;
|
|
|
|
|
case ICE_PHY_TYPE_LOW_40GBASE_CR4:
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
40000baseCR4_Full);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
40000baseCR4_Full);
|
|
|
|
|
break;
|
|
|
|
|
case ICE_PHY_TYPE_LOW_40G_XLAUI_AOC_ACC:
|
|
|
|
|
case ICE_PHY_TYPE_LOW_40G_XLAUI:
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
40000baseCR4_Full);
|
|
|
|
|
break;
|
|
|
|
|
case ICE_PHY_TYPE_LOW_40GBASE_SR4:
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
40000baseSR4_Full);
|
|
|
|
|
break;
|
|
|
|
|
case ICE_PHY_TYPE_LOW_40GBASE_LR4:
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
40000baseLR4_Full);
|
|
|
|
|
break;
|
|
|
|
|
case ICE_PHY_TYPE_LOW_40GBASE_KR4:
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, supported,
|
|
|
|
|
40000baseKR4_Full);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
|
|
|
|
|
ethtool_link_ksettings_add_link_mode(ks, advertising,
|
|
|
|
|
40000baseKR4_Full);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
unrecog_phy_low = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (unrecog_phy_low) {
|
|
|
|
|
/* if we got here and link is up something bad is afoot */
|
|
|
|
|
netdev_info(netdev, "WARNING: Unrecognized PHY_Low (0x%llx).\n",
|
|
|
|
|
(u64)link_info->phy_type_low);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now that we've worked out everything that could be supported by the
|
|
|
|
|
* current PHY type, get what is supported by the NVM and intersect
|
|
|
|
|
* them to get what is truly supported
|
|
|
|
|
*/
|
|
|
|
|
memset(&cap_ksettings, 0, sizeof(struct ethtool_link_ksettings));
|
|
|
|
|
ice_phy_type_to_ethtool(netdev, &cap_ksettings);
|
|
|
|
|
ethtool_intersect_link_masks(ks, &cap_ksettings);
|
|
|
|
|
|
|
|
|
|
switch (link_info->link_speed) {
|
|
|
|
|
case ICE_AQ_LINK_SPEED_40GB:
|
|
|
|
|
ks->base.speed = SPEED_40000;
|
|
|
|
|
break;
|
|
|
|
|
case ICE_AQ_LINK_SPEED_25GB:
|
|
|
|
|
ks->base.speed = SPEED_25000;
|
|
|
|
|
break;
|
|
|
|
|
case ICE_AQ_LINK_SPEED_40GB:
|
|
|
|
|
ks->base.speed = SPEED_40000;
|
|
|
|
|
case ICE_AQ_LINK_SPEED_20GB:
|
|
|
|
|
ks->base.speed = SPEED_20000;
|
|
|
|
|
break;
|
|
|
|
|
case ICE_AQ_LINK_SPEED_10GB:
|
|
|
|
|
ks->base.speed = SPEED_10000;
|
|
|
|
|
break;
|
|
|
|
|
case ICE_AQ_LINK_SPEED_5GB:
|
|
|
|
|
ks->base.speed = SPEED_5000;
|
|
|
|
|
break;
|
|
|
|
|
case ICE_AQ_LINK_SPEED_2500MB:
|
|
|
|
|
ks->base.speed = SPEED_2500;
|
|
|
|
|
break;
|
|
|
|
|
case ICE_AQ_LINK_SPEED_1000MB:
|
|
|
|
|
ks->base.speed = SPEED_1000;
|
|
|
|
|
break;
|
|
|
|
|
case ICE_AQ_LINK_SPEED_100MB:
|
|
|
|
|
ks->base.speed = SPEED_100;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ks->base.speed = SPEED_UNKNOWN;
|
|
|
|
|
netdev_info(netdev,
|
|
|
|
|
"WARNING: Unrecognized link_speed (0x%x).\n",
|
|
|
|
|
link_info->link_speed);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ks->base.duplex = DUPLEX_FULL;
|
|
|
|
|
} else {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* ice_get_settings_link_down - Get the Link settings when link is down
|
|
|
|
|
* @ks: ethtool ksettings to fill in
|
|
|
|
|
* @netdev: network interface device structure
|
|
|
|
|
*
|
|
|
|
|
* Reports link settings that can be determined when link is down
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
ice_get_settings_link_down(struct ethtool_link_ksettings *ks,
|
|
|
|
|
struct net_device __always_unused *netdev)
|
|
|
|
|
{
|
|
|
|
|
/* link is down and the driver needs to fall back on
|
|
|
|
|
* supported phy types to figure out what info to display
|
|
|
|
|
*/
|
|
|
|
|
ice_phy_type_to_ethtool(netdev, ks);
|
|
|
|
|
|
|
|
|
|
/* With no link, speed and duplex are unknown */
|
|
|
|
|
ks->base.speed = SPEED_UNKNOWN;
|
|
|
|
|
ks->base.duplex = DUPLEX_UNKNOWN;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* ice_get_link_ksettings - Get Link Speed and Duplex settings
|
|
|
|
|
* @netdev: network interface device structure
|
|
|
|
|
* @ks: ethtool ksettings
|
|
|
|
|
*
|
|
|
|
|
* Reports speed/duplex settings based on media_type
|
|
|
|
|
*/
|
|
|
|
|
static int ice_get_link_ksettings(struct net_device *netdev,
|
|
|
|
|
struct ethtool_link_ksettings *ks)
|
|
|
|
|
{
|
|
|
|
|
struct ice_netdev_priv *np = netdev_priv(netdev);
|
|
|
|
|
struct ice_link_status *hw_link_info;
|
|
|
|
|
struct ice_vsi *vsi = np->vsi;
|
|
|
|
|
|
|
|
|
|
ethtool_link_ksettings_zero_link_mode(ks, supported);
|
|
|
|
|
ethtool_link_ksettings_zero_link_mode(ks, advertising);
|
|
|
|
|
hw_link_info = &vsi->port_info->phy.link_info;
|
|
|
|
|
|
|
|
|
|
/* set speed and duplex */
|
|
|
|
|
if (hw_link_info->link_info & ICE_AQ_LINK_UP)
|
|
|
|
|
ice_get_settings_link_up(ks, netdev);
|
|
|
|
|
else
|
|
|
|
|
ice_get_settings_link_down(ks, netdev);
|
|
|
|
|
|
|
|
|
|
/* set autoneg settings */
|
|
|
|
|
ks->base.autoneg = ((hw_link_info->an_info & ICE_AQ_AN_COMPLETED) ?
|
|
|
|
|
AUTONEG_ENABLE : AUTONEG_DISABLE);
|
|
|
|
|
ks->base.autoneg = (hw_link_info->an_info & ICE_AQ_AN_COMPLETED) ?
|
|
|
|
|
AUTONEG_ENABLE : AUTONEG_DISABLE;
|
|
|
|
|
|
|
|
|
|
/* set media type settings */
|
|
|
|
|
switch (vsi->port_info->phy.media_type) {
|
|
|
|
@@ -441,6 +856,311 @@ ice_get_link_ksettings(struct net_device *netdev,
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* ice_ksettings_find_adv_link_speed - Find advertising link speed
|
|
|
|
|
* @ks: ethtool ksettings
|
|
|
|
|
*/
|
|
|
|
|
static u16
|
|
|
|
|
ice_ksettings_find_adv_link_speed(const struct ethtool_link_ksettings *ks)
|
|
|
|
|
{
|
|
|
|
|
u16 adv_link_speed = 0;
|
|
|
|
|
|
|
|
|
|
if (ethtool_link_ksettings_test_link_mode(ks, advertising,
|
|
|
|
|
100baseT_Full))
|
|
|
|
|
adv_link_speed |= ICE_AQ_LINK_SPEED_100MB;
|
|
|
|
|
if (ethtool_link_ksettings_test_link_mode(ks, advertising,
|
|
|
|
|
1000baseX_Full))
|
|
|
|
|
adv_link_speed |= ICE_AQ_LINK_SPEED_1000MB;
|
|
|
|
|
if (ethtool_link_ksettings_test_link_mode(ks, advertising,
|
|
|
|
|
1000baseT_Full) ||
|
|
|
|
|
ethtool_link_ksettings_test_link_mode(ks, advertising,
|
|
|
|
|
1000baseKX_Full))
|
|
|
|
|
adv_link_speed |= ICE_AQ_LINK_SPEED_1000MB;
|
|
|
|
|
if (ethtool_link_ksettings_test_link_mode(ks, advertising,
|
|
|
|
|
2500baseT_Full))
|
|
|
|
|
adv_link_speed |= ICE_AQ_LINK_SPEED_2500MB;
|
|
|
|
|
if (ethtool_link_ksettings_test_link_mode(ks, advertising,
|
|
|
|
|
2500baseX_Full))
|
|
|
|
|
adv_link_speed |= ICE_AQ_LINK_SPEED_2500MB;
|
|
|
|
|
if (ethtool_link_ksettings_test_link_mode(ks, advertising,
|
|
|
|
|
5000baseT_Full))
|
|
|
|
|
adv_link_speed |= ICE_AQ_LINK_SPEED_5GB;
|
|
|
|
|
if (ethtool_link_ksettings_test_link_mode(ks, advertising,
|
|
|
|
|
10000baseT_Full) ||
|
|
|
|
|
ethtool_link_ksettings_test_link_mode(ks, advertising,
|
|
|
|
|
10000baseKR_Full))
|
|
|
|
|
adv_link_speed |= ICE_AQ_LINK_SPEED_10GB;
|
|
|
|
|
if (ethtool_link_ksettings_test_link_mode(ks, advertising,
|
|
|
|
|
10000baseSR_Full) ||
|
|
|
|
|
ethtool_link_ksettings_test_link_mode(ks, advertising,
|
|
|
|
|
10000baseLR_Full))
|
|
|
|
|
adv_link_speed |= ICE_AQ_LINK_SPEED_10GB;
|
|
|
|
|
if (ethtool_link_ksettings_test_link_mode(ks, advertising,
|
|
|
|
|
25000baseCR_Full) ||
|
|
|
|
|
ethtool_link_ksettings_test_link_mode(ks, advertising,
|
|
|
|
|
25000baseSR_Full) ||
|
|
|
|
|
ethtool_link_ksettings_test_link_mode(ks, advertising,
|
|
|
|
|
25000baseKR_Full))
|
|
|
|
|
adv_link_speed |= ICE_AQ_LINK_SPEED_25GB;
|
|
|
|
|
if (ethtool_link_ksettings_test_link_mode(ks, advertising,
|
|
|
|
|
40000baseCR4_Full) ||
|
|
|
|
|
ethtool_link_ksettings_test_link_mode(ks, advertising,
|
|
|
|
|
40000baseSR4_Full) ||
|
|
|
|
|
ethtool_link_ksettings_test_link_mode(ks, advertising,
|
|
|
|
|
40000baseLR4_Full) ||
|
|
|
|
|
ethtool_link_ksettings_test_link_mode(ks, advertising,
|
|
|
|
|
40000baseKR4_Full))
|
|
|
|
|
adv_link_speed |= ICE_AQ_LINK_SPEED_40GB;
|
|
|
|
|
|
|
|
|
|
return adv_link_speed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* ice_setup_autoneg
|
|
|
|
|
* @p: port info
|
|
|
|
|
* @ks: ethtool_link_ksettings
|
|
|
|
|
* @config: configuration that will be sent down to FW
|
|
|
|
|
* @autoneg_enabled: autonegotiation is enabled or not
|
|
|
|
|
* @autoneg_changed: will there a change in autonegotiation
|
|
|
|
|
* @netdev: network interface device structure
|
|
|
|
|
*
|
|
|
|
|
* Setup PHY autonegotiation feature
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
ice_setup_autoneg(struct ice_port_info *p, struct ethtool_link_ksettings *ks,
|
|
|
|
|
struct ice_aqc_set_phy_cfg_data *config,
|
|
|
|
|
u8 autoneg_enabled, u8 *autoneg_changed,
|
|
|
|
|
struct net_device *netdev)
|
|
|
|
|
{
|
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
|
|
*autoneg_changed = 0;
|
|
|
|
|
|
|
|
|
|
/* Check autoneg */
|
|
|
|
|
if (autoneg_enabled == AUTONEG_ENABLE) {
|
|
|
|
|
/* If autoneg was not already enabled */
|
|
|
|
|
if (!(p->phy.link_info.an_info & ICE_AQ_AN_COMPLETED)) {
|
|
|
|
|
/* If autoneg is not supported, return error */
|
|
|
|
|
if (!ethtool_link_ksettings_test_link_mode(ks,
|
|
|
|
|
supported,
|
|
|
|
|
Autoneg)) {
|
|
|
|
|
netdev_info(netdev, "Autoneg not supported on this phy.\n");
|
|
|
|
|
err = -EINVAL;
|
|
|
|
|
} else {
|
|
|
|
|
/* Autoneg is allowed to change */
|
|
|
|
|
config->caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
|
|
|
|
|
*autoneg_changed = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
/* If autoneg is currently enabled */
|
|
|
|
|
if (p->phy.link_info.an_info & ICE_AQ_AN_COMPLETED) {
|
|
|
|
|
/* If autoneg is supported 10GBASE_T is the only phy
|
|
|
|
|
* that can disable it, so otherwise return error
|
|
|
|
|
*/
|
|
|
|
|
if (ethtool_link_ksettings_test_link_mode(ks,
|
|
|
|
|
supported,
|
|
|
|
|
Autoneg)) {
|
|
|
|
|
netdev_info(netdev, "Autoneg cannot be disabled on this phy\n");
|
|
|
|
|
err = -EINVAL;
|
|
|
|
|
} else {
|
|
|
|
|
/* Autoneg is allowed to change */
|
|
|
|
|
config->caps &= ~ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
|
|
|
|
|
*autoneg_changed = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* ice_set_link_ksettings - Set Speed and Duplex
|
|
|
|
|
* @netdev: network interface device structure
|
|
|
|
|
* @ks: ethtool ksettings
|
|
|
|
|
*
|
|
|
|
|
* Set speed/duplex per media_types advertised/forced
|
|
|
|
|
*/
|
|
|
|
|
static int ice_set_link_ksettings(struct net_device *netdev,
|
|
|
|
|
const struct ethtool_link_ksettings *ks)
|
|
|
|
|
{
|
|
|
|
|
u8 autoneg, timeout = TEST_SET_BITS_TIMEOUT, lport = 0;
|
|
|
|
|
struct ice_netdev_priv *np = netdev_priv(netdev);
|
|
|
|
|
struct ethtool_link_ksettings safe_ks, copy_ks;
|
|
|
|
|
struct ice_aqc_get_phy_caps_data *abilities;
|
|
|
|
|
u16 adv_link_speed, curr_link_speed, idx;
|
|
|
|
|
struct ice_aqc_set_phy_cfg_data config;
|
|
|
|
|
struct ice_pf *pf = np->vsi->back;
|
|
|
|
|
struct ice_port_info *p;
|
|
|
|
|
u8 autoneg_changed = 0;
|
|
|
|
|
enum ice_status status;
|
|
|
|
|
u64 phy_type_low;
|
|
|
|
|
int err = 0;
|
|
|
|
|
bool linkup;
|
|
|
|
|
|
|
|
|
|
p = np->vsi->port_info;
|
|
|
|
|
|
|
|
|
|
if (!p)
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
|
|
/* Check if this is lan vsi */
|
|
|
|
|
for (idx = 0 ; idx < pf->num_alloc_vsi ; idx++) {
|
|
|
|
|
if (pf->vsi[idx]->type == ICE_VSI_PF) {
|
|
|
|
|
if (np->vsi != pf->vsi[idx])
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (p->phy.media_type != ICE_MEDIA_BASET &&
|
|
|
|
|
p->phy.media_type != ICE_MEDIA_FIBER &&
|
|
|
|
|
p->phy.media_type != ICE_MEDIA_BACKPLANE &&
|
|
|
|
|
p->phy.media_type != ICE_MEDIA_DA &&
|
|
|
|
|
p->phy.link_info.link_info & ICE_AQ_LINK_UP)
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
|
|
/* copy the ksettings to copy_ks to avoid modifying the original */
|
|
|
|
|
memcpy(©_ks, ks, sizeof(struct ethtool_link_ksettings));
|
|
|
|
|
|
|
|
|
|
/* save autoneg out of ksettings */
|
|
|
|
|
autoneg = copy_ks.base.autoneg;
|
|
|
|
|
|
|
|
|
|
memset(&safe_ks, 0, sizeof(safe_ks));
|
|
|
|
|
|
|
|
|
|
/* Get link modes supported by hardware.*/
|
|
|
|
|
ice_phy_type_to_ethtool(netdev, &safe_ks);
|
|
|
|
|
|
|
|
|
|
/* and check against modes requested by user.
|
|
|
|
|
* Return an error if unsupported mode was set.
|
|
|
|
|
*/
|
|
|
|
|
if (!bitmap_subset(copy_ks.link_modes.advertising,
|
|
|
|
|
safe_ks.link_modes.supported,
|
|
|
|
|
__ETHTOOL_LINK_MODE_MASK_NBITS))
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
/* get our own copy of the bits to check against */
|
|
|
|
|
memset(&safe_ks, 0, sizeof(struct ethtool_link_ksettings));
|
|
|
|
|
safe_ks.base.cmd = copy_ks.base.cmd;
|
|
|
|
|
safe_ks.base.link_mode_masks_nwords =
|
|
|
|
|
copy_ks.base.link_mode_masks_nwords;
|
|
|
|
|
ice_get_link_ksettings(netdev, &safe_ks);
|
|
|
|
|
|
|
|
|
|
/* set autoneg back to what it currently is */
|
|
|
|
|
copy_ks.base.autoneg = safe_ks.base.autoneg;
|
|
|
|
|
/* we don't compare the speed */
|
|
|
|
|
copy_ks.base.speed = safe_ks.base.speed;
|
|
|
|
|
|
|
|
|
|
/* If copy_ks.base and safe_ks.base are not the same now, then they are
|
|
|
|
|
* trying to set something that we do not support.
|
|
|
|
|
*/
|
|
|
|
|
if (memcmp(©_ks.base, &safe_ks.base,
|
|
|
|
|
sizeof(struct ethtool_link_settings)))
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
|
|
while (test_and_set_bit(__ICE_CFG_BUSY, pf->state)) {
|
|
|
|
|
timeout--;
|
|
|
|
|
if (!timeout)
|
|
|
|
|
return -EBUSY;
|
|
|
|
|
usleep_range(TEST_SET_BITS_SLEEP_MIN, TEST_SET_BITS_SLEEP_MAX);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
abilities = devm_kzalloc(&pf->pdev->dev, sizeof(*abilities),
|
|
|
|
|
GFP_KERNEL);
|
|
|
|
|
if (!abilities)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
/* Get the current phy config */
|
|
|
|
|
status = ice_aq_get_phy_caps(p, false, ICE_AQC_REPORT_SW_CFG, abilities,
|
|
|
|
|
NULL);
|
|
|
|
|
if (status) {
|
|
|
|
|
err = -EAGAIN;
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Copy abilities to config in case autoneg is not set below */
|
|
|
|
|
memset(&config, 0, sizeof(struct ice_aqc_set_phy_cfg_data));
|
|
|
|
|
config.caps = abilities->caps & ~ICE_AQC_PHY_AN_MODE;
|
|
|
|
|
if (abilities->caps & ICE_AQC_PHY_AN_MODE)
|
|
|
|
|
config.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
|
|
|
|
|
|
|
|
|
|
/* Check autoneg */
|
|
|
|
|
err = ice_setup_autoneg(p, &safe_ks, &config, autoneg, &autoneg_changed,
|
|
|
|
|
netdev);
|
|
|
|
|
|
|
|
|
|
if (err)
|
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
|
|
/* Call to get the current link speed */
|
|
|
|
|
p->phy.get_link_info = true;
|
|
|
|
|
status = ice_get_link_status(p, &linkup);
|
|
|
|
|
if (status) {
|
|
|
|
|
err = -EAGAIN;
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
curr_link_speed = p->phy.link_info.link_speed;
|
|
|
|
|
adv_link_speed = ice_ksettings_find_adv_link_speed(ks);
|
|
|
|
|
|
|
|
|
|
/* If speed didn't get set, set it to what it currently is.
|
|
|
|
|
* This is needed because if advertise is 0 (as it is when autoneg
|
|
|
|
|
* is disabled) then speed won't get set.
|
|
|
|
|
*/
|
|
|
|
|
if (!adv_link_speed)
|
|
|
|
|
adv_link_speed = curr_link_speed;
|
|
|
|
|
|
|
|
|
|
/* Convert the advertise link speeds to their corresponded PHY_TYPE */
|
|
|
|
|
ice_update_phy_type(&phy_type_low, adv_link_speed);
|
|
|
|
|
|
|
|
|
|
if (!autoneg_changed && adv_link_speed == curr_link_speed) {
|
|
|
|
|
netdev_info(netdev, "Nothing changed, exiting without setting anything.\n");
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* copy over the rest of the abilities */
|
|
|
|
|
config.low_power_ctrl = abilities->low_power_ctrl;
|
|
|
|
|
config.eee_cap = abilities->eee_cap;
|
|
|
|
|
config.eeer_value = abilities->eeer_value;
|
|
|
|
|
config.link_fec_opt = abilities->link_fec_options;
|
|
|
|
|
|
|
|
|
|
/* save the requested speeds */
|
|
|
|
|
p->phy.link_info.req_speeds = adv_link_speed;
|
|
|
|
|
|
|
|
|
|
/* set link and auto negotiation so changes take effect */
|
|
|
|
|
config.caps |= ICE_AQ_PHY_ENA_LINK;
|
|
|
|
|
|
|
|
|
|
if (phy_type_low) {
|
|
|
|
|
config.phy_type_low = cpu_to_le64(phy_type_low) &
|
|
|
|
|
abilities->phy_type_low;
|
|
|
|
|
} else {
|
|
|
|
|
err = -EAGAIN;
|
|
|
|
|
netdev_info(netdev, "Nothing changed. No PHY_TYPE is corresponded to advertised link speed.\n");
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If link is up put link down */
|
|
|
|
|
if (p->phy.link_info.link_info & ICE_AQ_LINK_UP) {
|
|
|
|
|
/* Tell the OS link is going down, the link will go
|
|
|
|
|
* back up when fw says it is ready asynchronously
|
|
|
|
|
*/
|
|
|
|
|
ice_print_link_msg(np->vsi, false);
|
|
|
|
|
netif_carrier_off(netdev);
|
|
|
|
|
netif_tx_stop_all_queues(netdev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* make the aq call */
|
|
|
|
|
status = ice_aq_set_phy_cfg(&pf->hw, lport, &config, NULL);
|
|
|
|
|
if (status) {
|
|
|
|
|
netdev_info(netdev, "Set phy config failed,\n");
|
|
|
|
|
err = -EAGAIN;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
done:
|
|
|
|
|
devm_kfree(&pf->pdev->dev, abilities);
|
|
|
|
|
clear_bit(__ICE_CFG_BUSY, pf->state);
|
|
|
|
|
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* ice_get_rxnfc - command to get RX flow classification rules
|
|
|
|
|
* @netdev: network interface device structure
|
|
|
|
@@ -933,6 +1653,7 @@ static int ice_set_rxfh(struct net_device *netdev, const u32 *indir,
|
|
|
|
|
|
|
|
|
|
static const struct ethtool_ops ice_ethtool_ops = {
|
|
|
|
|
.get_link_ksettings = ice_get_link_ksettings,
|
|
|
|
|
.set_link_ksettings = ice_set_link_ksettings,
|
|
|
|
|
.get_drvinfo = ice_get_drvinfo,
|
|
|
|
|
.get_regs_len = ice_get_regs_len,
|
|
|
|
|
.get_regs = ice_get_regs,
|
|
|
|
|