Commit 5a056cd7 authored by Paul Greenwalt's avatar Paul Greenwalt Committed by Jeff Kirsher

ice: add lp_advertising flow control support

Add support for reporting link partner advertising when
ETHTOOL_GLINKSETTINGS defined. Get pause param reports the Tx/Rx
pause configured, and then ethtool issues ETHTOOL_GSET ioctl and
ice_get_settings_link_up reports the negotiated Tx/Rx pause. Negotiated
pause frame report per IEEE 802.3-2005 table 288-3.

$ ethtool --show-pause ens6f0
Pause parameters for ens6f0:
Autonegotiate:  on
RX:             on
TX:             on
RX negotiated:  on
TX negotiated:  on

$ ethtool ens6f0
Settings for ens6f0:
        Supported ports: [ FIBRE ]
        Supported link modes:   25000baseCR/Full
        Supported pause frame use: Symmetric
        Supports auto-negotiation: Yes
        Supported FEC modes: None BaseR RS
        Advertised link modes:  25000baseCR/Full
        Advertised pause frame use: Symmetric Receive-only
        Advertised auto-negotiation: Yes
        Advertised FEC modes: None BaseR RS
        Link partner advertised link modes:  Not reported
        Link partner advertised pause frame use: Symmetric
        Link partner advertised auto-negotiation: Yes
        Link partner advertised FEC modes: Not reported
        Speed: 25000Mb/s
        Duplex: Full
        Port: Direct Attach Copper
        PHYAD: 0
        Transceiver: internal
        Auto-negotiation: on
        Supports Wake-on: g
        Wake-on: g
        Current message level: 0x00000007 (7)
                               drv probe link
        Link detected: yes

When ETHTOOL_GLINKSETTINGS is not defined, get pause param reports the
negotiated Tx/Rx pause.
Signed-off-by: default avatarPaul Greenwalt <paul.greenwalt@intel.com>
Tested-by: default avatarAndrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 6a7ce95d
...@@ -1716,6 +1716,7 @@ ice_get_settings_link_up(struct ethtool_link_ksettings *ks, ...@@ -1716,6 +1716,7 @@ ice_get_settings_link_up(struct ethtool_link_ksettings *ks,
struct net_device *netdev) struct net_device *netdev)
{ {
struct ice_netdev_priv *np = netdev_priv(netdev); struct ice_netdev_priv *np = netdev_priv(netdev);
struct ice_port_info *pi = np->vsi->port_info;
struct ethtool_link_ksettings cap_ksettings; struct ethtool_link_ksettings cap_ksettings;
struct ice_link_status *link_info; struct ice_link_status *link_info;
struct ice_vsi *vsi = np->vsi; struct ice_vsi *vsi = np->vsi;
...@@ -2040,6 +2041,33 @@ ice_get_settings_link_up(struct ethtool_link_ksettings *ks, ...@@ -2040,6 +2041,33 @@ ice_get_settings_link_up(struct ethtool_link_ksettings *ks,
break; break;
} }
ks->base.duplex = DUPLEX_FULL; ks->base.duplex = DUPLEX_FULL;
if (link_info->an_info & ICE_AQ_AN_COMPLETED)
ethtool_link_ksettings_add_link_mode(ks, lp_advertising,
Autoneg);
/* Set flow control negotiated Rx/Tx pause */
switch (pi->fc.current_mode) {
case ICE_FC_FULL:
ethtool_link_ksettings_add_link_mode(ks, lp_advertising, Pause);
break;
case ICE_FC_TX_PAUSE:
ethtool_link_ksettings_add_link_mode(ks, lp_advertising, Pause);
ethtool_link_ksettings_add_link_mode(ks, lp_advertising,
Asym_Pause);
break;
case ICE_FC_RX_PAUSE:
ethtool_link_ksettings_add_link_mode(ks, lp_advertising,
Asym_Pause);
break;
case ICE_FC_PFC:
/* fall through */
default:
ethtool_link_ksettings_del_link_mode(ks, lp_advertising, Pause);
ethtool_link_ksettings_del_link_mode(ks, lp_advertising,
Asym_Pause);
break;
}
} }
/** /**
...@@ -2078,9 +2106,12 @@ ice_get_link_ksettings(struct net_device *netdev, ...@@ -2078,9 +2106,12 @@ ice_get_link_ksettings(struct net_device *netdev,
struct ice_aqc_get_phy_caps_data *caps; struct ice_aqc_get_phy_caps_data *caps;
struct ice_link_status *hw_link_info; struct ice_link_status *hw_link_info;
struct ice_vsi *vsi = np->vsi; struct ice_vsi *vsi = np->vsi;
enum ice_status status;
int err = 0;
ethtool_link_ksettings_zero_link_mode(ks, supported); ethtool_link_ksettings_zero_link_mode(ks, supported);
ethtool_link_ksettings_zero_link_mode(ks, advertising); ethtool_link_ksettings_zero_link_mode(ks, advertising);
ethtool_link_ksettings_zero_link_mode(ks, lp_advertising);
hw_link_info = &vsi->port_info->phy.link_info; hw_link_info = &vsi->port_info->phy.link_info;
/* set speed and duplex */ /* set speed and duplex */
...@@ -2125,48 +2156,36 @@ ice_get_link_ksettings(struct net_device *netdev, ...@@ -2125,48 +2156,36 @@ ice_get_link_ksettings(struct net_device *netdev,
/* flow control is symmetric and always supported */ /* flow control is symmetric and always supported */
ethtool_link_ksettings_add_link_mode(ks, supported, Pause); ethtool_link_ksettings_add_link_mode(ks, supported, Pause);
switch (vsi->port_info->fc.req_mode) { caps = devm_kzalloc(&vsi->back->pdev->dev, sizeof(*caps), GFP_KERNEL);
case ICE_FC_FULL: if (!caps)
return -ENOMEM;
status = ice_aq_get_phy_caps(vsi->port_info, false,
ICE_AQC_REPORT_SW_CFG, caps, NULL);
if (status) {
err = -EIO;
goto done;
}
/* Set the advertised flow control based on the PHY capability */
if ((caps->caps & ICE_AQC_PHY_EN_TX_LINK_PAUSE) &&
(caps->caps & ICE_AQC_PHY_EN_RX_LINK_PAUSE)) {
ethtool_link_ksettings_add_link_mode(ks, advertising, Pause); ethtool_link_ksettings_add_link_mode(ks, advertising, Pause);
break;
case ICE_FC_TX_PAUSE:
ethtool_link_ksettings_add_link_mode(ks, advertising, ethtool_link_ksettings_add_link_mode(ks, advertising,
Asym_Pause); Asym_Pause);
break; } else if (caps->caps & ICE_AQC_PHY_EN_TX_LINK_PAUSE) {
case ICE_FC_RX_PAUSE: ethtool_link_ksettings_add_link_mode(ks, advertising,
Asym_Pause);
} else if (caps->caps & ICE_AQC_PHY_EN_RX_LINK_PAUSE) {
ethtool_link_ksettings_add_link_mode(ks, advertising, Pause); ethtool_link_ksettings_add_link_mode(ks, advertising, Pause);
ethtool_link_ksettings_add_link_mode(ks, advertising, ethtool_link_ksettings_add_link_mode(ks, advertising,
Asym_Pause); Asym_Pause);
break; } else {
case ICE_FC_PFC:
default:
ethtool_link_ksettings_del_link_mode(ks, advertising, Pause); ethtool_link_ksettings_del_link_mode(ks, advertising, Pause);
ethtool_link_ksettings_del_link_mode(ks, advertising, ethtool_link_ksettings_del_link_mode(ks, advertising,
Asym_Pause); Asym_Pause);
break;
} }
caps = devm_kzalloc(&vsi->back->pdev->dev, sizeof(*caps), GFP_KERNEL);
if (!caps)
goto done;
if (ice_aq_get_phy_caps(vsi->port_info, false, ICE_AQC_REPORT_TOPO_CAP,
caps, NULL))
netdev_info(netdev, "Get phy capability failed.\n");
/* Set supported FEC modes based on PHY capability */
ethtool_link_ksettings_add_link_mode(ks, supported, FEC_NONE);
if (caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_EN ||
caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_CLAUSE74_EN)
ethtool_link_ksettings_add_link_mode(ks, supported, FEC_BASER);
if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_CLAUSE91_EN)
ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS);
if (ice_aq_get_phy_caps(vsi->port_info, false, ICE_AQC_REPORT_SW_CFG,
caps, NULL))
netdev_info(netdev, "Get phy capability failed.\n");
/* Set advertised FEC modes based on PHY capability */ /* Set advertised FEC modes based on PHY capability */
ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_NONE); ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_NONE);
...@@ -2178,9 +2197,25 @@ ice_get_link_ksettings(struct net_device *netdev, ...@@ -2178,9 +2197,25 @@ ice_get_link_ksettings(struct net_device *netdev,
caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_544_REQ) caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_544_REQ)
ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_RS); ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_RS);
status = ice_aq_get_phy_caps(vsi->port_info, false,
ICE_AQC_REPORT_TOPO_CAP, caps, NULL);
if (status) {
err = -EIO;
goto done;
}
/* Set supported FEC modes based on PHY capability */
ethtool_link_ksettings_add_link_mode(ks, supported, FEC_NONE);
if (caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_EN ||
caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_CLAUSE74_EN)
ethtool_link_ksettings_add_link_mode(ks, supported, FEC_BASER);
if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_CLAUSE91_EN)
ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS);
done: done:
devm_kfree(&vsi->back->pdev->dev, caps); devm_kfree(&vsi->back->pdev->dev, caps);
return 0; return err;
} }
/** /**
...@@ -2763,6 +2798,11 @@ static int ice_nway_reset(struct net_device *netdev) ...@@ -2763,6 +2798,11 @@ static int ice_nway_reset(struct net_device *netdev)
* ice_get_pauseparam - Get Flow Control status * ice_get_pauseparam - Get Flow Control status
* @netdev: network interface device structure * @netdev: network interface device structure
* @pause: ethernet pause (flow control) parameters * @pause: ethernet pause (flow control) parameters
*
* Get requested flow control status from PHY capability.
* If autoneg is true, then ethtool will send the ETHTOOL_GSET ioctl which
* is handled by ice_get_link_ksettings. ice_get_link_ksettings will report
* the negotiated Rx/Tx pause via lp_advertising.
*/ */
static void static void
ice_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) ice_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment