in bridges/vme_ca91cx42.c [1018:1160]
static 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;
struct device *dev;
dev = list->parent->parent->parent;
/* XXX descriptor must be aligned on 64-bit boundaries */
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry) {
retval = -ENOMEM;
goto err_mem;
}
/* Test descriptor alignment */
if ((unsigned long)&entry->descriptor & CA91CX42_DCPP_M) {
dev_err(dev, "Descriptor not aligned to 16 byte boundary as "
"required: %p\n", &entry->descriptor);
retval = -EINVAL;
goto err_align;
}
memset(&entry->descriptor, 0, sizeof(entry->descriptor));
if (dest->type == VME_DMA_VME) {
entry->descriptor.dctl |= CA91CX42_DCTL_L2V;
vme_attr = dest->private;
pci_attr = src->private;
} else {
vme_attr = src->private;
pci_attr = dest->private;
}
/* Check we can do fulfill required attributes */
if ((vme_attr->aspace & ~(VME_A16 | VME_A24 | VME_A32 | VME_USER1 |
VME_USER2)) != 0) {
dev_err(dev, "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) {
dev_err(dev, "Unsupported cycle type\n");
retval = -EINVAL;
goto err_cycle;
}
/* Check to see if we can fulfill source and destination */
if (!(((src->type == VME_DMA_PCI) && (dest->type == VME_DMA_VME)) ||
((src->type == VME_DMA_VME) && (dest->type == VME_DMA_PCI)))) {
dev_err(dev, "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:
dev_err(dev, "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:
dev_err(dev, "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;
}