cxgb4/cxgb4vf: link management changes for new SFP

newer SFPs like SFP28 and QSFP28 Transceiver Modules present
several new possibilities which we haven't faced before. Fix the
assumptions in the code reflecting the more limited capabilities
of previous Transceiver Module systems

Original work by Casey Leedom <leedom@chelsio.com>

Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Ganesh Goudar 2018-05-24 17:49:30 +05:30 committed by David S. Miller
parent b526e56b31
commit 57ccaedb74
3 changed files with 85 additions and 18 deletions

View File

@ -800,24 +800,20 @@ static int set_link_ksettings(struct net_device *dev,
if (base->duplex != DUPLEX_FULL)
return -EINVAL;
if (!(lc->pcaps & FW_PORT_CAP32_ANEG)) {
/* PHY offers a single speed. See if that's what's
* being requested.
*/
if (base->autoneg == AUTONEG_DISABLE &&
(lc->pcaps & speed_to_fw_caps(base->speed)))
return 0;
return -EINVAL;
}
old_lc = *lc;
if (base->autoneg == AUTONEG_DISABLE) {
if (!(lc->pcaps & FW_PORT_CAP32_ANEG) ||
base->autoneg == AUTONEG_DISABLE) {
fw_caps = speed_to_fw_caps(base->speed);
if (!(lc->pcaps & fw_caps))
/* Must only specify a single speed which must be supported
* as part of the Physical Port Capabilities.
*/
if ((fw_caps & (fw_caps - 1)) != 0 ||
!(lc->pcaps & fw_caps))
return -EINVAL;
lc->speed_caps = fw_caps;
lc->acaps = 0;
lc->acaps = fw_caps;
} else {
fw_caps =
lmm_to_fw_caps(link_ksettings->link_modes.advertising);

View File

@ -4066,6 +4066,7 @@ int t4_link_l1cfg_core(struct adapter *adapter, unsigned int mbox,
fw_port_cap32_t fw_fc, cc_fec, fw_fec, rcap;
struct fw_port_cmd cmd;
unsigned int fw_mdi;
int ret;
fw_mdi = (FW_PORT_CAP32_MDI_V(FW_PORT_CAP32_MDI_AUTO) & lc->pcaps);
/* Convert driver coding of Pause Frame Flow Control settings into the
@ -4100,6 +4101,13 @@ int t4_link_l1cfg_core(struct adapter *adapter, unsigned int mbox,
rcap = lc->acaps | fw_fc | fw_fec | fw_mdi;
}
if (rcap & ~lc->pcaps) {
dev_err(adapter->pdev_dev,
"Requested Port Capabilities %#x exceed Physical Port Capabilities %#x\n",
rcap, lc->pcaps);
return -EINVAL;
}
/* And send that on to the Firmware ...
*/
memset(&cmd, 0, sizeof(cmd));
@ -4110,13 +4118,21 @@ int t4_link_l1cfg_core(struct adapter *adapter, unsigned int mbox,
cpu_to_be32(FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16
? FW_PORT_ACTION_L1_CFG
: FW_PORT_ACTION_L1_CFG32) |
FW_LEN16(cmd));
FW_LEN16(cmd));
if (fw_caps == FW_CAPS16)
cmd.u.l1cfg.rcap = cpu_to_be32(fwcaps32_to_caps16(rcap));
else
cmd.u.l1cfg32.rcap32 = cpu_to_be32(rcap);
return t4_wr_mbox_meat_timeout(adapter, mbox, &cmd, sizeof(cmd), NULL,
sleep_ok, timeout);
ret = t4_wr_mbox_meat_timeout(adapter, mbox, &cmd, sizeof(cmd), NULL,
sleep_ok, timeout);
if (ret) {
dev_err(adapter->pdev_dev,
"Requested Port Capabilities %#x rejected, error %d\n",
rcap, -ret);
return ret;
}
return ret;
}
/**
@ -8395,7 +8411,9 @@ void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl)
lc->lpacaps = lpacaps;
lc->acaps = acaps & ADVERT_MASK;
if (lc->acaps & FW_PORT_CAP32_ANEG) {
if (!(lc->acaps & FW_PORT_CAP32_ANEG)) {
lc->autoneg = AUTONEG_DISABLE;
} else if (lc->acaps & FW_PORT_CAP32_ANEG) {
lc->autoneg = AUTONEG_ENABLE;
} else {
/* When Autoneg is disabled, user needs to set
@ -8600,6 +8618,13 @@ static void init_link_config(struct link_config *lc, fw_port_cap32_t pcaps,
lc->requested_fec = FEC_AUTO;
lc->fec = fwcap_to_cc_fec(lc->def_acaps);
/* If the Port is capable of Auto-Negtotiation, initialize it as
* "enabled" and copy over all of the Physical Port Capabilities
* to the Advertised Port Capabilities. Otherwise mark it as
* Auto-Negotiate disabled and select the highest supported speed
* for the link. Note parallel structure in t4_link_l1cfg_core()
* and t4_handle_get_port_info().
*/
if (lc->pcaps & FW_PORT_CAP32_ANEG) {
lc->acaps = lc->pcaps & ADVERT_MASK;
lc->autoneg = AUTONEG_ENABLE;
@ -8607,6 +8632,7 @@ static void init_link_config(struct link_config *lc, fw_port_cap32_t pcaps,
} else {
lc->acaps = 0;
lc->autoneg = AUTONEG_DISABLE;
lc->speed_caps = fwcap_to_fwspeed(acaps);
}
}

View File

@ -405,6 +405,36 @@ static unsigned int fwcap_to_speed(fw_port_cap32_t caps)
return 0;
}
/**
* fwcap_to_fwspeed - return highest speed in Port Capabilities
* @acaps: advertised Port Capabilities
*
* Get the highest speed for the port from the advertised Port
* Capabilities. It will be either the highest speed from the list of
* speeds or whatever user has set using ethtool.
*/
static fw_port_cap32_t fwcap_to_fwspeed(fw_port_cap32_t acaps)
{
#define TEST_SPEED_RETURN(__caps_speed) \
do { \
if (acaps & FW_PORT_CAP32_SPEED_##__caps_speed) \
return FW_PORT_CAP32_SPEED_##__caps_speed; \
} while (0)
TEST_SPEED_RETURN(400G);
TEST_SPEED_RETURN(200G);
TEST_SPEED_RETURN(100G);
TEST_SPEED_RETURN(50G);
TEST_SPEED_RETURN(40G);
TEST_SPEED_RETURN(25G);
TEST_SPEED_RETURN(10G);
TEST_SPEED_RETURN(1G);
TEST_SPEED_RETURN(100M);
#undef TEST_SPEED_RETURN
return 0;
}
/*
* init_link_config - initialize a link's SW state
* @lc: structure holding the link state
@ -431,6 +461,13 @@ static void init_link_config(struct link_config *lc,
lc->requested_fec = FEC_AUTO;
lc->fec = lc->auto_fec;
/* If the Port is capable of Auto-Negtotiation, initialize it as
* "enabled" and copy over all of the Physical Port Capabilities
* to the Advertised Port Capabilities. Otherwise mark it as
* Auto-Negotiate disabled and select the highest supported speed
* for the link. Note parallel structure in t4_link_l1cfg_core()
* and t4_handle_get_port_info().
*/
if (lc->pcaps & FW_PORT_CAP32_ANEG) {
lc->acaps = acaps & ADVERT_MASK;
lc->autoneg = AUTONEG_ENABLE;
@ -438,6 +475,7 @@ static void init_link_config(struct link_config *lc,
} else {
lc->acaps = 0;
lc->autoneg = AUTONEG_DISABLE;
lc->speed_caps = fwcap_to_fwspeed(acaps);
}
}
@ -1955,7 +1993,14 @@ static void t4vf_handle_get_port_info(struct port_info *pi,
lc->lpacaps = lpacaps;
lc->acaps = acaps & ADVERT_MASK;
if (lc->acaps & FW_PORT_CAP32_ANEG) {
/* If we're not physically capable of Auto-Negotiation, note
* this as Auto-Negotiation disabled. Otherwise, we track
* what Auto-Negotiation settings we have. Note parallel
* structure in init_link_config().
*/
if (!(lc->pcaps & FW_PORT_CAP32_ANEG)) {
lc->autoneg = AUTONEG_DISABLE;
} else if (lc->acaps & FW_PORT_CAP32_ANEG) {
lc->autoneg = AUTONEG_ENABLE;
} else {
/* When Autoneg is disabled, user needs to set