Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4860ab74 authored by Martyn Welch's avatar Martyn Welch Committed by Greg Kroah-Hartman
Browse files

Staging: vme: add ca91cx42 dma support



Add support for the DMA controller in the ca91cx42 bridge.

Signed-off-by: default avatarMartyn Welch <martyn.welch@ge.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 2b82beb8
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -56,7 +56,6 @@ Tempe (tsi148)
Universe II (ca91c142)
----------------------

- DMA unsupported.
- RMW transactions unsupported.
- Mailboxes unsupported.
- Error Detection.
+1 −0
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@ comment "VME Bridge Drivers"

config VME_CA91CX42
	tristate "Universe II"
	depends on VIRT_TO_BUS
	help
	 If you say Y here you get support for the Tundra CA91C142
	 (Universe II) VME bridge chip.
+260 −339
Original line number Diff line number Diff line
@@ -592,8 +592,8 @@ static int ca91cx42_alloc_resource(struct vme_master_resource *image,
}

/*
 *  * Free and unmap PCI Resource
 *   */
 * Free and unmap PCI Resource
 */
static void ca91cx42_free_resource(struct vme_master_resource *image)
{
	iounmap(image->kern_base);
@@ -899,6 +899,261 @@ ssize_t ca91cx42_master_write(struct vme_master_resource *image, void *buf,
	return retval;
}

int ca91cx42_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
	struct vme_dma_attr *dest, size_t count)
{
	struct ca91cx42_dma_entry *entry, *prev;
	struct vme_dma_pci *pci_attr;
	struct vme_dma_vme *vme_attr;
	dma_addr_t desc_ptr;
	int retval = 0;

	/* XXX descriptor must be aligned on 64-bit boundaries */
	entry = (struct ca91cx42_dma_entry *)
		kmalloc(sizeof(struct ca91cx42_dma_entry), GFP_KERNEL);
	if (entry == NULL) {
		printk(KERN_ERR "Failed to allocate memory for dma resource "
			"structure\n");
		retval = -ENOMEM;
		goto err_mem;
	}

	/* Test descriptor alignment */
	if ((unsigned long)&(entry->descriptor) & CA91CX42_DCPP_M) {
		printk("Descriptor not aligned to 16 byte boundary as "
			"required: %p\n", &(entry->descriptor));
		retval = -EINVAL;
		goto err_align;
	}

	memset(&(entry->descriptor), 0, sizeof(struct ca91cx42_dma_descriptor));

	if (dest->type == VME_DMA_VME) {
		entry->descriptor.dctl |= CA91CX42_DCTL_L2V;
		vme_attr = (struct vme_dma_vme *)dest->private;
		pci_attr = (struct vme_dma_pci *)src->private;
	} else {
		vme_attr = (struct vme_dma_vme *)src->private;
		pci_attr = (struct vme_dma_pci *)dest->private;
	}

	/* Check we can do fullfill required attributes */
	if ((vme_attr->aspace & ~(VME_A16 | VME_A24 | VME_A32 | VME_USER1 |
		VME_USER2)) != 0) {

		printk(KERN_ERR "Unsupported cycle type\n");
		retval = -EINVAL;
		goto err_aspace;
	}

	if ((vme_attr->cycle & ~(VME_SCT | VME_BLT | VME_SUPER | VME_USER |
		VME_PROG | VME_DATA)) != 0) {

		printk(KERN_ERR "Unsupported cycle type\n");
		retval = -EINVAL;
		goto err_cycle;
	}

	/* Check to see if we can fullfill source and destination */
	if (!(((src->type == VME_DMA_PCI) && (dest->type == VME_DMA_VME)) ||
		((src->type == VME_DMA_VME) && (dest->type == VME_DMA_PCI)))) {

		printk(KERN_ERR "Cannot perform transfer with this "
			"source-destination combination\n");
		retval = -EINVAL;
		goto err_direct;
	}

	/* Setup cycle types */
	if (vme_attr->cycle & VME_BLT)
		entry->descriptor.dctl |= CA91CX42_DCTL_VCT_BLT;

	/* Setup data width */
	switch (vme_attr->dwidth) {
	case VME_D8:
		entry->descriptor.dctl |= CA91CX42_DCTL_VDW_D8;
		break;
	case VME_D16:
		entry->descriptor.dctl |= CA91CX42_DCTL_VDW_D16;
		break;
	case VME_D32:
		entry->descriptor.dctl |= CA91CX42_DCTL_VDW_D32;
		break;
	case VME_D64:
		entry->descriptor.dctl |= CA91CX42_DCTL_VDW_D64;
		break;
	default:
		printk(KERN_ERR "Invalid data width\n");
		return -EINVAL;
	}

	/* Setup address space */
	switch (vme_attr->aspace) {
	case VME_A16:
		entry->descriptor.dctl |= CA91CX42_DCTL_VAS_A16;
		break;
	case VME_A24:
		entry->descriptor.dctl |= CA91CX42_DCTL_VAS_A24;
		break;
	case VME_A32:
		entry->descriptor.dctl |= CA91CX42_DCTL_VAS_A32;
		break;
	case VME_USER1:
		entry->descriptor.dctl |= CA91CX42_DCTL_VAS_USER1;
		break;
	case VME_USER2:
		entry->descriptor.dctl |= CA91CX42_DCTL_VAS_USER2;
		break;
	default:
		printk(KERN_ERR "Invalid address space\n");
		return -EINVAL;
		break;
	}

	if (vme_attr->cycle & VME_SUPER)
		entry->descriptor.dctl |= CA91CX42_DCTL_SUPER_SUPR;
	if (vme_attr->cycle & VME_PROG)
		entry->descriptor.dctl |= CA91CX42_DCTL_PGM_PGM;

	entry->descriptor.dtbc = count;
	entry->descriptor.dla = pci_attr->address;
	entry->descriptor.dva = vme_attr->address;
	entry->descriptor.dcpp = CA91CX42_DCPP_NULL;

	/* Add to list */
	list_add_tail(&(entry->list), &(list->entries));

	/* Fill out previous descriptors "Next Address" */
	if (entry->list.prev != &(list->entries)) {
		prev = list_entry(entry->list.prev, struct ca91cx42_dma_entry,
			list);
		/* We need the bus address for the pointer */
		desc_ptr = virt_to_bus(&(entry->descriptor));
		prev->descriptor.dcpp = desc_ptr & ~CA91CX42_DCPP_M;
	}

	return 0;

err_cycle:
err_aspace:
err_direct:
err_align:
	kfree(entry);
err_mem:
	return retval;
}

static int ca91cx42_dma_busy(struct vme_bridge *ca91cx42_bridge)
{
	u32 tmp;
	struct ca91cx42_driver *bridge;

	bridge = ca91cx42_bridge->driver_priv;

	tmp = ioread32(bridge->base + DGCS);

	if (tmp & CA91CX42_DGCS_ACT)
		return 0;
	else
		return 1;
}

int ca91cx42_dma_list_exec(struct vme_dma_list *list)
{
	struct vme_dma_resource *ctrlr;
	struct ca91cx42_dma_entry *entry;
	int retval = 0;
	dma_addr_t bus_addr;
	u32 val;

	struct ca91cx42_driver *bridge;

	ctrlr = list->parent;

	bridge = ctrlr->parent->driver_priv;

	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);

	wait_event_interruptible(bridge->dma_queue,
		ca91cx42_dma_busy(ctrlr->parent));

	/*
	 * 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)) {

		printk(KERN_ERR "ca91c042: DMA Error. DGCS=%08X\n", val);
		val = ioread32(bridge->base + DCTL);
	}

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

	return retval;

}

int ca91cx42_dma_list_empty(struct vme_dma_list *list)
{
	struct list_head *pos, *temp;
	struct ca91cx42_dma_entry *entry;

	/* detach and free each entry */
	list_for_each_safe(pos, temp, &(list->entries)) {
		list_del(pos);
		entry = list_entry(pos, struct ca91cx42_dma_entry, list);
		kfree(entry);
	}

	return 0;
}

/*
 * All 4 location monitors reside at the same base - this is therefore a
 * system wide configuration.
@@ -1203,9 +1458,7 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
	struct ca91cx42_driver *ca91cx42_device;
	struct vme_master_resource *master_image;
	struct vme_slave_resource *slave_image;
#if 0
	struct vme_dma_resource *dma_ctrlr;
#endif
	struct vme_lm_resource *lm;

	/* We want to support more than one of each bridge so we need to
@@ -1336,7 +1589,7 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
		list_add_tail(&(slave_image->list),
			&(ca91cx42_bridge->slave_resources));
	}
#if 0

	/* Add dma engines to list */
	INIT_LIST_HEAD(&(ca91cx42_bridge->dma_resources));
	for (i = 0; i < CA91C142_MAX_DMA; i++) {
@@ -1359,7 +1612,7 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
		list_add_tail(&(dma_ctrlr->list),
			&(ca91cx42_bridge->dma_resources));
	}
#endif

	/* Add location monitor to list */
	INIT_LIST_HEAD(&(ca91cx42_bridge->lm_resources));
	lm = kmalloc(sizeof(struct vme_lm_resource), GFP_KERNEL);
@@ -1384,10 +1637,10 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
	ca91cx42_bridge->master_write = ca91cx42_master_write;
#if 0
	ca91cx42_bridge->master_rmw = ca91cx42_master_rmw;
#endif
	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;
#endif
	ca91cx42_bridge->irq_set = ca91cx42_irq_set;
	ca91cx42_bridge->irq_generate = ca91cx42_irq_generate;
	ca91cx42_bridge->lm_set = ca91cx42_lm_set;
@@ -1436,7 +1689,6 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
		list_del(pos);
		kfree(lm);
	}
#if 0
err_dma:
	/* resources are stored in link list */
	list_for_each(pos, &(ca91cx42_bridge->dma_resources)) {
@@ -1444,7 +1696,6 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
		list_del(pos);
		kfree(dma_ctrlr);
	}
#endif
err_slave:
	/* resources are stored in link list */
	list_for_each(pos, &(ca91cx42_bridge->slave_resources)) {
@@ -1575,7 +1826,6 @@ module_exit(ca91cx42_exit);
 *--------------------------------------------------------------------------*/

#if 0
#define	SWIZZLE(X) ( ((X & 0xFF000000) >> 24) | ((X & 0x00FF0000) >>  8) | ((X & 0x0000FF00) <<  8) | ((X & 0x000000FF) << 24))

int ca91cx42_master_rmw(vmeRmwCfg_t *vmeRmw)
{
@@ -1659,335 +1909,6 @@ int ca91cx42_master_rmw(vmeRmwCfg_t *vmeRmw)
	return 0;
}

int uniSetupDctlReg(vmeDmaPacket_t * vmeDma, int *dctlregreturn)
{
	unsigned int dctlreg = 0x80;
	struct vmeAttr *vmeAttr;

	if (vmeDma->srcBus == VME_DMA_VME) {
		dctlreg = 0;
		vmeAttr = &vmeDma->srcVmeAttr;
	} else {
		dctlreg = 0x80000000;
		vmeAttr = &vmeDma->dstVmeAttr;
	}

	switch (vmeAttr->maxDataWidth) {
	case VME_D8:
		break;
	case VME_D16:
		dctlreg |= 0x00400000;
		break;
	case VME_D32:
		dctlreg |= 0x00800000;
		break;
	case VME_D64:
		dctlreg |= 0x00C00000;
		break;
	}

	switch (vmeAttr->addrSpace) {
	case VME_A16:
		break;
	case VME_A24:
		dctlreg |= 0x00010000;
		break;
	case VME_A32:
		dctlreg |= 0x00020000;
		break;
	case VME_USER1:
		dctlreg |= 0x00060000;
		break;
	case VME_USER2:
		dctlreg |= 0x00070000;
		break;

	case VME_A64:		/* not supported in Universe DMA */
	case VME_CRCSR:
	case VME_USER3:
	case VME_USER4:
		return -EINVAL;
		break;
	}
	if (vmeAttr->userAccessType == VME_PROG) {
		dctlreg |= 0x00004000;
	}
	if (vmeAttr->dataAccessType == VME_SUPER) {
		dctlreg |= 0x00001000;
	}
	if (vmeAttr->xferProtocol != VME_SCT) {
		dctlreg |= 0x00000100;
	}
	*dctlregreturn = dctlreg;
	return 0;
}

unsigned int
ca91cx42_start_dma(int channel, unsigned int dgcsreg, TDMA_Cmd_Packet *vmeLL)
{
	unsigned int val;

	/* Setup registers as needed for direct or chained. */
	if (dgcsreg & 0x8000000) {
		iowrite32(0, bridge->base + DTBC);
		iowrite32((unsigned int)vmeLL, bridge->base + DCPP);
	} else {
#if	0
		printk(KERN_ERR "Starting: DGCS = %08x\n", dgcsreg);
		printk(KERN_ERR "Starting: DVA  = %08x\n",
			ioread32(&vmeLL->dva));
		printk(KERN_ERR "Starting: DLV  = %08x\n",
			ioread32(&vmeLL->dlv));
		printk(KERN_ERR "Starting: DTBC = %08x\n",
			ioread32(&vmeLL->dtbc));
		printk(KERN_ERR "Starting: DCTL = %08x\n",
			ioread32(&vmeLL->dctl));
#endif
		/* Write registers */
		iowrite32(ioread32(&vmeLL->dva), bridge->base + DVA);
		iowrite32(ioread32(&vmeLL->dlv), bridge->base + DLA);
		iowrite32(ioread32(&vmeLL->dtbc), bridge->base + DTBC);
		iowrite32(ioread32(&vmeLL->dctl), bridge->base + DCTL);
		iowrite32(0, bridge->base + DCPP);
	}

	/* Start the operation */
	iowrite32(dgcsreg, bridge->base + DGCS);
	val = get_tbl();
	iowrite32(dgcsreg | 0x8000000F, bridge->base + DGCS);
	return val;
}

TDMA_Cmd_Packet *ca91cx42_setup_dma(vmeDmaPacket_t * vmeDma)
{
	vmeDmaPacket_t *vmeCur;
	int maxPerPage;
	int currentLLcount;
	TDMA_Cmd_Packet *startLL;
	TDMA_Cmd_Packet *currentLL;
	TDMA_Cmd_Packet *nextLL;
	unsigned int dctlreg = 0;

	maxPerPage = PAGESIZE / sizeof(TDMA_Cmd_Packet) - 1;
	startLL = (TDMA_Cmd_Packet *) __get_free_pages(GFP_KERNEL, 0);
	if (startLL == 0) {
		return startLL;
	}
	/* First allocate pages for descriptors and create linked list */
	vmeCur = vmeDma;
	currentLL = startLL;
	currentLLcount = 0;
	while (vmeCur != 0) {
		if (vmeCur->pNextPacket != 0) {
			currentLL->dcpp = (unsigned int)(currentLL + 1);
			currentLLcount++;
			if (currentLLcount >= maxPerPage) {
				currentLL->dcpp =
				    __get_free_pages(GFP_KERNEL, 0);
				currentLLcount = 0;
			}
			currentLL = (TDMA_Cmd_Packet *) currentLL->dcpp;
		} else {
			currentLL->dcpp = (unsigned int)0;
		}
		vmeCur = vmeCur->pNextPacket;
	}

	/* Next fill in information for each descriptor */
	vmeCur = vmeDma;
	currentLL = startLL;
	while (vmeCur != 0) {
		if (vmeCur->srcBus == VME_DMA_VME) {
			iowrite32(vmeCur->srcAddr, &currentLL->dva);
			iowrite32(vmeCur->dstAddr, &currentLL->dlv);
		} else {
			iowrite32(vmeCur->srcAddr, &currentLL->dlv);
			iowrite32(vmeCur->dstAddr, &currentLL->dva);
		}
		uniSetupDctlReg(vmeCur, &dctlreg);
		iowrite32(dctlreg, &currentLL->dctl);
		iowrite32(vmeCur->byteCount, &currentLL->dtbc);

		currentLL = (TDMA_Cmd_Packet *) currentLL->dcpp;
		vmeCur = vmeCur->pNextPacket;
	}

	/* Convert Links to PCI addresses. */
	currentLL = startLL;
	while (currentLL != 0) {
		nextLL = (TDMA_Cmd_Packet *) currentLL->dcpp;
		if (nextLL == 0) {
			iowrite32(1, &currentLL->dcpp);
		} else {
			iowrite32((unsigned int)virt_to_bus(nextLL),
			       &currentLL->dcpp);
		}
		currentLL = nextLL;
	}

	/* Return pointer to descriptors list */
	return startLL;
}

int ca91cx42_free_dma(TDMA_Cmd_Packet *startLL)
{
	TDMA_Cmd_Packet *currentLL;
	TDMA_Cmd_Packet *prevLL;
	TDMA_Cmd_Packet *nextLL;
	unsigned int dcppreg;

	/* Convert Links to virtual addresses. */
	currentLL = startLL;
	while (currentLL != 0) {
		dcppreg = ioread32(&currentLL->dcpp);
		dcppreg &= ~6;
		if (dcppreg & 1) {
			currentLL->dcpp = 0;
		} else {
			currentLL->dcpp = (unsigned int)bus_to_virt(dcppreg);
		}
		currentLL = (TDMA_Cmd_Packet *) currentLL->dcpp;
	}

	/* Free all pages associated with the descriptors. */
	currentLL = startLL;
	prevLL = currentLL;
	while (currentLL != 0) {
		nextLL = (TDMA_Cmd_Packet *) currentLL->dcpp;
		if (currentLL + 1 != nextLL) {
			free_pages((int)prevLL, 0);
			prevLL = nextLL;
		}
		currentLL = nextLL;
	}

	/* Return pointer to descriptors list */
	return 0;
}

int ca91cx42_do_dma(vmeDmaPacket_t *vmeDma)
{
	unsigned int dgcsreg = 0;
	unsigned int dctlreg = 0;
	int val;
	int channel, x;
	vmeDmaPacket_t *curDma;
	TDMA_Cmd_Packet *dmaLL;

	/* Sanity check the VME chain. */
	channel = vmeDma->channel_number;
	if (channel > 0) {
		return -EINVAL;
	}
	curDma = vmeDma;
	while (curDma != 0) {
		if (curDma->byteCount == 0) {
			return -EINVAL;
		}
		if (curDma->byteCount >= 0x1000000) {
			return -EINVAL;
		}
		if ((curDma->srcAddr & 7) != (curDma->dstAddr & 7)) {
			return -EINVAL;
		}
		switch (curDma->srcBus) {
		case VME_DMA_PCI:
			if (curDma->dstBus != VME_DMA_VME) {
				return -EINVAL;
			}
			break;
		case VME_DMA_VME:
			if (curDma->dstBus != VME_DMA_PCI) {
				return -EINVAL;
			}
			break;
		default:
			return -EINVAL;
			break;
		}
		if (uniSetupDctlReg(curDma, &dctlreg) < 0) {
			return -EINVAL;
		}

		curDma = curDma->pNextPacket;
		if (curDma == vmeDma) {	/* Endless Loop! */
			return -EINVAL;
		}
	}

	/* calculate control register */
	if (vmeDma->pNextPacket != 0) {
		dgcsreg = 0x8000000;
	} else {
		dgcsreg = 0;
	}

	for (x = 0; x < 8; x++) {	/* vme block size */
		if ((256 << x) >= vmeDma->maxVmeBlockSize) {
			break;
		}
	}
	if (x == 8)
		x = 7;
	dgcsreg |= (x << 20);

	if (vmeDma->vmeBackOffTimer) {
		for (x = 1; x < 8; x++) {	/* vme timer */
			if ((16 << (x - 1)) >= vmeDma->vmeBackOffTimer) {
				break;
			}
		}
		if (x == 8)
			x = 7;
		dgcsreg |= (x << 16);
	}
	/*` Setup the dma chain */
	dmaLL = ca91cx42_setup_dma(vmeDma);

	/* Start the DMA */
	if (dgcsreg & 0x8000000) {
		vmeDma->vmeDmaStartTick =
		    ca91cx42_start_dma(channel, dgcsreg,
				  (TDMA_Cmd_Packet *) virt_to_phys(dmaLL));
	} else {
		vmeDma->vmeDmaStartTick =
		    ca91cx42_start_dma(channel, dgcsreg, dmaLL);
	}

	wait_event_interruptible(dma_queue,
		ioread32(bridge->base + DGCS) & 0x800);

	val = ioread32(bridge->base + DGCS);
	iowrite32(val | 0xF00, bridge->base + DGCS);

	vmeDma->vmeDmaStatus = 0;

	if (!(val & 0x00000800)) {
		vmeDma->vmeDmaStatus = val & 0x700;
		printk(KERN_ERR "ca91c042: DMA Error in ca91cx42_DMA_irqhandler"
			" DGCS=%08X\n", val);
		val = ioread32(bridge->base + DCPP);
		printk(KERN_ERR "ca91c042: DCPP=%08X\n", val);
		val = ioread32(bridge->base + DCTL);
		printk(KERN_ERR "ca91c042: DCTL=%08X\n", val);
		val = ioread32(bridge->base + DTBC);
		printk(KERN_ERR "ca91c042: DTBC=%08X\n", val);
		val = ioread32(bridge->base + DLA);
		printk(KERN_ERR "ca91c042: DLA=%08X\n", val);
		val = ioread32(bridge->base + DVA);
		printk(KERN_ERR "ca91c042: DVA=%08X\n", val);

	}
	/* Free the dma chain */
	ca91cx42_free_dma(dmaLL);

	return 0;
}





int ca91cx42_set_arbiter(vmeArbiterCfg_t *vmeArb)
{
	int temp_ctl = 0;
+66 −27
Original line number Diff line number Diff line
@@ -57,7 +57,7 @@ struct ca91cx42_driver {
struct ca91cx42_dma_descriptor {
	unsigned int dctl;      /* DMA Control */
	unsigned int dtbc;      /* Transfer Byte Count */
	unsigned int dlv;       /* PCI Address */
	unsigned int dla;       /* PCI Address */
	unsigned int res1;      /* Reserved */
	unsigned int dva;       /* Vme Address */
	unsigned int res2;      /* Reserved */
@@ -253,32 +253,6 @@ static const int CA91CX42_VSI_TO[] = { VSI0_TO, VSI1_TO, VSI2_TO, VSI3_TO,
#define VCSR_SET		0x0FF8
#define VCSR_BS			0x0FFC

// DMA General Control/Status Register DGCS (0x220)
// 32-24 ||  GO   | STOPR | HALTR |   0   || CHAIN |   0   |   0   |   0   ||
// 23-16 ||              VON              ||             VOFF              ||
// 15-08 ||  ACT  | STOP  | HALT  |   0   || DONE  | LERR  | VERR  | P_ERR ||
// 07-00 ||   0   | INT_S | INT_H |   0   || I_DNE | I_LER | I_VER | I_PER ||

// VON - Length Per DMA VMEBus Transfer
//  0000 = None
//  0001 = 256 Bytes
//  0010 = 512
//  0011 = 1024
//  0100 = 2048
//  0101 = 4096
//  0110 = 8192
//  0111 = 16384

// VOFF - wait between DMA tenures
//  0000 = 0    us
//  0001 = 16
//  0010 = 32
//  0011 = 64
//  0100 = 128
//  0101 = 256
//  0110 = 512
//  0111 = 1024

/*
 * PCI Class Register
 * offset 008
@@ -370,6 +344,71 @@ static const int CA91CX42_VSI_TO[] = { VSI0_TO, VSI1_TO, VSI2_TO, VSI3_TO,
#define CA91CX42_OF_SLSI_LAS                0
#define CA91CX42_BM_SLSI_RESERVED           0x3F0F0000

/*
 * DCTL Register
 * offset 200
 */
#define CA91CX42_DCTL_L2V		(1<<31)
#define CA91CX42_DCTL_VDW_M		(3<<22)
#define CA91CX42_DCTL_VDW_M		(3<<22)
#define CA91CX42_DCTL_VDW_D8		0
#define CA91CX42_DCTL_VDW_D16		(1<<22)
#define CA91CX42_DCTL_VDW_D32		(1<<23)
#define CA91CX42_DCTL_VDW_D64		(3<<22)

#define CA91CX42_DCTL_VAS_M		(7<<16)
#define CA91CX42_DCTL_VAS_A16		0
#define CA91CX42_DCTL_VAS_A24		(1<<16)
#define CA91CX42_DCTL_VAS_A32		(1<<17)
#define CA91CX42_DCTL_VAS_USER1		(3<<17)
#define CA91CX42_DCTL_VAS_USER2		(7<<16)

#define CA91CX42_DCTL_PGM_M		(1<<14)
#define CA91CX42_DCTL_PGM_DATA		0
#define CA91CX42_DCTL_PGM_PGM		(1<<14)

#define CA91CX42_DCTL_SUPER_M		(1<<12)
#define CA91CX42_DCTL_SUPER_NPRIV	0
#define CA91CX42_DCTL_SUPER_SUPR	(1<<12)

#define CA91CX42_DCTL_VCT_M		(1<<8)
#define CA91CX42_DCTL_VCT_BLT		(1<<8)
#define CA91CX42_DCTL_LD64EN		(1<<7)

/*
 * DCPP Register
 * offset 218
 */
#define CA91CX42_DCPP_M			0xf
#define CA91CX42_DCPP_NULL		(1<<0)

/*
 * DMA General Control/Status Register (DGCS)
 * offset 220
 */
#define CA91CX42_DGCS_GO		(1<<31)
#define CA91CX42_DGCS_STOP_REQ		(1<<30)
#define CA91CX42_DGCS_HALT_REQ		(1<<29)
#define CA91CX42_DGCS_CHAIN		(1<<27)

#define CA91CX42_DGCS_VON_M		(7<<20)

#define CA91CX42_DGCS_VOFF_M		(0xf<<16)

#define CA91CX42_DGCS_ACT		(1<<15)
#define CA91CX42_DGCS_STOP		(1<<14)
#define CA91CX42_DGCS_HALT		(1<<13)
#define CA91CX42_DGCS_DONE		(1<<11)
#define CA91CX42_DGCS_LERR		(1<<10)
#define CA91CX42_DGCS_VERR		(1<<9)
#define CA91CX42_DGCS_PERR		(1<<8)
#define CA91CX42_DGCS_INT_STOP		(1<<6)
#define CA91CX42_DGCS_INT_HALT		(1<<5)
#define CA91CX42_DGCS_INT_DONE		(1<<3)
#define CA91CX42_DGCS_INT_LERR		(1<<2)
#define CA91CX42_DGCS_INT_VERR		(1<<1)
#define CA91CX42_DGCS_INT_PERR		(1<<0)

/*
 * PCI Interrupt Enable Register
 * offset  300