cxgbe(4): Various link/media related improvements.
- Deal with changes to port_type, and not just port_mod when a transceiver is changed. This fixes hot swapping of transceivers of different types (QSFP+ or QSA or QSFP28 in a QSFP28 port, SFP+ or SFP28 in a SFP28 port, etc.). - Always refresh media information for ifconfig if the port is down. The firmware does not generate tranceiver-change interrupts unless at least one VI is enabled on the physical port. Before this change ifconfig diplayed potentially stale information for ports that were administratively down. - Always recalculate and reapply L1 config on a transceiver change. - Display PAUSE settings in ifconfig. The driver sysctls for this continue to work as well. MFC after: 2 weeks Sponsored by: Chelsio Communications
This commit is contained in:
parent
f7afe7679c
commit
01285747aa
@ -1036,10 +1036,10 @@ adap2pinfo(struct adapter *sc, int idx)
|
||||
}
|
||||
|
||||
static inline void
|
||||
t4_os_set_hw_addr(struct adapter *sc, int idx, uint8_t hw_addr[])
|
||||
t4_os_set_hw_addr(struct port_info *pi, uint8_t hw_addr[])
|
||||
{
|
||||
|
||||
bcopy(hw_addr, sc->port[idx]->vi[0].hw_addr, ETHER_ADDR_LEN);
|
||||
bcopy(hw_addr, pi->vi[0].hw_addr, ETHER_ADDR_LEN);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
@ -1088,24 +1088,6 @@ port_top_speed(const struct port_info *pi)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static inline int
|
||||
port_top_speed_raw(const struct port_info *pi)
|
||||
{
|
||||
|
||||
if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_100G)
|
||||
return (FW_PORT_CAP_SPEED_100G);
|
||||
if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_40G)
|
||||
return (FW_PORT_CAP_SPEED_40G);
|
||||
if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_25G)
|
||||
return (FW_PORT_CAP_SPEED_25G);
|
||||
if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_10G)
|
||||
return (FW_PORT_CAP_SPEED_10G);
|
||||
if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_1G)
|
||||
return (FW_PORT_CAP_SPEED_1G);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static inline int
|
||||
tx_resume_threshold(struct sge_eq *eq)
|
||||
{
|
||||
@ -1142,8 +1124,8 @@ extern device_method_t cxgbe_methods[];
|
||||
int t4_os_find_pci_capability(struct adapter *, int);
|
||||
int t4_os_pci_save_state(struct adapter *);
|
||||
int t4_os_pci_restore_state(struct adapter *);
|
||||
void t4_os_portmod_changed(const struct adapter *, int);
|
||||
void t4_os_link_changed(struct adapter *, int, int);
|
||||
void t4_os_portmod_changed(struct port_info *, int, int, struct link_config *);
|
||||
void t4_os_link_changed(struct port_info *, struct link_config *);
|
||||
void t4_iterate(void (*)(struct adapter *, void *), void *);
|
||||
void t4_init_devnames(struct adapter *);
|
||||
void t4_add_adapter(struct adapter *);
|
||||
|
@ -399,16 +399,18 @@ struct trace_params {
|
||||
};
|
||||
|
||||
struct link_config {
|
||||
/* OS-specific code owns all the requested_* fields */
|
||||
unsigned char requested_aneg; /* link aneg user has requested */
|
||||
unsigned char requested_fc; /* flow control user has requested */
|
||||
unsigned char requested_fec; /* FEC user has requested */
|
||||
unsigned int requested_speed; /* speed user has requested */
|
||||
|
||||
unsigned short supported; /* link capabilities */
|
||||
unsigned short advertising; /* advertised capabilities */
|
||||
unsigned short lp_advertising; /* peer advertised capabilities */
|
||||
unsigned int requested_speed; /* speed user has requested */
|
||||
unsigned int speed; /* actual link speed */
|
||||
unsigned char requested_fc; /* flow control user has requested */
|
||||
unsigned char fc; /* actual link flow control */
|
||||
unsigned char requested_fec; /* FEC user has requested */
|
||||
unsigned char fec; /* actual FEC */
|
||||
unsigned char autoneg; /* autonegotiating? */
|
||||
unsigned char link_ok; /* link up? */
|
||||
unsigned char link_down_rc; /* link down reason */
|
||||
};
|
||||
@ -766,6 +768,7 @@ int t4_sge_ctxt_rd_bd(struct adapter *adap, unsigned int cid, enum ctxt_type cty
|
||||
u32 *data);
|
||||
int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox);
|
||||
const char *t4_link_down_rc_str(unsigned char link_down_rc);
|
||||
int t4_update_port_info(struct port_info *pi);
|
||||
int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl);
|
||||
int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox, u32 addr, u32 val);
|
||||
int t4_sched_config(struct adapter *adapter, int type, int minmaxen,
|
||||
|
@ -3683,9 +3683,6 @@ void t4_ulprx_read_la(struct adapter *adap, u32 *la_buf)
|
||||
}
|
||||
}
|
||||
|
||||
#define ADVERT_MASK (V_FW_PORT_CAP_SPEED(M_FW_PORT_CAP_SPEED) | \
|
||||
FW_PORT_CAP_ANEG)
|
||||
|
||||
/**
|
||||
* t4_link_l1cfg - apply link configuration to MAC/PHY
|
||||
* @phy: the PHY to setup
|
||||
@ -3704,7 +3701,7 @@ int t4_link_l1cfg(struct adapter *adap, unsigned int mbox, unsigned int port,
|
||||
{
|
||||
struct fw_port_cmd c;
|
||||
unsigned int mdi = V_FW_PORT_CAP_MDI(FW_PORT_CAP_MDI_AUTO);
|
||||
unsigned int fc, fec;
|
||||
unsigned int aneg, fc, fec, speed;
|
||||
|
||||
fc = 0;
|
||||
if (lc->requested_fc & PAUSE_RX)
|
||||
@ -3714,11 +3711,40 @@ int t4_link_l1cfg(struct adapter *adap, unsigned int mbox, unsigned int port,
|
||||
|
||||
fec = 0;
|
||||
if (lc->requested_fec & FEC_RS)
|
||||
fec |= FW_PORT_CAP_FEC_RS;
|
||||
if (lc->requested_fec & FEC_BASER_RS)
|
||||
fec |= FW_PORT_CAP_FEC_BASER_RS;
|
||||
if (lc->requested_fec & FEC_RESERVED)
|
||||
fec |= FW_PORT_CAP_FEC_RESERVED;
|
||||
fec = FW_PORT_CAP_FEC_RS;
|
||||
else if (lc->requested_fec & FEC_BASER_RS)
|
||||
fec = FW_PORT_CAP_FEC_BASER_RS;
|
||||
else if (lc->requested_fec & FEC_RESERVED)
|
||||
fec = FW_PORT_CAP_FEC_RESERVED;
|
||||
|
||||
if (!(lc->supported & FW_PORT_CAP_ANEG) ||
|
||||
lc->requested_aneg == AUTONEG_DISABLE) {
|
||||
aneg = 0;
|
||||
switch (lc->requested_speed) {
|
||||
case 100:
|
||||
speed = FW_PORT_CAP_SPEED_100G;
|
||||
break;
|
||||
case 40:
|
||||
speed = FW_PORT_CAP_SPEED_40G;
|
||||
break;
|
||||
case 25:
|
||||
speed = FW_PORT_CAP_SPEED_25G;
|
||||
break;
|
||||
case 10:
|
||||
speed = FW_PORT_CAP_SPEED_10G;
|
||||
break;
|
||||
case 1:
|
||||
speed = FW_PORT_CAP_SPEED_1G;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
aneg = FW_PORT_CAP_ANEG;
|
||||
speed = lc->supported &
|
||||
V_FW_PORT_CAP_SPEED(M_FW_PORT_CAP_SPEED);
|
||||
}
|
||||
|
||||
memset(&c, 0, sizeof(c));
|
||||
c.op_to_portid = cpu_to_be32(V_FW_CMD_OP(FW_PORT_CMD) |
|
||||
@ -3727,21 +3753,9 @@ int t4_link_l1cfg(struct adapter *adap, unsigned int mbox, unsigned int port,
|
||||
c.action_to_len16 =
|
||||
cpu_to_be32(V_FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) |
|
||||
FW_LEN16(c));
|
||||
c.u.l1cfg.rcap = cpu_to_be32(aneg | speed | fc | fec | mdi);
|
||||
|
||||
if (!(lc->supported & FW_PORT_CAP_ANEG)) {
|
||||
c.u.l1cfg.rcap = cpu_to_be32((lc->supported & ADVERT_MASK) |
|
||||
fc | fec);
|
||||
lc->fc = lc->requested_fc & ~PAUSE_AUTONEG;
|
||||
lc->fec = lc->requested_fec;
|
||||
} else if (lc->autoneg == AUTONEG_DISABLE) {
|
||||
c.u.l1cfg.rcap = cpu_to_be32(lc->requested_speed |
|
||||
fc | fec | mdi);
|
||||
lc->fc = lc->requested_fc & ~PAUSE_AUTONEG;
|
||||
lc->fec = lc->requested_fec;
|
||||
} else
|
||||
c.u.l1cfg.rcap = cpu_to_be32(lc->advertising | fc | fec | mdi);
|
||||
|
||||
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
|
||||
return t4_wr_mbox_ns(adap, mbox, &c, sizeof(c), NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -7474,6 +7488,90 @@ const char *t4_link_down_rc_str(unsigned char link_down_rc)
|
||||
return reason[link_down_rc];
|
||||
}
|
||||
|
||||
/*
|
||||
* Updates all fields owned by the common code in port_info and link_config
|
||||
* based on information provided by the firmware. Does not touch any
|
||||
* requested_* field.
|
||||
*/
|
||||
static void handle_port_info(struct port_info *pi, const struct fw_port_info *p)
|
||||
{
|
||||
struct link_config *lc = &pi->link_cfg;
|
||||
int speed;
|
||||
unsigned char fc, fec;
|
||||
u32 stat = be32_to_cpu(p->lstatus_to_modtype);
|
||||
|
||||
pi->port_type = G_FW_PORT_CMD_PTYPE(stat);
|
||||
pi->mod_type = G_FW_PORT_CMD_MODTYPE(stat);
|
||||
pi->mdio_addr = stat & F_FW_PORT_CMD_MDIOCAP ?
|
||||
G_FW_PORT_CMD_MDIOADDR(stat) : -1;
|
||||
|
||||
lc->supported = be16_to_cpu(p->pcap);
|
||||
lc->advertising = be16_to_cpu(p->acap);
|
||||
lc->lp_advertising = be16_to_cpu(p->lpacap);
|
||||
lc->link_ok = (stat & F_FW_PORT_CMD_LSTATUS) != 0;
|
||||
lc->link_down_rc = G_FW_PORT_CMD_LINKDNRC(stat);
|
||||
|
||||
speed = 0;
|
||||
if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100M))
|
||||
speed = 100;
|
||||
else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_1G))
|
||||
speed = 1000;
|
||||
else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_10G))
|
||||
speed = 10000;
|
||||
else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_25G))
|
||||
speed = 25000;
|
||||
else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_40G))
|
||||
speed = 40000;
|
||||
else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100G))
|
||||
speed = 100000;
|
||||
lc->speed = speed;
|
||||
|
||||
fc = 0;
|
||||
if (stat & F_FW_PORT_CMD_RXPAUSE)
|
||||
fc |= PAUSE_RX;
|
||||
if (stat & F_FW_PORT_CMD_TXPAUSE)
|
||||
fc |= PAUSE_TX;
|
||||
lc->fc = fc;
|
||||
|
||||
fec = 0;
|
||||
if (lc->advertising & FW_PORT_CAP_FEC_RS)
|
||||
fec |= FEC_RS;
|
||||
if (lc->advertising & FW_PORT_CAP_FEC_BASER_RS)
|
||||
fec |= FEC_BASER_RS;
|
||||
if (lc->advertising & FW_PORT_CAP_FEC_RESERVED)
|
||||
fec |= FEC_RESERVED;
|
||||
lc->fec = fec;
|
||||
}
|
||||
|
||||
/**
|
||||
* t4_update_port_info - retrieve and update port information if changed
|
||||
* @pi: the port_info
|
||||
*
|
||||
* We issue a Get Port Information Command to the Firmware and, if
|
||||
* successful, we check to see if anything is different from what we
|
||||
* last recorded and update things accordingly.
|
||||
*/
|
||||
int t4_update_port_info(struct port_info *pi)
|
||||
{
|
||||
struct fw_port_cmd port_cmd;
|
||||
int ret;
|
||||
|
||||
memset(&port_cmd, 0, sizeof port_cmd);
|
||||
port_cmd.op_to_portid = cpu_to_be32(V_FW_CMD_OP(FW_PORT_CMD) |
|
||||
F_FW_CMD_REQUEST | F_FW_CMD_READ |
|
||||
V_FW_PORT_CMD_PORTID(pi->tx_chan));
|
||||
port_cmd.action_to_len16 = cpu_to_be32(
|
||||
V_FW_PORT_CMD_ACTION(FW_PORT_ACTION_GET_PORT_INFO) |
|
||||
FW_LEN16(port_cmd));
|
||||
ret = t4_wr_mbox_ns(pi->adapter, pi->adapter->mbox,
|
||||
&port_cmd, sizeof(port_cmd), &port_cmd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
handle_port_info(pi, &port_cmd.u.info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* t4_handle_fw_rpl - process a FW reply message
|
||||
* @adap: the adapter
|
||||
@ -7490,52 +7588,31 @@ int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl)
|
||||
|
||||
if (opcode == FW_PORT_CMD && action == FW_PORT_ACTION_GET_PORT_INFO) {
|
||||
/* link/module state change message */
|
||||
int speed = 0, fc = 0, i;
|
||||
int i, old_ptype, old_mtype;
|
||||
int chan = G_FW_PORT_CMD_PORTID(be32_to_cpu(p->op_to_portid));
|
||||
struct port_info *pi = NULL;
|
||||
struct link_config *lc;
|
||||
u32 stat = be32_to_cpu(p->u.info.lstatus_to_modtype);
|
||||
int link_ok = (stat & F_FW_PORT_CMD_LSTATUS) != 0;
|
||||
u32 mod = G_FW_PORT_CMD_MODTYPE(stat);
|
||||
|
||||
if (stat & F_FW_PORT_CMD_RXPAUSE)
|
||||
fc |= PAUSE_RX;
|
||||
if (stat & F_FW_PORT_CMD_TXPAUSE)
|
||||
fc |= PAUSE_TX;
|
||||
if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100M))
|
||||
speed = 100;
|
||||
else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_1G))
|
||||
speed = 1000;
|
||||
else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_10G))
|
||||
speed = 10000;
|
||||
else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_25G))
|
||||
speed = 25000;
|
||||
else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_40G))
|
||||
speed = 40000;
|
||||
else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100G))
|
||||
speed = 100000;
|
||||
struct link_config *lc, old_lc;
|
||||
|
||||
for_each_port(adap, i) {
|
||||
pi = adap2pinfo(adap, i);
|
||||
if (pi->tx_chan == chan)
|
||||
break;
|
||||
}
|
||||
lc = &pi->link_cfg;
|
||||
|
||||
if (mod != pi->mod_type) {
|
||||
pi->mod_type = mod;
|
||||
t4_os_portmod_changed(adap, i);
|
||||
lc = &pi->link_cfg;
|
||||
old_lc = *lc;
|
||||
old_ptype = pi->port_type;
|
||||
old_mtype = pi->mod_type;
|
||||
|
||||
handle_port_info(pi, &p->u.info);
|
||||
if (old_ptype != pi->port_type || old_mtype != pi->mod_type) {
|
||||
t4_os_portmod_changed(pi, old_ptype, old_mtype,
|
||||
&old_lc);
|
||||
}
|
||||
if (link_ok != lc->link_ok || speed != lc->speed ||
|
||||
fc != lc->fc) { /* something changed */
|
||||
if (!link_ok && lc->link_ok)
|
||||
lc->link_down_rc = G_FW_PORT_CMD_LINKDNRC(stat);
|
||||
lc->link_ok = link_ok;
|
||||
lc->speed = speed;
|
||||
lc->fc = fc;
|
||||
lc->supported = be16_to_cpu(p->u.info.pcap);
|
||||
lc->lp_advertising = be16_to_cpu(p->u.info.lpacap);
|
||||
t4_os_link_changed(adap, i, link_ok);
|
||||
if (old_lc.link_ok != lc->link_ok ||
|
||||
old_lc.speed != lc->speed ||
|
||||
old_lc.fc != lc->fc) {
|
||||
t4_os_link_changed(pi, &old_lc);
|
||||
}
|
||||
} else {
|
||||
CH_WARN_RATELIMIT(adap, "Unknown firmware reply %d\n", opcode);
|
||||
@ -7566,48 +7643,6 @@ static void get_pci_mode(struct adapter *adapter,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* init_link_config - initialize a link's SW state
|
||||
* @lc: structure holding the link state
|
||||
* @pcaps: supported link capabilities
|
||||
* @acaps: advertised link capabilities
|
||||
*
|
||||
* Initializes the SW state maintained for each link, including the link's
|
||||
* capabilities and default speed/flow-control/autonegotiation settings.
|
||||
*/
|
||||
static void init_link_config(struct link_config *lc, unsigned int pcaps,
|
||||
unsigned int acaps)
|
||||
{
|
||||
unsigned int fec;
|
||||
|
||||
lc->supported = pcaps;
|
||||
lc->lp_advertising = 0;
|
||||
lc->requested_speed = 0;
|
||||
lc->speed = 0;
|
||||
lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;
|
||||
lc->link_ok = 0;
|
||||
lc->link_down_rc = 255;
|
||||
|
||||
fec = 0;
|
||||
if (acaps & FW_PORT_CAP_FEC_RS)
|
||||
fec |= FEC_RS;
|
||||
if (acaps & FW_PORT_CAP_FEC_BASER_RS)
|
||||
fec |= FEC_BASER_RS;
|
||||
if (acaps & FW_PORT_CAP_FEC_RESERVED)
|
||||
fec |= FEC_RESERVED;
|
||||
fec &= G_FW_PORT_CAP_FEC(lc->supported);
|
||||
lc->requested_fec = lc->fec = fec;
|
||||
|
||||
if (lc->supported & FW_PORT_CAP_ANEG) {
|
||||
lc->advertising = lc->supported & ADVERT_MASK;
|
||||
lc->autoneg = AUTONEG_ENABLE;
|
||||
lc->requested_fc |= PAUSE_AUTONEG;
|
||||
} else {
|
||||
lc->advertising = 0;
|
||||
lc->autoneg = AUTONEG_DISABLE;
|
||||
}
|
||||
}
|
||||
|
||||
struct flash_desc {
|
||||
u32 vendor_and_model_id;
|
||||
u32 size_mb;
|
||||
@ -8144,24 +8179,7 @@ int t4_port_init(struct adapter *adap, int mbox, int pf, int vf, int port_id)
|
||||
|
||||
if (!(adap->flags & IS_VF) ||
|
||||
adap->params.vfres.r_caps & FW_CMD_CAP_PORT) {
|
||||
c.op_to_portid = htonl(V_FW_CMD_OP(FW_PORT_CMD) |
|
||||
F_FW_CMD_REQUEST | F_FW_CMD_READ |
|
||||
V_FW_PORT_CMD_PORTID(j));
|
||||
c.action_to_len16 = htonl(
|
||||
V_FW_PORT_CMD_ACTION(FW_PORT_ACTION_GET_PORT_INFO) |
|
||||
FW_LEN16(c));
|
||||
ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = be32_to_cpu(c.u.info.lstatus_to_modtype);
|
||||
p->mdio_addr = (ret & F_FW_PORT_CMD_MDIOCAP) ?
|
||||
G_FW_PORT_CMD_MDIOADDR(ret) : -1;
|
||||
p->port_type = G_FW_PORT_CMD_PTYPE(ret);
|
||||
p->mod_type = G_FW_PORT_CMD_MODTYPE(ret);
|
||||
|
||||
init_link_config(&p->link_cfg, be16_to_cpu(c.u.info.pcap),
|
||||
be16_to_cpu(c.u.info.acap));
|
||||
t4_update_port_info(p);
|
||||
}
|
||||
|
||||
ret = t4_alloc_vi(adap, mbox, j, pf, vf, 1, addr, &rss_size);
|
||||
@ -8177,7 +8195,7 @@ int t4_port_init(struct adapter *adap, int mbox, int pf, int vf, int port_id)
|
||||
p->rx_chan_map = t4_get_mps_bg_map(adap, j);
|
||||
p->lport = j;
|
||||
p->vi[0].rss_size = rss_size;
|
||||
t4_os_set_hw_addr(adap, p->port_id, addr);
|
||||
t4_os_set_hw_addr(p, addr);
|
||||
|
||||
param = V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
|
||||
V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_RSSINFO) |
|
||||
|
@ -487,6 +487,7 @@ static int get_params__post_init(struct adapter *);
|
||||
static int set_params__post_init(struct adapter *);
|
||||
static void t4_set_desc(struct adapter *);
|
||||
static void build_medialist(struct port_info *, struct ifmedia *);
|
||||
static void init_l1cfg(struct port_info *);
|
||||
static int cxgbe_init_synchronized(struct vi_info *);
|
||||
static int cxgbe_uninit_synchronized(struct vi_info *);
|
||||
static void quiesce_txq(struct adapter *, struct sge_txq *);
|
||||
@ -955,7 +956,6 @@ t4_attach(device_t dev)
|
||||
n10g = n1g = 0;
|
||||
for_each_port(sc, i) {
|
||||
struct port_info *pi;
|
||||
struct link_config *lc;
|
||||
|
||||
pi = malloc(sizeof(*pi), M_CXGBE, M_ZERO | M_WAITOK);
|
||||
sc->port[i] = pi;
|
||||
@ -984,28 +984,6 @@ t4_attach(device_t dev)
|
||||
goto done;
|
||||
}
|
||||
|
||||
lc = &pi->link_cfg;
|
||||
lc->requested_fc &= ~(PAUSE_TX | PAUSE_RX);
|
||||
lc->requested_fc |= t4_pause_settings;
|
||||
if (t4_fec != -1) {
|
||||
lc->requested_fec = t4_fec &
|
||||
G_FW_PORT_CAP_FEC(lc->supported);
|
||||
}
|
||||
if (lc->supported & FW_PORT_CAP_ANEG && t4_autoneg != -1) {
|
||||
lc->autoneg = t4_autoneg ? AUTONEG_ENABLE :
|
||||
AUTONEG_DISABLE;
|
||||
}
|
||||
lc->requested_speed = port_top_speed_raw(pi);
|
||||
|
||||
rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc);
|
||||
if (rc != 0) {
|
||||
device_printf(dev, "port %d l1cfg failed: %d\n", i, rc);
|
||||
free(pi->vi, M_CXGBE);
|
||||
free(pi, M_CXGBE);
|
||||
sc->port[i] = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
snprintf(pi->lockname, sizeof(pi->lockname), "%sp%d",
|
||||
device_get_nameunit(dev), i);
|
||||
mtx_init(&pi->pi_lock, pi->lockname, 0, MTX_DEF);
|
||||
@ -1480,7 +1458,6 @@ cxgbe_vi_attach(device_t dev, struct vi_info *vi)
|
||||
/* Initialize ifmedia for this VI */
|
||||
ifmedia_init(&vi->media, IFM_IMASK, cxgbe_media_change,
|
||||
cxgbe_media_status);
|
||||
build_medialist(vi->pi, &vi->media);
|
||||
|
||||
vi->vlan_c = EVENTHANDLER_REGISTER(vlan_config, cxgbe_vlan_config, ifp,
|
||||
EVENTHANDLER_PRI_ANY);
|
||||
@ -2022,32 +1999,63 @@ cxgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
|
||||
struct vi_info *vi = ifp->if_softc;
|
||||
struct port_info *pi = vi->pi;
|
||||
struct ifmedia_entry *cur;
|
||||
int speed = pi->link_cfg.speed;
|
||||
struct link_config *lc = &pi->link_cfg;
|
||||
|
||||
/*
|
||||
* If all the interfaces are administratively down the firmware does not
|
||||
* report transceiver changes. Refresh port info here so that ifconfig
|
||||
* displays accurate information at all times.
|
||||
*/
|
||||
if (begin_synchronized_op(pi->adapter, NULL, SLEEP_OK | INTR_OK,
|
||||
"t4med") == 0) {
|
||||
PORT_LOCK(pi);
|
||||
if (pi->up_vis == 0) {
|
||||
t4_update_port_info(pi);
|
||||
build_medialist(pi, &vi->media);
|
||||
}
|
||||
PORT_UNLOCK(pi);
|
||||
end_synchronized_op(pi->adapter, 0);
|
||||
}
|
||||
|
||||
cur = vi->media.ifm_cur;
|
||||
|
||||
ifmr->ifm_status = IFM_AVALID;
|
||||
if (!pi->link_cfg.link_ok)
|
||||
if (lc->link_ok == 0)
|
||||
return;
|
||||
|
||||
ifmr->ifm_status |= IFM_ACTIVE;
|
||||
ifmr->ifm_active &= ~(IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE);
|
||||
if (lc->fc & PAUSE_RX)
|
||||
ifmr->ifm_active |= IFM_ETH_RXPAUSE;
|
||||
if (lc->fc & PAUSE_TX)
|
||||
ifmr->ifm_active |= IFM_ETH_TXPAUSE;
|
||||
|
||||
/* active and current will differ iff current media is autoselect. */
|
||||
if (IFM_SUBTYPE(cur->ifm_media) != IFM_AUTO)
|
||||
return;
|
||||
|
||||
ifmr->ifm_active = IFM_ETHER | IFM_FDX;
|
||||
if (speed == 10000)
|
||||
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;
|
||||
else if (speed == 1000)
|
||||
break;
|
||||
case 1000:
|
||||
ifmr->ifm_active |= IFM_1000_T;
|
||||
else if (speed == 100)
|
||||
break;
|
||||
case 100:
|
||||
ifmr->ifm_active |= IFM_100_TX;
|
||||
else if (speed == 10)
|
||||
break;
|
||||
case 10:
|
||||
ifmr->ifm_active |= IFM_10_T;
|
||||
else
|
||||
KASSERT(0, ("%s: link up but speed unknown (%u)", __func__,
|
||||
speed));
|
||||
break;
|
||||
default:
|
||||
device_printf(vi->dev, "link up but speed unknown (%u)\n",
|
||||
lc->speed);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
@ -3590,11 +3598,18 @@ build_medialist(struct port_info *pi, struct ifmedia *media)
|
||||
{
|
||||
int m;
|
||||
|
||||
PORT_LOCK(pi);
|
||||
PORT_LOCK_ASSERT_OWNED(pi);
|
||||
|
||||
ifmedia_removeall(media);
|
||||
|
||||
m = IFM_ETHER | IFM_FDX;
|
||||
/*
|
||||
* XXX: Would it be better to ifmedia_add all 4 combinations of pause
|
||||
* settings for every speed instead of just txpause|rxpause? ifconfig
|
||||
* media display looks much better if autoselect is the only case where
|
||||
* 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;
|
||||
|
||||
switch(pi->port_type) {
|
||||
case FW_PORT_TYPE_BT_XFI:
|
||||
@ -3770,8 +3785,53 @@ build_medialist(struct port_info *pi, struct ifmedia *media)
|
||||
ifmedia_set(media, m | IFM_UNKNOWN);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PORT_UNLOCK(pi);
|
||||
/*
|
||||
* Update all the requested_* fields in the link config and then send a mailbox
|
||||
* command to apply the settings.
|
||||
*/
|
||||
static void
|
||||
init_l1cfg(struct port_info *pi)
|
||||
{
|
||||
struct adapter *sc = pi->adapter;
|
||||
struct link_config *lc = &pi->link_cfg;
|
||||
int rc;
|
||||
|
||||
ASSERT_SYNCHRONIZED_OP(sc);
|
||||
|
||||
if (t4_autoneg != 0 && lc->supported & FW_PORT_CAP_ANEG) {
|
||||
lc->requested_aneg = AUTONEG_ENABLE;
|
||||
lc->requested_speed = 0;
|
||||
} else {
|
||||
lc->requested_aneg = AUTONEG_DISABLE;
|
||||
lc->requested_speed = port_top_speed(pi); /* in Gbps */
|
||||
}
|
||||
|
||||
lc->requested_fc = t4_pause_settings & (PAUSE_TX | PAUSE_RX);
|
||||
|
||||
if (t4_fec != -1) {
|
||||
lc->requested_fec = t4_fec & (FEC_RS | FEC_BASER_RS |
|
||||
FEC_RESERVED);
|
||||
} else {
|
||||
/* Use the suggested value provided by the firmware in acaps */
|
||||
if (lc->advertising & FW_PORT_CAP_FEC_RS)
|
||||
lc->requested_fec = FEC_RS;
|
||||
else if (lc->advertising & FW_PORT_CAP_FEC_BASER_RS)
|
||||
lc->requested_fec = FEC_BASER_RS;
|
||||
else if (lc->advertising & FW_PORT_CAP_FEC_RESERVED)
|
||||
lc->requested_fec = FEC_RESERVED;
|
||||
else
|
||||
lc->requested_fec = 0;
|
||||
}
|
||||
|
||||
rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc);
|
||||
if (rc != 0) {
|
||||
device_printf(pi->dev, "l1cfg failed: %d\n", rc);
|
||||
} else {
|
||||
lc->fc = lc->requested_fc;
|
||||
lc->fec = lc->requested_fec;
|
||||
}
|
||||
}
|
||||
|
||||
#define FW_MAC_EXACT_CHUNK 7
|
||||
@ -4053,8 +4113,12 @@ cxgbe_init_synchronized(struct vi_info *vi)
|
||||
|
||||
/* all ok */
|
||||
PORT_LOCK(pi);
|
||||
if (pi->up_vis++ == 0) {
|
||||
t4_update_port_info(pi);
|
||||
build_medialist(vi->pi, &vi->media);
|
||||
init_l1cfg(pi);
|
||||
}
|
||||
ifp->if_drv_flags |= IFF_DRV_RUNNING;
|
||||
pi->up_vis++;
|
||||
|
||||
if (pi->nvi > 1 || sc->flags & IS_VF)
|
||||
callout_reset(&vi->tick, hz, vi_tick, vi);
|
||||
@ -4127,7 +4191,7 @@ cxgbe_uninit_synchronized(struct vi_info *vi)
|
||||
pi->link_cfg.link_ok = 0;
|
||||
pi->link_cfg.speed = 0;
|
||||
pi->link_cfg.link_down_rc = 255;
|
||||
t4_os_link_changed(sc, pi->port_id, 0);
|
||||
t4_os_link_changed(pi, NULL);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -5813,6 +5877,9 @@ sysctl_pause_settings(SYSCTL_HANDLER_ARGS)
|
||||
lc->requested_fc &= ~(PAUSE_TX | PAUSE_RX);
|
||||
lc->requested_fc |= n;
|
||||
rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc);
|
||||
if (rc == 0) {
|
||||
lc->fc = lc->requested_fc;
|
||||
}
|
||||
}
|
||||
end_synchronized_op(sc, 0);
|
||||
}
|
||||
@ -5870,6 +5937,9 @@ sysctl_fec(SYSCTL_HANDLER_ARGS)
|
||||
lc->requested_fec = n &
|
||||
G_FW_PORT_CAP_FEC(lc->supported);
|
||||
rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc);
|
||||
if (rc == 0) {
|
||||
lc->fec = lc->requested_fec;
|
||||
}
|
||||
}
|
||||
end_synchronized_op(sc, 0);
|
||||
}
|
||||
@ -5886,7 +5956,7 @@ sysctl_autoneg(SYSCTL_HANDLER_ARGS)
|
||||
int rc, val, old;
|
||||
|
||||
if (lc->supported & FW_PORT_CAP_ANEG)
|
||||
val = lc->autoneg == AUTONEG_ENABLE ? 1 : 0;
|
||||
val = lc->requested_aneg == AUTONEG_ENABLE ? 1 : 0;
|
||||
else
|
||||
val = -1;
|
||||
rc = sysctl_handle_int(oidp, &val, 0, req);
|
||||
@ -5901,18 +5971,18 @@ sysctl_autoneg(SYSCTL_HANDLER_ARGS)
|
||||
val = AUTONEG_ENABLE;
|
||||
else
|
||||
return (EINVAL);
|
||||
if (lc->autoneg == val)
|
||||
if (lc->requested_aneg == val)
|
||||
return (0); /* no change */
|
||||
|
||||
rc = begin_synchronized_op(sc, &pi->vi[0], SLEEP_OK | INTR_OK,
|
||||
"t4aneg");
|
||||
if (rc)
|
||||
return (rc);
|
||||
old = lc->autoneg;
|
||||
lc->autoneg = val;
|
||||
old = lc->requested_aneg;
|
||||
lc->requested_aneg = val;
|
||||
rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc);
|
||||
if (rc != 0)
|
||||
lc->autoneg = old;
|
||||
lc->requested_aneg = old;
|
||||
end_synchronized_op(sc, 0);
|
||||
return (rc);
|
||||
}
|
||||
@ -8874,9 +8944,9 @@ t4_os_pci_restore_state(struct adapter *sc)
|
||||
}
|
||||
|
||||
void
|
||||
t4_os_portmod_changed(const struct adapter *sc, int idx)
|
||||
t4_os_portmod_changed(struct port_info *pi, int old_ptype, int old_mtype,
|
||||
struct link_config *old_lc)
|
||||
{
|
||||
struct port_info *pi = sc->port[idx];
|
||||
struct vi_info *vi;
|
||||
struct ifnet *ifp;
|
||||
int v;
|
||||
@ -8884,9 +8954,15 @@ t4_os_portmod_changed(const struct adapter *sc, int idx)
|
||||
NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX", "LRM"
|
||||
};
|
||||
|
||||
PORT_LOCK(pi);
|
||||
for_each_vi(pi, v, vi) {
|
||||
build_medialist(pi, &vi->media);
|
||||
}
|
||||
PORT_UNLOCK(pi);
|
||||
if (begin_synchronized_op(pi->adapter, vi, HOLD_LOCK, "t4mod") == 0) {
|
||||
init_l1cfg(pi);
|
||||
end_synchronized_op(pi->adapter, LOCK_HELD);
|
||||
}
|
||||
|
||||
ifp = pi->vi[0].ifp;
|
||||
if (pi->mod_type == FW_PORT_MOD_TYPE_NONE)
|
||||
@ -8896,8 +8972,8 @@ t4_os_portmod_changed(const struct adapter *sc, int idx)
|
||||
else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED)
|
||||
if_printf(ifp, "unsupported transceiver inserted.\n");
|
||||
else if (pi->mod_type > 0 && pi->mod_type < nitems(mod_str)) {
|
||||
if_printf(ifp, "%s transceiver inserted.\n",
|
||||
mod_str[pi->mod_type]);
|
||||
if_printf(ifp, "%dGbps %s transceiver inserted.\n",
|
||||
port_top_speed(pi), mod_str[pi->mod_type]);
|
||||
} else {
|
||||
if_printf(ifp, "transceiver (type %d) inserted.\n",
|
||||
pi->mod_type);
|
||||
@ -8905,11 +8981,11 @@ t4_os_portmod_changed(const struct adapter *sc, int idx)
|
||||
}
|
||||
|
||||
void
|
||||
t4_os_link_changed(struct adapter *sc, int idx, int link_stat)
|
||||
t4_os_link_changed(struct port_info *pi, struct link_config *old_lc)
|
||||
{
|
||||
struct port_info *pi = sc->port[idx];
|
||||
struct vi_info *vi;
|
||||
struct ifnet *ifp;
|
||||
struct link_config *lc;
|
||||
int v;
|
||||
|
||||
for_each_vi(pi, v, vi) {
|
||||
@ -8917,8 +8993,9 @@ t4_os_link_changed(struct adapter *sc, int idx, int link_stat)
|
||||
if (ifp == NULL)
|
||||
continue;
|
||||
|
||||
if (link_stat) {
|
||||
ifp->if_baudrate = IF_Mbps(pi->link_cfg.speed);
|
||||
lc = &pi->link_cfg;
|
||||
if (lc->link_ok) {
|
||||
ifp->if_baudrate = IF_Mbps(lc->speed);
|
||||
if_link_state_change(ifp, LINK_STATE_UP);
|
||||
} else {
|
||||
if_link_state_change(ifp, LINK_STATE_DOWN);
|
||||
|
Loading…
x
Reference in New Issue
Block a user