Skip to content

Commit

Permalink
[hermon] Allocate space for GRH on UD queue pairs
Browse files Browse the repository at this point in the history
The Infiniband specification (volume 1, section 11.4.1.2 "Post Receive
Request") notes that for UD QPs, the GRH will be placed in the first
40 bytes of the receive buffer if present.  (If no GRH is present,
which is normal, then the first 40 bytes of the receive buffer will be
unused.)

Mellanox hardware performs this placement automatically: other headers
will be stripped (and their values returned via the CQE), but the
first 40 bytes of the data buffer will be consumed by the (probably
non-existent) GRH.

This does not fit neatly into iPXE's internal abstraction, which
expects the data buffer to represent just the data payload with the
addresses from the GRH (if present) passed as additional parameters to
ib_complete_recv().

The end result of this discrepancy is that attempts to receive
full-sized 2048-byte IPoIB packets on Mellanox hardware will fail.

Fix by allocating a separate ring buffer to hold the received GRHs.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
  • Loading branch information
mcb30 committed Mar 21, 2016
1 parent 0141ea3 commit e84c917
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 12 deletions.
53 changes: 42 additions & 11 deletions src/drivers/infiniband/hermon.c
Expand Up @@ -1111,6 +1111,8 @@ static int hermon_create_qp ( struct ib_device *ibdev,
struct hermon *hermon = ib_get_drvdata ( ibdev );
struct hermon_queue_pair *hermon_qp;
struct hermonprm_qp_ee_state_transitions qpctx;
struct hermonprm_wqe_segment_data_ptr *data;
unsigned int i;
int rc;

/* Calculate queue pair number */
Expand Down Expand Up @@ -1147,18 +1149,36 @@ static int hermon_create_qp ( struct ib_device *ibdev,
sizeof ( hermon_qp->send.wqe[0] ) );
hermon_qp->recv.wqe_size = ( qp->recv.num_wqes *
sizeof ( hermon_qp->recv.wqe[0] ) );
if ( ( qp->type == IB_QPT_SMI ) || ( qp->type == IB_QPT_GSI ) ||
( qp->type == IB_QPT_UD ) ) {
hermon_qp->recv.grh_size = ( qp->recv.num_wqes *
sizeof ( hermon_qp->recv.grh[0] ));
}
hermon_qp->wqe_size = ( hermon_qp->send.wqe_size +
hermon_qp->recv.wqe_size );
hermon_qp->recv.wqe_size +
hermon_qp->recv.grh_size );
hermon_qp->wqe = malloc_dma ( hermon_qp->wqe_size,
sizeof ( hermon_qp->send.wqe[0] ) );
if ( ! hermon_qp->wqe ) {
rc = -ENOMEM;
goto err_alloc_wqe;
}
hermon_qp->send.wqe = hermon_qp->wqe;
memset ( hermon_qp->send.wqe, 0xff, hermon_qp->send.wqe_size );
hermon_qp->recv.wqe = ( hermon_qp->wqe + hermon_qp->send.wqe_size );
if ( hermon_qp->recv.grh_size ) {
hermon_qp->recv.grh = ( hermon_qp->wqe +
hermon_qp->send.wqe_size +
hermon_qp->recv.wqe_size );
}

/* Initialise work queue entries */
memset ( hermon_qp->send.wqe, 0xff, hermon_qp->send.wqe_size );
memset ( hermon_qp->recv.wqe, 0, hermon_qp->recv.wqe_size );
data = &hermon_qp->recv.wqe[0].recv.data[0];
for ( i = 0 ; i < ( hermon_qp->recv.wqe_size / sizeof ( *data ) ); i++){
MLX_FILL_1 ( data, 1, l_key, HERMON_INVALID_LKEY );
data++;
}

/* Allocate MTT entries */
if ( ( rc = hermon_alloc_mtt ( hermon, hermon_qp->wqe,
Expand Down Expand Up @@ -1633,6 +1653,8 @@ static int hermon_post_recv ( struct ib_device *ibdev,
struct ib_work_queue *wq = &qp->recv;
struct hermon_recv_work_queue *hermon_recv_wq = &hermon_qp->recv;
struct hermonprm_recv_wqe *wqe;
struct hermonprm_wqe_segment_data_ptr *data;
struct ib_global_route_header *grh;
unsigned int wqe_idx_mask;

/* Allocate work queue entry */
Expand All @@ -1646,12 +1668,19 @@ static int hermon_post_recv ( struct ib_device *ibdev,
wqe = &hermon_recv_wq->wqe[wq->next_idx & wqe_idx_mask].recv;

/* Construct work queue entry */
MLX_FILL_1 ( &wqe->data[0], 0, byte_count, iob_tailroom ( iobuf ) );
MLX_FILL_1 ( &wqe->data[0], 1, l_key, hermon->lkey );
MLX_FILL_H ( &wqe->data[0], 2,
local_address_h, virt_to_bus ( iobuf->data ) );
MLX_FILL_1 ( &wqe->data[0], 3,
local_address_l, virt_to_bus ( iobuf->data ) );
data = &wqe->data[0];
if ( hermon_qp->recv.grh ) {
grh = &hermon_qp->recv.grh[wq->next_idx & wqe_idx_mask];
MLX_FILL_1 ( data, 0, byte_count, sizeof ( *grh ) );
MLX_FILL_1 ( data, 1, l_key, hermon->lkey );
MLX_FILL_H ( data, 2, local_address_h, virt_to_bus ( grh ) );
MLX_FILL_1 ( data, 3, local_address_l, virt_to_bus ( grh ) );
data++;
}
MLX_FILL_1 ( data, 0, byte_count, iob_tailroom ( iobuf ) );
MLX_FILL_1 ( data, 1, l_key, hermon->lkey );
MLX_FILL_H ( data, 2, local_address_h, virt_to_bus ( iobuf->data ) );
MLX_FILL_1 ( data, 3, local_address_l, virt_to_bus ( iobuf->data ) );

/* Update work queue's index */
wq->next_idx++;
Expand All @@ -1676,6 +1705,7 @@ static int hermon_complete ( struct ib_device *ibdev,
struct ib_completion_queue *cq,
union hermonprm_completion_entry *cqe ) {
struct hermon *hermon = ib_get_drvdata ( ibdev );
struct hermon_queue_pair *hermon_qp;
struct ib_work_queue *wq;
struct ib_queue_pair *qp;
struct io_buffer *iobuf;
Expand Down Expand Up @@ -1713,6 +1743,7 @@ static int hermon_complete ( struct ib_device *ibdev,
return -EIO;
}
qp = wq->qp;
hermon_qp = ib_qp_get_drvdata ( qp );

/* Identify work queue entry */
wqe_idx = MLX_GET ( &cqe->normal, wqe_counter );
Expand Down Expand Up @@ -1747,9 +1778,9 @@ static int hermon_complete ( struct ib_device *ibdev,
case IB_QPT_SMI:
case IB_QPT_GSI:
case IB_QPT_UD:
assert ( iob_len ( iobuf ) >= sizeof ( *grh ) );
grh = iobuf->data;
iob_pull ( iobuf, sizeof ( *grh ) );
/* Locate corresponding GRH */
assert ( hermon_qp->recv.grh != NULL );
grh = &hermon_qp->recv.grh[ wqe_idx & wqe_idx_mask ];
/* Construct address vector */
source = &recv_source;
source->qpn = MLX_GET ( &cqe->normal, srq_rqpn );
Expand Down
6 changes: 5 additions & 1 deletion src/drivers/infiniband/hermon.h
Expand Up @@ -515,7 +515,7 @@ struct hermonprm_eth_send_wqe {
struct hermonprm_wqe_segment_data_ptr data[HERMON_MAX_GATHER];
} __attribute__ (( packed ));

#define HERMON_MAX_SCATTER 1
#define HERMON_MAX_SCATTER 2

struct hermonprm_recv_wqe {
struct hermonprm_wqe_segment_data_ptr data[HERMON_MAX_SCATTER];
Expand Down Expand Up @@ -686,6 +686,10 @@ struct hermon_recv_work_queue {
union hermon_recv_wqe *wqe;
/** Size of work queue */
size_t wqe_size;
/** GRH buffers (if applicable) */
struct ib_global_route_header *grh;
/** Size of GRH buffers */
size_t grh_size;
/** Doorbell record */
struct hermonprm_qp_db_record *doorbell;
};
Expand Down

0 comments on commit e84c917

Please sign in to comment.