david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

[arbel] Perform ICM allocations according to the specification

The current method for ICM allocation exactly matches the addresses
chosen by the old Etherboot driver, but does not match the
specification.  Some ICM tables (notably the queue pair context table)
therefore end up incorrectly aligned.

Fix by performing allocations as per the specification.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown 2010-09-17 04:56:23 +01:00
parent f7a49e23e9
commit d84e4e0575
2 changed files with 87 additions and 44 deletions

View File

@ -1981,7 +1981,7 @@ static int arbel_start_firmware ( struct arbel *arbel ) {
arbel_cmd_enable_lam ( arbel, &lam ); arbel_cmd_enable_lam ( arbel, &lam );
/* Allocate firmware pages and map firmware area */ /* Allocate firmware pages and map firmware area */
fw_size = ( fw_pages * 4096 ); fw_size = ( fw_pages * ARBEL_PAGE_SIZE );
arbel->firmware_area = umalloc ( fw_size * 2 ); arbel->firmware_area = umalloc ( fw_size * 2 );
if ( ! arbel->firmware_area ) { if ( ! arbel->firmware_area ) {
rc = -ENOMEM; rc = -ENOMEM;
@ -2092,18 +2092,17 @@ static int arbel_get_limits ( struct arbel *arbel ) {
} }
/** /**
* Get ICM usage * Align ICM table
* *
* @v log_num_entries Log2 of the number of entries * @v icm_offset Current ICM offset
* @v entry_size Entry size * @v len ICM table length
* @ret usage Usage size in ICM * @ret icm_offset ICM offset
*/ */
static size_t icm_usage ( unsigned int log_num_entries, size_t entry_size ) { static size_t icm_align ( size_t icm_offset, size_t len ) {
size_t usage;
usage = ( ( 1 << log_num_entries ) * entry_size ); /* Round up to a multiple of the table size */
usage = ( ( usage + 4095 ) & ~4095 ); assert ( len == ( 1UL << ( fls ( len ) - 1 ) ) );
return usage; return ( ( icm_offset + len - 1 ) & ~( len - 1 ) );
} }
/** /**
@ -2123,6 +2122,8 @@ static int arbel_alloc_icm ( struct arbel *arbel,
size_t icm_offset = 0; size_t icm_offset = 0;
unsigned int log_num_qps, log_num_srqs, log_num_ees, log_num_cqs; unsigned int log_num_qps, log_num_srqs, log_num_ees, log_num_cqs;
unsigned int log_num_mtts, log_num_mpts, log_num_rdbs, log_num_eqs; unsigned int log_num_mtts, log_num_mpts, log_num_rdbs, log_num_eqs;
unsigned int log_num_mcs;
size_t len;
int rc; int rc;
icm_offset = ( ( arbel->limits.reserved_uars + 1 ) << 12 ); icm_offset = ( ( arbel->limits.reserved_uars + 1 ) << 12 );
@ -2130,108 +2131,143 @@ static int arbel_alloc_icm ( struct arbel *arbel,
/* Queue pair contexts */ /* Queue pair contexts */
log_num_qps = fls ( arbel->limits.reserved_qps + log_num_qps = fls ( arbel->limits.reserved_qps +
ARBEL_RSVD_SPECIAL_QPS + ARBEL_MAX_QPS - 1 ); ARBEL_RSVD_SPECIAL_QPS + ARBEL_MAX_QPS - 1 );
len = ( ( 1 << log_num_qps ) * arbel->limits.qpc_entry_size );
icm_offset = icm_align ( icm_offset, len );
MLX_FILL_2 ( init_hca, 13, MLX_FILL_2 ( init_hca, 13,
qpc_eec_cqc_eqc_rdb_parameters.qpc_base_addr_l, qpc_eec_cqc_eqc_rdb_parameters.qpc_base_addr_l,
( icm_offset >> 7 ), ( icm_offset >> 7 ),
qpc_eec_cqc_eqc_rdb_parameters.log_num_of_qp, qpc_eec_cqc_eqc_rdb_parameters.log_num_of_qp,
log_num_qps ); log_num_qps );
DBGC ( arbel, "Arbel %p ICM QPC base = %zx\n", arbel, icm_offset ); DBGC ( arbel, "Arbel %p ICM QPC at [%zx,%zx)\n",
icm_offset += icm_usage ( log_num_qps, arbel->limits.qpc_entry_size ); arbel, icm_offset, ( icm_offset + len ) );
icm_offset += len;
/* Extended queue pair contexts */ /* Extended queue pair contexts */
len = ( ( 1 << log_num_qps ) * arbel->limits.eqpc_entry_size );
icm_offset = icm_align ( icm_offset, len );
MLX_FILL_1 ( init_hca, 25, MLX_FILL_1 ( init_hca, 25,
qpc_eec_cqc_eqc_rdb_parameters.eqpc_base_addr_l, qpc_eec_cqc_eqc_rdb_parameters.eqpc_base_addr_l,
icm_offset ); icm_offset );
DBGC ( arbel, "Arbel %p ICM EQPC base = %zx\n", arbel, icm_offset ); DBGC ( arbel, "Arbel %p ICM EQPC at [%zx,%zx)\n",
// icm_offset += icm_usage ( log_num_qps, arbel->limits.eqpc_entry_size ); arbel, icm_offset, ( icm_offset + len ) );
icm_offset += icm_usage ( log_num_qps, arbel->limits.qpc_entry_size ); icm_offset += len;
/* Shared receive queue contexts */ /* Shared receive queue contexts */
log_num_srqs = fls ( arbel->limits.reserved_srqs - 1 ); log_num_srqs = fls ( arbel->limits.reserved_srqs - 1 );
len = ( ( 1 << log_num_srqs ) * arbel->limits.srqc_entry_size );
icm_offset = icm_align ( icm_offset, len );
MLX_FILL_2 ( init_hca, 19, MLX_FILL_2 ( init_hca, 19,
qpc_eec_cqc_eqc_rdb_parameters.srqc_base_addr_l, qpc_eec_cqc_eqc_rdb_parameters.srqc_base_addr_l,
( icm_offset >> 5 ), ( icm_offset >> 5 ),
qpc_eec_cqc_eqc_rdb_parameters.log_num_of_srq, qpc_eec_cqc_eqc_rdb_parameters.log_num_of_srq,
log_num_srqs ); log_num_srqs );
DBGC ( arbel, "Arbel %p ICM SRQC base = %zx\n", arbel, icm_offset ); DBGC ( arbel, "Arbel %p ICM SRQC at [%zx,%zx)\n",
icm_offset += icm_usage ( log_num_srqs, arbel->limits.srqc_entry_size ); arbel, icm_offset, ( icm_offset + len ) );
icm_offset += len;
/* End-to-end contexts */ /* End-to-end contexts */
log_num_ees = fls ( arbel->limits.reserved_ees - 1 ); log_num_ees = fls ( arbel->limits.reserved_ees - 1 );
len = ( ( 1 << log_num_ees ) * arbel->limits.eec_entry_size );
icm_offset = icm_align ( icm_offset, len );
MLX_FILL_2 ( init_hca, 17, MLX_FILL_2 ( init_hca, 17,
qpc_eec_cqc_eqc_rdb_parameters.eec_base_addr_l, qpc_eec_cqc_eqc_rdb_parameters.eec_base_addr_l,
( icm_offset >> 7 ), ( icm_offset >> 7 ),
qpc_eec_cqc_eqc_rdb_parameters.log_num_of_ee, qpc_eec_cqc_eqc_rdb_parameters.log_num_of_ee,
log_num_ees ); log_num_ees );
DBGC ( arbel, "Arbel %p ICM EEC base = %zx\n", arbel, icm_offset ); DBGC ( arbel, "Arbel %p ICM EEC at [%zx,%zx)\n",
icm_offset += icm_usage ( log_num_ees, arbel->limits.eec_entry_size ); arbel, icm_offset, ( icm_offset + len ) );
icm_offset += len;
/* Extended end-to-end contexts */ /* Extended end-to-end contexts */
len = ( ( 1 << log_num_ees ) * arbel->limits.eeec_entry_size );
icm_offset = icm_align ( icm_offset, len );
MLX_FILL_1 ( init_hca, 29, MLX_FILL_1 ( init_hca, 29,
qpc_eec_cqc_eqc_rdb_parameters.eeec_base_addr_l, qpc_eec_cqc_eqc_rdb_parameters.eeec_base_addr_l,
icm_offset ); icm_offset );
DBGC ( arbel, "Arbel %p ICM EEEC base = %zx\n", arbel, icm_offset ); DBGC ( arbel, "Arbel %p ICM EEEC at [%zx,%zx)\n",
icm_offset += icm_usage ( log_num_ees, arbel->limits.eeec_entry_size ); arbel, icm_offset, ( icm_offset + len ) );
icm_offset += len;
/* Completion queue contexts */ /* Completion queue contexts */
log_num_cqs = fls ( arbel->limits.reserved_cqs + ARBEL_MAX_CQS - 1 ); log_num_cqs = fls ( arbel->limits.reserved_cqs + ARBEL_MAX_CQS - 1 );
len = ( ( 1 << log_num_cqs ) * arbel->limits.cqc_entry_size );
icm_offset = icm_align ( icm_offset, len );
MLX_FILL_2 ( init_hca, 21, MLX_FILL_2 ( init_hca, 21,
qpc_eec_cqc_eqc_rdb_parameters.cqc_base_addr_l, qpc_eec_cqc_eqc_rdb_parameters.cqc_base_addr_l,
( icm_offset >> 6 ), ( icm_offset >> 6 ),
qpc_eec_cqc_eqc_rdb_parameters.log_num_of_cq, qpc_eec_cqc_eqc_rdb_parameters.log_num_of_cq,
log_num_cqs ); log_num_cqs );
DBGC ( arbel, "Arbel %p ICM CQC base = %zx\n", arbel, icm_offset ); DBGC ( arbel, "Arbel %p ICM CQC at [%zx,%zx)\n",
icm_offset += icm_usage ( log_num_cqs, arbel->limits.cqc_entry_size ); arbel, icm_offset, ( icm_offset + len ) );
icm_offset += len;
/* Memory translation table */ /* Memory translation table */
log_num_mtts = fls ( arbel->limits.reserved_mtts - 1 ); log_num_mtts = fls ( arbel->limits.reserved_mtts - 1 );
len = ( ( 1 << log_num_mtts ) * arbel->limits.mtt_entry_size );
icm_offset = icm_align ( icm_offset, len );
MLX_FILL_1 ( init_hca, 65, MLX_FILL_1 ( init_hca, 65,
tpt_parameters.mtt_base_addr_l, icm_offset ); tpt_parameters.mtt_base_addr_l, icm_offset );
DBGC ( arbel, "Arbel %p ICM MTT base = %zx\n", arbel, icm_offset ); DBGC ( arbel, "Arbel %p ICM MTT at [%zx,%zx)\n",
icm_offset += icm_usage ( log_num_mtts, arbel->limits.mtt_entry_size ); arbel, icm_offset, ( icm_offset + len ) );
icm_offset += len;
/* Memory protection table */ /* Memory protection table */
log_num_mpts = fls ( arbel->limits.reserved_mrws + 1 - 1 ); log_num_mpts = fls ( arbel->limits.reserved_mrws + 1 - 1 );
len = ( ( 1 << log_num_mpts ) * arbel->limits.mpt_entry_size );
icm_offset = icm_align ( icm_offset, len );
MLX_FILL_1 ( init_hca, 61, MLX_FILL_1 ( init_hca, 61,
tpt_parameters.mpt_base_adr_l, icm_offset ); tpt_parameters.mpt_base_adr_l, icm_offset );
MLX_FILL_1 ( init_hca, 62, MLX_FILL_1 ( init_hca, 62,
tpt_parameters.log_mpt_sz, log_num_mpts ); tpt_parameters.log_mpt_sz, log_num_mpts );
DBGC ( arbel, "Arbel %p ICM MTT base = %zx\n", arbel, icm_offset ); DBGC ( arbel, "Arbel %p ICM MTT at [%zx,%zx)\n",
icm_offset += icm_usage ( log_num_mpts, arbel->limits.mpt_entry_size ); arbel, icm_offset, ( icm_offset + len ) );
icm_offset += len;
/* RDMA something or other */ /* Remote read data base table */
log_num_rdbs = fls ( arbel->limits.reserved_rdbs - 1 ); log_num_rdbs = fls ( arbel->limits.reserved_rdbs - 1 );
len = ( ( 1 << log_num_rdbs ) * ARBEL_RDB_ENTRY_SIZE );
icm_offset = icm_align ( icm_offset, len );
MLX_FILL_1 ( init_hca, 37, MLX_FILL_1 ( init_hca, 37,
qpc_eec_cqc_eqc_rdb_parameters.rdb_base_addr_l, qpc_eec_cqc_eqc_rdb_parameters.rdb_base_addr_l,
icm_offset ); icm_offset );
DBGC ( arbel, "Arbel %p ICM RDB base = %zx\n", arbel, icm_offset ); DBGC ( arbel, "Arbel %p ICM RDB at [%zx,%zx)\n",
icm_offset += icm_usage ( log_num_rdbs, 32 ); arbel, icm_offset, ( icm_offset + len ) );
icm_offset += len;
/* Event queue contexts */ /* Event queue contexts */
log_num_eqs = fls ( arbel->limits.reserved_eqs + ARBEL_MAX_EQS - 1 ); log_num_eqs = fls ( arbel->limits.reserved_eqs + ARBEL_MAX_EQS - 1 );
len = ( ( 1 << log_num_eqs ) * arbel->limits.eqc_entry_size );
icm_offset = icm_align ( icm_offset, len );
MLX_FILL_2 ( init_hca, 33, MLX_FILL_2 ( init_hca, 33,
qpc_eec_cqc_eqc_rdb_parameters.eqc_base_addr_l, qpc_eec_cqc_eqc_rdb_parameters.eqc_base_addr_l,
( icm_offset >> 6 ), ( icm_offset >> 6 ),
qpc_eec_cqc_eqc_rdb_parameters.log_num_eq, qpc_eec_cqc_eqc_rdb_parameters.log_num_eq,
log_num_eqs ); log_num_eqs );
DBGC ( arbel, "Arbel %p ICM EQ base = %zx\n", arbel, icm_offset ); DBGC ( arbel, "Arbel %p ICM EQ at [%zx,%zx)\n",
icm_offset += ( ( 1 << log_num_eqs ) * arbel->limits.eqc_entry_size ); arbel, icm_offset, ( icm_offset + len ) );
icm_offset += len;
/* Multicast table */ /* Multicast table */
log_num_mcs = ARBEL_LOG_MULTICAST_HASH_SIZE;
len = ( ( 1 << log_num_mcs ) * sizeof ( struct arbelprm_mgm_entry ) );
icm_offset = icm_align ( icm_offset, len );
MLX_FILL_1 ( init_hca, 49, MLX_FILL_1 ( init_hca, 49,
multicast_parameters.mc_base_addr_l, icm_offset ); multicast_parameters.mc_base_addr_l, icm_offset );
MLX_FILL_1 ( init_hca, 52, MLX_FILL_1 ( init_hca, 52,
multicast_parameters.log_mc_table_entry_sz, multicast_parameters.log_mc_table_entry_sz,
fls ( sizeof ( struct arbelprm_mgm_entry ) - 1 ) ); fls ( sizeof ( struct arbelprm_mgm_entry ) - 1 ) );
MLX_FILL_1 ( init_hca, 53, MLX_FILL_1 ( init_hca, 53,
multicast_parameters.mc_table_hash_sz, 8 ); multicast_parameters.mc_table_hash_sz,
( 1 << log_num_mcs ) );
MLX_FILL_1 ( init_hca, 54, MLX_FILL_1 ( init_hca, 54,
multicast_parameters.log_mc_table_sz, 3 ); multicast_parameters.log_mc_table_sz,
DBGC ( arbel, "Arbel %p ICM MC base = %zx\n", arbel, icm_offset ); log_num_mcs /* Only one entry per hash */ );
icm_offset += ( 8 * sizeof ( struct arbelprm_mgm_entry ) ); DBGC ( arbel, "Arbel %p ICM MC at [%zx,%zx)\n",
arbel, icm_offset, ( icm_offset + len ) );
icm_offset += len;
arbel->icm_len = icm_offset; /* Round up to a whole number of pages */
arbel->icm_len = ( ( arbel->icm_len + 4095 ) & ~4095 ); arbel->icm_len = icm_align ( icm_offset, ARBEL_PAGE_SIZE );
/* Get ICM auxiliary area size */ /* Get ICM auxiliary area size */
memset ( &icm_size, 0, sizeof ( icm_size ) ); memset ( &icm_size, 0, sizeof ( icm_size ) );
@ -2242,7 +2278,8 @@ static int arbel_alloc_icm ( struct arbel *arbel,
arbel, strerror ( rc ) ); arbel, strerror ( rc ) );
goto err_set_icm_size; goto err_set_icm_size;
} }
arbel->icm_aux_len = ( MLX_GET ( &icm_aux_size, value ) * 4096 ); arbel->icm_aux_len =
( MLX_GET ( &icm_aux_size, value ) * ARBEL_PAGE_SIZE );
/* Allocate ICM data and auxiliary area */ /* Allocate ICM data and auxiliary area */
DBGC ( arbel, "Arbel %p requires %zd kB ICM and %zd kB AUX ICM\n", DBGC ( arbel, "Arbel %p requires %zd kB ICM and %zd kB AUX ICM\n",
@ -2257,7 +2294,8 @@ static int arbel_alloc_icm ( struct arbel *arbel,
/* Map ICM auxiliary area */ /* Map ICM auxiliary area */
memset ( &map_icm_aux, 0, sizeof ( map_icm_aux ) ); memset ( &map_icm_aux, 0, sizeof ( map_icm_aux ) );
MLX_FILL_2 ( &map_icm_aux, 3, MLX_FILL_2 ( &map_icm_aux, 3,
log2size, fls ( ( arbel->icm_aux_len / 4096 ) - 1 ), log2size,
fls ( ( arbel->icm_aux_len / ARBEL_PAGE_SIZE ) - 1 ),
pa_l, pa_l,
( user_to_phys ( arbel->icm, arbel->icm_len ) >> 12 ) ); ( user_to_phys ( arbel->icm, arbel->icm_len ) >> 12 ) );
if ( ( rc = arbel_cmd_map_icm_aux ( arbel, &map_icm_aux ) ) != 0 ) { if ( ( rc = arbel_cmd_map_icm_aux ( arbel, &map_icm_aux ) ) != 0 ) {
@ -2269,7 +2307,8 @@ static int arbel_alloc_icm ( struct arbel *arbel,
/* MAP ICM area */ /* MAP ICM area */
memset ( &map_icm, 0, sizeof ( map_icm ) ); memset ( &map_icm, 0, sizeof ( map_icm ) );
MLX_FILL_2 ( &map_icm, 3, MLX_FILL_2 ( &map_icm, 3,
log2size, fls ( ( arbel->icm_len / 4096 ) - 1 ), log2size,
fls ( ( arbel->icm_len / ARBEL_PAGE_SIZE ) - 1 ),
pa_l, ( user_to_phys ( arbel->icm, 0 ) >> 12 ) ); pa_l, ( user_to_phys ( arbel->icm, 0 ) >> 12 ) );
if ( ( rc = arbel_cmd_map_icm ( arbel, &map_icm ) ) != 0 ) { if ( ( rc = arbel_cmd_map_icm ( arbel, &map_icm ) ) != 0 ) {
DBGC ( arbel, "Arbel %p could not map ICM: %s\n", DBGC ( arbel, "Arbel %p could not map ICM: %s\n",
@ -2287,7 +2326,7 @@ static int arbel_alloc_icm ( struct arbel *arbel,
return 0; return 0;
arbel_cmd_unmap_icm ( arbel, ( arbel->icm_len / 4096 ) ); arbel_cmd_unmap_icm ( arbel, ( arbel->icm_len / ARBEL_PAGE_SIZE ) );
err_map_icm: err_map_icm:
arbel_cmd_unmap_icm_aux ( arbel ); arbel_cmd_unmap_icm_aux ( arbel );
err_map_icm_aux: err_map_icm_aux:
@ -2304,7 +2343,7 @@ static int arbel_alloc_icm ( struct arbel *arbel,
* @v arbel Arbel device * @v arbel Arbel device
*/ */
static void arbel_free_icm ( struct arbel *arbel ) { static void arbel_free_icm ( struct arbel *arbel ) {
arbel_cmd_unmap_icm ( arbel, ( arbel->icm_len / 4096 ) ); arbel_cmd_unmap_icm ( arbel, ( arbel->icm_len / ARBEL_PAGE_SIZE ) );
arbel_cmd_unmap_icm_aux ( arbel ); arbel_cmd_unmap_icm_aux ( arbel );
ufree ( arbel->icm ); ufree ( arbel->icm );
arbel->icm = UNULL; arbel->icm = UNULL;

View File

@ -93,6 +93,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ARBEL_PAGE_SIZE 4096 #define ARBEL_PAGE_SIZE 4096
#define ARBEL_RDB_ENTRY_SIZE 32
#define ARBEL_DB_POST_SND_OFFSET 0x10 #define ARBEL_DB_POST_SND_OFFSET 0x10
#define ARBEL_DB_EQ_OFFSET(_eqn) ( 0x08 * (_eqn) ) #define ARBEL_DB_EQ_OFFSET(_eqn) ( 0x08 * (_eqn) )
@ -103,6 +105,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ARBEL_EV_PORT_STATE_CHANGE 0x09 #define ARBEL_EV_PORT_STATE_CHANGE 0x09
#define ARBEL_LOG_MULTICAST_HASH_SIZE 3
/* /*
* Datatypes that seem to be missing from the autogenerated documentation * Datatypes that seem to be missing from the autogenerated documentation
* *