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 .
2008-07-25 21:32:52 +04:00
* Copyright ( c ) 2005 , 2006 , 2007 , 2008 Mellanox Technologies . All rights reserved .
2007-05-09 05:00:38 +04:00
* 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 ,
} ;
2008-10-22 21:25:29 +04:00
static int log_num_mac = 2 ;
module_param_named ( log_num_mac , log_num_mac , int , 0444 ) ;
MODULE_PARM_DESC ( log_num_mac , " Log2 max number of MACs per ETH port (1-7) " ) ;
static int log_num_vlan ;
module_param_named ( log_num_vlan , log_num_vlan , int , 0444 ) ;
MODULE_PARM_DESC ( log_num_vlan , " Log2 max number of VLANs per ETH port (0-7) " ) ;
static int use_prio ;
module_param_named ( use_prio , use_prio , bool , 0444 ) ;
MODULE_PARM_DESC ( use_prio , " Enable steering by VLAN priority on ETH ports "
" (0/1, default 0) " ) ;
2008-10-23 02:38:42 +04:00
static int mlx4_check_port_params ( struct mlx4_dev * dev ,
enum mlx4_port_type * port_type )
{
int i ;
for ( i = 0 ; i < dev - > caps . num_ports - 1 ; i + + ) {
if ( port_type [ i ] ! = port_type [ i + 1 ] & &
! ( dev - > caps . flags & MLX4_DEV_CAP_FLAG_DPDP ) ) {
mlx4_err ( dev , " Only same port types supported "
" on this HCA, aborting. \n " ) ;
return - EINVAL ;
}
}
if ( ( port_type [ 0 ] = = MLX4_PORT_TYPE_ETH ) & &
( port_type [ 1 ] = = MLX4_PORT_TYPE_IB ) ) {
mlx4_err ( dev , " eth-ib configuration is not supported. \n " ) ;
return - EINVAL ;
}
for ( i = 0 ; i < dev - > caps . num_ports ; i + + ) {
if ( ! ( port_type [ i ] & dev - > caps . supported_type [ i + 1 ] ) ) {
mlx4_err ( dev , " Requested port type for port %d is not "
" supported on this HCA \n " , i + 1 ) ;
return - EINVAL ;
}
}
return 0 ;
}
static void mlx4_set_port_mask ( struct mlx4_dev * dev )
{
int i ;
dev - > caps . port_mask = 0 ;
for ( i = 1 ; i < = dev - > caps . num_ports ; + + i )
if ( dev - > caps . port_type [ i ] = = MLX4_PORT_TYPE_IB )
dev - > caps . port_mask | = 1 < < ( i - 1 ) ;
}
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 ] ;
2008-10-22 21:56:48 +04:00
dev - > caps . ib_mtu_cap [ i ] = dev_cap - > ib_mtu [ i ] ;
2007-06-18 19:15:02 +04:00
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 ] ;
2008-10-22 21:56:48 +04:00
dev - > caps . eth_mtu_cap [ i ] = dev_cap - > eth_mtu [ i ] ;
dev - > caps . def_mac [ i ] = dev_cap - > def_mac [ i ] ;
2008-10-23 02:38:42 +04:00
dev - > caps . supported_type [ i ] = dev_cap - > supported_port_types [ i ] ;
2007-06-18 19:15:02 +04:00
}
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 . 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 ;
2008-07-23 19:12:26 +04:00
dev - > caps . bmme_flags = dev_cap - > bmme_flags ;
dev - > caps . reserved_lkey = dev_cap - > reserved_lkey ;
2007-05-09 05:00:38 +04:00
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
2008-10-22 21:25:29 +04:00
dev - > caps . log_num_macs = log_num_mac ;
dev - > caps . log_num_vlans = log_num_vlan ;
dev - > caps . log_num_prios = use_prio ? 3 : 0 ;
for ( i = 1 ; i < = dev - > caps . num_ports ; + + i ) {
2008-10-23 02:38:42 +04:00
if ( dev - > caps . supported_type [ i ] ! = MLX4_PORT_TYPE_ETH )
dev - > caps . port_type [ i ] = MLX4_PORT_TYPE_IB ;
else
dev - > caps . port_type [ i ] = MLX4_PORT_TYPE_ETH ;
2008-10-22 21:25:29 +04:00
if ( dev - > caps . log_num_macs > dev_cap - > log_max_macs [ i ] ) {
dev - > caps . log_num_macs = dev_cap - > log_max_macs [ i ] ;
mlx4_warn ( dev , " Requested number of MACs is too much "
" for port %d, reducing to %d. \n " ,
i , 1 < < dev - > caps . log_num_macs ) ;
}
if ( dev - > caps . log_num_vlans > dev_cap - > log_max_vlans [ i ] ) {
dev - > caps . log_num_vlans = dev_cap - > log_max_vlans [ i ] ;
mlx4_warn ( dev , " Requested number of VLANs is too much "
" for port %d, reducing to %d. \n " ,
i , 1 < < dev - > caps . log_num_vlans ) ;
}
}
2008-10-23 02:38:42 +04:00
mlx4_set_port_mask ( dev ) ;
2008-10-22 21:25:29 +04:00
dev - > caps . reserved_qps_cnt [ MLX4_QP_REGION_FW ] = dev_cap - > reserved_qps ;
dev - > caps . reserved_qps_cnt [ MLX4_QP_REGION_ETH_ADDR ] =
dev - > caps . reserved_qps_cnt [ MLX4_QP_REGION_FC_ADDR ] =
( 1 < < dev - > caps . log_num_macs ) *
( 1 < < dev - > caps . log_num_vlans ) *
( 1 < < dev - > caps . log_num_prios ) *
dev - > caps . num_ports ;
dev - > caps . reserved_qps_cnt [ MLX4_QP_REGION_FC_EXCH ] = MLX4_NUM_FEXCH ;
dev - > caps . reserved_qps = dev - > caps . reserved_qps_cnt [ MLX4_QP_REGION_FW ] +
dev - > caps . reserved_qps_cnt [ MLX4_QP_REGION_ETH_ADDR ] +
dev - > caps . reserved_qps_cnt [ MLX4_QP_REGION_FC_ADDR ] +
dev - > caps . reserved_qps_cnt [ MLX4_QP_REGION_FC_EXCH ] ;
2007-05-09 05:00:38 +04:00
return 0 ;
}
2008-10-23 02:38:42 +04:00
/*
* Change the port configuration of the device .
* Every user of this function must hold the port mutex .
*/
static int mlx4_change_port_types ( struct mlx4_dev * dev ,
enum mlx4_port_type * port_types )
{
int err = 0 ;
int change = 0 ;
int port ;
for ( port = 0 ; port < dev - > caps . num_ports ; port + + ) {
if ( port_types [ port ] ! = dev - > caps . port_type [ port + 1 ] ) {
change = 1 ;
dev - > caps . port_type [ port + 1 ] = port_types [ port ] ;
}
}
if ( change ) {
mlx4_unregister_device ( dev ) ;
for ( port = 1 ; port < = dev - > caps . num_ports ; port + + ) {
mlx4_CLOSE_PORT ( dev , port ) ;
err = mlx4_SET_PORT ( dev , port ) ;
if ( err ) {
mlx4_err ( dev , " Failed to set port %d, "
" aborting \n " , port ) ;
goto out ;
}
}
mlx4_set_port_mask ( dev ) ;
err = mlx4_register_device ( dev ) ;
}
out :
return err ;
}
static ssize_t show_port_type ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct mlx4_port_info * info = container_of ( attr , struct mlx4_port_info ,
port_attr ) ;
struct mlx4_dev * mdev = info - > dev ;
return sprintf ( buf , " %s \n " ,
mdev - > caps . port_type [ info - > port ] = = MLX4_PORT_TYPE_IB ?
" ib " : " eth " ) ;
}
static ssize_t set_port_type ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t count )
{
struct mlx4_port_info * info = container_of ( attr , struct mlx4_port_info ,
port_attr ) ;
struct mlx4_dev * mdev = info - > dev ;
struct mlx4_priv * priv = mlx4_priv ( mdev ) ;
enum mlx4_port_type types [ MLX4_MAX_PORTS ] ;
int i ;
int err = 0 ;
if ( ! strcmp ( buf , " ib \n " ) )
info - > tmp_type = MLX4_PORT_TYPE_IB ;
else if ( ! strcmp ( buf , " eth \n " ) )
info - > tmp_type = MLX4_PORT_TYPE_ETH ;
else {
mlx4_err ( mdev , " %s is not supported port type \n " , buf ) ;
return - EINVAL ;
}
mutex_lock ( & priv - > port_mutex ) ;
for ( i = 0 ; i < mdev - > caps . num_ports ; i + + )
types [ i ] = priv - > port [ i + 1 ] . tmp_type ? priv - > port [ i + 1 ] . tmp_type :
mdev - > caps . port_type [ i + 1 ] ;
err = mlx4_check_port_params ( mdev , types ) ;
if ( err )
goto out ;
for ( i = 1 ; i < = mdev - > caps . num_ports ; i + + )
priv - > port [ i ] . tmp_type = 0 ;
err = mlx4_change_port_types ( mdev , types ) ;
out :
mutex_unlock ( & priv - > port_mutex ) ;
return err ? err : count ;
}
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 ,
2008-10-22 21:25:29 +04:00
dev - > caps . reserved_qps_cnt [ MLX4_QP_REGION_FW ] ,
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 ,
2008-12-22 18:15:03 +03:00
dev - > caps . num_eqs , dev - > caps . num_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 ,
2008-10-22 21:25:29 +04:00
dev - > caps . reserved_qps_cnt [ MLX4_QP_REGION_FW ] ,
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 ,
2008-10-22 21:25:29 +04:00
dev - > caps . reserved_qps_cnt [ MLX4_QP_REGION_FW ] ,
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 ,
2008-10-22 21:25:29 +04:00
dev - > caps . reserved_qps_cnt [ MLX4_QP_REGION_FW ] ,
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 ,
2008-10-22 21:25:29 +04:00
dev - > caps . reserved_qps_cnt [ MLX4_QP_REGION_FW ] ,
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 ;
2008-07-15 10:48:53 +04:00
struct mlx4_mod_stat_cfg mlx4_cfg ;
2007-05-09 05:00:38 +04:00
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 ;
}
2008-07-15 10:48:53 +04:00
mlx4_cfg . log_pg_sz_m = 1 ;
mlx4_cfg . log_pg_sz = 0 ;
err = mlx4_MOD_STAT_CFG ( dev , & mlx4_cfg ) ;
if ( err )
mlx4_warn ( dev , " Failed to override log_pg_sz parameter \n " ) ;
2007-05-09 05:00:38 +04:00
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 ;
2008-10-23 02:38:42 +04:00
int port ;
2008-11-29 08:29:46 +03:00
__be32 ib_port_default_caps ;
2007-05-09 05:00:38 +04:00
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 " ,
2008-12-22 18:15:03 +03:00
priv - > eq_table . eq [ dev - > caps . num_comp_vectors ] . irq ) ;
2007-08-07 17:08:28 +04:00
mlx4_warn ( dev , " Trying again without MSI-X. \n " ) ;
} else {
mlx4_err ( dev , " NOP command failed to generate interrupt "
" (IRQ %d), aborting. \n " ,
2008-12-22 18:15:03 +03:00
priv - > eq_table . eq [ dev - > caps . num_comp_vectors ] . 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 ;
}
2008-10-23 02:38:42 +04:00
for ( port = 1 ; port < = dev - > caps . num_ports ; port + + ) {
2008-11-29 08:29:46 +03:00
ib_port_default_caps = 0 ;
err = mlx4_get_port_ib_caps ( dev , port , & ib_port_default_caps ) ;
if ( err )
mlx4_warn ( dev , " failed to get port %d default "
" ib capabilities (%d). Continuing with "
" caps = 0 \n " , port , err ) ;
dev - > caps . ib_port_def_cap [ port ] = ib_port_default_caps ;
2008-10-23 02:38:42 +04:00
err = mlx4_SET_PORT ( dev , port ) ;
if ( err ) {
mlx4_err ( dev , " Failed to set port %d, aborting \n " ,
port ) ;
goto err_mcg_table_free ;
}
}
2007-05-09 05:00:38 +04:00
return 0 ;
2008-10-23 02:38:42 +04:00
err_mcg_table_free :
mlx4_cleanup_mcg_table ( dev ) ;
2007-05-09 05:00:38 +04:00
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 ) ;
2008-12-22 18:15:03 +03:00
struct msix_entry * entries ;
int nreq ;
2007-05-09 05:00:38 +04:00
int err ;
int i ;
if ( msi_x ) {
2009-01-10 00:14:07 +03:00
nreq = min_t ( int , dev - > caps . num_eqs - dev - > caps . reserved_eqs ,
num_possible_cpus ( ) + 1 ) ;
2008-12-22 18:15:03 +03:00
entries = kcalloc ( nreq , sizeof * entries , GFP_KERNEL ) ;
if ( ! entries )
goto no_msi ;
for ( i = 0 ; i < nreq ; + + i )
2007-05-09 05:00:38 +04:00
entries [ i ] . entry = i ;
2008-12-22 18:15:03 +03:00
retry :
err = pci_enable_msix ( dev - > pdev , entries , nreq ) ;
2007-05-09 05:00:38 +04:00
if ( err ) {
2008-12-22 18:15:03 +03:00
/* Try again if at least 2 vectors are available */
if ( err > 1 ) {
mlx4_info ( dev , " Requested %d vectors, "
" but only %d MSI-X vectors available, "
" trying again \n " , nreq , err ) ;
nreq = err ;
goto retry ;
}
2007-05-09 05:00:38 +04:00
goto no_msi ;
}
2008-12-22 18:15:03 +03:00
dev - > caps . num_comp_vectors = nreq - 1 ;
for ( i = 0 ; i < nreq ; + + i )
2007-05-09 05:00:38 +04:00
priv - > eq_table . eq [ i ] . irq = entries [ i ] . vector ;
dev - > flags | = MLX4_FLAG_MSI_X ;
2008-12-22 18:15:03 +03:00
kfree ( entries ) ;
2007-05-09 05:00:38 +04:00
return ;
}
no_msi :
2008-12-22 18:15:03 +03:00
dev - > caps . num_comp_vectors = 1 ;
for ( i = 0 ; i < 2 ; + + i )
2007-05-09 05:00:38 +04:00
priv - > eq_table . eq [ i ] . irq = dev - > pdev - > irq ;
}
2008-10-23 02:38:42 +04:00
static int mlx4_init_port_info ( struct mlx4_dev * dev , int port )
2008-10-22 22:44:46 +04:00
{
struct mlx4_port_info * info = & mlx4_priv ( dev ) - > port [ port ] ;
2008-10-23 02:38:42 +04:00
int err = 0 ;
2008-10-22 22:44:46 +04:00
info - > dev = dev ;
info - > port = port ;
mlx4_init_mac_table ( dev , & info - > mac_table ) ;
mlx4_init_vlan_table ( dev , & info - > vlan_table ) ;
2008-10-23 02:38:42 +04:00
sprintf ( info - > dev_name , " mlx4_port%d " , port ) ;
info - > port_attr . attr . name = info - > dev_name ;
info - > port_attr . attr . mode = S_IRUGO | S_IWUSR ;
info - > port_attr . show = show_port_type ;
info - > port_attr . store = set_port_type ;
err = device_create_file ( & dev - > pdev - > dev , & info - > port_attr ) ;
if ( err ) {
mlx4_err ( dev , " Failed to create file for port %d \n " , port ) ;
info - > port = - 1 ;
}
return err ;
}
static void mlx4_cleanup_port_info ( struct mlx4_port_info * info )
{
if ( info - > port < 0 )
return ;
device_remove_file ( & info - > dev - > pdev - > dev , & info - > port_attr ) ;
2008-10-22 22:44:46 +04:00
}
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 ;
2008-10-22 22:44:46 +04:00
int port ;
2007-05-09 05:00:38 +04:00
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
2008-10-23 02:38:42 +04:00
mutex_init ( & priv - > port_mutex ) ;
2008-04-23 22:55:45 +04:00
INIT_LIST_HEAD ( & priv - > pgdir_list ) ;
mutex_init ( & priv - > pgdir_mutex ) ;
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 ;
2008-12-22 18:15:03 +03:00
err = mlx4_alloc_eq_table ( dev ) ;
if ( err )
goto err_close ;
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 )
2008-12-22 18:15:03 +03:00
goto err_free_eq ;
2007-05-09 05:00:38 +04:00
2008-10-23 02:38:42 +04:00
for ( port = 1 ; port < = dev - > caps . num_ports ; port + + ) {
err = mlx4_init_port_info ( dev , port ) ;
if ( err )
goto err_port ;
}
2008-10-22 22:44:46 +04:00
2007-05-09 05:00:38 +04:00
err = mlx4_register_device ( dev ) ;
if ( err )
2008-10-23 02:38:42 +04:00
goto err_port ;
2007-05-09 05:00:38 +04:00
pci_set_drvdata ( pdev , dev ) ;
return 0 ;
2008-10-23 02:38:42 +04:00
err_port :
for ( port = 1 ; port < = dev - > caps . num_ports ; port + + )
mlx4_cleanup_port_info ( & priv - > port [ port ] ) ;
2007-05-09 05:00:38 +04:00
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 ) ;
2008-12-22 18:15:03 +03:00
err_free_eq :
mlx4_free_eq_table ( dev ) ;
2007-05-09 05:00:38 +04:00
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 ) ;
2008-10-23 02:38:42 +04:00
for ( p = 1 ; p < = dev - > caps . num_ports ; p + + ) {
mlx4_cleanup_port_info ( & priv - > port [ p ] ) ;
2007-05-09 05:00:38 +04:00
mlx4_CLOSE_PORT ( dev , p ) ;
2008-10-23 02:38:42 +04:00
}
2007-05-09 05:00:38 +04:00
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 ) ;
2008-12-22 18:15:03 +03:00
mlx4_free_eq_table ( dev ) ;
2007-05-09 05:00:38 +04:00
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 */
2008-10-23 02:48:03 +04:00
{ PCI_VDEVICE ( MELLANOX , 0x6368 ) } , /* MT25408 "Hermon" EN 10GigE */
{ PCI_VDEVICE ( MELLANOX , 0x6750 ) } , /* MT25408 "Hermon" EN 10GigE PCIe gen2 */
2009-02-27 21:29:13 +03:00
{ PCI_VDEVICE ( MELLANOX , 0x6372 ) } , /* MT25458 ConnectX EN 10GBASE-T 10GigE */
{ PCI_VDEVICE ( MELLANOX , 0x675a ) } , /* MT25458 ConnectX EN 10GBASE-T+Gen2 10GigE */
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 )
} ;
2008-10-23 02:38:42 +04:00
static int __init mlx4_verify_params ( void )
{
if ( ( log_num_mac < 0 ) | | ( log_num_mac > 7 ) ) {
printk ( KERN_WARNING " mlx4_core: bad num_mac: %d \n " , log_num_mac ) ;
return - 1 ;
}
if ( ( log_num_vlan < 0 ) | | ( log_num_vlan > 7 ) ) {
printk ( KERN_WARNING " mlx4_core: bad num_vlan: %d \n " , log_num_vlan ) ;
return - 1 ;
}
return 0 ;
}
2007-05-09 05:00:38 +04:00
static int __init mlx4_init ( void )
{
int ret ;
2008-10-23 02:38:42 +04:00
if ( mlx4_verify_params ( ) )
return - EINVAL ;
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 ) ;