Skip to content

Commit

Permalink
[infiniband] Poll completion queues automatically
Browse files Browse the repository at this point in the history
Currently, all Infiniband users must create a process for polling
their completion queues (or rely on a regular hook such as
netdev_poll() in ipoib.c).

Move instead to a model whereby the Infiniband core maintains a single
process calling ib_poll_eq(), and polling the event queue triggers
polls of the applicable completion queues.  (At present, the
Infiniband core simply polls all of the device's completion queues.)
Polling a completion queue will now implicitly refill all attached
receive work queues; this is analogous to the way that netdev_poll()
implicitly refills the RX ring.

Infiniband users no longer need to create a process just to poll their
completion queues and refill their receive rings.
  • Loading branch information
Michael Brown committed Jul 17, 2009
1 parent 1f5c023 commit 887d296
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 113 deletions.
9 changes: 3 additions & 6 deletions src/drivers/net/ipoib.c
Expand Up @@ -743,10 +743,7 @@ static void ipoib_poll ( struct net_device *netdev ) {
struct ipoib_device *ipoib = netdev->priv;
struct ib_device *ibdev = ipoib->ibdev;

ib_poll_cq ( ibdev, ipoib->meta.cq );
ib_poll_cq ( ibdev, ipoib->data.cq );
ib_qset_refill_recv ( ibdev, &ipoib->meta );
ib_qset_refill_recv ( ibdev, &ipoib->data );
ib_poll_eq ( ibdev );
}

/**
Expand Down Expand Up @@ -861,8 +858,8 @@ static int ipoib_open ( struct net_device *netdev ) {
mac->qpn = htonl ( ipoib->data.qp->qpn );

/* Fill receive rings */
ib_qset_refill_recv ( ibdev, &ipoib->meta );
ib_qset_refill_recv ( ibdev, &ipoib->data );
ib_refill_recv ( ibdev, ipoib->meta.qp );
ib_refill_recv ( ibdev, ipoib->data.qp );

/* Join broadcast group */
if ( ( rc = ipoib_join_broadcast_group ( ipoib ) ) != 0 ) {
Expand Down
4 changes: 0 additions & 4 deletions src/include/gpxe/ib_qset.h
Expand Up @@ -18,17 +18,13 @@ struct ib_queue_set {
struct ib_completion_queue *cq;
/** Queue pair */
struct ib_queue_pair *qp;
/** Receive work queue maximum fill level */
unsigned int recv_max_fill;
};

extern int ib_create_qset ( struct ib_device *ibdev,
struct ib_queue_set *qset, unsigned int num_cqes,
struct ib_completion_queue_operations *cq_op,
unsigned int num_send_wqes,
unsigned int num_recv_wqes, unsigned long qkey );
extern void ib_qset_refill_recv ( struct ib_device *ibdev,
struct ib_queue_set *qset );
extern void ib_destroy_qset ( struct ib_device *ibdev,
struct ib_queue_set *qset );

Expand Down
3 changes: 0 additions & 3 deletions src/include/gpxe/ib_sma.h
Expand Up @@ -10,7 +10,6 @@
FILE_LICENCE ( GPL2_OR_LATER );

#include <gpxe/infiniband.h>
#include <gpxe/process.h>

/** Infiniband Subnet Management Agent operations */
struct ib_sma_operations {
Expand All @@ -33,8 +32,6 @@ struct ib_sma {
struct ib_completion_queue *cq;
/** SMA queue pair */
struct ib_queue_pair *qp;
/** Poll process */
struct process poll;
};

/** SMA number of send WQEs
Expand Down
22 changes: 11 additions & 11 deletions src/include/gpxe/infiniband.h
Expand Up @@ -154,6 +154,10 @@ struct ib_completion_queue_operations {

/** An Infiniband Completion Queue */
struct ib_completion_queue {
/** Containing Infiniband device */
struct ib_device *ibdev;
/** List of completion queues on this Infiniband device */
struct list_head list;
/** Completion queue number */
unsigned long cqn;
/** Number of completion queue entries */
Expand Down Expand Up @@ -310,6 +314,8 @@ struct ib_device {
struct list_head list;
/** Underlying device */
struct device *dev;
/** List of completion queues */
struct list_head cqs;
/** List of queue pairs */
struct list_head qps;
/** Infiniband operations */
Expand Down Expand Up @@ -350,6 +356,8 @@ ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes,
struct ib_completion_queue_operations *op );
extern void ib_destroy_cq ( struct ib_device *ibdev,
struct ib_completion_queue *cq );
extern void ib_poll_cq ( struct ib_device *ibdev,
struct ib_completion_queue *cq );
extern struct ib_queue_pair *
ib_create_qp ( struct ib_device *ibdev, unsigned int num_send_wqes,
struct ib_completion_queue *send_cq, unsigned int num_recv_wqes,
Expand All @@ -376,6 +384,8 @@ extern void ib_complete_recv ( struct ib_device *ibdev,
struct ib_queue_pair *qp,
struct ib_address_vector *av,
struct io_buffer *iobuf, int rc );
extern void ib_refill_recv ( struct ib_device *ibdev,
struct ib_queue_pair *qp );
extern int ib_open ( struct ib_device *ibdev );
extern void ib_close ( struct ib_device *ibdev );
extern int ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
Expand All @@ -388,23 +398,13 @@ extern struct ib_device * alloc_ibdev ( size_t priv_size );
extern int register_ibdev ( struct ib_device *ibdev );
extern void unregister_ibdev ( struct ib_device *ibdev );
extern void ib_link_state_changed ( struct ib_device *ibdev );
extern void ib_poll_eq ( struct ib_device *ibdev );
extern struct list_head ib_devices;

/** Iterate over all network devices */
#define for_each_ibdev( ibdev ) \
list_for_each_entry ( (ibdev), &ib_devices, list )

/**
* Poll completion queue
*
* @v ibdev Infiniband device
* @v cq Completion queue
*/
static inline __always_inline void
ib_poll_cq ( struct ib_device *ibdev, struct ib_completion_queue *cq ) {
ibdev->op->poll_cq ( ibdev, cq );
}

/**
* Check link state
*
Expand Down
112 changes: 109 additions & 3 deletions src/net/infiniband.c
Expand Up @@ -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
*
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -98,9 +108,37 @@ 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
*
Expand Down Expand Up @@ -400,6 +438,44 @@ void ib_complete_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
qp->recv.fill--;
}

/**
* 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
*
Expand Down Expand Up @@ -436,6 +512,13 @@ void ib_close ( struct ib_device *ibdev ) {
ibdev->op->close ( ibdev );
}

/***************************************************************************
*
* Multicast
*
***************************************************************************
*/

/**
* Attach to multicast group
*
Expand Down Expand Up @@ -495,6 +578,13 @@ void ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
}
}

/***************************************************************************
*
* Miscellaneous
*
***************************************************************************
*/

/**
* Get Infiniband HCA information
*
Expand Down Expand Up @@ -540,6 +630,22 @@ void ib_link_state_changed ( struct ib_device *ibdev ) {
ipoib_link_state_changed ( 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
*
Expand All @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down
34 changes: 0 additions & 34 deletions src/net/infiniband/ib_qset.c
Expand Up @@ -54,9 +54,6 @@ int ib_create_qset ( struct ib_device *ibdev, struct ib_queue_set *qset,
assert ( qset->cq == NULL );
assert ( qset->qp == NULL );

/* Store queue parameters */
qset->recv_max_fill = num_recv_wqes;

/* Allocate completion queue */
qset->cq = ib_create_cq ( ibdev, num_cqes, cq_op );
if ( ! qset->cq ) {
Expand All @@ -83,37 +80,6 @@ int ib_create_qset ( struct ib_device *ibdev, struct ib_queue_set *qset,
return rc;
}

/**
* Refill IPoIB receive ring
*
* @v ibdev Infiniband device
* @v qset Queue set
*/
void ib_qset_refill_recv ( struct ib_device *ibdev,
struct ib_queue_set *qset ) {
struct io_buffer *iobuf;
int rc;

while ( qset->qp->recv.fill < qset->recv_max_fill ) {

/* 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, qset->qp, iobuf ) ) != 0 ) {
DBGC ( ibdev, "IBDEV %p could not refill: %s\n",
ibdev, strerror ( rc ) );
free_iob ( iobuf );
/* Give up */
return;
}
}
}

/**
* Destroy queue set
*
Expand Down

0 comments on commit 887d296

Please sign in to comment.