Commit 0caeaf6a authored by Rahul Lakkireddy's avatar Rahul Lakkireddy Committed by David S. Miller
Browse files

cxgb4/cxgb4vf: fix flow control display for auto negotiation

As per 802.3-2005, Section Two, Annex 28B, Table 28B-2 [1], when
_only_ Rx pause is enabled, both symmetric and asymmetric pause
towards local device must be enabled. Also, firmware returns the local
device's flow control pause params as part of advertised capabilities
and negotiated params as part of current link attributes. So, fix up
ethtool's flow control pause params fetch logic to read from acaps,
instead of linkattr.

[1] https://standards.ieee.org/standard/802_3-2005.html



Fixes: c3168cab ("cxgb4/cxgbvf: Handle 32-bit fw port capabilities")
Signed-off-by: default avatarSurendra Mobiya <surendra@chelsio.com>
Signed-off-by: default avatarRahul Lakkireddy <rahul.lakkireddy@chelsio.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 3faf6eda
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -504,6 +504,7 @@ struct link_config {

	enum cc_pause  requested_fc;     /* flow control user has requested */
	enum cc_pause  fc;               /* actual link flow control */
	enum cc_pause  advertised_fc;    /* actual advertised flow control */

	enum cc_fec    requested_fec;	 /* Forward Error Correction: */
	enum cc_fec    fec;		 /* requested and actual in use */
+2 −2
Original line number Diff line number Diff line
@@ -807,8 +807,8 @@ static void get_pauseparam(struct net_device *dev,
	struct port_info *p = netdev_priv(dev);

	epause->autoneg = (p->link_cfg.requested_fc & PAUSE_AUTONEG) != 0;
	epause->rx_pause = (p->link_cfg.fc & PAUSE_RX) != 0;
	epause->tx_pause = (p->link_cfg.fc & PAUSE_TX) != 0;
	epause->rx_pause = (p->link_cfg.advertised_fc & PAUSE_RX) != 0;
	epause->tx_pause = (p->link_cfg.advertised_fc & PAUSE_TX) != 0;
}

static int set_pauseparam(struct net_device *dev,
+13 −8
Original line number Diff line number Diff line
@@ -4089,7 +4089,8 @@ static inline fw_port_cap32_t cc_to_fwcap_pause(enum cc_pause cc_pause)
		if (cc_pause & PAUSE_TX)
			fw_pause |= FW_PORT_CAP32_802_3_PAUSE;
		else
			fw_pause |= FW_PORT_CAP32_802_3_ASM_DIR;
			fw_pause |= FW_PORT_CAP32_802_3_ASM_DIR |
				    FW_PORT_CAP32_802_3_PAUSE;
	} else if (cc_pause & PAUSE_TX) {
		fw_pause |= FW_PORT_CAP32_802_3_ASM_DIR;
	}
@@ -8563,17 +8564,17 @@ static fw_port_cap32_t lstatus_to_fwcap(u32 lstatus)
void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl)
{
	const struct fw_port_cmd *cmd = (const void *)rpl;
	int action = FW_PORT_CMD_ACTION_G(be32_to_cpu(cmd->action_to_len16));
	struct adapter *adapter = pi->adapter;
	fw_port_cap32_t pcaps, acaps, lpacaps, linkattr;
	struct link_config *lc = &pi->link_cfg;
	int link_ok, linkdnrc;
	enum fw_port_type port_type;
	struct adapter *adapter = pi->adapter;
	unsigned int speed, fc, fec, adv_fc;
	enum fw_port_module_type mod_type;
	unsigned int speed, fc, fec;
	fw_port_cap32_t pcaps, acaps, lpacaps, linkattr;
	int action, link_ok, linkdnrc;
	enum fw_port_type port_type;

	/* Extract the various fields from the Port Information message.
	 */
	action = FW_PORT_CMD_ACTION_G(be32_to_cpu(cmd->action_to_len16));
	switch (action) {
	case FW_PORT_ACTION_GET_PORT_INFO: {
		u32 lstatus = be32_to_cpu(cmd->u.info.lstatus_to_modtype);
@@ -8611,6 +8612,7 @@ void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl)
	}

	fec = fwcap_to_cc_fec(acaps);
	adv_fc = fwcap_to_cc_pause(acaps);
	fc = fwcap_to_cc_pause(linkattr);
	speed = fwcap_to_speed(linkattr);

@@ -8667,7 +8669,9 @@ void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl)
	}

	if (link_ok != lc->link_ok || speed != lc->speed ||
	    fc != lc->fc || fec != lc->fec) {	/* something changed */
	    fc != lc->fc || adv_fc != lc->advertised_fc ||
	    fec != lc->fec) {
		/* something changed */
		if (!link_ok && lc->link_ok) {
			lc->link_down_rc = linkdnrc;
			dev_warn_ratelimited(adapter->pdev_dev,
@@ -8677,6 +8681,7 @@ void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl)
		}
		lc->link_ok = link_ok;
		lc->speed = speed;
		lc->advertised_fc = adv_fc;
		lc->fc = fc;
		lc->fec = fec;

+2 −2
Original line number Diff line number Diff line
@@ -1690,8 +1690,8 @@ static void cxgb4vf_get_pauseparam(struct net_device *dev,
	struct port_info *pi = netdev_priv(dev);

	pauseparam->autoneg = (pi->link_cfg.requested_fc & PAUSE_AUTONEG) != 0;
	pauseparam->rx_pause = (pi->link_cfg.fc & PAUSE_RX) != 0;
	pauseparam->tx_pause = (pi->link_cfg.fc & PAUSE_TX) != 0;
	pauseparam->rx_pause = (pi->link_cfg.advertised_fc & PAUSE_RX) != 0;
	pauseparam->tx_pause = (pi->link_cfg.advertised_fc & PAUSE_TX) != 0;
}

/*
+1 −0
Original line number Diff line number Diff line
@@ -135,6 +135,7 @@ struct link_config {

	enum cc_pause	requested_fc;	/* flow control user has requested */
	enum cc_pause	fc;		/* actual link flow control */
	enum cc_pause   advertised_fc;  /* actual advertised flow control */

	enum cc_fec	auto_fec;	/* Forward Error Correction: */
	enum cc_fec	requested_fec;	/*   "automatic" (IEEE 802.3), */
Loading