aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Chan <michael.chan@broadcom.com>2018-03-31 13:54:15 -0400
committerDavid S. Miller <davem@davemloft.net>2018-03-31 23:24:19 -0400
commit845adfe40c2a75e67ddae6639fc2b987338b7983 (patch)
treeee9abc40ff26ae032453e1b94f2e8c8a80c27e8f
parent596f9d55feebdf31c03172fcc82cdec62bb969ea (diff)
bnxt_en: Improve valid bit checking in firmware response message.
When firmware sends a DMA response to the driver, the last byte of the message will be set to 1 to indicate that the whole response is valid. The driver waits for the message to be valid before reading the message. The firmware spec allows these response messages to increase in length by adding new fields to the end of these messages. The older spec's valid location may become a new field in a newer spec. To guarantee compatibility, the driver should zero the valid byte before interpreting the entire message so that any new fields not implemented by the older spec will be read as zero. For messages that are forwarded to VFs, we need to set the length and re-instate the valid bit so the VF will see the valid response. Signed-off-by: Michael Chan <michael.chan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.c21
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c2
2 files changed, 18 insertions, 5 deletions
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 62b7d69cc8e5..6fcf4dc67d5e 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -3422,7 +3422,8 @@ static int bnxt_hwrm_do_send_msg(struct bnxt *bp, void *msg, u32 msg_len,
3422 int i, intr_process, rc, tmo_count; 3422 int i, intr_process, rc, tmo_count;
3423 struct input *req = msg; 3423 struct input *req = msg;
3424 u32 *data = msg; 3424 u32 *data = msg;
3425 __le32 *resp_len, *valid; 3425 __le32 *resp_len;
3426 u8 *valid;
3426 u16 cp_ring_id, len = 0; 3427 u16 cp_ring_id, len = 0;
3427 struct hwrm_err_output *resp = bp->hwrm_cmd_resp_addr; 3428 struct hwrm_err_output *resp = bp->hwrm_cmd_resp_addr;
3428 u16 max_req_len = BNXT_HWRM_MAX_REQ_LEN; 3429 u16 max_req_len = BNXT_HWRM_MAX_REQ_LEN;
@@ -3474,6 +3475,7 @@ static int bnxt_hwrm_do_send_msg(struct bnxt *bp, void *msg, u32 msg_len,
3474 3475
3475 i = 0; 3476 i = 0;
3476 tmo_count = timeout * 40; 3477 tmo_count = timeout * 40;
3478 resp_len = bp->hwrm_cmd_resp_addr + HWRM_RESP_LEN_OFFSET;
3477 if (intr_process) { 3479 if (intr_process) {
3478 /* Wait until hwrm response cmpl interrupt is processed */ 3480 /* Wait until hwrm response cmpl interrupt is processed */
3479 while (bp->hwrm_intr_seq_id != HWRM_SEQ_ID_INVALID && 3481 while (bp->hwrm_intr_seq_id != HWRM_SEQ_ID_INVALID &&
@@ -3486,9 +3488,11 @@ static int bnxt_hwrm_do_send_msg(struct bnxt *bp, void *msg, u32 msg_len,
3486 le16_to_cpu(req->req_type)); 3488 le16_to_cpu(req->req_type));
3487 return -1; 3489 return -1;
3488 } 3490 }
3491 len = (le32_to_cpu(*resp_len) & HWRM_RESP_LEN_MASK) >>
3492 HWRM_RESP_LEN_SFT;
3493 valid = bp->hwrm_cmd_resp_addr + len - 1;
3489 } else { 3494 } else {
3490 /* Check if response len is updated */ 3495 /* Check if response len is updated */
3491 resp_len = bp->hwrm_cmd_resp_addr + HWRM_RESP_LEN_OFFSET;
3492 for (i = 0; i < tmo_count; i++) { 3496 for (i = 0; i < tmo_count; i++) {
3493 len = (le32_to_cpu(*resp_len) & HWRM_RESP_LEN_MASK) >> 3497 len = (le32_to_cpu(*resp_len) & HWRM_RESP_LEN_MASK) >>
3494 HWRM_RESP_LEN_SFT; 3498 HWRM_RESP_LEN_SFT;
@@ -3504,10 +3508,12 @@ static int bnxt_hwrm_do_send_msg(struct bnxt *bp, void *msg, u32 msg_len,
3504 return -1; 3508 return -1;
3505 } 3509 }
3506 3510
3507 /* Last word of resp contains valid bit */ 3511 /* Last byte of resp contains valid bit */
3508 valid = bp->hwrm_cmd_resp_addr + len - 4; 3512 valid = bp->hwrm_cmd_resp_addr + len - 1;
3509 for (i = 0; i < 5; i++) { 3513 for (i = 0; i < 5; i++) {
3510 if (le32_to_cpu(*valid) & HWRM_RESP_VALID_MASK) 3514 /* make sure we read from updated DMA memory */
3515 dma_rmb();
3516 if (*valid)
3511 break; 3517 break;
3512 udelay(1); 3518 udelay(1);
3513 } 3519 }
@@ -3520,6 +3526,11 @@ static int bnxt_hwrm_do_send_msg(struct bnxt *bp, void *msg, u32 msg_len,
3520 } 3526 }
3521 } 3527 }
3522 3528
3529 /* Zero valid bit for compatibility. Valid bit in an older spec
3530 * may become a new field in a newer spec. We must make sure that
3531 * a new field not implemented by old spec will read zero.
3532 */
3533 *valid = 0;
3523 rc = le16_to_cpu(resp->error_code); 3534 rc = le16_to_cpu(resp->error_code);
3524 if (rc && !silent) 3535 if (rc && !silent)
3525 netdev_err(bp->dev, "hwrm req_type 0x%x seq id 0x%x error 0x%x\n", 3536 netdev_err(bp->dev, "hwrm req_type 0x%x seq id 0x%x error 0x%x\n",
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
index 4fa4761fbd1c..f952963d594e 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
@@ -974,7 +974,9 @@ static int bnxt_vf_set_link(struct bnxt *bp, struct bnxt_vf_info *vf)
974 memcpy(&phy_qcfg_resp, &bp->link_info.phy_qcfg_resp, 974 memcpy(&phy_qcfg_resp, &bp->link_info.phy_qcfg_resp,
975 sizeof(phy_qcfg_resp)); 975 sizeof(phy_qcfg_resp));
976 mutex_unlock(&bp->hwrm_cmd_lock); 976 mutex_unlock(&bp->hwrm_cmd_lock);
977 phy_qcfg_resp.resp_len = cpu_to_le16(sizeof(phy_qcfg_resp));
977 phy_qcfg_resp.seq_id = phy_qcfg_req->seq_id; 978 phy_qcfg_resp.seq_id = phy_qcfg_req->seq_id;
979 phy_qcfg_resp.valid = 1;
978 980
979 if (vf->flags & BNXT_VF_LINK_UP) { 981 if (vf->flags & BNXT_VF_LINK_UP) {
980 /* if physical link is down, force link up on VF */ 982 /* if physical link is down, force link up on VF */