[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