summaryrefslogtreecommitdiffstats
path: root/src/net/infiniband.c
diff options
context:
space:
mode:
authorMichael Brown2008-10-03 01:07:52 +0200
committerMichael Brown2008-11-11 06:31:06 +0100
commitd9751edafa08b2ec3779004d4209400b95884cd4 (patch)
tree532aaeda86668006aee5fc6994e6f0b773c2a427 /src/net/infiniband.c
parent[ne2k_isa] Restore support for ne2k isa cards (diff)
downloadipxe-d9751edafa08b2ec3779004d4209400b95884cd4.tar.gz
ipxe-d9751edafa08b2ec3779004d4209400b95884cd4.tar.xz
ipxe-d9751edafa08b2ec3779004d4209400b95884cd4.zip
[infiniband] Flush uncompleted work queue entries at QP teardown
Avoid leaking I/O buffers in ib_destroy_qp() by completing any outstanding work queue entries with a generic error code. This requires the completion handlers to be available to ib_destroy_qp(), which is done by making them static configuration parameters of the CQ (set by ib_create_cq()) rather than being provided on each call to ib_poll_cq(). This mimics the functionality of netdev_{tx,rx}_flush(). The netdev flush functions would previously have been catching any I/O buffers leaked by the IPoIB data queue (though not by the IPoIB metadata queue).
Diffstat (limited to 'src/net/infiniband.c')
-rw-r--r--src/net/infiniband.c31
1 files changed, 29 insertions, 2 deletions
diff --git a/src/net/infiniband.c b/src/net/infiniband.c
index ab76742e..8437b4ce 100644
--- a/src/net/infiniband.c
+++ b/src/net/infiniband.c
@@ -46,10 +46,13 @@ struct list_head ib_devices = LIST_HEAD_INIT ( ib_devices );
*
* @v ibdev Infiniband device
* @v num_cqes Number of completion queue entries
+ * @v complete_send Send completion handler
+ * @v complete_recv Receive completion handler
* @ret cq New completion queue
*/
-struct ib_completion_queue * ib_create_cq ( struct ib_device *ibdev,
- unsigned int num_cqes ) {
+struct ib_completion_queue *
+ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes,
+ ib_completer_t complete_send, ib_completer_t complete_recv ) {
struct ib_completion_queue *cq;
int rc;
@@ -61,6 +64,8 @@ struct ib_completion_queue * ib_create_cq ( struct ib_device *ibdev,
return NULL;
cq->num_cqes = num_cqes;
INIT_LIST_HEAD ( &cq->work_queues );
+ cq->complete_send = complete_send;
+ cq->complete_recv = complete_recv;
/* Perform device-specific initialisation and get CQN */
if ( ( rc = ibdev->op->create_cq ( ibdev, cq ) ) != 0 ) {
@@ -190,11 +195,33 @@ int ib_modify_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp,
* @v qp Queue pair
*/
void ib_destroy_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
+ struct ib_completion completion = {
+ .syndrome = IB_SYN_LOCAL_QP,
+ };
+ struct io_buffer *iobuf;
+ unsigned int i;
+
DBGC ( ibdev, "IBDEV %p destroying QPN %#lx\n",
ibdev, qp->qpn );
+
+ /* Perform device-specific destruction */
ibdev->op->destroy_qp ( ibdev, qp );
+
+ /* Complete any remaining I/O buffers with errors */
+ for ( i = 0 ; i < qp->send.num_wqes ; i++ ) {
+ if ( ( iobuf = qp->send.iobufs[i] ) != NULL )
+ ib_complete_send ( ibdev, qp, &completion, iobuf );
+ }
+ for ( i = 0 ; i < qp->recv.num_wqes ; i++ ) {
+ if ( ( iobuf = qp->recv.iobufs[i] ) != NULL )
+ ib_complete_recv ( ibdev, qp, &completion, iobuf );
+ }
+
+ /* Remove work queues from completion queue */
list_del ( &qp->send.list );
list_del ( &qp->recv.list );
+
+ /* Free QP */
free ( qp );
}