diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_adminq_cmd.h | 25 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_common.c | 121 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_common.h | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_controlq.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_controlq.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_dcb.c | 14 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_dcb_lib.c | 24 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_ethtool.c | 229 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_lib.c | 216 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_lib.h | 12 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_main.c | 199 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_switch.c | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_txrx.c | 8 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_type.h | 12 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c | 95 |
16 files changed, 754 insertions, 218 deletions
diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index c1e4dd7357b4..9ee6b55553c0 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -44,7 +44,7 @@ extern const char ice_drv_ver[]; #define ICE_BAR0 0 #define ICE_REQ_DESC_MULTIPLE 32 -#define ICE_MIN_NUM_DESC ICE_REQ_DESC_MULTIPLE +#define ICE_MIN_NUM_DESC 64 #define ICE_MAX_NUM_DESC 8160 #define ICE_DFLT_MIN_RX_DESC 512 /* if the default number of Rx descriptors between ICE_MAX_NUM_DESC and the diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index 8680ee2ffa1b..765e3c2ed045 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -35,8 +35,8 @@ struct ice_aqc_get_ver { /* Queue Shutdown (direct 0x0003) */ struct ice_aqc_q_shutdown { -#define ICE_AQC_DRIVER_UNLOADING BIT(0) __le32 driver_unloading; +#define ICE_AQC_DRIVER_UNLOADING BIT(0) u8 reserved[12]; }; @@ -120,11 +120,9 @@ struct ice_aqc_manage_mac_read { #define ICE_AQC_MAN_MAC_WOL_ADDR_VALID BIT(7) #define ICE_AQC_MAN_MAC_READ_S 4 #define ICE_AQC_MAN_MAC_READ_M (0xF << ICE_AQC_MAN_MAC_READ_S) - u8 lport_num; - u8 lport_num_valid; -#define ICE_AQC_MAN_MAC_PORT_NUM_IS_VALID BIT(0) + u8 rsvd[2]; u8 num_addr; /* Used in response */ - u8 reserved[3]; + u8 rsvd1[3]; __le32 addr_high; __le32 addr_low; }; @@ -140,7 +138,7 @@ struct ice_aqc_manage_mac_read_resp { /* Manage MAC address, write command - direct (0x0108) */ struct ice_aqc_manage_mac_write { - u8 port_num; + u8 rsvd; u8 flags; #define ICE_AQC_MAN_MAC_WR_MC_MAG_EN BIT(0) #define ICE_AQC_MAN_MAC_WR_WOL_LAA_PFR_KEEP BIT(1) @@ -920,6 +918,8 @@ struct ice_aqc_get_phy_caps_data { #define ICE_AQC_PHY_EN_LINK BIT(3) #define ICE_AQC_PHY_AN_MODE BIT(4) #define ICE_AQC_GET_PHY_EN_MOD_QUAL BIT(5) +#define ICE_AQC_PHY_EN_AUTO_FEC BIT(7) +#define ICE_AQC_PHY_CAPS_MASK ICE_M(0xff, 0) u8 low_power_ctrl; #define ICE_AQC_PHY_EN_D3COLD_LOW_POWER_AUTONEG BIT(0) __le16 eee_cap; @@ -932,6 +932,7 @@ struct ice_aqc_get_phy_caps_data { #define ICE_AQC_PHY_EEE_EN_40GBASE_KR4 BIT(6) __le16 eeer_value; u8 phy_id_oui[4]; /* PHY/Module ID connected on the port */ + u8 phy_fw_ver[8]; u8 link_fec_options; #define ICE_AQC_PHY_FEC_10G_KR_40G_KR4_EN BIT(0) #define ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ BIT(1) @@ -940,6 +941,8 @@ struct ice_aqc_get_phy_caps_data { #define ICE_AQC_PHY_FEC_25G_RS_544_REQ BIT(4) #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 extended_compliance_code; #define ICE_MODULE_TYPE_TOTAL_BYTE 3 u8 module_type[ICE_MODULE_TYPE_TOTAL_BYTE]; @@ -954,13 +957,14 @@ struct ice_aqc_get_phy_caps_data { #define ICE_AQC_MOD_TYPE_BYTE2_SFP_PLUS 0xA0 #define ICE_AQC_MOD_TYPE_BYTE2_QSFP_PLUS 0x86 u8 qualified_module_count; + u8 rsvd2[7]; /* Bytes 47:41 reserved */ #define ICE_AQC_QUAL_MOD_COUNT_MAX 16 struct { u8 v_oui[3]; - u8 rsvd1; + u8 rsvd3; u8 v_part[16]; __le32 v_rev; - __le64 rsvd8; + __le64 rsvd4; } qual_modules[ICE_AQC_QUAL_MOD_COUNT_MAX]; }; @@ -1062,6 +1066,7 @@ struct ice_aqc_get_link_status_data { #define ICE_AQ_LINK_25G_KR_FEC_EN BIT(0) #define ICE_AQ_LINK_25G_RS_528_FEC_EN BIT(1) #define ICE_AQ_LINK_25G_RS_544_FEC_EN BIT(2) +#define ICE_AQ_FEC_MASK ICE_M(0x7, 0) /* Pacing Config */ #define ICE_AQ_CFG_PACING_S 3 #define ICE_AQ_CFG_PACING_M (0xF << ICE_AQ_CFG_PACING_S) @@ -1268,7 +1273,7 @@ struct ice_aqc_get_cee_dcb_cfg_resp { }; /* Set Local LLDP MIB (indirect 0x0A08) - * Used to replace the local MIB of a given LLDP agent. e.g. DCBx + * Used to replace the local MIB of a given LLDP agent. e.g. DCBX */ struct ice_aqc_lldp_set_local_mib { u8 type; @@ -1285,7 +1290,7 @@ struct ice_aqc_lldp_set_local_mib { }; /* Stop/Start LLDP Agent (direct 0x0A09) - * Used for stopping/starting specific LLDP agent. e.g. DCBx. + * Used for stopping/starting specific LLDP agent. e.g. DCBX. * The same structure is used for the response, with the command field * being used as the status field. */ diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 16c694a1b076..2e0731c1e1a3 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -304,6 +304,8 @@ ice_aq_get_link_info(struct ice_port_info *pi, bool ena_lse, hw_link_info->an_info = link_data.an_info; hw_link_info->ext_info = link_data.ext_info; hw_link_info->max_frame_size = le16_to_cpu(link_data.max_frame_size); + hw_link_info->fec_info = link_data.cfg & ICE_AQ_FEC_MASK; + hw_link_info->topo_media_conflict = link_data.topo_media_conflict; hw_link_info->pacing = link_data.cfg & ICE_AQ_CFG_PACING_M; /* update fc info */ @@ -497,7 +499,7 @@ static enum ice_status ice_get_fw_log_cfg(struct ice_hw *hw) if (!status) { u16 i; - /* Save fw logging information into the hw structure */ + /* Save FW logging information into the HW structure */ for (i = 0; i < ICE_AQC_FW_LOG_ID_MAX; i++) { u16 v, m, flgs; @@ -679,17 +681,17 @@ out: */ void ice_output_fw_log(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf) { - ice_debug(hw, ICE_DBG_AQ_MSG, "[ FW Log Msg Start ]\n"); - ice_debug_array(hw, ICE_DBG_AQ_MSG, 16, 1, (u8 *)buf, + ice_debug(hw, ICE_DBG_FW_LOG, "[ FW Log Msg Start ]\n"); + ice_debug_array(hw, ICE_DBG_FW_LOG, 16, 1, (u8 *)buf, le16_to_cpu(desc->datalen)); - ice_debug(hw, ICE_DBG_AQ_MSG, "[ FW Log Msg End ]\n"); + ice_debug(hw, ICE_DBG_FW_LOG, "[ FW Log Msg End ]\n"); } /** * ice_get_itr_intrl_gran - determine int/intrl granularity * @hw: pointer to the HW struct * - * Determines the itr/intrl granularities based on the maximum aggregate + * Determines the ITR/intrl granularities based on the maximum aggregate * bandwidth according to the device's configuration during power-on. */ static void ice_get_itr_intrl_gran(struct ice_hw *hw) @@ -860,6 +862,10 @@ err_unroll_cqinit: /** * ice_deinit_hw - unroll initialization operations done by ice_init_hw * @hw: pointer to the hardware structure + * + * This should be called only during nominal operation, not as a result of + * ice_init_hw() failing since ice_init_hw() will take care of unrolling + * applicable initializations if it fails for any reason. */ void ice_deinit_hw(struct ice_hw *hw) { @@ -1996,36 +2002,37 @@ ice_aq_set_phy_cfg(struct ice_hw *hw, u8 lport, */ enum ice_status ice_update_link_info(struct ice_port_info *pi) { - struct ice_aqc_get_phy_caps_data *pcaps; - struct ice_phy_info *phy_info; + struct ice_link_status *li; enum ice_status status; - struct ice_hw *hw; if (!pi) return ICE_ERR_PARAM; - hw = pi->hw; + li = &pi->phy.link_info; - pcaps = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*pcaps), GFP_KERNEL); - if (!pcaps) - return ICE_ERR_NO_MEMORY; - - phy_info = &pi->phy; status = ice_aq_get_link_info(pi, true, NULL, NULL); if (status) - goto out; + return status; + + if (li->link_info & ICE_AQ_MEDIA_AVAILABLE) { + struct ice_aqc_get_phy_caps_data *pcaps; + struct ice_hw *hw; + + hw = pi->hw; + pcaps = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*pcaps), + GFP_KERNEL); + if (!pcaps) + return ICE_ERR_NO_MEMORY; - if (phy_info->link_info.link_info & ICE_AQ_MEDIA_AVAILABLE) { status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_SW_CFG, pcaps, NULL); - if (status) - goto out; + if (!status) + memcpy(li->module_type, &pcaps->module_type, + sizeof(li->module_type)); - memcpy(phy_info->link_info.module_type, &pcaps->module_type, - sizeof(phy_info->link_info.module_type)); + devm_kfree(ice_hw_to_dev(hw), pcaps); } -out: - devm_kfree(ice_hw_to_dev(hw), pcaps); + return status; } @@ -2130,6 +2137,74 @@ out: } /** + * ice_copy_phy_caps_to_cfg - Copy PHY ability data to configuration data + * @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, + struct ice_aqc_set_phy_cfg_data *cfg) +{ + if (!caps || !cfg) + return; + + cfg->phy_type_low = caps->phy_type_low; + cfg->phy_type_high = caps->phy_type_high; + cfg->caps = caps->caps; + cfg->low_power_ctrl = caps->low_power_ctrl; + cfg->eee_cap = caps->eee_cap; + cfg->eeer_value = caps->eeer_value; + cfg->link_fec_opt = caps->link_fec_options; +} + +/** + * ice_cfg_phy_fec - Configure PHY FEC data based on FEC mode + * @cfg: PHY configuration data to set FEC mode + * @fec: FEC mode to configure + * + * Caller should copy ice_aqc_get_phy_caps_data.caps ICE_AQC_PHY_EN_AUTO_FEC + * (bit 7) and ice_aqc_get_phy_caps_data.link_fec_options to cfg.caps + * ICE_AQ_PHY_ENA_AUTO_FEC (bit 7) and cfg.link_fec_options before calling. + */ +void +ice_cfg_phy_fec(struct ice_aqc_set_phy_cfg_data *cfg, enum ice_fec_mode fec) +{ + switch (fec) { + case ICE_FEC_BASER: + /* Clear auto FEC and RS bits, and AND BASE-R ability + * bits and OR request bits. + */ + cfg->caps &= ~ICE_AQC_PHY_EN_AUTO_FEC; + cfg->link_fec_opt &= ICE_AQC_PHY_FEC_10G_KR_40G_KR4_EN | + ICE_AQC_PHY_FEC_25G_KR_CLAUSE74_EN; + cfg->link_fec_opt |= ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ | + ICE_AQC_PHY_FEC_25G_KR_REQ; + break; + case ICE_FEC_RS: + /* Clear auto FEC and BASE-R bits, and AND RS ability + * bits and OR request bits. + */ + cfg->caps &= ~ICE_AQC_PHY_EN_AUTO_FEC; + cfg->link_fec_opt &= ICE_AQC_PHY_FEC_25G_RS_CLAUSE91_EN; + cfg->link_fec_opt |= ICE_AQC_PHY_FEC_25G_RS_528_REQ | + ICE_AQC_PHY_FEC_25G_RS_544_REQ; + break; + case ICE_FEC_NONE: + /* Clear auto FEC and all FEC option bits. */ + cfg->caps &= ~ICE_AQC_PHY_EN_AUTO_FEC; + cfg->link_fec_opt &= ~ICE_AQC_PHY_FEC_MASK; + break; + case ICE_FEC_AUTO: + /* AND auto FEC bit, and all caps bits. */ + cfg->caps &= ICE_AQC_PHY_CAPS_MASK; + break; + } +} + +/** * ice_get_link_status - get status of the HW network link * @pi: port information structure * @link_up: pointer to bool (true/false = linkup/linkdown) @@ -2624,7 +2699,7 @@ do_aq: ice_debug(hw, ICE_DBG_SCHED, "VM%d disable failed %d\n", vmvf_num, hw->adminq.sq_last_status); else - ice_debug(hw, ICE_DBG_SCHED, "disable Q %d failed %d\n", + ice_debug(hw, ICE_DBG_SCHED, "disable queue %d failed %d\n", le16_to_cpu(qg_list[0].q_id[0]), hw->adminq.sq_last_status); } diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index 9773d7b2e9c9..d1f8353fe6bb 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -86,7 +86,11 @@ ice_aq_set_phy_cfg(struct ice_hw *hw, u8 lport, enum ice_status ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update); - +void +ice_cfg_phy_fec(struct ice_aqc_set_phy_cfg_data *cfg, enum ice_fec_mode fec); +void +ice_copy_phy_caps_to_cfg(struct ice_aqc_get_phy_caps_data *caps, + struct ice_aqc_set_phy_cfg_data *cfg); enum ice_status ice_aq_set_link_restart_an(struct ice_port_info *pi, bool ena_link, struct ice_sq_cd *cd); diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.c b/drivers/net/ethernet/intel/ice/ice_controlq.c index cc8cb5fdcdc1..e91ac4df0242 100644 --- a/drivers/net/ethernet/intel/ice/ice_controlq.c +++ b/drivers/net/ethernet/intel/ice/ice_controlq.c @@ -439,7 +439,7 @@ do { \ /* free the buffer info list */ \ if ((qi)->ring.cmd_buf) \ devm_kfree(ice_hw_to_dev(hw), (qi)->ring.cmd_buf); \ - /* free dma head */ \ + /* free DMA head */ \ devm_kfree(ice_hw_to_dev(hw), (qi)->ring.dma_head); \ } while (0) diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.h b/drivers/net/ethernet/intel/ice/ice_controlq.h index e0585394d984..44945c2165d8 100644 --- a/drivers/net/ethernet/intel/ice/ice_controlq.h +++ b/drivers/net/ethernet/intel/ice/ice_controlq.h @@ -35,7 +35,7 @@ enum ice_ctl_q { #define ICE_CTL_Q_SQ_CMD_TIMEOUT 250 /* msecs */ struct ice_ctl_q_ring { - void *dma_head; /* Virtual address to dma head */ + void *dma_head; /* Virtual address to DMA head */ struct ice_dma_mem desc_buf; /* descriptor ring memory */ void *cmd_buf; /* command buffer memory */ diff --git a/drivers/net/ethernet/intel/ice/ice_dcb.c b/drivers/net/ethernet/intel/ice/ice_dcb.c index 49fbfe7c1ad7..c2002ded65f6 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb.c +++ b/drivers/net/ethernet/intel/ice/ice_dcb.c @@ -669,7 +669,7 @@ ice_lldp_to_dcb_cfg(u8 *lldpmib, struct ice_dcbx_cfg *dcbcfg) /** * ice_aq_get_dcb_cfg * @hw: pointer to the HW struct - * @mib_type: mib type for the query + * @mib_type: MIB type for the query * @bridgetype: bridge type for the query (remote) * @dcbcfg: store for LLDPDU data * @@ -700,13 +700,13 @@ ice_aq_get_dcb_cfg(struct ice_hw *hw, u8 mib_type, u8 bridgetype, } /** - * ice_aq_start_stop_dcbx - Start/Stop DCBx service in FW + * ice_aq_start_stop_dcbx - Start/Stop DCBX service in FW * @hw: pointer to the HW struct - * @start_dcbx_agent: True if DCBx Agent needs to be started - * False if DCBx Agent needs to be stopped - * @dcbx_agent_status: FW indicates back the DCBx agent status - * True if DCBx Agent is active - * False if DCBx Agent is stopped + * @start_dcbx_agent: True if DCBX Agent needs to be started + * False if DCBX Agent needs to be stopped + * @dcbx_agent_status: FW indicates back the DCBX agent status + * True if DCBX Agent is active + * False if DCBX Agent is stopped * @cd: pointer to command details structure or NULL * * Start/Stop the embedded dcbx Agent. In case that this wrapper function diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c index b97e3e8d499b..fe88b127ca42 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c @@ -120,12 +120,14 @@ static void ice_pf_dcb_recfg(struct ice_pf *pf) tc_map = ICE_DFLT_TRAFFIC_CLASS; ret = ice_vsi_cfg_tc(pf->vsi[v], tc_map); - if (ret) + if (ret) { dev_err(&pf->pdev->dev, "Failed to config TC for VSI index: %d\n", pf->vsi[v]->idx); - else - ice_vsi_map_rings_to_vectors(pf->vsi[v]); + continue; + } + + ice_vsi_map_rings_to_vectors(pf->vsi[v]); } } @@ -281,7 +283,7 @@ dcb_error: /** * ice_dcb_init_cfg - set the initial DCB config in SW - * @pf: pf to apply config to + * @pf: PF to apply config to * @locked: Is the RTNL held */ static int ice_dcb_init_cfg(struct ice_pf *pf, bool locked) @@ -309,7 +311,7 @@ static int ice_dcb_init_cfg(struct ice_pf *pf, bool locked) /** * ice_dcb_sw_default_config - Apply a default DCB config - * @pf: pf to apply config to + * @pf: PF to apply config to * @locked: was this function called with RTNL held */ static int ice_dcb_sw_dflt_cfg(struct ice_pf *pf, bool locked) @@ -354,7 +356,7 @@ static int ice_dcb_sw_dflt_cfg(struct ice_pf *pf, bool locked) /** * ice_init_pf_dcb - initialize DCB for a PF - * @pf: pf to initiialize DCB for + * @pf: PF to initialize DCB for * @locked: Was function called with RTNL held */ int ice_init_pf_dcb(struct ice_pf *pf, bool locked) @@ -369,7 +371,7 @@ int ice_init_pf_dcb(struct ice_pf *pf, bool locked) err = ice_init_dcb(hw); if (err) { - /* FW LLDP is not active, default to SW DCBx/LLDP */ + /* FW LLDP is not active, default to SW DCBX/LLDP */ dev_info(&pf->pdev->dev, "FW LLDP is not active\n"); hw->port_info->dcbx_status = ICE_DCBX_STATUS_NOT_STARTED; hw->port_info->is_sw_lldp = true; @@ -387,10 +389,8 @@ int ice_init_pf_dcb(struct ice_pf *pf, bool locked) set_bit(ICE_FLAG_ENABLE_FW_LLDP, pf->flags); } - if (port_info->dcbx_status == ICE_DCBX_STATUS_NOT_STARTED) { - sw_default = 1; + if (port_info->dcbx_status == ICE_DCBX_STATUS_NOT_STARTED) dev_info(&pf->pdev->dev, "DCBX not started\n"); - } if (sw_default) { err = ice_dcb_sw_dflt_cfg(pf, locked); @@ -604,10 +604,10 @@ ice_dcb_process_lldp_set_mib_change(struct ice_pf *pf, /* store the old configuration */ tmp_dcbx_cfg = pf->hw.port_info->local_dcbx_cfg; - /* Reset the old DCBx configuration data */ + /* Reset the old DCBX configuration data */ memset(&pi->local_dcbx_cfg, 0, sizeof(pi->local_dcbx_cfg)); - /* Get updated DCBx data from firmware */ + /* Get updated DCBX data from firmware */ ret = ice_get_dcb_cfg(pf->hw.port_info); if (ret) { dev_err(&pf->pdev->dev, "Failed to get DCB config\n"); diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 9dde6dd78643..52083a63dee6 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -960,6 +960,185 @@ ice_set_phys_id(struct net_device *netdev, enum ethtool_phys_id_state state) } /** + * ice_set_fec_cfg - Set link FEC options + * @netdev: network interface device structure + * @req_fec: FEC mode to configure + */ +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_aqc_set_phy_cfg_data config = { 0 }; + struct ice_aqc_get_phy_caps_data *caps; + struct ice_vsi *vsi = np->vsi; + u8 sw_cfg_caps, sw_cfg_fec; + struct ice_port_info *pi; + enum ice_status status; + int err = 0; + + pi = vsi->port_info; + if (!pi) + return -EOPNOTSUPP; + + /* Changing the FEC parameters is not supported if not the PF VSI */ + if (vsi->type != ICE_VSI_PF) { + netdev_info(netdev, "Changing FEC parameters only supported for PF VSI\n"); + return -EOPNOTSUPP; + } + + /* Get last SW configuration */ + caps = devm_kzalloc(&vsi->back->pdev->dev, sizeof(*caps), GFP_KERNEL); + if (!caps) + 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 */ + ice_copy_phy_caps_to_cfg(caps, &config); + sw_cfg_caps = caps->caps; + sw_cfg_fec = caps->link_fec_options; + + /* Get toloplogy caps, then copy PHY FEC topoloy caps to PHY config */ + memset(caps, 0, sizeof(*caps)); + + status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_TOPO_CAP, + caps, NULL); + if (status) { + err = -EAGAIN; + goto done; + } + + config.caps |= (caps->caps & ICE_AQC_PHY_EN_AUTO_FEC); + config.link_fec_opt = caps->link_fec_options; + + ice_cfg_phy_fec(&config, req_fec); + + /* If FEC mode has changed, then set PHY configuration and enable AN. */ + if ((config.caps & ICE_AQ_PHY_ENA_AUTO_FEC) != + (sw_cfg_caps & ICE_AQC_PHY_EN_AUTO_FEC) || + config.link_fec_opt != sw_cfg_fec) { + if (caps->caps & ICE_AQC_PHY_AN_MODE) + config.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; + + status = ice_aq_set_phy_cfg(pi->hw, pi->lport, &config, NULL); + + if (status) + err = -EAGAIN; + } + +done: + devm_kfree(&vsi->back->pdev->dev, caps); + return err; +} + +/** + * ice_set_fecparam - Set FEC link options + * @netdev: network interface device structure + * @fecparam: Ethtool structure to retrieve FEC parameters + */ +static int +ice_set_fecparam(struct net_device *netdev, struct ethtool_fecparam *fecparam) +{ + struct ice_netdev_priv *np = netdev_priv(netdev); + struct ice_vsi *vsi = np->vsi; + enum ice_fec_mode fec; + + switch (fecparam->fec) { + case ETHTOOL_FEC_AUTO: + fec = ICE_FEC_AUTO; + break; + case ETHTOOL_FEC_RS: + fec = ICE_FEC_RS; + break; + case ETHTOOL_FEC_BASER: + fec = ICE_FEC_BASER; + break; + case ETHTOOL_FEC_OFF: + case ETHTOOL_FEC_NONE: + fec = ICE_FEC_NONE; + break; + default: + dev_warn(&vsi->back->pdev->dev, "Unsupported FEC mode: %d\n", + fecparam->fec); + return -EINVAL; + } + + return ice_set_fec_cfg(netdev, fec); +} + +/** + * ice_get_fecparam - Get link FEC options + * @netdev: network interface device structure + * @fecparam: Ethtool structure to retrieve FEC parameters + */ +static int +ice_get_fecparam(struct net_device *netdev, struct ethtool_fecparam *fecparam) +{ + struct ice_netdev_priv *np = netdev_priv(netdev); + struct ice_aqc_get_phy_caps_data *caps; + struct ice_link_status *link_info; + struct ice_vsi *vsi = np->vsi; + struct ice_port_info *pi; + enum ice_status status; + int err = 0; + + pi = vsi->port_info; + + if (!pi) + return -EOPNOTSUPP; + link_info = &pi->phy.link_info; + + /* Set FEC mode based on negotiated link info */ + switch (link_info->fec_info) { + case ICE_AQ_LINK_25G_KR_FEC_EN: + fecparam->active_fec = ETHTOOL_FEC_BASER; + break; + case ICE_AQ_LINK_25G_RS_528_FEC_EN: + /* fall through */ + case ICE_AQ_LINK_25G_RS_544_FEC_EN: + fecparam->active_fec = ETHTOOL_FEC_RS; + break; + default: + fecparam->active_fec = ETHTOOL_FEC_OFF; + break; + } + + caps = devm_kzalloc(&vsi->back->pdev->dev, sizeof(*caps), GFP_KERNEL); + if (!caps) + return -ENOMEM; + + status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_TOPO_CAP, + caps, NULL); + if (status) { + err = -EAGAIN; + goto done; + } + + /* Set supported/configured FEC modes based on PHY capability */ + if (caps->caps & ICE_AQC_PHY_EN_AUTO_FEC) + fecparam->fec |= ETHTOOL_FEC_AUTO; + if (caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_EN || + caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ || + caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_CLAUSE74_EN || + caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_REQ) + fecparam->fec |= ETHTOOL_FEC_BASER; + if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_528_REQ || + caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_544_REQ || + caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_CLAUSE91_EN) + fecparam->fec |= ETHTOOL_FEC_RS; + if (caps->link_fec_options == 0) + fecparam->fec |= ETHTOOL_FEC_OFF; + +done: + devm_kfree(&vsi->back->pdev->dev, caps); + return err; +} + +/** * ice_get_priv_flags - report device private flags * @netdev: network interface device structure * @@ -1026,6 +1205,7 @@ static int ice_set_priv_flags(struct net_device *netdev, u32 flags) if (!test_bit(ICE_FLAG_ENABLE_FW_LLDP, pf->flags)) { enum ice_status status; + /* Disable FW LLDP engine */ status = ice_aq_cfg_lldp_mib_change(&pf->hw, false, NULL); /* If unregistering for LLDP events fails, this is @@ -1050,6 +1230,11 @@ static int ice_set_priv_flags(struct net_device *netdev, u32 flags) status = ice_init_pf_dcb(pf, true); if (status) dev_warn(&pf->pdev->dev, "Fail to init DCB\n"); + + /* Forward LLDP packets to default VSI so that they + * are passed up the stack + */ + ice_cfg_sw_lldp(vsi, false, true); } else { enum ice_status status; bool dcbx_agent_status; @@ -1062,7 +1247,7 @@ static int ice_set_priv_flags(struct net_device *netdev, u32 flags) dev_warn(&pf->pdev->dev, "Fail to start LLDP Agent\n"); - /* AQ command to start FW DCBx agent will fail if + /* AQ command to start FW DCBX agent will fail if * the agent is already started */ status = ice_aq_start_stop_dcbx(&pf->hw, true, @@ -1083,6 +1268,11 @@ static int ice_set_priv_flags(struct net_device *netdev, u32 flags) status = ice_init_pf_dcb(pf, true); if (status) dev_dbg(&pf->pdev->dev, "Fail to init DCB\n"); + + /* Remove rule to direct LLDP packets to default VSI. + * The FW LLDP engine will now be consuming them. + */ + ice_cfg_sw_lldp(vsi, false, false); } } clear_bit(ICE_FLAG_ETHTOOL_CTXT, pf->flags); @@ -1885,6 +2075,7 @@ ice_get_link_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *ks) { struct ice_netdev_priv *np = netdev_priv(netdev); + struct ice_aqc_get_phy_caps_data *caps; struct ice_link_status *hw_link_info; struct ice_vsi *vsi = np->vsi; @@ -1955,6 +2146,40 @@ ice_get_link_ksettings(struct net_device *netdev, 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 */ + ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_NONE); + + if (caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ || + caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_REQ) + ethtool_link_ksettings_add_link_mode(ks, advertising, + FEC_BASER); + if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_528_REQ || + caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_544_REQ) + ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_RS); + +done: + devm_kfree(&vsi->back->pdev->dev, caps); return 0; } @@ -3167,6 +3392,8 @@ static const struct ethtool_ops ice_ethtool_ops = { .get_ts_info = ethtool_op_get_ts_info, .get_per_queue_coalesce = ice_get_per_q_coalesce, .set_per_queue_coalesce = ice_set_per_q_coalesce, + .get_fecparam = ice_get_fecparam, + .set_fecparam = ice_set_fecparam, }; /** diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 8db9427d863f..35c5ff910afa 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -321,10 +321,10 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi, u16 vf_id) vsi->alloc_rxq = vf->num_vf_qs; /* pf->num_vf_msix includes (VF miscellaneous vector + * data queue interrupts). Since vsi->num_q_vectors is number - * of queues vectors, subtract 1 from the original vector - * count + * of queues vectors, subtract 1 (ICE_NONQ_VECS_VF) from the + * original vector count */ - vsi->num_q_vectors = pf->num_vf_msix - 1; + vsi->num_q_vectors = pf->num_vf_msix - ICE_NONQ_VECS_VF; break; case ICE_VSI_LB: vsi->alloc_txq = 1; @@ -1836,8 +1836,73 @@ ice_cfg_itr(struct ice_hw *hw, struct ice_q_vector *q_vector) } /** + * ice_cfg_txq_interrupt - configure interrupt on Tx queue + * @vsi: the VSI being configured + * @txq: Tx queue being mapped to MSI-X vector + * @msix_idx: MSI-X vector index within the function + * @itr_idx: ITR index of the interrupt cause + * + * Configure interrupt on Tx queue by associating Tx queue to MSI-X vector + * within the function space. + */ +#ifdef CONFIG_PCI_IOV +void +ice_cfg_txq_interrupt(struct ice_vsi *vsi, u16 txq, u16 msix_idx, u16 itr_idx) +#else +static void +ice_cfg_txq_interrupt(struct ice_vsi *vsi, u16 txq, u16 msix_idx, u16 itr_idx) +#endif /* CONFIG_PCI_IOV */ +{ + struct ice_pf *pf = vsi->back; + struct ice_hw *hw = &pf->hw; + u32 val; + + itr_idx = (itr_idx << QINT_TQCTL_ITR_INDX_S) & QINT_TQCTL_ITR_INDX_M; + + val = QINT_TQCTL_CAUSE_ENA_M | itr_idx | + ((msix_idx << QINT_TQCTL_MSIX_INDX_S) & QINT_TQCTL_MSIX_INDX_M); + + wr32(hw, QINT_TQCTL(vsi->txq_map[txq]), val); +} + +/** + * ice_cfg_rxq_interrupt - configure interrupt on Rx queue + * @vsi: the VSI being configured + * @rxq: Rx queue being mapped to MSI-X vector + * @msix_idx: MSI-X vector index within the function + * @itr_idx: ITR index of the interrupt cause + * + * Configure interrupt on Rx queue by associating Rx queue to MSI-X vector + * within the function space. + */ +#ifdef CONFIG_PCI_IOV +void +ice_cfg_rxq_interrupt(struct ice_vsi *vsi, u16 rxq, u16 msix_idx, u16 itr_idx) +#else +static void +ice_cfg_rxq_interrupt(struct ice_vsi *vsi, u16 rxq, u16 msix_idx, u16 itr_idx) +#endif /* CONFIG_PCI_IOV */ +{ + struct ice_pf *pf = vsi->back; + struct ice_hw *hw = &pf->hw; + u32 val; + + itr_idx = (itr_idx << QINT_RQCTL_ITR_INDX_S) & QINT_RQCTL_ITR_INDX_M; + + val = QINT_RQCTL_CAUSE_ENA_M | itr_idx | + ((msix_idx << QINT_RQCTL_MSIX_INDX_S) & QINT_RQCTL_MSIX_INDX_M); + + wr32(hw, QINT_RQCTL(vsi->rxq_map[rxq]), val); + + ice_flush(hw); +} + +/** * ice_vsi_cfg_msix - MSIX mode Interrupt Config in the HW * @vsi: the VSI being configured + * + * This configures MSIX mode interrupts for the PF VSI, and should not be used + * for the VF VSI. */ void ice_vsi_cfg_msix(struct ice_vsi *vsi) { @@ -1850,8 +1915,7 @@ void ice_vsi_cfg_msix(struct ice_vsi *vsi) struct ice_q_vector *q_vector = vsi->q_vectors[i]; u16 reg_idx = q_vector->reg_idx; - if (vsi->type != ICE_VSI_VF) - ice_cfg_itr(hw, q_vector); + ice_cfg_itr(hw, q_vector); wr32(hw, GLINT_RATE(reg_idx), ice_intrl_usec_to_reg(q_vector->intrl, hw->intrl_gran)); @@ -1868,43 +1932,17 @@ void ice_vsi_cfg_msix(struct ice_vsi *vsi) * tracked for this PF. */ for (q = 0; q < q_vector->num_ring_tx; q++) { - int itr_idx = (q_vector->tx.itr_idx << - QINT_TQCTL_ITR_INDX_S) & - QINT_TQCTL_ITR_INDX_M; - u32 val; - - if (vsi->type == ICE_VSI_VF) - val = QINT_TQCTL_CAUSE_ENA_M | itr_idx | - (((i + 1) << QINT_TQCTL_MSIX_INDX_S) & - QINT_TQCTL_MSIX_INDX_M); - else - val = QINT_TQCTL_CAUSE_ENA_M | itr_idx | - ((reg_idx << QINT_TQCTL_MSIX_INDX_S) & - QINT_TQCTL_MSIX_INDX_M); - wr32(hw, QINT_TQCTL(vsi->txq_map[txq]), val); + ice_cfg_txq_interrupt(vsi, txq, reg_idx, + q_vector->tx.itr_idx); txq++; } for (q = 0; q < q_vector->num_ring_rx; q++) { - int itr_idx = (q_vector->rx.itr_idx << - QINT_RQCTL_ITR_INDX_S) & - QINT_RQCTL_ITR_INDX_M; - u32 val; - - if (vsi->type == ICE_VSI_VF) - val = QINT_RQCTL_CAUSE_ENA_M | itr_idx | - (((i + 1) << QINT_RQCTL_MSIX_INDX_S) & - QINT_RQCTL_MSIX_INDX_M); - else - val = QINT_RQCTL_CAUSE_ENA_M | itr_idx | - ((reg_idx << QINT_RQCTL_MSIX_INDX_S) & - QINT_RQCTL_MSIX_INDX_M); - wr32(hw, QINT_RQCTL(vsi->rxq_map[rxq]), val); + ice_cfg_rxq_interrupt(vsi, rxq, reg_idx, + q_vector->rx.itr_idx); rxq++; } } - - ice_flush(hw); } /** @@ -2307,6 +2345,56 @@ ice_vsi_add_rem_eth_mac(struct ice_vsi *vsi, bool add_rule) ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list); } +#define ICE_ETH_P_LLDP 0x88CC + +/** + * ice_cfg_sw_lld |