Commit ea78ce4d authored by Paul Greenwalt's avatar Paul Greenwalt Committed by Tony Nguyen

ice: add link lenient and default override support

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: default avatarPaul Greenwalt <paul.greenwalt@intel.com>
Signed-off-by: default avatarEvan Swanson <evan.swanson@intel.com>
Tested-by: default avatarAndrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: default avatarTony Nguyen <anthony.l.nguyen@intel.com>
parent 1a3571b5
......@@ -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 */
};
......@@ -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 */
};
......@@ -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 {
......
......@@ -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];
......@@ -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) */
......
......@@ -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;
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;
}
......@@ -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);
......@@ -2757,6 +2790,7 @@ 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
*
......@@ -2764,10 +2798,11 @@ ice_phy_caps_equals_cfg(struct ice_aqc_get_phy_caps_data *phy_caps,
* 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));
......@@ -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;
}
}
/**
......@@ -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);
......@@ -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;
}
......@@ -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
......@@ -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,
......
......@@ -1413,7 +1413,7 @@ static int ice_force_phys_link_state(struct ice_vsi *vsi, bool link_up)
* ice_init_nvm_phy_type - Initialize the NVM PHY type
* @pi: port info structure
*
* Initialize nvm_phy_type_[low|high]
* Initialize nvm_phy_type_[low|high] for link lenient mode support
*/
static int ice_init_nvm_phy_type(struct ice_port_info *pi)
{
......@@ -1443,6 +1443,59 @@ static int ice_init_nvm_phy_type(struct ice_port_info *pi)
return err;
}
/**
* ice_init_link_dflt_override - Initialize link default override
* @pi: port info structure
*/
static void ice_init_link_dflt_override(struct ice_port_info *pi)
{
struct ice_link_default_override_tlv *ldo;
struct ice_pf *pf = pi->hw->back;
ldo = &pf->link_dflt_override;
ice_get_link_default_override(ldo, pi);
}
/**
* ice_init_phy_cfg_dflt_override - Initialize PHY cfg default override settings
* @pi: port info structure
*
* If default override is enabled, initialized the user PHY cfg speed and FEC
* settings using the default override mask from the NVM.
*
* The PHY should only be configured with the default override settings the
* first time media is available. The __ICE_LINK_DEFAULT_OVERRIDE_PENDING state
* is used to indicate that the user PHY cfg default override is initialized
* and the PHY has not been configured with the default override settings. The
* state is set here, and cleared in ice_configure_phy the first time the PHY is
* configured.
*/
static void ice_init_phy_cfg_dflt_override(struct ice_port_info *pi)
{
struct ice_link_default_override_tlv *ldo;
struct ice_aqc_set_phy_cfg_data *cfg;
struct ice_phy_info *phy = &pi->phy;
struct ice_pf *pf = pi->hw->back;
ldo = &pf->link_dflt_override;
/* If link default override is enabled, use to mask NVM PHY capabilities
* for speed and FEC default configuration.
*/
cfg = &phy->curr_user_phy_cfg;
if (ldo->phy_type_low || ldo->phy_type_high) {
cfg->phy_type_low = pf->nvm_phy_type_lo &
cpu_to_le64(ldo->phy_type_low);
cfg->phy_type_high = pf->nvm_phy_type_hi &
cpu_to_le64(ldo->phy_type_high);
}
cfg->link_fec_opt = ldo->fec_options;
phy->curr_user_fec_req = ICE_FEC_AUTO;
set_bit(__ICE_LINK_DEFAULT_OVERRIDE_PENDING, pf->state);
}
/**
* ice_init_phy_user_cfg - Initialize the PHY user configuration
* @pi: port info structure
......@@ -1485,12 +1538,31 @@ static int ice_init_phy_user_cfg(struct ice_port_info *pi)
goto err_out;
}
ice_copy_phy_caps_to_cfg(pcaps, &pi->phy.curr_user_phy_cfg);
/* initialize PHY using topology with media */
ice_copy_phy_caps_to_cfg(pi, pcaps, &pi->phy.curr_user_phy_cfg);
/* check if lenient mode is supported and enabled */
if (ice_fw_supports_link_override(&vsi->back->hw) &&
!(pcaps->module_compliance_enforcement &
ICE_AQC_MOD_ENFORCE_STRICT_MODE)) {
set_bit(ICE_FLAG_LINK_LENIENT_MODE_ENA, pf->flags);
/* if link default override is enabled, initialize user PHY
* configuration with link default override values
*/
if (pf->link_dflt_override.options & ICE_LINK_OVERRIDE_EN) {
ice_init_phy_cfg_dflt_override(pi);
goto out;
}
}
/* if link default override is not enabled, initialize PHY using
* topology with media
*/
phy->curr_user_fec_req = ice_caps_to_fec_mode(pcaps->caps,
pcaps->link_fec_options);
phy->curr_user_fc_req = ice_caps_to_fc_mode(pcaps->caps);
out:
phy->curr_user_speed_req = ICE_AQ_LINK_SPEED_M;
set_bit(__ICE_PHY_INIT_COMPLETE, pf->state);
err_out:
......@@ -1511,7 +1583,6 @@ static int ice_configure_phy(struct ice_vsi *vsi)
struct device *dev = ice_pf_to_dev(vsi->back);
struct ice_aqc_get_phy_caps_data *pcaps;
struct ice_aqc_set_phy_cfg_data *cfg;
u64 phy_low = 0, phy_high = 0;
struct ice_port_info *pi;
enum ice_status status;
int err = 0;
......@@ -1571,14 +1642,24 @@ static int ice_configure_phy(struct ice_vsi *vsi)
goto done;
}
ice_copy_phy_caps_to_cfg(pcaps, cfg);
ice_copy_phy_caps_to_cfg(pi, pcaps, cfg);
/* Speed - If default override pending, use curr_user_phy_cfg set in
* ice_init_phy_user_cfg_ldo.
*/
ice_update_phy_type(&phy_low, &phy_high, pi->phy.curr_user_speed_req);
if (test_and_clear_bit(__ICE_LINK_DEFAULT_OVERRIDE_PENDING,
vsi->back->state)) {
cfg->phy_type_low = pi->phy.curr_user_phy_cfg.phy_type_low;
cfg->phy_type_high = pi->phy.curr_user_phy_cfg.phy_type_high;
} else {
u64 phy_low = 0, phy_high = 0;
ice_update_phy_type(&phy_low, &phy_high,
pi->phy.curr_user_speed_req);
cfg->phy_type_low = pcaps->phy_type_low & cpu_to_le64(phy_low);
cfg->phy_type_high = pcaps->phy_type_high & cpu_to_le64(phy_high);
cfg->phy_type_high = pcaps->phy_type_high &
cpu_to_le64(phy_high);
}
/* Can't provide what was requested; use PHY capabilities */
if (!cfg->phy_type_low && !cfg->phy_type_high) {
......@@ -3749,6 +3830,8 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
goto err_alloc_sw_unroll;
}
ice_init_link_dflt_override(pf->hw.port_info);
/* if media available, initialize PHY settings */
if (pf->hw.port_info->phy.link_info.link_info &
ICE_AQ_MEDIA_AVAILABLE) {
......
......@@ -196,7 +196,7 @@ enum ice_status ice_read_sr_word(struct ice_hw *hw, u16 offset, u16 *data)
* Area (PFA) and returns the TLV pointer and length. The caller can
* use these to read the variable length TLV value.
*/
static enum ice_status
enum ice_status
ice_get_pfa_module_tlv(struct ice_hw *hw, u16 *module_tlv, u16 *module_tlv_len,
u16 module_type)
{
......
......@@ -11,6 +11,9 @@ enum ice_status
ice_read_flat_nvm(struct ice_hw *hw, u32 offset, u32 *length, u8 *data,
bool read_shadow_ram);
enum ice_status
ice_get_pfa_module_tlv(struct ice_hw *hw, u16 *module_tlv, u16 *module_tlv_len,
u16 module_type);
enum ice_status
ice_read_pba_string(struct ice_hw *hw, u8 *pba_num, u32 pba_num_size);
enum ice_status ice_init_nvm(struct ice_hw *hw);
enum ice_status ice_read_sr_word(struct ice_hw *hw, u16 offset, u16 *data);
......
......@@ -118,6 +118,7 @@ enum ice_set_fc_aq_failures {
/* Various MAC types */
enum ice_mac_type {
ICE_MAC_UNKNOWN = 0,
ICE_MAC_E810,
ICE_MAC_GENERIC,
};
......@@ -314,6 +315,28 @@ struct ice_nvm_info {
u8 blank_nvm_mode; /* is NVM empty (no FW present) */
};
struct ice_link_default_override_tlv {
u8 options;
#define ICE_LINK_OVERRIDE_OPT_M 0x3F
#define ICE_LINK_OVERRIDE_STRICT_MODE BIT(0)
#define ICE_LINK_OVERRIDE_EPCT_DIS BIT(1)
#define ICE_LINK_OVERRIDE_PORT_DIS BIT(2)
#define ICE_LINK_OVERRIDE_EN BIT(3)
#define ICE_LINK_OVERRIDE_AUTO_LINK_DIS BIT(4)
#define ICE_LINK_OVERRIDE_EEE_EN BIT(5)
u8 phy_config;
#define ICE_LINK_OVERRIDE_PHY_CFG_S 8
#define ICE_LINK_OVERRIDE_PHY_CFG_M (0xC3 << ICE_LINK_OVERRIDE_PHY_CFG_S)
#define ICE_LINK_OVERRIDE_PAUSE_M 0x3
#define ICE_LINK_OVERRIDE_LESM_EN BIT(6)
#define ICE_LINK_OVERRIDE_AUTO_FEC_EN BIT(7)
u8 fec_options;
#define ICE_LINK_OVERRIDE_FEC_OPT_M 0xFF
u8 rsvd1;
u64 phy_type_low;
u64 phy_type_high;
};
#define ICE_NVM_VER_LEN 32
/* netlist version information */
......@@ -465,6 +488,7 @@ struct ice_dcb_app_priority_table {
#define ICE_APP_SEL_ETHTYPE 0x1
#define ICE_APP_SEL_TCPIP 0x2
#define ICE_CEE_APP_SEL_ETHTYPE 0x0
#define ICE_SR_LINK_DEFAULT_OVERRIDE_PTR 0x134
#define ICE_CEE_APP_SEL_TCPIP 0x1
struct ice_dcbx_cfg {
......@@ -748,6 +772,17 @@ struct ice_hw_port_stats {
#define ICE_OROM_VER_MASK (0xff << ICE_OROM_VER_SHIFT)
#define ICE_SR_PFA_PTR 0x40
#define ICE_SR_SECTOR_SIZE_IN_WORDS 0x800
/* Link override related */
#define ICE_SR_PFA_LINK_OVERRIDE_WORDS 10
#define ICE_SR_PFA_LINK_OVERRIDE_PHY_WORDS 4
#define ICE_SR_PFA_LINK_OVERRIDE_OFFSET 2
#define ICE_SR_PFA_LINK_OVERRIDE_FEC_OFFSET 1
#define ICE_SR_PFA_LINK_OVERRIDE_PHY_OFFSET 2
#define ICE_FW_API_LINK_OVERRIDE_MAJ 1
#define ICE_FW_API_LINK_OVERRIDE_MIN 5
#define ICE_FW_API_LINK_OVERRIDE_PATCH 2
#define ICE_SR_WORDS_IN_1KB 512
/* Hash redirection LUT for VSI - maximum array size */
......
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