diff options
Diffstat (limited to 'drivers/net/ethernet/intel/ice/ice_common.c')
| -rw-r--r-- | drivers/net/ethernet/intel/ice/ice_common.c | 372 | 
1 files changed, 324 insertions, 48 deletions
diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 27d0cbbd29da..039342a0ed15 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -8,6 +8,108 @@  #define ICE_PF_RESET_WAIT_COUNT	300 +static const char * const ice_link_mode_str_low[] = { +	[0] = "100BASE_TX", +	[1] = "100M_SGMII", +	[2] = "1000BASE_T", +	[3] = "1000BASE_SX", +	[4] = "1000BASE_LX", +	[5] = "1000BASE_KX", +	[6] = "1G_SGMII", +	[7] = "2500BASE_T", +	[8] = "2500BASE_X", +	[9] = "2500BASE_KX", +	[10] = "5GBASE_T", +	[11] = "5GBASE_KR", +	[12] = "10GBASE_T", +	[13] = "10G_SFI_DA", +	[14] = "10GBASE_SR", +	[15] = "10GBASE_LR", +	[16] = "10GBASE_KR_CR1", +	[17] = "10G_SFI_AOC_ACC", +	[18] = "10G_SFI_C2C", +	[19] = "25GBASE_T", +	[20] = "25GBASE_CR", +	[21] = "25GBASE_CR_S", +	[22] = "25GBASE_CR1", +	[23] = "25GBASE_SR", +	[24] = "25GBASE_LR", +	[25] = "25GBASE_KR", +	[26] = "25GBASE_KR_S", +	[27] = "25GBASE_KR1", +	[28] = "25G_AUI_AOC_ACC", +	[29] = "25G_AUI_C2C", +	[30] = "40GBASE_CR4", +	[31] = "40GBASE_SR4", +	[32] = "40GBASE_LR4", +	[33] = "40GBASE_KR4", +	[34] = "40G_XLAUI_AOC_ACC", +	[35] = "40G_XLAUI", +	[36] = "50GBASE_CR2", +	[37] = "50GBASE_SR2", +	[38] = "50GBASE_LR2", +	[39] = "50GBASE_KR2", +	[40] = "50G_LAUI2_AOC_ACC", +	[41] = "50G_LAUI2", +	[42] = "50G_AUI2_AOC_ACC", +	[43] = "50G_AUI2", +	[44] = "50GBASE_CP", +	[45] = "50GBASE_SR", +	[46] = "50GBASE_FR", +	[47] = "50GBASE_LR", +	[48] = "50GBASE_KR_PAM4", +	[49] = "50G_AUI1_AOC_ACC", +	[50] = "50G_AUI1", +	[51] = "100GBASE_CR4", +	[52] = "100GBASE_SR4", +	[53] = "100GBASE_LR4", +	[54] = "100GBASE_KR4", +	[55] = "100G_CAUI4_AOC_ACC", +	[56] = "100G_CAUI4", +	[57] = "100G_AUI4_AOC_ACC", +	[58] = "100G_AUI4", +	[59] = "100GBASE_CR_PAM4", +	[60] = "100GBASE_KR_PAM4", +	[61] = "100GBASE_CP2", +	[62] = "100GBASE_SR2", +	[63] = "100GBASE_DR", +}; + +static const char * const ice_link_mode_str_high[] = { +	[0] = "100GBASE_KR2_PAM4", +	[1] = "100G_CAUI2_AOC_ACC", +	[2] = "100G_CAUI2", +	[3] = "100G_AUI2_AOC_ACC", +	[4] = "100G_AUI2", +}; + +/** + * ice_dump_phy_type - helper function to dump phy_type + * @hw: pointer to the HW structure + * @low: 64 bit value for phy_type_low + * @high: 64 bit value for phy_type_high + * @prefix: prefix string to differentiate multiple dumps + */ +static void +ice_dump_phy_type(struct ice_hw *hw, u64 low, u64 high, const char *prefix) +{ +	ice_debug(hw, ICE_DBG_PHY, "%s: phy_type_low: 0x%016llx\n", prefix, low); + +	for (u32 i = 0; i < BITS_PER_TYPE(typeof(low)); i++) { +		if (low & BIT_ULL(i)) +			ice_debug(hw, ICE_DBG_PHY, "%s:   bit(%d): %s\n", +				  prefix, i, ice_link_mode_str_low[i]); +	} + +	ice_debug(hw, ICE_DBG_PHY, "%s: phy_type_high: 0x%016llx\n", prefix, high); + +	for (u32 i = 0; i < BITS_PER_TYPE(typeof(high)); i++) { +		if (high & BIT_ULL(i)) +			ice_debug(hw, ICE_DBG_PHY, "%s:   bit(%d): %s\n", +				  prefix, i, ice_link_mode_str_high[i]); +	} +} +  /**   * ice_set_mac_type - Sets MAC type   * @hw: pointer to the HW structure @@ -80,9 +182,23 @@ bool ice_is_e810t(struct ice_hw *hw)  {  	switch (hw->device_id) {  	case ICE_DEV_ID_E810C_SFP: -		if (hw->subsystem_device_id == ICE_SUBDEV_ID_E810T || -		    hw->subsystem_device_id == ICE_SUBDEV_ID_E810T2) +		switch (hw->subsystem_device_id) { +		case ICE_SUBDEV_ID_E810T: +		case ICE_SUBDEV_ID_E810T2: +		case ICE_SUBDEV_ID_E810T3: +		case ICE_SUBDEV_ID_E810T4: +		case ICE_SUBDEV_ID_E810T6: +		case ICE_SUBDEV_ID_E810T7: +			return true; +		} +		break; +	case ICE_DEV_ID_E810C_QSFP: +		switch (hw->subsystem_device_id) { +		case ICE_SUBDEV_ID_E810T2: +		case ICE_SUBDEV_ID_E810T3: +		case ICE_SUBDEV_ID_E810T5:  			return true; +		}  		break;  	default:  		break; @@ -183,6 +299,7 @@ ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode,  	struct ice_aqc_get_phy_caps *cmd;  	u16 pcaps_size = sizeof(*pcaps);  	struct ice_aq_desc desc; +	const char *prefix;  	struct ice_hw *hw;  	int status; @@ -204,29 +321,48 @@ ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode,  	cmd->param0 |= cpu_to_le16(report_mode);  	status = ice_aq_send_cmd(hw, &desc, pcaps, pcaps_size, cd); -	ice_debug(hw, ICE_DBG_LINK, "get phy caps - report_mode = 0x%x\n", -		  report_mode); -	ice_debug(hw, ICE_DBG_LINK, "	phy_type_low = 0x%llx\n", -		  (unsigned long long)le64_to_cpu(pcaps->phy_type_low)); -	ice_debug(hw, ICE_DBG_LINK, "	phy_type_high = 0x%llx\n", -		  (unsigned long long)le64_to_cpu(pcaps->phy_type_high)); -	ice_debug(hw, ICE_DBG_LINK, "	caps = 0x%x\n", pcaps->caps); -	ice_debug(hw, ICE_DBG_LINK, "	low_power_ctrl_an = 0x%x\n", +	ice_debug(hw, ICE_DBG_LINK, "get phy caps dump\n"); + +	switch (report_mode) { +	case ICE_AQC_REPORT_TOPO_CAP_MEDIA: +		prefix = "phy_caps_media"; +		break; +	case ICE_AQC_REPORT_TOPO_CAP_NO_MEDIA: +		prefix = "phy_caps_no_media"; +		break; +	case ICE_AQC_REPORT_ACTIVE_CFG: +		prefix = "phy_caps_active"; +		break; +	case ICE_AQC_REPORT_DFLT_CFG: +		prefix = "phy_caps_default"; +		break; +	default: +		prefix = "phy_caps_invalid"; +	} + +	ice_dump_phy_type(hw, le64_to_cpu(pcaps->phy_type_low), +			  le64_to_cpu(pcaps->phy_type_high), prefix); + +	ice_debug(hw, ICE_DBG_LINK, "%s: report_mode = 0x%x\n", +		  prefix, report_mode); +	ice_debug(hw, ICE_DBG_LINK, "%s: caps = 0x%x\n", prefix, pcaps->caps); +	ice_debug(hw, ICE_DBG_LINK, "%s: low_power_ctrl_an = 0x%x\n", prefix,  		  pcaps->low_power_ctrl_an); -	ice_debug(hw, ICE_DBG_LINK, "	eee_cap = 0x%x\n", pcaps->eee_cap); -	ice_debug(hw, ICE_DBG_LINK, "	eeer_value = 0x%x\n", +	ice_debug(hw, ICE_DBG_LINK, "%s: eee_cap = 0x%x\n", prefix, +		  pcaps->eee_cap); +	ice_debug(hw, ICE_DBG_LINK, "%s: eeer_value = 0x%x\n", prefix,  		  pcaps->eeer_value); -	ice_debug(hw, ICE_DBG_LINK, "	link_fec_options = 0x%x\n", +	ice_debug(hw, ICE_DBG_LINK, "%s: link_fec_options = 0x%x\n", prefix,  		  pcaps->link_fec_options); -	ice_debug(hw, ICE_DBG_LINK, "	module_compliance_enforcement = 0x%x\n", -		  pcaps->module_compliance_enforcement); -	ice_debug(hw, ICE_DBG_LINK, "   extended_compliance_code = 0x%x\n", -		  pcaps->extended_compliance_code); -	ice_debug(hw, ICE_DBG_LINK, "   module_type[0] = 0x%x\n", +	ice_debug(hw, ICE_DBG_LINK, "%s: module_compliance_enforcement = 0x%x\n", +		  prefix, pcaps->module_compliance_enforcement); +	ice_debug(hw, ICE_DBG_LINK, "%s: extended_compliance_code = 0x%x\n", +		  prefix, pcaps->extended_compliance_code); +	ice_debug(hw, ICE_DBG_LINK, "%s: module_type[0] = 0x%x\n", prefix,  		  pcaps->module_type[0]); -	ice_debug(hw, ICE_DBG_LINK, "   module_type[1] = 0x%x\n", +	ice_debug(hw, ICE_DBG_LINK, "%s: module_type[1] = 0x%x\n", prefix,  		  pcaps->module_type[1]); -	ice_debug(hw, ICE_DBG_LINK, "   module_type[2] = 0x%x\n", +	ice_debug(hw, ICE_DBG_LINK, "%s: module_type[2] = 0x%x\n", prefix,  		  pcaps->module_type[2]);  	if (!status && report_mode == ICE_AQC_REPORT_TOPO_CAP_MEDIA) { @@ -2397,6 +2533,8 @@ ice_parse_1588_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p,  	info->tmr1_owned = ((number & ICE_TS_TMR1_OWND_M) != 0);  	info->tmr1_ena = ((number & ICE_TS_TMR1_ENA_M) != 0); +	info->ts_ll_read = ((number & ICE_TS_LL_TX_TS_READ_M) != 0); +  	info->ena_ports = logical_id;  	info->tmr_own_map = phys_id; @@ -2414,6 +2552,8 @@ ice_parse_1588_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p,  		  info->tmr1_owned);  	ice_debug(hw, ICE_DBG_INIT, "dev caps: tmr1_ena = %u\n",  		  info->tmr1_ena); +	ice_debug(hw, ICE_DBG_INIT, "dev caps: ts_ll_read = %u\n", +		  info->ts_ll_read);  	ice_debug(hw, ICE_DBG_INIT, "dev caps: ieee_1588 ena_ports = %u\n",  		  info->ena_ports);  	ice_debug(hw, ICE_DBG_INIT, "dev caps: tmr_own_map = %u\n", @@ -2776,6 +2916,26 @@ ice_aq_set_port_params(struct ice_port_info *pi, bool double_vlan,  }  /** + * ice_is_100m_speed_supported + * @hw: pointer to the HW struct + * + * returns true if 100M speeds are supported by the device, + * false otherwise. + */ +bool ice_is_100m_speed_supported(struct ice_hw *hw) +{ +	switch (hw->device_id) { +	case ICE_DEV_ID_E822C_SGMII: +	case ICE_DEV_ID_E822L_SGMII: +	case ICE_DEV_ID_E823L_1GBE: +	case ICE_DEV_ID_E823C_SGMII: +		return true; +	default: +		return false; +	} +} + +/**   * ice_get_link_speed_based_on_phy_type - returns link speed   * @phy_type_low: lower part of phy_type   * @phy_type_high: higher part of phy_type @@ -3535,6 +3695,121 @@ ice_aq_set_port_id_led(struct ice_port_info *pi, bool is_orig_mode,  }  /** + * ice_aq_get_port_options + * @hw: pointer to the HW struct + * @options: buffer for the resultant port options + * @option_count: input - size of the buffer in port options structures, + *                output - number of returned port options + * @lport: logical port to call the command with (optional) + * @lport_valid: when false, FW uses port owned by the PF instead of lport, + *               when PF owns more than 1 port it must be true + * @active_option_idx: index of active port option in returned buffer + * @active_option_valid: active option in returned buffer is valid + * @pending_option_idx: index of pending port option in returned buffer + * @pending_option_valid: pending option in returned buffer is valid + * + * Calls Get Port Options AQC (0x06ea) and verifies result. + */ +int +ice_aq_get_port_options(struct ice_hw *hw, +			struct ice_aqc_get_port_options_elem *options, +			u8 *option_count, u8 lport, bool lport_valid, +			u8 *active_option_idx, bool *active_option_valid, +			u8 *pending_option_idx, bool *pending_option_valid) +{ +	struct ice_aqc_get_port_options *cmd; +	struct ice_aq_desc desc; +	int status; +	u8 i; + +	/* options buffer shall be able to hold max returned options */ +	if (*option_count < ICE_AQC_PORT_OPT_COUNT_M) +		return -EINVAL; + +	cmd = &desc.params.get_port_options; +	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_port_options); + +	if (lport_valid) +		cmd->lport_num = lport; +	cmd->lport_num_valid = lport_valid; + +	status = ice_aq_send_cmd(hw, &desc, options, +				 *option_count * sizeof(*options), NULL); +	if (status) +		return status; + +	/* verify direct FW response & set output parameters */ +	*option_count = FIELD_GET(ICE_AQC_PORT_OPT_COUNT_M, +				  cmd->port_options_count); +	ice_debug(hw, ICE_DBG_PHY, "options: %x\n", *option_count); +	*active_option_valid = FIELD_GET(ICE_AQC_PORT_OPT_VALID, +					 cmd->port_options); +	if (*active_option_valid) { +		*active_option_idx = FIELD_GET(ICE_AQC_PORT_OPT_ACTIVE_M, +					       cmd->port_options); +		if (*active_option_idx > (*option_count - 1)) +			return -EIO; +		ice_debug(hw, ICE_DBG_PHY, "active idx: %x\n", +			  *active_option_idx); +	} + +	*pending_option_valid = FIELD_GET(ICE_AQC_PENDING_PORT_OPT_VALID, +					  cmd->pending_port_option_status); +	if (*pending_option_valid) { +		*pending_option_idx = FIELD_GET(ICE_AQC_PENDING_PORT_OPT_IDX_M, +						cmd->pending_port_option_status); +		if (*pending_option_idx > (*option_count - 1)) +			return -EIO; +		ice_debug(hw, ICE_DBG_PHY, "pending idx: %x\n", +			  *pending_option_idx); +	} + +	/* mask output options fields */ +	for (i = 0; i < *option_count; i++) { +		options[i].pmd = FIELD_GET(ICE_AQC_PORT_OPT_PMD_COUNT_M, +					   options[i].pmd); +		options[i].max_lane_speed = FIELD_GET(ICE_AQC_PORT_OPT_MAX_LANE_M, +						      options[i].max_lane_speed); +		ice_debug(hw, ICE_DBG_PHY, "pmds: %x max speed: %x\n", +			  options[i].pmd, options[i].max_lane_speed); +	} + +	return 0; +} + +/** + * ice_aq_set_port_option + * @hw: pointer to the HW struct + * @lport: logical port to call the command with + * @lport_valid: when false, FW uses port owned by the PF instead of lport, + *               when PF owns more than 1 port it must be true + * @new_option: new port option to be written + * + * Calls Set Port Options AQC (0x06eb). + */ +int +ice_aq_set_port_option(struct ice_hw *hw, u8 lport, u8 lport_valid, +		       u8 new_option) +{ +	struct ice_aqc_set_port_option *cmd; +	struct ice_aq_desc desc; + +	if (new_option > ICE_AQC_PORT_OPT_COUNT_M) +		return -EINVAL; + +	cmd = &desc.params.set_port_option; +	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_port_option); + +	if (lport_valid) +		cmd->lport_num = lport; + +	cmd->lport_num_valid = lport_valid; +	cmd->selected_port_option = new_option; + +	return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); +} + +/**   * ice_aq_sff_eeprom   * @hw: pointer to the HW struct   * @lport: bits [7:0] = logical port, bit [8] = logical port valid @@ -5029,20 +5304,22 @@ ice_aq_get_gpio(struct ice_hw *hw, u16 gpio_ctrl_handle, u8 pin_idx,  }  /** - * ice_fw_supports_link_override + * ice_is_fw_api_min_ver   * @hw: pointer to the hardware structure + * @maj: major version + * @min: minor version + * @patch: patch version   * - * Checks if the firmware supports link override + * Checks if the firmware API is minimum version   */ -bool ice_fw_supports_link_override(struct ice_hw *hw) +static bool ice_is_fw_api_min_ver(struct ice_hw *hw, u8 maj, u8 min, u8 patch)  { -	if (hw->api_maj_ver == ICE_FW_API_LINK_OVERRIDE_MAJ) { -		if (hw->api_min_ver > ICE_FW_API_LINK_OVERRIDE_MIN) +	if (hw->api_maj_ver == maj) { +		if (hw->api_min_ver > min)  			return true; -		if (hw->api_min_ver == ICE_FW_API_LINK_OVERRIDE_MIN && -		    hw->api_patch >= ICE_FW_API_LINK_OVERRIDE_PATCH) +		if (hw->api_min_ver == min && hw->api_patch >= patch)  			return true; -	} else if (hw->api_maj_ver > ICE_FW_API_LINK_OVERRIDE_MAJ) { +	} else if (hw->api_maj_ver > maj) {  		return true;  	} @@ -5050,6 +5327,19 @@ bool ice_fw_supports_link_override(struct ice_hw *hw)  }  /** + * 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) +{ +	return ice_is_fw_api_min_ver(hw, ICE_FW_API_LINK_OVERRIDE_MAJ, +				     ICE_FW_API_LINK_OVERRIDE_MIN, +				     ICE_FW_API_LINK_OVERRIDE_PATCH); +} + +/**   * ice_get_link_default_override   * @ldo: pointer to the link default override struct   * @pi: pointer to the port info struct @@ -5179,16 +5469,9 @@ bool ice_fw_supports_lldp_fltr_ctrl(struct ice_hw *hw)  	if (hw->mac_type != ICE_MAC_E810)  		return false; -	if (hw->api_maj_ver == ICE_FW_API_LLDP_FLTR_MAJ) { -		if (hw->api_min_ver > ICE_FW_API_LLDP_FLTR_MIN) -			return true; -		if (hw->api_min_ver == ICE_FW_API_LLDP_FLTR_MIN && -		    hw->api_patch >= ICE_FW_API_LLDP_FLTR_PATCH) -			return true; -	} else if (hw->api_maj_ver > ICE_FW_API_LLDP_FLTR_MAJ) { -		return true; -	} -	return false; +	return ice_is_fw_api_min_ver(hw, ICE_FW_API_LLDP_FLTR_MAJ, +				     ICE_FW_API_LLDP_FLTR_MIN, +				     ICE_FW_API_LLDP_FLTR_PATCH);  }  /** @@ -5225,14 +5508,7 @@ ice_lldp_fltr_add_remove(struct ice_hw *hw, u16 vsi_num, bool add)   */  bool ice_fw_supports_report_dflt_cfg(struct ice_hw *hw)  { -	if (hw->api_maj_ver == ICE_FW_API_REPORT_DFLT_CFG_MAJ) { -		if (hw->api_min_ver > ICE_FW_API_REPORT_DFLT_CFG_MIN) -			return true; -		if (hw->api_min_ver == ICE_FW_API_REPORT_DFLT_CFG_MIN && -		    hw->api_patch >= ICE_FW_API_REPORT_DFLT_CFG_PATCH) -			return true; -	} else if (hw->api_maj_ver > ICE_FW_API_REPORT_DFLT_CFG_MAJ) { -		return true; -	} -	return false; +	return ice_is_fw_api_min_ver(hw, ICE_FW_API_REPORT_DFLT_CFG_MAJ, +				     ICE_FW_API_REPORT_DFLT_CFG_MIN, +				     ICE_FW_API_REPORT_DFLT_CFG_PATCH);  }  |