diff --git a/src/drivers/net/mlx_ipoib/arbel.h b/src/drivers/net/mlx_ipoib/arbel.h index a41b6330..68c6282c 100644 --- a/src/drivers/net/mlx_ipoib/arbel.h +++ b/src/drivers/net/mlx_ipoib/arbel.h @@ -85,6 +85,12 @@ union arbelprm_doorbell_register { * */ +/** Arbel device limits */ +struct arbel_dev_limits { + /** Number of reserved CQs */ + unsigned long reserved_cqs; +}; + /** Alignment of Arbel send work queue entries */ #define ARBEL_SEND_WQE_ALIGN 128 @@ -129,6 +135,12 @@ struct arbel_queue_pair { struct arbel_recv_work_queue recv; }; +/** Maximum number of allocatable completion queues + * + * This is a policy decision, not a device limit. + */ +#define ARBEL_MAX_CQS 8 + /** An Arbel completion queue */ struct arbel_completion_queue { /** Infiniband completion queue */ @@ -139,6 +151,14 @@ struct arbel_completion_queue { union arbelprm_completion_entry *cqe; }; +/** An Arbel resource bitmask */ +typedef uint32_t arbel_bitmask_t; + +/** Size of an Arbel resource bitmask */ +#define ARBEL_BITMASK_SIZE(max_entries) \ + ( ( (max_entries) + ( 8 * sizeof ( arbel_bitmask_t ) ) - 1 ) / \ + ( 8 * sizeof ( arbel_bitmask_t ) ) ) + /** An Arbel device */ struct arbel { /** Configuration registers */ @@ -157,7 +177,12 @@ struct arbel { * Used to get unrestricted memory access. */ unsigned long reserved_lkey; + + /** Completion queue in-use bitmask */ + arbel_bitmask_t cq_inuse[ ARBEL_BITMASK_SIZE ( ARBEL_MAX_CQS ) ]; + /** Device limits */ + struct arbel_dev_limits limits; }; /* @@ -203,4 +228,64 @@ struct arbel { #define ARBEL_HCR_OUT_CMD( _opcode, _out_mbox, _out_len ) \ ARBEL_HCR_CMD ( _opcode, 0, 0, _out_mbox, _out_len ) +/* + * Doorbell record allocation + * + * The doorbell record map looks like: + * + * ARBEL_MAX_CQS * Arm completion queue doorbell + * ARBEL_MAX_QPS * Send work request doorbell + * Group separator + * ...(empty space)... + * ARBEL_MAX_QPS * Receive work request doorbell + * ARBEL_MAX_CQS * Completion queue consumer counter update doorbell + */ + +#define ARBEL_MAX_DOORBELL_RECORDS 512 +#define ARBEL_GROUP_SEPARATOR_DOORBELL ( ARBEL_MAX_CQS + ARBEL_MAX_QPS ) + +/** + * Get arm completion queue doorbell index + * + * @v cqn_offset Completion queue number offset + * @ret doorbell_idx Doorbell index + */ +static inline unsigned int +arbel_arm_cq_doorbell_idx ( unsigned int cqn_offset ) { + return cqn_offset; +} + +/** + * Get send work request doorbell index + * + * @v qpn_offset Queue pair number offset + * @ret doorbell_idx Doorbell index + */ +static inline unsigned int +arbel_send_doorbell_idx ( unsigned int qpn_offset ) { + return ( ARBEL_MAX_CQS + qpn_offset ); +} + +/** + * Get receive work request doorbell index + * + * @v qpn_offset Queue pair number offset + * @ret doorbell_idx Doorbell index + */ +static inline unsigned int +arbel_recv_doorbell_idx ( unsigned int qpn_offset ) { + return ( ARBEL_MAX_DOORBELL_RECORDS - ARBEL_MAX_CQS - qpn_offset - 1 ); +} + +/** + * Get commpletion queue consumer counter doorbell index + * + * @v cqn_offset Completion queue number offset + * @ret doorbell_idx Doorbell index + */ +static inline unsigned int +arbel_cq_ci_doorbell_idx ( unsigned int cqn_offset ) { + return ( ARBEL_MAX_DOORBELL_RECORDS - cqn_offset - 1 ); +} + #endif /* _ARBEL_H */ diff --git a/src/drivers/net/mlx_ipoib/mt25218.c b/src/drivers/net/mlx_ipoib/mt25218.c index 4fcc6a3c..925b00f9 100644 --- a/src/drivers/net/mlx_ipoib/mt25218.c +++ b/src/drivers/net/mlx_ipoib/mt25218.c @@ -12,6 +12,7 @@ Skeleton NIC driver for Etherboot #include #include +#include #include #include #include @@ -266,6 +267,50 @@ static struct net_device_operations mlx_operations = { .irq = mlx_irq, }; + + + +/** + * Allocate queue number + * + * @v q_inuse Queue usage bitmask + * @v max_inuse Maximum number of in-use queues + * @ret qn_offset Free queue number offset, or negative error + */ +static int arbel_alloc_qn_offset ( arbel_bitmask_t *q_inuse, + unsigned int max_inuse ) { + unsigned int qn_offset = 0; + arbel_bitmask_t mask = 1; + + while ( qn_offset < max_inuse ) { + if ( ( mask & *q_inuse ) == 0 ) { + *q_inuse |= mask; + return qn_offset; + } + qn_offset++; + mask <<= 1; + if ( ! mask ) { + mask = 1; + q_inuse++; + } + } + return -ENFILE; +} + +/** + * Free queue number + * + * @v q_inuse Queue usage bitmask + * @v qn_offset Queue number offset + */ +static void arbel_free_qn_offset ( arbel_bitmask_t *q_inuse, int qn_offset ) { + arbel_bitmask_t mask; + + mask = ( 1 << ( qn_offset % ( 8 * sizeof ( mask ) ) ) ); + q_inuse += ( qn_offset / ( 8 * sizeof ( mask ) ) ); + *q_inuse &= ~mask; +} + /*************************************************************************** * * HCA commands @@ -412,22 +457,78 @@ arbel_cmd_sw2hw_cq ( struct arbel *arbel, unsigned long cqn, * @v ibdev Infiniband device * @v */ -static int arbel_create_cq ( struct ib_device *ibdev, +static int arbel_create_cq ( struct ib_device *ibdev, unsigned int num_cqes, struct ib_completion_queue **new_cq ) { struct arbel *arbel = ibdev->priv; + struct arbel_completion_queue *arbel_cq; struct arbelprm_completion_queue_context cqctx; - struct ib_completion_queue *cq; + int cqn_offset; + unsigned int cqn; + size_t cqe_size; + unsigned int i; + int rc; - cq = zalloc ( sizeof ( *cq ) ); - if ( ! cq ) - return -ENOMEM; + /* Find a free completion queue number */ + cqn_offset = arbel_alloc_qn_offset ( arbel->cq_inuse, ARBEL_MAX_CQS ); + if ( cqn_offset < 0 ) { + rc = cqn_offset; + goto err_cqn_offset; + } + cqn = ( arbel->limits.reserved_cqs + cqn_offset ); - + /* Allocate control structures */ + arbel_cq = zalloc ( sizeof ( *arbel_cq ) ); + if ( ! arbel_cq ) { + rc = -ENOMEM; + goto err_arbel_cq; + } + arbel_cq->cq.cqn = cqn; + arbel_cq->cq.num_cqes = num_cqes; + INIT_LIST_HEAD ( &arbel_cq->cq.work_queues ); + arbel_cq->doorbell_idx = arbel_cq_ci_doorbell_idx ( cqn_offset ); + /* Allocate completion queue itself */ + cqe_size = ( num_cqes * sizeof ( arbel_cq->cqe[0] ) ); + arbel_cq->cqe = malloc_dma ( cqe_size, sizeof ( arbel_cq->cqe[0] ) ); + if ( ! arbel_cq->cqe ) { + rc = -ENOMEM; + goto err_cqe; + } + memset ( arbel_cq->cqe, 0, cqe_size ); + for ( i = 0 ; i < num_cqes ; i++ ) { + MLX_FILL_1 ( &arbel_cq->cqe[i].normal, 7, owner, 1 ); + } + barrier(); + + /* Initialise doorbell records */ + // ... + + /* Hand queue over to hardware */ memset ( &cqctx, 0, sizeof ( cqctx ) ); - + MLX_FILL_1 ( &cqctx, 0, st, 0xa /* "Event fired" */ ); + MLX_FILL_1 ( &cqctx, 2, start_address_l, + virt_to_bus ( arbel_cq->cqe ) ); + /// .... - return arbel_cmd_sw2hw_cq ( arbel, 0, &cqctx ); + if ( ( rc = arbel_cmd_sw2hw_cq ( arbel, cqn, &cqctx ) ) != 0 ) { + // ... + } + + + // completion queue number + // doorbell index + + *new_cq = &arbel_cq->cq; + + + return 0; + + err_cqe: + free ( arbel_cq ); + err_arbel_cq: + arbel_free_qn_offset ( arbel->cq_inuse, cqn_offset ); + err_cqn_offset: + return rc; } @@ -764,6 +865,8 @@ static void arbel_remove ( struct pci_device *pci ) { static int arbel_probe ( struct pci_device *pci, const struct pci_device_id *id __unused ) { struct net_device *netdev; + struct arbelprm_query_dev_lim dev_lim; + struct arbel *arbel = &static_arbel; struct mlx_nic *mlx; struct ib_mac *mac; udqp_t qph; @@ -815,12 +918,14 @@ static int arbel_probe ( struct pci_device *pci, list_add ( &static_ipoib_qp.qp.recv.list, &static_ipoib_recv_cq.cq.work_queues ); - struct arbelprm_query_dev_lim dev_lim; - memset ( &dev_lim, 0xaa, sizeof ( dev_lim ) ); - if ( ( rc = arbel_cmd_query_dev_lim ( &static_arbel, - &dev_lim ) ) != 0 ) { - DBG ( "QUERY_DEV_LIM failed: %s\n", strerror ( rc ) ); + /* Get device limits */ + if ( ( rc = arbel_cmd_query_dev_lim ( arbel, &dev_lim ) ) != 0 ) { + DBGC ( arbel, "Arbel %p could not get device limits: %s\n", + arbel, strerror ( rc ) ); + goto err_query_dev_lim; } + arbel->limits.reserved_cqs = + ( 1 << MLX_GET ( &dev_lim, log2_rsvd_cqs ) ); DBG ( "Device limits:\n "); DBG_HD ( &dev_lim, sizeof ( dev_lim ) ); @@ -830,6 +935,7 @@ static int arbel_probe ( struct pci_device *pci, return 0; + err_query_dev_lim: err_register_netdev: err_ipoib_init: ib_driver_close ( 0 ); diff --git a/src/drivers/net/mlx_ipoib/mt25218.h b/src/drivers/net/mlx_ipoib/mt25218.h index 590d72f6..85c60a0e 100644 --- a/src/drivers/net/mlx_ipoib/mt25218.h +++ b/src/drivers/net/mlx_ipoib/mt25218.h @@ -146,10 +146,10 @@ /* uar context indexes */ enum { - MADS_RCV_CQ_ARM_DB_IDX, MADS_SND_CQ_ARM_DB_IDX, - IPOIB_RCV_CQ_ARM_DB_IDX, + MADS_RCV_CQ_ARM_DB_IDX, IPOIB_SND_CQ_ARM_DB_IDX, + IPOIB_RCV_CQ_ARM_DB_IDX, MADS_SND_QP_DB_IDX, IPOIB_SND_QP_DB_IDX, GROUP_SEP_IDX, @@ -158,12 +158,12 @@ enum { unmapped doorbell records -------------------------- */ END_UNMAPPED_DB_IDX = 505, - MADS_RCV_QP_DB_IDX = 506, - IPOIB_RCV_QP_DB_IDX = 507, - MADS_RCV_CQ_CI_DB_IDX = 508, - MADS_SND_CQ_CI_DB_IDX = 509, - IPOIB_RCV_CQ_CI_DB_IDX = 510, - IPOIB_SND_CQ_CI_DB_IDX = 511 + IPOIB_RCV_QP_DB_IDX = 506, + MADS_RCV_QP_DB_IDX = 507, + IPOIB_RCV_CQ_CI_DB_IDX = 508, + IPOIB_SND_CQ_CI_DB_IDX = 509, + MADS_RCV_CQ_CI_DB_IDX = 510, + MADS_SND_CQ_CI_DB_IDX = 511, }; /* uar resources types */