Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 504159c3 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'net-hns3-enhance-capabilities-for-fibre-port'



Jian Shen says:

====================
net: hns3: enhance capabilities for fibre port

This patchset enhances more capabilities for fibre port,
include multipe media type identification, autoneg,
change port speed and FEC encoding.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e28441e2 7e6ec914
Loading
Loading
Loading
Loading
+30 −4
Original line number Diff line number Diff line
@@ -120,6 +120,25 @@ enum hnae3_media_type {
	HNAE3_MEDIA_TYPE_NONE,
};

/* must be consistent with definition in firmware */
enum hnae3_module_type {
	HNAE3_MODULE_TYPE_UNKNOWN	= 0x00,
	HNAE3_MODULE_TYPE_FIBRE_LR	= 0x01,
	HNAE3_MODULE_TYPE_FIBRE_SR	= 0x02,
	HNAE3_MODULE_TYPE_AOC		= 0x03,
	HNAE3_MODULE_TYPE_CR		= 0x04,
	HNAE3_MODULE_TYPE_KR		= 0x05,
	HNAE3_MODULE_TYPE_TP		= 0x06,

};

enum hnae3_fec_mode {
	HNAE3_FEC_AUTO = 0,
	HNAE3_FEC_BASER,
	HNAE3_FEC_RS,
	HNAE3_FEC_USER_DEF,
};

enum hnae3_reset_notify_type {
	HNAE3_UP_CLIENT,
	HNAE3_DOWN_CLIENT,
@@ -230,10 +249,10 @@ struct hnae3_ae_dev {
 *   non-ok
 * get_ksettings_an_result()
 *   Get negotiation status,speed and duplex
 * update_speed_duplex_h()
 *   Update hardware speed and duplex
 * get_media_type()
 *   Get media type of MAC
 * check_port_speed()
 *   Check target speed whether is supported
 * adjust_link()
 *   Adjust link status
 * set_loopback()
@@ -250,6 +269,8 @@ struct hnae3_ae_dev {
 *   set auto autonegotiation of pause frame use
 * get_autoneg()
 *   get auto autonegotiation of pause frame use
 * restart_autoneg()
 *   restart autonegotiation
 * get_coalesce_usecs()
 *   get usecs to delay a TX interrupt after a packet is sent
 * get_rx_max_coalesced_frames()
@@ -340,11 +361,15 @@ struct hnae3_ae_ops {
	void (*get_ksettings_an_result)(struct hnae3_handle *handle,
					u8 *auto_neg, u32 *speed, u8 *duplex);

	int (*update_speed_duplex_h)(struct hnae3_handle *handle);
	int (*cfg_mac_speed_dup_h)(struct hnae3_handle *handle, int speed,
				   u8 duplex);

	void (*get_media_type)(struct hnae3_handle *handle, u8 *media_type);
	void (*get_media_type)(struct hnae3_handle *handle, u8 *media_type,
			       u8 *module_type);
	int (*check_port_speed)(struct hnae3_handle *handle, u32 speed);
	void (*get_fec)(struct hnae3_handle *handle, u8 *fec_ability,
			u8 *fec_mode);
	int (*set_fec)(struct hnae3_handle *handle, u32 fec_mode);
	void (*adjust_link)(struct hnae3_handle *handle, int speed, int duplex);
	int (*set_loopback)(struct hnae3_handle *handle,
			    enum hnae3_loop loop_mode, bool en);
@@ -360,6 +385,7 @@ struct hnae3_ae_ops {

	int (*set_autoneg)(struct hnae3_handle *handle, bool enable);
	int (*get_autoneg)(struct hnae3_handle *handle);
	int (*restart_autoneg)(struct hnae3_handle *handle);

	void (*get_coalesce_usecs)(struct hnae3_handle *handle,
				   u32 *tx_usecs, u32 *rx_usecs);
+172 −8
Original line number Diff line number Diff line
@@ -604,6 +604,7 @@ static int hns3_get_link_ksettings(struct net_device *netdev,
{
	struct hnae3_handle *h = hns3_get_handle(netdev);
	const struct hnae3_ae_ops *ops;
	u8 module_type;
	u8 media_type;
	u8 link_stat;

@@ -612,7 +613,7 @@ static int hns3_get_link_ksettings(struct net_device *netdev,

	ops = h->ae_algo->ops;
	if (ops->get_media_type)
		ops->get_media_type(h, &media_type);
		ops->get_media_type(h, &media_type, &module_type);
	else
		return -EOPNOTSUPP;

@@ -622,7 +623,15 @@ static int hns3_get_link_ksettings(struct net_device *netdev,
		hns3_get_ksettings(h, cmd);
		break;
	case HNAE3_MEDIA_TYPE_FIBER:
		if (module_type == HNAE3_MODULE_TYPE_CR)
			cmd->base.port = PORT_DA;
		else
			cmd->base.port = PORT_FIBRE;

		hns3_get_ksettings(h, cmd);
		break;
	case HNAE3_MEDIA_TYPE_BACKPLANE:
		cmd->base.port = PORT_NONE;
		hns3_get_ksettings(h, cmd);
		break;
	case HNAE3_MEDIA_TYPE_COPPER:
@@ -650,10 +659,54 @@ static int hns3_get_link_ksettings(struct net_device *netdev,
	return 0;
}

static int hns3_check_ksettings_param(struct net_device *netdev,
				      const struct ethtool_link_ksettings *cmd)
{
	struct hnae3_handle *handle = hns3_get_handle(netdev);
	const struct hnae3_ae_ops *ops = handle->ae_algo->ops;
	u8 module_type = HNAE3_MODULE_TYPE_UNKNOWN;
	u8 media_type = HNAE3_MEDIA_TYPE_UNKNOWN;
	u8 autoneg;
	u32 speed;
	u8 duplex;
	int ret;

	if (ops->get_ksettings_an_result) {
		ops->get_ksettings_an_result(handle, &autoneg, &speed, &duplex);
		if (cmd->base.autoneg == autoneg && cmd->base.speed == speed &&
		    cmd->base.duplex == duplex)
			return 0;
	}

	if (ops->get_media_type)
		ops->get_media_type(handle, &media_type, &module_type);

	if (cmd->base.duplex != DUPLEX_FULL &&
	    media_type != HNAE3_MEDIA_TYPE_COPPER) {
		netdev_err(netdev,
			   "only copper port supports half duplex!");
		return -EINVAL;
	}

	if (ops->check_port_speed) {
		ret = ops->check_port_speed(handle, cmd->base.speed);
		if (ret) {
			netdev_err(netdev, "unsupported speed\n");
			return ret;
		}
	}

	return 0;
}

static int hns3_set_link_ksettings(struct net_device *netdev,
				   const struct ethtool_link_ksettings *cmd)
{
	/* Chip doesn't support this mode. */
	struct hnae3_handle *handle = hns3_get_handle(netdev);
	const struct hnae3_ae_ops *ops = handle->ae_algo->ops;
	int ret = 0;

	/* Chip don't support this mode. */
	if (cmd->base.speed == SPEED_1000 && cmd->base.duplex == DUPLEX_HALF)
		return -EINVAL;

@@ -661,7 +714,24 @@ static int hns3_set_link_ksettings(struct net_device *netdev,
	if (netdev->phydev)
		return phy_ethtool_ksettings_set(netdev->phydev, cmd);

	if (handle->pdev->revision == 0x20)
		return -EOPNOTSUPP;

	ret = hns3_check_ksettings_param(netdev, cmd);
	if (ret)
		return ret;

	if (ops->set_autoneg) {
		ret = ops->set_autoneg(handle, cmd->base.autoneg);
		if (ret)
			return ret;
	}

	if (ops->cfg_mac_speed_dup_h)
		ret = ops->cfg_mac_speed_dup_h(handle, cmd->base.speed,
					       cmd->base.duplex);

	return ret;
}

static u32 hns3_get_rss_key_size(struct net_device *netdev)
@@ -866,19 +936,36 @@ static int hns3_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)

static int hns3_nway_reset(struct net_device *netdev)
{
	struct hnae3_handle *handle = hns3_get_handle(netdev);
	const struct hnae3_ae_ops *ops = handle->ae_algo->ops;
	struct phy_device *phy = netdev->phydev;
	int autoneg;

	if (!netif_running(netdev))
		return 0;

	/* Only support nway_reset for netdev with phy attached for now */
	if (!phy)
	if (hns3_nic_resetting(netdev)) {
		netdev_err(netdev, "dev resetting!");
		return -EBUSY;
	}

	if (!ops->get_autoneg || !ops->restart_autoneg)
		return -EOPNOTSUPP;

	if (phy->autoneg != AUTONEG_ENABLE)
	autoneg = ops->get_autoneg(handle);
	if (autoneg != AUTONEG_ENABLE) {
		netdev_err(netdev,
			   "Autoneg is off, don't support to restart it\n");
		return -EINVAL;
	}

	if (phy)
		return genphy_restart_aneg(phy);

	if (handle->pdev->revision == 0x20)
		return -EOPNOTSUPP;

	return ops->restart_autoneg(handle);
}

static void hns3_get_channels(struct net_device *netdev,
@@ -1124,6 +1211,81 @@ static void hns3_set_msglevel(struct net_device *netdev, u32 msg_level)
	h->msg_enable = msg_level;
}

/* Translate local fec value into ethtool value. */
static unsigned int loc_to_eth_fec(u8 loc_fec)
{
	u32 eth_fec = 0;

	if (loc_fec & BIT(HNAE3_FEC_AUTO))
		eth_fec |= ETHTOOL_FEC_AUTO;
	if (loc_fec & BIT(HNAE3_FEC_RS))
		eth_fec |= ETHTOOL_FEC_RS;
	if (loc_fec & BIT(HNAE3_FEC_BASER))
		eth_fec |= ETHTOOL_FEC_BASER;

	/* if nothing is set, then FEC is off */
	if (!eth_fec)
		eth_fec = ETHTOOL_FEC_OFF;

	return eth_fec;
}

/* Translate ethtool fec value into local value. */
static unsigned int eth_to_loc_fec(unsigned int eth_fec)
{
	u32 loc_fec = 0;

	if (eth_fec & ETHTOOL_FEC_OFF)
		return loc_fec;

	if (eth_fec & ETHTOOL_FEC_AUTO)
		loc_fec |= BIT(HNAE3_FEC_AUTO);
	if (eth_fec & ETHTOOL_FEC_RS)
		loc_fec |= BIT(HNAE3_FEC_RS);
	if (eth_fec & ETHTOOL_FEC_BASER)
		loc_fec |= BIT(HNAE3_FEC_BASER);

	return loc_fec;
}

static int hns3_get_fecparam(struct net_device *netdev,
			     struct ethtool_fecparam *fec)
{
	struct hnae3_handle *handle = hns3_get_handle(netdev);
	const struct hnae3_ae_ops *ops = handle->ae_algo->ops;
	u8 fec_ability;
	u8 fec_mode;

	if (handle->pdev->revision == 0x20)
		return -EOPNOTSUPP;

	if (!ops->get_fec)
		return -EOPNOTSUPP;

	ops->get_fec(handle, &fec_ability, &fec_mode);

	fec->fec = loc_to_eth_fec(fec_ability);
	fec->active_fec = loc_to_eth_fec(fec_mode);

	return 0;
}

static int hns3_set_fecparam(struct net_device *netdev,
			     struct ethtool_fecparam *fec)
{
	struct hnae3_handle *handle = hns3_get_handle(netdev);
	const struct hnae3_ae_ops *ops = handle->ae_algo->ops;
	u32 fec_mode;

	if (handle->pdev->revision == 0x20)
		return -EOPNOTSUPP;

	if (!ops->set_fec)
		return -EOPNOTSUPP;
	fec_mode = eth_to_loc_fec(fec->fec);
	return ops->set_fec(handle, fec_mode);
}

static const struct ethtool_ops hns3vf_ethtool_ops = {
	.get_drvinfo = hns3_get_drvinfo,
	.get_ringparam = hns3_get_ringparam,
@@ -1177,6 +1339,8 @@ static const struct ethtool_ops hns3_ethtool_ops = {
	.set_phys_id = hns3_set_phys_id,
	.get_msglevel = hns3_get_msglevel,
	.set_msglevel = hns3_set_msglevel,
	.get_fecparam = hns3_get_fecparam,
	.set_fecparam = hns3_set_fecparam,
};

void hns3_ethtool_set_ops(struct net_device *netdev)
+26 −4
Original line number Diff line number Diff line
@@ -113,6 +113,7 @@ enum hclge_opcode_type {
	HCLGE_OPC_MAC_TNL_INT_EN	= 0x0311,
	HCLGE_OPC_CLEAR_MAC_TNL_INT	= 0x0312,
	HCLGE_OPC_SERDES_LOOPBACK       = 0x0315,
	HCLGE_OPC_CONFIG_FEC_MODE	= 0x031A,

	/* PFC/Pause commands */
	HCLGE_OPC_CFG_MAC_PAUSE_EN      = 0x0701,
@@ -244,7 +245,7 @@ enum hclge_opcode_type {
	HCLGE_OPC_QUERY_NCL_CONFIG	= 0x7011,

	/* SFP command */
	HCLGE_OPC_SFP_GET_SPEED		= 0x7104,
	HCLGE_OPC_GET_SFP_INFO		= 0x7104,

	/* Error INT commands */
	HCLGE_MAC_COMMON_INT_EN		= 0x030E,
@@ -599,9 +600,30 @@ struct hclge_config_auto_neg_cmd {
	u8      rsv[20];
};

struct hclge_sfp_speed_cmd {
	__le32	sfp_speed;
	u32	rsv[5];
struct hclge_sfp_info_cmd {
	__le32 speed;
	u8 query_type; /* 0: sfp speed, 1: active speed */
	u8 active_fec;
	u8 autoneg; /* autoneg state */
	u8 autoneg_ability; /* whether support autoneg */
	__le32 speed_ability; /* speed ability for current media */
	__le32 module_type;
	u8 rsv[8];
};

#define HCLGE_MAC_CFG_FEC_AUTO_EN_B	0
#define HCLGE_MAC_CFG_FEC_MODE_S	1
#define HCLGE_MAC_CFG_FEC_MODE_M	GENMASK(3, 1)
#define HCLGE_MAC_CFG_FEC_SET_DEF_B	0
#define HCLGE_MAC_CFG_FEC_CLR_DEF_B	1

#define HCLGE_MAC_FEC_OFF		0
#define HCLGE_MAC_FEC_BASER		1
#define HCLGE_MAC_FEC_RS		2
struct hclge_config_fec_cmd {
	u8 fec_mode;
	u8 default_config;
	u8 rsv[22];
};

#define HCLGE_MAC_UPLINK_PORT		0x100
+363 −47
Original line number Diff line number Diff line
@@ -845,33 +845,189 @@ static int hclge_parse_speed(int speed_cmd, int *speed)
	return 0;
}

static void hclge_parse_fiber_link_mode(struct hclge_dev *hdev,
					u8 speed_ability)
static int hclge_check_port_speed(struct hnae3_handle *handle, u32 speed)
{
	unsigned long *supported = hdev->hw.mac.supported;
	struct hclge_vport *vport = hclge_get_vport(handle);
	struct hclge_dev *hdev = vport->back;
	u32 speed_ability = hdev->hw.mac.speed_ability;
	u32 speed_bit = 0;

	if (speed_ability & HCLGE_SUPPORT_1G_BIT)
		linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
				 supported);
	switch (speed) {
	case HCLGE_MAC_SPEED_10M:
		speed_bit = HCLGE_SUPPORT_10M_BIT;
		break;
	case HCLGE_MAC_SPEED_100M:
		speed_bit = HCLGE_SUPPORT_100M_BIT;
		break;
	case HCLGE_MAC_SPEED_1G:
		speed_bit = HCLGE_SUPPORT_1G_BIT;
		break;
	case HCLGE_MAC_SPEED_10G:
		speed_bit = HCLGE_SUPPORT_10G_BIT;
		break;
	case HCLGE_MAC_SPEED_25G:
		speed_bit = HCLGE_SUPPORT_25G_BIT;
		break;
	case HCLGE_MAC_SPEED_40G:
		speed_bit = HCLGE_SUPPORT_40G_BIT;
		break;
	case HCLGE_MAC_SPEED_50G:
		speed_bit = HCLGE_SUPPORT_50G_BIT;
		break;
	case HCLGE_MAC_SPEED_100G:
		speed_bit = HCLGE_SUPPORT_100G_BIT;
		break;
	default:
		return -EINVAL;
	}

	if (speed_bit & speed_ability)
		return 0;

	return -EINVAL;
}

static void hclge_convert_setting_sr(struct hclge_mac *mac, u8 speed_ability)
{
	if (speed_ability & HCLGE_SUPPORT_10G_BIT)
		linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
				 supported);
				 mac->supported);
	if (speed_ability & HCLGE_SUPPORT_25G_BIT)
		linkmode_set_bit(ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
				 mac->supported);
	if (speed_ability & HCLGE_SUPPORT_40G_BIT)
		linkmode_set_bit(ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
				 mac->supported);
	if (speed_ability & HCLGE_SUPPORT_50G_BIT)
		linkmode_set_bit(ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
				 mac->supported);
	if (speed_ability & HCLGE_SUPPORT_100G_BIT)
		linkmode_set_bit(ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
				 mac->supported);
}

static void hclge_convert_setting_lr(struct hclge_mac *mac, u8 speed_ability)
{
	if (speed_ability & HCLGE_SUPPORT_10G_BIT)
		linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
				 mac->supported);
	if (speed_ability & HCLGE_SUPPORT_25G_BIT)
		linkmode_set_bit(ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
				 supported);
				 mac->supported);
	if (speed_ability & HCLGE_SUPPORT_50G_BIT)
		linkmode_set_bit(ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
				 mac->supported);
	if (speed_ability & HCLGE_SUPPORT_40G_BIT)
		linkmode_set_bit(ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
				 mac->supported);
	if (speed_ability & HCLGE_SUPPORT_100G_BIT)
		linkmode_set_bit(ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
				 mac->supported);
}

static void hclge_convert_setting_cr(struct hclge_mac *mac, u8 speed_ability)
{
	if (speed_ability & HCLGE_SUPPORT_10G_BIT)
		linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
				 mac->supported);
	if (speed_ability & HCLGE_SUPPORT_25G_BIT)
		linkmode_set_bit(ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
				 mac->supported);
	if (speed_ability & HCLGE_SUPPORT_40G_BIT)
		linkmode_set_bit(ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
				 mac->supported);
	if (speed_ability & HCLGE_SUPPORT_50G_BIT)
		linkmode_set_bit(ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
				 supported);
		linkmode_set_bit(ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
				 mac->supported);
	if (speed_ability & HCLGE_SUPPORT_100G_BIT)
		linkmode_set_bit(ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
				 mac->supported);
}

static void hclge_convert_setting_kr(struct hclge_mac *mac, u8 speed_ability)
{
	if (speed_ability & HCLGE_SUPPORT_1G_BIT)
		linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
				 mac->supported);
	if (speed_ability & HCLGE_SUPPORT_10G_BIT)
		linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
				 mac->supported);
	if (speed_ability & HCLGE_SUPPORT_25G_BIT)
		linkmode_set_bit(ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
				 mac->supported);
	if (speed_ability & HCLGE_SUPPORT_40G_BIT)
		linkmode_set_bit(ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
				 mac->supported);
	if (speed_ability & HCLGE_SUPPORT_50G_BIT)
		linkmode_set_bit(ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
				 mac->supported);
	if (speed_ability & HCLGE_SUPPORT_100G_BIT)
		linkmode_set_bit(ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
				 supported);
		linkmode_set_bit(ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
				 mac->supported);
}

	linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, supported);
	linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, supported);
static void hclge_convert_setting_fec(struct hclge_mac *mac)
{
	linkmode_clear_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT, mac->supported);
	linkmode_clear_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT, mac->supported);

	switch (mac->speed) {
	case HCLGE_MAC_SPEED_10G:
	case HCLGE_MAC_SPEED_40G:
		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT,
				 mac->supported);
		mac->fec_ability =
			BIT(HNAE3_FEC_BASER) | BIT(HNAE3_FEC_AUTO);
		break;
	case HCLGE_MAC_SPEED_25G:
	case HCLGE_MAC_SPEED_50G:
		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT,
				 mac->supported);
		mac->fec_ability =
			BIT(HNAE3_FEC_BASER) | BIT(HNAE3_FEC_RS) |
			BIT(HNAE3_FEC_AUTO);
		break;
	case HCLGE_MAC_SPEED_100G:
		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT, mac->supported);
		mac->fec_ability = BIT(HNAE3_FEC_RS) | BIT(HNAE3_FEC_AUTO);
		break;
	default:
		mac->fec_ability = 0;
		break;
	}
}

static void hclge_parse_fiber_link_mode(struct hclge_dev *hdev,
					u8 speed_ability)
{
	struct hclge_mac *mac = &hdev->hw.mac;

	if (speed_ability & HCLGE_SUPPORT_1G_BIT)
		linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
				 mac->supported);

	hclge_convert_setting_sr(mac, speed_ability);
	hclge_convert_setting_lr(mac, speed_ability);
	hclge_convert_setting_cr(mac, speed_ability);
	if (hdev->pdev->revision >= 0x21)
		hclge_convert_setting_fec(mac);

	linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, mac->supported);
	linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, mac->supported);
	linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT, mac->supported);
}

static void hclge_parse_backplane_link_mode(struct hclge_dev *hdev,
					    u8 speed_ability)
{
	struct hclge_mac *mac = &hdev->hw.mac;

	hclge_convert_setting_kr(mac, speed_ability);
	if (hdev->pdev->revision >= 0x21)
		hclge_convert_setting_fec(mac);
	linkmode_set_bit(ETHTOOL_LINK_MODE_Backplane_BIT, mac->supported);
	linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, mac->supported);
	linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT, mac->supported);
}

static void hclge_parse_copper_link_mode(struct hclge_dev *hdev,
@@ -912,8 +1068,9 @@ static void hclge_parse_link_mode(struct hclge_dev *hdev, u8 speed_ability)
		hclge_parse_fiber_link_mode(hdev, speed_ability);
	else if (media_type == HNAE3_MEDIA_TYPE_COPPER)
		hclge_parse_copper_link_mode(hdev, speed_ability);
	else if (media_type == HNAE3_MEDIA_TYPE_BACKPLANE)
		hclge_parse_backplane_link_mode(hdev, speed_ability);
}

static void hclge_parse_cfg(struct hclge_cfg *cfg, struct hclge_desc *desc)
{
	struct hclge_cfg_param_cmd *req;
@@ -2120,6 +2277,16 @@ static int hclge_set_autoneg(struct hnae3_handle *handle, bool enable)
	struct hclge_vport *vport = hclge_get_vport(handle);
	struct hclge_dev *hdev = vport->back;

	if (!hdev->hw.mac.support_autoneg) {
		if (enable) {
			dev_err(&hdev->pdev->dev,
				"autoneg is not supported by current port\n");
			return -EOPNOTSUPP;
		} else {
			return 0;
		}
	}

	return hclge_set_autoneg_en(hdev, enable);
}

@@ -2135,6 +2302,78 @@ static int hclge_get_autoneg(struct hnae3_handle *handle)
	return hdev->hw.mac.autoneg;
}

static int hclge_restart_autoneg(struct hnae3_handle *handle)
{
	struct hclge_vport *vport = hclge_get_vport(handle);
	struct hclge_dev *hdev = vport->back;
	int ret;

	dev_dbg(&hdev->pdev->dev, "restart autoneg\n");

	ret = hclge_notify_client(hdev, HNAE3_DOWN_CLIENT);
	if (ret)
		return ret;
	return hclge_notify_client(hdev, HNAE3_UP_CLIENT);
}

static int hclge_set_fec_hw(struct hclge_dev *hdev, u32 fec_mode)
{
	struct hclge_config_fec_cmd *req;
	struct hclge_desc desc;
	int ret;

	hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CONFIG_FEC_MODE, false);

	req = (struct hclge_config_fec_cmd *)desc.data;
	if (fec_mode & BIT(HNAE3_FEC_AUTO))
		hnae3_set_bit(req->fec_mode, HCLGE_MAC_CFG_FEC_AUTO_EN_B, 1);
	if (fec_mode & BIT(HNAE3_FEC_RS))
		hnae3_set_field(req->fec_mode, HCLGE_MAC_CFG_FEC_MODE_M,
				HCLGE_MAC_CFG_FEC_MODE_S, HCLGE_MAC_FEC_RS);
	if (fec_mode & BIT(HNAE3_FEC_BASER))
		hnae3_set_field(req->fec_mode, HCLGE_MAC_CFG_FEC_MODE_M,
				HCLGE_MAC_CFG_FEC_MODE_S, HCLGE_MAC_FEC_BASER);

	ret = hclge_cmd_send(&hdev->hw, &desc, 1);
	if (ret)
		dev_err(&hdev->pdev->dev, "set fec mode failed %d.\n", ret);

	return ret;
}

static int hclge_set_fec(struct hnae3_handle *handle, u32 fec_mode)
{
	struct hclge_vport *vport = hclge_get_vport(handle);
	struct hclge_dev *hdev = vport->back;
	struct hclge_mac *mac = &hdev->hw.mac;
	int ret;

	if (fec_mode && !(mac->fec_ability & fec_mode)) {
		dev_err(&hdev->pdev->dev, "unsupported fec mode\n");
		return -EINVAL;
	}

	ret = hclge_set_fec_hw(hdev, fec_mode);
	if (ret)
		return ret;

	mac->user_fec_mode = fec_mode | BIT(HNAE3_FEC_USER_DEF);
	return 0;
}

static void hclge_get_fec(struct hnae3_handle *handle, u8 *fec_ability,
			  u8 *fec_mode)
{
	struct hclge_vport *vport = hclge_get_vport(handle);
	struct hclge_dev *hdev = vport->back;
	struct hclge_mac *mac = &hdev->hw.mac;

	if (fec_ability)
		*fec_ability = mac->fec_ability;
	if (fec_mode)
		*fec_mode = mac->fec_mode;
}

static int hclge_mac_init(struct hclge_dev *hdev)
{
	struct hclge_mac *mac = &hdev->hw.mac;
@@ -2152,6 +2391,15 @@ static int hclge_mac_init(struct hclge_dev *hdev)

	mac->link = 0;

	if (mac->user_fec_mode & BIT(HNAE3_FEC_USER_DEF)) {
		ret = hclge_set_fec_hw(hdev, mac->user_fec_mode);
		if (ret) {
			dev_err(&hdev->pdev->dev,
				"Fec mode init fail, ret = %d\n", ret);
			return ret;
		}
	}

	ret = hclge_set_mac_mtu(hdev, hdev->mps);
	if (ret) {
		dev_err(&hdev->pdev->dev, "set mtu failed ret=%d\n", ret);
@@ -2258,14 +2506,35 @@ static void hclge_update_link_status(struct hclge_dev *hdev)
	}
}

static void hclge_update_port_capability(struct hclge_mac *mac)
{
	/* firmware can not identify back plane type, the media type
	 * read from configuration can help deal it
	 */
	if (mac->media_type == HNAE3_MEDIA_TYPE_BACKPLANE &&
	    mac->module_type == HNAE3_MODULE_TYPE_UNKNOWN)
		mac->module_type = HNAE3_MODULE_TYPE_KR;
	else if (mac->media_type == HNAE3_MEDIA_TYPE_COPPER)
		mac->module_type = HNAE3_MODULE_TYPE_TP;

	if (mac->support_autoneg == true) {
		linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, mac->supported);
		linkmode_copy(mac->advertising, mac->supported);
	} else {
		linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
				   mac->supported);
		linkmode_zero(mac->advertising);
	}
}

static int hclge_get_sfp_speed(struct hclge_dev *hdev, u32 *speed)
{
	struct hclge_sfp_speed_cmd *resp = NULL;
	struct hclge_sfp_info_cmd *resp = NULL;
	struct hclge_desc desc;
	int ret;

	hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_SFP_GET_SPEED, true);
	resp = (struct hclge_sfp_speed_cmd *)desc.data;
	hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_GET_SFP_INFO, true);
	resp = (struct hclge_sfp_info_cmd *)desc.data;
	ret = hclge_cmd_send(&hdev->hw, &desc, 1);
	if (ret == -EOPNOTSUPP) {
		dev_warn(&hdev->pdev->dev,
@@ -2276,28 +2545,67 @@ static int hclge_get_sfp_speed(struct hclge_dev *hdev, u32 *speed)
		return ret;
	}

	*speed = resp->sfp_speed;
	*speed = le32_to_cpu(resp->speed);

	return 0;
}

static int hclge_update_speed_duplex(struct hclge_dev *hdev)
static int hclge_get_sfp_info(struct hclge_dev *hdev, struct hclge_mac *mac)
{
	struct hclge_mac mac = hdev->hw.mac;
	int speed;
	struct hclge_sfp_info_cmd *resp;
	struct hclge_desc desc;
	int ret;

	/* get the speed from SFP cmd when phy
	 * doesn't exit.
	hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_GET_SFP_INFO, true);
	resp = (struct hclge_sfp_info_cmd *)desc.data;

	resp->query_type = QUERY_ACTIVE_SPEED;

	ret = hclge_cmd_send(&hdev->hw, &desc, 1);
	if (ret == -EOPNOTSUPP) {
		dev_warn(&hdev->pdev->dev,
			 "IMP does not support get SFP info %d\n", ret);
		return ret;
	} else if (ret) {
		dev_err(&hdev->pdev->dev, "get sfp info failed %d\n", ret);
		return ret;
	}

	mac->speed = le32_to_cpu(resp->speed);
	/* if resp->speed_ability is 0, it means it's an old version
	 * firmware, do not update these params
	 */
	if (mac.phydev)
	if (resp->speed_ability) {
		mac->module_type = le32_to_cpu(resp->module_type);
		mac->speed_ability = le32_to_cpu(resp->speed_ability);
		mac->autoneg = resp->autoneg;
		mac->support_autoneg = resp->autoneg_ability;
	} else {
		mac->speed_type = QUERY_SFP_SPEED;
	}

	return 0;
}

static int hclge_update_port_info(struct hclge_dev *hdev)
{
	struct hclge_mac *mac = &hdev->hw.mac;
	int speed = HCLGE_MAC_SPEED_UNKNOWN;
	int ret;

	/* get the port info from SFP cmd if not copper port */
	if (mac->media_type == HNAE3_MEDIA_TYPE_COPPER)
		return 0;

	/* if IMP does not support get SFP/qSFP speed, return directly */
	/* if IMP does not support get SFP/qSFP info, return directly */
	if (!hdev->support_sfp_query)
		return 0;

	if (hdev->pdev->revision >= 0x21)
		ret = hclge_get_sfp_info(hdev, mac);
	else
		ret = hclge_get_sfp_speed(hdev, &speed);

	if (ret == -EOPNOTSUPP) {
		hdev->support_sfp_query = false;
		return ret;
@@ -2305,19 +2613,20 @@ static int hclge_update_speed_duplex(struct hclge_dev *hdev)
		return ret;
	}

	if (hdev->pdev->revision >= 0x21) {
		if (mac->speed_type == QUERY_ACTIVE_SPEED) {
			hclge_update_port_capability(mac);
			return 0;
		}
		return hclge_cfg_mac_speed_dup(hdev, mac->speed,
					       HCLGE_MAC_FULL);
	} else {
		if (speed == HCLGE_MAC_SPEED_UNKNOWN)
			return 0; /* do nothing if no SFP */

		/* must config full duplex for SFP */
		return hclge_cfg_mac_speed_dup(hdev, speed, HCLGE_MAC_FULL);
	}

static int hclge_update_speed_duplex_h(struct hnae3_handle *handle)
{
	struct hclge_vport *vport = hclge_get_vport(handle);
	struct hclge_dev *hdev = vport->back;

	return hclge_update_speed_duplex(hdev);
}

static int hclge_get_status(struct hnae3_handle *handle)
@@ -3209,7 +3518,7 @@ static void hclge_service_task(struct work_struct *work)
		hdev->hw_stats.stats_timer = 0;
	}

	hclge_update_speed_duplex(hdev);
	hclge_update_port_info(hdev);
	hclge_update_link_status(hdev);
	hclge_update_vport_alive(hdev);
	hclge_service_complete(hdev);
@@ -7474,13 +7783,13 @@ static int hclge_set_pauseparam(struct hnae3_handle *handle, u32 auto_neg,
	if (!fc_autoneg)
		return hclge_cfg_pauseparam(hdev, rx_en, tx_en);

	/* Only support flow control negotiation for netdev with
	 * phy attached for now.
	 */
	if (!phydev)
	if (phydev)
		return phy_start_aneg(phydev);

	if (hdev->pdev->revision == 0x20)
		return -EOPNOTSUPP;

	return phy_start_aneg(phydev);
	return hclge_restart_autoneg(handle);
}

static void hclge_get_ksettings_an_result(struct hnae3_handle *handle,
@@ -7497,13 +7806,17 @@ static void hclge_get_ksettings_an_result(struct hnae3_handle *handle,
		*auto_neg = hdev->hw.mac.autoneg;
}

static void hclge_get_media_type(struct hnae3_handle *handle, u8 *media_type)
static void hclge_get_media_type(struct hnae3_handle *handle, u8 *media_type,
				 u8 *module_type)
{
	struct hclge_vport *vport = hclge_get_vport(handle);
	struct hclge_dev *hdev = vport->back;

	if (media_type)
		*media_type = hdev->hw.mac.media_type;

	if (module_type)
		*module_type = hdev->hw.mac.module_type;
}

static void hclge_get_mdix_mode(struct hnae3_handle *handle,
@@ -8541,9 +8854,11 @@ static const struct hnae3_ae_ops hclge_ops = {
	.client_stop = hclge_client_stop,
	.get_status = hclge_get_status,
	.get_ksettings_an_result = hclge_get_ksettings_an_result,
	.update_speed_duplex_h = hclge_update_speed_duplex_h,
	.cfg_mac_speed_dup_h = hclge_cfg_mac_speed_dup_h,
	.get_media_type = hclge_get_media_type,
	.check_port_speed = hclge_check_port_speed,
	.get_fec = hclge_get_fec,
	.set_fec = hclge_set_fec,
	.get_rss_key_size = hclge_get_rss_key_size,
	.get_rss_indir_size = hclge_get_rss_indir_size,
	.get_rss = hclge_get_rss,
@@ -8560,6 +8875,7 @@ static const struct hnae3_ae_ops hclge_ops = {
	.rm_mc_addr = hclge_rm_mc_addr,
	.set_autoneg = hclge_set_autoneg,
	.get_autoneg = hclge_get_autoneg,
	.restart_autoneg = hclge_restart_autoneg,
	.get_pauseparam = hclge_get_pauseparam,
	.set_pauseparam = hclge_set_pauseparam,
	.set_mtu = hclge_set_mtu,
+14 −2

File changed.

Preview size limit exceeded, changes collapsed.

Loading