Skip to content

Commit

Permalink
cxgb4/cxgb4vf: link management changes for new SFP
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Ganesh Goudar authored and David S. Miller committed May 25, 2018
1 parent b526e56 commit 57ccaed
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 18 deletions.
22 changes: 9 additions & 13 deletions drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
34 changes: 30 additions & 4 deletions drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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));
Expand All @@ -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;
}

/**
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -8600,13 +8618,21 @@ 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;
lc->requested_fc |= PAUSE_AUTONEG;
} else {
lc->acaps = 0;
lc->autoneg = AUTONEG_DISABLE;
lc->speed_caps = fwcap_to_fwspeed(acaps);
}
}

Expand Down
47 changes: 46 additions & 1 deletion drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -431,13 +461,21 @@ 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;
lc->requested_fc |= PAUSE_AUTONEG;
} else {
lc->acaps = 0;
lc->autoneg = AUTONEG_DISABLE;
lc->speed_caps = fwcap_to_fwspeed(acaps);
}
}

Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 57ccaed

Please sign in to comment.