in platform/barefoot/sonic-platform-modules-bfn-newport/modules/bf_fpga_main.c [866:1125]
static int bf_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) {
struct bf_pci_dev *bfdev;
int err, pci_use_highmem;
int i, num_irq;
u32 build_date, build_ver;
memset(bf_global, 0, sizeof(bf_global));
bfdev = kzalloc(sizeof(struct bf_pci_dev), GFP_KERNEL);
if (!bfdev) {
return -ENOMEM;
}
/* init the cookies to be passed to ISRs */
for (i = 0; i < BF_MSIX_ENTRY_CNT; i++) {
bfdev->bf_int_vec[i].int_vec_offset = i;
bfdev->bf_int_vec[i].bf_dev = bfdev;
}
/* initialize intr_mode to none */
bfdev->mode = BF_INTR_MODE_NONE;
/* clear pci_error_state */
bfdev->info.pci_error_state = 0;
/*
* enable device
*/
err = pci_enable_device(pdev);
if (err != 0) {
printk(KERN_ERR "bf_fpga cannot enable PCI device\n");
goto fail_free;
}
/*
* reserve device's PCI memory regions for use by this
* module
*/
err = pci_request_regions(pdev, "bf_fpga_umem");
if (err != 0) {
printk(KERN_ERR "bf_fpga Cannot request regions\n");
goto fail_pci_disable;
}
/* remap IO memory */
err = bf_setup_bars(pdev, &bfdev->info);
if (err != 0) {
printk(KERN_ERR "bf_fpga Cannot setup BARs\n");
goto fail_release_iomem;
}
if (!dma_set_mask(pci_dev_to_dev(pdev), DMA_BIT_MASK(64)) &&
!dma_set_coherent_mask(pci_dev_to_dev(pdev), DMA_BIT_MASK(64))) {
pci_use_highmem = 1;
} else {
err = dma_set_mask(pci_dev_to_dev(pdev), DMA_BIT_MASK(32));
if (err) {
err = dma_set_coherent_mask(pci_dev_to_dev(pdev), DMA_BIT_MASK(32));
if (err) {
printk(KERN_ERR "bf_fpga no usable DMA configuration, aborting\n");
goto fail_release_iomem;
}
}
pci_use_highmem = 0;
}
/* enable pci error reporting */
/* for the current kernel version, kernel config must have set the followings:
* CONFIG_PCIEPORTBUS=y and CONFIG_PCIEAER = y
* we have pci_error_handlers defined that gets invoked by kernel AER module
* upon detecting the pcie error on this device's addresses.
* However, there seems no way that AER would pass the offending addresses
* to the callback functions. AER logs the error messages on the console.
* This driver's calback function send the SIGIO signal to the user space
* to indicate the error condition.
*/
pci_enable_pcie_error_reporting(pdev);
bf_fpga_disable_int_dma(bfdev);
/* enable bus mastering on the device */
pci_set_master(pdev);
/* fill in bfdev info */
bfdev->info.version = "0.1";
bfdev->info.owner = THIS_MODULE;
bfdev->pdev = pdev;
switch (bf_intr_mode_default) {
#ifdef CONFIG_PCI_MSI
case BF_INTR_MODE_MSIX:
/* Only 1 msi-x vector needed */
bfdev->info.msix_entries =
kcalloc(BF_MSIX_ENTRY_CNT, sizeof(struct msix_entry), GFP_KERNEL);
if (!bfdev->info.msix_entries) {
err = -ENOMEM;
goto fail_clear_pci_master;
}
for (i = 0; i < BF_MSIX_ENTRY_CNT; i++) {
bfdev->info.msix_entries[i].entry = i;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)
num_irq =
pci_enable_msix(pdev, bfdev->info.msix_entries, BF_MSIX_ENTRY_CNT);
if (num_irq == 0) {
bfdev->info.num_irq = BF_MSIX_ENTRY_CNT;
bfdev->info.irq = bfdev->info.msix_entries[0].vector;
bfdev->mode = BF_INTR_MODE_MSIX;
printk(KERN_DEBUG "bf_fpga using %d MSIX irq from %ld\n",
num_irq,
bfdev->info.irq);
break;
}
#else
num_irq = pci_enable_msix_range(
pdev, bfdev->info.msix_entries, BF_MSIX_ENTRY_CNT, BF_MSIX_ENTRY_CNT);
if (num_irq == BF_MSIX_ENTRY_CNT) {
bfdev->info.num_irq = num_irq;
bfdev->info.irq = bfdev->info.msix_entries[0].vector;
bfdev->mode = BF_INTR_MODE_MSIX;
printk(KERN_DEBUG "bf_fpga using %d MSIX irq from %ld\n",
num_irq,
bfdev->info.irq);
break;
} else {
if (num_irq) pci_disable_msix(pdev);
kfree(bfdev->info.msix_entries);
bfdev->info.msix_entries = NULL;
printk(KERN_ERR
"bf_fpga error allocating MSIX vectors. Trying MSI...\n");
/* and, fall back to MSI */
}
#endif /* LINUX_VERSION_CODE */
/* ** intentional no-break */
/* FALLTHRU */
case BF_INTR_MODE_MSI:
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)
num_irq = pci_enable_msi_block(pdev, BF_MSI_ENTRY_CNT);
/* we must get requested number of MSI vectors enabled */
if (num_irq == 0) {
bfdev->info.num_irq = BF_MSI_ENTRY_CNT;
bfdev->info.irq = pdev->irq;
bfdev->mode = BF_INTR_MODE_MSI;
printk(KERN_DEBUG "bf_fpga using %d MSI irq from %ld\n",
bfdev->info.num_irq,
bfdev->info.irq);
break;
}
#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
num_irq = pci_enable_msi_range(pdev, BF_MSI_ENTRY_CNT, BF_MSI_ENTRY_CNT);
if (num_irq > 0) {
bfdev->info.num_irq = num_irq;
bfdev->info.irq = pdev->irq;
bfdev->mode = BF_INTR_MODE_MSI;
printk(KERN_DEBUG "bf_fpga using %d MSI irq from %ld\n",
bfdev->info.num_irq,
bfdev->info.irq);
break;
}
#else
num_irq = pci_alloc_irq_vectors_affinity(pdev,
BF_MSI_ENTRY_CNT,
BF_MSI_ENTRY_CNT,
PCI_IRQ_MSI | PCI_IRQ_AFFINITY,
NULL);
if (num_irq > 0) {
bfdev->info.num_irq = num_irq;
bfdev->info.irq = pci_irq_vector(pdev, 0);
bfdev->mode = BF_INTR_MODE_MSI;
printk(KERN_DEBUG "bf_fpga using %d MSI irq from %ld\n",
bfdev->info.num_irq,
bfdev->info.irq);
break;
}
#endif /* LINUX_VERSION_CODE */
#endif /* CONFIG_PCI_MSI */
/* fall back to Legacy Interrupt, intentional no-break */
/* FALLTHRU */
case BF_INTR_MODE_LEGACY:
if (pci_intx_mask_supported(pdev)) {
bfdev->info.irq_flags = IRQF_SHARED;
bfdev->info.irq = pdev->irq;
bfdev->mode = BF_INTR_MODE_LEGACY;
printk(KERN_DEBUG "bf_fpga using LEGACY irq %ld\n", bfdev->info.irq);
break;
}
printk(KERN_NOTICE "bf_fpga PCI INTx mask not supported\n");
/* fall back to no Interrupt, intentional no-break */
/* FALLTHRU */
case BF_INTR_MODE_NONE:
bfdev->info.irq = 0;
bfdev->info.num_irq = 0;
bfdev->mode = BF_INTR_MODE_NONE;
break;
default:
printk(KERN_DEBUG "bf_fpga invalid IRQ mode %u", bf_intr_mode_default);
err = -EINVAL;
goto fail_clear_pci_master;
}
pci_set_drvdata(pdev, bfdev);
sprintf(bfdev->name, "bf_fpga%d", bfdev->info.minor);
/* register bf driver */
err = bf_register_device(&pdev->dev, bfdev);
if (err != 0) {
goto fail_release_irq;
}
bf_global[bfdev->info.minor].async_queue = NULL;
bf_global[bfdev->info.minor].bfdev = bfdev;
dev_info(&pdev->dev,
"bf_fpga device %d registered with irq %ld\n",
bfdev->instance,
bfdev->info.irq);
if (fpga_i2c_init(bfdev->info.mem[0].internal_addr)) {
printk(KERN_ERR "bf_fpga i2c initialization failed\n");
goto fail_register_device;
}
if (bf_fpga_sysfs_add(bfdev)) {
printk(KERN_ERR "bf_fpga stsfs initialization failed\n");
goto fail_i2c_init;
}
build_ver =
*((u32 *)(bfdev->info.mem[0].internal_addr) + (BF_FPGA_VER_REG / 4));
build_date =
*((u32 *)(bfdev->info.mem[0].internal_addr) + (BF_FPGA_BUILD_DATE / 4));
fpga_print_build_date(build_date);
printk(KERN_ALERT "bf_fpga version %hu.%hu probe ok\n",
(u16)(build_ver >> 16),
(u16)(build_ver));
return 0;
fail_i2c_init:
fpga_i2c_deinit();
fail_register_device:
bf_unregister_device(bfdev);
fail_release_irq:
pci_set_drvdata(pdev, NULL);
if (bfdev->mode == BF_INTR_MODE_MSIX) {
pci_disable_msix(bfdev->pdev);
kfree(bfdev->info.msix_entries);
bfdev->info.msix_entries = NULL;
} else if (bfdev->mode == BF_INTR_MODE_MSI) {
pci_disable_msi(bfdev->pdev);
}
fail_clear_pci_master:
pci_clear_master(pdev);
fail_release_iomem:
bf_pci_release_iomem(&bfdev->info);
pci_release_regions(pdev);
fail_pci_disable:
pci_disable_device(pdev);
fail_free:
kfree(bfdev);
printk(KERN_ERR "bf_fpga probe failed\n");
return err;
}