Commit 1d6f3cd8 authored by Dmitry Kravkov's avatar Dmitry Kravkov Committed by David S. Miller

bnx2x: Prevent VF race

The mail box containing the Vf-Pf messages is susceptible
to a race - it's possible for 2 flows to try and write commands,
causing one to override the other's message.
Use a mutex to synchronize the access, preventing said race.
Signed-off-by: default avatarDmitry Kravkov <dmitry@broadcom.com>
Signed-off-by: default avatarYuval Mintz <yuvalmin@broadcom.com>
Signed-off-by: default avatarAriel Elior <ariele@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 21776537
...@@ -1277,6 +1277,8 @@ struct bnx2x { ...@@ -1277,6 +1277,8 @@ struct bnx2x {
#define BP_FW_MB_IDX(bp) BP_FW_MB_IDX_VN(bp, BP_VN(bp)) #define BP_FW_MB_IDX(bp) BP_FW_MB_IDX_VN(bp, BP_VN(bp))
#ifdef CONFIG_BNX2X_SRIOV #ifdef CONFIG_BNX2X_SRIOV
/* protects vf2pf mailbox from simultaneous access */
struct mutex vf2pf_mutex;
/* vf pf channel mailbox contains request and response buffers */ /* vf pf channel mailbox contains request and response buffers */
struct bnx2x_vf_mbx_msg *vf2pf_mbox; struct bnx2x_vf_mbx_msg *vf2pf_mbox;
dma_addr_t vf2pf_mbox_mapping; dma_addr_t vf2pf_mbox_mapping;
......
...@@ -12521,7 +12521,8 @@ static int bnx2x_init_one(struct pci_dev *pdev, ...@@ -12521,7 +12521,8 @@ static int bnx2x_init_one(struct pci_dev *pdev,
* l2 connections. * l2 connections.
*/ */
if (IS_VF(bp)) { if (IS_VF(bp)) {
bnx2x_vf_map_doorbells(bp); bp->doorbells = bnx2x_vf_doorbells(bp);
mutex_init(&bp->vf2pf_mutex);
rc = bnx2x_vf_pci_alloc(bp); rc = bnx2x_vf_pci_alloc(bp);
if (rc) if (rc)
goto init_one_exit; goto init_one_exit;
......
...@@ -2388,8 +2388,8 @@ int bnx2x_iov_eq_sp_event(struct bnx2x *bp, union event_ring_elem *elem) ...@@ -2388,8 +2388,8 @@ int bnx2x_iov_eq_sp_event(struct bnx2x *bp, union event_ring_elem *elem)
goto get_vf; goto get_vf;
case EVENT_RING_OPCODE_MALICIOUS_VF: case EVENT_RING_OPCODE_MALICIOUS_VF:
abs_vfid = elem->message.data.malicious_vf_event.vf_id; abs_vfid = elem->message.data.malicious_vf_event.vf_id;
DP(BNX2X_MSG_IOV, "Got VF MALICIOUS notification abs_vfid=%d\n", DP(BNX2X_MSG_IOV, "Got VF MALICIOUS notification abs_vfid=%d err_id=0x%x\n",
abs_vfid); abs_vfid, elem->message.data.malicious_vf_event.err_id);
goto get_vf; goto get_vf;
default: default:
return 1; return 1;
...@@ -2446,8 +2446,8 @@ int bnx2x_iov_eq_sp_event(struct bnx2x *bp, union event_ring_elem *elem) ...@@ -2446,8 +2446,8 @@ int bnx2x_iov_eq_sp_event(struct bnx2x *bp, union event_ring_elem *elem)
/* Do nothing for now */ /* Do nothing for now */
break; break;
case EVENT_RING_OPCODE_MALICIOUS_VF: case EVENT_RING_OPCODE_MALICIOUS_VF:
DP(BNX2X_MSG_IOV, "got VF [%d] MALICIOUS notification\n", DP(BNX2X_MSG_IOV, "Got VF MALICIOUS notification abs_vfid=%d error id %x\n",
vf->abs_vfid); abs_vfid, elem->message.data.malicious_vf_event.err_id);
/* Do nothing for now */ /* Do nothing for now */
break; break;
} }
...@@ -3417,10 +3417,10 @@ enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp) ...@@ -3417,10 +3417,10 @@ enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp)
return PFVF_BULLETIN_UPDATED; return PFVF_BULLETIN_UPDATED;
} }
void bnx2x_vf_map_doorbells(struct bnx2x *bp) void __iomem *bnx2x_vf_doorbells(struct bnx2x *bp)
{ {
/* vf doorbells are embedded within the regview */ /* vf doorbells are embedded within the regview */
bp->doorbells = bp->regview + PXP_VF_ADDR_DB_START; return bp->regview + PXP_VF_ADDR_DB_START;
} }
int bnx2x_vf_pci_alloc(struct bnx2x *bp) int bnx2x_vf_pci_alloc(struct bnx2x *bp)
......
...@@ -713,6 +713,7 @@ void bnx2x_add_tlv(struct bnx2x *bp, void *tlvs_list, u16 offset, u16 type, ...@@ -713,6 +713,7 @@ void bnx2x_add_tlv(struct bnx2x *bp, void *tlvs_list, u16 offset, u16 type,
u16 length); u16 length);
void bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv, void bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv,
u16 type, u16 length); u16 type, u16 length);
void bnx2x_vfpf_finalize(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv);
void bnx2x_dp_tlv_list(struct bnx2x *bp, void *tlvs_list); void bnx2x_dp_tlv_list(struct bnx2x *bp, void *tlvs_list);
bool bnx2x_tlv_supported(u16 tlvtype); bool bnx2x_tlv_supported(u16 tlvtype);
...@@ -751,7 +752,7 @@ static inline int bnx2x_vf_ustorm_prods_offset(struct bnx2x *bp, ...@@ -751,7 +752,7 @@ static inline int bnx2x_vf_ustorm_prods_offset(struct bnx2x *bp,
} }
enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp); enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp);
void bnx2x_vf_map_doorbells(struct bnx2x *bp); void __iomem *bnx2x_vf_doorbells(struct bnx2x *bp);
int bnx2x_vf_pci_alloc(struct bnx2x *bp); int bnx2x_vf_pci_alloc(struct bnx2x *bp);
int bnx2x_enable_sriov(struct bnx2x *bp); int bnx2x_enable_sriov(struct bnx2x *bp);
void bnx2x_disable_sriov(struct bnx2x *bp); void bnx2x_disable_sriov(struct bnx2x *bp);
...@@ -808,7 +809,11 @@ static inline enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp ...@@ -808,7 +809,11 @@ static inline enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp
return PFVF_BULLETIN_UNCHANGED; return PFVF_BULLETIN_UNCHANGED;
} }
static inline int bnx2x_vf_map_doorbells(struct bnx2x *bp) {return 0; } static inline void __iomem *bnx2x_vf_doorbells(struct bnx2x *bp)
{
return NULL;
}
static inline int bnx2x_vf_pci_alloc(struct bnx2x *bp) {return 0; } static inline int bnx2x_vf_pci_alloc(struct bnx2x *bp) {return 0; }
static inline void bnx2x_pf_set_vfs_vlan(struct bnx2x *bp) {} static inline void bnx2x_pf_set_vfs_vlan(struct bnx2x *bp) {}
static inline int bnx2x_sriov_configure(struct pci_dev *dev, int num_vfs) {return 0; } static inline int bnx2x_sriov_configure(struct pci_dev *dev, int num_vfs) {return 0; }
......
...@@ -36,6 +36,8 @@ void bnx2x_add_tlv(struct bnx2x *bp, void *tlvs_list, u16 offset, u16 type, ...@@ -36,6 +36,8 @@ void bnx2x_add_tlv(struct bnx2x *bp, void *tlvs_list, u16 offset, u16 type,
void bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv, void bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv,
u16 type, u16 length) u16 type, u16 length)
{ {
mutex_lock(&bp->vf2pf_mutex);
DP(BNX2X_MSG_IOV, "preparing to send %d tlv over vf pf channel\n", DP(BNX2X_MSG_IOV, "preparing to send %d tlv over vf pf channel\n",
type); type);
...@@ -49,6 +51,15 @@ void bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv, ...@@ -49,6 +51,15 @@ void bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv,
first_tlv->resp_msg_offset = sizeof(bp->vf2pf_mbox->req); first_tlv->resp_msg_offset = sizeof(bp->vf2pf_mbox->req);
} }
/* releases the mailbox */
void bnx2x_vfpf_finalize(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv)
{
DP(BNX2X_MSG_IOV, "done sending [%d] tlv over vf pf channel\n",
first_tlv->tl.type);
mutex_unlock(&bp->vf2pf_mutex);
}
/* list the types and lengths of the tlvs on the buffer */ /* list the types and lengths of the tlvs on the buffer */
void bnx2x_dp_tlv_list(struct bnx2x *bp, void *tlvs_list) void bnx2x_dp_tlv_list(struct bnx2x *bp, void *tlvs_list)
{ {
...@@ -181,8 +192,10 @@ int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count) ...@@ -181,8 +192,10 @@ int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count)
/* clear mailbox and prep first tlv */ /* clear mailbox and prep first tlv */
bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_ACQUIRE, sizeof(*req)); bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_ACQUIRE, sizeof(*req));
if (bnx2x_get_vf_id(bp, &vf_id)) if (bnx2x_get_vf_id(bp, &vf_id)) {
return -EAGAIN; rc = -EAGAIN;
goto out;
}
req->vfdev_info.vf_id = vf_id; req->vfdev_info.vf_id = vf_id;
req->vfdev_info.vf_os = 0; req->vfdev_info.vf_os = 0;
...@@ -213,7 +226,7 @@ int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count) ...@@ -213,7 +226,7 @@ int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count)
/* PF timeout */ /* PF timeout */
if (rc) if (rc)
return rc; goto out;
/* copy acquire response from buffer to bp */ /* copy acquire response from buffer to bp */
memcpy(&bp->acquire_resp, resp, sizeof(bp->acquire_resp)); memcpy(&bp->acquire_resp, resp, sizeof(bp->acquire_resp));
...@@ -253,7 +266,8 @@ int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count) ...@@ -253,7 +266,8 @@ int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count)
/* PF reports error */ /* PF reports error */
BNX2X_ERR("Failed to get the requested amount of resources: %d. Breaking...\n", BNX2X_ERR("Failed to get the requested amount of resources: %d. Breaking...\n",
bp->acquire_resp.hdr.status); bp->acquire_resp.hdr.status);
return -EAGAIN; rc = -EAGAIN;
goto out;
} }
} }
...@@ -279,20 +293,24 @@ int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count) ...@@ -279,20 +293,24 @@ int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count)
bp->acquire_resp.resc.current_mac_addr, bp->acquire_resp.resc.current_mac_addr,
ETH_ALEN); ETH_ALEN);
return 0; out:
bnx2x_vfpf_finalize(bp, &req->first_tlv);
return rc;
} }
int bnx2x_vfpf_release(struct bnx2x *bp) int bnx2x_vfpf_release(struct bnx2x *bp)
{ {
struct vfpf_release_tlv *req = &bp->vf2pf_mbox->req.release; struct vfpf_release_tlv *req = &bp->vf2pf_mbox->req.release;
struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp; struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
u32 rc = 0, vf_id; u32 rc, vf_id;
/* clear mailbox and prep first tlv */ /* clear mailbox and prep first tlv */
bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_RELEASE, sizeof(*req)); bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_RELEASE, sizeof(*req));
if (bnx2x_get_vf_id(bp, &vf_id)) if (bnx2x_get_vf_id(bp, &vf_id)) {
return -EAGAIN; rc = -EAGAIN;
goto out;
}
req->vf_id = vf_id; req->vf_id = vf_id;
...@@ -308,7 +326,8 @@ int bnx2x_vfpf_release(struct bnx2x *bp) ...@@ -308,7 +326,8 @@ int bnx2x_vfpf_release(struct bnx2x *bp)
if (rc) if (rc)
/* PF timeout */ /* PF timeout */
return rc; goto out;
if (resp->hdr.status == PFVF_STATUS_SUCCESS) { if (resp->hdr.status == PFVF_STATUS_SUCCESS) {
/* PF released us */ /* PF released us */
DP(BNX2X_MSG_SP, "vf released\n"); DP(BNX2X_MSG_SP, "vf released\n");
...@@ -316,10 +335,13 @@ int bnx2x_vfpf_release(struct bnx2x *bp) ...@@ -316,10 +335,13 @@ int bnx2x_vfpf_release(struct bnx2x *bp)
/* PF reports error */ /* PF reports error */
BNX2X_ERR("PF failed our release request - are we out of sync? response status: %d\n", BNX2X_ERR("PF failed our release request - are we out of sync? response status: %d\n",
resp->hdr.status); resp->hdr.status);
return -EAGAIN; rc = -EAGAIN;
goto out;
} }
out:
bnx2x_vfpf_finalize(bp, &req->first_tlv);
return 0; return rc;
} }
/* Tell PF about SB addresses */ /* Tell PF about SB addresses */
...@@ -350,16 +372,20 @@ int bnx2x_vfpf_init(struct bnx2x *bp) ...@@ -350,16 +372,20 @@ int bnx2x_vfpf_init(struct bnx2x *bp)
rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping); rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
if (rc) if (rc)
return rc; goto out;
if (resp->hdr.status != PFVF_STATUS_SUCCESS) { if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
BNX2X_ERR("INIT VF failed: %d. Breaking...\n", BNX2X_ERR("INIT VF failed: %d. Breaking...\n",
resp->hdr.status); resp->hdr.status);
return -EAGAIN; rc = -EAGAIN;
goto out;
} }
DP(BNX2X_MSG_SP, "INIT VF Succeeded\n"); DP(BNX2X_MSG_SP, "INIT VF Succeeded\n");
return 0; out:
bnx2x_vfpf_finalize(bp, &req->first_tlv);
return rc;
} }
/* CLOSE VF - opposite to INIT_VF */ /* CLOSE VF - opposite to INIT_VF */
...@@ -401,6 +427,8 @@ void bnx2x_vfpf_close_vf(struct bnx2x *bp) ...@@ -401,6 +427,8 @@ void bnx2x_vfpf_close_vf(struct bnx2x *bp)
BNX2X_ERR("Sending CLOSE failed: pf response was %d\n", BNX2X_ERR("Sending CLOSE failed: pf response was %d\n",
resp->hdr.status); resp->hdr.status);
bnx2x_vfpf_finalize(bp, &req->first_tlv);
free_irq: free_irq:
/* Disable HW interrupts, NAPI */ /* Disable HW interrupts, NAPI */
bnx2x_netif_stop(bp, 0); bnx2x_netif_stop(bp, 0);
...@@ -485,8 +513,11 @@ int bnx2x_vfpf_setup_q(struct bnx2x *bp, int fp_idx) ...@@ -485,8 +513,11 @@ int bnx2x_vfpf_setup_q(struct bnx2x *bp, int fp_idx)
if (resp->hdr.status != PFVF_STATUS_SUCCESS) { if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
BNX2X_ERR("Status of SETUP_Q for queue[%d] is %d\n", BNX2X_ERR("Status of SETUP_Q for queue[%d] is %d\n",
fp_idx, resp->hdr.status); fp_idx, resp->hdr.status);
return -EINVAL; rc = -EINVAL;
} }
bnx2x_vfpf_finalize(bp, &req->first_tlv);
return rc; return rc;
} }
...@@ -514,17 +545,19 @@ int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx) ...@@ -514,17 +545,19 @@ int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx)
if (rc) { if (rc) {
BNX2X_ERR("Sending TEARDOWN for queue %d failed: %d\n", qidx, BNX2X_ERR("Sending TEARDOWN for queue %d failed: %d\n", qidx,
rc); rc);
return rc; goto out;
} }
/* PF failed the transaction */ /* PF failed the transaction */
if (resp->hdr.status != PFVF_STATUS_SUCCESS) { if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
BNX2X_ERR("TEARDOWN for queue %d failed: %d\n", qidx, BNX2X_ERR("TEARDOWN for queue %d failed: %d\n", qidx,
resp->hdr.status); resp->hdr.status);
return -EINVAL; rc = -EINVAL;
} }
return 0; out:
bnx2x_vfpf_finalize(bp, &req->first_tlv);
return rc;
} }
/* request pf to add a mac for the vf */ /* request pf to add a mac for the vf */
...@@ -532,7 +565,7 @@ int bnx2x_vfpf_set_mac(struct bnx2x *bp) ...@@ -532,7 +565,7 @@ int bnx2x_vfpf_set_mac(struct bnx2x *bp)
{ {
struct vfpf_set_q_filters_tlv *req = &bp->vf2pf_mbox->req.set_q_filters; struct vfpf_set_q_filters_tlv *req = &bp->vf2pf_mbox->req.set_q_filters;
struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp; struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
int rc; int rc = 0;
/* clear mailbox and prep first tlv */ /* clear mailbox and prep first tlv */
bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SET_Q_FILTERS, bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SET_Q_FILTERS,
...@@ -561,7 +594,7 @@ int bnx2x_vfpf_set_mac(struct bnx2x *bp) ...@@ -561,7 +594,7 @@ int bnx2x_vfpf_set_mac(struct bnx2x *bp)
rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping); rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
if (rc) { if (rc) {
BNX2X_ERR("failed to send message to pf. rc was %d\n", rc); BNX2X_ERR("failed to send message to pf. rc was %d\n", rc);
return rc; goto out;
} }
/* failure may mean PF was configured with a new mac for us */ /* failure may mean PF was configured with a new mac for us */
...@@ -586,8 +619,10 @@ int bnx2x_vfpf_set_mac(struct bnx2x *bp) ...@@ -586,8 +619,10 @@ int bnx2x_vfpf_set_mac(struct bnx2x *bp)
if (resp->hdr.status != PFVF_STATUS_SUCCESS) { if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
BNX2X_ERR("vfpf SET MAC failed: %d\n", resp->hdr.status); BNX2X_ERR("vfpf SET MAC failed: %d\n", resp->hdr.status);
return -EINVAL; rc = -EINVAL;
} }
out:
bnx2x_vfpf_finalize(bp, &req->first_tlv);
return 0; return 0;
} }
...@@ -642,14 +677,16 @@ int bnx2x_vfpf_set_mcast(struct net_device *dev) ...@@ -642,14 +677,16 @@ int bnx2x_vfpf_set_mcast(struct net_device *dev)
rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping); rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
if (rc) { if (rc) {
BNX2X_ERR("Sending a message failed: %d\n", rc); BNX2X_ERR("Sending a message failed: %d\n", rc);
return rc; goto out;
} }
if (resp->hdr.status != PFVF_STATUS_SUCCESS) { if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
BNX2X_ERR("Set Rx mode/multicast failed: %d\n", BNX2X_ERR("Set Rx mode/multicast failed: %d\n",
resp->hdr.status); resp->hdr.status);
return -EINVAL; rc = -EINVAL;
} }
out:
bnx2x_vfpf_finalize(bp, &req->first_tlv);
return 0; return 0;
} }
...@@ -688,7 +725,8 @@ int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp) ...@@ -688,7 +725,8 @@ int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp)
break; break;
default: default:
BNX2X_ERR("BAD rx mode (%d)\n", mode); BNX2X_ERR("BAD rx mode (%d)\n", mode);
return -EINVAL; rc = -EINVAL;
goto out;
} }
req->flags |= VFPF_SET_Q_FILTERS_RX_MASK_CHANGED; req->flags |= VFPF_SET_Q_FILTERS_RX_MASK_CHANGED;
...@@ -707,8 +745,10 @@ int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp) ...@@ -707,8 +745,10 @@ int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp)
if (resp->hdr.status != PFVF_STATUS_SUCCESS) { if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
BNX2X_ERR("Set Rx mode failed: %d\n", resp->hdr.status); BNX2X_ERR("Set Rx mode failed: %d\n", resp->hdr.status);
return -EINVAL; rc = -EINVAL;
} }
out:
bnx2x_vfpf_finalize(bp, &req->first_tlv);
return rc; return rc;
} }
......
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