Skip to content

Commit fd3c615

Browse files
Mintz, Yuvaldavem330
authored andcommitted
qed: Fix race with multiple VFs
A PF syncronizes all IOV activity relating to its VFs by using a single workqueue handling the work. The workqueue would reach a bitmask of pending VF events and act upon each in turn. Problem is that the indication of a VF message [which sets the 'vf event' bit for that VF] arrives and is set in the slowpath attention context, which isn't syncronized with the processing of the events. When multiple VFs are present, it's possible that PF would lose the indication of one of the VF's pending evens, leading that VF to later timeout. Instead of adding locks/barriers, simply move from a bitmask into a per-VF indication inside that VF entry in the PF database. Signed-off-by: Yuval Mintz <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 4ca257e commit fd3c615

File tree

2 files changed

+26
-17
lines changed

2 files changed

+26
-17
lines changed

drivers/net/ethernet/qlogic/qed/qed_sriov.c

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3014,8 +3014,7 @@ qed_iov_execute_vf_flr_cleanup(struct qed_hwfn *p_hwfn,
30143014
ack_vfs[vfid / 32] |= BIT((vfid % 32));
30153015
p_hwfn->pf_iov_info->pending_flr[rel_vf_id / 64] &=
30163016
~(1ULL << (rel_vf_id % 64));
3017-
p_hwfn->pf_iov_info->pending_events[rel_vf_id / 64] &=
3018-
~(1ULL << (rel_vf_id % 64));
3017+
p_vf->vf_mbx.b_pending_msg = false;
30193018
}
30203019

30213020
return rc;
@@ -3128,11 +3127,20 @@ static void qed_iov_process_mbx_req(struct qed_hwfn *p_hwfn,
31283127
mbx = &p_vf->vf_mbx;
31293128

31303129
/* qed_iov_process_mbx_request */
3131-
DP_VERBOSE(p_hwfn, QED_MSG_IOV,
3132-
"VF[%02x]: Processing mailbox message\n", p_vf->abs_vf_id);
3130+
if (!mbx->b_pending_msg) {
3131+
DP_NOTICE(p_hwfn,
3132+
"VF[%02x]: Trying to process mailbox message when none is pending\n",
3133+
p_vf->abs_vf_id);
3134+
return;
3135+
}
3136+
mbx->b_pending_msg = false;
31333137

31343138
mbx->first_tlv = mbx->req_virt->first_tlv;
31353139

3140+
DP_VERBOSE(p_hwfn, QED_MSG_IOV,
3141+
"VF[%02x]: Processing mailbox message [type %04x]\n",
3142+
p_vf->abs_vf_id, mbx->first_tlv.tl.type);
3143+
31363144
/* check if tlv type is known */
31373145
if (qed_iov_tlv_supported(mbx->first_tlv.tl.type) &&
31383146
!p_vf->b_malicious) {
@@ -3219,20 +3227,19 @@ static void qed_iov_process_mbx_req(struct qed_hwfn *p_hwfn,
32193227
}
32203228
}
32213229

3222-
static void qed_iov_pf_add_pending_events(struct qed_hwfn *p_hwfn, u8 vfid)
3230+
void qed_iov_pf_get_pending_events(struct qed_hwfn *p_hwfn, u64 *events)
32233231
{
3224-
u64 add_bit = 1ULL << (vfid % 64);
3232+
int i;
32253233

3226-
p_hwfn->pf_iov_info->pending_events[vfid / 64] |= add_bit;
3227-
}
3234+
memset(events, 0, sizeof(u64) * QED_VF_ARRAY_LENGTH);
32283235

3229-
static void qed_iov_pf_get_and_clear_pending_events(struct qed_hwfn *p_hwfn,
3230-
u64 *events)
3231-
{
3232-
u64 *p_pending_events = p_hwfn->pf_iov_info->pending_events;
3236+
qed_for_each_vf(p_hwfn, i) {
3237+
struct qed_vf_info *p_vf;
32333238

3234-
memcpy(events, p_pending_events, sizeof(u64) * QED_VF_ARRAY_LENGTH);
3235-
memset(p_pending_events, 0, sizeof(u64) * QED_VF_ARRAY_LENGTH);
3239+
p_vf = &p_hwfn->pf_iov_info->vfs_array[i];
3240+
if (p_vf->vf_mbx.b_pending_msg)
3241+
events[i / 64] |= 1ULL << (i % 64);
3242+
}
32363243
}
32373244

32383245
static struct qed_vf_info *qed_sriov_get_vf_from_absid(struct qed_hwfn *p_hwfn,
@@ -3266,7 +3273,7 @@ static int qed_sriov_vfpf_msg(struct qed_hwfn *p_hwfn,
32663273
p_vf->vf_mbx.pending_req = (((u64)vf_msg->hi) << 32) | vf_msg->lo;
32673274

32683275
/* Mark the event and schedule the workqueue */
3269-
qed_iov_pf_add_pending_events(p_hwfn, p_vf->relative_vf_id);
3276+
p_vf->vf_mbx.b_pending_msg = true;
32703277
qed_schedule_iov(p_hwfn, QED_IOV_WQ_MSG_FLAG);
32713278

32723279
return 0;
@@ -4030,7 +4037,7 @@ static void qed_handle_vf_msg(struct qed_hwfn *hwfn)
40304037
return;
40314038
}
40324039

4033-
qed_iov_pf_get_and_clear_pending_events(hwfn, events);
4040+
qed_iov_pf_get_pending_events(hwfn, events);
40344041

40354042
DP_VERBOSE(hwfn, QED_MSG_IOV,
40364043
"Event mask of VF events: 0x%llx 0x%llx 0x%llx\n",

drivers/net/ethernet/qlogic/qed/qed_sriov.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,9 @@ struct qed_iov_vf_mbx {
140140
/* Address in VF where a pending message is located */
141141
dma_addr_t pending_req;
142142

143+
/* Message from VF awaits handling */
144+
bool b_pending_msg;
145+
143146
u8 *offset;
144147

145148
/* saved VF request header */
@@ -232,7 +235,6 @@ struct qed_vf_info {
232235
*/
233236
struct qed_pf_iov {
234237
struct qed_vf_info vfs_array[MAX_NUM_VFS];
235-
u64 pending_events[QED_VF_ARRAY_LENGTH];
236238
u64 pending_flr[QED_VF_ARRAY_LENGTH];
237239

238240
/* Allocate message address continuosuly and split to each VF */

0 commit comments

Comments
 (0)