main.c

来自「linux 内核源代码」· C语言 代码 · 共 972 行 · 第 1/2 页

C
972
字号
/* * 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_DEBUGint 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_MSIstatic int msi_x = 1;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 */static const char mlx4_version[] __devinitdata =	DRV_NAME ": Mellanox ConnectX core driver v"	DRV_VERSION " (" DRV_RELDATE ")\n";static struct mlx4_profile default_profile = {	.num_qp		= 1 << 16,	.num_srq	= 1 << 16,	.rdmarc_per_qp	= 1 << 4,	.num_cq		= 1 << 16,	.num_mcg	= 1 << 13,	.num_mpt	= 1 << 17,	.num_mtt	= 1 << 20,};static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap){	int err;	int i;	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;	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];	}	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;	dev->caps.reserved_mtts	     = DIV_ROUND_UP(dev_cap->reserved_mtts,						    MLX4_MTT_ENTRY_PER_SEG);	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;	dev->caps.max_msg_sz         = dev_cap->max_msg_sz;	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;	return 0;}static int __devinit mlx4_load_fw(struct mlx4_dev *dev){	struct mlx4_priv *priv = mlx4_priv(dev);	int err;	priv->fw.fw_icm = mlx4_alloc_icm(dev, priv->fw.fw_pages,					 GFP_HIGHUSER | __GFP_NOWARN, 0);	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:	mlx4_free_icm(dev, priv->fw.fw_icm, 0);	return err;}static int __devinit mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base,					  int cmpt_entry_sz){	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,				  dev->caps.reserved_qps, 0, 0);	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,				  dev->caps.reserved_srqs, 0, 0);	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,				  dev->caps.reserved_cqs, 0, 0);	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),				  MLX4_NUM_EQ + dev->caps.reserved_eqs, 0, 0);	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;}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){	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,					  GFP_HIGHUSER | __GFP_NOWARN, 0);	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;	}	/*	 * 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;	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,				  dev->caps.reserved_mtts, 1, 0);	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,				  dev->caps.reserved_mrws, 1, 1);	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,				  dev->caps.reserved_qps, 0, 0);	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,				  dev->caps.reserved_qps, 0, 0);	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,				  dev->caps.reserved_qps, 0, 0);	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,				  dev->caps.reserved_qps, 0, 0);	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,				  dev->caps.reserved_cqs, 0, 0);	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,				  dev->caps.reserved_srqs, 0, 0);	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,				  0, 0);	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:	mlx4_free_icm(dev, priv->fw.aux_icm, 0);	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);	mlx4_free_icm(dev, priv->fw.aux_icm, 0);}static void mlx4_close_hca(struct mlx4_dev *dev){	mlx4_CLOSE_HCA(dev, 0);	mlx4_free_icms(dev);	mlx4_UNMAP_FA(dev);	mlx4_free_icm(dev, mlx4_priv(dev)->fw.fw_icm, 0);}static int mlx4_init_hca(struct mlx4_dev *dev){	struct mlx4_priv	  *priv = mlx4_priv(dev);	struct mlx4_adapter	   adapter;	struct mlx4_dev_cap	   dev_cap;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?