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

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
...@@ -504,6 +504,7 @@ struct link_config { ...@@ -504,6 +504,7 @@ struct link_config {
enum cc_pause requested_fc; /* flow control user has requested */ enum cc_pause requested_fc; /* flow control user has requested */
enum cc_pause fc; /* actual link flow control */ 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 requested_fec; /* Forward Error Correction: */
enum cc_fec fec; /* requested and actual in use */ enum cc_fec fec; /* requested and actual in use */
......
...@@ -807,8 +807,8 @@ static void get_pauseparam(struct net_device *dev, ...@@ -807,8 +807,8 @@ static void get_pauseparam(struct net_device *dev,
struct port_info *p = netdev_priv(dev); struct port_info *p = netdev_priv(dev);
epause->autoneg = (p->link_cfg.requested_fc & PAUSE_AUTONEG) != 0; epause->autoneg = (p->link_cfg.requested_fc & PAUSE_AUTONEG) != 0;
epause->rx_pause = (p->link_cfg.fc & PAUSE_RX) != 0; epause->rx_pause = (p->link_cfg.advertised_fc & PAUSE_RX) != 0;
epause->tx_pause = (p->link_cfg.fc & PAUSE_TX) != 0; epause->tx_pause = (p->link_cfg.advertised_fc & PAUSE_TX) != 0;
} }
static int set_pauseparam(struct net_device *dev, static int set_pauseparam(struct net_device *dev,
......
...@@ -4089,7 +4089,8 @@ static inline fw_port_cap32_t cc_to_fwcap_pause(enum cc_pause cc_pause) ...@@ -4089,7 +4089,8 @@ static inline fw_port_cap32_t cc_to_fwcap_pause(enum cc_pause cc_pause)
if (cc_pause & PAUSE_TX) if (cc_pause & PAUSE_TX)
fw_pause |= FW_PORT_CAP32_802_3_PAUSE; fw_pause |= FW_PORT_CAP32_802_3_PAUSE;
else 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) { } else if (cc_pause & PAUSE_TX) {
fw_pause |= FW_PORT_CAP32_802_3_ASM_DIR; fw_pause |= FW_PORT_CAP32_802_3_ASM_DIR;
} }
...@@ -8563,17 +8564,17 @@ static fw_port_cap32_t lstatus_to_fwcap(u32 lstatus) ...@@ -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) void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl)
{ {
const struct fw_port_cmd *cmd = (const void *)rpl; const struct fw_port_cmd *cmd = (const void *)rpl;
int action = FW_PORT_CMD_ACTION_G(be32_to_cpu(cmd->action_to_len16)); fw_port_cap32_t pcaps, acaps, lpacaps, linkattr;
struct adapter *adapter = pi->adapter;
struct link_config *lc = &pi->link_cfg; struct link_config *lc = &pi->link_cfg;
int link_ok, linkdnrc; struct adapter *adapter = pi->adapter;
enum fw_port_type port_type; unsigned int speed, fc, fec, adv_fc;
enum fw_port_module_type mod_type; enum fw_port_module_type mod_type;
unsigned int speed, fc, fec; int action, link_ok, linkdnrc;
fw_port_cap32_t pcaps, acaps, lpacaps, linkattr; enum fw_port_type port_type;
/* Extract the various fields from the Port Information message. /* Extract the various fields from the Port Information message.
*/ */
action = FW_PORT_CMD_ACTION_G(be32_to_cpu(cmd->action_to_len16));
switch (action) { switch (action) {
case FW_PORT_ACTION_GET_PORT_INFO: { case FW_PORT_ACTION_GET_PORT_INFO: {
u32 lstatus = be32_to_cpu(cmd->u.info.lstatus_to_modtype); 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) ...@@ -8611,6 +8612,7 @@ void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl)
} }
fec = fwcap_to_cc_fec(acaps); fec = fwcap_to_cc_fec(acaps);
adv_fc = fwcap_to_cc_pause(acaps);
fc = fwcap_to_cc_pause(linkattr); fc = fwcap_to_cc_pause(linkattr);
speed = fwcap_to_speed(linkattr); speed = fwcap_to_speed(linkattr);
...@@ -8667,7 +8669,9 @@ void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl) ...@@ -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 || 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) { if (!link_ok && lc->link_ok) {
lc->link_down_rc = linkdnrc; lc->link_down_rc = linkdnrc;
dev_warn_ratelimited(adapter->pdev_dev, dev_warn_ratelimited(adapter->pdev_dev,
...@@ -8677,6 +8681,7 @@ void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl) ...@@ -8677,6 +8681,7 @@ void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl)
} }
lc->link_ok = link_ok; lc->link_ok = link_ok;
lc->speed = speed; lc->speed = speed;
lc->advertised_fc = adv_fc;
lc->fc = fc; lc->fc = fc;
lc->fec = fec; lc->fec = fec;
......
...@@ -1690,8 +1690,8 @@ static void cxgb4vf_get_pauseparam(struct net_device *dev, ...@@ -1690,8 +1690,8 @@ static void cxgb4vf_get_pauseparam(struct net_device *dev,
struct port_info *pi = netdev_priv(dev); struct port_info *pi = netdev_priv(dev);
pauseparam->autoneg = (pi->link_cfg.requested_fc & PAUSE_AUTONEG) != 0; pauseparam->autoneg = (pi->link_cfg.requested_fc & PAUSE_AUTONEG) != 0;
pauseparam->rx_pause = (pi->link_cfg.fc & PAUSE_RX) != 0; pauseparam->rx_pause = (pi->link_cfg.advertised_fc & PAUSE_RX) != 0;
pauseparam->tx_pause = (pi->link_cfg.fc & PAUSE_TX) != 0; pauseparam->tx_pause = (pi->link_cfg.advertised_fc & PAUSE_TX) != 0;
} }
/* /*
......
...@@ -135,6 +135,7 @@ struct link_config { ...@@ -135,6 +135,7 @@ struct link_config {
enum cc_pause requested_fc; /* flow control user has requested */ enum cc_pause requested_fc; /* flow control user has requested */
enum cc_pause fc; /* actual link flow control */ 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 auto_fec; /* Forward Error Correction: */
enum cc_fec requested_fec; /* "automatic" (IEEE 802.3), */ enum cc_fec requested_fec; /* "automatic" (IEEE 802.3), */
......
...@@ -1913,16 +1913,16 @@ static const char *t4vf_link_down_rc_str(unsigned char link_down_rc) ...@@ -1913,16 +1913,16 @@ static const char *t4vf_link_down_rc_str(unsigned char link_down_rc)
static void t4vf_handle_get_port_info(struct port_info *pi, static void t4vf_handle_get_port_info(struct port_info *pi,
const struct fw_port_cmd *cmd) const struct fw_port_cmd *cmd)
{ {
int action = FW_PORT_CMD_ACTION_G(be32_to_cpu(cmd->action_to_len16)); fw_port_cap32_t pcaps, acaps, lpacaps, linkattr;
struct adapter *adapter = pi->adapter;
struct link_config *lc = &pi->link_cfg; struct link_config *lc = &pi->link_cfg;
int link_ok, linkdnrc; struct adapter *adapter = pi->adapter;
enum fw_port_type port_type; unsigned int speed, fc, fec, adv_fc;
enum fw_port_module_type mod_type; enum fw_port_module_type mod_type;
unsigned int speed, fc, fec; int action, link_ok, linkdnrc;
fw_port_cap32_t pcaps, acaps, lpacaps, linkattr; enum fw_port_type port_type;
/* Extract the various fields from the Port Information message. */ /* Extract the various fields from the Port Information message. */
action = FW_PORT_CMD_ACTION_G(be32_to_cpu(cmd->action_to_len16));
switch (action) { switch (action) {
case FW_PORT_ACTION_GET_PORT_INFO: { case FW_PORT_ACTION_GET_PORT_INFO: {
u32 lstatus = be32_to_cpu(cmd->u.info.lstatus_to_modtype); u32 lstatus = be32_to_cpu(cmd->u.info.lstatus_to_modtype);
...@@ -1982,6 +1982,7 @@ static void t4vf_handle_get_port_info(struct port_info *pi, ...@@ -1982,6 +1982,7 @@ static void t4vf_handle_get_port_info(struct port_info *pi,
} }
fec = fwcap_to_cc_fec(acaps); fec = fwcap_to_cc_fec(acaps);
adv_fc = fwcap_to_cc_pause(acaps);
fc = fwcap_to_cc_pause(linkattr); fc = fwcap_to_cc_pause(linkattr);
speed = fwcap_to_speed(linkattr); speed = fwcap_to_speed(linkattr);
...@@ -2012,7 +2013,9 @@ static void t4vf_handle_get_port_info(struct port_info *pi, ...@@ -2012,7 +2013,9 @@ static void t4vf_handle_get_port_info(struct port_info *pi,
} }
if (link_ok != lc->link_ok || speed != lc->speed || 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) { if (!link_ok && lc->link_ok) {
lc->link_down_rc = linkdnrc; lc->link_down_rc = linkdnrc;
dev_warn_ratelimited(adapter->pdev_dev, dev_warn_ratelimited(adapter->pdev_dev,
...@@ -2022,6 +2025,7 @@ static void t4vf_handle_get_port_info(struct port_info *pi, ...@@ -2022,6 +2025,7 @@ static void t4vf_handle_get_port_info(struct port_info *pi,
} }
lc->link_ok = link_ok; lc->link_ok = link_ok;
lc->speed = speed; lc->speed = speed;
lc->advertised_fc = adv_fc;
lc->fc = fc; lc->fc = fc;
lc->fec = fec; lc->fec = fec;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment