diff options
author | Mike Marciniszyn <mike.marciniszyn@intel.com> | 2013-06-04 15:05:37 -0400 |
---|---|---|
committer | Roland Dreier <roland@purestorage.com> | 2013-06-21 20:19:49 -0400 |
commit | 85caafe307a06e4f9993c8f3c994a07374c07831 (patch) | |
tree | c17964cc02d75f2bb6f827eed9daeec719b85d17 /drivers/infiniband/hw | |
parent | c804f07248895ff9c9dccb6cda703068a0657b6c (diff) |
IB/qib: Optimize CQ callbacks
The current workqueue implemention has the following performance
deficiencies on QDR HCAs:
- The CQ call backs tend to run on the CPUs processing the
receive queues
- The single thread queue isn't optimal for multiple HCAs
This patch adds a dedicated per HCA bound thread to process CQ callbacks.
Reviewed-by: Ramkrishna Vepa <ramkrishna.vepa@intel.com>
Signed-off-by: Mike Marciniszyn <mike.marciniszyn@intel.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
Diffstat (limited to 'drivers/infiniband/hw')
-rw-r--r-- | drivers/infiniband/hw/qib/qib.h | 5 | ||||
-rw-r--r-- | drivers/infiniband/hw/qib/qib_cq.c | 67 | ||||
-rw-r--r-- | drivers/infiniband/hw/qib/qib_init.c | 18 | ||||
-rw-r--r-- | drivers/infiniband/hw/qib/qib_verbs.h | 10 |
4 files changed, 76 insertions, 24 deletions
diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h index 2ee82e6550c7..3a78b92cbd4e 100644 --- a/drivers/infiniband/hw/qib/qib.h +++ b/drivers/infiniband/hw/qib/qib.h | |||
@@ -1,7 +1,7 @@ | |||
1 | #ifndef _QIB_KERNEL_H | 1 | #ifndef _QIB_KERNEL_H |
2 | #define _QIB_KERNEL_H | 2 | #define _QIB_KERNEL_H |
3 | /* | 3 | /* |
4 | * Copyright (c) 2012 Intel Corporation. All rights reserved. | 4 | * Copyright (c) 2012, 2013 Intel Corporation. All rights reserved. |
5 | * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved. | 5 | * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved. |
6 | * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. | 6 | * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. |
7 | * | 7 | * |
@@ -51,6 +51,7 @@ | |||
51 | #include <linux/completion.h> | 51 | #include <linux/completion.h> |
52 | #include <linux/kref.h> | 52 | #include <linux/kref.h> |
53 | #include <linux/sched.h> | 53 | #include <linux/sched.h> |
54 | #include <linux/kthread.h> | ||
54 | 55 | ||
55 | #include "qib_common.h" | 56 | #include "qib_common.h" |
56 | #include "qib_verbs.h" | 57 | #include "qib_verbs.h" |
@@ -1090,6 +1091,8 @@ struct qib_devdata { | |||
1090 | u16 psxmitwait_check_rate; | 1091 | u16 psxmitwait_check_rate; |
1091 | /* high volume overflow errors defered to tasklet */ | 1092 | /* high volume overflow errors defered to tasklet */ |
1092 | struct tasklet_struct error_tasklet; | 1093 | struct tasklet_struct error_tasklet; |
1094 | /* per device cq worker */ | ||
1095 | struct kthread_worker *worker; | ||
1093 | 1096 | ||
1094 | int assigned_node_id; /* NUMA node closest to HCA */ | 1097 | int assigned_node_id; /* NUMA node closest to HCA */ |
1095 | }; | 1098 | }; |
diff --git a/drivers/infiniband/hw/qib/qib_cq.c b/drivers/infiniband/hw/qib/qib_cq.c index 5246aa486bbe..ab4e11cfab15 100644 --- a/drivers/infiniband/hw/qib/qib_cq.c +++ b/drivers/infiniband/hw/qib/qib_cq.c | |||
@@ -1,4 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2013 Intel Corporation. All rights reserved. | ||
2 | * Copyright (c) 2006, 2007, 2008, 2010 QLogic Corporation. All rights reserved. | 3 | * Copyright (c) 2006, 2007, 2008, 2010 QLogic Corporation. All rights reserved. |
3 | * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved. | 4 | * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved. |
4 | * | 5 | * |
@@ -34,8 +35,10 @@ | |||
34 | #include <linux/err.h> | 35 | #include <linux/err.h> |
35 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
36 | #include <linux/vmalloc.h> | 37 | #include <linux/vmalloc.h> |
38 | #include <linux/kthread.h> | ||
37 | 39 | ||
38 | #include "qib_verbs.h" | 40 | #include "qib_verbs.h" |
41 | #include "qib.h" | ||
39 | 42 | ||
40 | /** | 43 | /** |
41 | * qib_cq_enter - add a new entry to the completion queue | 44 | * qib_cq_enter - add a new entry to the completion queue |
@@ -102,13 +105,18 @@ void qib_cq_enter(struct qib_cq *cq, struct ib_wc *entry, int solicited) | |||
102 | if (cq->notify == IB_CQ_NEXT_COMP || | 105 | if (cq->notify == IB_CQ_NEXT_COMP || |
103 | (cq->notify == IB_CQ_SOLICITED && | 106 | (cq->notify == IB_CQ_SOLICITED && |
104 | (solicited || entry->status != IB_WC_SUCCESS))) { | 107 | (solicited || entry->status != IB_WC_SUCCESS))) { |
105 | cq->notify = IB_CQ_NONE; | 108 | struct kthread_worker *worker; |
106 | cq->triggered++; | ||
107 | /* | 109 | /* |
108 | * This will cause send_complete() to be called in | 110 | * This will cause send_complete() to be called in |
109 | * another thread. | 111 | * another thread. |
110 | */ | 112 | */ |
111 | queue_work(qib_cq_wq, &cq->comptask); | 113 | smp_rmb(); |
114 | worker = cq->dd->worker; | ||
115 | if (likely(worker)) { | ||
116 | cq->notify = IB_CQ_NONE; | ||
117 | cq->triggered++; | ||
118 | queue_kthread_work(worker, &cq->comptask); | ||
119 | } | ||
112 | } | 120 | } |
113 | 121 | ||
114 | spin_unlock_irqrestore(&cq->lock, flags); | 122 | spin_unlock_irqrestore(&cq->lock, flags); |
@@ -163,7 +171,7 @@ bail: | |||
163 | return npolled; | 171 | return npolled; |
164 | } | 172 | } |
165 | 173 | ||
166 | static void send_complete(struct work_struct *work) | 174 | static void send_complete(struct kthread_work *work) |
167 | { | 175 | { |
168 | struct qib_cq *cq = container_of(work, struct qib_cq, comptask); | 176 | struct qib_cq *cq = container_of(work, struct qib_cq, comptask); |
169 | 177 | ||
@@ -287,11 +295,12 @@ struct ib_cq *qib_create_cq(struct ib_device *ibdev, int entries, | |||
287 | * The number of entries should be >= the number requested or return | 295 | * The number of entries should be >= the number requested or return |
288 | * an error. | 296 | * an error. |
289 | */ | 297 | */ |
298 | cq->dd = dd_from_dev(dev); | ||
290 | cq->ibcq.cqe = entries; | 299 | cq->ibcq.cqe = entries; |
291 | cq->notify = IB_CQ_NONE; | 300 | cq->notify = IB_CQ_NONE; |
292 | cq->triggered = 0; | 301 | cq->triggered = 0; |
293 | spin_lock_init(&cq->lock); | 302 | spin_lock_init(&cq->lock); |
294 | INIT_WORK(&cq->comptask, send_complete); | 303 | init_kthread_work(&cq->comptask, send_complete); |
295 | wc->head = 0; | 304 | wc->head = 0; |
296 | wc->tail = 0; | 305 | wc->tail = 0; |
297 | cq->queue = wc; | 306 | cq->queue = wc; |
@@ -323,7 +332,7 @@ int qib_destroy_cq(struct ib_cq *ibcq) | |||
323 | struct qib_ibdev *dev = to_idev(ibcq->device); | 332 | struct qib_ibdev *dev = to_idev(ibcq->device); |
324 | struct qib_cq *cq = to_icq(ibcq); | 333 | struct qib_cq *cq = to_icq(ibcq); |
325 | 334 | ||
326 | flush_work(&cq->comptask); | 335 | flush_kthread_work(&cq->comptask); |
327 | spin_lock(&dev->n_cqs_lock); | 336 | spin_lock(&dev->n_cqs_lock); |
328 | dev->n_cqs_allocated--; | 337 | dev->n_cqs_allocated--; |
329 | spin_unlock(&dev->n_cqs_lock); | 338 | spin_unlock(&dev->n_cqs_lock); |
@@ -483,3 +492,49 @@ bail_free: | |||
483 | bail: | 492 | bail: |
484 | return ret; | 493 | return ret; |
485 | } | 494 | } |
495 | |||
496 | int qib_cq_init(struct qib_devdata *dd) | ||
497 | { | ||
498 | int ret = 0; | ||
499 | int cpu; | ||
500 | struct task_struct *task; | ||
501 | |||
502 | if (dd->worker) | ||
503 | return 0; | ||
504 | dd->worker = kzalloc(sizeof(*dd->worker), GFP_KERNEL); | ||
505 | if (!dd->worker) | ||
506 | return -ENOMEM; | ||
507 | init_kthread_worker(dd->worker); | ||
508 | task = kthread_create_on_node( | ||
509 | kthread_worker_fn, | ||
510 | dd->worker, | ||
511 | dd->assigned_node_id, | ||
512 | "qib_cq%d", dd->unit); | ||
513 | if (IS_ERR(task)) | ||
514 | goto task_fail; | ||
515 | cpu = cpumask_first(cpumask_of_node(dd->assigned_node_id)); | ||
516 | kthread_bind(task, cpu); | ||
517 | wake_up_process(task); | ||
518 | out: | ||
519 | return ret; | ||
520 | task_fail: | ||
521 | ret = PTR_ERR(task); | ||
522 | kfree(dd->worker); | ||
523 | dd->worker = NULL; | ||
524 | goto out; | ||
525 | } | ||
526 | |||
527 | void qib_cq_exit(struct qib_devdata *dd) | ||
528 | { | ||
529 | struct kthread_worker *worker; | ||
530 | |||
531 | worker = dd->worker; | ||
532 | if (!worker) | ||
533 | return; | ||
534 | /* blocks future queuing from send_complete() */ | ||
535 | dd->worker = NULL; | ||
536 | smp_wmb(); | ||
537 | flush_kthread_worker(worker); | ||
538 | kthread_stop(worker->task); | ||
539 | kfree(worker); | ||
540 | } | ||
diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c index e02217b5c46d..ff36903474ea 100644 --- a/drivers/infiniband/hw/qib/qib_init.c +++ b/drivers/infiniband/hw/qib/qib_init.c | |||
@@ -97,8 +97,6 @@ unsigned qib_wc_pat = 1; /* default (1) is to use PAT, not MTRR */ | |||
97 | module_param_named(wc_pat, qib_wc_pat, uint, S_IRUGO); | 97 | module_param_named(wc_pat, qib_wc_pat, uint, S_IRUGO); |
98 | MODULE_PARM_DESC(wc_pat, "enable write-combining via PAT mechanism"); | 98 | MODULE_PARM_DESC(wc_pat, "enable write-combining via PAT mechanism"); |
99 | 99 | ||
100 | struct workqueue_struct *qib_cq_wq; | ||
101 | |||
102 | static void verify_interrupt(unsigned long); | 100 | static void verify_interrupt(unsigned long); |
103 | 101 | ||
104 | static struct idr qib_unit_table; | 102 | static struct idr qib_unit_table; |
@@ -445,6 +443,7 @@ static int loadtime_init(struct qib_devdata *dd) | |||
445 | dd->intrchk_timer.function = verify_interrupt; | 443 | dd->intrchk_timer.function = verify_interrupt; |
446 | dd->intrchk_timer.data = (unsigned long) dd; | 444 | dd->intrchk_timer.data = (unsigned long) dd; |
447 | 445 | ||
446 | ret = qib_cq_init(dd); | ||
448 | done: | 447 | done: |
449 | return ret; | 448 | return ret; |
450 | } | 449 | } |
@@ -1215,12 +1214,6 @@ static int __init qlogic_ib_init(void) | |||
1215 | if (ret) | 1214 | if (ret) |
1216 | goto bail; | 1215 | goto bail; |
1217 | 1216 | ||
1218 | qib_cq_wq = create_singlethread_workqueue("qib_cq"); | ||
1219 | if (!qib_cq_wq) { | ||
1220 | ret = -ENOMEM; | ||
1221 | goto bail_dev; | ||
1222 | } | ||
1223 | |||
1224 | /* | 1217 | /* |
1225 | * These must be called before the driver is registered with | 1218 | * These must be called before the driver is registered with |
1226 | * the PCI subsystem. | 1219 | * the PCI subsystem. |
@@ -1233,7 +1226,7 @@ static int __init qlogic_ib_init(void) | |||
1233 | ret = pci_register_driver(&qib_driver); | 1226 | ret = pci_register_driver(&qib_driver); |
1234 | if (ret < 0) { | 1227 | if (ret < 0) { |
1235 | pr_err("Unable to register driver: error %d\n", -ret); | 1228 | pr_err("Unable to register driver: error %d\n", -ret); |
1236 | goto bail_unit; | 1229 | goto bail_dev; |
1237 | } | 1230 | } |
1238 | 1231 | ||
1239 | /* not fatal if it doesn't work */ | 1232 | /* not fatal if it doesn't work */ |
@@ -1241,13 +1234,11 @@ static int __init qlogic_ib_init(void) | |||
1241 | pr_err("Unable to register ipathfs\n"); | 1234 | pr_err("Unable to register ipathfs\n"); |
1242 | goto bail; /* all OK */ | 1235 | goto bail; /* all OK */ |
1243 | 1236 | ||
1244 | bail_unit: | 1237 | bail_dev: |
1245 | #ifdef CONFIG_INFINIBAND_QIB_DCA | 1238 | #ifdef CONFIG_INFINIBAND_QIB_DCA |
1246 | dca_unregister_notify(&dca_notifier); | 1239 | dca_unregister_notify(&dca_notifier); |
1247 | #endif | 1240 | #endif |
1248 | idr_destroy(&qib_unit_table); | 1241 | idr_destroy(&qib_unit_table); |
1249 | destroy_workqueue(qib_cq_wq); | ||
1250 | bail_dev: | ||
1251 | qib_dev_cleanup(); | 1242 | qib_dev_cleanup(); |
1252 | bail: | 1243 | bail: |
1253 | return ret; | 1244 | return ret; |
@@ -1273,8 +1264,6 @@ static void __exit qlogic_ib_cleanup(void) | |||
1273 | #endif | 1264 | #endif |
1274 | pci_unregister_driver(&qib_driver); | 1265 | pci_unregister_driver(&qib_driver); |
1275 | 1266 | ||
1276 | destroy_workqueue(qib_cq_wq); | ||
1277 | |||
1278 | qib_cpulist_count = 0; | 1267 | qib_cpulist_count = 0; |
1279 | kfree(qib_cpulist); | 1268 | kfree(qib_cpulist); |
1280 | 1269 | ||
@@ -1365,6 +1354,7 @@ static void cleanup_device_data(struct qib_devdata *dd) | |||
1365 | } | 1354 | } |
1366 | kfree(tmp); | 1355 | kfree(tmp); |
1367 | kfree(dd->boardname); | 1356 | kfree(dd->boardname); |
1357 | qib_cq_exit(dd); | ||
1368 | } | 1358 | } |
1369 | 1359 | ||
1370 | /* | 1360 | /* |
diff --git a/drivers/infiniband/hw/qib/qib_verbs.h b/drivers/infiniband/hw/qib/qib_verbs.h index aff8b2c17886..86c2cb3c9caf 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.h +++ b/drivers/infiniband/hw/qib/qib_verbs.h | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/interrupt.h> | 41 | #include <linux/interrupt.h> |
42 | #include <linux/kref.h> | 42 | #include <linux/kref.h> |
43 | #include <linux/workqueue.h> | 43 | #include <linux/workqueue.h> |
44 | #include <linux/kthread.h> | ||
44 | #include <linux/completion.h> | 45 | #include <linux/completion.h> |
45 | #include <rdma/ib_pack.h> | 46 | #include <rdma/ib_pack.h> |
46 | #include <rdma/ib_user_verbs.h> | 47 | #include <rdma/ib_user_verbs.h> |
@@ -267,7 +268,8 @@ struct qib_cq_wc { | |||
267 | */ | 268 | */ |
268 | struct qib_cq { | 269 | struct qib_cq { |
269 | struct ib_cq ibcq; | 270 | struct ib_cq ibcq; |
270 | struct work_struct comptask; | 271 | struct kthread_work comptask; |
272 | struct qib_devdata *dd; | ||
271 | spinlock_t lock; /* protect changes in this struct */ | 273 | spinlock_t lock; /* protect changes in this struct */ |
272 | u8 notify; | 274 | u8 notify; |
273 | u8 triggered; | 275 | u8 triggered; |
@@ -832,8 +834,6 @@ static inline int qib_send_ok(struct qib_qp *qp) | |||
832 | !(qp->s_flags & QIB_S_ANY_WAIT_SEND)); | 834 | !(qp->s_flags & QIB_S_ANY_WAIT_SEND)); |
833 | } | 835 | } |
834 | 836 | ||
835 | extern struct workqueue_struct *qib_cq_wq; | ||
836 | |||
837 | /* | 837 | /* |
838 | * This must be called with s_lock held. | 838 | * This must be called with s_lock held. |
839 | */ | 839 | */ |
@@ -972,6 +972,10 @@ int qib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr); | |||
972 | 972 | ||
973 | int qib_destroy_srq(struct ib_srq *ibsrq); | 973 | int qib_destroy_srq(struct ib_srq *ibsrq); |
974 | 974 | ||
975 | int qib_cq_init(struct qib_devdata *dd); | ||
976 | |||
977 | void qib_cq_exit(struct qib_devdata *dd); | ||
978 | |||
975 | void qib_cq_enter(struct qib_cq *cq, struct ib_wc *entry, int sig); | 979 | void qib_cq_enter(struct qib_cq *cq, struct ib_wc *entry, int sig); |
976 | 980 | ||
977 | int qib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry); | 981 | int qib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry); |