Loading drivers/staging/vme/TODO +0 −1 Original line number Diff line number Diff line Loading @@ -56,7 +56,6 @@ Tempe (tsi148) Universe II (ca91c142) ---------------------- - DMA unsupported. - RMW transactions unsupported. - Mailboxes unsupported. - Error Detection. Loading drivers/staging/vme/bridges/Kconfig +1 −0 Original line number Diff line number Diff line Loading @@ -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. Loading drivers/staging/vme/bridges/vme_ca91cx42.c +260 −339 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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. Loading Loading @@ -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 Loading Loading @@ -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++) { Loading @@ -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); Loading @@ -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; Loading Loading @@ -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)) { Loading @@ -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)) { Loading Loading @@ -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) { Loading Loading @@ -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, ¤tLL->dva); iowrite32(vmeCur->dstAddr, ¤tLL->dlv); } else { iowrite32(vmeCur->srcAddr, ¤tLL->dlv); iowrite32(vmeCur->dstAddr, ¤tLL->dva); } uniSetupDctlReg(vmeCur, &dctlreg); iowrite32(dctlreg, ¤tLL->dctl); iowrite32(vmeCur->byteCount, ¤tLL->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, ¤tLL->dcpp); } else { iowrite32((unsigned int)virt_to_bus(nextLL), ¤tLL->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(¤tLL->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; Loading drivers/staging/vme/bridges/vme_ca91cx42.h +66 −27 Original line number Diff line number Diff line Loading @@ -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 */ Loading Loading @@ -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 Loading Loading @@ -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 Loading Loading
drivers/staging/vme/TODO +0 −1 Original line number Diff line number Diff line Loading @@ -56,7 +56,6 @@ Tempe (tsi148) Universe II (ca91c142) ---------------------- - DMA unsupported. - RMW transactions unsupported. - Mailboxes unsupported. - Error Detection. Loading
drivers/staging/vme/bridges/Kconfig +1 −0 Original line number Diff line number Diff line Loading @@ -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. Loading
drivers/staging/vme/bridges/vme_ca91cx42.c +260 −339 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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. Loading Loading @@ -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 Loading Loading @@ -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++) { Loading @@ -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); Loading @@ -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; Loading Loading @@ -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)) { Loading @@ -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)) { Loading Loading @@ -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) { Loading Loading @@ -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, ¤tLL->dva); iowrite32(vmeCur->dstAddr, ¤tLL->dlv); } else { iowrite32(vmeCur->srcAddr, ¤tLL->dlv); iowrite32(vmeCur->dstAddr, ¤tLL->dva); } uniSetupDctlReg(vmeCur, &dctlreg); iowrite32(dctlreg, ¤tLL->dctl); iowrite32(vmeCur->byteCount, ¤tLL->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, ¤tLL->dcpp); } else { iowrite32((unsigned int)virt_to_bus(nextLL), ¤tLL->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(¤tLL->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; Loading
drivers/staging/vme/bridges/vme_ca91cx42.h +66 −27 Original line number Diff line number Diff line Loading @@ -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 */ Loading Loading @@ -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 Loading Loading @@ -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 Loading