mirror of
https://github.com/torvalds/linux.git
synced 2024-11-14 08:02:07 +00:00
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:
parent
b526e56b31
commit
57ccaedb74
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user