in bridges/vme_tsi148.c [2269:2556]
static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
int retval, i, master_num;
u32 data;
struct list_head *pos = NULL, *n;
struct vme_bridge *tsi148_bridge;
struct tsi148_driver *tsi148_device;
struct vme_master_resource *master_image;
struct vme_slave_resource *slave_image;
struct vme_dma_resource *dma_ctrlr;
struct vme_lm_resource *lm;
/* If we want to support more than one of each bridge, we need to
* dynamically generate this so we get one per device
*/
tsi148_bridge = kzalloc(sizeof(*tsi148_bridge), GFP_KERNEL);
if (!tsi148_bridge) {
retval = -ENOMEM;
goto err_struct;
}
vme_init_bridge(tsi148_bridge);
tsi148_device = kzalloc(sizeof(*tsi148_device), GFP_KERNEL);
if (!tsi148_device) {
retval = -ENOMEM;
goto err_driver;
}
tsi148_bridge->driver_priv = tsi148_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 */
tsi148_device->base = ioremap(pci_resource_start(pdev, 0),
4096);
if (!tsi148_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(tsi148_device->base + TSI148_PCFS_ID) & 0x0000FFFF;
if (data != PCI_VENDOR_ID_TUNDRA) {
dev_err(&pdev->dev, "CRG region check failed\n");
retval = -EIO;
goto err_test;
}
/* Initialize wait queues & mutual exclusion flags */
init_waitqueue_head(&tsi148_device->dma_queue[0]);
init_waitqueue_head(&tsi148_device->dma_queue[1]);
init_waitqueue_head(&tsi148_device->iack_queue);
mutex_init(&tsi148_device->vme_int);
mutex_init(&tsi148_device->vme_rmw);
tsi148_bridge->parent = &pdev->dev;
strcpy(tsi148_bridge->name, driver_name);
/* Setup IRQ */
retval = tsi148_irq_init(tsi148_bridge);
if (retval != 0) {
dev_err(&pdev->dev, "Chip Initialization failed.\n");
goto err_irq;
}
/* If we are going to flush writes, we need to read from the VME bus.
* We need to do this safely, thus we read the devices own CR/CSR
* register. To do this we must set up a window in CR/CSR space and
* hence have one less master window resource available.
*/
master_num = TSI148_MAX_MASTER;
if (err_chk) {
master_num--;
tsi148_device->flush_image =
kmalloc(sizeof(*tsi148_device->flush_image),
GFP_KERNEL);
if (!tsi148_device->flush_image) {
retval = -ENOMEM;
goto err_master;
}
tsi148_device->flush_image->parent = tsi148_bridge;
spin_lock_init(&tsi148_device->flush_image->lock);
tsi148_device->flush_image->locked = 1;
tsi148_device->flush_image->number = master_num;
memset(&tsi148_device->flush_image->bus_resource, 0,
sizeof(tsi148_device->flush_image->bus_resource));
tsi148_device->flush_image->kern_base = NULL;
}
/* Add master windows to list */
for (i = 0; i < master_num; i++) {
master_image = kmalloc(sizeof(*master_image), GFP_KERNEL);
if (!master_image) {
retval = -ENOMEM;
goto err_master;
}
master_image->parent = tsi148_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_A64 | VME_CRCSR | VME_USER1 | VME_USER2 |
VME_USER3 | VME_USER4;
master_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 |
VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER |
VME_PROG | VME_DATA;
master_image->width_attr = VME_D16 | VME_D32;
memset(&master_image->bus_resource, 0,
sizeof(master_image->bus_resource));
master_image->kern_base = NULL;
list_add_tail(&master_image->list,
&tsi148_bridge->master_resources);
}
/* Add slave windows to list */
for (i = 0; i < TSI148_MAX_SLAVE; i++) {
slave_image = kmalloc(sizeof(*slave_image), GFP_KERNEL);
if (!slave_image) {
retval = -ENOMEM;
goto err_slave;
}
slave_image->parent = tsi148_bridge;
mutex_init(&slave_image->mtx);
slave_image->locked = 0;
slave_image->number = i;
slave_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
VME_A64;
slave_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 |
VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER |
VME_PROG | VME_DATA;
list_add_tail(&slave_image->list,
&tsi148_bridge->slave_resources);
}
/* Add dma engines to list */
for (i = 0; i < TSI148_MAX_DMA; i++) {
dma_ctrlr = kmalloc(sizeof(*dma_ctrlr), GFP_KERNEL);
if (!dma_ctrlr) {
retval = -ENOMEM;
goto err_dma;
}
dma_ctrlr->parent = tsi148_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 | VME_DMA_VME_TO_VME |
VME_DMA_MEM_TO_MEM | VME_DMA_PATTERN_TO_VME |
VME_DMA_PATTERN_TO_MEM;
INIT_LIST_HEAD(&dma_ctrlr->pending);
INIT_LIST_HEAD(&dma_ctrlr->running);
list_add_tail(&dma_ctrlr->list,
&tsi148_bridge->dma_resources);
}
/* Add location monitor to list */
lm = kmalloc(sizeof(*lm), GFP_KERNEL);
if (!lm) {
retval = -ENOMEM;
goto err_lm;
}
lm->parent = tsi148_bridge;
mutex_init(&lm->mtx);
lm->locked = 0;
lm->number = 1;
lm->monitors = 4;
list_add_tail(&lm->list, &tsi148_bridge->lm_resources);
tsi148_bridge->slave_get = tsi148_slave_get;
tsi148_bridge->slave_set = tsi148_slave_set;
tsi148_bridge->master_get = tsi148_master_get;
tsi148_bridge->master_set = tsi148_master_set;
tsi148_bridge->master_read = tsi148_master_read;
tsi148_bridge->master_write = tsi148_master_write;
tsi148_bridge->master_rmw = tsi148_master_rmw;
tsi148_bridge->dma_list_add = tsi148_dma_list_add;
tsi148_bridge->dma_list_exec = tsi148_dma_list_exec;
tsi148_bridge->dma_list_empty = tsi148_dma_list_empty;
tsi148_bridge->irq_set = tsi148_irq_set;
tsi148_bridge->irq_generate = tsi148_irq_generate;
tsi148_bridge->lm_set = tsi148_lm_set;
tsi148_bridge->lm_get = tsi148_lm_get;
tsi148_bridge->lm_attach = tsi148_lm_attach;
tsi148_bridge->lm_detach = tsi148_lm_detach;
tsi148_bridge->slot_get = tsi148_slot_get;
tsi148_bridge->alloc_consistent = tsi148_alloc_consistent;
tsi148_bridge->free_consistent = tsi148_free_consistent;
data = ioread32be(tsi148_device->base + TSI148_LCSR_VSTAT);
dev_info(&pdev->dev, "Board is%s the VME system controller\n",
(data & TSI148_LCSR_VSTAT_SCONS) ? "" : " not");
if (!geoid)
dev_info(&pdev->dev, "VME geographical address is %d\n",
data & TSI148_LCSR_VSTAT_GA_M);
else
dev_info(&pdev->dev, "VME geographical address is set to %d\n",
geoid);
dev_info(&pdev->dev, "VME Write and flush and error check is %s\n",
err_chk ? "enabled" : "disabled");
retval = tsi148_crcsr_init(tsi148_bridge, pdev);
if (retval) {
dev_err(&pdev->dev, "CR/CSR configuration failed.\n");
goto err_crcsr;
}
retval = vme_register_bridge(tsi148_bridge);
if (retval != 0) {
dev_err(&pdev->dev, "Chip Registration failed.\n");
goto err_reg;
}
pci_set_drvdata(pdev, tsi148_bridge);
/* Clear VME bus "board fail", and "power-up reset" lines */
data = ioread32be(tsi148_device->base + TSI148_LCSR_VSTAT);
data &= ~TSI148_LCSR_VSTAT_BRDFL;
data |= TSI148_LCSR_VSTAT_CPURST;
iowrite32be(data, tsi148_device->base + TSI148_LCSR_VSTAT);
return 0;
err_reg:
tsi148_crcsr_exit(tsi148_bridge, pdev);
err_crcsr:
err_lm:
/* resources are stored in link list */
list_for_each_safe(pos, n, &tsi148_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, &tsi148_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, &tsi148_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, &tsi148_bridge->master_resources) {
master_image = list_entry(pos, struct vme_master_resource,
list);
list_del(pos);
kfree(master_image);
}
tsi148_irq_exit(tsi148_bridge, pdev);
err_irq:
err_test:
iounmap(tsi148_device->base);
err_remap:
pci_release_regions(pdev);
err_resource:
pci_disable_device(pdev);
err_enable:
kfree(tsi148_device);
err_driver:
kfree(tsi148_bridge);
err_struct:
return retval;
}