📄 mthca_main.c
字号:
static int __devinit mthca_setup_hca(struct mthca_dev *dev){ int err; u8 status; MTHCA_INIT_DOORBELL_LOCK(&dev->doorbell_lock); err = mthca_init_pd_table(dev); if (err) { mthca_err(dev, "Failed to initialize " "protection domain table, aborting.\n"); return err; } err = mthca_init_mr_table(dev); if (err) { mthca_err(dev, "Failed to initialize " "memory region table, aborting.\n"); goto err_pd_table_free; } err = mthca_pd_alloc(dev, &dev->driver_pd); if (err) { mthca_err(dev, "Failed to create driver PD, " "aborting.\n"); goto err_mr_table_free; } if (dev->hca_type == ARBEL_NATIVE) { mthca_warn(dev, "Sorry, native MT25208 mode support is not done, " "aborting.\n"); err = -ENODEV; goto err_pd_free; } err = mthca_init_eq_table(dev); if (err) { mthca_err(dev, "Failed to initialize " "event queue table, aborting.\n"); goto err_pd_free; } err = mthca_cmd_use_events(dev); if (err) { mthca_err(dev, "Failed to switch to event-driven " "firmware commands, aborting.\n"); goto err_eq_table_free; } err = mthca_NOP(dev, &status); if (err || status) { mthca_err(dev, "NOP command failed to generate interrupt, aborting.\n"); if (dev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X)) mthca_err(dev, "Try again with MSI/MSI-X disabled.\n"); else mthca_err(dev, "BIOS or ACPI interrupt routing problem?\n"); goto err_cmd_poll; } else mthca_dbg(dev, "NOP command IRQ test passed\n"); err = mthca_init_cq_table(dev); if (err) { mthca_err(dev, "Failed to initialize " "completion queue table, aborting.\n"); goto err_cmd_poll; } err = mthca_init_qp_table(dev); if (err) { mthca_err(dev, "Failed to initialize " "queue pair table, aborting.\n"); goto err_cq_table_free; } err = mthca_init_av_table(dev); if (err) { mthca_err(dev, "Failed to initialize " "address vector table, aborting.\n"); goto err_qp_table_free; } err = mthca_init_mcg_table(dev); if (err) { mthca_err(dev, "Failed to initialize " "multicast group table, aborting.\n"); goto err_av_table_free; } return 0;err_av_table_free: mthca_cleanup_av_table(dev);err_qp_table_free: mthca_cleanup_qp_table(dev);err_cq_table_free: mthca_cleanup_cq_table(dev);err_cmd_poll: mthca_cmd_use_polling(dev);err_eq_table_free: mthca_cleanup_eq_table(dev);err_pd_free: mthca_pd_free(dev, &dev->driver_pd);err_mr_table_free: mthca_cleanup_mr_table(dev);err_pd_table_free: mthca_cleanup_pd_table(dev); return err;}static int __devinit mthca_request_regions(struct pci_dev *pdev, int ddr_hidden){ int err; /* * We request our first BAR in two chunks, since the MSI-X * vector table is right in the middle. * * This is why we can't just use pci_request_regions() -- if * we did then setting up MSI-X would fail, since the PCI core * wants to do request_mem_region on the MSI-X vector table. */ if (!request_mem_region(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE, MTHCA_HCR_SIZE, DRV_NAME)) { err = -EBUSY; goto err_hcr_failed; } if (!request_mem_region(pci_resource_start(pdev, 0) + MTHCA_ECR_BASE, MTHCA_MAP_ECR_SIZE, DRV_NAME)) { err = -EBUSY; goto err_ecr_failed; } if (!request_mem_region(pci_resource_start(pdev, 0) + MTHCA_CLR_INT_BASE, MTHCA_CLR_INT_SIZE, DRV_NAME)) { err = -EBUSY; goto err_int_failed; } err = pci_request_region(pdev, 2, DRV_NAME); if (err) goto err_bar2_failed; if (!ddr_hidden) { err = pci_request_region(pdev, 4, DRV_NAME); if (err) goto err_bar4_failed; } return 0;err_bar4_failed: pci_release_region(pdev, 2);err_bar2_failed: release_mem_region(pci_resource_start(pdev, 0) + MTHCA_CLR_INT_BASE, MTHCA_CLR_INT_SIZE);err_int_failed: release_mem_region(pci_resource_start(pdev, 0) + MTHCA_ECR_BASE, MTHCA_MAP_ECR_SIZE);err_ecr_failed: release_mem_region(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE, MTHCA_HCR_SIZE);err_hcr_failed: return err;}static void mthca_release_regions(struct pci_dev *pdev, int ddr_hidden){ if (!ddr_hidden) pci_release_region(pdev, 4); pci_release_region(pdev, 2); release_mem_region(pci_resource_start(pdev, 0) + MTHCA_CLR_INT_BASE, MTHCA_CLR_INT_SIZE); release_mem_region(pci_resource_start(pdev, 0) + MTHCA_ECR_BASE, MTHCA_MAP_ECR_SIZE); release_mem_region(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE, MTHCA_HCR_SIZE);}static int __devinit mthca_enable_msi_x(struct mthca_dev *mdev){ struct msix_entry entries[3]; int err; entries[0].entry = 0; entries[1].entry = 1; entries[2].entry = 2; err = pci_enable_msix(mdev->pdev, entries, ARRAY_SIZE(entries)); if (err) { if (err > 0) mthca_info(mdev, "Only %d MSI-X vectors available, " "not using MSI-X\n", err); return err; } mdev->eq_table.eq[MTHCA_EQ_COMP ].msi_x_vector = entries[0].vector; mdev->eq_table.eq[MTHCA_EQ_ASYNC].msi_x_vector = entries[1].vector; mdev->eq_table.eq[MTHCA_EQ_CMD ].msi_x_vector = entries[2].vector; return 0;}static void mthca_close_hca(struct mthca_dev *mdev){ u8 status; mthca_CLOSE_HCA(mdev, 0, &status); if (mdev->hca_type == ARBEL_NATIVE) { 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); mthca_UNMAP_FA(mdev, &status); mthca_free_icm(mdev, mdev->fw.arbel.fw_icm); if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM)) mthca_DISABLE_LAM(mdev, &status); } else mthca_SYS_DIS(mdev, &status);}static int __devinit mthca_init_one(struct pci_dev *pdev, const struct pci_device_id *id){ static int mthca_version_printed = 0; int ddr_hidden = 0; int err; unsigned long mthca_base; struct mthca_dev *mdev; if (!mthca_version_printed) { printk(KERN_INFO "%s", mthca_version); ++mthca_version_printed; } printk(KERN_INFO PFX "Initializing %s (%s)\n", pci_pretty_name(pdev), pci_name(pdev)); err = pci_enable_device(pdev); if (err) { dev_err(&pdev->dev, "Cannot enable PCI device, " "aborting.\n"); return err; } /* * Check for BARs. We expect 0: 1MB, 2: 8MB, 4: DDR (may not * be present) */ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) || pci_resource_len(pdev, 0) != 1 << 20) { dev_err(&pdev->dev, "Missing DCS, aborting."); err = -ENODEV; goto err_disable_pdev; } if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM) || pci_resource_len(pdev, 2) != 1 << 23) { dev_err(&pdev->dev, "Missing UAR, aborting."); err = -ENODEV; goto err_disable_pdev; } if (!(pci_resource_flags(pdev, 4) & IORESOURCE_MEM)) ddr_hidden = 1; err = mthca_request_regions(pdev, ddr_hidden); if (err) { dev_err(&pdev->dev, "Cannot obtain PCI resources, " "aborting.\n"); goto err_disable_pdev; } 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_free_res; } } 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_free_res; } } mdev = (struct mthca_dev *) ib_alloc_device(sizeof *mdev); if (!mdev) { dev_err(&pdev->dev, "Device struct alloc failed, " "aborting.\n"); err = -ENOMEM; goto err_free_res; } mdev->pdev = pdev; mdev->hca_type = id->driver_data; if (ddr_hidden) mdev->mthca_flags |= MTHCA_FLAG_DDR_HIDDEN; /* * 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 = mthca_reset(mdev); if (err) { mthca_err(mdev, "Failed to reset HCA, aborting.\n"); goto err_free_dev; } if (msi_x && !mthca_enable_msi_x(mdev)) mdev->mthca_flags |= MTHCA_FLAG_MSI_X; if (msi && !(mdev->mthca_flags & MTHCA_FLAG_MSI_X) && !pci_enable_msi(pdev)) mdev->mthca_flags |= MTHCA_FLAG_MSI; sema_init(&mdev->cmd.hcr_sem, 1); sema_init(&mdev->cmd.poll_sem, 1); mdev->cmd.use_events = 0; mthca_base = pci_resource_start(pdev, 0); mdev->hcr = ioremap(mthca_base + MTHCA_HCR_BASE, MTHCA_HCR_SIZE); if (!mdev->hcr) { mthca_err(mdev, "Couldn't map command register, " "aborting.\n"); err = -ENOMEM; goto err_free_dev; } mdev->clr_base = ioremap(mthca_base + MTHCA_CLR_INT_BASE, MTHCA_CLR_INT_SIZE); if (!mdev->clr_base) { mthca_err(mdev, "Couldn't map interrupt clear register, " "aborting.\n"); err = -ENOMEM; goto err_iounmap; } mdev->ecr_base = ioremap(mthca_base + MTHCA_ECR_BASE, MTHCA_ECR_SIZE + MTHCA_ECR_CLR_SIZE); if (!mdev->ecr_base) { mthca_err(mdev, "Couldn't map ecr register, " "aborting.\n"); err = -ENOMEM; goto err_iounmap_clr; } mthca_base = pci_resource_start(pdev, 2); mdev->kar = ioremap(mthca_base + PAGE_SIZE * MTHCA_KAR_PAGE, PAGE_SIZE); if (!mdev->kar) { mthca_err(mdev, "Couldn't map kernel access region, " "aborting.\n"); err = -ENOMEM; goto err_iounmap_ecr; } err = mthca_tune_pci(mdev); if (err) goto err_iounmap_kar; err = mthca_init_hca(mdev); if (err) goto err_iounmap_kar; err = mthca_setup_hca(mdev); if (err) goto err_close; err = mthca_register_device(mdev); if (err) goto err_cleanup; err = mthca_create_agents(mdev); if (err) goto err_unregister; pci_set_drvdata(pdev, mdev); return 0;err_unregister: mthca_unregister_device(mdev);err_cleanup: mthca_cleanup_mcg_table(mdev); mthca_cleanup_av_table(mdev); mthca_cleanup_qp_table(mdev); mthca_cleanup_cq_table(mdev); mthca_cmd_use_polling(mdev); mthca_cleanup_eq_table(mdev); mthca_pd_free(mdev, &mdev->driver_pd); mthca_cleanup_mr_table(mdev); mthca_cleanup_pd_table(mdev);err_close: mthca_close_hca(mdev);err_iounmap_kar: iounmap(mdev->kar);err_iounmap_ecr: iounmap(mdev->ecr_base);err_iounmap_clr: iounmap(mdev->clr_base);err_iounmap: iounmap(mdev->hcr);err_free_dev: if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) pci_disable_msix(pdev); if (mdev->mthca_flags & MTHCA_FLAG_MSI) pci_disable_msi(pdev); ib_dealloc_device(&mdev->ib_dev);err_free_res: mthca_release_regions(pdev, ddr_hidden);err_disable_pdev: pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); return err;}static void __devexit mthca_remove_one(struct pci_dev *pdev){ struct mthca_dev *mdev = pci_get_drvdata(pdev); u8 status; int p; if (mdev) { mthca_free_agents(mdev); mthca_unregister_device(mdev); for (p = 1; p <= mdev->limits.num_ports; ++p) mthca_CLOSE_IB(mdev, p, &status); mthca_cleanup_mcg_table(mdev); mthca_cleanup_av_table(mdev); mthca_cleanup_qp_table(mdev); mthca_cleanup_cq_table(mdev); mthca_cmd_use_polling(mdev); mthca_cleanup_eq_table(mdev); mthca_pd_free(mdev, &mdev->driver_pd); mthca_cleanup_mr_table(mdev); mthca_cleanup_pd_table(mdev); mthca_close_hca(mdev); iounmap(mdev->hcr); iounmap(mdev->ecr_base); iounmap(mdev->clr_base); if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) pci_disable_msix(pdev); if (mdev->mthca_flags & MTHCA_FLAG_MSI) pci_disable_msi(pdev); ib_dealloc_device(&mdev->ib_dev); mthca_release_regions(pdev, mdev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); }}static struct pci_device_id mthca_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_TAVOR), .driver_data = TAVOR }, { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_TAVOR), .driver_data = TAVOR }, { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT), .driver_data = ARBEL_COMPAT }, { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT), .driver_data = ARBEL_COMPAT }, { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_ARBEL), .driver_data = ARBEL_NATIVE }, { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_ARBEL), .driver_data = ARBEL_NATIVE }, { 0, }};MODULE_DEVICE_TABLE(pci, mthca_pci_table);static struct pci_driver mthca_driver = { .name = "ib_mthca", .id_table = mthca_pci_table, .probe = mthca_init_one, .remove = __devexit_p(mthca_remove_one)};static int __init mthca_init(void){ int ret; ret = pci_register_driver(&mthca_driver); return ret < 0 ? ret : 0;}static void __exit mthca_cleanup(void){ pci_unregister_driver(&mthca_driver);}module_init(mthca_init);module_exit(mthca_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -