static int fpga_probe()

in solos-pci.c [1191:1350]


static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
	int err;
	uint16_t fpga_ver;
	uint8_t major_ver, minor_ver;
	uint32_t data32;
	struct solos_card *card;

	card = kzalloc(sizeof(*card), GFP_KERNEL);
	if (!card)
		return -ENOMEM;

	card->dev = dev;
	init_waitqueue_head(&card->fw_wq);
	init_waitqueue_head(&card->param_wq);

	err = pci_enable_device(dev);
	if (err) {
		dev_warn(&dev->dev,  "Failed to enable PCI device\n");
		goto out;
	}

	err = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));
	if (err) {
		dev_warn(&dev->dev, "Failed to set 32-bit DMA mask\n");
		goto out;
	}

	err = pci_request_regions(dev, "solos");
	if (err) {
		dev_warn(&dev->dev, "Failed to request regions\n");
		goto out;
	}

	card->config_regs = pci_iomap(dev, 0, CONFIG_RAM_SIZE);
	if (!card->config_regs) {
		dev_warn(&dev->dev, "Failed to ioremap config registers\n");
		err = -ENOMEM;
		goto out_release_regions;
	}
	card->buffers = pci_iomap(dev, 1, DATA_RAM_SIZE);
	if (!card->buffers) {
		dev_warn(&dev->dev, "Failed to ioremap data buffers\n");
		err = -ENOMEM;
		goto out_unmap_config;
	}

	if (reset) {
		iowrite32(1, card->config_regs + FPGA_MODE);
		ioread32(card->config_regs + FPGA_MODE);

		iowrite32(0, card->config_regs + FPGA_MODE);
		ioread32(card->config_regs + FPGA_MODE);
	}

	data32 = ioread32(card->config_regs + FPGA_VER);
	fpga_ver = (data32 & 0x0000FFFF);
	major_ver = ((data32 & 0xFF000000) >> 24);
	minor_ver = ((data32 & 0x00FF0000) >> 16);
	card->fpga_version = FPGA_VERSION(major_ver,minor_ver);
	if (card->fpga_version > LEGACY_BUFFERS)
		card->buffer_size = BUF_SIZE;
	else
		card->buffer_size = OLD_BUF_SIZE;
	dev_info(&dev->dev, "Solos FPGA Version %d.%02d svn-%d\n",
		 major_ver, minor_ver, fpga_ver);

	if (fpga_ver < 37 && (fpga_upgrade || firmware_upgrade ||
			      db_fpga_upgrade || db_firmware_upgrade)) {
		dev_warn(&dev->dev,
			 "FPGA too old; cannot upgrade flash. Use JTAG.\n");
		fpga_upgrade = firmware_upgrade = 0;
		db_fpga_upgrade = db_firmware_upgrade = 0;
	}

	/* Stopped using Atmel flash after 0.03-38 */
	if (fpga_ver < 39)
		card->atmel_flash = 1;
	else
		card->atmel_flash = 0;

	data32 = ioread32(card->config_regs + PORTS);
	card->nr_ports = (data32 & 0x000000FF);

	if (card->fpga_version >= DMA_SUPPORTED) {
		pci_set_master(dev);
		card->using_dma = 1;
		if (1) { /* All known FPGA versions so far */
			card->dma_alignment = 3;
			card->dma_bounce = kmalloc_array(card->nr_ports,
							 BUF_SIZE, GFP_KERNEL);
			if (!card->dma_bounce) {
				dev_warn(&card->dev->dev, "Failed to allocate DMA bounce buffers\n");
				err = -ENOMEM;
				/* Fallback to MMIO doesn't work */
				goto out_unmap_both;
			}
		}
	} else {
		card->using_dma = 0;
		/* Set RX empty flag for all ports */
		iowrite32(0xF0, card->config_regs + FLAGS_ADDR);
	}

	pci_set_drvdata(dev, card);

	tasklet_init(&card->tlet, solos_bh, (unsigned long)card);
	spin_lock_init(&card->tx_lock);
	spin_lock_init(&card->tx_queue_lock);
	spin_lock_init(&card->cli_queue_lock);
	spin_lock_init(&card->param_queue_lock);
	INIT_LIST_HEAD(&card->param_queue);

	err = request_irq(dev->irq, solos_irq, IRQF_SHARED,
			  "solos-pci", card);
	if (err) {
		dev_dbg(&card->dev->dev, "Failed to request interrupt IRQ: %d\n", dev->irq);
		goto out_unmap_both;
	}

	iowrite32(1, card->config_regs + IRQ_EN_ADDR);

	if (fpga_upgrade)
		flash_upgrade(card, 0);

	if (firmware_upgrade)
		flash_upgrade(card, 1);

	if (db_fpga_upgrade)
		flash_upgrade(card, 2);

	if (db_firmware_upgrade)
		flash_upgrade(card, 3);

	err = atm_init(card, &dev->dev);
	if (err)
		goto out_free_irq;

	if (card->fpga_version >= DMA_SUPPORTED &&
	    sysfs_create_group(&card->dev->dev.kobj, &gpio_attr_group))
		dev_err(&card->dev->dev, "Could not register parameter group for GPIOs\n");

	return 0;

 out_free_irq:
	iowrite32(0, card->config_regs + IRQ_EN_ADDR);
	free_irq(dev->irq, card);
	tasklet_kill(&card->tlet);
	
 out_unmap_both:
	kfree(card->dma_bounce);
	pci_iounmap(dev, card->buffers);
 out_unmap_config:
	pci_iounmap(dev, card->config_regs);
 out_release_regions:
	pci_release_regions(dev);
 out:
	kfree(card);
	return err;
}