Commit 1a3571b5 authored by Paul Greenwalt's avatar Paul Greenwalt Committed by Tony Nguyen

ice: restore PHY settings on media insertion

After the transition from no media to media FW will clear the
set-phy-cfg data set by the user. Save initial PHY settings and any
settings later requested by the user and use that data to restore PHY
settings on media insertion. Since PHY configuration is now being stored,
replace calls that were calling FW to get the configuration with the saved
copy.
Signed-off-by: default avatarPaul Greenwalt <paul.greenwalt@intel.com>
Signed-off-by: default avatarChinh T Cao <chinh.t.cao@intel.com>
Signed-off-by: default avatarPaul M Stillwell Jr <paul.m.stillwell.jr@intel.com>
Tested-by: default avatarAndrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: default avatarTony Nguyen <anthony.l.nguyen@intel.com>
parent 61cf42e7
...@@ -222,6 +222,7 @@ enum ice_state { ...@@ -222,6 +222,7 @@ enum ice_state {
__ICE_OICR_INTR_DIS, /* Global OICR interrupt disabled */ __ICE_OICR_INTR_DIS, /* Global OICR interrupt disabled */
__ICE_MDD_VF_PRINT_PENDING, /* set when MDD event handle */ __ICE_MDD_VF_PRINT_PENDING, /* set when MDD event handle */
__ICE_VF_RESETS_DISABLED, /* disable resets during ice_remove */ __ICE_VF_RESETS_DISABLED, /* disable resets during ice_remove */
__ICE_PHY_INIT_COMPLETE,
__ICE_STATE_NBITS /* must be last */ __ICE_STATE_NBITS /* must be last */
}; };
...@@ -437,6 +438,9 @@ struct ice_pf { ...@@ -437,6 +438,9 @@ struct ice_pf {
u32 tx_timeout_recovery_level; u32 tx_timeout_recovery_level;
char int_name[ICE_INT_NAME_STR_LEN]; char int_name[ICE_INT_NAME_STR_LEN];
u32 sw_int_count; u32 sw_int_count;
__le64 nvm_phy_type_lo; /* NVM PHY type low */
__le64 nvm_phy_type_hi; /* NVM PHY type high */
}; };
struct ice_netdev_priv { struct ice_netdev_priv {
......
...@@ -1147,6 +1147,7 @@ struct ice_aqc_get_link_status_data { ...@@ -1147,6 +1147,7 @@ struct ice_aqc_get_link_status_data {
#define ICE_AQ_LINK_PWR_QSFP_CLASS_3 2 #define ICE_AQ_LINK_PWR_QSFP_CLASS_3 2
#define ICE_AQ_LINK_PWR_QSFP_CLASS_4 3 #define ICE_AQ_LINK_PWR_QSFP_CLASS_4 3
__le16 link_speed; __le16 link_speed;
#define ICE_AQ_LINK_SPEED_M 0x7FF
#define ICE_AQ_LINK_SPEED_10MB BIT(0) #define ICE_AQ_LINK_SPEED_10MB BIT(0)
#define ICE_AQ_LINK_SPEED_100MB BIT(1) #define ICE_AQ_LINK_SPEED_100MB BIT(1)
#define ICE_AQ_LINK_SPEED_1000MB BIT(2) #define ICE_AQ_LINK_SPEED_1000MB BIT(2)
......
...@@ -2424,7 +2424,7 @@ ice_update_phy_type(u64 *phy_type_low, u64 *phy_type_high, ...@@ -2424,7 +2424,7 @@ ice_update_phy_type(u64 *phy_type_low, u64 *phy_type_high,
/** /**
* ice_aq_set_phy_cfg * ice_aq_set_phy_cfg
* @hw: pointer to the HW struct * @hw: pointer to the HW struct
* @lport: logical port number * @pi: port info structure of the interested logical port
* @cfg: structure with PHY configuration data to be set * @cfg: structure with PHY configuration data to be set
* @cd: pointer to command details structure or NULL * @cd: pointer to command details structure or NULL
* *
...@@ -2434,7 +2434,7 @@ ice_update_phy_type(u64 *phy_type_low, u64 *phy_type_high, ...@@ -2434,7 +2434,7 @@ ice_update_phy_type(u64 *phy_type_low, u64 *phy_type_high,
* parameters. This status will be indicated by the command response (0x0601). * parameters. This status will be indicated by the command response (0x0601).
*/ */
enum ice_status enum ice_status
ice_aq_set_phy_cfg(struct ice_hw *hw, u8 lport, ice_aq_set_phy_cfg(struct ice_hw *hw, struct ice_port_info *pi,
struct ice_aqc_set_phy_cfg_data *cfg, struct ice_sq_cd *cd) struct ice_aqc_set_phy_cfg_data *cfg, struct ice_sq_cd *cd)
{ {
struct ice_aq_desc desc; struct ice_aq_desc desc;
...@@ -2453,7 +2453,7 @@ ice_aq_set_phy_cfg(struct ice_hw *hw, u8 lport, ...@@ -2453,7 +2453,7 @@ ice_aq_set_phy_cfg(struct ice_hw *hw, u8 lport,
} }
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_phy_cfg); ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_phy_cfg);
desc.params.set_phy.lport_num = lport; desc.params.set_phy.lport_num = pi->lport;
desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
ice_debug(hw, ICE_DBG_LINK, "phy_type_low = 0x%llx\n", ice_debug(hw, ICE_DBG_LINK, "phy_type_low = 0x%llx\n",
...@@ -2471,6 +2471,9 @@ ice_aq_set_phy_cfg(struct ice_hw *hw, u8 lport, ...@@ -2471,6 +2471,9 @@ ice_aq_set_phy_cfg(struct ice_hw *hw, u8 lport,
if (hw->adminq.sq_last_status == ICE_AQ_RC_EMODE) if (hw->adminq.sq_last_status == ICE_AQ_RC_EMODE)
status = 0; status = 0;
if (!status)
pi->phy.curr_user_phy_cfg = *cfg;
return status; return status;
} }
...@@ -2514,17 +2517,99 @@ enum ice_status ice_update_link_info(struct ice_port_info *pi) ...@@ -2514,17 +2517,99 @@ enum ice_status ice_update_link_info(struct ice_port_info *pi)
return status; return status;
} }
/**
* ice_cache_phy_user_req
* @pi: port information structure
* @cache_data: PHY logging data
* @cache_mode: PHY logging mode
*
* Log the user request on (FC, FEC, SPEED) for later use.
*/
static void
ice_cache_phy_user_req(struct ice_port_info *pi,
struct ice_phy_cache_mode_data cache_data,
enum ice_phy_cache_mode cache_mode)
{
if (!pi)
return;
switch (cache_mode) {
case ICE_FC_MODE:
pi->phy.curr_user_fc_req = cache_data.data.curr_user_fc_req;
break;
case ICE_SPEED_MODE:
pi->phy.curr_user_speed_req =
cache_data.data.curr_user_speed_req;
break;
case ICE_FEC_MODE:
pi->phy.curr_user_fec_req = cache_data.data.curr_user_fec_req;
break;
default:
break;
}
}
/**
* ice_caps_to_fc_mode
* @caps: PHY capabilities
*
* Convert PHY FC capabilities to ice FC mode
*/
enum ice_fc_mode ice_caps_to_fc_mode(u8 caps)
{
if (caps & ICE_AQC_PHY_EN_TX_LINK_PAUSE &&
caps & ICE_AQC_PHY_EN_RX_LINK_PAUSE)
return ICE_FC_FULL;
if (caps & ICE_AQC_PHY_EN_TX_LINK_PAUSE)
return ICE_FC_TX_PAUSE;
if (caps & ICE_AQC_PHY_EN_RX_LINK_PAUSE)
return ICE_FC_RX_PAUSE;
return ICE_FC_NONE;
}
/**
* ice_caps_to_fec_mode
* @caps: PHY capabilities
* @fec_options: Link FEC options
*
* Convert PHY FEC capabilities to ice FEC mode
*/
enum ice_fec_mode ice_caps_to_fec_mode(u8 caps, u8 fec_options)
{
if (caps & ICE_AQC_PHY_EN_AUTO_FEC)
return ICE_FEC_AUTO;
if (fec_options & (ICE_AQC_PHY_FEC_10G_KR_40G_KR4_EN |
ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ |
ICE_AQC_PHY_FEC_25G_KR_CLAUSE74_EN |
ICE_AQC_PHY_FEC_25G_KR_REQ))
return ICE_FEC_BASER;
if (fec_options & (ICE_AQC_PHY_FEC_25G_RS_528_REQ |
ICE_AQC_PHY_FEC_25G_RS_544_REQ |
ICE_AQC_PHY_FEC_25G_RS_CLAUSE91_EN))
return ICE_FEC_RS;
return ICE_FEC_NONE;
}
/** /**
* ice_cfg_phy_fc - Configure PHY FC data based on FC mode * ice_cfg_phy_fc - Configure PHY FC data based on FC mode
* @pi: port information structure
* @cfg: PHY configuration data to set FC mode * @cfg: PHY configuration data to set FC mode
* @req_mode: FC mode to configure * @req_mode: FC mode to configure
*/ */
static enum ice_status enum ice_status
ice_cfg_phy_fc(struct ice_aqc_set_phy_cfg_data *cfg, enum ice_fc_mode req_mode) ice_cfg_phy_fc(struct ice_port_info *pi, struct ice_aqc_set_phy_cfg_data *cfg,
enum ice_fc_mode req_mode)
{ {
struct ice_phy_cache_mode_data cache_data;
u8 pause_mask = 0x0; u8 pause_mask = 0x0;
if (!cfg) if (!pi || !cfg)
return ICE_ERR_BAD_PTR; return ICE_ERR_BAD_PTR;
switch (req_mode) { switch (req_mode) {
...@@ -2549,6 +2634,10 @@ ice_cfg_phy_fc(struct ice_aqc_set_phy_cfg_data *cfg, enum ice_fc_mode req_mode) ...@@ -2549,6 +2634,10 @@ ice_cfg_phy_fc(struct ice_aqc_set_phy_cfg_data *cfg, enum ice_fc_mode req_mode)
/* set the new capabilities */ /* set the new capabilities */
cfg->caps |= pause_mask; cfg->caps |= pause_mask;
/* Cache user FC request */
cache_data.data.curr_user_fc_req = req_mode;
ice_cache_phy_user_req(pi, cache_data, ICE_FC_MODE);
return 0; return 0;
} }
...@@ -2563,12 +2652,12 @@ ice_cfg_phy_fc(struct ice_aqc_set_phy_cfg_data *cfg, enum ice_fc_mode req_mode) ...@@ -2563,12 +2652,12 @@ ice_cfg_phy_fc(struct ice_aqc_set_phy_cfg_data *cfg, enum ice_fc_mode req_mode)
enum ice_status enum ice_status
ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update) ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update)
{ {
struct ice_aqc_set_phy_cfg_data cfg = { 0 }; struct ice_aqc_set_phy_cfg_data cfg = { 0 };
struct ice_aqc_get_phy_caps_data *pcaps; struct ice_aqc_get_phy_caps_data *pcaps;
enum ice_status status; enum ice_status status;
struct ice_hw *hw; struct ice_hw *hw;
if (!pi) if (!pi || !aq_failures)
return ICE_ERR_BAD_PTR; return ICE_ERR_BAD_PTR;
*aq_failures = 0; *aq_failures = 0;
...@@ -2589,7 +2678,7 @@ ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update) ...@@ -2589,7 +2678,7 @@ ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update)
ice_copy_phy_caps_to_cfg(pcaps, &cfg); ice_copy_phy_caps_to_cfg(pcaps, &cfg);
/* Configure the set PHY data */ /* Configure the set PHY data */
status = ice_cfg_phy_fc(&cfg, pi->fc.req_mode); status = ice_cfg_phy_fc(pi, &cfg, pi->fc.req_mode);
if (status) if (status)
goto out; goto out;
...@@ -2601,7 +2690,7 @@ ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update) ...@@ -2601,7 +2690,7 @@ ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update)
if (ena_auto_link_update) if (ena_auto_link_update)
cfg.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; cfg.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
status = ice_aq_set_phy_cfg(hw, pi->lport, &cfg, NULL); status = ice_aq_set_phy_cfg(hw, pi, &cfg, NULL);
if (status) { if (status) {
*aq_failures = ICE_SET_FC_AQ_FAIL_SET; *aq_failures = ICE_SET_FC_AQ_FAIL_SET;
goto out; goto out;
...@@ -2630,6 +2719,42 @@ ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update) ...@@ -2630,6 +2719,42 @@ ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update)
return status; return status;
} }
/**
* ice_phy_caps_equals_cfg
* @phy_caps: PHY capabilities
* @phy_cfg: PHY configuration
*
* Helper function to determine if PHY capabilities matches PHY
* configuration
*/
bool
ice_phy_caps_equals_cfg(struct ice_aqc_get_phy_caps_data *phy_caps,
struct ice_aqc_set_phy_cfg_data *phy_cfg)
{
u8 caps_mask, cfg_mask;
if (!phy_caps || !phy_cfg)
return false;
/* These bits are not common between capabilities and configuration.
* Do not use them to determine equality.
*/
caps_mask = ICE_AQC_PHY_CAPS_MASK & ~(ICE_AQC_PHY_AN_MODE |
ICE_AQC_GET_PHY_EN_MOD_QUAL);
cfg_mask = ICE_AQ_PHY_ENA_VALID_MASK & ~ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
if (phy_caps->phy_type_low != phy_cfg->phy_type_low ||
phy_caps->phy_type_high != phy_cfg->phy_type_high ||
((phy_caps->caps & caps_mask) != (phy_cfg->caps & cfg_mask)) ||
phy_caps->low_power_ctrl != phy_cfg->low_power_ctrl ||
phy_caps->eee_cap != phy_cfg->eee_cap ||
phy_caps->eeer_value != phy_cfg->eeer_value ||
phy_caps->link_fec_options != phy_cfg->link_fec_opt)
return false;
return true;
}
/** /**
* ice_copy_phy_caps_to_cfg - Copy PHY ability data to configuration data * ice_copy_phy_caps_to_cfg - Copy PHY ability data to configuration data
* @caps: PHY ability structure to copy date from * @caps: PHY ability structure to copy date from
......
...@@ -98,18 +98,26 @@ ice_aq_manage_mac_write(struct ice_hw *hw, const u8 *mac_addr, u8 flags, ...@@ -98,18 +98,26 @@ ice_aq_manage_mac_write(struct ice_hw *hw, const u8 *mac_addr, u8 flags,
struct ice_sq_cd *cd); struct ice_sq_cd *cd);
enum ice_status ice_clear_pf_cfg(struct ice_hw *hw); enum ice_status ice_clear_pf_cfg(struct ice_hw *hw);
enum ice_status enum ice_status
ice_aq_set_phy_cfg(struct ice_hw *hw, u8 lport, ice_aq_set_phy_cfg(struct ice_hw *hw, struct ice_port_info *pi,
struct ice_aqc_set_phy_cfg_data *cfg, struct ice_sq_cd *cd); struct ice_aqc_set_phy_cfg_data *cfg, struct ice_sq_cd *cd);
enum ice_fc_mode ice_caps_to_fc_mode(u8 caps);
enum ice_fec_mode ice_caps_to_fec_mode(u8 caps, u8 fec_options);
enum ice_status enum ice_status
ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, ice_set_fc(struct ice_port_info *pi, u8 *aq_failures,
bool ena_auto_link_update); bool ena_auto_link_update);
enum ice_status enum ice_status
ice_cfg_phy_fec(struct ice_port_info *pi, struct ice_aqc_set_phy_cfg_data *cfg, ice_cfg_phy_fc(struct ice_port_info *pi, struct ice_aqc_set_phy_cfg_data *cfg,
enum ice_fec_mode fec); enum ice_fc_mode fc);
bool
ice_phy_caps_equals_cfg(struct ice_aqc_get_phy_caps_data *caps,
struct ice_aqc_set_phy_cfg_data *cfg);
void void
ice_copy_phy_caps_to_cfg(struct ice_aqc_get_phy_caps_data *caps, ice_copy_phy_caps_to_cfg(struct ice_aqc_get_phy_caps_data *caps,
struct ice_aqc_set_phy_cfg_data *cfg); struct ice_aqc_set_phy_cfg_data *cfg);
enum ice_status enum ice_status
ice_cfg_phy_fec(struct ice_port_info *pi, struct ice_aqc_set_phy_cfg_data *cfg,
enum ice_fec_mode fec);
enum ice_status
ice_aq_set_link_restart_an(struct ice_port_info *pi, bool ena_link, ice_aq_set_link_restart_an(struct ice_port_info *pi, bool ena_link,
struct ice_sq_cd *cd); struct ice_sq_cd *cd);
enum ice_status enum ice_status
......
...@@ -966,11 +966,8 @@ static int ice_set_fec_cfg(struct net_device *netdev, enum ice_fec_mode req_fec) ...@@ -966,11 +966,8 @@ static int ice_set_fec_cfg(struct net_device *netdev, enum ice_fec_mode req_fec)
{ {
struct ice_netdev_priv *np = netdev_priv(netdev); struct ice_netdev_priv *np = netdev_priv(netdev);
struct ice_aqc_set_phy_cfg_data config = { 0 }; struct ice_aqc_set_phy_cfg_data config = { 0 };
struct ice_aqc_get_phy_caps_data *caps;
struct ice_vsi *vsi = np->vsi; struct ice_vsi *vsi = np->vsi;
struct ice_port_info *pi; struct ice_port_info *pi;
enum ice_status status;
int err = 0;
pi = vsi->port_info; pi = vsi->port_info;
if (!pi) if (!pi)
...@@ -982,30 +979,26 @@ static int ice_set_fec_cfg(struct net_device *netdev, enum ice_fec_mode req_fec) ...@@ -982,30 +979,26 @@ static int ice_set_fec_cfg(struct net_device *netdev, enum ice_fec_mode req_fec)
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
/* Get last SW configuration */ /* Proceed only if requesting different FEC mode */
caps = kzalloc(sizeof(*caps), GFP_KERNEL); if (pi->phy.curr_user_fec_req == req_fec)
if (!caps) return 0;
return -ENOMEM;
status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_SW_CFG,
caps, NULL);
if (status) {
err = -EAGAIN;
goto done;
}
/* Copy SW configuration returned from PHY caps to PHY config */ /* Copy the current user PHY configuration. The current user PHY
ice_copy_phy_caps_to_cfg(caps, &config); * configuration is initialized during probe from PHY capabilities
* software mode, and updated on set PHY configuration.
*/
memcpy(&config, &pi->phy.curr_user_phy_cfg, sizeof(config));
ice_cfg_phy_fec(pi, &config, req_fec); ice_cfg_phy_fec(pi, &config, req_fec);
config.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; config.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
if (ice_aq_set_phy_cfg(pi->hw, pi->lport, &config, NULL)) if (ice_aq_set_phy_cfg(pi->hw, pi, &config, NULL))
err = -EAGAIN; return -EAGAIN;
done: /* Save requested FEC config */
kfree(caps); pi->phy.curr_user_fec_req = req_fec;
return err;
return 0;
} }
/** /**
...@@ -2102,10 +2095,10 @@ static int ...@@ -2102,10 +2095,10 @@ static int
ice_set_link_ksettings(struct net_device *netdev, ice_set_link_ksettings(struct net_device *netdev,
const struct ethtool_link_ksettings *ks) const struct ethtool_link_ksettings *ks)
{ {
u8 autoneg, timeout = TEST_SET_BITS_TIMEOUT, lport = 0;
struct ice_netdev_priv *np = netdev_priv(netdev); struct ice_netdev_priv *np = netdev_priv(netdev);
struct ethtool_link_ksettings safe_ks, copy_ks; struct ethtool_link_ksettings safe_ks, copy_ks;
struct ice_aqc_get_phy_caps_data *abilities; struct ice_aqc_get_phy_caps_data *abilities;
u8 autoneg, timeout = TEST_SET_BITS_TIMEOUT;
u16 adv_link_speed, curr_link_speed, idx; u16 adv_link_speed, curr_link_speed, idx;
struct ice_aqc_set_phy_cfg_data config; struct ice_aqc_set_phy_cfg_data config;
struct ice_pf *pf = np->vsi->back; struct ice_pf *pf = np->vsi->back;
...@@ -2137,6 +2130,18 @@ ice_set_link_ksettings(struct net_device *netdev, ...@@ -2137,6 +2130,18 @@ ice_set_link_ksettings(struct net_device *netdev,
p->phy.link_info.link_info & ICE_AQ_LINK_UP) p->phy.link_info.link_info & ICE_AQ_LINK_UP)
return -EOPNOTSUPP; return -EOPNOTSUPP;
abilities = kzalloc(sizeof(*abilities), GFP_KERNEL);
if (!abilities)
return -ENOMEM;
/* Get the PHY capabilities based on media */
status = ice_aq_get_phy_caps(p, false, ICE_AQC_REPORT_TOPO_CAP,
abilities, NULL);
if (status) {
err = -EAGAIN;
goto done;
}
/* copy the ksettings to copy_ks to avoid modifying the original */ /* copy the ksettings to copy_ks to avoid modifying the original */
memcpy(&copy_ks, ks, sizeof(copy_ks)); memcpy(&copy_ks, ks, sizeof(copy_ks));
...@@ -2153,8 +2158,10 @@ ice_set_link_ksettings(struct net_device *netdev, ...@@ -2153,8 +2158,10 @@ ice_set_link_ksettings(struct net_device *netdev,
*/ */
if (!bitmap_subset(copy_ks.link_modes.advertising, if (!bitmap_subset(copy_ks.link_modes.advertising,
safe_ks.link_modes.supported, safe_ks.link_modes.supported,
__ETHTOOL_LINK_MODE_MASK_NBITS)) __ETHTOOL_LINK_MODE_MASK_NBITS)) {
return -EINVAL; err = -EINVAL;
goto done;
}
/* get our own copy of the bits to check against */ /* get our own copy of the bits to check against */
memset(&safe_ks, 0, sizeof(safe_ks)); memset(&safe_ks, 0, sizeof(safe_ks));
...@@ -2171,33 +2178,27 @@ ice_set_link_ksettings(struct net_device *netdev, ...@@ -2171,33 +2178,27 @@ ice_set_link_ksettings(struct net_device *netdev,
/* If copy_ks.base and safe_ks.base are not the same now, then they are /* 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. * trying to set something that we do not support.
*/ */
if (memcmp(&copy_ks.base, &safe_ks.base, sizeof(copy_ks.base))) if (memcmp(&copy_ks.base, &safe_ks.base, sizeof(copy_ks.base))) {
return -EOPNOTSUPP; err = -EOPNOTSUPP;
goto done;
}
while (test_and_set_bit(__ICE_CFG_BUSY, pf->state)) { while (test_and_set_bit(__ICE_CFG_BUSY, pf->state)) {
timeout--; timeout--;
if (!timeout) if (!timeout) {
return -EBUSY; err = -EBUSY;
goto done;
}
usleep_range(TEST_SET_BITS_SLEEP_MIN, TEST_SET_BITS_SLEEP_MAX); usleep_range(TEST_SET_BITS_SLEEP_MIN, TEST_SET_BITS_SLEEP_MAX);
} }
abilities = kzalloc(sizeof(*abilities), GFP_KERNEL); /* Copy the current user PHY configuration. The current user PHY
if (!abilities) * configuration is initialized during probe from PHY capabilities
return -ENOMEM; * software mode, and updated on set PHY configuration.
*/
/* Get the current PHY config */ memcpy(&config, &p->phy.curr_user_phy_cfg, sizeof(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 */ config.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
memset(&config, 0, sizeof(config));
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 */ /* Check autoneg */
err = ice_setup_autoneg(p, &safe_ks, &config, autoneg, &autoneg_changed, err = ice_setup_autoneg(p, &safe_ks, &config, autoneg, &autoneg_changed,
...@@ -2232,26 +2233,30 @@ ice_set_link_ksettings(struct net_device *netdev, ...@@ -2232,26 +2233,30 @@ ice_set_link_ksettings(struct net_device *netdev,
goto done; 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 */ /* save the requested speeds */
p->phy.link_info.req_speeds = adv_link_speed; p->phy.link_info.req_speeds = adv_link_speed;
/* set link and auto negotiation so changes take effect */ /* set link and auto negotiation so changes take effect */
config.caps |= ICE_AQ_PHY_ENA_LINK; config.caps |= ICE_AQ_PHY_ENA_LINK;
if (phy_type_low || phy_type_high) { /* check if there is a PHY type for the requested advertised speed */
config.phy_type_high = cpu_to_le64(phy_type_high) & if (!(phy_type_low || phy_type_high)) {
netdev_info(netdev, "The selected speed is not supported by the current media. Please select a link speed that is supported by the current media.\n");
err = -EAGAIN;
goto done;
}
/* intersect requested advertised speed PHY types with media PHY types
* for set PHY configuration
*/
config.phy_type_high = cpu_to_le64(phy_type_high) &
abilities->phy_type_high; abilities->phy_type_high;
config.phy_type_low = cpu_to_le64(phy_type_low) & config.phy_type_low = cpu_to_le64(phy_type_low) &
abilities->phy_type_low; abilities->phy_type_low;
} else {
if (!(config.phy_type_high || config.phy_type_low)) {
netdev_info(netdev, "The selected speed is not supported by the current media. Please select a link speed that is supported by the current media.\n");
err = -EAGAIN; err = -EAGAIN;
netdev_info(netdev, "Nothing changed. No PHY_TYPE is corresponded to advertised link speed.\n");
goto done; goto done;
} }
...@@ -2266,12 +2271,15 @@ ice_set_link_ksettings(struct net_device *netdev, ...@@ -2266,12 +2271,15 @@ ice_set_link_ksettings(struct net_device *netdev,
} }
/* make the aq call */ /* make the aq call */
status = ice_aq_set_phy_cfg(&pf->hw, lport, &config, NULL); status = ice_aq_set_phy_cfg(&pf->hw, p, &config, NULL);
if (status) { if (status) {
netdev_info(netdev, "Set phy config failed,\n"); netdev_info(netdev, "Set phy config failed,\n");
err = -EAGAIN; err = -EAGAIN;
goto done;
} }
/* Save speed request */
p->phy.curr_user_speed_req = adv_link_speed;
done: done:
kfree(abilities); kfree(abilities);
clear_bit(__ICE_CFG_BUSY, pf->state); clear_bit(__ICE_CFG_BUSY, pf->state);
......
This diff is collapsed.
...@@ -87,6 +87,12 @@ enum ice_fc_mode { ...@@ -87,6 +87,12 @@ enum ice_fc_mode {
ICE_FC_DFLT ICE_FC_DFLT
}; };
enum ice_phy_cache_mode {
ICE_FC_MODE = 0,
ICE_SPEED_MODE,
ICE_FEC_MODE
};
enum ice_fec_mode { enum ice_fec_mode {
ICE_FEC_NONE = 0, ICE_FEC_NONE = 0,
ICE_FEC_RS, ICE_FEC_RS,
...@@ -94,6 +100,14 @@ enum ice_fec_mode { ...@@ -94,6 +100,14 @@ enum ice_fec_mode {
ICE_FEC_AUTO ICE_FEC_AUTO
}; };
struct ice_phy_cache_mode_data {
union {
enum ice_fec_mode curr_user_fec_req;
enum ice_fc_mode curr_user_fc_req;
u16 curr_user_speed_req;
} data;
};
enum ice_set_fc_aq_failures { enum ice_set_fc_aq_failures {
ICE_SET_FC_AQ_FAIL_NONE = 0, ICE_SET_FC_AQ_FAIL_NONE = 0,
ICE_SET_FC_AQ_FAIL_GET, ICE_SET_FC_AQ_FAIL_GET,
...@@ -160,6 +174,13 @@ struct ice_phy_info { ...@@ -160,6 +174,13 @@ struct ice_phy_info {
u64 phy_type_high; u64 phy_type_high;
enum ice_media_type media_type; enum ice_media_type media_type;
u8 get_link_info; u8 get_link_info;
/* Please refer to struct ice_aqc_get_link_status_data to get
* detail of enable bit in curr_user_speed_req
*/
u16 curr_user_speed_req;
enum ice_fec_mode curr_user_fec_req;
enum ice_fc_mode curr_user_fc_req;
struct ice_aqc_set_phy_cfg_data curr_user_phy_cfg;
}; };
/* protocol enumeration for filters */ /* protocol enumeration for filters */
......
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