cxgb4: Don't assume FW_PORT_CMD reply is always port info msg
The firmware can send a set of asynchronous replies through FW_PORT_CMD with DCBX information when that's negotiated with the Link Peer. The old code always assumed that a FW_PORT_CMD reply was always a Get Port Information message. This change conditionalizes the code to only handle the Get Port Information messages and throws a warning if we don't understand what we've been given. Also refactor t4_handle_fw_rpl() so that core functionality performed by t4_handle_get_port_info() for a specified port. Signed-off-by: Hariprasad Shenai <hariprasad@chelsio.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
134491fdc3
commit
23853a0a9a
@ -1470,6 +1470,7 @@ int t4_ctrl_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
|
|||||||
int t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
|
int t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
|
||||||
unsigned int vf, unsigned int eqid);
|
unsigned int vf, unsigned int eqid);
|
||||||
int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox);
|
int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox);
|
||||||
|
void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl);
|
||||||
int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl);
|
int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl);
|
||||||
void t4_db_full(struct adapter *adapter);
|
void t4_db_full(struct adapter *adapter);
|
||||||
void t4_db_dropped(struct adapter *adapter);
|
void t4_db_dropped(struct adapter *adapter);
|
||||||
|
@ -7103,52 +7103,88 @@ int t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* t4_handle_fw_rpl - process a FW reply message
|
* t4_handle_get_port_info - process a FW reply message
|
||||||
* @adap: the adapter
|
* @pi: the port info
|
||||||
* @rpl: start of the FW message
|
* @rpl: start of the FW message
|
||||||
*
|
*
|
||||||
* Processes a FW message, such as link state change messages.
|
* Processes a GET_PORT_INFO FW reply message.
|
||||||
|
*/
|
||||||
|
void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl)
|
||||||
|
{
|
||||||
|
const struct fw_port_cmd *p = (const void *)rpl;
|
||||||
|
struct adapter *adap = pi->adapter;
|
||||||
|
|
||||||
|
/* link/module state change message */
|
||||||
|
int speed = 0, fc = 0;
|
||||||
|
struct link_config *lc;
|
||||||
|
u32 stat = be32_to_cpu(p->u.info.lstatus_to_modtype);
|
||||||
|
int link_ok = (stat & FW_PORT_CMD_LSTATUS_F) != 0;
|
||||||
|
u32 mod = FW_PORT_CMD_MODTYPE_G(stat);
|
||||||
|
|
||||||
|
if (stat & FW_PORT_CMD_RXPAUSE_F)
|
||||||
|
fc |= PAUSE_RX;
|
||||||
|
if (stat & FW_PORT_CMD_TXPAUSE_F)
|
||||||
|
fc |= PAUSE_TX;
|
||||||
|
if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M))
|
||||||
|
speed = 100;
|
||||||
|
else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G))
|
||||||
|
speed = 1000;
|
||||||
|
else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_10G))
|
||||||
|
speed = 10000;
|
||||||
|
else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_40G))
|
||||||
|
speed = 40000;
|
||||||
|
|
||||||
|
lc = &pi->link_cfg;
|
||||||
|
|
||||||
|
if (mod != pi->mod_type) {
|
||||||
|
pi->mod_type = mod;
|
||||||
|
t4_os_portmod_changed(adap, pi->port_id);
|
||||||
|
}
|
||||||
|
if (link_ok != lc->link_ok || speed != lc->speed ||
|
||||||
|
fc != lc->fc) { /* something changed */
|
||||||
|
lc->link_ok = link_ok;
|
||||||
|
lc->speed = speed;
|
||||||
|
lc->fc = fc;
|
||||||
|
lc->supported = be16_to_cpu(p->u.info.pcap);
|
||||||
|
t4_os_link_changed(adap, pi->port_id, link_ok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* t4_handle_fw_rpl - process a FW reply message
|
||||||
|
* @adap: the adapter
|
||||||
|
* @rpl: start of the FW message
|
||||||
|
*
|
||||||
|
* Processes a FW message, such as link state change messages.
|
||||||
*/
|
*/
|
||||||
int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl)
|
int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl)
|
||||||
{
|
{
|
||||||
u8 opcode = *(const u8 *)rpl;
|
u8 opcode = *(const u8 *)rpl;
|
||||||
|
|
||||||
if (opcode == FW_PORT_CMD) { /* link/module state change message */
|
/* This might be a port command ... this simplifies the following
|
||||||
int speed = 0, fc = 0;
|
* conditionals ... We can get away with pre-dereferencing
|
||||||
const struct fw_port_cmd *p = (void *)rpl;
|
* action_to_len16 because it's in the first 16 bytes and all messages
|
||||||
|
* will be at least that long.
|
||||||
|
*/
|
||||||
|
const struct fw_port_cmd *p = (const void *)rpl;
|
||||||
|
unsigned int action =
|
||||||
|
FW_PORT_CMD_ACTION_G(be32_to_cpu(p->action_to_len16));
|
||||||
|
|
||||||
|
if (opcode == FW_PORT_CMD && action == FW_PORT_ACTION_GET_PORT_INFO) {
|
||||||
|
int i;
|
||||||
int chan = FW_PORT_CMD_PORTID_G(be32_to_cpu(p->op_to_portid));
|
int chan = FW_PORT_CMD_PORTID_G(be32_to_cpu(p->op_to_portid));
|
||||||
int port = adap->chan_map[chan];
|
struct port_info *pi = NULL;
|
||||||
struct port_info *pi = adap2pinfo(adap, port);
|
|
||||||
struct link_config *lc = &pi->link_cfg;
|
|
||||||
u32 stat = be32_to_cpu(p->u.info.lstatus_to_modtype);
|
|
||||||
int link_ok = (stat & FW_PORT_CMD_LSTATUS_F) != 0;
|
|
||||||
u32 mod = FW_PORT_CMD_MODTYPE_G(stat);
|
|
||||||
|
|
||||||
if (stat & FW_PORT_CMD_RXPAUSE_F)
|
for_each_port(adap, i) {
|
||||||
fc |= PAUSE_RX;
|
pi = adap2pinfo(adap, i);
|
||||||
if (stat & FW_PORT_CMD_TXPAUSE_F)
|
if (pi->tx_chan == chan)
|
||||||
fc |= PAUSE_TX;
|
break;
|
||||||
if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M))
|
}
|
||||||
speed = 100;
|
|
||||||
else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G))
|
|
||||||
speed = 1000;
|
|
||||||
else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_10G))
|
|
||||||
speed = 10000;
|
|
||||||
else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_40G))
|
|
||||||
speed = 40000;
|
|
||||||
|
|
||||||
if (link_ok != lc->link_ok || speed != lc->speed ||
|
t4_handle_get_port_info(pi, rpl);
|
||||||
fc != lc->fc) { /* something changed */
|
} else {
|
||||||
lc->link_ok = link_ok;
|
dev_warn(adap->pdev_dev, "Unknown firmware reply %d\n", opcode);
|
||||||
lc->speed = speed;
|
return -EINVAL;
|
||||||
lc->fc = fc;
|
|
||||||
lc->supported = be16_to_cpu(p->u.info.pcap);
|
|
||||||
t4_os_link_changed(adap, port, link_ok);
|
|
||||||
}
|
|
||||||
if (mod != pi->mod_type) {
|
|
||||||
pi->mod_type = mod;
|
|
||||||
t4_os_portmod_changed(adap, port);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user