diff --git a/src/drivers/net/mlx_ipoib/bit_ops.h b/src/drivers/net/mlx_ipoib/bit_ops.h index b67f92ce..74823a60 100644 --- a/src/drivers/net/mlx_ipoib/bit_ops.h +++ b/src/drivers/net/mlx_ipoib/bit_ops.h @@ -133,4 +133,102 @@ struct addr_64_st { field; \ }) + + +/* Remaining code Copyright Fen Systems Ltd. 2007 */ + +/** Bit offset of a field within a pseudo_bit_t structure */ +#define MLX_BIT_OFFSET( _structure, _field ) \ + offsetof ( struct _structure, _field ) + +/** Bit width of a field within a pseudo_bit_t structure */ +#define MLX_BIT_WIDTH( _structure, _field ) \ + sizeof ( ( ( struct _structure * ) NULL )->_field ) + +/* + * Assemble native-endian dword from named fields and values + * + */ + +#define MLX_ASSEMBLE_1( _structure, _index, _field, _value ) \ + ( (_value) << \ + ( MLX_BIT_OFFSET ( _structure, _field ) - ( 32 * (_index) ) ) ) + +#define MLX_ASSEMBLE_2( _structure, _index, _field, _value, ... ) \ + ( MLX_ASSEMBLE_1 ( _structure, _index, _field, _value ) | \ + MLX_ASSEMBLE_1 ( _structure, _index, __VA_ARGS__ ) ) + +#define MLX_ASSEMBLE_3( _structure, _index, _field, _value, ... ) \ + ( MLX_ASSEMBLE_1 ( _structure, _index, _field, _value ) | \ + MLX_ASSEMBLE_2 ( _structure, _index, __VA_ARGS__ ) ) + +#define MLX_ASSEMBLE_4( _structure, _index, _field, _value, ... ) \ + ( MLX_ASSEMBLE_1 ( _structure, _index, _field, _value ) | \ + MLX_ASSEMBLE_3 ( _structure, _index, __VA_ARGS__ ) ) + +/* + * Build native-endian (positive) dword bitmasks from named fields + * + */ + +#define MLX_MASK_1( _structure, _index, _field ) \ + MLX_ASSEMBLE_1 ( _structure, _index, _field, \ + ( ( 1 << MLX_BIT_WIDTH ( _structure, \ + _field ) ) - 1 ) ) + +#define MLX_MASK_2( _structure, _index, _field, ... ) \ + ( MLX_MASK_1 ( _structure, _index, _field ) | \ + MLX_MASK_1 ( _structure, _index, __VA_ARGS__ ) ) + +#define MLX_MASK_3( _structure, _index, _field, ... ) \ + ( MLX_MASK_1 ( _structure, _index, _field ) | \ + MLX_MASK_2 ( _structure, _index, __VA_ARGS__ ) ) + +#define MLX_MASK_4( _structure, _index, _field, ... ) \ + ( MLX_MASK_1 ( _structure, _index, _field ) | \ + MLX_MASK_3 ( _structure, _index, __VA_ARGS__ ) ) + +/* + * Populate big-endian dwords from named fields and values + * + */ + +#define MLX_POPULATE( _base, _index, _assembled ) \ + do { \ + uint32_t *__ptr = ( ( (uint32_t *) (_base) ) + (_index) ); \ + uint32_t __assembled = (_assembled); \ + *__ptr = cpu_to_be32 ( __assembled ); \ + } while ( 0 ) + +#define MLX_POPULATE_1( _base, _structure, _index, ... ) \ + MLX_POPULATE ( _base, _index, \ + MLX_ASSEMBLE_1 ( _structure, _index, __VA_ARGS__ ) ) + +#define MLX_POPULATE_2( _base, _structure, _index, ... ) \ + MLX_POPULATE ( _base, _index, \ + MLX_ASSEMBLE_2 ( _structure, _index, __VA_ARGS__ ) ) + +#define MLX_POPULATE_3( _base, _structure, _index, ... ) \ + MLX_POPULATE ( _base, _index, \ + MLX_ASSEMBLE_3 ( _structure, _index, __VA_ARGS__ ) ) + +#define MLX_POPULATE_4( _base, _structure, _index, ... ) \ + MLX_POPULATE ( _base, _index, \ + MLX_ASSEMBLE_4 ( _structure, _index, __VA_ARGS__ ) ) + +/* + * Modify big-endian dword using named field and value + * + */ + +#define MLX_MODIFY( _base, _structure, _index, _field, _value ) \ + do { \ + uint32_t *__ptr = ( ( (uint32_t *) (_base) ) + (_index) ); \ + uint32_t __value = be32_to_cpu ( *__ptr ); \ + __value &= ~( MLX_MASK_1 ( _structure, _index, _field ) ); \ + __value |= MLX_ASSEMBLE_1 ( _structure, _index, \ + _field, _value ); \ + *__ptr = cpu_to_be32 ( __value ); \ + } while ( 0 ) + #endif /* __bit_ops_h__ */ diff --git a/src/drivers/net/mlx_ipoib/mt25218.c b/src/drivers/net/mlx_ipoib/mt25218.c index c6015fb2..e8290bb6 100644 --- a/src/drivers/net/mlx_ipoib/mt25218.c +++ b/src/drivers/net/mlx_ipoib/mt25218.c @@ -224,28 +224,32 @@ static struct net_device_operations mlx_operations = { }; +struct mlx_send_work_queue { + /** Doorbell number */ + unsigned int doorbell_idx; + /** Work queue entries */ + struct ud_send_wqe_st *wqe; +}; -int ib_alloc_wqe ( struct ib_work_queue *wq, struct io_buffer *iobuf ) { - unsigned int wqe_idx; - unsigned int new_write_ptr; +struct mlx { + /** User Access Region */ + unsigned long uar; + /** Doorbell records */ + union db_record_st *db_rec; +}; - /* Allocate queue entry */ - wqe_idx = new_write_ptr = wq->write_ptr; - if ( wq->iobuf[wqe_idx] ) - return -ENOBUFS; - wq->iobuf[wqe_idx] = iobuf; +static struct ib_gid mlx_no_gid = { + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 } +}; - /* Update write pointer */ - new_write_ptr++; - new_write_ptr &= ( wq->num_wqes - 1 ); - wq->write_ptr = new_write_ptr; +static void mlx_ring_doorbell ( struct mlx *mlx, void *db_reg, + unsigned int offset ) { + uint32_t *db_reg_dword = db_reg; - return wqe_idx; -} - -static inline void ib_free_wqe ( struct ib_work_queue *wq, int wqe_idx ) { - assert ( wq->iobuf[wqe_idx] != NULL ); - wq->iobuf[wqe_idx] = NULL; + barrier(); + writel ( db_reg_dword[0], ( mlx->uar + offset + 0 ) ); + barrier(); + writel ( db_reg_dword[1], ( mlx->uar + offset + 4 ) ); } static int mlx_post_send ( struct ib_device *ibdev, struct io_buffer *iobuf, @@ -253,7 +257,7 @@ static int mlx_post_send ( struct ib_device *ibdev, struct io_buffer *iobuf, struct ib_queue_pair *qp ) { struct mlx *mlx = ibdev->priv; struct ib_work_queue *wq = &qp->send; - struct mlx_work_queue *mlx_wq = wq->priv; + struct mlx_send_work_queue *mlx_wq = wq->priv; unsigned int wqe_idx_mask = ( wq->num_wqes - 1 ); unsigned int prev_wqe_idx; struct ud_send_wqe_st *prev_wqe; @@ -261,11 +265,12 @@ static int mlx_post_send ( struct ib_device *ibdev, struct io_buffer *iobuf, struct ud_send_wqe_st *wqe; struct ib_gid *gid; size_t nds; - struct send_doorbell_st doorbell; + union db_record_st *db_rec; + struct send_doorbell_st db_reg; /* Allocate work queue entry */ prev_wqe_idx = wq->posted; - wqe_idx = ( prev_wqe_index + 1 ); + wqe_idx = ( prev_wqe_idx + 1 ); if ( wq->iobuf[wqe_idx & wqe_idx_mask] ) { DBGC ( mlx, "MLX %p send queue full", mlx ); return -ENOBUFS; @@ -282,16 +287,16 @@ static int mlx_post_send ( struct ib_device *ibdev, struct io_buffer *iobuf, memset ( &wqe->udseg, 0, sizeof ( wqe->udseg ) ); MLX_POPULATE_2 ( &wqe->udseg, arbelprm_ud_address_vector_st, 0, pd, GLOBAL_PD, - port_number, mlx->port ); + port_number, PXE_IB_PORT ); MLX_POPULATE_2 ( &wqe->udseg, arbelprm_ud_address_vector_st, 1, - rlid, av->remote_lid, + rlid, av->dlid, g, av->gid_present ); MLX_POPULATE_2 ( &wqe->udseg, arbelprm_ud_address_vector_st, 2, max_stat_rate, ( ( av->rate >= 3 ) ? 0 : 1 ), msg, 3 ); MLX_POPULATE_1 ( &wqe->udseg, arbelprm_ud_address_vector_st, 3, sl, av->sl ); - gid = ( av->gid_present ? av->gid : &ib_no_gid ); + gid = ( av->gid_present ? &av->gid : &mlx_no_gid ); memcpy ( ( ( ( void * ) &wqe->udseg ) + 16 ), gid, sizeof ( *gid ) ); MLX_POPULATE_1 ( &wqe->udseg, arbelprm_wqe_segment_ud_st, 8, @@ -305,55 +310,34 @@ static int mlx_post_send ( struct ib_device *ibdev, struct io_buffer *iobuf, /* Update previous work queue entry's "next" field */ nds = ( offsetof ( typeof ( *wqe ), mpointer ) + sizeof ( wqe->mpointer[0] ) ); - MLX_MODIFY_1 ( &prev_wqe->next.next, arbelprm_wqe_segment_next_st, 0, - nopcode, XDEV_NOPCODE_SEND ); + MLX_MODIFY ( &prev_wqe->next.next, arbelprm_wqe_segment_next_st, 0, + nopcode, XDEV_NOPCODE_SEND ); MLX_POPULATE_3 ( &prev_wqe->next.next, arbelprm_wqe_segment_next_st, 1, nds, nds, f, 1, always1, 1 ); - /* Ring doorbell */ - - doorbell index is a property of the queue pair - - - MLX_POPULATE_1 ( mlx_wq->send_uar_context, arbelprm_qp_db_record_st, 0, + /* Update doorbell record */ + db_rec = &mlx->db_rec[mlx_wq->doorbell_idx]; + MLX_POPULATE_1 ( db_rec, arbelprm_qp_db_record_st, 0, counter, ( wqe_idx & 0xffff ) ); - memset ( &doorbell, 0, sizeof ( doorbell ) ); - MLX_POPULATE_4 ( &doorbell, arbelprm_send_doorbell_st, 0, + barrier(); + + /* Ring doorbell register */ + MLX_POPULATE_4 ( &db_reg, arbelprm_send_doorbell_st, 0, nopcode, XDEV_NOPCODE_SEND, f, 1, wqe_counter, ( prev_wqe_idx & 0xffff ), wqe_cnt, 1 ); - MLX_POPULATE_2 ( &doorbell, arbelprm_send_doorbell_st, 1, + MLX_POPULATE_2 ( &db_reg, arbelprm_send_doorbell_st, 1, nds, nds, qpn, qp->qpn ); - barrier(); + mlx_ring_doorbell ( mlx, &db_reg, POST_SND_OFFSET ); + /* Update work queue's posted index */ wq->posted = wqe_idx; - - struct mlx_nic *mlx = netdev->priv; - ud_av_t av = iobuf->data; - ud_send_wqe_t snd_wqe; - int rc; - - snd_wqe = alloc_send_wqe ( mlx->ipoib_qph ); - if ( ! snd_wqe ) { - DBGC ( mlx, "MLX %p out of TX WQEs\n", mlx ); - return -ENOBUFS; - } - - prep_send_wqe_buf ( mlx->ipoib_qph, mlx->bcast_av, snd_wqe, - iobuf->data, 0, iob_len ( iobuf ), 0 ); - if ( ( rc = post_send_req ( mlx->ipoib_qph, snd_wqe, 1 ) ) != 0 ) { - DBGC ( mlx, "MLX %p could not post TX WQE %p: %s\n", - mlx, snd_wqe, strerror ( rc ) ); - free_wqe ( snd_wqe ); - return rc; - } - - + return 0; } static struct ib_device_operations mlx_ib_operations = { diff --git a/src/drivers/net/mlx_ipoib/mt25218.h b/src/drivers/net/mlx_ipoib/mt25218.h index 1e7c8d8b..590d72f6 100644 --- a/src/drivers/net/mlx_ipoib/mt25218.h +++ b/src/drivers/net/mlx_ipoib/mt25218.h @@ -342,6 +342,24 @@ struct cq_dbell_st { __u8 raw[MT_STRUCT_SIZE(arbelprm_cq_cmd_doorbell_st)]; } __attribute__ ((packed)); +struct qp_db_record_st { + __u8 raw[MT_STRUCT_SIZE(arbelprm_qp_db_record_st)]; +} __attribute__ ((packed)); + +struct cq_arm_db_record_st { + __u8 raw[MT_STRUCT_SIZE(arbelprm_cq_arm_db_record_st)]; +} __attribute__ ((packed)); + +struct cq_ci_db_record_st { + __u8 raw[MT_STRUCT_SIZE(arbelprm_cq_ci_db_record_st)]; +} __attribute__ ((packed)); + +union db_record_st { + struct qp_db_record_st qp; + struct cq_arm_db_record_st cq_arm; + struct cq_ci_db_record_st cq_ci; +} __attribute__ ((packed)); + struct mad_ifc_inprm_st { union mad_u mad; } __attribute__ ((packed)); diff --git a/src/include/gpxe/infiniband.h b/src/include/gpxe/infiniband.h index 22a8a982..ccb6e49e 100644 --- a/src/include/gpxe/infiniband.h +++ b/src/include/gpxe/infiniband.h @@ -61,6 +61,9 @@ struct ibhdr { uint16_t reserved; } __attribute__ (( packed )); + + + /** An Infiniband Work Queue */ struct ib_work_queue { /** Number of work queue entries */ @@ -70,10 +73,7 @@ struct ib_work_queue { * This is the index of the most recently posted entry. */ unsigned int posted; - /** Driver-private data - * - * Typically used to hold the address of the work queue. - */ + /** Driver private data */ void *priv; /** I/O buffers assigned to work queue */ struct io_buffer *iobuf[0]; @@ -87,13 +87,30 @@ struct ib_queue_pair { struct ib_work_queue send; /** Receive queue */ struct ib_work_queue recv; + /** Driver private data */ + void *priv; }; /** An Infiniband Address Vector */ struct ib_address_vector { - + /** Destination Queue Pair */ + unsigned int dest_qp; + /** Queue key */ + unsigned int qkey; + /** Destination Local ID */ + unsigned int dlid; + /** Rate */ + unsigned int rate; + /** Service level */ + unsigned int sl; + /** GID is present */ + unsigned int gid_present; + /** GID */ + struct ib_gid gid; }; +struct ib_device; + /** * Infiniband device operations * @@ -119,7 +136,11 @@ struct ib_device_operations { struct ib_queue_pair *qp ); }; - +/** An Infiniband device */ +struct ib_device { + /** Driver private data */ + void *priv; +};