📄 mthca_main.c
字号:
/* * Copyright (c) 2004, 2005 Topspin Communications. 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. * * $Id: mthca_main.c 1396 2004-12-28 04:10:27Z roland $ */#include <linux/config.h>#include <linux/version.h>#include <linux/module.h>#include <linux/init.h>#include <linux/errno.h>#include <linux/pci.h>#include <linux/interrupt.h>#include "mthca_dev.h"#include "mthca_config_reg.h"#include "mthca_cmd.h"#include "mthca_profile.h"#include "mthca_memfree.h"MODULE_AUTHOR("Roland Dreier");MODULE_DESCRIPTION("Mellanox InfiniBand HCA low-level driver");MODULE_LICENSE("Dual BSD/GPL");MODULE_VERSION(DRV_VERSION);#ifdef CONFIG_PCI_MSIstatic int msi_x = 0;module_param(msi_x, int, 0444);MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero");static int msi = 0;module_param(msi, int, 0444);MODULE_PARM_DESC(msi, "attempt to use MSI if nonzero");#else /* CONFIG_PCI_MSI */#define msi_x (0)#define msi (0)#endif /* CONFIG_PCI_MSI */static const char mthca_version[] __devinitdata = "ib_mthca: Mellanox InfiniBand HCA driver v" DRV_VERSION " (" DRV_RELDATE ")\n";static struct mthca_profile default_profile = { .num_qp = 1 << 16, .rdb_per_qp = 4, .num_cq = 1 << 16, .num_mcg = 1 << 13, .num_mpt = 1 << 17, .num_mtt = 1 << 20, .num_udav = 1 << 15, /* Tavor only */ .uarc_size = 1 << 18, /* Arbel only */};static int __devinit mthca_tune_pci(struct mthca_dev *mdev){ int cap; u16 val; /* First try to max out Read Byte Count */ cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_PCIX); if (cap) { if (pci_read_config_word(mdev->pdev, cap + PCI_X_CMD, &val)) { mthca_err(mdev, "Couldn't read PCI-X command register, " "aborting.\n"); return -ENODEV; } val = (val & ~PCI_X_CMD_MAX_READ) | (3 << 2); if (pci_write_config_word(mdev->pdev, cap + PCI_X_CMD, val)) { mthca_err(mdev, "Couldn't write PCI-X command register, " "aborting.\n"); return -ENODEV; } } else if (mdev->hca_type == TAVOR) mthca_info(mdev, "No PCI-X capability, not setting RBC.\n"); cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_EXP); if (cap) { if (pci_read_config_word(mdev->pdev, cap + PCI_EXP_DEVCTL, &val)) { mthca_err(mdev, "Couldn't read PCI Express device control " "register, aborting.\n"); return -ENODEV; } val = (val & ~PCI_EXP_DEVCTL_READRQ) | (5 << 12); if (pci_write_config_word(mdev->pdev, cap + PCI_EXP_DEVCTL, val)) { mthca_err(mdev, "Couldn't write PCI Express device control " "register, aborting.\n"); return -ENODEV; } } else if (mdev->hca_type == ARBEL_NATIVE || mdev->hca_type == ARBEL_COMPAT) mthca_info(mdev, "No PCI Express capability, " "not setting Max Read Request Size.\n"); return 0;}static int __devinit mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim *dev_lim){ int err; u8 status; err = mthca_QUERY_DEV_LIM(mdev, dev_lim, &status); if (err) { mthca_err(mdev, "QUERY_DEV_LIM command failed, aborting.\n"); return err; } if (status) { mthca_err(mdev, "QUERY_DEV_LIM returned status 0x%02x, " "aborting.\n", status); return -EINVAL; } if (dev_lim->min_page_sz > PAGE_SIZE) { mthca_err(mdev, "HCA minimum page size of %d bigger than " "kernel PAGE_SIZE of %ld, aborting.\n", dev_lim->min_page_sz, PAGE_SIZE); return -ENODEV; } if (dev_lim->num_ports > MTHCA_MAX_PORTS) { mthca_err(mdev, "HCA has %d ports, but we only support %d, " "aborting.\n", dev_lim->num_ports, MTHCA_MAX_PORTS); return -ENODEV; } mdev->limits.num_ports = dev_lim->num_ports; mdev->limits.vl_cap = dev_lim->max_vl; mdev->limits.mtu_cap = dev_lim->max_mtu; mdev->limits.gid_table_len = dev_lim->max_gids; mdev->limits.pkey_table_len = dev_lim->max_pkeys; mdev->limits.local_ca_ack_delay = dev_lim->local_ca_ack_delay; mdev->limits.max_sg = dev_lim->max_sg; mdev->limits.reserved_qps = dev_lim->reserved_qps; mdev->limits.reserved_srqs = dev_lim->reserved_srqs; mdev->limits.reserved_eecs = dev_lim->reserved_eecs; mdev->limits.reserved_cqs = dev_lim->reserved_cqs; mdev->limits.reserved_eqs = dev_lim->reserved_eqs; mdev->limits.reserved_mtts = dev_lim->reserved_mtts; mdev->limits.reserved_mrws = dev_lim->reserved_mrws; mdev->limits.reserved_uars = dev_lim->reserved_uars; mdev->limits.reserved_pds = dev_lim->reserved_pds; if (dev_lim->flags & DEV_LIM_FLAG_SRQ) mdev->mthca_flags |= MTHCA_FLAG_SRQ; return 0;}static int __devinit mthca_init_tavor(struct mthca_dev *mdev){ u8 status; int err; struct mthca_dev_lim dev_lim; struct mthca_profile profile; struct mthca_init_hca_param init_hca; struct mthca_adapter adapter; err = mthca_SYS_EN(mdev, &status); if (err) { mthca_err(mdev, "SYS_EN command failed, aborting.\n"); return err; } if (status) { mthca_err(mdev, "SYS_EN returned status 0x%02x, " "aborting.\n", status); return -EINVAL; } err = mthca_QUERY_FW(mdev, &status); if (err) { mthca_err(mdev, "QUERY_FW command failed, aborting.\n"); goto err_disable; } if (status) { mthca_err(mdev, "QUERY_FW returned status 0x%02x, " "aborting.\n", status); err = -EINVAL; goto err_disable; } err = mthca_QUERY_DDR(mdev, &status); if (err) { mthca_err(mdev, "QUERY_DDR command failed, aborting.\n"); goto err_disable; } if (status) { mthca_err(mdev, "QUERY_DDR returned status 0x%02x, " "aborting.\n", status); err = -EINVAL; goto err_disable; } err = mthca_dev_lim(mdev, &dev_lim); profile = default_profile; profile.num_uar = dev_lim.uar_size / PAGE_SIZE; profile.uarc_size = 0; err = mthca_make_profile(mdev, &profile, &dev_lim, &init_hca); if (err < 0) goto err_disable; err = mthca_INIT_HCA(mdev, &init_hca, &status); if (err) { mthca_err(mdev, "INIT_HCA command failed, aborting.\n"); goto err_disable; } if (status) { mthca_err(mdev, "INIT_HCA returned status 0x%02x, " "aborting.\n", status); err = -EINVAL; goto err_disable; } err = mthca_QUERY_ADAPTER(mdev, &adapter, &status); if (err) { mthca_err(mdev, "QUERY_ADAPTER command failed, aborting.\n"); goto err_close; } if (status) { mthca_err(mdev, "QUERY_ADAPTER returned status 0x%02x, " "aborting.\n", status); err = -EINVAL; goto err_close; } mdev->eq_table.inta_pin = adapter.inta_pin; mdev->rev_id = adapter.revision_id; return 0;err_close: mthca_CLOSE_HCA(mdev, 0, &status);err_disable: mthca_SYS_DIS(mdev, &status); return err;}static int __devinit mthca_load_fw(struct mthca_dev *mdev){ u8 status; int err; /* FIXME: use HCA-attached memory for FW if present */ mdev->fw.arbel.fw_icm = mthca_alloc_icm(mdev, mdev->fw.arbel.fw_pages, GFP_HIGHUSER | __GFP_NOWARN); if (!mdev->fw.arbel.fw_icm) { mthca_err(mdev, "Couldn't allocate FW area, aborting.\n"); return -ENOMEM; } err = mthca_MAP_FA(mdev, mdev->fw.arbel.fw_icm, &status); if (err) { mthca_err(mdev, "MAP_FA command failed, aborting.\n"); goto err_free; } if (status) { mthca_err(mdev, "MAP_FA returned status 0x%02x, aborting.\n", status); err = -EINVAL; goto err_free; } err = mthca_RUN_FW(mdev, &status); if (err) { mthca_err(mdev, "RUN_FW command failed, aborting.\n"); goto err_unmap_fa; } if (status) { mthca_err(mdev, "RUN_FW returned status 0x%02x, aborting.\n", status); err = -EINVAL; goto err_unmap_fa; } return 0;err_unmap_fa: mthca_UNMAP_FA(mdev, &status);err_free: mthca_free_icm(mdev, mdev->fw.arbel.fw_icm); return err;}static int __devinit mthca_init_icm(struct mthca_dev *mdev, struct mthca_dev_lim *dev_lim, struct mthca_init_hca_param *init_hca, u64 icm_size){ u64 aux_pages; u8 status; int err; err = mthca_SET_ICM_SIZE(mdev, icm_size, &aux_pages, &status); if (err) { mthca_err(mdev, "SET_ICM_SIZE command failed, aborting.\n"); return err; } if (status) { mthca_err(mdev, "SET_ICM_SIZE returned status 0x%02x, " "aborting.\n", status); return -EINVAL; } mthca_dbg(mdev, "%lld KB of HCA context requires %lld KB aux memory.\n", (unsigned long long) icm_size >> 10, (unsigned long long) aux_pages << 2); mdev->fw.arbel.aux_icm = mthca_alloc_icm(mdev, aux_pages, GFP_HIGHUSER | __GFP_NOWARN); if (!mdev->fw.arbel.aux_icm) { mthca_err(mdev, "Couldn't allocate aux memory, aborting.\n"); return -ENOMEM; } err = mthca_MAP_ICM_AUX(mdev, mdev->fw.arbel.aux_icm, &status); if (err) { mthca_err(mdev, "MAP_ICM_AUX command failed, aborting.\n"); goto err_free_aux; } if (status) { mthca_err(mdev, "MAP_ICM_AUX returned status 0x%02x, aborting.\n", status); err = -EINVAL; goto err_free_aux; } err = mthca_map_eq_icm(mdev, init_hca->eqc_base); if (err) { mthca_err(mdev, "Failed to map EQ context memory, aborting.\n"); goto err_unmap_aux; } mdev->mr_table.mtt_table = mthca_alloc_icm_table(mdev, init_hca->mtt_base, mdev->limits.num_mtt_segs * init_hca->mtt_seg_sz, mdev->limits.reserved_mtts * init_hca->mtt_seg_sz, 1); if (!mdev->mr_table.mtt_table) { mthca_err(mdev, "Failed to map MTT context memory, aborting.\n"); err = -ENOMEM; goto err_unmap_eq; } mdev->mr_table.mpt_table = mthca_alloc_icm_table(mdev, init_hca->mpt_base, mdev->limits.num_mpts * dev_lim->mpt_entry_sz, mdev->limits.reserved_mrws * dev_lim->mpt_entry_sz, 1); if (!mdev->mr_table.mpt_table) { mthca_err(mdev, "Failed to map MPT context memory, aborting.\n"); err = -ENOMEM; goto err_unmap_mtt; } mdev->qp_table.qp_table = mthca_alloc_icm_table(mdev, init_hca->qpc_base, mdev->limits.num_qps * dev_lim->qpc_entry_sz, mdev->limits.reserved_qps * dev_lim->qpc_entry_sz, 1); if (!mdev->qp_table.qp_table) { mthca_err(mdev, "Failed to map QP context memory, aborting.\n"); err = -ENOMEM; goto err_unmap_mpt; } mdev->qp_table.eqp_table = mthca_alloc_icm_table(mdev, init_hca->eqpc_base, mdev->limits.num_qps * dev_lim->eqpc_entry_sz, mdev->limits.reserved_qps * dev_lim->eqpc_entry_sz, 1); if (!mdev->qp_table.eqp_table) { mthca_err(mdev, "Failed to map EQP context memory, aborting.\n"); err = -ENOMEM; goto err_unmap_qp; } mdev->cq_table.table = mthca_alloc_icm_table(mdev, init_hca->cqc_base, mdev->limits.num_cqs * dev_lim->cqc_entry_sz, mdev->limits.reserved_cqs * dev_lim->cqc_entry_sz, 1); if (!mdev->cq_table.table) { mthca_err(mdev, "Failed to map CQ context memory, aborting.\n"); err = -ENOMEM; goto err_unmap_eqp; } return 0;err_unmap_eqp: mthca_free_icm_table(mdev, mdev->qp_table.eqp_table);err_unmap_qp: mthca_free_icm_table(mdev, mdev->qp_table.qp_table);err_unmap_mpt: mthca_free_icm_table(mdev, mdev->mr_table.mpt_table);err_unmap_mtt: mthca_free_icm_table(mdev, mdev->mr_table.mtt_table);err_unmap_eq: mthca_unmap_eq_icm(mdev);err_unmap_aux: mthca_UNMAP_ICM_AUX(mdev, &status);err_free_aux: mthca_free_icm(mdev, mdev->fw.arbel.aux_icm); return err;}static int __devinit mthca_init_arbel(struct mthca_dev *mdev){ struct mthca_dev_lim dev_lim; struct mthca_profile profile; struct mthca_init_hca_param init_hca; struct mthca_adapter adapter; u64 icm_size; u8 status; int err; err = mthca_QUERY_FW(mdev, &status); if (err) { mthca_err(mdev, "QUERY_FW command failed, aborting.\n"); return err; } if (status) { mthca_err(mdev, "QUERY_FW returned status 0x%02x, " "aborting.\n", status); return -EINVAL; } err = mthca_ENABLE_LAM(mdev, &status); if (err) { mthca_err(mdev, "ENABLE_LAM command failed, aborting.\n"); return err; } if (status == MTHCA_CMD_STAT_LAM_NOT_PRE) { mthca_dbg(mdev, "No HCA-attached memory (running in MemFree mode)\n"); mdev->mthca_flags |= MTHCA_FLAG_NO_LAM; } else if (status) { mthca_err(mdev, "ENABLE_LAM returned status 0x%02x, " "aborting.\n", status); return -EINVAL; } err = mthca_load_fw(mdev); if (err) { mthca_err(mdev, "Failed to start FW, aborting.\n"); goto err_disable; } err = mthca_dev_lim(mdev, &dev_lim); if (err) { mthca_err(mdev, "QUERY_DEV_LIM command failed, aborting.\n"); goto err_stop_fw; } profile = default_profile; profile.num_uar = dev_lim.uar_size / PAGE_SIZE; profile.num_udav = 0; icm_size = mthca_make_profile(mdev, &profile, &dev_lim, &init_hca); if ((int) icm_size < 0) { err = icm_size; goto err_stop_fw; } err = mthca_init_icm(mdev, &dev_lim, &init_hca, icm_size); if (err) goto err_stop_fw; err = mthca_INIT_HCA(mdev, &init_hca, &status); if (err) { mthca_err(mdev, "INIT_HCA command failed, aborting.\n"); goto err_free_icm; } if (status) { mthca_err(mdev, "INIT_HCA returned status 0x%02x, " "aborting.\n", status); err = -EINVAL; goto err_free_icm; } err = mthca_QUERY_ADAPTER(mdev, &adapter, &status); if (err) { mthca_err(mdev, "QUERY_ADAPTER command failed, aborting.\n"); goto err_free_icm; } if (status) { mthca_err(mdev, "QUERY_ADAPTER returned status 0x%02x, " "aborting.\n", status); err = -EINVAL; goto err_free_icm; } mdev->eq_table.inta_pin = adapter.inta_pin; mdev->rev_id = adapter.revision_id; return 0;err_free_icm: mthca_free_icm_table(mdev, mdev->cq_table.table); mthca_free_icm_table(mdev, mdev->qp_table.eqp_table); mthca_free_icm_table(mdev, mdev->qp_table.qp_table); mthca_free_icm_table(mdev, mdev->mr_table.mpt_table); mthca_free_icm_table(mdev, mdev->mr_table.mtt_table); mthca_unmap_eq_icm(mdev); mthca_UNMAP_ICM_AUX(mdev, &status); mthca_free_icm(mdev, mdev->fw.arbel.aux_icm);err_stop_fw: mthca_UNMAP_FA(mdev, &status); mthca_free_icm(mdev, mdev->fw.arbel.fw_icm);err_disable: if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM)) mthca_DISABLE_LAM(mdev, &status); return err;}static int __devinit mthca_init_hca(struct mthca_dev *mdev){ if (mdev->hca_type == ARBEL_NATIVE) return mthca_init_arbel(mdev); else return mthca_init_tavor(mdev);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -