diff options
author | Michael Brown | 2008-10-03 01:07:52 +0200 |
---|---|---|
committer | Michael Brown | 2008-11-11 06:31:06 +0100 |
commit | d9751edafa08b2ec3779004d4209400b95884cd4 (patch) | |
tree | 532aaeda86668006aee5fc6994e6f0b773c2a427 /src/net/infiniband.c | |
parent | [ne2k_isa] Restore support for ne2k isa cards (diff) | |
download | ipxe-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.c | 31 |
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 ); } |