2007-05-09 05:00:38 +04:00
/*
* Copyright ( c ) 2004 , 2005 Topspin Communications . All rights reserved .
* Copyright ( c ) 2005 Sun Microsystems , Inc . 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 <linux/module.h>
# include <linux/init.h>
# include <linux/errno.h>
# include <linux/pci.h>
# include <linux/dma-mapping.h>
# include <linux/mlx4/device.h>
# include <linux/mlx4/doorbell.h>
# include "mlx4.h"
# include "fw.h"
# include "icm.h"
MODULE_AUTHOR ( " Roland Dreier " ) ;
MODULE_DESCRIPTION ( " Mellanox ConnectX HCA low-level driver " ) ;
MODULE_LICENSE ( " Dual BSD/GPL " ) ;
MODULE_VERSION ( DRV_VERSION ) ;
# ifdef CONFIG_MLX4_DEBUG
int mlx4_debug_level = 0 ;
module_param_named ( debug_level , mlx4_debug_level , int , 0644 ) ;
MODULE_PARM_DESC ( debug_level , " Enable debug tracing if > 0 " ) ;
# endif /* CONFIG_MLX4_DEBUG */
# ifdef CONFIG_PCI_MSI
2007-08-07 17:08:28 +04:00
static int msi_x = 1 ;
2007-05-09 05:00:38 +04:00
module_param ( msi_x , int , 0444 ) ;
MODULE_PARM_DESC ( msi_x , " attempt to use MSI-X if nonzero " ) ;
# else /* CONFIG_PCI_MSI */
# define msi_x (0)
# endif /* CONFIG_PCI_MSI */
2008-02-05 07:20:44 +03:00
static char mlx4_version [ ] __devinitdata =
2007-05-09 05:00:38 +04:00
DRV_NAME " : Mellanox ConnectX core driver v "
DRV_VERSION " ( " DRV_RELDATE " ) \n " ;
static struct mlx4_profile default_profile = {
2008-04-17 08:09:32 +04:00
. num_qp = 1 < < 17 ,
2007-05-09 05:00:38 +04:00
. num_srq = 1 < < 16 ,
2007-07-17 14:11:43 +04:00
. rdmarc_per_qp = 1 < < 4 ,
2007-05-09 05:00:38 +04:00
. num_cq = 1 < < 16 ,
. num_mcg = 1 < < 13 ,
. num_mpt = 1 < < 17 ,
. num_mtt = 1 < < 20 ,
} ;
2007-10-11 02:43:54 +04:00
static int mlx4_dev_cap ( struct mlx4_dev * dev , struct mlx4_dev_cap * dev_cap )
2007-05-09 05:00:38 +04:00
{
int err ;
2007-06-18 19:15:02 +04:00
int i ;
2007-05-09 05:00:38 +04:00
err = mlx4_QUERY_DEV_CAP ( dev , dev_cap ) ;
if ( err ) {
mlx4_err ( dev , " QUERY_DEV_CAP command failed, aborting. \n " ) ;
return err ;
}
if ( dev_cap - > min_page_sz > PAGE_SIZE ) {
mlx4_err ( dev , " HCA minimum page size of %d bigger than "
" kernel PAGE_SIZE of %ld, aborting. \n " ,
dev_cap - > min_page_sz , PAGE_SIZE ) ;
return - ENODEV ;
}
if ( dev_cap - > num_ports > MLX4_MAX_PORTS ) {
mlx4_err ( dev , " HCA has %d ports, but we only support %d, "
" aborting. \n " ,
dev_cap - > num_ports , MLX4_MAX_PORTS ) ;
return - ENODEV ;
}
if ( dev_cap - > uar_size > pci_resource_len ( dev - > pdev , 2 ) ) {
mlx4_err ( dev , " HCA reported UAR size of 0x%x bigger than "
" PCI resource 2 size of 0x%llx, aborting. \n " ,
dev_cap - > uar_size ,
( unsigned long long ) pci_resource_len ( dev - > pdev , 2 ) ) ;
return - ENODEV ;
}
dev - > caps . num_ports = dev_cap - > num_ports ;
2007-06-18 19:15:02 +04:00
for ( i = 1 ; i < = dev - > caps . num_ports ; + + i ) {
dev - > caps . vl_cap [ i ] = dev_cap - > max_vl [ i ] ;
dev - > caps . mtu_cap [ i ] = dev_cap - > max_mtu [ i ] ;
dev - > caps . gid_table_len [ i ] = dev_cap - > max_gids [ i ] ;
dev - > caps . pkey_table_len [ i ] = dev_cap - > max_pkeys [ i ] ;
dev - > caps . port_width_cap [ i ] = dev_cap - > max_port_width [ i ] ;
}
2007-05-09 05:00:38 +04:00
dev - > caps . num_uars = dev_cap - > uar_size / PAGE_SIZE ;
dev - > caps . local_ca_ack_delay = dev_cap - > local_ca_ack_delay ;
dev - > caps . bf_reg_size = dev_cap - > bf_reg_size ;
dev - > caps . bf_regs_per_page = dev_cap - > bf_regs_per_page ;
dev - > caps . max_sq_sg = dev_cap - > max_sq_sg ;
dev - > caps . max_rq_sg = dev_cap - > max_rq_sg ;
dev - > caps . max_wqes = dev_cap - > max_qp_sz ;
dev - > caps . max_qp_init_rdma = dev_cap - > max_requester_per_qp ;
dev - > caps . reserved_qps = dev_cap - > reserved_qps ;
dev - > caps . max_srq_wqes = dev_cap - > max_srq_sz ;
dev - > caps . max_srq_sge = dev_cap - > max_rq_sg - 1 ;
dev - > caps . reserved_srqs = dev_cap - > reserved_srqs ;
dev - > caps . max_sq_desc_sz = dev_cap - > max_sq_desc_sz ;
dev - > caps . max_rq_desc_sz = dev_cap - > max_rq_desc_sz ;
dev - > caps . num_qp_per_mgm = MLX4_QP_PER_MGM ;
/*
* Subtract 1 from the limit because we need to allocate a
* spare CQE so the HCA HW can tell the difference between an
* empty CQ and a full CQ .
*/
dev - > caps . max_cqes = dev_cap - > max_cq_sz - 1 ;
dev - > caps . reserved_cqs = dev_cap - > reserved_cqs ;
dev - > caps . reserved_eqs = dev_cap - > reserved_eqs ;
2007-10-10 06:59:16 +04:00
dev - > caps . reserved_mtts = DIV_ROUND_UP ( dev_cap - > reserved_mtts ,
MLX4_MTT_ENTRY_PER_SEG ) ;
2007-05-09 05:00:38 +04:00
dev - > caps . reserved_mrws = dev_cap - > reserved_mrws ;
dev - > caps . reserved_uars = dev_cap - > reserved_uars ;
dev - > caps . reserved_pds = dev_cap - > reserved_pds ;
dev - > caps . mtt_entry_sz = MLX4_MTT_ENTRY_PER_SEG * dev_cap - > mtt_entry_sz ;
2007-06-26 16:55:28 +04:00
dev - > caps . max_msg_sz = dev_cap - > max_msg_sz ;
2007-05-09 05:00:38 +04:00
dev - > caps . page_size_cap = ~ ( u32 ) ( dev_cap - > min_page_sz - 1 ) ;
dev - > caps . flags = dev_cap - > flags ;
dev - > caps . stat_rate_support = dev_cap - > stat_rate_support ;
2008-04-17 08:09:27 +04:00
dev - > caps . max_gso_sz = dev_cap - > max_gso_sz ;
2007-05-09 05:00:38 +04:00
return 0 ;
}
2008-02-05 07:20:41 +03:00
static int mlx4_load_fw ( struct mlx4_dev * dev )
2007-05-09 05:00:38 +04:00
{
struct mlx4_priv * priv = mlx4_priv ( dev ) ;
int err ;
priv - > fw . fw_icm = mlx4_alloc_icm ( dev , priv - > fw . fw_pages ,
2007-08-01 13:28:20 +04:00
GFP_HIGHUSER | __GFP_NOWARN , 0 ) ;
2007-05-09 05:00:38 +04:00
if ( ! priv - > fw . fw_icm ) {
mlx4_err ( dev , " Couldn't allocate FW area, aborting. \n " ) ;
return - ENOMEM ;
}
err = mlx4_MAP_FA ( dev , priv - > fw . fw_icm ) ;
if ( err ) {
mlx4_err ( dev , " MAP_FA command failed, aborting. \n " ) ;
goto err_free ;
}
err = mlx4_RUN_FW ( dev ) ;
if ( err ) {
mlx4_err ( dev , " RUN_FW command failed, aborting. \n " ) ;
goto err_unmap_fa ;
}
return 0 ;
err_unmap_fa :
mlx4_UNMAP_FA ( dev ) ;
err_free :
2007-08-01 13:28:20 +04:00
mlx4_free_icm ( dev , priv - > fw . fw_icm , 0 ) ;
2007-05-09 05:00:38 +04:00
return err ;
}
2008-02-05 07:20:41 +03:00
static int mlx4_init_cmpt_table ( struct mlx4_dev * dev , u64 cmpt_base ,
int cmpt_entry_sz )
2007-05-09 05:00:38 +04:00
{
struct mlx4_priv * priv = mlx4_priv ( dev ) ;
int err ;
err = mlx4_init_icm_table ( dev , & priv - > qp_table . cmpt_table ,
cmpt_base +
( ( u64 ) ( MLX4_CMPT_TYPE_QP *
cmpt_entry_sz ) < < MLX4_CMPT_SHIFT ) ,
cmpt_entry_sz , dev - > caps . num_qps ,
2007-08-01 13:28:20 +04:00
dev - > caps . reserved_qps , 0 , 0 ) ;
2007-05-09 05:00:38 +04:00
if ( err )
goto err ;
err = mlx4_init_icm_table ( dev , & priv - > srq_table . cmpt_table ,
cmpt_base +
( ( u64 ) ( MLX4_CMPT_TYPE_SRQ *
cmpt_entry_sz ) < < MLX4_CMPT_SHIFT ) ,
cmpt_entry_sz , dev - > caps . num_srqs ,
2007-08-01 13:28:20 +04:00
dev - > caps . reserved_srqs , 0 , 0 ) ;
2007-05-09 05:00:38 +04:00
if ( err )
goto err_qp ;
err = mlx4_init_icm_table ( dev , & priv - > cq_table . cmpt_table ,
cmpt_base +
( ( u64 ) ( MLX4_CMPT_TYPE_CQ *
cmpt_entry_sz ) < < MLX4_CMPT_SHIFT ) ,
cmpt_entry_sz , dev - > caps . num_cqs ,
2007-08-01 13:28:20 +04:00
dev - > caps . reserved_cqs , 0 , 0 ) ;
2007-05-09 05:00:38 +04:00
if ( err )
goto err_srq ;
err = mlx4_init_icm_table ( dev , & priv - > eq_table . cmpt_table ,
cmpt_base +
( ( u64 ) ( MLX4_CMPT_TYPE_EQ *
cmpt_entry_sz ) < < MLX4_CMPT_SHIFT ) ,
cmpt_entry_sz ,
roundup_pow_of_two ( MLX4_NUM_EQ +
dev - > caps . reserved_eqs ) ,
2007-08-01 13:28:20 +04:00
MLX4_NUM_EQ + dev - > caps . reserved_eqs , 0 , 0 ) ;
2007-05-09 05:00:38 +04:00
if ( err )
goto err_cq ;
return 0 ;
err_cq :
mlx4_cleanup_icm_table ( dev , & priv - > cq_table . cmpt_table ) ;
err_srq :
mlx4_cleanup_icm_table ( dev , & priv - > srq_table . cmpt_table ) ;
err_qp :
mlx4_cleanup_icm_table ( dev , & priv - > qp_table . cmpt_table ) ;
err :
return err ;
}
2007-10-11 02:43:54 +04:00
static int mlx4_init_icm ( struct mlx4_dev * dev , struct mlx4_dev_cap * dev_cap ,
struct mlx4_init_hca_param * init_hca , u64 icm_size )
2007-05-09 05:00:38 +04:00
{
struct mlx4_priv * priv = mlx4_priv ( dev ) ;
u64 aux_pages ;
int err ;
err = mlx4_SET_ICM_SIZE ( dev , icm_size , & aux_pages ) ;
if ( err ) {
mlx4_err ( dev , " SET_ICM_SIZE command failed, aborting. \n " ) ;
return err ;
}
mlx4_dbg ( dev , " %lld KB of HCA context requires %lld KB aux memory. \n " ,
( unsigned long long ) icm_size > > 10 ,
( unsigned long long ) aux_pages < < 2 ) ;
priv - > fw . aux_icm = mlx4_alloc_icm ( dev , aux_pages ,
2007-08-01 13:28:20 +04:00
GFP_HIGHUSER | __GFP_NOWARN , 0 ) ;
2007-05-09 05:00:38 +04:00
if ( ! priv - > fw . aux_icm ) {
mlx4_err ( dev , " Couldn't allocate aux memory, aborting. \n " ) ;
return - ENOMEM ;
}
err = mlx4_MAP_ICM_AUX ( dev , priv - > fw . aux_icm ) ;
if ( err ) {
mlx4_err ( dev , " MAP_ICM_AUX command failed, aborting. \n " ) ;
goto err_free_aux ;
}
err = mlx4_init_cmpt_table ( dev , init_hca - > cmpt_base , dev_cap - > cmpt_entry_sz ) ;
if ( err ) {
mlx4_err ( dev , " Failed to map cMPT context memory, aborting. \n " ) ;
goto err_unmap_aux ;
}
err = mlx4_map_eq_icm ( dev , init_hca - > eqc_base ) ;
if ( err ) {
mlx4_err ( dev , " Failed to map EQ context memory, aborting. \n " ) ;
goto err_unmap_cmpt ;
}
2007-08-01 13:28:53 +04:00
/*
* Reserved MTT entries must be aligned up to a cacheline
* boundary , since the FW will write to them , while the driver
* writes to all other MTT entries . ( The variable
* dev - > caps . mtt_entry_sz below is really the MTT segment
* size , not the raw entry size )
*/
dev - > caps . reserved_mtts =
ALIGN ( dev - > caps . reserved_mtts * dev - > caps . mtt_entry_sz ,
dma_get_cache_alignment ( ) ) / dev - > caps . mtt_entry_sz ;
2007-05-09 05:00:38 +04:00
err = mlx4_init_icm_table ( dev , & priv - > mr_table . mtt_table ,
init_hca - > mtt_base ,
dev - > caps . mtt_entry_sz ,
dev - > caps . num_mtt_segs ,
2007-08-01 13:28:20 +04:00
dev - > caps . reserved_mtts , 1 , 0 ) ;
2007-05-09 05:00:38 +04:00
if ( err ) {
mlx4_err ( dev , " Failed to map MTT context memory, aborting. \n " ) ;
goto err_unmap_eq ;
}
err = mlx4_init_icm_table ( dev , & priv - > mr_table . dmpt_table ,
init_hca - > dmpt_base ,
dev_cap - > dmpt_entry_sz ,
dev - > caps . num_mpts ,
2007-08-01 13:28:20 +04:00
dev - > caps . reserved_mrws , 1 , 1 ) ;
2007-05-09 05:00:38 +04:00
if ( err ) {
mlx4_err ( dev , " Failed to map dMPT context memory, aborting. \n " ) ;
goto err_unmap_mtt ;
}
err = mlx4_init_icm_table ( dev , & priv - > qp_table . qp_table ,
init_hca - > qpc_base ,
dev_cap - > qpc_entry_sz ,
dev - > caps . num_qps ,
2007-08-01 13:28:20 +04:00
dev - > caps . reserved_qps , 0 , 0 ) ;
2007-05-09 05:00:38 +04:00
if ( err ) {
mlx4_err ( dev , " Failed to map QP context memory, aborting. \n " ) ;
goto err_unmap_dmpt ;
}
err = mlx4_init_icm_table ( dev , & priv - > qp_table . auxc_table ,
init_hca - > auxc_base ,
dev_cap - > aux_entry_sz ,
dev - > caps . num_qps ,
2007-08-01 13:28:20 +04:00
dev - > caps . reserved_qps , 0 , 0 ) ;
2007-05-09 05:00:38 +04:00
if ( err ) {
mlx4_err ( dev , " Failed to map AUXC context memory, aborting. \n " ) ;
goto err_unmap_qp ;
}
err = mlx4_init_icm_table ( dev , & priv - > qp_table . altc_table ,
init_hca - > altc_base ,
dev_cap - > altc_entry_sz ,
dev - > caps . num_qps ,
2007-08-01 13:28:20 +04:00
dev - > caps . reserved_qps , 0 , 0 ) ;
2007-05-09 05:00:38 +04:00
if ( err ) {
mlx4_err ( dev , " Failed to map ALTC context memory, aborting. \n " ) ;
goto err_unmap_auxc ;
}
err = mlx4_init_icm_table ( dev , & priv - > qp_table . rdmarc_table ,
init_hca - > rdmarc_base ,
dev_cap - > rdmarc_entry_sz < < priv - > qp_table . rdmarc_shift ,
dev - > caps . num_qps ,
2007-08-01 13:28:20 +04:00
dev - > caps . reserved_qps , 0 , 0 ) ;
2007-05-09 05:00:38 +04:00
if ( err ) {
mlx4_err ( dev , " Failed to map RDMARC context memory, aborting \n " ) ;
goto err_unmap_altc ;
}
err = mlx4_init_icm_table ( dev , & priv - > cq_table . table ,
init_hca - > cqc_base ,
dev_cap - > cqc_entry_sz ,
dev - > caps . num_cqs ,
2007-08-01 13:28:20 +04:00
dev - > caps . reserved_cqs , 0 , 0 ) ;
2007-05-09 05:00:38 +04:00
if ( err ) {
mlx4_err ( dev , " Failed to map CQ context memory, aborting. \n " ) ;
goto err_unmap_rdmarc ;
}
err = mlx4_init_icm_table ( dev , & priv - > srq_table . table ,
init_hca - > srqc_base ,
dev_cap - > srq_entry_sz ,
dev - > caps . num_srqs ,
2007-08-01 13:28:20 +04:00
dev - > caps . reserved_srqs , 0 , 0 ) ;
2007-05-09 05:00:38 +04:00
if ( err ) {
mlx4_err ( dev , " Failed to map SRQ context memory, aborting. \n " ) ;
goto err_unmap_cq ;
}
/*
* It ' s not strictly required , but for simplicity just map the
* whole multicast group table now . The table isn ' t very big
* and it ' s a lot easier than trying to track ref counts .
*/
err = mlx4_init_icm_table ( dev , & priv - > mcg_table . table ,
init_hca - > mc_base , MLX4_MGM_ENTRY_SIZE ,
dev - > caps . num_mgms + dev - > caps . num_amgms ,
dev - > caps . num_mgms + dev - > caps . num_amgms ,
2007-08-01 13:28:20 +04:00
0 , 0 ) ;
2007-05-09 05:00:38 +04:00
if ( err ) {
mlx4_err ( dev , " Failed to map MCG context memory, aborting. \n " ) ;
goto err_unmap_srq ;
}
return 0 ;
err_unmap_srq :
mlx4_cleanup_icm_table ( dev , & priv - > srq_table . table ) ;
err_unmap_cq :
mlx4_cleanup_icm_table ( dev , & priv - > cq_table . table ) ;
err_unmap_rdmarc :
mlx4_cleanup_icm_table ( dev , & priv - > qp_table . rdmarc_table ) ;
err_unmap_altc :
mlx4_cleanup_icm_table ( dev , & priv - > qp_table . altc_table ) ;
err_unmap_auxc :
mlx4_cleanup_icm_table ( dev , & priv - > qp_table . auxc_table ) ;
err_unmap_qp :
mlx4_cleanup_icm_table ( dev , & priv - > qp_table . qp_table ) ;
err_unmap_dmpt :
mlx4_cleanup_icm_table ( dev , & priv - > mr_table . dmpt_table ) ;
err_unmap_mtt :
mlx4_cleanup_icm_table ( dev , & priv - > mr_table . mtt_table ) ;
err_unmap_eq :
mlx4_unmap_eq_icm ( dev ) ;
err_unmap_cmpt :
mlx4_cleanup_icm_table ( dev , & priv - > eq_table . cmpt_table ) ;
mlx4_cleanup_icm_table ( dev , & priv - > cq_table . cmpt_table ) ;
mlx4_cleanup_icm_table ( dev , & priv - > srq_table . cmpt_table ) ;
mlx4_cleanup_icm_table ( dev , & priv - > qp_table . cmpt_table ) ;
err_unmap_aux :
mlx4_UNMAP_ICM_AUX ( dev ) ;
err_free_aux :
2007-08-01 13:28:20 +04:00
mlx4_free_icm ( dev , priv - > fw . aux_icm , 0 ) ;
2007-05-09 05:00:38 +04:00
return err ;
}
static void mlx4_free_icms ( struct mlx4_dev * dev )
{
struct mlx4_priv * priv = mlx4_priv ( dev ) ;
mlx4_cleanup_icm_table ( dev , & priv - > mcg_table . table ) ;
mlx4_cleanup_icm_table ( dev , & priv - > srq_table . table ) ;
mlx4_cleanup_icm_table ( dev , & priv - > cq_table . table ) ;
mlx4_cleanup_icm_table ( dev , & priv - > qp_table . rdmarc_table ) ;
mlx4_cleanup_icm_table ( dev , & priv - > qp_table . altc_table ) ;
mlx4_cleanup_icm_table ( dev , & priv - > qp_table . auxc_table ) ;
mlx4_cleanup_icm_table ( dev , & priv - > qp_table . qp_table ) ;
mlx4_cleanup_icm_table ( dev , & priv - > mr_table . dmpt_table ) ;
mlx4_cleanup_icm_table ( dev , & priv - > mr_table . mtt_table ) ;
mlx4_cleanup_icm_table ( dev , & priv - > eq_table . cmpt_table ) ;
mlx4_cleanup_icm_table ( dev , & priv - > cq_table . cmpt_table ) ;
mlx4_cleanup_icm_table ( dev , & priv - > srq_table . cmpt_table ) ;
mlx4_cleanup_icm_table ( dev , & priv - > qp_table . cmpt_table ) ;
mlx4_unmap_eq_icm ( dev ) ;
mlx4_UNMAP_ICM_AUX ( dev ) ;
2007-08-01 13:28:20 +04:00
mlx4_free_icm ( dev , priv - > fw . aux_icm , 0 ) ;
2007-05-09 05:00:38 +04:00
}
static void mlx4_close_hca ( struct mlx4_dev * dev )
{
mlx4_CLOSE_HCA ( dev , 0 ) ;
mlx4_free_icms ( dev ) ;
mlx4_UNMAP_FA ( dev ) ;
2007-08-01 13:28:20 +04:00
mlx4_free_icm ( dev , mlx4_priv ( dev ) - > fw . fw_icm , 0 ) ;
2007-05-09 05:00:38 +04:00
}
2007-10-11 02:43:54 +04:00
static int mlx4_init_hca ( struct mlx4_dev * dev )
2007-05-09 05:00:38 +04:00
{
struct mlx4_priv * priv = mlx4_priv ( dev ) ;
struct mlx4_adapter adapter ;
struct mlx4_dev_cap dev_cap ;
struct mlx4_profile profile ;
struct mlx4_init_hca_param init_hca ;
u64 icm_size ;
int err ;
err = mlx4_QUERY_FW ( dev ) ;
if ( err ) {
mlx4_err ( dev , " QUERY_FW command failed, aborting. \n " ) ;
return err ;
}
err = mlx4_load_fw ( dev ) ;
if ( err ) {
mlx4_err ( dev , " Failed to start FW, aborting. \n " ) ;
return err ;
}
err = mlx4_dev_cap ( dev , & dev_cap ) ;
if ( err ) {
mlx4_err ( dev , " QUERY_DEV_CAP command failed, aborting. \n " ) ;
goto err_stop_fw ;
}
profile = default_profile ;
icm_size = mlx4_make_profile ( dev , & profile , & dev_cap , & init_hca ) ;
if ( ( long long ) icm_size < 0 ) {
err = icm_size ;
goto err_stop_fw ;
}
init_hca . log_uar_sz = ilog2 ( dev - > caps . num_uars ) ;
err = mlx4_init_icm ( dev , & dev_cap , & init_hca , icm_size ) ;
if ( err )
goto err_stop_fw ;
err = mlx4_INIT_HCA ( dev , & init_hca ) ;
if ( err ) {
mlx4_err ( dev , " INIT_HCA command failed, aborting. \n " ) ;
goto err_free_icm ;
}
err = mlx4_QUERY_ADAPTER ( dev , & adapter ) ;
if ( err ) {
mlx4_err ( dev , " QUERY_ADAPTER command failed, aborting. \n " ) ;
goto err_close ;
}
priv - > eq_table . inta_pin = adapter . inta_pin ;
2007-09-18 11:14:18 +04:00
memcpy ( dev - > board_id , adapter . board_id , sizeof dev - > board_id ) ;
2007-05-09 05:00:38 +04:00
return 0 ;
err_close :
mlx4_close_hca ( dev ) ;
err_free_icm :
mlx4_free_icms ( dev ) ;
err_stop_fw :
mlx4_UNMAP_FA ( dev ) ;
2007-08-01 13:28:20 +04:00
mlx4_free_icm ( dev , priv - > fw . fw_icm , 0 ) ;
2007-05-09 05:00:38 +04:00
return err ;
}
2007-10-11 02:43:54 +04:00
static int mlx4_setup_hca ( struct mlx4_dev * dev )
2007-05-09 05:00:38 +04:00
{
struct mlx4_priv * priv = mlx4_priv ( dev ) ;
int err ;
err = mlx4_init_uar_table ( dev ) ;
if ( err ) {
mlx4_err ( dev , " Failed to initialize "
" user access region table, aborting. \n " ) ;
return err ;
}
err = mlx4_uar_alloc ( dev , & priv - > driver_uar ) ;
if ( err ) {
mlx4_err ( dev , " Failed to allocate driver access region, "
" aborting. \n " ) ;
goto err_uar_table_free ;
}
priv - > kar = ioremap ( priv - > driver_uar . pfn < < PAGE_SHIFT , PAGE_SIZE ) ;
if ( ! priv - > kar ) {
mlx4_err ( dev , " Couldn't map kernel access region, "
" aborting. \n " ) ;
err = - ENOMEM ;
goto err_uar_free ;
}
err = mlx4_init_pd_table ( dev ) ;
if ( err ) {
mlx4_err ( dev , " Failed to initialize "
" protection domain table, aborting. \n " ) ;
goto err_kar_unmap ;
}
err = mlx4_init_mr_table ( dev ) ;
if ( err ) {
mlx4_err ( dev , " Failed to initialize "
" memory region table, aborting. \n " ) ;
goto err_pd_table_free ;
}
err = mlx4_init_eq_table ( dev ) ;
if ( err ) {
mlx4_err ( dev , " Failed to initialize "
" event queue table, aborting. \n " ) ;
2007-07-12 18:50:45 +04:00
goto err_mr_table_free ;
2007-05-09 05:00:38 +04:00
}
err = mlx4_cmd_use_events ( dev ) ;
if ( err ) {
mlx4_err ( dev , " Failed to switch to event-driven "
" firmware commands, aborting. \n " ) ;
goto err_eq_table_free ;
}
err = mlx4_NOP ( dev ) ;
if ( err ) {
2007-08-07 17:08:28 +04:00
if ( dev - > flags & MLX4_FLAG_MSI_X ) {
mlx4_warn ( dev , " NOP command failed to generate MSI-X "
" interrupt IRQ %d). \n " ,
priv - > eq_table . eq [ MLX4_EQ_ASYNC ] . irq ) ;
mlx4_warn ( dev , " Trying again without MSI-X. \n " ) ;
} else {
mlx4_err ( dev , " NOP command failed to generate interrupt "
" (IRQ %d), aborting. \n " ,
priv - > eq_table . eq [ MLX4_EQ_ASYNC ] . irq ) ;
2007-05-09 05:00:38 +04:00
mlx4_err ( dev , " BIOS or ACPI interrupt routing problem? \n " ) ;
2007-08-07 17:08:28 +04:00
}
2007-05-09 05:00:38 +04:00
goto err_cmd_poll ;
}
mlx4_dbg ( dev , " NOP command IRQ test passed \n " ) ;
err = mlx4_init_cq_table ( dev ) ;
if ( err ) {
mlx4_err ( dev , " Failed to initialize "
" completion queue table, aborting. \n " ) ;
goto err_cmd_poll ;
}
err = mlx4_init_srq_table ( dev ) ;
if ( err ) {
mlx4_err ( dev , " Failed to initialize "
" shared receive queue table, aborting. \n " ) ;
goto err_cq_table_free ;
}
err = mlx4_init_qp_table ( dev ) ;
if ( err ) {
mlx4_err ( dev , " Failed to initialize "
" queue pair table, aborting. \n " ) ;
goto err_srq_table_free ;
}
err = mlx4_init_mcg_table ( dev ) ;
if ( err ) {
mlx4_err ( dev , " Failed to initialize "
" multicast group table, aborting. \n " ) ;
goto err_qp_table_free ;
}
return 0 ;
err_qp_table_free :
mlx4_cleanup_qp_table ( dev ) ;
err_srq_table_free :
mlx4_cleanup_srq_table ( dev ) ;
err_cq_table_free :
mlx4_cleanup_cq_table ( dev ) ;
err_cmd_poll :
mlx4_cmd_use_polling ( dev ) ;
err_eq_table_free :
mlx4_cleanup_eq_table ( dev ) ;
2007-07-12 18:50:45 +04:00
err_mr_table_free :
2007-05-09 05:00:38 +04:00
mlx4_cleanup_mr_table ( dev ) ;
err_pd_table_free :
mlx4_cleanup_pd_table ( dev ) ;
err_kar_unmap :
iounmap ( priv - > kar ) ;
err_uar_free :
mlx4_uar_free ( dev , & priv - > driver_uar ) ;
err_uar_table_free :
mlx4_cleanup_uar_table ( dev ) ;
return err ;
}
2008-02-05 07:20:41 +03:00
static void mlx4_enable_msi_x ( struct mlx4_dev * dev )
2007-05-09 05:00:38 +04:00
{
struct mlx4_priv * priv = mlx4_priv ( dev ) ;
struct msix_entry entries [ MLX4_NUM_EQ ] ;
int err ;
int i ;
if ( msi_x ) {
for ( i = 0 ; i < MLX4_NUM_EQ ; + + i )
entries [ i ] . entry = i ;
err = pci_enable_msix ( dev - > pdev , entries , ARRAY_SIZE ( entries ) ) ;
if ( err ) {
if ( err > 0 )
mlx4_info ( dev , " Only %d MSI-X vectors available, "
" not using MSI-X \n " , err ) ;
goto no_msi ;
}
for ( i = 0 ; i < MLX4_NUM_EQ ; + + i )
priv - > eq_table . eq [ i ] . irq = entries [ i ] . vector ;
dev - > flags | = MLX4_FLAG_MSI_X ;
return ;
}
no_msi :
for ( i = 0 ; i < MLX4_NUM_EQ ; + + i )
priv - > eq_table . eq [ i ] . irq = dev - > pdev - > irq ;
}
2007-10-11 02:43:54 +04:00
static int __mlx4_init_one ( struct pci_dev * pdev , const struct pci_device_id * id )
2007-05-09 05:00:38 +04:00
{
struct mlx4_priv * priv ;
struct mlx4_dev * dev ;
int err ;
printk ( KERN_INFO PFX " Initializing %s \n " ,
pci_name ( pdev ) ) ;
err = pci_enable_device ( pdev ) ;
if ( err ) {
dev_err ( & pdev - > dev , " Cannot enable PCI device, "
" aborting. \n " ) ;
return err ;
}
/*
2008-04-17 08:09:35 +04:00
* Check for BARs . We expect 0 : 1 MB
2007-05-09 05:00:38 +04:00
*/
if ( ! ( pci_resource_flags ( pdev , 0 ) & IORESOURCE_MEM ) | |
pci_resource_len ( pdev , 0 ) ! = 1 < < 20 ) {
dev_err ( & pdev - > dev , " Missing DCS, aborting. \n " ) ;
err = - ENODEV ;
goto err_disable_pdev ;
}
if ( ! ( pci_resource_flags ( pdev , 2 ) & IORESOURCE_MEM ) ) {
dev_err ( & pdev - > dev , " Missing UAR, aborting. \n " ) ;
err = - ENODEV ;
goto err_disable_pdev ;
}
err = pci_request_region ( pdev , 0 , DRV_NAME ) ;
if ( err ) {
dev_err ( & pdev - > dev , " Cannot request control region, aborting. \n " ) ;
goto err_disable_pdev ;
}
err = pci_request_region ( pdev , 2 , DRV_NAME ) ;
if ( err ) {
dev_err ( & pdev - > dev , " Cannot request UAR region, aborting. \n " ) ;
goto err_release_bar0 ;
}
pci_set_master ( pdev ) ;
err = pci_set_dma_mask ( pdev , DMA_64BIT_MASK ) ;
if ( err ) {
dev_warn ( & pdev - > dev , " Warning: couldn't set 64-bit PCI DMA mask. \n " ) ;
err = pci_set_dma_mask ( pdev , DMA_32BIT_MASK ) ;
if ( err ) {
dev_err ( & pdev - > dev , " Can't set PCI DMA mask, aborting. \n " ) ;
goto err_release_bar2 ;
}
}
err = pci_set_consistent_dma_mask ( pdev , DMA_64BIT_MASK ) ;
if ( err ) {
dev_warn ( & pdev - > dev , " Warning: couldn't set 64-bit "
" consistent PCI DMA mask. \n " ) ;
err = pci_set_consistent_dma_mask ( pdev , DMA_32BIT_MASK ) ;
if ( err ) {
dev_err ( & pdev - > dev , " Can't set consistent PCI DMA mask, "
" aborting. \n " ) ;
goto err_release_bar2 ;
}
}
priv = kzalloc ( sizeof * priv , GFP_KERNEL ) ;
if ( ! priv ) {
dev_err ( & pdev - > dev , " Device struct alloc failed, "
" aborting. \n " ) ;
err = - ENOMEM ;
goto err_release_bar2 ;
}
dev = & priv - > dev ;
dev - > pdev = pdev ;
2007-06-07 22:51:58 +04:00
INIT_LIST_HEAD ( & priv - > ctx_list ) ;
spin_lock_init ( & priv - > ctx_lock ) ;
2007-05-09 05:00:38 +04:00
/*
* Now reset the HCA before we touch the PCI capabilities or
* attempt a firmware command , since a boot ROM may have left
* the HCA in an undefined state .
*/
err = mlx4_reset ( dev ) ;
if ( err ) {
mlx4_err ( dev , " Failed to reset HCA, aborting. \n " ) ;
goto err_free_dev ;
}
if ( mlx4_cmd_init ( dev ) ) {
mlx4_err ( dev , " Failed to init command interface, aborting. \n " ) ;
goto err_free_dev ;
}
err = mlx4_init_hca ( dev ) ;
if ( err )
goto err_cmd ;
2007-08-07 17:08:28 +04:00
mlx4_enable_msi_x ( dev ) ;
2007-05-09 05:00:38 +04:00
err = mlx4_setup_hca ( dev ) ;
2007-08-07 17:08:28 +04:00
if ( err = = - EBUSY & & ( dev - > flags & MLX4_FLAG_MSI_X ) ) {
dev - > flags & = ~ MLX4_FLAG_MSI_X ;
pci_disable_msix ( pdev ) ;
err = mlx4_setup_hca ( dev ) ;
}
2007-05-09 05:00:38 +04:00
if ( err )
goto err_close ;
err = mlx4_register_device ( dev ) ;
if ( err )
goto err_cleanup ;
pci_set_drvdata ( pdev , dev ) ;
return 0 ;
err_cleanup :
mlx4_cleanup_mcg_table ( dev ) ;
mlx4_cleanup_qp_table ( dev ) ;
mlx4_cleanup_srq_table ( dev ) ;
mlx4_cleanup_cq_table ( dev ) ;
mlx4_cmd_use_polling ( dev ) ;
mlx4_cleanup_eq_table ( dev ) ;
mlx4_cleanup_mr_table ( dev ) ;
mlx4_cleanup_pd_table ( dev ) ;
mlx4_cleanup_uar_table ( dev ) ;
err_close :
2007-08-07 17:08:28 +04:00
if ( dev - > flags & MLX4_FLAG_MSI_X )
pci_disable_msix ( pdev ) ;
2007-05-09 05:00:38 +04:00
mlx4_close_hca ( dev ) ;
err_cmd :
mlx4_cmd_cleanup ( dev ) ;
err_free_dev :
kfree ( priv ) ;
err_release_bar2 :
pci_release_region ( pdev , 2 ) ;
err_release_bar0 :
pci_release_region ( pdev , 0 ) ;
err_disable_pdev :
pci_disable_device ( pdev ) ;
pci_set_drvdata ( pdev , NULL ) ;
return err ;
}
2007-10-11 02:43:54 +04:00
static int __devinit mlx4_init_one ( struct pci_dev * pdev ,
const struct pci_device_id * id )
{
static int mlx4_version_printed ;
if ( ! mlx4_version_printed ) {
printk ( KERN_INFO " %s " , mlx4_version ) ;
+ + mlx4_version_printed ;
}
2007-10-14 01:10:50 +04:00
return __mlx4_init_one ( pdev , id ) ;
2007-10-11 02:43:54 +04:00
}
static void mlx4_remove_one ( struct pci_dev * pdev )
2007-05-09 05:00:38 +04:00
{
struct mlx4_dev * dev = pci_get_drvdata ( pdev ) ;
struct mlx4_priv * priv = mlx4_priv ( dev ) ;
int p ;
if ( dev ) {
mlx4_unregister_device ( dev ) ;
for ( p = 1 ; p < = dev - > caps . num_ports ; + + p )
mlx4_CLOSE_PORT ( dev , p ) ;
mlx4_cleanup_mcg_table ( dev ) ;
mlx4_cleanup_qp_table ( dev ) ;
mlx4_cleanup_srq_table ( dev ) ;
mlx4_cleanup_cq_table ( dev ) ;
mlx4_cmd_use_polling ( dev ) ;
mlx4_cleanup_eq_table ( dev ) ;
mlx4_cleanup_mr_table ( dev ) ;
mlx4_cleanup_pd_table ( dev ) ;
iounmap ( priv - > kar ) ;
mlx4_uar_free ( dev , & priv - > driver_uar ) ;
mlx4_cleanup_uar_table ( dev ) ;
mlx4_close_hca ( dev ) ;
mlx4_cmd_cleanup ( dev ) ;
if ( dev - > flags & MLX4_FLAG_MSI_X )
pci_disable_msix ( pdev ) ;
kfree ( priv ) ;
pci_release_region ( pdev , 2 ) ;
pci_release_region ( pdev , 0 ) ;
pci_disable_device ( pdev ) ;
pci_set_drvdata ( pdev , NULL ) ;
}
}
2007-07-12 18:50:45 +04:00
int mlx4_restart_one ( struct pci_dev * pdev )
{
mlx4_remove_one ( pdev ) ;
2007-10-11 02:43:54 +04:00
return __mlx4_init_one ( pdev , NULL ) ;
2007-07-12 18:50:45 +04:00
}
2007-05-09 05:00:38 +04:00
static struct pci_device_id mlx4_pci_table [ ] = {
{ PCI_VDEVICE ( MELLANOX , 0x6340 ) } , /* MT25408 "Hermon" SDR */
{ PCI_VDEVICE ( MELLANOX , 0x634a ) } , /* MT25408 "Hermon" DDR */
{ PCI_VDEVICE ( MELLANOX , 0x6354 ) } , /* MT25408 "Hermon" QDR */
2007-07-02 18:36:18 +04:00
{ PCI_VDEVICE ( MELLANOX , 0x6732 ) } , /* MT25408 "Hermon" DDR PCIe gen2 */
{ PCI_VDEVICE ( MELLANOX , 0x673c ) } , /* MT25408 "Hermon" QDR PCIe gen2 */
2007-05-09 05:00:38 +04:00
{ 0 , }
} ;
MODULE_DEVICE_TABLE ( pci , mlx4_pci_table ) ;
static struct pci_driver mlx4_driver = {
. name = DRV_NAME ,
. id_table = mlx4_pci_table ,
. probe = mlx4_init_one ,
. remove = __devexit_p ( mlx4_remove_one )
} ;
static int __init mlx4_init ( void )
{
int ret ;
2007-07-12 18:50:45 +04:00
ret = mlx4_catas_init ( ) ;
if ( ret )
return ret ;
2007-05-09 05:00:38 +04:00
ret = pci_register_driver ( & mlx4_driver ) ;
return ret < 0 ? ret : 0 ;
}
static void __exit mlx4_cleanup ( void )
{
pci_unregister_driver ( & mlx4_driver ) ;
2007-07-12 18:50:45 +04:00
mlx4_catas_cleanup ( ) ;
2007-05-09 05:00:38 +04:00
}
module_init ( mlx4_init ) ;
module_exit ( mlx4_cleanup ) ;