summaryrefslogtreecommitdiffstats
path: root/src/net/infiniband.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/net/infiniband.c')
-rw-r--r--src/net/infiniband.c112
1 files changed, 109 insertions, 3 deletions
diff --git a/src/net/infiniband.c b/src/net/infiniband.c
index 4784f404..48572e03 100644
--- a/src/net/infiniband.c
+++ b/src/net/infiniband.c
@@ -43,6 +43,13 @@ FILE_LICENCE ( GPL2_OR_LATER );
/** List of Infiniband devices */
struct list_head ib_devices = LIST_HEAD_INIT ( ib_devices );
+/***************************************************************************
+ *
+ * Completion queues
+ *
+ ***************************************************************************
+ */
+
/**
* Create completion queue
*
@@ -63,6 +70,8 @@ ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes,
cq = zalloc ( sizeof ( *cq ) );
if ( ! cq )
goto err_alloc_cq;
+ cq->ibdev = ibdev;
+ list_add ( &cq->list, &ibdev->cqs );
cq->num_cqes = num_cqes;
INIT_LIST_HEAD ( &cq->work_queues );
cq->op = op;
@@ -81,6 +90,7 @@ ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes,
ibdev->op->destroy_cq ( ibdev, cq );
err_dev_create_cq:
+ list_del ( &cq->list );
free ( cq );
err_alloc_cq:
return NULL;
@@ -98,10 +108,38 @@ void ib_destroy_cq ( struct ib_device *ibdev,
ibdev, cq->cqn );
assert ( list_empty ( &cq->work_queues ) );
ibdev->op->destroy_cq ( ibdev, cq );
+ list_del ( &cq->list );
free ( cq );
}
/**
+ * Poll completion queue
+ *
+ * @v ibdev Infiniband device
+ * @v cq Completion queue
+ */
+void ib_poll_cq ( struct ib_device *ibdev,
+ struct ib_completion_queue *cq ) {
+ struct ib_work_queue *wq;
+
+ /* Poll completion queue */
+ ibdev->op->poll_cq ( ibdev, cq );
+
+ /* Refill receive work queues */
+ list_for_each_entry ( wq, &cq->work_queues, list ) {
+ if ( ! wq->is_send )
+ ib_refill_recv ( ibdev, wq->qp );
+ }
+}
+
+/***************************************************************************
+ *
+ * Work queues
+ *
+ ***************************************************************************
+ */
+
+/**
* Create queue pair
*
* @v ibdev Infiniband device
@@ -401,6 +439,44 @@ void ib_complete_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
}
/**
+ * Refill receive work queue
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ */
+void ib_refill_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
+ struct io_buffer *iobuf;
+ int rc;
+
+ /* Keep filling while unfilled entries remain */
+ while ( qp->recv.fill < qp->recv.num_wqes ) {
+
+ /* Allocate I/O buffer */
+ iobuf = alloc_iob ( IB_MAX_PAYLOAD_SIZE );
+ if ( ! iobuf ) {
+ /* Non-fatal; we will refill on next attempt */
+ return;
+ }
+
+ /* Post I/O buffer */
+ if ( ( rc = ib_post_recv ( ibdev, qp, iobuf ) ) != 0 ) {
+ DBGC ( ibdev, "IBDEV %p could not refill: %s\n",
+ ibdev, strerror ( rc ) );
+ free_iob ( iobuf );
+ /* Give up */
+ return;
+ }
+ }
+}
+
+/***************************************************************************
+ *
+ * Link control
+ *
+ ***************************************************************************
+ */
+
+/**
* Open port
*
* @v ibdev Infiniband device
@@ -436,6 +512,13 @@ void ib_close ( struct ib_device *ibdev ) {
ibdev->op->close ( ibdev );
}
+/***************************************************************************
+ *
+ * Multicast
+ *
+ ***************************************************************************
+ */
+
/**
* Attach to multicast group
*
@@ -495,6 +578,13 @@ void ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
}
}
+/***************************************************************************
+ *
+ * Miscellaneous
+ *
+ ***************************************************************************
+ */
+
/**
* Get Infiniband HCA information
*
@@ -541,6 +631,22 @@ void ib_link_state_changed ( struct ib_device *ibdev ) {
}
/**
+ * Poll event queue
+ *
+ * @v ibdev Infiniband device
+ */
+void ib_poll_eq ( struct ib_device *ibdev ) {
+ struct ib_completion_queue *cq;
+
+ /* Poll device's event queue */
+ ibdev->op->poll_eq ( ibdev );
+
+ /* Poll all completion queues */
+ list_for_each_entry ( cq, &ibdev->cqs, list )
+ ib_poll_cq ( ibdev, cq );
+}
+
+/**
* Single-step the Infiniband event queue
*
* @v process Infiniband event queue process
@@ -548,9 +654,8 @@ void ib_link_state_changed ( struct ib_device *ibdev ) {
static void ib_step ( struct process *process __unused ) {
struct ib_device *ibdev;
- list_for_each_entry ( ibdev, &ib_devices, list ) {
- ibdev->op->poll_eq ( ibdev );
- }
+ for_each_ibdev ( ibdev )
+ ib_poll_eq ( ibdev );
}
/** Infiniband event queue process */
@@ -581,6 +686,7 @@ struct ib_device * alloc_ibdev ( size_t priv_size ) {
if ( ibdev ) {
drv_priv = ( ( ( void * ) ibdev ) + sizeof ( *ibdev ) );
ib_set_drvdata ( ibdev, drv_priv );
+ INIT_LIST_HEAD ( &ibdev->cqs );
INIT_LIST_HEAD ( &ibdev->qps );
ibdev->lid = IB_LID_NONE;
ibdev->pkey = IB_PKEY_NONE;