summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
diff options
context:
space:
mode:
authorYuval Mintz <Yuval.Mintz@qlogic.com>2014-03-23 20:12:24 +0400
committerDavid S. Miller <davem@davemloft.net>2014-03-26 05:07:03 +0400
commit370d4a26590fcc7510ad4a8432e4982a209f1b59 (patch)
treec6047611d7d2661fd10e0117411c4762336a3b26 /drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
parent42f8277f56cf4a9570b1f0fe10a4fec3f48c832a (diff)
downloadlinux-370d4a26590fcc7510ad4a8432e4982a209f1b59.tar.xz
bnx2x: Create workqueue for IOV related tasks
The bnx2x sriov mechanisms were done in the bnx2x slowpath workitem which runs on the bnx2x's workqueue; This workitem is also responsible for the bottom half of interrupt handling in the driver, and specifically it also receives FW notifications of ramrod completions, allowing other flows to progress. The original design of the sriov reltaed-flows was based on the notion such flows must not sleep, since their context is the slowpath workitem. Otherwise, we might reach timeouts - those flows may wait for ramrod completion that will never arrive as the workitem wlll not be re-scheduled until that same flow will be over. In more recent time bnx2x started supporting features in which the VF interface can be configured by the tools accessing the PF on the hypervisor. This support created possible races on the VF-PF lock (which is taken either when the PF is handling a VF message or when the PF is doing some slowpath work on behalf of the VF) which may cause timeouts on the VF side and lags on the PF side. This patch changes the scheme - it creates a new workqueue for sriov related tasks and moves all handling currently done in the slowpath task into the the new workqueue. Signed-off-by: Yuval Mintz <Yuval.Mintz@qlogic.com> Signed-off-by: Ariel Elior <Ariel.Elior@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c')
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c41
1 files changed, 36 insertions, 5 deletions
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
index 61e6f606d8a4..8e2b191234f1 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
@@ -2042,6 +2042,9 @@ int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param,
goto failed;
}
+ /* Prepare the VFs event synchronization mechanism */
+ mutex_init(&bp->vfdb->event_mutex);
+
return 0;
failed:
DP(BNX2X_MSG_IOV, "Failed err=%d\n", err);
@@ -2469,7 +2472,7 @@ get_vf:
return 0;
}
/* SRIOV: reschedule any 'in_progress' operations */
- bnx2x_iov_sp_event(bp, cid, false);
+ bnx2x_iov_sp_event(bp, cid);
return 0;
}
@@ -2506,7 +2509,7 @@ void bnx2x_iov_set_queue_sp_obj(struct bnx2x *bp, int vf_cid,
}
}
-void bnx2x_iov_sp_event(struct bnx2x *bp, int vf_cid, bool queue_work)
+void bnx2x_iov_sp_event(struct bnx2x *bp, int vf_cid)
{
struct bnx2x_virtf *vf;
@@ -2518,8 +2521,7 @@ void bnx2x_iov_sp_event(struct bnx2x *bp, int vf_cid, bool queue_work)
if (vf) {
/* set in_progress flag */
atomic_set(&vf->op_in_progress, 1);
- if (queue_work)
- queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
+ bnx2x_schedule_iov_task(bp, BNX2X_IOV_CONT_VFOP);
}
}
@@ -2604,7 +2606,7 @@ void bnx2x_iov_adjust_stats_req(struct bnx2x *bp)
bp->fw_stats_req->hdr.cmd_num = bp->fw_stats_num + stats_count;
}
-void bnx2x_iov_sp_task(struct bnx2x *bp)
+void bnx2x_iov_vfop_cont(struct bnx2x *bp)
{
int i;
@@ -3875,3 +3877,32 @@ void bnx2x_iov_channel_down(struct bnx2x *bp)
bnx2x_post_vf_bulletin(bp, vf_idx);
}
}
+
+void bnx2x_iov_task(struct work_struct *work)
+{
+ struct bnx2x *bp = container_of(work, struct bnx2x, iov_task.work);
+
+ if (!netif_running(bp->dev))
+ return;
+
+ if (test_and_clear_bit(BNX2X_IOV_HANDLE_FLR,
+ &bp->iov_task_state))
+ bnx2x_vf_handle_flr_event(bp);
+
+ if (test_and_clear_bit(BNX2X_IOV_CONT_VFOP,
+ &bp->iov_task_state))
+ bnx2x_iov_vfop_cont(bp);
+
+ if (test_and_clear_bit(BNX2X_IOV_HANDLE_VF_MSG,
+ &bp->iov_task_state))
+ bnx2x_vf_mbx(bp);
+}
+
+void bnx2x_schedule_iov_task(struct bnx2x *bp, enum bnx2x_iov_flag flag)
+{
+ smp_mb__before_clear_bit();
+ set_bit(flag, &bp->iov_task_state);
+ smp_mb__after_clear_bit();
+ DP(BNX2X_MSG_IOV, "Scheduling iov task [Flag: %d]\n", flag);
+ queue_delayed_work(bnx2x_iov_wq, &bp->iov_task, 0);
+}