forked from mirrors/linux
		
	ice: Implement handlers for ethtool PHY/link operations
This patch implements handlers for ethtool get_link_ksettings and set_link_ksettings. Helper functions use by these handlers are also introduced in this patch. Signed-off-by: Chinh Cao <chinh.t.cao@intel.com> Signed-off-by: Anirudh Venkataramanan <anirudh.venkataramanan@intel.com> Tested-by: Tony Brelinski <tonyx.brelinski@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
		
							parent
							
								
									0f9d5027a7
								
							
						
					
					
						commit
						48cb27f2fd
					
				
					 4 changed files with 892 additions and 54 deletions
				
			
		| 
						 | 
					@ -922,7 +922,9 @@ struct ice_aqc_set_phy_cfg_data {
 | 
				
			||||||
#define ICE_AQ_PHY_ENA_RX_PAUSE_ABILITY		BIT(1)
 | 
					#define ICE_AQ_PHY_ENA_RX_PAUSE_ABILITY		BIT(1)
 | 
				
			||||||
#define ICE_AQ_PHY_ENA_LOW_POWER	BIT(2)
 | 
					#define ICE_AQ_PHY_ENA_LOW_POWER	BIT(2)
 | 
				
			||||||
#define ICE_AQ_PHY_ENA_LINK		BIT(3)
 | 
					#define ICE_AQ_PHY_ENA_LINK		BIT(3)
 | 
				
			||||||
#define ICE_AQ_PHY_ENA_ATOMIC_LINK		BIT(5)
 | 
					#define ICE_AQ_PHY_ENA_AUTO_LINK_UPDT	BIT(5)
 | 
				
			||||||
 | 
					#define ICE_AQ_PHY_ENA_LESM		BIT(6)
 | 
				
			||||||
 | 
					#define ICE_AQ_PHY_ENA_AUTO_FEC		BIT(7)
 | 
				
			||||||
	u8 low_power_ctrl;
 | 
						u8 low_power_ctrl;
 | 
				
			||||||
	__le16 eee_cap; /* Value from ice_aqc_get_phy_caps */
 | 
						__le16 eee_cap; /* Value from ice_aqc_get_phy_caps */
 | 
				
			||||||
	__le16 eeer_value;
 | 
						__le16 eeer_value;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -125,7 +125,7 @@ ice_aq_manage_mac_read(struct ice_hw *hw, void *buf, u16 buf_size,
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Returns the various PHY capabilities supported on the Port (0x0600)
 | 
					 * Returns the various PHY capabilities supported on the Port (0x0600)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static enum ice_status
 | 
					enum ice_status
 | 
				
			||||||
ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode,
 | 
					ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode,
 | 
				
			||||||
		    struct ice_aqc_get_phy_caps_data *pcaps,
 | 
							    struct ice_aqc_get_phy_caps_data *pcaps,
 | 
				
			||||||
		    struct ice_sq_cd *cd)
 | 
							    struct ice_sq_cd *cd)
 | 
				
			||||||
| 
						 | 
					@ -1408,6 +1408,110 @@ void ice_clear_pxe_mode(struct ice_hw *hw)
 | 
				
			||||||
		ice_aq_clear_pxe_mode(hw);
 | 
							ice_aq_clear_pxe_mode(hw);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * ice_get_link_speed_based_on_phy_type - returns link speed
 | 
				
			||||||
 | 
					 * @phy_type_low: lower part of phy_type
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This helper function will convert a phy_type_low to its corresponding link
 | 
				
			||||||
 | 
					 * speed.
 | 
				
			||||||
 | 
					 * Note: In the structure of phy_type_low, there should be one bit set, as
 | 
				
			||||||
 | 
					 * this function will convert one phy type to its speed.
 | 
				
			||||||
 | 
					 * If no bit gets set, ICE_LINK_SPEED_UNKNOWN will be returned
 | 
				
			||||||
 | 
					 * If more than one bit gets set, ICE_LINK_SPEED_UNKNOWN will be returned
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static u16
 | 
				
			||||||
 | 
					ice_get_link_speed_based_on_phy_type(u64 phy_type_low)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u16 speed_phy_type_low = ICE_AQ_LINK_SPEED_UNKNOWN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (phy_type_low) {
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_100BASE_TX:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_100M_SGMII:
 | 
				
			||||||
 | 
							speed_phy_type_low = ICE_AQ_LINK_SPEED_100MB;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_1000BASE_T:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_1000BASE_SX:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_1000BASE_LX:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_1000BASE_KX:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_1G_SGMII:
 | 
				
			||||||
 | 
							speed_phy_type_low = ICE_AQ_LINK_SPEED_1000MB;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_2500BASE_T:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_2500BASE_X:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_2500BASE_KX:
 | 
				
			||||||
 | 
							speed_phy_type_low = ICE_AQ_LINK_SPEED_2500MB;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_5GBASE_T:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_5GBASE_KR:
 | 
				
			||||||
 | 
							speed_phy_type_low = ICE_AQ_LINK_SPEED_5GB;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_10GBASE_T:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_10G_SFI_DA:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_10GBASE_SR:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_10GBASE_LR:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_10GBASE_KR_CR1:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_10G_SFI_AOC_ACC:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_10G_SFI_C2C:
 | 
				
			||||||
 | 
							speed_phy_type_low = ICE_AQ_LINK_SPEED_10GB;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_25GBASE_T:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_25GBASE_CR:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_25GBASE_CR_S:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_25GBASE_CR1:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_25GBASE_SR:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_25GBASE_LR:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_25GBASE_KR:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_25GBASE_KR_S:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_25GBASE_KR1:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_25G_AUI_AOC_ACC:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_25G_AUI_C2C:
 | 
				
			||||||
 | 
							speed_phy_type_low = ICE_AQ_LINK_SPEED_25GB;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_40GBASE_CR4:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_40GBASE_SR4:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_40GBASE_LR4:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_40GBASE_KR4:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_40G_XLAUI_AOC_ACC:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_40G_XLAUI:
 | 
				
			||||||
 | 
							speed_phy_type_low = ICE_AQ_LINK_SPEED_40GB;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							speed_phy_type_low = ICE_AQ_LINK_SPEED_UNKNOWN;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return speed_phy_type_low;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * ice_update_phy_type
 | 
				
			||||||
 | 
					 * @phy_type_low: pointer to the lower part of phy_type
 | 
				
			||||||
 | 
					 * @link_speeds_bitmap: targeted link speeds bitmap
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Note: For the link_speeds_bitmap structure, you can check it at
 | 
				
			||||||
 | 
					 * [ice_aqc_get_link_status->link_speed]. Caller can pass in
 | 
				
			||||||
 | 
					 * link_speeds_bitmap include multiple speeds.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The value of phy_type_low will present a certain link speed. This helper
 | 
				
			||||||
 | 
					 * function will turn on bits in the phy_type_low based on the value of
 | 
				
			||||||
 | 
					 * link_speeds_bitmap input parameter.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void ice_update_phy_type(u64 *phy_type_low, u16 link_speeds_bitmap)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u16 speed = ICE_AQ_LINK_SPEED_UNKNOWN;
 | 
				
			||||||
 | 
						u64 pt_low;
 | 
				
			||||||
 | 
						int index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* We first check with low part of phy_type */
 | 
				
			||||||
 | 
						for (index = 0; index <= ICE_PHY_TYPE_LOW_MAX_INDEX; index++) {
 | 
				
			||||||
 | 
							pt_low = BIT_ULL(index);
 | 
				
			||||||
 | 
							speed = ice_get_link_speed_based_on_phy_type(pt_low);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (link_speeds_bitmap & speed)
 | 
				
			||||||
 | 
								*phy_type_low |= BIT_ULL(index);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * ice_aq_set_phy_cfg
 | 
					 * ice_aq_set_phy_cfg
 | 
				
			||||||
 * @hw: pointer to the hw struct
 | 
					 * @hw: pointer to the hw struct
 | 
				
			||||||
| 
						 | 
					@ -1420,19 +1524,18 @@ void ice_clear_pxe_mode(struct ice_hw *hw)
 | 
				
			||||||
 * mode as the PF may not have the privilege to set some of the PHY Config
 | 
					 * mode as the PF may not have the privilege to set some of the PHY Config
 | 
				
			||||||
 * parameters. This status will be indicated by the command response (0x0601).
 | 
					 * parameters. This status will be indicated by the command response (0x0601).
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static 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, u8 lport,
 | 
				
			||||||
		   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_aqc_set_phy_cfg *cmd;
 | 
					 | 
				
			||||||
	struct ice_aq_desc desc;
 | 
						struct ice_aq_desc desc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!cfg)
 | 
						if (!cfg)
 | 
				
			||||||
		return ICE_ERR_PARAM;
 | 
							return ICE_ERR_PARAM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cmd = &desc.params.set_phy;
 | 
					 | 
				
			||||||
	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);
 | 
				
			||||||
	cmd->lport_num = lport;
 | 
						desc.params.set_phy.lport_num = lport;
 | 
				
			||||||
 | 
						desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ice_aq_send_cmd(hw, &desc, cfg, sizeof(*cfg), cd);
 | 
						return ice_aq_send_cmd(hw, &desc, cfg, sizeof(*cfg), cd);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1481,12 +1584,12 @@ ice_update_link_info(struct ice_port_info *pi)
 | 
				
			||||||
 * ice_set_fc
 | 
					 * ice_set_fc
 | 
				
			||||||
 * @pi: port information structure
 | 
					 * @pi: port information structure
 | 
				
			||||||
 * @aq_failures: pointer to status code, specific to ice_set_fc routine
 | 
					 * @aq_failures: pointer to status code, specific to ice_set_fc routine
 | 
				
			||||||
 * @atomic_restart: enable automatic link update
 | 
					 * @ena_auto_link_update: enable automatic link update
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Set the requested flow control mode.
 | 
					 * Set the requested flow control mode.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
enum ice_status
 | 
					enum ice_status
 | 
				
			||||||
ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool atomic_restart)
 | 
					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;
 | 
				
			||||||
| 
						 | 
					@ -1536,8 +1639,8 @@ ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool atomic_restart)
 | 
				
			||||||
		int retry_count, retry_max = 10;
 | 
							int retry_count, retry_max = 10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Auto restart link so settings take effect */
 | 
							/* Auto restart link so settings take effect */
 | 
				
			||||||
		if (atomic_restart)
 | 
							if (ena_auto_link_update)
 | 
				
			||||||
			cfg.caps |= ICE_AQ_PHY_ENA_ATOMIC_LINK;
 | 
								cfg.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
 | 
				
			||||||
		/* Copy over all the old settings */
 | 
							/* Copy over all the old settings */
 | 
				
			||||||
		cfg.phy_type_low = pcaps->phy_type_low;
 | 
							cfg.phy_type_low = pcaps->phy_type_low;
 | 
				
			||||||
		cfg.low_power_ctrl = pcaps->low_power_ctrl;
 | 
							cfg.low_power_ctrl = pcaps->low_power_ctrl;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -58,12 +58,24 @@ enum ice_status
 | 
				
			||||||
ice_aq_send_cmd(struct ice_hw *hw, struct ice_aq_desc *desc,
 | 
					ice_aq_send_cmd(struct ice_hw *hw, struct ice_aq_desc *desc,
 | 
				
			||||||
		void *buf, u16 buf_size, struct ice_sq_cd *cd);
 | 
							void *buf, u16 buf_size, struct ice_sq_cd *cd);
 | 
				
			||||||
enum ice_status ice_aq_get_fw_ver(struct ice_hw *hw, struct ice_sq_cd *cd);
 | 
					enum ice_status ice_aq_get_fw_ver(struct ice_hw *hw, struct ice_sq_cd *cd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum ice_status
 | 
				
			||||||
 | 
					ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode,
 | 
				
			||||||
 | 
							    struct ice_aqc_get_phy_caps_data *caps,
 | 
				
			||||||
 | 
							    struct ice_sq_cd *cd);
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					ice_update_phy_type(u64 *phy_type_low, u16 link_speeds_bitmap);
 | 
				
			||||||
enum ice_status
 | 
					enum ice_status
 | 
				
			||||||
ice_aq_manage_mac_write(struct ice_hw *hw, u8 *mac_addr, u8 flags,
 | 
					ice_aq_manage_mac_write(struct ice_hw *hw, 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_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool atomic_restart);
 | 
					ice_aq_set_phy_cfg(struct ice_hw *hw, u8 lport,
 | 
				
			||||||
 | 
							   struct ice_aqc_set_phy_cfg_data *cfg, struct ice_sq_cd *cd);
 | 
				
			||||||
 | 
					enum ice_status
 | 
				
			||||||
 | 
					ice_set_fc(struct ice_port_info *pi, u8 *aq_failures,
 | 
				
			||||||
 | 
						   bool ena_auto_link_update);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum ice_status
 | 
					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);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -332,58 +332,473 @@ ice_get_ethtool_stats(struct net_device *netdev,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					/**
 | 
				
			||||||
ice_get_link_ksettings(struct net_device *netdev,
 | 
					 * ice_phy_type_to_ethtool - convert the phy_types to ethtool link modes
 | 
				
			||||||
 | 
					 * @netdev: network interface device structure
 | 
				
			||||||
 | 
					 * @ks: ethtool link ksettings struct to fill out
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void ice_phy_type_to_ethtool(struct net_device *netdev,
 | 
				
			||||||
				    struct ethtool_link_ksettings *ks)
 | 
									    struct ethtool_link_ksettings *ks)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ice_netdev_priv *np = netdev_priv(netdev);
 | 
						struct ice_netdev_priv *np = netdev_priv(netdev);
 | 
				
			||||||
	struct ice_link_status *hw_link_info;
 | 
						struct ice_link_status *hw_link_info;
 | 
				
			||||||
	struct ice_vsi *vsi = np->vsi;
 | 
						struct ice_vsi *vsi = np->vsi;
 | 
				
			||||||
	bool link_up;
 | 
						u64 phy_types_low;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hw_link_info = &vsi->port_info->phy.link_info;
 | 
						hw_link_info = &vsi->port_info->phy.link_info;
 | 
				
			||||||
	link_up = hw_link_info->link_info & ICE_AQ_LINK_UP;
 | 
						phy_types_low = vsi->port_info->phy.phy_type_low;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ethtool_link_ksettings_zero_link_mode(ks, supported);
 | 
				
			||||||
 | 
						ethtool_link_ksettings_zero_link_mode(ks, advertising);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (phy_types_low & ICE_PHY_TYPE_LOW_100BASE_TX ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_100M_SGMII) {
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     100baseT_Full);
 | 
				
			||||||
 | 
							if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_100MB)
 | 
				
			||||||
 | 
								ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
												     100baseT_Full);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_T ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_1G_SGMII) {
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     1000baseT_Full);
 | 
				
			||||||
 | 
							if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_1000MB)
 | 
				
			||||||
 | 
								ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
												     1000baseT_Full);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_KX) {
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     1000baseKX_Full);
 | 
				
			||||||
 | 
							if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_1000MB)
 | 
				
			||||||
 | 
								ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
												     1000baseKX_Full);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_SX ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_LX) {
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     1000baseX_Full);
 | 
				
			||||||
 | 
							if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_1000MB)
 | 
				
			||||||
 | 
								ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
												     1000baseX_Full);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (phy_types_low & ICE_PHY_TYPE_LOW_2500BASE_T) {
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     2500baseT_Full);
 | 
				
			||||||
 | 
							if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_2500MB)
 | 
				
			||||||
 | 
								ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
												     2500baseT_Full);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (phy_types_low & ICE_PHY_TYPE_LOW_2500BASE_X ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_2500BASE_KX) {
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     2500baseX_Full);
 | 
				
			||||||
 | 
							if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_2500MB)
 | 
				
			||||||
 | 
								ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
												     2500baseX_Full);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (phy_types_low & ICE_PHY_TYPE_LOW_5GBASE_T ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_5GBASE_KR) {
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     5000baseT_Full);
 | 
				
			||||||
 | 
							if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_5GB)
 | 
				
			||||||
 | 
								ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
												     5000baseT_Full);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_T ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_10G_SFI_DA ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_10G_SFI_AOC_ACC ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_10G_SFI_C2C) {
 | 
				
			||||||
		ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
						     10000baseT_Full);
 | 
											     10000baseT_Full);
 | 
				
			||||||
 | 
							if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_10GB)
 | 
				
			||||||
			ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
								ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
							     10000baseT_Full);
 | 
												     10000baseT_Full);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_KR_CR1) {
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     10000baseKR_Full);
 | 
				
			||||||
 | 
							if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_10GB)
 | 
				
			||||||
 | 
								ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
												     10000baseKR_Full);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_SR) {
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     10000baseSR_Full);
 | 
				
			||||||
 | 
							if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_10GB)
 | 
				
			||||||
 | 
								ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
												     10000baseSR_Full);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_LR) {
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     10000baseLR_Full);
 | 
				
			||||||
 | 
							if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_10GB)
 | 
				
			||||||
 | 
								ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
												     10000baseLR_Full);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_T ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR_S ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR1 ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_25G_AUI_AOC_ACC ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_25G_AUI_C2C) {
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     25000baseCR_Full);
 | 
				
			||||||
 | 
							if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_25GB)
 | 
				
			||||||
 | 
								ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
												     25000baseCR_Full);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_SR ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_LR) {
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     25000baseSR_Full);
 | 
				
			||||||
 | 
							if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_25GB)
 | 
				
			||||||
 | 
								ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
												     25000baseSR_Full);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR_S ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR1) {
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     25000baseKR_Full);
 | 
				
			||||||
 | 
							if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_25GB)
 | 
				
			||||||
 | 
								ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
												     25000baseKR_Full);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_KR4) {
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     40000baseKR4_Full);
 | 
				
			||||||
 | 
							if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_40GB)
 | 
				
			||||||
 | 
								ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
												     40000baseKR4_Full);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_CR4 ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_40G_XLAUI_AOC_ACC ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_40G_XLAUI) {
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     40000baseCR4_Full);
 | 
				
			||||||
 | 
							if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_40GB)
 | 
				
			||||||
 | 
								ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
												     40000baseCR4_Full);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_SR4) {
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     40000baseSR4_Full);
 | 
				
			||||||
 | 
							if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_40GB)
 | 
				
			||||||
 | 
								ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
												     40000baseSR4_Full);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_LR4) {
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     40000baseLR4_Full);
 | 
				
			||||||
 | 
							if (hw_link_info->req_speeds & ICE_AQ_LINK_SPEED_40GB)
 | 
				
			||||||
 | 
								ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
												     40000baseLR4_Full);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* set speed and duplex */
 | 
						/* Autoneg PHY types */
 | 
				
			||||||
	if (link_up) {
 | 
						if (phy_types_low & ICE_PHY_TYPE_LOW_100BASE_TX ||
 | 
				
			||||||
		switch (hw_link_info->link_speed) {
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_T ||
 | 
				
			||||||
		case ICE_AQ_LINK_SPEED_100MB:
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_KX ||
 | 
				
			||||||
			ks->base.speed = SPEED_100;
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_2500BASE_T ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_2500BASE_KX ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_5GBASE_T ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_5GBASE_KR ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_T ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_KR_CR1 ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_T ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR_S ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR1 ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR_S ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR1 ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_CR4 ||
 | 
				
			||||||
 | 
						    phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_KR4) {
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     Autoneg);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											     Autoneg);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TEST_SET_BITS_TIMEOUT	50
 | 
				
			||||||
 | 
					#define TEST_SET_BITS_SLEEP_MAX	2000
 | 
				
			||||||
 | 
					#define TEST_SET_BITS_SLEEP_MIN	1000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * ice_get_settings_link_up - Get Link settings for when link is up
 | 
				
			||||||
 | 
					 * @ks: ethtool ksettings to fill in
 | 
				
			||||||
 | 
					 * @netdev: network interface device structure
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void ice_get_settings_link_up(struct ethtool_link_ksettings *ks,
 | 
				
			||||||
 | 
									     struct net_device *netdev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ice_netdev_priv *np = netdev_priv(netdev);
 | 
				
			||||||
 | 
						struct ethtool_link_ksettings cap_ksettings;
 | 
				
			||||||
 | 
						struct ice_link_status *link_info;
 | 
				
			||||||
 | 
						struct ice_vsi *vsi = np->vsi;
 | 
				
			||||||
 | 
						bool unrecog_phy_low = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						link_info = &vsi->port_info->phy.link_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Initialize supported and advertised settings based on phy settings */
 | 
				
			||||||
 | 
						switch (link_info->phy_type_low) {
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_100BASE_TX:
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     100baseT_Full);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											     100baseT_Full);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
		case ICE_AQ_LINK_SPEED_2500MB:
 | 
						case ICE_PHY_TYPE_LOW_100M_SGMII:
 | 
				
			||||||
			ks->base.speed = SPEED_2500;
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     100baseT_Full);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
		case ICE_AQ_LINK_SPEED_5GB:
 | 
						case ICE_PHY_TYPE_LOW_1000BASE_T:
 | 
				
			||||||
			ks->base.speed = SPEED_5000;
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     1000baseT_Full);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											     1000baseT_Full);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
		case ICE_AQ_LINK_SPEED_10GB:
 | 
						case ICE_PHY_TYPE_LOW_1G_SGMII:
 | 
				
			||||||
			ks->base.speed = SPEED_10000;
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     1000baseT_Full);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_1000BASE_SX:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_1000BASE_LX:
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     1000baseX_Full);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_1000BASE_KX:
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     1000baseKX_Full);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											     1000baseKX_Full);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_2500BASE_T:
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     2500baseT_Full);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											     2500baseT_Full);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_2500BASE_X:
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     2500baseX_Full);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_2500BASE_KX:
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     2500baseX_Full);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											     2500baseX_Full);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_5GBASE_T:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_5GBASE_KR:
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     5000baseT_Full);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											     5000baseT_Full);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_10GBASE_T:
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     10000baseT_Full);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											     10000baseT_Full);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_10G_SFI_DA:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_10G_SFI_AOC_ACC:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_10G_SFI_C2C:
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     10000baseT_Full);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_10GBASE_SR:
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     10000baseSR_Full);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_10GBASE_LR:
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     10000baseLR_Full);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_10GBASE_KR_CR1:
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     10000baseKR_Full);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											     10000baseKR_Full);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_25GBASE_T:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_25GBASE_CR:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_25GBASE_CR_S:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_25GBASE_CR1:
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     25000baseCR_Full);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											     25000baseCR_Full);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_25G_AUI_AOC_ACC:
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     25000baseCR_Full);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_25GBASE_SR:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_25GBASE_LR:
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     25000baseSR_Full);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_25GBASE_KR:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_25GBASE_KR1:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_25GBASE_KR_S:
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     25000baseKR_Full);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											     25000baseKR_Full);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_40GBASE_CR4:
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     40000baseCR4_Full);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											     40000baseCR4_Full);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_40G_XLAUI_AOC_ACC:
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_40G_XLAUI:
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     40000baseCR4_Full);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_40GBASE_SR4:
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     40000baseSR4_Full);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_40GBASE_LR4:
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     40000baseLR4_Full);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_PHY_TYPE_LOW_40GBASE_KR4:
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, supported,
 | 
				
			||||||
 | 
											     40000baseKR4_Full);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
 | 
				
			||||||
 | 
							ethtool_link_ksettings_add_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											     40000baseKR4_Full);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							unrecog_phy_low = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (unrecog_phy_low) {
 | 
				
			||||||
 | 
							/* if we got here and link is up something bad is afoot */
 | 
				
			||||||
 | 
							netdev_info(netdev, "WARNING: Unrecognized PHY_Low (0x%llx).\n",
 | 
				
			||||||
 | 
								    (u64)link_info->phy_type_low);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Now that we've worked out everything that could be supported by the
 | 
				
			||||||
 | 
						 * current PHY type, get what is supported by the NVM and intersect
 | 
				
			||||||
 | 
						 * them to get what is truly supported
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						memset(&cap_ksettings, 0, sizeof(struct ethtool_link_ksettings));
 | 
				
			||||||
 | 
						ice_phy_type_to_ethtool(netdev, &cap_ksettings);
 | 
				
			||||||
 | 
						ethtool_intersect_link_masks(ks, &cap_ksettings);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (link_info->link_speed) {
 | 
				
			||||||
 | 
						case ICE_AQ_LINK_SPEED_40GB:
 | 
				
			||||||
 | 
							ks->base.speed = SPEED_40000;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case ICE_AQ_LINK_SPEED_25GB:
 | 
						case ICE_AQ_LINK_SPEED_25GB:
 | 
				
			||||||
		ks->base.speed = SPEED_25000;
 | 
							ks->base.speed = SPEED_25000;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
		case ICE_AQ_LINK_SPEED_40GB:
 | 
						case ICE_AQ_LINK_SPEED_20GB:
 | 
				
			||||||
			ks->base.speed = SPEED_40000;
 | 
							ks->base.speed = SPEED_20000;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_AQ_LINK_SPEED_10GB:
 | 
				
			||||||
 | 
							ks->base.speed = SPEED_10000;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_AQ_LINK_SPEED_5GB:
 | 
				
			||||||
 | 
							ks->base.speed = SPEED_5000;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_AQ_LINK_SPEED_2500MB:
 | 
				
			||||||
 | 
							ks->base.speed = SPEED_2500;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_AQ_LINK_SPEED_1000MB:
 | 
				
			||||||
 | 
							ks->base.speed = SPEED_1000;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case ICE_AQ_LINK_SPEED_100MB:
 | 
				
			||||||
 | 
							ks->base.speed = SPEED_100;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
			ks->base.speed = SPEED_UNKNOWN;
 | 
							netdev_info(netdev,
 | 
				
			||||||
 | 
								    "WARNING: Unrecognized link_speed (0x%x).\n",
 | 
				
			||||||
 | 
								    link_info->link_speed);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	ks->base.duplex = DUPLEX_FULL;
 | 
						ks->base.duplex = DUPLEX_FULL;
 | 
				
			||||||
	} else {
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * ice_get_settings_link_down - Get the Link settings when link is down
 | 
				
			||||||
 | 
					 * @ks: ethtool ksettings to fill in
 | 
				
			||||||
 | 
					 * @netdev: network interface device structure
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Reports link settings that can be determined when link is down
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					ice_get_settings_link_down(struct ethtool_link_ksettings *ks,
 | 
				
			||||||
 | 
								   struct net_device __always_unused *netdev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* link is down and the driver needs to fall back on
 | 
				
			||||||
 | 
						 * supported phy types to figure out what info to display
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						ice_phy_type_to_ethtool(netdev, ks);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* With no link, speed and duplex are unknown */
 | 
				
			||||||
	ks->base.speed = SPEED_UNKNOWN;
 | 
						ks->base.speed = SPEED_UNKNOWN;
 | 
				
			||||||
	ks->base.duplex = DUPLEX_UNKNOWN;
 | 
						ks->base.duplex = DUPLEX_UNKNOWN;
 | 
				
			||||||
	}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * ice_get_link_ksettings - Get Link Speed and Duplex settings
 | 
				
			||||||
 | 
					 * @netdev: network interface device structure
 | 
				
			||||||
 | 
					 * @ks: ethtool ksettings
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Reports speed/duplex settings based on media_type
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int ice_get_link_ksettings(struct net_device *netdev,
 | 
				
			||||||
 | 
									  struct ethtool_link_ksettings *ks)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ice_netdev_priv *np = netdev_priv(netdev);
 | 
				
			||||||
 | 
						struct ice_link_status *hw_link_info;
 | 
				
			||||||
 | 
						struct ice_vsi *vsi = np->vsi;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ethtool_link_ksettings_zero_link_mode(ks, supported);
 | 
				
			||||||
 | 
						ethtool_link_ksettings_zero_link_mode(ks, advertising);
 | 
				
			||||||
 | 
						hw_link_info = &vsi->port_info->phy.link_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* set speed and duplex */
 | 
				
			||||||
 | 
						if (hw_link_info->link_info & ICE_AQ_LINK_UP)
 | 
				
			||||||
 | 
							ice_get_settings_link_up(ks, netdev);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							ice_get_settings_link_down(ks, netdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* set autoneg settings */
 | 
						/* set autoneg settings */
 | 
				
			||||||
	ks->base.autoneg = ((hw_link_info->an_info & ICE_AQ_AN_COMPLETED) ?
 | 
						ks->base.autoneg = (hw_link_info->an_info & ICE_AQ_AN_COMPLETED) ?
 | 
				
			||||||
			    AUTONEG_ENABLE : AUTONEG_DISABLE);
 | 
							AUTONEG_ENABLE : AUTONEG_DISABLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* set media type settings */
 | 
						/* set media type settings */
 | 
				
			||||||
	switch (vsi->port_info->phy.media_type) {
 | 
						switch (vsi->port_info->phy.media_type) {
 | 
				
			||||||
| 
						 | 
					@ -441,6 +856,311 @@ ice_get_link_ksettings(struct net_device *netdev,
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * ice_ksettings_find_adv_link_speed - Find advertising link speed
 | 
				
			||||||
 | 
					 * @ks: ethtool ksettings
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static u16
 | 
				
			||||||
 | 
					ice_ksettings_find_adv_link_speed(const struct ethtool_link_ksettings *ks)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u16 adv_link_speed = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ethtool_link_ksettings_test_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											  100baseT_Full))
 | 
				
			||||||
 | 
							adv_link_speed |= ICE_AQ_LINK_SPEED_100MB;
 | 
				
			||||||
 | 
						if (ethtool_link_ksettings_test_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											  1000baseX_Full))
 | 
				
			||||||
 | 
							adv_link_speed |= ICE_AQ_LINK_SPEED_1000MB;
 | 
				
			||||||
 | 
						if (ethtool_link_ksettings_test_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											  1000baseT_Full) ||
 | 
				
			||||||
 | 
						    ethtool_link_ksettings_test_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											  1000baseKX_Full))
 | 
				
			||||||
 | 
							adv_link_speed |= ICE_AQ_LINK_SPEED_1000MB;
 | 
				
			||||||
 | 
						if (ethtool_link_ksettings_test_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											  2500baseT_Full))
 | 
				
			||||||
 | 
							adv_link_speed |= ICE_AQ_LINK_SPEED_2500MB;
 | 
				
			||||||
 | 
						if (ethtool_link_ksettings_test_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											  2500baseX_Full))
 | 
				
			||||||
 | 
							adv_link_speed |= ICE_AQ_LINK_SPEED_2500MB;
 | 
				
			||||||
 | 
						if (ethtool_link_ksettings_test_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											  5000baseT_Full))
 | 
				
			||||||
 | 
							adv_link_speed |= ICE_AQ_LINK_SPEED_5GB;
 | 
				
			||||||
 | 
						if (ethtool_link_ksettings_test_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											  10000baseT_Full) ||
 | 
				
			||||||
 | 
						    ethtool_link_ksettings_test_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											  10000baseKR_Full))
 | 
				
			||||||
 | 
							adv_link_speed |= ICE_AQ_LINK_SPEED_10GB;
 | 
				
			||||||
 | 
						if (ethtool_link_ksettings_test_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											  10000baseSR_Full) ||
 | 
				
			||||||
 | 
						    ethtool_link_ksettings_test_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											  10000baseLR_Full))
 | 
				
			||||||
 | 
							adv_link_speed |= ICE_AQ_LINK_SPEED_10GB;
 | 
				
			||||||
 | 
						if (ethtool_link_ksettings_test_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											  25000baseCR_Full) ||
 | 
				
			||||||
 | 
						    ethtool_link_ksettings_test_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											  25000baseSR_Full) ||
 | 
				
			||||||
 | 
						    ethtool_link_ksettings_test_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											  25000baseKR_Full))
 | 
				
			||||||
 | 
							adv_link_speed |= ICE_AQ_LINK_SPEED_25GB;
 | 
				
			||||||
 | 
						if (ethtool_link_ksettings_test_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											  40000baseCR4_Full) ||
 | 
				
			||||||
 | 
						    ethtool_link_ksettings_test_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											  40000baseSR4_Full) ||
 | 
				
			||||||
 | 
						    ethtool_link_ksettings_test_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											  40000baseLR4_Full) ||
 | 
				
			||||||
 | 
						    ethtool_link_ksettings_test_link_mode(ks, advertising,
 | 
				
			||||||
 | 
											  40000baseKR4_Full))
 | 
				
			||||||
 | 
							adv_link_speed |= ICE_AQ_LINK_SPEED_40GB;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return adv_link_speed;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * ice_setup_autoneg
 | 
				
			||||||
 | 
					 * @p: port info
 | 
				
			||||||
 | 
					 * @ks: ethtool_link_ksettings
 | 
				
			||||||
 | 
					 * @config: configuration that will be sent down to FW
 | 
				
			||||||
 | 
					 * @autoneg_enabled: autonegotiation is enabled or not
 | 
				
			||||||
 | 
					 * @autoneg_changed: will there a change in autonegotiation
 | 
				
			||||||
 | 
					 * @netdev: network interface device structure
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Setup PHY autonegotiation feature
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					ice_setup_autoneg(struct ice_port_info *p, struct ethtool_link_ksettings *ks,
 | 
				
			||||||
 | 
							  struct ice_aqc_set_phy_cfg_data *config,
 | 
				
			||||||
 | 
							  u8 autoneg_enabled, u8 *autoneg_changed,
 | 
				
			||||||
 | 
							  struct net_device *netdev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int err = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*autoneg_changed = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Check autoneg */
 | 
				
			||||||
 | 
						if (autoneg_enabled == AUTONEG_ENABLE) {
 | 
				
			||||||
 | 
							/* If autoneg was not already enabled */
 | 
				
			||||||
 | 
							if (!(p->phy.link_info.an_info & ICE_AQ_AN_COMPLETED)) {
 | 
				
			||||||
 | 
								/* If autoneg is not supported, return error */
 | 
				
			||||||
 | 
								if (!ethtool_link_ksettings_test_link_mode(ks,
 | 
				
			||||||
 | 
													   supported,
 | 
				
			||||||
 | 
													   Autoneg)) {
 | 
				
			||||||
 | 
									netdev_info(netdev, "Autoneg not supported on this phy.\n");
 | 
				
			||||||
 | 
									err = -EINVAL;
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									/* Autoneg is allowed to change */
 | 
				
			||||||
 | 
									config->caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
 | 
				
			||||||
 | 
									*autoneg_changed = 1;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							/* If autoneg is currently enabled */
 | 
				
			||||||
 | 
							if (p->phy.link_info.an_info & ICE_AQ_AN_COMPLETED) {
 | 
				
			||||||
 | 
								/* If autoneg is supported 10GBASE_T is the only phy
 | 
				
			||||||
 | 
								 * that can disable it, so otherwise return error
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								if (ethtool_link_ksettings_test_link_mode(ks,
 | 
				
			||||||
 | 
													  supported,
 | 
				
			||||||
 | 
													  Autoneg)) {
 | 
				
			||||||
 | 
									netdev_info(netdev, "Autoneg cannot be disabled on this phy\n");
 | 
				
			||||||
 | 
									err = -EINVAL;
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									/* Autoneg is allowed to change */
 | 
				
			||||||
 | 
									config->caps &= ~ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
 | 
				
			||||||
 | 
									*autoneg_changed = 1;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * ice_set_link_ksettings - Set Speed and Duplex
 | 
				
			||||||
 | 
					 * @netdev: network interface device structure
 | 
				
			||||||
 | 
					 * @ks: ethtool ksettings
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Set speed/duplex per media_types advertised/forced
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int ice_set_link_ksettings(struct net_device *netdev,
 | 
				
			||||||
 | 
									  const struct ethtool_link_ksettings *ks)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u8 autoneg, timeout = TEST_SET_BITS_TIMEOUT, lport = 0;
 | 
				
			||||||
 | 
						struct ice_netdev_priv *np = netdev_priv(netdev);
 | 
				
			||||||
 | 
						struct ethtool_link_ksettings safe_ks, copy_ks;
 | 
				
			||||||
 | 
						struct ice_aqc_get_phy_caps_data *abilities;
 | 
				
			||||||
 | 
						u16 adv_link_speed, curr_link_speed, idx;
 | 
				
			||||||
 | 
						struct ice_aqc_set_phy_cfg_data config;
 | 
				
			||||||
 | 
						struct ice_pf *pf = np->vsi->back;
 | 
				
			||||||
 | 
						struct ice_port_info *p;
 | 
				
			||||||
 | 
						u8 autoneg_changed = 0;
 | 
				
			||||||
 | 
						enum ice_status status;
 | 
				
			||||||
 | 
						u64 phy_type_low;
 | 
				
			||||||
 | 
						int err = 0;
 | 
				
			||||||
 | 
						bool linkup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						p = np->vsi->port_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!p)
 | 
				
			||||||
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Check if this is lan vsi */
 | 
				
			||||||
 | 
						for (idx = 0 ; idx <  pf->num_alloc_vsi ; idx++) {
 | 
				
			||||||
 | 
							if (pf->vsi[idx]->type == ICE_VSI_PF) {
 | 
				
			||||||
 | 
								if (np->vsi != pf->vsi[idx])
 | 
				
			||||||
 | 
									return -EOPNOTSUPP;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (p->phy.media_type != ICE_MEDIA_BASET &&
 | 
				
			||||||
 | 
						    p->phy.media_type != ICE_MEDIA_FIBER &&
 | 
				
			||||||
 | 
						    p->phy.media_type != ICE_MEDIA_BACKPLANE &&
 | 
				
			||||||
 | 
						    p->phy.media_type != ICE_MEDIA_DA &&
 | 
				
			||||||
 | 
						    p->phy.link_info.link_info & ICE_AQ_LINK_UP)
 | 
				
			||||||
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* copy the ksettings to copy_ks to avoid modifying the original */
 | 
				
			||||||
 | 
						memcpy(©_ks, ks, sizeof(struct ethtool_link_ksettings));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* save autoneg out of ksettings */
 | 
				
			||||||
 | 
						autoneg = copy_ks.base.autoneg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&safe_ks, 0, sizeof(safe_ks));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Get link modes supported by hardware.*/
 | 
				
			||||||
 | 
						ice_phy_type_to_ethtool(netdev, &safe_ks);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* and check against modes requested by user.
 | 
				
			||||||
 | 
						 * Return an error if unsupported mode was set.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (!bitmap_subset(copy_ks.link_modes.advertising,
 | 
				
			||||||
 | 
								   safe_ks.link_modes.supported,
 | 
				
			||||||
 | 
								   __ETHTOOL_LINK_MODE_MASK_NBITS))
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* get our own copy of the bits to check against */
 | 
				
			||||||
 | 
						memset(&safe_ks, 0, sizeof(struct ethtool_link_ksettings));
 | 
				
			||||||
 | 
						safe_ks.base.cmd = copy_ks.base.cmd;
 | 
				
			||||||
 | 
						safe_ks.base.link_mode_masks_nwords =
 | 
				
			||||||
 | 
							copy_ks.base.link_mode_masks_nwords;
 | 
				
			||||||
 | 
						ice_get_link_ksettings(netdev, &safe_ks);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* set autoneg back to what it currently is */
 | 
				
			||||||
 | 
						copy_ks.base.autoneg = safe_ks.base.autoneg;
 | 
				
			||||||
 | 
						/* we don't compare the speed */
 | 
				
			||||||
 | 
						copy_ks.base.speed = safe_ks.base.speed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* 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.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (memcmp(©_ks.base, &safe_ks.base,
 | 
				
			||||||
 | 
							   sizeof(struct ethtool_link_settings)))
 | 
				
			||||||
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (test_and_set_bit(__ICE_CFG_BUSY, pf->state)) {
 | 
				
			||||||
 | 
							timeout--;
 | 
				
			||||||
 | 
							if (!timeout)
 | 
				
			||||||
 | 
								return -EBUSY;
 | 
				
			||||||
 | 
							usleep_range(TEST_SET_BITS_SLEEP_MIN, TEST_SET_BITS_SLEEP_MAX);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						abilities = devm_kzalloc(&pf->pdev->dev, sizeof(*abilities),
 | 
				
			||||||
 | 
									 GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!abilities)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Get the current phy 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 */
 | 
				
			||||||
 | 
						memset(&config, 0, sizeof(struct ice_aqc_set_phy_cfg_data));
 | 
				
			||||||
 | 
						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 */
 | 
				
			||||||
 | 
						err = ice_setup_autoneg(p, &safe_ks, &config, autoneg, &autoneg_changed,
 | 
				
			||||||
 | 
									netdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (err)
 | 
				
			||||||
 | 
							goto done;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Call to get the current link speed */
 | 
				
			||||||
 | 
						p->phy.get_link_info = true;
 | 
				
			||||||
 | 
						status = ice_get_link_status(p, &linkup);
 | 
				
			||||||
 | 
						if (status) {
 | 
				
			||||||
 | 
							err = -EAGAIN;
 | 
				
			||||||
 | 
							goto done;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						curr_link_speed = p->phy.link_info.link_speed;
 | 
				
			||||||
 | 
						adv_link_speed = ice_ksettings_find_adv_link_speed(ks);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* If speed didn't get set, set it to what it currently is.
 | 
				
			||||||
 | 
						 * This is needed because if advertise is 0 (as it is when autoneg
 | 
				
			||||||
 | 
						 * is disabled) then speed won't get set.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (!adv_link_speed)
 | 
				
			||||||
 | 
							adv_link_speed = curr_link_speed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Convert the advertise link speeds to their corresponded PHY_TYPE */
 | 
				
			||||||
 | 
						ice_update_phy_type(&phy_type_low, adv_link_speed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!autoneg_changed && adv_link_speed == curr_link_speed) {
 | 
				
			||||||
 | 
							netdev_info(netdev, "Nothing changed, exiting without setting anything.\n");
 | 
				
			||||||
 | 
							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 */
 | 
				
			||||||
 | 
						p->phy.link_info.req_speeds = adv_link_speed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* set link and auto negotiation so changes take effect */
 | 
				
			||||||
 | 
						config.caps |= ICE_AQ_PHY_ENA_LINK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (phy_type_low) {
 | 
				
			||||||
 | 
							config.phy_type_low = cpu_to_le64(phy_type_low) &
 | 
				
			||||||
 | 
								abilities->phy_type_low;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							err = -EAGAIN;
 | 
				
			||||||
 | 
							netdev_info(netdev, "Nothing changed. No PHY_TYPE is corresponded to advertised link speed.\n");
 | 
				
			||||||
 | 
							goto done;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* If link is up put link down */
 | 
				
			||||||
 | 
						if (p->phy.link_info.link_info & ICE_AQ_LINK_UP) {
 | 
				
			||||||
 | 
							/* Tell the OS link is going down, the link will go
 | 
				
			||||||
 | 
							 * back up when fw says it is ready asynchronously
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							ice_print_link_msg(np->vsi, false);
 | 
				
			||||||
 | 
							netif_carrier_off(netdev);
 | 
				
			||||||
 | 
							netif_tx_stop_all_queues(netdev);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* make the aq call */
 | 
				
			||||||
 | 
						status = ice_aq_set_phy_cfg(&pf->hw, lport, &config, NULL);
 | 
				
			||||||
 | 
						if (status) {
 | 
				
			||||||
 | 
							netdev_info(netdev, "Set phy config failed,\n");
 | 
				
			||||||
 | 
							err = -EAGAIN;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					done:
 | 
				
			||||||
 | 
						devm_kfree(&pf->pdev->dev, abilities);
 | 
				
			||||||
 | 
						clear_bit(__ICE_CFG_BUSY, pf->state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * ice_get_rxnfc - command to get RX flow classification rules
 | 
					 * ice_get_rxnfc - command to get RX flow classification rules
 | 
				
			||||||
 * @netdev: network interface device structure
 | 
					 * @netdev: network interface device structure
 | 
				
			||||||
| 
						 | 
					@ -933,6 +1653,7 @@ static int ice_set_rxfh(struct net_device *netdev, const u32 *indir,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct ethtool_ops ice_ethtool_ops = {
 | 
					static const struct ethtool_ops ice_ethtool_ops = {
 | 
				
			||||||
	.get_link_ksettings	= ice_get_link_ksettings,
 | 
						.get_link_ksettings	= ice_get_link_ksettings,
 | 
				
			||||||
 | 
						.set_link_ksettings	= ice_set_link_ksettings,
 | 
				
			||||||
	.get_drvinfo            = ice_get_drvinfo,
 | 
						.get_drvinfo            = ice_get_drvinfo,
 | 
				
			||||||
	.get_regs_len           = ice_get_regs_len,
 | 
						.get_regs_len           = ice_get_regs_len,
 | 
				
			||||||
	.get_regs               = ice_get_regs,
 | 
						.get_regs               = ice_get_regs,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue