/* bspVmeDmaList.c: * implementation of generic parts of the 'linked-list VME DMA' API. */ /* * Authorship * ---------- * This software was created by * Till Straumann , 2006, 2007, * Stanford Linear Accelerator Center, Stanford University. * * Acknowledgement of sponsorship * ------------------------------ * This software was produced by * the Stanford Linear Accelerator Center, Stanford University, * under Contract DE-AC03-76SFO0515 with the Department of Energy. * * Government disclaimer of liability * ---------------------------------- * Neither the United States nor the United States Department of Energy, * nor any of their employees, makes any warranty, express or implied, or * assumes any legal liability or responsibility for the accuracy, * completeness, or usefulness of any data, apparatus, product, or process * disclosed, or represents that its use would not infringe privately owned * rights. * * Stanford disclaimer of liability * -------------------------------- * Stanford University makes no representations or warranties, express or * implied, nor assumes any liability for the use of this software. * * Stanford disclaimer of copyright * -------------------------------- * Stanford University, owner of the copyright, hereby disclaims its * copyright and all other rights in this software. Hence, anyone may * freely use it for any purpose without restriction. * * Maintenance of notices * ---------------------- * In the interest of clarity regarding the origin and status of this * SLAC software, this and all the preceding Stanford University notices * are to remain affixed to any copy or derivative of this software made * or distributed by the recipient and are to be affixed to any copy of * software made or distributed by the recipient that contains a copy or * derivative of this software. * * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 */ #include #include #include #include #include #include "bspVmeDmaListP.h" #define DEBUG typedef struct VMEDmaListNodeRec_ { VMEDmaListNode p, n; /* linkage */ DmaDescriptor d; /* real descriptor */ void *usrData; VMEDmaListClass class; /* pointer to 'class' record */ } VMEDmaListNodeRec; #define LCHUNK 10 #ifdef DEBUG static void lprint(VMEDmaListNode d) { printf("n 0x%08lx, p: 0x%08lx, n: 0x%08lx d: 0x%08lx\n", (uint32_t)d, (uint32_t)d->p, (uint32_t)d->n, (uint32_t)d->d); } #endif static VMEDmaListNode lalloc(VMEDmaListClass pc) { VMEDmaListNode rval; int i; if ( !pc->freeList ) { /* alloc block of 10 descriptors */ pc->freeList = calloc( (LCHUNK), sizeof(*pc->freeList)); if ( ! (pc->freeList) ) { return 0; } /* link together and set 'class' pointer */ for (i=0; i<(LCHUNK)-1; i++) { pc->freeList[i].n = &pc->freeList[i+1]; pc->freeList[i].class = pc; } pc->freeList[i].n = 0; pc->freeList[i].class = pc; /* Allocate 'real' descriptor memory */ if ( pc->desc_alloc ) { for (i=0; i<(LCHUNK); i++) { if ( ! (pc->freeList[i].d = pc->desc_alloc()) ) { int j; if ( pc->desc_free ) { for (j=0; jdesc_free(pc->freeList[i].d); } free(pc->freeList); pc->freeList = 0; return 0; } } } else { int blksize; uint32_t algnmsk = pc->desc_align - 1; char *memptr; /* ignore their 'free' method */ pc->desc_free = 0; blksize = (pc->desc_size + algnmsk) & ~algnmsk; if ( ! (memptr = malloc(blksize*(LCHUNK) + pc->desc_align - 1)) ) { free(pc->freeList); pc->freeList = 0; return 0; } /* align memory ptr; must not be freed() anymore */ memptr = (char*)( ((uint32_t)memptr + algnmsk) & ~ algnmsk ); for ( i = 0; i<(LCHUNK); i++, memptr+=blksize ) { memset(memptr, 0, blksize); pc->freeList[i].d = (DmaDescriptor)memptr; } } } rval = pc->freeList; pc->freeList = pc->freeList->n; rval->n = rval->p = 0; return rval; } static int lfree(VMEDmaListNode d) { if ( d->p || d->n ) return -1; d->n = d->class->freeList; d->class->freeList = d; return 0; } static int lenq(VMEDmaListNode a, VMEDmaListNode d) { if ( a ) { /* enqueue */ if ( d->n || d->p ) return -1; if ( (d->n = a->n) ) a->n->p = d; d->p = a; a->n = d; } else { /* dequeue */ if ( d->n ) d->n->p = d->p; if ( d->p ) d->p->n = d->n; d->n = d->p = 0; } return 0; } int BSP_VMEDmaListDescriptorStartTool(volatile void *controller, int channel, VMEDmaListNode n) { if ( !n ) return -1; return n->class->desc_start(controller, channel, n->d); } VMEDmaListNode BSP_VMEDmaListDescriptorSetupTool( VMEDmaListNode n, uint32_t attr_mask, uint32_t xfer_mode, uint32_t pci_addr, uint32_t vme_addr, uint32_t n_bytes) { if ( !n ) return 0; if ( n->class->desc_setup(n->d, attr_mask, xfer_mode, pci_addr, vme_addr, n_bytes) ) { return 0; } return n; } VMEDmaListNode BSP_VMEDmaListDescriptorNewTool( VMEDmaListClass pc, uint32_t attr_mask, uint32_t xfer_mode, uint32_t pci_addr, uint32_t vme_addr, uint32_t n_bytes) { VMEDmaListNode n; if ( !(n=lalloc(pc)) ) return 0; /* no memory */ if ( n->class->desc_init ) n->class->desc_init(n->d); if ( n->class->desc_setup(n->d, attr_mask, xfer_mode, pci_addr, vme_addr, n_bytes) ) { BSP_VMEDmaListDescriptorDestroy(n); return 0; } return n; } int BSP_VMEDmaListDescriptorDestroy(BSP_VMEDmaListDescriptor p) { VMEDmaListNode d = p; return lfree(d); } int BSP_VMEDmaListDestroy(BSP_VMEDmaListDescriptor p) { VMEDmaListNode d = p; VMEDmaListNode n; while (d) { n = d->n; if ( BSP_VMEDmaListDescriptorEnq(0, d) || BSP_VMEDmaListDescriptorDestroy(d) ) return -1; d = n; } return 0; } int BSP_VMEDmaListDescriptorEnq(BSP_VMEDmaListDescriptor p, BSP_VMEDmaListDescriptor q) { VMEDmaListNode anchor = p; VMEDmaListNode d = q; DmaDescriptorSetNxt setnxt = d->class->desc_setnxt; if ( !anchor ) { /* dequeue can't fail - we can update dnlal first (need d->p) */ if ( d->p ) setnxt(d->p->d, d->n ? d->n->d : 0); /* paranoia */ setnxt(d->d, 0); } else { if ( d->class != anchor->class ) return -1; } if ( lenq(anchor, d) ) return -1; /* update descriptor pointers */ if ( anchor ) { setnxt(d->d, d->n ? d->n->d : 0); setnxt(anchor->d, d->d); } return 0; } BSP_VMEDmaListDescriptor BSP_VMEDmaListDescriptorNext(BSP_VMEDmaListDescriptor p) { VMEDmaListNode d = p; return d->n; } BSP_VMEDmaListDescriptor BSP_VMEDmaDescriptorPrev(BSP_VMEDmaListDescriptor p) { VMEDmaListNode d = p; return d->p; } void BSP_VMEDmaListDescriptorSetUsr(BSP_VMEDmaListDescriptor p, void *usrData) { VMEDmaListNode d = p; d->usrData = usrData; } void * BSP_VMEDmaListDescriptorGetUsr(BSP_VMEDmaListDescriptor p) { VMEDmaListNode d = p; return d->usrData; } int BSP_VMEDmaListRefresh(BSP_VMEDmaListDescriptor p) { VMEDmaListNode anchor = p; DmaDescriptorRefr desc_refr; VMEDmaListNode n; if ( (desc_refr = anchor->class->desc_refr) ) { for ( n = anchor; n; n = n->n ) { desc_refr(n->d); } } return 0; } #ifdef DEBUG void BSP_VMEDmaListDump(BSP_VMEDmaListDescriptor p) { VMEDmaListNode d = p; while (d) { printf("----------\n"); lprint(d); if (d->class->desc_dump) d->class->desc_dump(d->d); d = d->n; } } #endif