cxgbe(4): Consider all supported speeds when building the ifmedia list
for a port. Fix other related issues while here: - Require port lock for access to link_config. - Allow 100Mbps operation by tracking the speed in Mbps. Yes, really. - New port flag to indicate that the media list is immutable. It will be used in future refinements. This also fixes a bug where the driver reports incorrect media with recent firmwares. MFC after: 2 days Sponsored by: Chelsio Communications
This commit is contained in:
parent
64b378f1e1
commit
56226f5673
@ -164,6 +164,7 @@ enum {
|
|||||||
|
|
||||||
/* port flags */
|
/* port flags */
|
||||||
HAS_TRACEQ = (1 << 3),
|
HAS_TRACEQ = (1 << 3),
|
||||||
|
FIXED_IFMEDIA = (1 << 4), /* ifmedia list doesn't change. */
|
||||||
|
|
||||||
/* VI flags */
|
/* VI flags */
|
||||||
DOOMED = (1 << 0),
|
DOOMED = (1 << 0),
|
||||||
|
@ -418,12 +418,12 @@ struct link_config {
|
|||||||
unsigned char requested_aneg; /* link aneg user has requested */
|
unsigned char requested_aneg; /* link aneg user has requested */
|
||||||
unsigned char requested_fc; /* flow control user has requested */
|
unsigned char requested_fc; /* flow control user has requested */
|
||||||
unsigned char requested_fec; /* FEC user has requested */
|
unsigned char requested_fec; /* FEC user has requested */
|
||||||
unsigned int requested_speed; /* speed user has requested */
|
unsigned int requested_speed; /* speed user has requested (Mbps) */
|
||||||
|
|
||||||
unsigned short supported; /* link capabilities */
|
unsigned short supported; /* link capabilities */
|
||||||
unsigned short advertising; /* advertised capabilities */
|
unsigned short advertising; /* advertised capabilities */
|
||||||
unsigned short lp_advertising; /* peer advertised capabilities */
|
unsigned short lp_advertising; /* peer advertised capabilities */
|
||||||
unsigned int speed; /* actual link speed */
|
unsigned int speed; /* actual link speed (Mbps) */
|
||||||
unsigned char fc; /* actual link flow control */
|
unsigned char fc; /* actual link flow control */
|
||||||
unsigned char fec; /* actual FEC */
|
unsigned char fec; /* actual FEC */
|
||||||
unsigned char link_ok; /* link up? */
|
unsigned char link_ok; /* link up? */
|
||||||
|
@ -3727,21 +3727,24 @@ int t4_link_l1cfg(struct adapter *adap, unsigned int mbox, unsigned int port,
|
|||||||
lc->requested_aneg == AUTONEG_DISABLE) {
|
lc->requested_aneg == AUTONEG_DISABLE) {
|
||||||
aneg = 0;
|
aneg = 0;
|
||||||
switch (lc->requested_speed) {
|
switch (lc->requested_speed) {
|
||||||
case 100:
|
case 100000:
|
||||||
speed = FW_PORT_CAP_SPEED_100G;
|
speed = FW_PORT_CAP_SPEED_100G;
|
||||||
break;
|
break;
|
||||||
case 40:
|
case 40000:
|
||||||
speed = FW_PORT_CAP_SPEED_40G;
|
speed = FW_PORT_CAP_SPEED_40G;
|
||||||
break;
|
break;
|
||||||
case 25:
|
case 25000:
|
||||||
speed = FW_PORT_CAP_SPEED_25G;
|
speed = FW_PORT_CAP_SPEED_25G;
|
||||||
break;
|
break;
|
||||||
case 10:
|
case 10000:
|
||||||
speed = FW_PORT_CAP_SPEED_10G;
|
speed = FW_PORT_CAP_SPEED_10G;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1000:
|
||||||
speed = FW_PORT_CAP_SPEED_1G;
|
speed = FW_PORT_CAP_SPEED_1G;
|
||||||
break;
|
break;
|
||||||
|
case 100:
|
||||||
|
speed = FW_PORT_CAP_SPEED_100M;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
break;
|
break;
|
||||||
@ -7715,9 +7718,9 @@ static void handle_port_info(struct port_info *pi, const struct fw_port_info *p)
|
|||||||
|
|
||||||
fec = 0;
|
fec = 0;
|
||||||
if (lc->advertising & FW_PORT_CAP_FEC_RS)
|
if (lc->advertising & FW_PORT_CAP_FEC_RS)
|
||||||
fec |= FEC_RS;
|
fec = FEC_RS;
|
||||||
if (lc->advertising & FW_PORT_CAP_FEC_BASER_RS)
|
else if (lc->advertising & FW_PORT_CAP_FEC_BASER_RS)
|
||||||
fec |= FEC_BASER_RS;
|
fec = FEC_BASER_RS;
|
||||||
lc->fec = fec;
|
lc->fec = fec;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7778,14 +7781,16 @@ int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
lc = &pi->link_cfg;
|
lc = &pi->link_cfg;
|
||||||
|
PORT_LOCK(pi);
|
||||||
old_lc = &pi->old_link_cfg;
|
old_lc = &pi->old_link_cfg;
|
||||||
old_ptype = pi->port_type;
|
old_ptype = pi->port_type;
|
||||||
old_mtype = pi->mod_type;
|
old_mtype = pi->mod_type;
|
||||||
|
|
||||||
handle_port_info(pi, &p->u.info);
|
handle_port_info(pi, &p->u.info);
|
||||||
|
PORT_UNLOCK(pi);
|
||||||
if (old_ptype != pi->port_type || old_mtype != pi->mod_type) {
|
if (old_ptype != pi->port_type || old_mtype != pi->mod_type) {
|
||||||
t4_os_portmod_changed(pi);
|
t4_os_portmod_changed(pi);
|
||||||
}
|
}
|
||||||
|
PORT_LOCK(pi);
|
||||||
if (old_lc->link_ok != lc->link_ok ||
|
if (old_lc->link_ok != lc->link_ok ||
|
||||||
old_lc->speed != lc->speed ||
|
old_lc->speed != lc->speed ||
|
||||||
old_lc->fec != lc->fec ||
|
old_lc->fec != lc->fec ||
|
||||||
@ -7793,6 +7798,7 @@ int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl)
|
|||||||
t4_os_link_changed(pi);
|
t4_os_link_changed(pi);
|
||||||
*old_lc = *lc;
|
*old_lc = *lc;
|
||||||
}
|
}
|
||||||
|
PORT_UNLOCK(pi);
|
||||||
} else {
|
} else {
|
||||||
CH_WARN_RATELIMIT(adap, "Unknown firmware reply %d\n", opcode);
|
CH_WARN_RATELIMIT(adap, "Unknown firmware reply %d\n", opcode);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -2087,68 +2087,210 @@ cxgbe_media_change(struct ifnet *ifp)
|
|||||||
return (EOPNOTSUPP);
|
return (EOPNOTSUPP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mbps to FW_PORT_CAP_SPEED_* bit.
|
||||||
|
*/
|
||||||
|
static uint16_t
|
||||||
|
speed_to_fwspeed(int speed)
|
||||||
|
{
|
||||||
|
|
||||||
|
switch (speed) {
|
||||||
|
case 100000:
|
||||||
|
return (FW_PORT_CAP_SPEED_100G);
|
||||||
|
case 40000:
|
||||||
|
return (FW_PORT_CAP_SPEED_40G);
|
||||||
|
case 25000:
|
||||||
|
return (FW_PORT_CAP_SPEED_25G);
|
||||||
|
case 10000:
|
||||||
|
return (FW_PORT_CAP_SPEED_10G);
|
||||||
|
case 1000:
|
||||||
|
return (FW_PORT_CAP_SPEED_1G);
|
||||||
|
case 100:
|
||||||
|
return (FW_PORT_CAP_SPEED_100M);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Base media word (without ETHER, pause, link active, etc.) for the port at the
|
||||||
|
* given speed.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
port_mword(struct port_info *pi, uint16_t speed)
|
||||||
|
{
|
||||||
|
|
||||||
|
MPASS(speed & M_FW_PORT_CAP_SPEED);
|
||||||
|
MPASS(powerof2(speed));
|
||||||
|
|
||||||
|
switch(pi->port_type) {
|
||||||
|
case FW_PORT_TYPE_BT_SGMII:
|
||||||
|
case FW_PORT_TYPE_BT_XFI:
|
||||||
|
case FW_PORT_TYPE_BT_XAUI:
|
||||||
|
/* BaseT */
|
||||||
|
switch (speed) {
|
||||||
|
case FW_PORT_CAP_SPEED_100M:
|
||||||
|
return (IFM_100_T);
|
||||||
|
case FW_PORT_CAP_SPEED_1G:
|
||||||
|
return (IFM_1000_T);
|
||||||
|
case FW_PORT_CAP_SPEED_10G:
|
||||||
|
return (IFM_10G_T);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FW_PORT_TYPE_KX4:
|
||||||
|
if (speed == FW_PORT_CAP_SPEED_10G)
|
||||||
|
return (IFM_10G_KX4);
|
||||||
|
break;
|
||||||
|
case FW_PORT_TYPE_CX4:
|
||||||
|
if (speed == FW_PORT_CAP_SPEED_10G)
|
||||||
|
return (IFM_10G_CX4);
|
||||||
|
break;
|
||||||
|
case FW_PORT_TYPE_KX:
|
||||||
|
if (speed == FW_PORT_CAP_SPEED_1G)
|
||||||
|
return (IFM_1000_KX);
|
||||||
|
break;
|
||||||
|
case FW_PORT_TYPE_KR:
|
||||||
|
case FW_PORT_TYPE_BP_AP:
|
||||||
|
case FW_PORT_TYPE_BP4_AP:
|
||||||
|
case FW_PORT_TYPE_BP40_BA:
|
||||||
|
case FW_PORT_TYPE_KR4_100G:
|
||||||
|
case FW_PORT_TYPE_KR_SFP28:
|
||||||
|
case FW_PORT_TYPE_KR_XLAUI:
|
||||||
|
switch (speed) {
|
||||||
|
case FW_PORT_CAP_SPEED_1G:
|
||||||
|
return (IFM_1000_KX);
|
||||||
|
case FW_PORT_CAP_SPEED_10G:
|
||||||
|
return (IFM_10G_KR);
|
||||||
|
case FW_PORT_CAP_SPEED_25G:
|
||||||
|
return (IFM_25G_KR);
|
||||||
|
case FW_PORT_CAP_SPEED_40G:
|
||||||
|
return (IFM_40G_KR4);
|
||||||
|
case FW_PORT_CAP_SPEED_100G:
|
||||||
|
return (IFM_100G_KR4);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FW_PORT_TYPE_FIBER_XFI:
|
||||||
|
case FW_PORT_TYPE_FIBER_XAUI:
|
||||||
|
case FW_PORT_TYPE_SFP:
|
||||||
|
case FW_PORT_TYPE_QSFP_10G:
|
||||||
|
case FW_PORT_TYPE_QSA:
|
||||||
|
case FW_PORT_TYPE_QSFP:
|
||||||
|
case FW_PORT_TYPE_CR4_QSFP:
|
||||||
|
case FW_PORT_TYPE_CR_QSFP:
|
||||||
|
case FW_PORT_TYPE_CR2_QSFP:
|
||||||
|
case FW_PORT_TYPE_SFP28:
|
||||||
|
/* Pluggable transceiver */
|
||||||
|
switch (pi->mod_type) {
|
||||||
|
case FW_PORT_MOD_TYPE_LR:
|
||||||
|
switch (speed) {
|
||||||
|
case FW_PORT_CAP_SPEED_1G:
|
||||||
|
return (IFM_1000_LX);
|
||||||
|
case FW_PORT_CAP_SPEED_10G:
|
||||||
|
return (IFM_10G_LR);
|
||||||
|
case FW_PORT_CAP_SPEED_25G:
|
||||||
|
return (IFM_25G_LR);
|
||||||
|
case FW_PORT_CAP_SPEED_40G:
|
||||||
|
return (IFM_40G_LR4);
|
||||||
|
case FW_PORT_CAP_SPEED_100G:
|
||||||
|
return (IFM_100G_LR4);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FW_PORT_MOD_TYPE_SR:
|
||||||
|
switch (speed) {
|
||||||
|
case FW_PORT_CAP_SPEED_1G:
|
||||||
|
return (IFM_1000_SX);
|
||||||
|
case FW_PORT_CAP_SPEED_10G:
|
||||||
|
return (IFM_10G_SR);
|
||||||
|
case FW_PORT_CAP_SPEED_25G:
|
||||||
|
return (IFM_25G_SR);
|
||||||
|
case FW_PORT_CAP_SPEED_40G:
|
||||||
|
return (IFM_40G_SR4);
|
||||||
|
case FW_PORT_CAP_SPEED_100G:
|
||||||
|
return (IFM_100G_SR4);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FW_PORT_MOD_TYPE_ER:
|
||||||
|
if (speed == FW_PORT_CAP_SPEED_10G)
|
||||||
|
return (IFM_10G_ER);
|
||||||
|
break;
|
||||||
|
case FW_PORT_MOD_TYPE_TWINAX_PASSIVE:
|
||||||
|
case FW_PORT_MOD_TYPE_TWINAX_ACTIVE:
|
||||||
|
switch (speed) {
|
||||||
|
case FW_PORT_CAP_SPEED_1G:
|
||||||
|
return (IFM_1000_CX);
|
||||||
|
case FW_PORT_CAP_SPEED_10G:
|
||||||
|
return (IFM_10G_TWINAX);
|
||||||
|
case FW_PORT_CAP_SPEED_25G:
|
||||||
|
return (IFM_25G_CR);
|
||||||
|
case FW_PORT_CAP_SPEED_40G:
|
||||||
|
return (IFM_40G_CR4);
|
||||||
|
case FW_PORT_CAP_SPEED_100G:
|
||||||
|
return (IFM_100G_CR4);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FW_PORT_MOD_TYPE_LRM:
|
||||||
|
if (speed == FW_PORT_CAP_SPEED_10G)
|
||||||
|
return (IFM_10G_LRM);
|
||||||
|
break;
|
||||||
|
case FW_PORT_MOD_TYPE_NA:
|
||||||
|
MPASS(0); /* Not pluggable? */
|
||||||
|
/* fall throough */
|
||||||
|
case FW_PORT_MOD_TYPE_ERROR:
|
||||||
|
case FW_PORT_MOD_TYPE_UNKNOWN:
|
||||||
|
case FW_PORT_MOD_TYPE_NOTSUPPORTED:
|
||||||
|
break;
|
||||||
|
case FW_PORT_MOD_TYPE_NONE:
|
||||||
|
return (IFM_NONE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FW_PORT_TYPE_NONE:
|
||||||
|
return (IFM_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (IFM_UNKNOWN);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cxgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
|
cxgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
|
||||||
{
|
{
|
||||||
struct vi_info *vi = ifp->if_softc;
|
struct vi_info *vi = ifp->if_softc;
|
||||||
struct port_info *pi = vi->pi;
|
struct port_info *pi = vi->pi;
|
||||||
struct ifmedia_entry *cur;
|
struct adapter *sc = pi->adapter;
|
||||||
struct link_config *lc = &pi->link_cfg;
|
struct link_config *lc = &pi->link_cfg;
|
||||||
|
|
||||||
/*
|
if (begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4med") != 0)
|
||||||
* If all the interfaces are administratively down the firmware does not
|
return;
|
||||||
* report transceiver changes. Refresh port info here so that ifconfig
|
PORT_LOCK(pi);
|
||||||
* displays accurate information at all times.
|
|
||||||
*/
|
if (pi->up_vis == 0) {
|
||||||
if (begin_synchronized_op(pi->adapter, NULL, SLEEP_OK | INTR_OK,
|
/*
|
||||||
"t4med") == 0) {
|
* If all the interfaces are administratively down the firmware
|
||||||
PORT_LOCK(pi);
|
* does not report transceiver changes. Refresh port info here
|
||||||
if (pi->up_vis == 0) {
|
* so that ifconfig displays accurate ifmedia at all times.
|
||||||
t4_update_port_info(pi);
|
* This is the only reason we have a synchronized op in this
|
||||||
build_medialist(pi, &pi->media);
|
* function. Just PORT_LOCK would have been enough otherwise.
|
||||||
}
|
*/
|
||||||
PORT_UNLOCK(pi);
|
t4_update_port_info(pi);
|
||||||
end_synchronized_op(pi->adapter, 0);
|
build_medialist(pi, &pi->media);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ifm_status */
|
||||||
ifmr->ifm_status = IFM_AVALID;
|
ifmr->ifm_status = IFM_AVALID;
|
||||||
if (lc->link_ok == 0)
|
if (lc->link_ok == 0)
|
||||||
return;
|
goto done;
|
||||||
|
|
||||||
ifmr->ifm_status |= IFM_ACTIVE;
|
ifmr->ifm_status |= IFM_ACTIVE;
|
||||||
|
|
||||||
|
/* ifm_active */
|
||||||
|
ifmr->ifm_active = IFM_ETHER;
|
||||||
ifmr->ifm_active &= ~(IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE);
|
ifmr->ifm_active &= ~(IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE);
|
||||||
if (lc->fc & PAUSE_RX)
|
if (lc->fc & PAUSE_RX)
|
||||||
ifmr->ifm_active |= IFM_ETH_RXPAUSE;
|
ifmr->ifm_active |= IFM_ETH_RXPAUSE;
|
||||||
if (lc->fc & PAUSE_TX)
|
if (lc->fc & PAUSE_TX)
|
||||||
ifmr->ifm_active |= IFM_ETH_TXPAUSE;
|
ifmr->ifm_active |= IFM_ETH_TXPAUSE;
|
||||||
|
ifmr->ifm_active |= port_mword(pi, speed_to_fwspeed(lc->speed));
|
||||||
/* active and current will differ iff current media is autoselect. */
|
done:
|
||||||
cur = pi->media.ifm_cur;
|
PORT_UNLOCK(pi);
|
||||||
if (cur != NULL && IFM_SUBTYPE(cur->ifm_media) != IFM_AUTO)
|
end_synchronized_op(sc, 0);
|
||||||
return;
|
|
||||||
|
|
||||||
ifmr->ifm_active = IFM_ETHER | IFM_FDX;
|
|
||||||
if (lc->fc & PAUSE_RX)
|
|
||||||
ifmr->ifm_active |= IFM_ETH_RXPAUSE;
|
|
||||||
if (lc->fc & PAUSE_TX)
|
|
||||||
ifmr->ifm_active |= IFM_ETH_TXPAUSE;
|
|
||||||
switch (lc->speed) {
|
|
||||||
case 10000:
|
|
||||||
ifmr->ifm_active |= IFM_10G_T;
|
|
||||||
break;
|
|
||||||
case 1000:
|
|
||||||
ifmr->ifm_active |= IFM_1000_T;
|
|
||||||
break;
|
|
||||||
case 100:
|
|
||||||
ifmr->ifm_active |= IFM_100_TX;
|
|
||||||
break;
|
|
||||||
case 10:
|
|
||||||
ifmr->ifm_active |= IFM_10_T;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
device_printf(vi->dev, "link up but speed unknown (%u)\n",
|
|
||||||
lc->speed);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -3995,214 +4137,114 @@ t4_set_desc(struct adapter *sc)
|
|||||||
device_set_desc_copy(sc->dev, buf);
|
device_set_desc_copy(sc->dev, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static inline void
|
||||||
build_medialist(struct port_info *pi, struct ifmedia *media)
|
ifmedia_add4(struct ifmedia *media, int m)
|
||||||
{
|
{
|
||||||
int m;
|
|
||||||
|
ifmedia_add(media, m, 0, NULL);
|
||||||
|
ifmedia_add(media, m | IFM_ETH_TXPAUSE, 0, NULL);
|
||||||
|
ifmedia_add(media, m | IFM_ETH_RXPAUSE, 0, NULL);
|
||||||
|
ifmedia_add(media, m | IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_current_media(struct port_info *pi, struct ifmedia *media)
|
||||||
|
{
|
||||||
|
struct link_config *lc;
|
||||||
|
int mword;
|
||||||
|
|
||||||
PORT_LOCK_ASSERT_OWNED(pi);
|
PORT_LOCK_ASSERT_OWNED(pi);
|
||||||
|
|
||||||
ifmedia_removeall(media);
|
/* Leave current media alone if it's already set to IFM_NONE. */
|
||||||
|
if (media->ifm_cur != NULL &&
|
||||||
|
IFM_SUBTYPE(media->ifm_cur->ifm_media) == IFM_NONE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mword = IFM_ETHER;
|
||||||
|
lc = &pi->link_cfg;
|
||||||
|
if (lc->requested_aneg == AUTONEG_ENABLE &&
|
||||||
|
lc->supported & FW_PORT_CAP_ANEG) {
|
||||||
|
ifmedia_set(media, mword | IFM_AUTO);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (lc->requested_fc & PAUSE_TX)
|
||||||
|
mword |= IFM_ETH_TXPAUSE;
|
||||||
|
if (lc->requested_fc & PAUSE_RX)
|
||||||
|
mword |= IFM_ETH_RXPAUSE;
|
||||||
|
mword |= port_mword(pi, speed_to_fwspeed(lc->requested_speed));
|
||||||
|
ifmedia_set(media, mword);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
build_medialist(struct port_info *pi, struct ifmedia *media)
|
||||||
|
{
|
||||||
|
uint16_t ss, speed;
|
||||||
|
int unknown, mword, bit;
|
||||||
|
struct link_config *lc;
|
||||||
|
|
||||||
|
PORT_LOCK_ASSERT_OWNED(pi);
|
||||||
|
|
||||||
|
if (pi->flags & FIXED_IFMEDIA)
|
||||||
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX: Would it be better to ifmedia_add all 4 combinations of pause
|
* First setup all the requested_ fields so that they comply with what's
|
||||||
* settings for every speed instead of just txpause|rxpause? ifconfig
|
* supported by the port + transceiver. Note that this clobbers any
|
||||||
* media display looks much better if autoselect is the only case where
|
* user preferences set via sysctl_pause_settings or sysctl_autoneg.
|
||||||
* ifm_current is different from ifm_active. If the user picks anything
|
|
||||||
* except txpause|rxpause the display is ugly.
|
|
||||||
*/
|
*/
|
||||||
m = IFM_ETHER | IFM_FDX | IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE;
|
init_l1cfg(pi);
|
||||||
|
|
||||||
switch(pi->port_type) {
|
/*
|
||||||
case FW_PORT_TYPE_BT_XFI:
|
* Now (re)build the ifmedia list.
|
||||||
case FW_PORT_TYPE_BT_XAUI:
|
*/
|
||||||
ifmedia_add(media, m | IFM_10G_T, 0, NULL);
|
ifmedia_removeall(media);
|
||||||
/* fall through */
|
lc = &pi->link_cfg;
|
||||||
|
ss = G_FW_PORT_CAP_SPEED(lc->supported); /* Supported Speeds */
|
||||||
case FW_PORT_TYPE_BT_SGMII:
|
if (__predict_false(ss == 0)) { /* not supposed to happen. */
|
||||||
ifmedia_add(media, m | IFM_1000_T, 0, NULL);
|
MPASS(ss != 0);
|
||||||
ifmedia_add(media, m | IFM_100_TX, 0, NULL);
|
no_media:
|
||||||
ifmedia_add(media, IFM_ETHER | IFM_AUTO, 0, NULL);
|
MPASS(LIST_EMPTY(&media->ifm_list));
|
||||||
ifmedia_set(media, IFM_ETHER | IFM_AUTO);
|
ifmedia_add(media, IFM_ETHER | IFM_NONE, 0, NULL);
|
||||||
break;
|
ifmedia_set(media, IFM_ETHER | IFM_NONE);
|
||||||
|
return;
|
||||||
case FW_PORT_TYPE_CX4:
|
|
||||||
ifmedia_add(media, m | IFM_10G_CX4, 0, NULL);
|
|
||||||
ifmedia_set(media, m | IFM_10G_CX4);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FW_PORT_TYPE_QSFP_10G:
|
|
||||||
case FW_PORT_TYPE_SFP:
|
|
||||||
case FW_PORT_TYPE_FIBER_XFI:
|
|
||||||
case FW_PORT_TYPE_FIBER_XAUI:
|
|
||||||
switch (pi->mod_type) {
|
|
||||||
|
|
||||||
case FW_PORT_MOD_TYPE_LR:
|
|
||||||
ifmedia_add(media, m | IFM_10G_LR, 0, NULL);
|
|
||||||
ifmedia_set(media, m | IFM_10G_LR);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FW_PORT_MOD_TYPE_SR:
|
|
||||||
ifmedia_add(media, m | IFM_10G_SR, 0, NULL);
|
|
||||||
ifmedia_set(media, m | IFM_10G_SR);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FW_PORT_MOD_TYPE_LRM:
|
|
||||||
ifmedia_add(media, m | IFM_10G_LRM, 0, NULL);
|
|
||||||
ifmedia_set(media, m | IFM_10G_LRM);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FW_PORT_MOD_TYPE_TWINAX_PASSIVE:
|
|
||||||
case FW_PORT_MOD_TYPE_TWINAX_ACTIVE:
|
|
||||||
ifmedia_add(media, m | IFM_10G_TWINAX, 0, NULL);
|
|
||||||
ifmedia_set(media, m | IFM_10G_TWINAX);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FW_PORT_MOD_TYPE_NONE:
|
|
||||||
m &= ~IFM_FDX;
|
|
||||||
ifmedia_add(media, m | IFM_NONE, 0, NULL);
|
|
||||||
ifmedia_set(media, m | IFM_NONE);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FW_PORT_MOD_TYPE_NA:
|
|
||||||
case FW_PORT_MOD_TYPE_ER:
|
|
||||||
default:
|
|
||||||
device_printf(pi->dev,
|
|
||||||
"unknown port_type (%d), mod_type (%d)\n",
|
|
||||||
pi->port_type, pi->mod_type);
|
|
||||||
ifmedia_add(media, m | IFM_UNKNOWN, 0, NULL);
|
|
||||||
ifmedia_set(media, m | IFM_UNKNOWN);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FW_PORT_TYPE_CR_QSFP:
|
|
||||||
case FW_PORT_TYPE_SFP28:
|
|
||||||
case FW_PORT_TYPE_KR_SFP28:
|
|
||||||
switch (pi->mod_type) {
|
|
||||||
|
|
||||||
case FW_PORT_MOD_TYPE_SR:
|
|
||||||
ifmedia_add(media, m | IFM_25G_SR, 0, NULL);
|
|
||||||
ifmedia_set(media, m | IFM_25G_SR);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FW_PORT_MOD_TYPE_TWINAX_PASSIVE:
|
|
||||||
case FW_PORT_MOD_TYPE_TWINAX_ACTIVE:
|
|
||||||
ifmedia_add(media, m | IFM_25G_CR, 0, NULL);
|
|
||||||
ifmedia_set(media, m | IFM_25G_CR);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FW_PORT_MOD_TYPE_NONE:
|
|
||||||
m &= ~IFM_FDX;
|
|
||||||
ifmedia_add(media, m | IFM_NONE, 0, NULL);
|
|
||||||
ifmedia_set(media, m | IFM_NONE);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
device_printf(pi->dev,
|
|
||||||
"unknown port_type (%d), mod_type (%d)\n",
|
|
||||||
pi->port_type, pi->mod_type);
|
|
||||||
ifmedia_add(media, m | IFM_UNKNOWN, 0, NULL);
|
|
||||||
ifmedia_set(media, m | IFM_UNKNOWN);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FW_PORT_TYPE_QSFP:
|
|
||||||
switch (pi->mod_type) {
|
|
||||||
|
|
||||||
case FW_PORT_MOD_TYPE_LR:
|
|
||||||
ifmedia_add(media, m | IFM_40G_LR4, 0, NULL);
|
|
||||||
ifmedia_set(media, m | IFM_40G_LR4);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FW_PORT_MOD_TYPE_SR:
|
|
||||||
ifmedia_add(media, m | IFM_40G_SR4, 0, NULL);
|
|
||||||
ifmedia_set(media, m | IFM_40G_SR4);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FW_PORT_MOD_TYPE_TWINAX_PASSIVE:
|
|
||||||
case FW_PORT_MOD_TYPE_TWINAX_ACTIVE:
|
|
||||||
ifmedia_add(media, m | IFM_40G_CR4, 0, NULL);
|
|
||||||
ifmedia_set(media, m | IFM_40G_CR4);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FW_PORT_MOD_TYPE_NONE:
|
|
||||||
m &= ~IFM_FDX;
|
|
||||||
ifmedia_add(media, m | IFM_NONE, 0, NULL);
|
|
||||||
ifmedia_set(media, m | IFM_NONE);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
device_printf(pi->dev,
|
|
||||||
"unknown port_type (%d), mod_type (%d)\n",
|
|
||||||
pi->port_type, pi->mod_type);
|
|
||||||
ifmedia_add(media, m | IFM_UNKNOWN, 0, NULL);
|
|
||||||
ifmedia_set(media, m | IFM_UNKNOWN);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FW_PORT_TYPE_KR4_100G:
|
|
||||||
case FW_PORT_TYPE_CR4_QSFP:
|
|
||||||
switch (pi->mod_type) {
|
|
||||||
|
|
||||||
case FW_PORT_MOD_TYPE_LR:
|
|
||||||
ifmedia_add(media, m | IFM_100G_LR4, 0, NULL);
|
|
||||||
ifmedia_set(media, m | IFM_100G_LR4);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FW_PORT_MOD_TYPE_SR:
|
|
||||||
ifmedia_add(media, m | IFM_100G_SR4, 0, NULL);
|
|
||||||
ifmedia_set(media, m | IFM_100G_SR4);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FW_PORT_MOD_TYPE_TWINAX_PASSIVE:
|
|
||||||
case FW_PORT_MOD_TYPE_TWINAX_ACTIVE:
|
|
||||||
ifmedia_add(media, m | IFM_100G_CR4, 0, NULL);
|
|
||||||
ifmedia_set(media, m | IFM_100G_CR4);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FW_PORT_MOD_TYPE_NONE:
|
|
||||||
m &= ~IFM_FDX;
|
|
||||||
ifmedia_add(media, m | IFM_NONE, 0, NULL);
|
|
||||||
ifmedia_set(media, m | IFM_NONE);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
device_printf(pi->dev,
|
|
||||||
"unknown port_type (%d), mod_type (%d)\n",
|
|
||||||
pi->port_type, pi->mod_type);
|
|
||||||
ifmedia_add(media, m | IFM_UNKNOWN, 0, NULL);
|
|
||||||
ifmedia_set(media, m | IFM_UNKNOWN);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
device_printf(pi->dev,
|
|
||||||
"unknown port_type (%d), mod_type (%d)\n", pi->port_type,
|
|
||||||
pi->mod_type);
|
|
||||||
ifmedia_add(media, m | IFM_UNKNOWN, 0, NULL);
|
|
||||||
ifmedia_set(media, m | IFM_UNKNOWN);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unknown = 0;
|
||||||
|
for (bit = 0; bit < fls(ss); bit++) {
|
||||||
|
speed = 1 << bit;
|
||||||
|
MPASS(speed & M_FW_PORT_CAP_SPEED);
|
||||||
|
if (ss & speed) {
|
||||||
|
mword = port_mword(pi, speed);
|
||||||
|
if (mword == IFM_NONE) {
|
||||||
|
goto no_media;
|
||||||
|
} else if (mword == IFM_UNKNOWN)
|
||||||
|
unknown++;
|
||||||
|
else
|
||||||
|
ifmedia_add4(media, IFM_ETHER | mword);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (unknown > 0) /* Add one unknown for all unknown media types. */
|
||||||
|
ifmedia_add4(media, IFM_ETHER | IFM_UNKNOWN);
|
||||||
|
if (lc->supported & FW_PORT_CAP_ANEG)
|
||||||
|
ifmedia_add(media, IFM_ETHER | IFM_AUTO, 0, NULL);
|
||||||
|
|
||||||
|
set_current_media(pi, media);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update all the requested_* fields in the link config and then send a mailbox
|
* Update all the requested_* fields in the link config to something valid (and
|
||||||
* command to apply the settings.
|
* reasonable).
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
init_l1cfg(struct port_info *pi)
|
init_l1cfg(struct port_info *pi)
|
||||||
{
|
{
|
||||||
struct adapter *sc = pi->adapter;
|
|
||||||
struct link_config *lc = &pi->link_cfg;
|
struct link_config *lc = &pi->link_cfg;
|
||||||
int rc;
|
|
||||||
|
|
||||||
ASSERT_SYNCHRONIZED_OP(sc);
|
PORT_LOCK_ASSERT_OWNED(pi);
|
||||||
|
|
||||||
|
/* Gbps -> Mbps */
|
||||||
|
lc->requested_speed = port_top_speed(pi) * 1000;
|
||||||
|
|
||||||
lc->requested_speed = port_top_speed(pi); /* in Gbps */
|
|
||||||
if (t4_autoneg != 0 && lc->supported & FW_PORT_CAP_ANEG) {
|
if (t4_autoneg != 0 && lc->supported & FW_PORT_CAP_ANEG) {
|
||||||
lc->requested_aneg = AUTONEG_ENABLE;
|
lc->requested_aneg = AUTONEG_ENABLE;
|
||||||
} else {
|
} else {
|
||||||
@ -4212,18 +4254,58 @@ init_l1cfg(struct port_info *pi)
|
|||||||
lc->requested_fc = t4_pause_settings & (PAUSE_TX | PAUSE_RX);
|
lc->requested_fc = t4_pause_settings & (PAUSE_TX | PAUSE_RX);
|
||||||
|
|
||||||
if (t4_fec != -1) {
|
if (t4_fec != -1) {
|
||||||
lc->requested_fec = t4_fec & (FEC_RS | FEC_BASER_RS |
|
if (t4_fec & FEC_RS && lc->supported & FW_PORT_CAP_FEC_RS) {
|
||||||
FEC_RESERVED);
|
lc->requested_fec = FEC_RS;
|
||||||
|
} else if (t4_fec & FEC_BASER_RS &&
|
||||||
|
lc->supported & FW_PORT_CAP_FEC_BASER_RS) {
|
||||||
|
lc->requested_fec = FEC_BASER_RS;
|
||||||
|
} else {
|
||||||
|
lc->requested_fec = 0;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Use the suggested value provided by the firmware in acaps */
|
/* Use the suggested value provided by the firmware in acaps */
|
||||||
if (lc->advertising & FW_PORT_CAP_FEC_RS)
|
if (lc->advertising & FW_PORT_CAP_FEC_RS &&
|
||||||
|
lc->supported & FW_PORT_CAP_FEC_RS) {
|
||||||
lc->requested_fec = FEC_RS;
|
lc->requested_fec = FEC_RS;
|
||||||
else if (lc->advertising & FW_PORT_CAP_FEC_BASER_RS)
|
} else if (lc->advertising & FW_PORT_CAP_FEC_BASER_RS &&
|
||||||
|
lc->supported & FW_PORT_CAP_FEC_BASER_RS) {
|
||||||
lc->requested_fec = FEC_BASER_RS;
|
lc->requested_fec = FEC_BASER_RS;
|
||||||
else
|
} else {
|
||||||
lc->requested_fec = 0;
|
lc->requested_fec = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Apply the settings in requested_* to the hardware. The parameters are
|
||||||
|
* expected to be sane.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
apply_l1cfg(struct port_info *pi)
|
||||||
|
{
|
||||||
|
struct adapter *sc = pi->adapter;
|
||||||
|
struct link_config *lc = &pi->link_cfg;
|
||||||
|
int rc;
|
||||||
|
#ifdef INVARIANTS
|
||||||
|
uint16_t fwspeed;
|
||||||
|
|
||||||
|
ASSERT_SYNCHRONIZED_OP(sc);
|
||||||
|
PORT_LOCK_ASSERT_OWNED(pi);
|
||||||
|
|
||||||
|
if (lc->requested_aneg == AUTONEG_ENABLE)
|
||||||
|
MPASS(lc->supported & FW_PORT_CAP_ANEG);
|
||||||
|
if (lc->requested_fc & PAUSE_TX)
|
||||||
|
MPASS(lc->supported & FW_PORT_CAP_FC_TX);
|
||||||
|
if (lc->requested_fc & PAUSE_RX)
|
||||||
|
MPASS(lc->supported & FW_PORT_CAP_FC_RX);
|
||||||
|
if (lc->requested_fec == FEC_RS)
|
||||||
|
MPASS(lc->supported & FW_PORT_CAP_FEC_RS);
|
||||||
|
if (lc->requested_fec == FEC_BASER_RS)
|
||||||
|
MPASS(lc->supported & FW_PORT_CAP_FEC_BASER_RS);
|
||||||
|
fwspeed = speed_to_fwspeed(lc->requested_speed);
|
||||||
|
MPASS(fwspeed != 0);
|
||||||
|
MPASS(lc->supported & fwspeed);
|
||||||
|
#endif
|
||||||
rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc);
|
rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
device_printf(pi->dev, "l1cfg failed: %d\n", rc);
|
device_printf(pi->dev, "l1cfg failed: %d\n", rc);
|
||||||
@ -4231,6 +4313,7 @@ init_l1cfg(struct port_info *pi)
|
|||||||
lc->fc = lc->requested_fc;
|
lc->fc = lc->requested_fc;
|
||||||
lc->fec = lc->requested_fec;
|
lc->fec = lc->requested_fec;
|
||||||
}
|
}
|
||||||
|
return (rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define FW_MAC_EXACT_CHUNK 7
|
#define FW_MAC_EXACT_CHUNK 7
|
||||||
@ -4515,7 +4598,7 @@ cxgbe_init_synchronized(struct vi_info *vi)
|
|||||||
if (pi->up_vis++ == 0) {
|
if (pi->up_vis++ == 0) {
|
||||||
t4_update_port_info(pi);
|
t4_update_port_info(pi);
|
||||||
build_medialist(pi, &pi->media);
|
build_medialist(pi, &pi->media);
|
||||||
init_l1cfg(pi);
|
apply_l1cfg(pi);
|
||||||
}
|
}
|
||||||
ifp->if_drv_flags |= IFF_DRV_RUNNING;
|
ifp->if_drv_flags |= IFF_DRV_RUNNING;
|
||||||
|
|
||||||
@ -4590,13 +4673,13 @@ cxgbe_uninit_synchronized(struct vi_info *vi)
|
|||||||
PORT_UNLOCK(pi);
|
PORT_UNLOCK(pi);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
PORT_UNLOCK(pi);
|
|
||||||
|
|
||||||
pi->link_cfg.link_ok = 0;
|
pi->link_cfg.link_ok = 0;
|
||||||
pi->link_cfg.speed = 0;
|
pi->link_cfg.speed = 0;
|
||||||
pi->link_cfg.link_down_rc = 255;
|
pi->link_cfg.link_down_rc = 255;
|
||||||
t4_os_link_changed(pi);
|
t4_os_link_changed(pi);
|
||||||
pi->old_link_cfg = pi->link_cfg;
|
pi->old_link_cfg = pi->link_cfg;
|
||||||
|
PORT_UNLOCK(pi);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -6346,14 +6429,17 @@ sysctl_pause_settings(SYSCTL_HANDLER_ARGS)
|
|||||||
"t4PAUSE");
|
"t4PAUSE");
|
||||||
if (rc)
|
if (rc)
|
||||||
return (rc);
|
return (rc);
|
||||||
|
PORT_LOCK(pi);
|
||||||
if ((lc->requested_fc & (PAUSE_TX | PAUSE_RX)) != n) {
|
if ((lc->requested_fc & (PAUSE_TX | PAUSE_RX)) != n) {
|
||||||
lc->requested_fc &= ~(PAUSE_TX | PAUSE_RX);
|
lc->requested_fc &= ~(PAUSE_TX | PAUSE_RX);
|
||||||
lc->requested_fc |= n;
|
lc->requested_fc |= n;
|
||||||
rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc);
|
rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc);
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
lc->fc = lc->requested_fc;
|
lc->fc = lc->requested_fc;
|
||||||
|
set_current_media(pi, &pi->media);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PORT_UNLOCK(pi);
|
||||||
end_synchronized_op(sc, 0);
|
end_synchronized_op(sc, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6401,11 +6487,14 @@ sysctl_fec(SYSCTL_HANDLER_ARGS)
|
|||||||
n = s[0] - '0';
|
n = s[0] - '0';
|
||||||
if (n & ~M_FW_PORT_CAP_FEC)
|
if (n & ~M_FW_PORT_CAP_FEC)
|
||||||
return (EINVAL); /* some other bit is set too */
|
return (EINVAL); /* some other bit is set too */
|
||||||
|
if (!powerof2(n))
|
||||||
|
return (EINVAL); /* one bit can be set at most */
|
||||||
|
|
||||||
rc = begin_synchronized_op(sc, &pi->vi[0], SLEEP_OK | INTR_OK,
|
rc = begin_synchronized_op(sc, &pi->vi[0], SLEEP_OK | INTR_OK,
|
||||||
"t4fec");
|
"t4fec");
|
||||||
if (rc)
|
if (rc)
|
||||||
return (rc);
|
return (rc);
|
||||||
|
PORT_LOCK(pi);
|
||||||
if ((lc->requested_fec & M_FW_PORT_CAP_FEC) != n) {
|
if ((lc->requested_fec & M_FW_PORT_CAP_FEC) != n) {
|
||||||
lc->requested_fec = n &
|
lc->requested_fec = n &
|
||||||
G_FW_PORT_CAP_FEC(lc->supported);
|
G_FW_PORT_CAP_FEC(lc->supported);
|
||||||
@ -6414,6 +6503,7 @@ sysctl_fec(SYSCTL_HANDLER_ARGS)
|
|||||||
lc->fec = lc->requested_fec;
|
lc->fec = lc->requested_fec;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PORT_UNLOCK(pi);
|
||||||
end_synchronized_op(sc, 0);
|
end_synchronized_op(sc, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6435,27 +6525,35 @@ sysctl_autoneg(SYSCTL_HANDLER_ARGS)
|
|||||||
rc = sysctl_handle_int(oidp, &val, 0, req);
|
rc = sysctl_handle_int(oidp, &val, 0, req);
|
||||||
if (rc != 0 || req->newptr == NULL)
|
if (rc != 0 || req->newptr == NULL)
|
||||||
return (rc);
|
return (rc);
|
||||||
if ((lc->supported & FW_PORT_CAP_ANEG) == 0)
|
|
||||||
return (ENOTSUP);
|
|
||||||
|
|
||||||
if (val == 0)
|
if (val == 0)
|
||||||
val = AUTONEG_DISABLE;
|
val = AUTONEG_DISABLE;
|
||||||
else if (val == 1)
|
else if (val == 1)
|
||||||
val = AUTONEG_ENABLE;
|
val = AUTONEG_ENABLE;
|
||||||
else
|
else
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
if (lc->requested_aneg == val)
|
|
||||||
return (0); /* no change */
|
|
||||||
|
|
||||||
rc = begin_synchronized_op(sc, &pi->vi[0], SLEEP_OK | INTR_OK,
|
rc = begin_synchronized_op(sc, &pi->vi[0], SLEEP_OK | INTR_OK,
|
||||||
"t4aneg");
|
"t4aneg");
|
||||||
if (rc)
|
if (rc)
|
||||||
return (rc);
|
return (rc);
|
||||||
|
PORT_LOCK(pi);
|
||||||
|
if ((lc->supported & FW_PORT_CAP_ANEG) == 0) {
|
||||||
|
rc = ENOTSUP;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (lc->requested_aneg == val) {
|
||||||
|
rc = 0; /* no change, do nothing. */
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
old = lc->requested_aneg;
|
old = lc->requested_aneg;
|
||||||
lc->requested_aneg = val;
|
lc->requested_aneg = val;
|
||||||
rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc);
|
rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc);
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
lc->requested_aneg = old;
|
lc->requested_aneg = old;
|
||||||
|
else
|
||||||
|
set_current_media(pi, &pi->media);
|
||||||
|
done:
|
||||||
|
PORT_UNLOCK(pi);
|
||||||
end_synchronized_op(sc, 0);
|
end_synchronized_op(sc, 0);
|
||||||
return (rc);
|
return (rc);
|
||||||
}
|
}
|
||||||
@ -9192,12 +9290,14 @@ t4_os_portmod_changed(struct port_info *pi)
|
|||||||
NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX", "LRM"
|
NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX", "LRM"
|
||||||
};
|
};
|
||||||
|
|
||||||
PORT_LOCK(pi);
|
MPASS((pi->flags & FIXED_IFMEDIA) == 0);
|
||||||
build_medialist(pi, &pi->media);
|
|
||||||
PORT_UNLOCK(pi);
|
|
||||||
vi = &pi->vi[0];
|
vi = &pi->vi[0];
|
||||||
if (begin_synchronized_op(sc, vi, HOLD_LOCK, "t4mod") == 0) {
|
if (begin_synchronized_op(sc, vi, HOLD_LOCK, "t4mod") == 0) {
|
||||||
init_l1cfg(pi);
|
PORT_LOCK(pi);
|
||||||
|
build_medialist(pi, &pi->media);
|
||||||
|
apply_l1cfg(pi);
|
||||||
|
PORT_UNLOCK(pi);
|
||||||
end_synchronized_op(sc, LOCK_HELD);
|
end_synchronized_op(sc, LOCK_HELD);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9225,6 +9325,8 @@ t4_os_link_changed(struct port_info *pi)
|
|||||||
struct link_config *lc;
|
struct link_config *lc;
|
||||||
int v;
|
int v;
|
||||||
|
|
||||||
|
PORT_LOCK_ASSERT_OWNED(pi);
|
||||||
|
|
||||||
for_each_vi(pi, v, vi) {
|
for_each_vi(pi, v, vi) {
|
||||||
ifp = vi->ifp;
|
ifp = vi->ifp;
|
||||||
if (ifp == NULL)
|
if (ifp == NULL)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user