2007-05-08 18:00:38 -07:00
/*
* Copyright ( c ) 2004 , 2005 Topspin Communications . All rights reserved .
* Copyright ( c ) 2005 Mellanox Technologies . All rights reserved .
* Copyright ( c ) 2006 , 2007 Cisco Systems , Inc . All rights reserved .
*
* This software is available to you under a choice of one of two
* licenses . You may choose to be licensed under the terms of the GNU
* General Public License ( GPL ) Version 2 , available from the file
* COPYING in the main directory of this source tree , or the
* OpenIB . org BSD license below :
*
* Redistribution and use in source and binary forms , with or
* without modification , are permitted provided that the following
* conditions are met :
*
* - Redistributions of source code must retain the above
* copyright notice , this list of conditions and the following
* disclaimer .
*
* - Redistributions in binary form must reproduce the above
* copyright notice , this list of conditions and the following
* disclaimer in the documentation and / or other materials
* provided with the distribution .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND ,
* EXPRESS OR IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY , FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER IN AN
* ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE .
*/
# include "mlx4.h"
# include "fw.h"
enum {
MLX4_RES_QP ,
MLX4_RES_RDMARC ,
MLX4_RES_ALTC ,
MLX4_RES_AUXC ,
MLX4_RES_SRQ ,
MLX4_RES_CQ ,
MLX4_RES_EQ ,
MLX4_RES_DMPT ,
MLX4_RES_CMPT ,
MLX4_RES_MTT ,
MLX4_RES_MCG ,
MLX4_RES_NUM
} ;
static const char * res_name [ ] = {
[ MLX4_RES_QP ] = " QP " ,
[ MLX4_RES_RDMARC ] = " RDMARC " ,
[ MLX4_RES_ALTC ] = " ALTC " ,
[ MLX4_RES_AUXC ] = " AUXC " ,
[ MLX4_RES_SRQ ] = " SRQ " ,
[ MLX4_RES_CQ ] = " CQ " ,
[ MLX4_RES_EQ ] = " EQ " ,
[ MLX4_RES_DMPT ] = " DMPT " ,
[ MLX4_RES_CMPT ] = " CMPT " ,
[ MLX4_RES_MTT ] = " MTT " ,
[ MLX4_RES_MCG ] = " MCG " ,
} ;
u64 mlx4_make_profile ( struct mlx4_dev * dev ,
struct mlx4_profile * request ,
struct mlx4_dev_cap * dev_cap ,
struct mlx4_init_hca_param * init_hca )
{
struct mlx4_priv * priv = mlx4_priv ( dev ) ;
struct mlx4_resource {
u64 size ;
u64 start ;
int type ;
int num ;
int log_num ;
} ;
u64 total_size = 0 ;
struct mlx4_resource * profile ;
struct mlx4_resource tmp ;
int i , j ;
profile = kzalloc ( MLX4_RES_NUM * sizeof * profile , GFP_KERNEL ) ;
if ( ! profile )
return - ENOMEM ;
profile [ MLX4_RES_QP ] . size = dev_cap - > qpc_entry_sz ;
profile [ MLX4_RES_RDMARC ] . size = dev_cap - > rdmarc_entry_sz ;
profile [ MLX4_RES_ALTC ] . size = dev_cap - > altc_entry_sz ;
profile [ MLX4_RES_AUXC ] . size = dev_cap - > aux_entry_sz ;
profile [ MLX4_RES_SRQ ] . size = dev_cap - > srq_entry_sz ;
profile [ MLX4_RES_CQ ] . size = dev_cap - > cqc_entry_sz ;
profile [ MLX4_RES_EQ ] . size = dev_cap - > eqc_entry_sz ;
profile [ MLX4_RES_DMPT ] . size = dev_cap - > dmpt_entry_sz ;
profile [ MLX4_RES_CMPT ] . size = dev_cap - > cmpt_entry_sz ;
2009-05-27 14:38:34 -07:00
profile [ MLX4_RES_MTT ] . size = dev - > caps . mtts_per_seg * dev_cap - > mtt_entry_sz ;
2007-05-08 18:00:38 -07:00
profile [ MLX4_RES_MCG ] . size = MLX4_MGM_ENTRY_SIZE ;
profile [ MLX4_RES_QP ] . num = request - > num_qp ;
profile [ MLX4_RES_RDMARC ] . num = request - > num_qp * request - > rdmarc_per_qp ;
profile [ MLX4_RES_ALTC ] . num = request - > num_qp ;
profile [ MLX4_RES_AUXC ] . num = request - > num_qp ;
profile [ MLX4_RES_SRQ ] . num = request - > num_srq ;
profile [ MLX4_RES_CQ ] . num = request - > num_cq ;
2009-01-15 20:43:56 -08:00
profile [ MLX4_RES_EQ ] . num = min_t ( unsigned , dev_cap - > max_eqs ,
dev_cap - > reserved_eqs +
num_possible_cpus ( ) + 1 ) ;
2007-05-08 18:00:38 -07:00
profile [ MLX4_RES_DMPT ] . num = request - > num_mpt ;
profile [ MLX4_RES_CMPT ] . num = MLX4_NUM_CMPTS ;
profile [ MLX4_RES_MTT ] . num = request - > num_mtt ;
profile [ MLX4_RES_MCG ] . num = request - > num_mcg ;
for ( i = 0 ; i < MLX4_RES_NUM ; + + i ) {
profile [ i ] . type = i ;
profile [ i ] . num = roundup_pow_of_two ( profile [ i ] . num ) ;
profile [ i ] . log_num = ilog2 ( profile [ i ] . num ) ;
profile [ i ] . size * = profile [ i ] . num ;
profile [ i ] . size = max ( profile [ i ] . size , ( u64 ) PAGE_SIZE ) ;
}
/*
* Sort the resources in decreasing order of size . Since they
* all have sizes that are powers of 2 , we ' ll be able to keep
* resources aligned to their size and pack them without gaps
* using the sorted order .
*/
for ( i = MLX4_RES_NUM ; i > 0 ; - - i )
for ( j = 1 ; j < i ; + + j ) {
if ( profile [ j ] . size > profile [ j - 1 ] . size ) {
tmp = profile [ j ] ;
profile [ j ] = profile [ j - 1 ] ;
profile [ j - 1 ] = tmp ;
}
}
for ( i = 0 ; i < MLX4_RES_NUM ; + + i ) {
if ( profile [ i ] . size ) {
profile [ i ] . start = total_size ;
total_size + = profile [ i ] . size ;
}
if ( total_size > dev_cap - > max_icm_sz ) {
mlx4_err ( dev , " Profile requires 0x%llx bytes; "
" won't fit in 0x%llx bytes of context memory. \n " ,
( unsigned long long ) total_size ,
( unsigned long long ) dev_cap - > max_icm_sz ) ;
kfree ( profile ) ;
return - ENOMEM ;
}
if ( profile [ i ] . size )
mlx4_dbg ( dev , " profile[%2d] (%6s): 2^%02d entries @ 0x%10llx, "
" size 0x%10llx \n " ,
i , res_name [ profile [ i ] . type ] , profile [ i ] . log_num ,
( unsigned long long ) profile [ i ] . start ,
( unsigned long long ) profile [ i ] . size ) ;
}
mlx4_dbg ( dev , " HCA context memory: reserving %d KB \n " ,
( int ) ( total_size > > 10 ) ) ;
for ( i = 0 ; i < MLX4_RES_NUM ; + + i ) {
switch ( profile [ i ] . type ) {
case MLX4_RES_QP :
dev - > caps . num_qps = profile [ i ] . num ;
init_hca - > qpc_base = profile [ i ] . start ;
init_hca - > log_num_qps = profile [ i ] . log_num ;
break ;
case MLX4_RES_RDMARC :
for ( priv - > qp_table . rdmarc_shift = 0 ;
request - > num_qp < < priv - > qp_table . rdmarc_shift < profile [ i ] . num ;
+ + priv - > qp_table . rdmarc_shift )
; /* nothing */
dev - > caps . max_qp_dest_rdma = 1 < < priv - > qp_table . rdmarc_shift ;
priv - > qp_table . rdmarc_base = ( u32 ) profile [ i ] . start ;
init_hca - > rdmarc_base = profile [ i ] . start ;
init_hca - > log_rd_per_qp = priv - > qp_table . rdmarc_shift ;
break ;
case MLX4_RES_ALTC :
init_hca - > altc_base = profile [ i ] . start ;
break ;
case MLX4_RES_AUXC :
init_hca - > auxc_base = profile [ i ] . start ;
break ;
case MLX4_RES_SRQ :
dev - > caps . num_srqs = profile [ i ] . num ;
init_hca - > srqc_base = profile [ i ] . start ;
init_hca - > log_num_srqs = profile [ i ] . log_num ;
break ;
case MLX4_RES_CQ :
dev - > caps . num_cqs = profile [ i ] . num ;
init_hca - > cqc_base = profile [ i ] . start ;
init_hca - > log_num_cqs = profile [ i ] . log_num ;
break ;
case MLX4_RES_EQ :
dev - > caps . num_eqs = profile [ i ] . num ;
init_hca - > eqc_base = profile [ i ] . start ;
init_hca - > log_num_eqs = profile [ i ] . log_num ;
break ;
case MLX4_RES_DMPT :
dev - > caps . num_mpts = profile [ i ] . num ;
priv - > mr_table . mpt_base = profile [ i ] . start ;
init_hca - > dmpt_base = profile [ i ] . start ;
init_hca - > log_mpt_sz = profile [ i ] . log_num ;
break ;
case MLX4_RES_CMPT :
init_hca - > cmpt_base = profile [ i ] . start ;
break ;
case MLX4_RES_MTT :
dev - > caps . num_mtt_segs = profile [ i ] . num ;
priv - > mr_table . mtt_base = profile [ i ] . start ;
init_hca - > mtt_base = profile [ i ] . start ;
break ;
case MLX4_RES_MCG :
dev - > caps . num_mgms = profile [ i ] . num > > 1 ;
dev - > caps . num_amgms = profile [ i ] . num > > 1 ;
init_hca - > mc_base = profile [ i ] . start ;
init_hca - > log_mc_entry_sz = ilog2 ( MLX4_MGM_ENTRY_SIZE ) ;
init_hca - > log_mc_table_sz = profile [ i ] . log_num ;
init_hca - > log_mc_hash_sz = profile [ i ] . log_num - 1 ;
break ;
default :
break ;
}
}
/*
* PDs don ' t take any HCA memory , but we assign them as part
* of the HCA profile anyway .
*/
dev - > caps . num_pds = MLX4_NUM_PDS ;
kfree ( profile ) ;
return total_size ;
}