[ewg] [PATCH 6/10] nes: use control QP callback at connection teardown

Glenn Grundstrom NetEffect glenn at lists.openfabrics.org
Thu Dec 20 12:32:10 PST 2007


Prevents a race condition between hardware and ULPs when
tearing down connections.  Memory and data structures are
cleaned up after the hardware ce handler has run.

Signed-off-by: Glenn Grundstrom <ggrundstrom at neteffect.com>

---

diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c
index 1088330..4376bc2 100644
--- a/drivers/infiniband/hw/nes/nes.c
+++ b/drivers/infiniband/hw/nes/nes.c
@@ -263,13 +263,43 @@ void nes_add_ref(struct ib_qp *ibqp)
 	atomic_inc(&nesqp->refcount);
 }
 
+static void nes_cqp_rem_ref_callback(struct nes_device *nesdev, struct nes_cqp_request *cqp_request)
+{
+	unsigned long flags;
+	struct nes_qp *nesqp = cqp_request->cqp_callback_pointer;
+	struct nes_adapter *nesadapter = nesdev->nesadapter;
+	u32 qp_id;
+
+	atomic_inc(&qps_destroyed);
+
+	/* Free the control structures */
+
+	qp_id = nesqp->hwqp.qp_id;
+	if (nesqp->pbl_vbase) {
+		pci_free_consistent(nesdev->pcidev, nesqp->qp_mem_size,
+				nesqp->hwqp.q2_vbase, nesqp->hwqp.q2_pbase);
+		spin_lock_irqsave(&nesadapter->pbl_lock, flags);
+		nesadapter->free_256pbl++;
+		spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+		pci_free_consistent(nesdev->pcidev, 256, nesqp->pbl_vbase, nesqp->pbl_pbase);
+		nesqp->pbl_vbase = NULL;
+		kunmap(nesqp->page);
+
+	} else {
+		pci_free_consistent(nesdev->pcidev, nesqp->qp_mem_size,
+				nesqp->hwqp.sq_vbase, nesqp->hwqp.sq_pbase);
+	}
+	nes_free_resource(nesadapter, nesadapter->allocated_qps, nesqp->hwqp.qp_id);
+
+	kfree(nesqp->allocated_buffer);
+
+}
 
 /**
  * nes_rem_ref
  */
 void nes_rem_ref(struct ib_qp *ibqp)
 {
-	unsigned long flags;
 	u64 u64temp;
 	struct nes_qp *nesqp;
 	struct nes_vnic *nesvnic = to_nesvnic(ibqp->device);
@@ -287,27 +317,7 @@ void nes_rem_ref(struct ib_qp *ibqp)
 	}
 
 	if (atomic_dec_and_test(&nesqp->refcount)) {
-		atomic_inc(&qps_destroyed);
-
-		/* Free the control structures */
-
-		if (nesqp->pbl_vbase) {
-			pci_free_consistent(nesdev->pcidev, nesqp->qp_mem_size,
-					nesqp->hwqp.q2_vbase, nesqp->hwqp.q2_pbase);
-			spin_lock_irqsave(&nesadapter->pbl_lock, flags);
-			nesadapter->free_256pbl++;
-			spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
-			pci_free_consistent(nesdev->pcidev, 256, nesqp->pbl_vbase, nesqp->pbl_pbase);
-			nesqp->pbl_vbase = NULL;
-			kunmap(nesqp->page);
-
-		} else {
-			pci_free_consistent(nesdev->pcidev, nesqp->qp_mem_size,
-					nesqp->hwqp.sq_vbase, nesqp->hwqp.sq_pbase);
-		}
-
 		nesadapter->qp_table[nesqp->hwqp.qp_id-NES_FIRST_QPN] = NULL;
-		nes_free_resource(nesadapter, nesadapter->allocated_qps, nesqp->hwqp.qp_id);
 
 		/* Destroy the QP */
 		cqp_request = nes_get_cqp_request(nesdev);
@@ -316,6 +326,9 @@ void nes_rem_ref(struct ib_qp *ibqp)
 			return;
 		}
 		cqp_request->waiting = 0;
+		cqp_request->callback = 1;
+		cqp_request->cqp_callback = nes_cqp_rem_ref_callback;
+		cqp_request->cqp_callback_pointer = nesqp;
 		cqp_wqe = &cqp_request->cqp_wqe;
 
 		cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
@@ -339,8 +352,6 @@ void nes_rem_ref(struct ib_qp *ibqp)
 				cpu_to_le32((u32)(u64temp >> 32));
 
 		nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
-
-		kfree(nesqp->allocated_buffer);
 	}
 }
 
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c
index 1048db2..06d1963 100644
--- a/drivers/infiniband/hw/nes/nes_hw.c
+++ b/drivers/infiniband/hw/nes/nes_hw.c
@@ -2427,6 +2427,16 @@ void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq)
 							spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
 						}
 					}
+				} else if (cqp_request->callback) {
+					/* Envoke the callback routine */
+					cqp_request->cqp_callback(nesdev, cqp_request);
+					if (cqp_request->dynamic) {
+						kfree(cqp_request);
+					} else {
+						spin_lock_irqsave(&nesdev->cqp.lock, flags);
+						list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+						spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+					}
 				} else {
 					nes_debug(NES_DBG_CQP, "CQP request %p (opcode 0x%02X) freed.\n",
 							cqp_request,
diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h
index ca0b006..0279d4c 100644
--- a/drivers/infiniband/hw/nes/nes_hw.h
+++ b/drivers/infiniband/hw/nes/nes_hw.h
@@ -813,18 +813,22 @@ struct nes_hw_aeqe {
 	__le32 aeqe_words[4];
 };
 
-
 struct nes_cqp_request {
+	union {
+		u64 cqp_callback_context;
+		void *cqp_callback_pointer;
+	};
 	wait_queue_head_t     waitq;
 	struct nes_hw_cqp_wqe cqp_wqe;
 	struct list_head      list;
 	atomic_t              refcount;
+	void (*cqp_callback)(struct nes_device *nesdev, struct nes_cqp_request *cqp_request);
 	u16                   major_code;
 	u16                   minor_code;
 	u8                    waiting;
 	u8                    request_done;
 	u8                    dynamic;
-	u8                    padding[1];
+	u8                    callback;
 };
 
 struct nes_hw_cqp {
@@ -1158,6 +1162,8 @@ struct nes_vnic {
 	struct nes_hw_nic    nic;
 	struct nes_hw_nic_cq nic_cq;
 
+	struct nes_cqp_request* (*get_cqp_request)(struct nes_device *nesdev);
+	void (*post_cqp_request)(struct nes_device*, struct nes_cqp_request *, int);
 	struct net_device_stats netstats;
 	/* used to put the netdev on the adapters logical port list */
 	struct list_head list;
diff --git a/drivers/infiniband/hw/nes/nes_utils.c b/drivers/infiniband/hw/nes/nes_utils.c
index 8d2c1ee..ffd2b99 100644
--- a/drivers/infiniband/hw/nes/nes_utils.c
+++ b/drivers/infiniband/hw/nes/nes_utils.c
@@ -558,6 +558,7 @@ struct nes_cqp_request *nes_get_cqp_request(struct nes_device *nesdev)
 		init_waitqueue_head(&cqp_request->waitq);
 		cqp_request->waiting = 0;
 		cqp_request->request_done = 0;
+		cqp_request->callback = 0;
 		init_waitqueue_head(&cqp_request->waitq);
 		nes_debug(NES_DBG_CQP, "Got cqp request %p from the available list \n",
 				cqp_request);



More information about the ewg mailing list