Skip to content

Commit

Permalink
ice: add link lenient and default override support
Browse files Browse the repository at this point in the history
Adds functions to check for link override firmware support and get
the override settings for a port. The previously supported/default link
mode was strict mode.

In strict mode link is configured based on get PHY capabilities PHY types
with media.

Lenient mode is now the default link mode. In lenient mode the link is
configured based on get PHY capabilities PHY types without media. This
allows the user to configure link that the media does not report. Limit the
minimum supported link mode to 25G for devices that support 100G, and 1G
for devices that support less than 100G.

Default override is only supported in lenient mode. If default override
is supported and enabled, then default override values are used for
configuring speed and FEC. Default override provide persistent link
settings in the NVM.

Signed-off-by: Paul Greenwalt <[email protected]>
Signed-off-by: Evan Swanson <[email protected]>
Tested-by: Andrew Bowers <[email protected]>
Signed-off-by: Tony Nguyen <[email protected]>
  • Loading branch information
pgreenwa authored and anguy11 committed Jul 23, 2020
1 parent 1a3571b commit ea78ce4
Show file tree
Hide file tree
Showing 9 changed files with 628 additions and 216 deletions.
3 changes: 3 additions & 0 deletions drivers/net/ethernet/intel/ice/ice.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ enum ice_state {
__ICE_OICR_INTR_DIS, /* Global OICR interrupt disabled */
__ICE_MDD_VF_PRINT_PENDING, /* set when MDD event handle */
__ICE_VF_RESETS_DISABLED, /* disable resets during ice_remove */
__ICE_LINK_DEFAULT_OVERRIDE_PENDING,
__ICE_PHY_INIT_COMPLETE,
__ICE_STATE_NBITS /* must be last */
};
Expand Down Expand Up @@ -364,6 +365,7 @@ enum ice_pf_flags {
ICE_FLAG_LEGACY_RX,
ICE_FLAG_VF_TRUE_PROMISC_ENA,
ICE_FLAG_MDD_AUTO_RESET_VF,
ICE_FLAG_LINK_LENIENT_MODE_ENA,
ICE_PF_FLAGS_NBITS /* must be last */
};

Expand Down Expand Up @@ -441,6 +443,7 @@ struct ice_pf {

__le64 nvm_phy_type_lo; /* NVM PHY type low */
__le64 nvm_phy_type_hi; /* NVM PHY type high */
struct ice_link_default_override_tlv link_dflt_override;
};

struct ice_netdev_priv {
Expand Down
5 changes: 3 additions & 2 deletions drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -983,7 +983,8 @@ struct ice_aqc_get_phy_caps_data {
#define ICE_AQC_PHY_FEC_25G_RS_CLAUSE91_EN BIT(6)
#define ICE_AQC_PHY_FEC_25G_KR_CLAUSE74_EN BIT(7)
#define ICE_AQC_PHY_FEC_MASK ICE_M(0xdf, 0)
u8 rsvd1; /* Byte 35 reserved */
u8 module_compliance_enforcement;
#define ICE_AQC_MOD_ENFORCE_STRICT_MODE BIT(0)
u8 extended_compliance_code;
#define ICE_MODULE_TYPE_TOTAL_BYTE 3
u8 module_type[ICE_MODULE_TYPE_TOTAL_BYTE];
Expand Down Expand Up @@ -1036,7 +1037,7 @@ struct ice_aqc_set_phy_cfg_data {
__le16 eee_cap; /* Value from ice_aqc_get_phy_caps */
__le16 eeer_value;
u8 link_fec_opt; /* Use defines from ice_aqc_get_phy_caps */
u8 rsvd1;
u8 module_compliance_enforcement;
};

/* Set MAC Config command data structure (direct 0x0603) */
Expand Down
170 changes: 166 additions & 4 deletions drivers/net/ethernet/intel/ice/ice_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,40 @@ static enum ice_status ice_set_mac_type(struct ice_hw *hw)
if (hw->vendor_id != PCI_VENDOR_ID_INTEL)
return ICE_ERR_DEVICE_NOT_SUPPORTED;

hw->mac_type = ICE_MAC_GENERIC;
switch (hw->device_id) {
case ICE_DEV_ID_E810C_BACKPLANE:
case ICE_DEV_ID_E810C_QSFP:
case ICE_DEV_ID_E810C_SFP:
case ICE_DEV_ID_E810_XXV_SFP:
hw->mac_type = ICE_MAC_E810;
break;
case ICE_DEV_ID_E823C_10G_BASE_T:
case ICE_DEV_ID_E823C_BACKPLANE:
case ICE_DEV_ID_E823C_QSFP:
case ICE_DEV_ID_E823C_SFP:
case ICE_DEV_ID_E823C_SGMII:
case ICE_DEV_ID_E822C_10G_BASE_T:
case ICE_DEV_ID_E822C_BACKPLANE:
case ICE_DEV_ID_E822C_QSFP:
case ICE_DEV_ID_E822C_SFP:
case ICE_DEV_ID_E822C_SGMII:
case ICE_DEV_ID_E822L_10G_BASE_T:
case ICE_DEV_ID_E822L_BACKPLANE:
case ICE_DEV_ID_E822L_SFP:
case ICE_DEV_ID_E822L_SGMII:
case ICE_DEV_ID_E823L_10G_BASE_T:
case ICE_DEV_ID_E823L_1GBE:
case ICE_DEV_ID_E823L_BACKPLANE:
case ICE_DEV_ID_E823L_QSFP:
case ICE_DEV_ID_E823L_SFP:
hw->mac_type = ICE_MAC_GENERIC;
break;
default:
hw->mac_type = ICE_MAC_UNKNOWN;
break;
}

ice_debug(hw, ICE_DBG_INIT, "mac_type: %d\n", hw->mac_type);
return 0;
}

Expand Down Expand Up @@ -2675,7 +2708,7 @@ ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update)
goto out;
}

ice_copy_phy_caps_to_cfg(pcaps, &cfg);
ice_copy_phy_caps_to_cfg(pi, pcaps, &cfg);

/* Configure the set PHY data */
status = ice_cfg_phy_fc(pi, &cfg, pi->fc.req_mode);
Expand Down Expand Up @@ -2757,17 +2790,19 @@ ice_phy_caps_equals_cfg(struct ice_aqc_get_phy_caps_data *phy_caps,

/**
* ice_copy_phy_caps_to_cfg - Copy PHY ability data to configuration data
* @pi: port information structure
* @caps: PHY ability structure to copy date from
* @cfg: PHY configuration structure to copy data to
*
* Helper function to copy AQC PHY get ability data to PHY set configuration
* data structure
*/
void
ice_copy_phy_caps_to_cfg(struct ice_aqc_get_phy_caps_data *caps,
ice_copy_phy_caps_to_cfg(struct ice_port_info *pi,
struct ice_aqc_get_phy_caps_data *caps,
struct ice_aqc_set_phy_cfg_data *cfg)
{
if (!caps || !cfg)
if (!pi || !caps || !cfg)
return;

memset(cfg, 0, sizeof(*cfg));
Expand All @@ -2778,6 +2813,19 @@ ice_copy_phy_caps_to_cfg(struct ice_aqc_get_phy_caps_data *caps,
cfg->eee_cap = caps->eee_cap;
cfg->eeer_value = caps->eeer_value;
cfg->link_fec_opt = caps->link_fec_options;
cfg->module_compliance_enforcement =
caps->module_compliance_enforcement;

if (ice_fw_supports_link_override(pi->hw)) {
struct ice_link_default_override_tlv tlv;

if (ice_get_link_default_override(&tlv, pi))
return;

if (tlv.options & ICE_LINK_OVERRIDE_STRICT_MODE)
cfg->module_compliance_enforcement |=
ICE_LINK_OVERRIDE_STRICT_MODE;
}
}

/**
Expand Down Expand Up @@ -2840,6 +2888,17 @@ ice_cfg_phy_fec(struct ice_port_info *pi, struct ice_aqc_set_phy_cfg_data *cfg,
break;
}

if (fec == ICE_FEC_AUTO && ice_fw_supports_link_override(pi->hw)) {
struct ice_link_default_override_tlv tlv;

if (ice_get_link_default_override(&tlv, pi))
goto out;

if (!(tlv.options & ICE_LINK_OVERRIDE_STRICT_MODE) &&
(tlv.options & ICE_LINK_OVERRIDE_EN))
cfg->link_fec_opt = tlv.fec_options;
}

out:
kfree(pcaps);

Expand Down Expand Up @@ -4043,3 +4102,106 @@ ice_sched_query_elem(struct ice_hw *hw, u32 node_teid,
ice_debug(hw, ICE_DBG_SCHED, "query element failed\n");
return status;
}

/**
* ice_fw_supports_link_override
* @hw: pointer to the hardware structure
*
* Checks if the firmware supports link override
*/
bool ice_fw_supports_link_override(struct ice_hw *hw)
{
/* Currently, only supported for E810 devices */
if (hw->mac_type != ICE_MAC_E810)
return false;

if (hw->api_maj_ver == ICE_FW_API_LINK_OVERRIDE_MAJ) {
if (hw->api_min_ver > ICE_FW_API_LINK_OVERRIDE_MIN)
return true;
if (hw->api_min_ver == ICE_FW_API_LINK_OVERRIDE_MIN &&
hw->api_patch >= ICE_FW_API_LINK_OVERRIDE_PATCH)
return true;
} else if (hw->api_maj_ver > ICE_FW_API_LINK_OVERRIDE_MAJ) {
return true;
}

return false;
}

/**
* ice_get_link_default_override
* @ldo: pointer to the link default override struct
* @pi: pointer to the port info struct
*
* Gets the link default override for a port
*/
enum ice_status
ice_get_link_default_override(struct ice_link_default_override_tlv *ldo,
struct ice_port_info *pi)
{
u16 i, tlv, tlv_len, tlv_start, buf, offset;
struct ice_hw *hw = pi->hw;
enum ice_status status;

status = ice_get_pfa_module_tlv(hw, &tlv, &tlv_len,
ICE_SR_LINK_DEFAULT_OVERRIDE_PTR);
if (status) {
ice_debug(hw, ICE_DBG_INIT,
"Failed to read link override TLV.\n");
return status;
}

/* Each port has its own config; calculate for our port */
tlv_start = tlv + pi->lport * ICE_SR_PFA_LINK_OVERRIDE_WORDS +
ICE_SR_PFA_LINK_OVERRIDE_OFFSET;

/* link options first */
status = ice_read_sr_word(hw, tlv_start, &buf);
if (status) {
ice_debug(hw, ICE_DBG_INIT,
"Failed to read override link options.\n");
return status;
}
ldo->options = buf & ICE_LINK_OVERRIDE_OPT_M;
ldo->phy_config = (buf & ICE_LINK_OVERRIDE_PHY_CFG_M) >>
ICE_LINK_OVERRIDE_PHY_CFG_S;

/* link PHY config */
offset = tlv_start + ICE_SR_PFA_LINK_OVERRIDE_FEC_OFFSET;
status = ice_read_sr_word(hw, offset, &buf);
if (status) {
ice_debug(hw, ICE_DBG_INIT,
"Failed to read override phy config.\n");
return status;
}
ldo->fec_options = buf & ICE_LINK_OVERRIDE_FEC_OPT_M;

/* PHY types low */
offset = tlv_start + ICE_SR_PFA_LINK_OVERRIDE_PHY_OFFSET;
for (i = 0; i < ICE_SR_PFA_LINK_OVERRIDE_PHY_WORDS; i++) {
status = ice_read_sr_word(hw, (offset + i), &buf);
if (status) {
ice_debug(hw, ICE_DBG_INIT,
"Failed to read override link options.\n");
return status;
}
/* shift 16 bits at a time to fill 64 bits */
ldo->phy_type_low |= ((u64)buf << (i * 16));
}

/* PHY types high */
offset = tlv_start + ICE_SR_PFA_LINK_OVERRIDE_PHY_OFFSET +
ICE_SR_PFA_LINK_OVERRIDE_PHY_WORDS;
for (i = 0; i < ICE_SR_PFA_LINK_OVERRIDE_PHY_WORDS; i++) {
status = ice_read_sr_word(hw, (offset + i), &buf);
if (status) {
ice_debug(hw, ICE_DBG_INIT,
"Failed to read override link options.\n");
return status;
}
/* shift 16 bits at a time to fill 64 bits */
ldo->phy_type_high |= ((u64)buf << (i * 16));
}

return status;
}
8 changes: 7 additions & 1 deletion drivers/net/ethernet/intel/ice/ice_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ enum ice_status ice_clear_pf_cfg(struct ice_hw *hw);
enum ice_status
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);
bool ice_fw_supports_link_override(struct ice_hw *hw);
enum ice_status
ice_get_link_default_override(struct ice_link_default_override_tlv *ldo,
struct ice_port_info *pi);

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
Expand All @@ -112,7 +117,8 @@ bool
ice_phy_caps_equals_cfg(struct ice_aqc_get_phy_caps_data *caps,
struct ice_aqc_set_phy_cfg_data *cfg);
void
ice_copy_phy_caps_to_cfg(struct ice_aqc_get_phy_caps_data *caps,
ice_copy_phy_caps_to_cfg(struct ice_port_info *pi,
struct ice_aqc_get_phy_caps_data *caps,
struct ice_aqc_set_phy_cfg_data *cfg);
enum ice_status
ice_cfg_phy_fec(struct ice_port_info *pi, struct ice_aqc_set_phy_cfg_data *cfg,
Expand Down
Loading

0 comments on commit ea78ce4

Please sign in to comment.