aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/hw
diff options
context:
space:
mode:
authorStefan Roscher <ossrosch@linux.vnet.ibm.com>2008-05-07 14:35:06 -0400
committerRoland Dreier <rolandd@cisco.com>2008-05-07 14:35:06 -0400
commit12137c593d127c6c1a3eb050674da047682badaf (patch)
treef615c55e363b550c7489aa0aceeb8d62c201fcad /drivers/infiniband/hw
parentab69b3cf1219e0d07bb4ea373f36b1de38af531c (diff)
IB/ehca: Wait for async events to finish before destroying QP
This is necessary because, in a multicore environment, a race between uverbs async handler and destroy QP could occur. Signed-off-by: Stefan Roscher <stefan.roscher at de.ibm.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/hw')
-rw-r--r--drivers/infiniband/hw/ehca/ehca_classes.h2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_irq.c4
-rw-r--r--drivers/infiniband/hw/ehca/ehca_qp.c5
3 files changed, 11 insertions, 0 deletions
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
index 00bab60f6de4..1e9e99a13933 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -192,6 +192,8 @@ struct ehca_qp {
192 int mtu_shift; 192 int mtu_shift;
193 u32 message_count; 193 u32 message_count;
194 u32 packet_count; 194 u32 packet_count;
195 atomic_t nr_events; /* events seen */
196 wait_queue_head_t wait_completion;
195}; 197};
196 198
197#define IS_SRQ(qp) (qp->ext_type == EQPT_SRQ) 199#define IS_SRQ(qp) (qp->ext_type == EQPT_SRQ)
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c
index ca5eb0cb628c..ce1ab0571be3 100644
--- a/drivers/infiniband/hw/ehca/ehca_irq.c
+++ b/drivers/infiniband/hw/ehca/ehca_irq.c
@@ -204,6 +204,8 @@ static void qp_event_callback(struct ehca_shca *shca, u64 eqe,
204 204
205 read_lock(&ehca_qp_idr_lock); 205 read_lock(&ehca_qp_idr_lock);
206 qp = idr_find(&ehca_qp_idr, token); 206 qp = idr_find(&ehca_qp_idr, token);
207 if (qp)
208 atomic_inc(&qp->nr_events);
207 read_unlock(&ehca_qp_idr_lock); 209 read_unlock(&ehca_qp_idr_lock);
208 210
209 if (!qp) 211 if (!qp)
@@ -223,6 +225,8 @@ static void qp_event_callback(struct ehca_shca *shca, u64 eqe,
223 if (fatal && qp->ext_type == EQPT_SRQBASE) 225 if (fatal && qp->ext_type == EQPT_SRQBASE)
224 dispatch_qp_event(shca, qp, IB_EVENT_QP_LAST_WQE_REACHED); 226 dispatch_qp_event(shca, qp, IB_EVENT_QP_LAST_WQE_REACHED);
225 227
228 if (atomic_dec_and_test(&qp->nr_events))
229 wake_up(&qp->wait_completion);
226 return; 230 return;
227} 231}
228 232
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
index 18fba92fa7ae..3f59587338ea 100644
--- a/drivers/infiniband/hw/ehca/ehca_qp.c
+++ b/drivers/infiniband/hw/ehca/ehca_qp.c
@@ -566,6 +566,8 @@ static struct ehca_qp *internal_create_qp(
566 return ERR_PTR(-ENOMEM); 566 return ERR_PTR(-ENOMEM);
567 } 567 }
568 568
569 atomic_set(&my_qp->nr_events, 0);
570 init_waitqueue_head(&my_qp->wait_completion);
569 spin_lock_init(&my_qp->spinlock_s); 571 spin_lock_init(&my_qp->spinlock_s);
570 spin_lock_init(&my_qp->spinlock_r); 572 spin_lock_init(&my_qp->spinlock_r);
571 my_qp->qp_type = qp_type; 573 my_qp->qp_type = qp_type;
@@ -1934,6 +1936,9 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
1934 idr_remove(&ehca_qp_idr, my_qp->token); 1936 idr_remove(&ehca_qp_idr, my_qp->token);
1935 write_unlock_irqrestore(&ehca_qp_idr_lock, flags); 1937 write_unlock_irqrestore(&ehca_qp_idr_lock, flags);
1936 1938
1939 /* now wait until all pending events have completed */
1940 wait_event(my_qp->wait_completion, !atomic_read(&my_qp->nr_events));
1941
1937 h_ret = hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp); 1942 h_ret = hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp);
1938 if (h_ret != H_SUCCESS) { 1943 if (h_ret != H_SUCCESS) {
1939 ehca_err(dev, "hipz_h_destroy_qp() failed h_ret=%li " 1944 ehca_err(dev, "hipz_h_destroy_qp() failed h_ret=%li "