static int tsi148_dma_list_exec()

in bridges/vme_tsi148.c [1801:1886]


static int tsi148_dma_list_exec(struct vme_dma_list *list)
{
	struct vme_dma_resource *ctrlr;
	int channel, retval;
	struct tsi148_dma_entry *entry;
	u32 bus_addr_high, bus_addr_low;
	u32 val, dctlreg = 0;
	struct vme_bridge *tsi148_bridge;
	struct tsi148_driver *bridge;

	ctrlr = list->parent;

	tsi148_bridge = ctrlr->parent;

	bridge = tsi148_bridge->driver_priv;

	mutex_lock(&ctrlr->mtx);

	channel = ctrlr->number;

	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 tsi148_dma_entry,
		list);

	mutex_unlock(&ctrlr->mtx);

	reg_split(entry->dma_handle, &bus_addr_high, &bus_addr_low);

	iowrite32be(bus_addr_high, bridge->base +
		TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DNLAU);
	iowrite32be(bus_addr_low, bridge->base +
		TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DNLAL);

	dctlreg = ioread32be(bridge->base + TSI148_LCSR_DMA[channel] +
		TSI148_LCSR_OFFSET_DCTL);

	/* Start the operation */
	iowrite32be(dctlreg | TSI148_LCSR_DCTL_DGO, bridge->base +
		TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DCTL);

	retval = wait_event_interruptible(bridge->dma_queue[channel],
		tsi148_dma_busy(ctrlr->parent, channel));

	if (retval) {
		iowrite32be(dctlreg | TSI148_LCSR_DCTL_ABT, bridge->base +
			TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DCTL);
		/* Wait for the operation to abort */
		wait_event(bridge->dma_queue[channel],
			   tsi148_dma_busy(ctrlr->parent, channel));
		retval = -EINTR;
		goto exit;
	}

	/*
	 * Read status register, this register is valid until we kick off a
	 * new transfer.
	 */
	val = ioread32be(bridge->base + TSI148_LCSR_DMA[channel] +
		TSI148_LCSR_OFFSET_DSTA);

	if (val & TSI148_LCSR_DSTA_VBE) {
		dev_err(tsi148_bridge->parent, "DMA Error. DSTA=%08X\n", val);
		retval = -EIO;
	}

exit:
	/* Remove list from running list */
	mutex_lock(&ctrlr->mtx);
	list_del(&list->list);
	mutex_unlock(&ctrlr->mtx);

	return retval;
}