Commit 7d9df38c authored by Michael Chan's avatar Michael Chan Committed by Jakub Kicinski

bnxt_en: Cap the size of HWRM_PORT_PHY_QCFG forwarded response

Firmware interface 1.10.2.118 has increased the size of
HWRM_PORT_PHY_QCFG response beyond the maximum size that can be
forwarded.  When the VF's link state is not the default auto state,
the PF will need to forward the response back to the VF to indicate
the forced state.  This regression may cause the VF to fail to
initialize.

Fix it by capping the HWRM_PORT_PHY_QCFG response to the maximum
96 bytes.  The SPEEDS2_SUPPORTED flag needs to be cleared because the
new speeds2 fields are beyond the legacy structure.  Also modify
bnxt_hwrm_fwd_resp() to print a warning if the message size exceeds 96
bytes to make this failure more obvious.

Fixes: 84a911db ("bnxt_en: Update firmware interface to 1.10.2.118")
Reviewed-by: default avatarSomnath Kotur <somnath.kotur@broadcom.com>
Reviewed-by: default avatarPavan Chebbi <pavan.chebbi@broadcom.com>
Signed-off-by: default avatarMichael Chan <michael.chan@broadcom.com>
Link: https://lore.kernel.org/r/20240612231736.57823-1-michael.chan@broadcom.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 6f4d93b7
...@@ -1434,6 +1434,57 @@ struct bnxt_l2_filter { ...@@ -1434,6 +1434,57 @@ struct bnxt_l2_filter {
atomic_t refcnt; atomic_t refcnt;
}; };
/* Compat version of hwrm_port_phy_qcfg_output capped at 96 bytes. The
* first 95 bytes are identical to hwrm_port_phy_qcfg_output in bnxt_hsi.h.
* The last valid byte in the compat version is different.
*/
struct hwrm_port_phy_qcfg_output_compat {
__le16 error_code;
__le16 req_type;
__le16 seq_id;
__le16 resp_len;
u8 link;
u8 active_fec_signal_mode;
__le16 link_speed;
u8 duplex_cfg;
u8 pause;
__le16 support_speeds;
__le16 force_link_speed;
u8 auto_mode;
u8 auto_pause;
__le16 auto_link_speed;
__le16 auto_link_speed_mask;
u8 wirespeed;
u8 lpbk;
u8 force_pause;
u8 module_status;
__le32 preemphasis;
u8 phy_maj;
u8 phy_min;
u8 phy_bld;
u8 phy_type;
u8 media_type;
u8 xcvr_pkg_type;
u8 eee_config_phy_addr;
u8 parallel_detect;
__le16 link_partner_adv_speeds;
u8 link_partner_adv_auto_mode;
u8 link_partner_adv_pause;
__le16 adv_eee_link_speed_mask;
__le16 link_partner_adv_eee_link_speed_mask;
__le32 xcvr_identifier_type_tx_lpi_timer;
__le16 fec_cfg;
u8 duplex_state;
u8 option_flags;
char phy_vendor_name[16];
char phy_vendor_partnumber[16];
__le16 support_pam4_speeds;
__le16 force_pam4_link_speed;
__le16 auto_pam4_link_speed_mask;
u8 link_partner_pam4_adv_speeds;
u8 valid;
};
struct bnxt_link_info { struct bnxt_link_info {
u8 phy_type; u8 phy_type;
u8 media_type; u8 media_type;
......
...@@ -950,8 +950,11 @@ static int bnxt_hwrm_fwd_resp(struct bnxt *bp, struct bnxt_vf_info *vf, ...@@ -950,8 +950,11 @@ static int bnxt_hwrm_fwd_resp(struct bnxt *bp, struct bnxt_vf_info *vf,
struct hwrm_fwd_resp_input *req; struct hwrm_fwd_resp_input *req;
int rc; int rc;
if (BNXT_FWD_RESP_SIZE_ERR(msg_size)) if (BNXT_FWD_RESP_SIZE_ERR(msg_size)) {
netdev_warn_once(bp->dev, "HWRM fwd response too big (%d bytes)\n",
msg_size);
return -EINVAL; return -EINVAL;
}
rc = hwrm_req_init(bp, req, HWRM_FWD_RESP); rc = hwrm_req_init(bp, req, HWRM_FWD_RESP);
if (!rc) { if (!rc) {
...@@ -1085,7 +1088,7 @@ static int bnxt_vf_set_link(struct bnxt *bp, struct bnxt_vf_info *vf) ...@@ -1085,7 +1088,7 @@ static int bnxt_vf_set_link(struct bnxt *bp, struct bnxt_vf_info *vf)
rc = bnxt_hwrm_exec_fwd_resp( rc = bnxt_hwrm_exec_fwd_resp(
bp, vf, sizeof(struct hwrm_port_phy_qcfg_input)); bp, vf, sizeof(struct hwrm_port_phy_qcfg_input));
} else { } else {
struct hwrm_port_phy_qcfg_output phy_qcfg_resp = {0}; struct hwrm_port_phy_qcfg_output_compat phy_qcfg_resp = {};
struct hwrm_port_phy_qcfg_input *phy_qcfg_req; struct hwrm_port_phy_qcfg_input *phy_qcfg_req;
phy_qcfg_req = phy_qcfg_req =
...@@ -1096,6 +1099,11 @@ static int bnxt_vf_set_link(struct bnxt *bp, struct bnxt_vf_info *vf) ...@@ -1096,6 +1099,11 @@ static int bnxt_vf_set_link(struct bnxt *bp, struct bnxt_vf_info *vf)
mutex_unlock(&bp->link_lock); mutex_unlock(&bp->link_lock);
phy_qcfg_resp.resp_len = cpu_to_le16(sizeof(phy_qcfg_resp)); phy_qcfg_resp.resp_len = cpu_to_le16(sizeof(phy_qcfg_resp));
phy_qcfg_resp.seq_id = phy_qcfg_req->seq_id; phy_qcfg_resp.seq_id = phy_qcfg_req->seq_id;
/* New SPEEDS2 fields are beyond the legacy structure, so
* clear the SPEEDS2_SUPPORTED flag.
*/
phy_qcfg_resp.option_flags &=
~PORT_PHY_QCAPS_RESP_FLAGS2_SPEEDS2_SUPPORTED;
phy_qcfg_resp.valid = 1; phy_qcfg_resp.valid = 1;
if (vf->flags & BNXT_VF_LINK_UP) { if (vf->flags & BNXT_VF_LINK_UP) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment