diff options
Diffstat (limited to 'drivers/infiniband/hw/ehca/ehca_cq.c')
-rw-r--r-- | drivers/infiniband/hw/ehca/ehca_cq.c | 50 |
1 files changed, 21 insertions, 29 deletions
diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c index 67f0670fe3b1..01d4a148bd71 100644 --- a/drivers/infiniband/hw/ehca/ehca_cq.c +++ b/drivers/infiniband/hw/ehca/ehca_cq.c | |||
@@ -56,11 +56,11 @@ int ehca_cq_assign_qp(struct ehca_cq *cq, struct ehca_qp *qp) | |||
56 | { | 56 | { |
57 | unsigned int qp_num = qp->real_qp_num; | 57 | unsigned int qp_num = qp->real_qp_num; |
58 | unsigned int key = qp_num & (QP_HASHTAB_LEN-1); | 58 | unsigned int key = qp_num & (QP_HASHTAB_LEN-1); |
59 | unsigned long spl_flags; | 59 | unsigned long flags; |
60 | 60 | ||
61 | spin_lock_irqsave(&cq->spinlock, spl_flags); | 61 | spin_lock_irqsave(&cq->spinlock, flags); |
62 | hlist_add_head(&qp->list_entries, &cq->qp_hashtab[key]); | 62 | hlist_add_head(&qp->list_entries, &cq->qp_hashtab[key]); |
63 | spin_unlock_irqrestore(&cq->spinlock, spl_flags); | 63 | spin_unlock_irqrestore(&cq->spinlock, flags); |
64 | 64 | ||
65 | ehca_dbg(cq->ib_cq.device, "cq_num=%x real_qp_num=%x", | 65 | ehca_dbg(cq->ib_cq.device, "cq_num=%x real_qp_num=%x", |
66 | cq->cq_number, qp_num); | 66 | cq->cq_number, qp_num); |
@@ -74,9 +74,9 @@ int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int real_qp_num) | |||
74 | unsigned int key = real_qp_num & (QP_HASHTAB_LEN-1); | 74 | unsigned int key = real_qp_num & (QP_HASHTAB_LEN-1); |
75 | struct hlist_node *iter; | 75 | struct hlist_node *iter; |
76 | struct ehca_qp *qp; | 76 | struct ehca_qp *qp; |
77 | unsigned long spl_flags; | 77 | unsigned long flags; |
78 | 78 | ||
79 | spin_lock_irqsave(&cq->spinlock, spl_flags); | 79 | spin_lock_irqsave(&cq->spinlock, flags); |
80 | hlist_for_each(iter, &cq->qp_hashtab[key]) { | 80 | hlist_for_each(iter, &cq->qp_hashtab[key]) { |
81 | qp = hlist_entry(iter, struct ehca_qp, list_entries); | 81 | qp = hlist_entry(iter, struct ehca_qp, list_entries); |
82 | if (qp->real_qp_num == real_qp_num) { | 82 | if (qp->real_qp_num == real_qp_num) { |
@@ -88,7 +88,7 @@ int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int real_qp_num) | |||
88 | break; | 88 | break; |
89 | } | 89 | } |
90 | } | 90 | } |
91 | spin_unlock_irqrestore(&cq->spinlock, spl_flags); | 91 | spin_unlock_irqrestore(&cq->spinlock, flags); |
92 | if (ret) | 92 | if (ret) |
93 | ehca_err(cq->ib_cq.device, | 93 | ehca_err(cq->ib_cq.device, |
94 | "qp not found cq_num=%x real_qp_num=%x", | 94 | "qp not found cq_num=%x real_qp_num=%x", |
@@ -146,6 +146,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, | |||
146 | spin_lock_init(&my_cq->spinlock); | 146 | spin_lock_init(&my_cq->spinlock); |
147 | spin_lock_init(&my_cq->cb_lock); | 147 | spin_lock_init(&my_cq->cb_lock); |
148 | spin_lock_init(&my_cq->task_lock); | 148 | spin_lock_init(&my_cq->task_lock); |
149 | atomic_set(&my_cq->nr_events, 0); | ||
149 | init_waitqueue_head(&my_cq->wait_completion); | 150 | init_waitqueue_head(&my_cq->wait_completion); |
150 | my_cq->ownpid = current->tgid; | 151 | my_cq->ownpid = current->tgid; |
151 | 152 | ||
@@ -162,9 +163,9 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, | |||
162 | goto create_cq_exit1; | 163 | goto create_cq_exit1; |
163 | } | 164 | } |
164 | 165 | ||
165 | spin_lock_irqsave(&ehca_cq_idr_lock, flags); | 166 | write_lock_irqsave(&ehca_cq_idr_lock, flags); |
166 | ret = idr_get_new(&ehca_cq_idr, my_cq, &my_cq->token); | 167 | ret = idr_get_new(&ehca_cq_idr, my_cq, &my_cq->token); |
167 | spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); | 168 | write_unlock_irqrestore(&ehca_cq_idr_lock, flags); |
168 | 169 | ||
169 | } while (ret == -EAGAIN); | 170 | } while (ret == -EAGAIN); |
170 | 171 | ||
@@ -293,9 +294,9 @@ create_cq_exit3: | |||
293 | "cq_num=%x h_ret=%lx", my_cq, my_cq->cq_number, h_ret); | 294 | "cq_num=%x h_ret=%lx", my_cq, my_cq->cq_number, h_ret); |
294 | 295 | ||
295 | create_cq_exit2: | 296 | create_cq_exit2: |
296 | spin_lock_irqsave(&ehca_cq_idr_lock, flags); | 297 | write_lock_irqsave(&ehca_cq_idr_lock, flags); |
297 | idr_remove(&ehca_cq_idr, my_cq->token); | 298 | idr_remove(&ehca_cq_idr, my_cq->token); |
298 | spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); | 299 | write_unlock_irqrestore(&ehca_cq_idr_lock, flags); |
299 | 300 | ||
300 | create_cq_exit1: | 301 | create_cq_exit1: |
301 | kmem_cache_free(cq_cache, my_cq); | 302 | kmem_cache_free(cq_cache, my_cq); |
@@ -303,16 +304,6 @@ create_cq_exit1: | |||
303 | return cq; | 304 | return cq; |
304 | } | 305 | } |
305 | 306 | ||
306 | static int get_cq_nr_events(struct ehca_cq *my_cq) | ||
307 | { | ||
308 | int ret; | ||
309 | unsigned long flags; | ||
310 | spin_lock_irqsave(&ehca_cq_idr_lock, flags); | ||
311 | ret = my_cq->nr_events; | ||
312 | spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); | ||
313 | return ret; | ||
314 | } | ||
315 | |||
316 | int ehca_destroy_cq(struct ib_cq *cq) | 307 | int ehca_destroy_cq(struct ib_cq *cq) |
317 | { | 308 | { |
318 | u64 h_ret; | 309 | u64 h_ret; |
@@ -339,17 +330,18 @@ int ehca_destroy_cq(struct ib_cq *cq) | |||
339 | } | 330 | } |
340 | } | 331 | } |
341 | 332 | ||
342 | spin_lock_irqsave(&ehca_cq_idr_lock, flags); | 333 | /* |
343 | while (my_cq->nr_events) { | 334 | * remove the CQ from the idr first to make sure |
344 | spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); | 335 | * no more interrupt tasklets will touch this CQ |
345 | wait_event(my_cq->wait_completion, !get_cq_nr_events(my_cq)); | 336 | */ |
346 | spin_lock_irqsave(&ehca_cq_idr_lock, flags); | 337 | write_lock_irqsave(&ehca_cq_idr_lock, flags); |
347 | /* recheck nr_events to assure no cqe has just arrived */ | ||
348 | } | ||
349 | |||
350 | idr_remove(&ehca_cq_idr, my_cq->token); | 338 | idr_remove(&ehca_cq_idr, my_cq->token); |
351 | spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); | 339 | write_unlock_irqrestore(&ehca_cq_idr_lock, flags); |
340 | |||
341 | /* now wait until all pending events have completed */ | ||
342 | wait_event(my_cq->wait_completion, !atomic_read(&my_cq->nr_events)); | ||
352 | 343 | ||
344 | /* nobody's using our CQ any longer -- we can destroy it */ | ||
353 | h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 0); | 345 | h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 0); |
354 | if (h_ret == H_R_STATE) { | 346 | if (h_ret == H_R_STATE) { |
355 | /* cq in err: read err data and destroy it forcibly */ | 347 | /* cq in err: read err data and destroy it forcibly */ |