in bridges/vme_ca91cx42.c [1177:1269]
static int ca91cx42_dma_list_exec(struct vme_dma_list *list)
{
struct vme_dma_resource *ctrlr;
struct ca91cx42_dma_entry *entry;
int retval;
dma_addr_t bus_addr;
u32 val;
struct device *dev;
struct ca91cx42_driver *bridge;
ctrlr = list->parent;
bridge = ctrlr->parent->driver_priv;
dev = ctrlr->parent->parent;
mutex_lock(&ctrlr->mtx);
if (!(list_empty(&ctrlr->running))) {
/*
* XXX We have an active DMA transfer and currently haven't
* sorted out the mechanism for "pending" DMA transfers.
* Return busy.
*/
/* Need to add to pending here */
mutex_unlock(&ctrlr->mtx);
return -EBUSY;
} else {
list_add(&list->list, &ctrlr->running);
}
/* Get first bus address and write into registers */
entry = list_first_entry(&list->entries, struct ca91cx42_dma_entry,
list);
bus_addr = virt_to_bus(&entry->descriptor);
mutex_unlock(&ctrlr->mtx);
iowrite32(0, bridge->base + DTBC);
iowrite32(bus_addr & ~CA91CX42_DCPP_M, bridge->base + DCPP);
/* Start the operation */
val = ioread32(bridge->base + DGCS);
/* XXX Could set VMEbus On and Off Counters here */
val &= (CA91CX42_DGCS_VON_M | CA91CX42_DGCS_VOFF_M);
val |= (CA91CX42_DGCS_CHAIN | CA91CX42_DGCS_STOP | CA91CX42_DGCS_HALT |
CA91CX42_DGCS_DONE | CA91CX42_DGCS_LERR | CA91CX42_DGCS_VERR |
CA91CX42_DGCS_PERR);
iowrite32(val, bridge->base + DGCS);
val |= CA91CX42_DGCS_GO;
iowrite32(val, bridge->base + DGCS);
retval = wait_event_interruptible(bridge->dma_queue,
ca91cx42_dma_busy(ctrlr->parent));
if (retval) {
val = ioread32(bridge->base + DGCS);
iowrite32(val | CA91CX42_DGCS_STOP_REQ, bridge->base + DGCS);
/* Wait for the operation to abort */
wait_event(bridge->dma_queue,
ca91cx42_dma_busy(ctrlr->parent));
retval = -EINTR;
goto exit;
}
/*
* Read status register, this register is valid until we kick off a
* new transfer.
*/
val = ioread32(bridge->base + DGCS);
if (val & (CA91CX42_DGCS_LERR | CA91CX42_DGCS_VERR |
CA91CX42_DGCS_PERR)) {
dev_err(dev, "ca91c042: DMA Error. DGCS=%08X\n", val);
val = ioread32(bridge->base + DCTL);
retval = -EIO;
}
exit:
/* Remove list from running list */
mutex_lock(&ctrlr->mtx);
list_del(&list->list);
mutex_unlock(&ctrlr->mtx);
return retval;
}