diff options
Diffstat (limited to 'drivers/infiniband/hw/qib/qib_cq.c')
-rw-r--r-- | drivers/infiniband/hw/qib/qib_cq.c | 67 |
1 files changed, 61 insertions, 6 deletions
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 | } | ||