static int ca91cx42_probe()

in bridges/vme_ca91cx42.c [1597:1842]


static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
	int retval, i;
	u32 data;
	struct list_head *pos = NULL, *n;
	struct vme_bridge *ca91cx42_bridge;
	struct ca91cx42_driver *ca91cx42_device;
	struct vme_master_resource *master_image;
	struct vme_slave_resource *slave_image;
	struct vme_dma_resource *dma_ctrlr;
	struct vme_lm_resource *lm;

	/* We want to support more than one of each bridge so we need to
	 * dynamically allocate the bridge structure
	 */
	ca91cx42_bridge = kzalloc(sizeof(*ca91cx42_bridge), GFP_KERNEL);
	if (!ca91cx42_bridge) {
		retval = -ENOMEM;
		goto err_struct;
	}
	vme_init_bridge(ca91cx42_bridge);

	ca91cx42_device = kzalloc(sizeof(*ca91cx42_device), GFP_KERNEL);
	if (!ca91cx42_device) {
		retval = -ENOMEM;
		goto err_driver;
	}

	ca91cx42_bridge->driver_priv = ca91cx42_device;

	/* Enable the device */
	retval = pci_enable_device(pdev);
	if (retval) {
		dev_err(&pdev->dev, "Unable to enable device\n");
		goto err_enable;
	}

	/* Map Registers */
	retval = pci_request_regions(pdev, driver_name);
	if (retval) {
		dev_err(&pdev->dev, "Unable to reserve resources\n");
		goto err_resource;
	}

	/* map registers in BAR 0 */
	ca91cx42_device->base = ioremap(pci_resource_start(pdev, 0),
		4096);
	if (!ca91cx42_device->base) {
		dev_err(&pdev->dev, "Unable to remap CRG region\n");
		retval = -EIO;
		goto err_remap;
	}

	/* Check to see if the mapping worked out */
	data = ioread32(ca91cx42_device->base + CA91CX42_PCI_ID) & 0x0000FFFF;
	if (data != PCI_VENDOR_ID_TUNDRA) {
		dev_err(&pdev->dev, "PCI_ID check failed\n");
		retval = -EIO;
		goto err_test;
	}

	/* Initialize wait queues & mutual exclusion flags */
	init_waitqueue_head(&ca91cx42_device->dma_queue);
	init_waitqueue_head(&ca91cx42_device->iack_queue);
	mutex_init(&ca91cx42_device->vme_int);
	mutex_init(&ca91cx42_device->vme_rmw);

	ca91cx42_bridge->parent = &pdev->dev;
	strcpy(ca91cx42_bridge->name, driver_name);

	/* Setup IRQ */
	retval = ca91cx42_irq_init(ca91cx42_bridge);
	if (retval != 0) {
		dev_err(&pdev->dev, "Chip Initialization failed.\n");
		goto err_irq;
	}

	/* Add master windows to list */
	for (i = 0; i < CA91C142_MAX_MASTER; i++) {
		master_image = kmalloc(sizeof(*master_image), GFP_KERNEL);
		if (!master_image) {
			retval = -ENOMEM;
			goto err_master;
		}
		master_image->parent = ca91cx42_bridge;
		spin_lock_init(&master_image->lock);
		master_image->locked = 0;
		master_image->number = i;
		master_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
			VME_CRCSR | VME_USER1 | VME_USER2;
		master_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
			VME_SUPER | VME_USER | VME_PROG | VME_DATA;
		master_image->width_attr = VME_D8 | VME_D16 | VME_D32 | VME_D64;
		memset(&master_image->bus_resource, 0,
		       sizeof(master_image->bus_resource));
		master_image->kern_base  = NULL;
		list_add_tail(&master_image->list,
			&ca91cx42_bridge->master_resources);
	}

	/* Add slave windows to list */
	for (i = 0; i < CA91C142_MAX_SLAVE; i++) {
		slave_image = kmalloc(sizeof(*slave_image), GFP_KERNEL);
		if (!slave_image) {
			retval = -ENOMEM;
			goto err_slave;
		}
		slave_image->parent = ca91cx42_bridge;
		mutex_init(&slave_image->mtx);
		slave_image->locked = 0;
		slave_image->number = i;
		slave_image->address_attr = VME_A24 | VME_A32 | VME_USER1 |
			VME_USER2;

		/* Only windows 0 and 4 support A16 */
		if (i == 0 || i == 4)
			slave_image->address_attr |= VME_A16;

		slave_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
			VME_SUPER | VME_USER | VME_PROG | VME_DATA;
		list_add_tail(&slave_image->list,
			&ca91cx42_bridge->slave_resources);
	}

	/* Add dma engines to list */
	for (i = 0; i < CA91C142_MAX_DMA; i++) {
		dma_ctrlr = kmalloc(sizeof(*dma_ctrlr), GFP_KERNEL);
		if (!dma_ctrlr) {
			retval = -ENOMEM;
			goto err_dma;
		}
		dma_ctrlr->parent = ca91cx42_bridge;
		mutex_init(&dma_ctrlr->mtx);
		dma_ctrlr->locked = 0;
		dma_ctrlr->number = i;
		dma_ctrlr->route_attr = VME_DMA_VME_TO_MEM |
			VME_DMA_MEM_TO_VME;
		INIT_LIST_HEAD(&dma_ctrlr->pending);
		INIT_LIST_HEAD(&dma_ctrlr->running);
		list_add_tail(&dma_ctrlr->list,
			&ca91cx42_bridge->dma_resources);
	}

	/* Add location monitor to list */
	lm = kmalloc(sizeof(*lm), GFP_KERNEL);
	if (!lm) {
		retval = -ENOMEM;
		goto err_lm;
	}
	lm->parent = ca91cx42_bridge;
	mutex_init(&lm->mtx);
	lm->locked = 0;
	lm->number = 1;
	lm->monitors = 4;
	list_add_tail(&lm->list, &ca91cx42_bridge->lm_resources);

	ca91cx42_bridge->slave_get = ca91cx42_slave_get;
	ca91cx42_bridge->slave_set = ca91cx42_slave_set;
	ca91cx42_bridge->master_get = ca91cx42_master_get;
	ca91cx42_bridge->master_set = ca91cx42_master_set;
	ca91cx42_bridge->master_read = ca91cx42_master_read;
	ca91cx42_bridge->master_write = ca91cx42_master_write;
	ca91cx42_bridge->master_rmw = ca91cx42_master_rmw;
	ca91cx42_bridge->dma_list_add = ca91cx42_dma_list_add;
	ca91cx42_bridge->dma_list_exec = ca91cx42_dma_list_exec;
	ca91cx42_bridge->dma_list_empty = ca91cx42_dma_list_empty;
	ca91cx42_bridge->irq_set = ca91cx42_irq_set;
	ca91cx42_bridge->irq_generate = ca91cx42_irq_generate;
	ca91cx42_bridge->lm_set = ca91cx42_lm_set;
	ca91cx42_bridge->lm_get = ca91cx42_lm_get;
	ca91cx42_bridge->lm_attach = ca91cx42_lm_attach;
	ca91cx42_bridge->lm_detach = ca91cx42_lm_detach;
	ca91cx42_bridge->slot_get = ca91cx42_slot_get;
	ca91cx42_bridge->alloc_consistent = ca91cx42_alloc_consistent;
	ca91cx42_bridge->free_consistent = ca91cx42_free_consistent;

	data = ioread32(ca91cx42_device->base + MISC_CTL);
	dev_info(&pdev->dev, "Board is%s the VME system controller\n",
		(data & CA91CX42_MISC_CTL_SYSCON) ? "" : " not");
	dev_info(&pdev->dev, "Slot ID is %d\n",
		ca91cx42_slot_get(ca91cx42_bridge));

	if (ca91cx42_crcsr_init(ca91cx42_bridge, pdev))
		dev_err(&pdev->dev, "CR/CSR configuration failed.\n");

	/* Need to save ca91cx42_bridge pointer locally in link list for use in
	 * ca91cx42_remove()
	 */
	retval = vme_register_bridge(ca91cx42_bridge);
	if (retval != 0) {
		dev_err(&pdev->dev, "Chip Registration failed.\n");
		goto err_reg;
	}

	pci_set_drvdata(pdev, ca91cx42_bridge);

	return 0;

err_reg:
	ca91cx42_crcsr_exit(ca91cx42_bridge, pdev);
err_lm:
	/* resources are stored in link list */
	list_for_each_safe(pos, n, &ca91cx42_bridge->lm_resources) {
		lm = list_entry(pos, struct vme_lm_resource, list);
		list_del(pos);
		kfree(lm);
	}
err_dma:
	/* resources are stored in link list */
	list_for_each_safe(pos, n, &ca91cx42_bridge->dma_resources) {
		dma_ctrlr = list_entry(pos, struct vme_dma_resource, list);
		list_del(pos);
		kfree(dma_ctrlr);
	}
err_slave:
	/* resources are stored in link list */
	list_for_each_safe(pos, n, &ca91cx42_bridge->slave_resources) {
		slave_image = list_entry(pos, struct vme_slave_resource, list);
		list_del(pos);
		kfree(slave_image);
	}
err_master:
	/* resources are stored in link list */
	list_for_each_safe(pos, n, &ca91cx42_bridge->master_resources) {
		master_image = list_entry(pos, struct vme_master_resource,
			list);
		list_del(pos);
		kfree(master_image);
	}

	ca91cx42_irq_exit(ca91cx42_device, pdev);
err_irq:
err_test:
	iounmap(ca91cx42_device->base);
err_remap:
	pci_release_regions(pdev);
err_resource:
	pci_disable_device(pdev);
err_enable:
	kfree(ca91cx42_device);
err_driver:
	kfree(ca91cx42_bridge);
err_struct:
	return retval;

}