]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
sif: rq: Use a workqueue to handle sif_flush_rq
authorWei Lin Guay <wei.lin.guay@oracle.com>
Fri, 1 Jul 2016 08:28:46 +0000 (10:28 +0200)
committerKnut Omang <knut.omang@oracle.com>
Sun, 3 Jul 2016 14:44:17 +0000 (16:44 +0200)
Orabug: 23491094

In sif_flush_rq, one of the required steps is to acquire
the qp mutex for qp state transition. Thus, this commit
moves the sif_flush_rq into a seperate singlethreaded
workqueue to ensure that sif_flush_rq is safe to call
from any context, including the interrupt context.

Signed-off-by: Wei Lin Guay <wei.lin.guay@oracle.com>
Reviewed-by: Knut Omang <knut.omang@oracle.com>
drivers/infiniband/hw/sif/sif_cq.c
drivers/infiniband/hw/sif/sif_dev.h
drivers/infiniband/hw/sif/sif_eq.c
drivers/infiniband/hw/sif/sif_main.c
drivers/infiniband/hw/sif/sif_qp.c
drivers/infiniband/hw/sif/sif_rq.c
drivers/infiniband/hw/sif/sif_rq.h
drivers/infiniband/hw/sif/sif_sndrcv.c

index 26270dee9e5be3007ad1e80ed46c7303da8ee077..6bc61e49ad3e071de2f5734886573206345b18b4 100644 (file)
@@ -468,7 +468,7 @@ static int handle_recv_wc(struct sif_dev *sdev, struct sif_cq *cq, struct ib_wc
                 */
                if (rq && !rq->is_srq
                    && !test_bit(SIF_QPS_IN_RESET, &qp->persistent_state)) {
-                       if (sif_flush_rq(sdev, rq, qp, rq_len))
+                       if (sif_flush_rq_wq(sdev, rq, qp, rq_len))
                                sif_log(sdev, SIF_INFO,
                                        "failed to flush RQ %d", rq->index);
                }
index b767004191c72980cd9e2eaeabf1934db42d247f..c92aecae5a062f6c24cfb31e09dc7469202e6047 100644 (file)
@@ -335,6 +335,7 @@ struct sif_dev {
 
        /* Owned by sif_r3.c - wa support */
        struct sif_wa_stats wa_stats;
+       struct workqueue_struct *misc_wq; /* Used to flush send/receive queue */
 };
 
 /* TBD: These should probably come from common pci headers
index 4bcf16c231f96e5c8d5a77fc84a44dab6a560c68..3c0f05c4537f75006102bf55b160b974df2c3474 100644 (file)
@@ -642,7 +642,7 @@ static void handle_event_work(struct work_struct *work)
                                ibqp->event_handler(&ibe, ibqp->qp_context);
                        } else {
                                /* WA #622: if reqular RQ, flush */
-                               if (sif_flush_rq(sdev, rq, qp, atomic_read(&rq_sw->length)))
+                               if (sif_flush_rq_wq(sdev, rq, qp, atomic_read(&rq_sw->length)))
                                        sif_log(sdev, SIF_INFO, "failed to flush RQ %d",
                                                rq->index);
                        }
index b53877e77738401674765c135795ebbdecc63fc1..cb0001b328a6611ba625e256778f6efb09cb3470 100644 (file)
@@ -253,6 +253,12 @@ static int sif_probe(struct pci_dev *pdev,
                err = -ENOMEM;
                goto wq_fail;
        }
+       sdev->misc_wq = create_singlethread_workqueue("sif_misc_wq");
+       if (!sdev->misc_wq) {
+               sif_log(sdev, SIF_INFO, "Failed to allocate sif misc work queue");
+               err = -ENOMEM;
+               goto wq_fail;
+       }
 
        err = sif_set_check_max_payload(sdev);
        if (err)
@@ -420,7 +426,9 @@ static void sif_remove(struct pci_dev *dev)
        pci_clear_master(dev);
        pci_disable_device(dev);
        flush_workqueue(sdev->wq);
+       flush_workqueue(sdev->misc_wq);
        destroy_workqueue(sdev->wq);
+       destroy_workqueue(sdev->misc_wq);
        sif_log(sdev, SIF_INFO, "removed device %s", sdev->ib_dev.name);
        ib_dealloc_device(&sdev->ib_dev);
 }
index 0e151111b9e5fe045077e284cf49bfe8914a09c7..53b578e092e80245e75418bee5156204aef10085 100644 (file)
@@ -969,7 +969,7 @@ int modify_qp(struct sif_dev *sdev, struct sif_qp *qp,
                                        "flush requested for qp(type %s) with no rq defined",
                                        string_enum_psif_qp_trans(qp->type));
                        } else {
-                               ret = sif_flush_rq(sdev, rq, qp, rq->entries);
+                               ret = sif_flush_rq_wq(sdev, rq, qp, rq->entries);
                                if (ret)
                                        sif_log(sdev, SIF_INFO, "failed to flush RQ %d", rq->index);
                        }
@@ -1068,7 +1068,7 @@ sif_mqp_ret:
                                qp->ibqp.event_handler(&ibe, qp->ibqp.qp_context);
                        } else if (!rq->is_srq) {
                                /* WA #622: if reqular RQ, flush */
-                               ret = sif_flush_rq(sdev, rq, qp, rq->entries);
+                               ret = sif_flush_rq_wq(sdev, rq, qp, rq->entries);
                                if (ret) {
                                        sif_log(sdev, SIF_INFO, "failed to flush RQ %d",
                                                rq->index);
index bf079af70f83d2ff4ac02de6ec7848922ea45517..e3154ae35319ed57b5bdbc5e606d9483ac8019e7 100644 (file)
@@ -22,6 +22,8 @@
 #include "sif_defs.h"
 #include <linux/seq_file.h>
 
+static void sif_flush_rq(struct work_struct *work);
+
 int poll_wait_for_rq_writeback(struct sif_dev *sdev, struct sif_rq *rq)
 {
        unsigned long timeout = sdev->min_resp_ticks;
@@ -277,6 +279,30 @@ static int find_recv_cqes_in_cq(struct sif_dev *sdev, struct sif_cq *cq, struct
        return n;
 }
 
+
+int sif_flush_rq_wq(struct sif_dev *sdev, struct sif_rq *rq, struct sif_qp *target_qp,
+                   int max_flushed_in_err)
+{
+       struct flush_rq_work *work;
+
+       work = kzalloc(sizeof(*work), GFP_ATOMIC);
+       if (!work)
+               return -ENOMEM;
+
+
+       memset(work, 0, sizeof(*work));
+       work->qp = target_qp;
+       work->sdev = sdev;
+       work->rq = rq;
+       work->entries = max_flushed_in_err;
+
+       INIT_WORK(&work->ws, sif_flush_rq);
+
+       queue_work(sdev->misc_wq, &work->ws);
+
+       return 0;
+}
+
 /* Invalidate the RQ cache and flush a desired amount of
  * the remaining entries in the given receive queue.
  * @target_qp indicates the value of the local_qp field in the generated
@@ -296,10 +322,14 @@ static int find_recv_cqes_in_cq(struct sif_dev *sdev, struct sif_cq *cq, struct
  * Note: No locking of the RQ is neccessary as there are multiple trigger points
  * for flushing RQEs within OFED verbs model.
  */
-int sif_flush_rq(struct sif_dev *sdev, struct sif_rq *rq, struct sif_qp *target_qp,
-               int max_flushed_in_err)
+static void sif_flush_rq(struct work_struct *work)
 {
        int len, real_len;
+       struct flush_rq_work *rq_work = container_of(work, struct flush_rq_work, ws);
+       struct sif_dev *sdev = rq_work->sdev;
+       struct sif_qp *target_qp = rq_work->qp;
+       struct sif_rq *rq = rq_work->rq;
+       int max_flushed_in_err = rq_work->entries;
        struct sif_rq_sw *rq_sw = get_sif_rq_sw(sdev, rq->index);
        int ret = 0;
        u32 head, tail;
@@ -311,7 +341,7 @@ int sif_flush_rq(struct sif_dev *sdev, struct sif_rq *rq, struct sif_qp *target_
         */
        if (test_bit(FLUSH_RQ_IN_PROGRESS, &rq_sw->flags)) {
                set_bit(FLUSH_RQ_IN_FLIGHT, &rq_sw->flags);
-               return ret;
+               goto done;
        }
 
        /* if race condition happened while trying to flush RQ,
@@ -319,7 +349,7 @@ int sif_flush_rq(struct sif_dev *sdev, struct sif_rq *rq, struct sif_qp *target_
         */
        if (test_and_set_bit(FLUSH_RQ_IN_PROGRESS, &rq_sw->flags)) {
                set_bit(FLUSH_RQ_IN_FLIGHT, &rq_sw->flags);
-               return ret;
+               goto done;
        }
 
        if (!sif_feature(disable_rq_flush))
@@ -544,7 +574,8 @@ free_rq_error:
        }
 error:
        clear_bit(FLUSH_RQ_IN_PROGRESS, &rq_sw->flags);
-       return ret = ret > 0 ? 0 : ret;
+done:
+       kfree(rq_work);
 }
 
 
index 8dd2fcb37cef610608f6df0914dbca24bbcf89f9..f7aea2cb5a180679d8a6644a7e259e5d9855e200 100644 (file)
@@ -36,6 +36,14 @@ struct sif_rq {
        struct sif_mem *mem; /* Allocated queue memory */
 };
 
+struct flush_rq_work {
+       struct work_struct ws;
+       struct sif_dev *sdev;
+       struct sif_rq *rq;
+       struct sif_qp *qp;
+       int entries;
+};
+
 static inline struct sif_rq *to_srq(struct ib_srq *ibsrq)
 {
        return container_of(ibsrq, struct sif_rq, ibsrq);
@@ -58,7 +66,7 @@ int alloc_rq(struct sif_dev *sdev, struct sif_pd *pd,
  * @target_qp indicates the value of the local_qp field in the generated
  * completion but is not interpreted by SIF in any way.
  */
-int sif_flush_rq(struct sif_dev *sdev, struct sif_rq *rq,
+int sif_flush_rq_wq(struct sif_dev *sdev, struct sif_rq *rq,
                struct sif_qp *target_qp, int max_flushed_in_err);
 
 int free_rq(struct sif_dev *sdev, int rq_idx);
index aad7fa0ece3b49270839d6ad1e8ce46cb4473526..43ec8ed9a7d925b87b242ec9043668977915c19e 100644 (file)
@@ -752,7 +752,7 @@ err_post_recv:
 
        /* WA #622, Check if QP in ERROR, flush RQ */
        if (!rq->is_srq && qp->last_set_state == IB_QPS_ERR) {
-               if (sif_flush_rq(sdev, rq, qp, atomic_read(&rq_sw->length)))
+               if (sif_flush_rq_wq(sdev, rq, qp, atomic_read(&rq_sw->length)))
                        sif_log(sdev, SIF_INFO, "failed to flush RQ %d", rq->index);
        }