static int ca91cx42_dma_list_exec()

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;

}