]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
IB/core: Add an unbound WQ type to the new CQ API
authorJack Morgenstein <jackm@dev.mellanox.co.il>
Mon, 27 Aug 2018 05:35:55 +0000 (08:35 +0300)
committerKleber Sacilotto de Souza <kleber.souza@canonical.com>
Wed, 16 Oct 2019 09:55:13 +0000 (11:55 +0200)
BugLink: https://bugs.launchpad.net/bugs/1847155
commit f794809a7259dfaa3d47d90ef5a86007cf48b1ce upstream.

The upstream kernel commit cited below modified the workqueue in the
new CQ API to be bound to a specific CPU (instead of being unbound).
This caused ALL users of the new CQ API to use the same bound WQ.

Specifically, MAD handling was severely delayed when the CPU bound
to the WQ was busy handling (higher priority) interrupts.

This caused a delay in the MAD "heartbeat" response handling,
which resulted in ports being incorrectly classified as "down".

To fix this, add a new "unbound" WQ type to the new CQ API, so that users
have the option to choose either a bound WQ or an unbound WQ.

For MADs, choose the new "unbound" WQ.

Fixes: b7363e67b23e ("IB/device: Convert ib-comp-wq to be CPU-bound")
Signed-off-by: Jack Morgenstein <jackm@dev.mellanox.co.il>
Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
Reviewed-by: Sagi Grimberg <sagi@grimberg.m>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
drivers/infiniband/core/cq.c
drivers/infiniband/core/device.c
drivers/infiniband/core/mad.c
include/rdma/ib_verbs.h

index 757d308bebe84c2a9b093c44dc46654f50304022..88c54db16f29be8a8ee23c2cc98988554588b7db 100644 (file)
@@ -112,12 +112,12 @@ static void ib_cq_poll_work(struct work_struct *work)
                                    IB_POLL_BATCH);
        if (completed >= IB_POLL_BUDGET_WORKQUEUE ||
            ib_req_notify_cq(cq, IB_POLL_FLAGS) > 0)
-               queue_work(ib_comp_wq, &cq->work);
+               queue_work(cq->comp_wq, &cq->work);
 }
 
 static void ib_cq_completion_workqueue(struct ib_cq *cq, void *private)
 {
-       queue_work(ib_comp_wq, &cq->work);
+       queue_work(cq->comp_wq, &cq->work);
 }
 
 /**
@@ -169,9 +169,12 @@ struct ib_cq *ib_alloc_cq(struct ib_device *dev, void *private,
                ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
                break;
        case IB_POLL_WORKQUEUE:
+       case IB_POLL_UNBOUND_WORKQUEUE:
                cq->comp_handler = ib_cq_completion_workqueue;
                INIT_WORK(&cq->work, ib_cq_poll_work);
                ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
+               cq->comp_wq = (cq->poll_ctx == IB_POLL_WORKQUEUE) ?
+                               ib_comp_wq : ib_comp_unbound_wq;
                break;
        default:
                ret = -EINVAL;
@@ -206,6 +209,7 @@ void ib_free_cq(struct ib_cq *cq)
                irq_poll_disable(&cq->iop);
                break;
        case IB_POLL_WORKQUEUE:
+       case IB_POLL_UNBOUND_WORKQUEUE:
                cancel_work_sync(&cq->work);
                break;
        default:
index 4dff06ab771ec010c4d86eb21b35f65889d7cf8a..61ade4b3e7bb56cb6b6081f186a8bb221a4a18cf 100644 (file)
@@ -61,6 +61,7 @@ struct ib_client_data {
 };
 
 struct workqueue_struct *ib_comp_wq;
+struct workqueue_struct *ib_comp_unbound_wq;
 struct workqueue_struct *ib_wq;
 EXPORT_SYMBOL_GPL(ib_wq);
 
@@ -1202,10 +1203,19 @@ static int __init ib_core_init(void)
                goto err;
        }
 
+       ib_comp_unbound_wq =
+               alloc_workqueue("ib-comp-unb-wq",
+                               WQ_UNBOUND | WQ_HIGHPRI | WQ_MEM_RECLAIM |
+                               WQ_SYSFS, WQ_UNBOUND_MAX_ACTIVE);
+       if (!ib_comp_unbound_wq) {
+               ret = -ENOMEM;
+               goto err_comp;
+       }
+
        ret = class_register(&ib_class);
        if (ret) {
                pr_warn("Couldn't create InfiniBand device class\n");
-               goto err_comp;
+               goto err_comp_unbound;
        }
 
        ret = rdma_nl_init();
@@ -1254,6 +1264,8 @@ err_ibnl:
        rdma_nl_exit();
 err_sysfs:
        class_unregister(&ib_class);
+err_comp_unbound:
+       destroy_workqueue(ib_comp_unbound_wq);
 err_comp:
        destroy_workqueue(ib_comp_wq);
 err:
@@ -1272,6 +1284,7 @@ static void __exit ib_core_cleanup(void)
        addr_cleanup();
        rdma_nl_exit();
        class_unregister(&ib_class);
+       destroy_workqueue(ib_comp_unbound_wq);
        destroy_workqueue(ib_comp_wq);
        /* Make sure that any pending umem accounting work is done. */
        destroy_workqueue(ib_wq);
index 49b6da1d990fcebf5e3ebf8294a99561afe7a5f3..e4339b9e43a54351ca46ae71c9bc5672bffe59fd 100644 (file)
@@ -3178,7 +3178,7 @@ static int ib_mad_port_open(struct ib_device *device,
        }
 
        port_priv->cq = ib_alloc_cq(port_priv->device, port_priv, cq_size, 0,
-                       IB_POLL_WORKQUEUE);
+                       IB_POLL_UNBOUND_WORKQUEUE);
        if (IS_ERR(port_priv->cq)) {
                dev_err(&device->dev, "Couldn't create ib_mad CQ\n");
                ret = PTR_ERR(port_priv->cq);
index 9d7278b2672045cdf62e8f73d268011f72ff304c..be88fef7ae1b0efdc4a78970d4da7c639fa21a40 100644 (file)
@@ -68,6 +68,7 @@
 
 extern struct workqueue_struct *ib_wq;
 extern struct workqueue_struct *ib_comp_wq;
+extern struct workqueue_struct *ib_comp_unbound_wq;
 
 union ib_gid {
        u8      raw[16];
@@ -1557,9 +1558,10 @@ struct ib_ah {
 typedef void (*ib_comp_handler)(struct ib_cq *cq, void *cq_context);
 
 enum ib_poll_context {
-       IB_POLL_DIRECT,         /* caller context, no hw completions */
-       IB_POLL_SOFTIRQ,        /* poll from softirq context */
-       IB_POLL_WORKQUEUE,      /* poll from workqueue */
+       IB_POLL_DIRECT,            /* caller context, no hw completions */
+       IB_POLL_SOFTIRQ,           /* poll from softirq context */
+       IB_POLL_WORKQUEUE,         /* poll from workqueue */
+       IB_POLL_UNBOUND_WORKQUEUE, /* poll from unbound workqueue */
 };
 
 struct ib_cq {
@@ -1576,6 +1578,7 @@ struct ib_cq {
                struct irq_poll         iop;
                struct work_struct      work;
        };
+       struct workqueue_struct *comp_wq;
 };
 
 struct ib_srq {