Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:58

0001 /* bspVmeDmaList.c:
0002  * implementation of generic parts of the 'linked-list VME DMA' API.
0003  */
0004 
0005 /*
0006  * Authorship
0007  * ----------
0008  * This software was created by
0009  *     Till Straumann <strauman@slac.stanford.edu>, 2006, 2007,
0010  *     Stanford Linear Accelerator Center, Stanford University.
0011  *
0012  * Acknowledgement of sponsorship
0013  * ------------------------------
0014  * This software was produced by
0015  *     the Stanford Linear Accelerator Center, Stanford University,
0016  *     under Contract DE-AC03-76SFO0515 with the Department of Energy.
0017  *
0018  * Government disclaimer of liability
0019  * ----------------------------------
0020  * Neither the United States nor the United States Department of Energy,
0021  * nor any of their employees, makes any warranty, express or implied, or
0022  * assumes any legal liability or responsibility for the accuracy,
0023  * completeness, or usefulness of any data, apparatus, product, or process
0024  * disclosed, or represents that its use would not infringe privately owned
0025  * rights.
0026  *
0027  * Stanford disclaimer of liability
0028  * --------------------------------
0029  * Stanford University makes no representations or warranties, express or
0030  * implied, nor assumes any liability for the use of this software.
0031  *
0032  * Stanford disclaimer of copyright
0033  * --------------------------------
0034  * Stanford University, owner of the copyright, hereby disclaims its
0035  * copyright and all other rights in this software.  Hence, anyone may
0036  * freely use it for any purpose without restriction.
0037  *
0038  * Maintenance of notices
0039  * ----------------------
0040  * In the interest of clarity regarding the origin and status of this
0041  * SLAC software, this and all the preceding Stanford University notices
0042  * are to remain affixed to any copy or derivative of this software made
0043  * or distributed by the recipient and are to be affixed to any copy of
0044  * software made or distributed by the recipient that contains a copy or
0045  * derivative of this software.
0046  *
0047  * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
0048  */
0049 
0050 #include <inttypes.h>
0051 #include <stdint.h>
0052 #include <stdlib.h>
0053 #include <stdio.h>
0054 #include <string.h>
0055 
0056 #define DEBUG
0057 #include <bsp/VMEDMA.h>
0058 #include <bsp/bspVmeDmaList.h>
0059 #include "bspVmeDmaListP.h"
0060 
0061 
0062 typedef struct VMEDmaListNodeRec_ {
0063     VMEDmaListNode  p, n;       /* linkage         */
0064     DmaDescriptor   d;          /* real descriptor */
0065     void            *usrData;
0066     VMEDmaListClass class;      /* pointer to 'class' record */
0067 } VMEDmaListNodeRec;
0068 
0069 #define LCHUNK  10
0070 
0071 #ifdef DEBUG
0072 static void
0073 lprint(VMEDmaListNode d)
0074 {
0075     printf("n 0x%08" PRIu32", p: 0x%08" PRIu32 ", n: 0x%08" PRIu32 " d: 0x%08" PRIu32 "\n",
0076         (uint32_t)d, (uint32_t)d->p, (uint32_t)d->n, (uint32_t)d->d);
0077 }
0078 #endif
0079 
0080 static VMEDmaListNode
0081 lalloc(VMEDmaListClass pc)
0082 {
0083 VMEDmaListNode rval;
0084 int i;
0085 
0086     if ( !pc->freeList ) {
0087         /* alloc block of 10 descriptors */
0088         pc->freeList = calloc( (LCHUNK),  sizeof(*pc->freeList));
0089 
0090         if ( ! (pc->freeList) ) {
0091             return 0;
0092         }
0093 
0094         /* link together and set 'class' pointer */
0095         for (i=0; i<(LCHUNK)-1; i++) {
0096             pc->freeList[i].n     = &pc->freeList[i+1];
0097             pc->freeList[i].class = pc;
0098         }
0099         pc->freeList[i].n     = 0;
0100         pc->freeList[i].class = pc;
0101 
0102         /* Allocate 'real' descriptor memory */
0103         if ( pc->desc_alloc ) {
0104             for (i=0; i<(LCHUNK); i++) {
0105                 if ( ! (pc->freeList[i].d = pc->desc_alloc()) ) {
0106                     int j;
0107                     if ( pc->desc_free ) {
0108                         for (j=0; j<i; j++)
0109                             pc->desc_free(pc->freeList[i].d);
0110                     }
0111                     free(pc->freeList);
0112                     pc->freeList = 0;
0113                     return 0;
0114                 }
0115             }
0116         } else {
0117             int      blksize;
0118             uint32_t algnmsk = pc->desc_align - 1;
0119             char     *memptr;
0120 
0121             /* ignore their 'free' method */
0122             pc->desc_free = 0;
0123 
0124             blksize  = (pc->desc_size + algnmsk) & ~algnmsk;
0125 
0126             if ( ! (memptr = malloc(blksize*(LCHUNK) + pc->desc_align - 1)) ) {
0127                 free(pc->freeList);
0128                 pc->freeList = 0;
0129                 return 0;
0130             }
0131 
0132             /* align memory ptr; must not be freed() anymore */
0133             memptr = (char*)( ((uint32_t)memptr + algnmsk) & ~ algnmsk );
0134 
0135             for ( i = 0; i<(LCHUNK); i++, memptr+=blksize ) {
0136                 memset(memptr, 0, blksize);
0137                 pc->freeList[i].d = (DmaDescriptor)memptr;
0138             }
0139         }
0140     }
0141     rval         = pc->freeList;
0142     pc->freeList = pc->freeList->n;
0143     rval->n      = rval->p = 0;
0144     return rval;
0145 }
0146 
0147 static int
0148 lfree(VMEDmaListNode d)
0149 {
0150     if ( d->p || d->n )
0151         return -1;
0152     d->n = d->class->freeList;
0153     d->class->freeList = d;
0154     return 0;
0155 }
0156 
0157 static int
0158 lenq(VMEDmaListNode a, VMEDmaListNode d)
0159 {
0160     if ( a ) {
0161         /* enqueue */
0162         if ( d->n || d->p )
0163             return -1;
0164         if ( (d->n = a->n) )
0165             a->n->p = d;
0166         d->p = a;
0167         a->n = d;
0168     } else {
0169         /* dequeue */
0170         if ( d->n )
0171             d->n->p = d->p;
0172         if ( d->p )
0173             d->p->n = d->n;
0174         d->n = d->p = 0;
0175     }
0176     return 0;
0177 }
0178 
0179 
0180 int
0181 BSP_VMEDmaListDescriptorStartTool(volatile void *controller, int channel, VMEDmaListNode n)
0182 {
0183     if ( !n )
0184         return -1;
0185     return n->class->desc_start(controller, channel, n->d);
0186 }
0187 
0188 VMEDmaListNode
0189 BSP_VMEDmaListDescriptorSetupTool(
0190         VMEDmaListNode n,
0191         uint32_t    attr_mask,
0192         uint32_t    xfer_mode,
0193         uint32_t    pci_addr,
0194         uint32_t    vme_addr,
0195         uint32_t    n_bytes)
0196 {
0197     if ( !n )
0198         return 0;
0199 
0200     if ( n->class->desc_setup(n->d, attr_mask, xfer_mode, pci_addr, vme_addr, n_bytes) ) {
0201         return 0;
0202     }
0203 
0204     return n;
0205 }
0206 
0207 VMEDmaListNode
0208 BSP_VMEDmaListDescriptorNewTool(
0209         VMEDmaListClass pc,
0210         uint32_t    attr_mask,
0211         uint32_t    xfer_mode,
0212         uint32_t    pci_addr,
0213         uint32_t    vme_addr,
0214         uint32_t    n_bytes)
0215 {
0216 VMEDmaListNode n;
0217 
0218     if ( !(n=lalloc(pc)) )
0219         return 0;   /* no memory */
0220 
0221     if ( n->class->desc_init )
0222         n->class->desc_init(n->d);
0223 
0224     if ( n->class->desc_setup(n->d, attr_mask, xfer_mode, pci_addr, vme_addr, n_bytes) ) {
0225         BSP_VMEDmaListDescriptorDestroy(n);
0226         return 0;
0227     }
0228     return n;
0229 }
0230 
0231 int
0232 BSP_VMEDmaListDescriptorDestroy(BSP_VMEDmaListDescriptor p)
0233 {
0234 VMEDmaListNode d = p;
0235     return lfree(d);
0236 }
0237 
0238 int
0239 BSP_VMEDmaListDestroy(BSP_VMEDmaListDescriptor p)
0240 {
0241 VMEDmaListNode d = p;
0242 VMEDmaListNode n;
0243     while (d) {
0244         n = d->n;
0245         if ( BSP_VMEDmaListDescriptorEnq(0, d) ||
0246              BSP_VMEDmaListDescriptorDestroy(d) )
0247             return -1;
0248         d = n;
0249     }
0250     return 0;
0251 }
0252 
0253 int
0254 BSP_VMEDmaListDescriptorEnq(BSP_VMEDmaListDescriptor p, BSP_VMEDmaListDescriptor q)
0255 {
0256 VMEDmaListNode      anchor = p;
0257 VMEDmaListNode           d = q;
0258 DmaDescriptorSetNxt setnxt = d->class->desc_setnxt;
0259 
0260     if ( !anchor ) {
0261         /* dequeue can't fail - we can update dnlal first (need d->p) */
0262         if ( d->p )
0263             setnxt(d->p->d, d->n ? d->n->d : 0);
0264         /* paranoia */
0265         setnxt(d->d, 0);
0266     } else {
0267         if ( d->class != anchor->class )
0268             return -1;
0269     }
0270     if ( lenq(anchor, d) )
0271         return -1;
0272     /* update descriptor pointers */
0273     if ( anchor ) {
0274         setnxt(d->d,      d->n ? d->n->d : 0);
0275         setnxt(anchor->d, d->d);
0276     }
0277     return 0;
0278 }
0279 
0280 BSP_VMEDmaListDescriptor
0281 BSP_VMEDmaListDescriptorNext(BSP_VMEDmaListDescriptor p)
0282 {
0283 VMEDmaListNode d = p;
0284     return d->n;
0285 }
0286 
0287 BSP_VMEDmaListDescriptor
0288 BSP_VMEDmaListDescriptorPrev(BSP_VMEDmaListDescriptor p)
0289 {
0290 VMEDmaListNode d = p;
0291     return d->p;
0292 }
0293 
0294 void
0295 BSP_VMEDmaListDescriptorSetUsr(BSP_VMEDmaListDescriptor p, void *usrData)
0296 {
0297 VMEDmaListNode d = p;
0298     d->usrData = usrData;
0299 }
0300 
0301 void *
0302 BSP_VMEDmaListDescriptorGetUsr(BSP_VMEDmaListDescriptor p)
0303 {
0304 VMEDmaListNode d = p;
0305     return d->usrData;
0306 }
0307 
0308 int
0309 BSP_VMEDmaListRefresh(BSP_VMEDmaListDescriptor p)
0310 {
0311 VMEDmaListNode    anchor = p;
0312 DmaDescriptorRefr desc_refr;
0313 VMEDmaListNode    n;
0314     if ( (desc_refr = anchor->class->desc_refr) ) {
0315         for ( n = anchor; n; n = n->n ) {
0316             desc_refr(n->d);
0317         }
0318     }
0319     return 0;
0320 }
0321 
0322 #ifdef DEBUG
0323 void
0324 BSP_VMEDmaListDump(BSP_VMEDmaListDescriptor p)
0325 {
0326 VMEDmaListNode d = p;
0327     while (d) {
0328         printf("----------\n");
0329         lprint(d);
0330         if (d->class->desc_dump)
0331             d->class->desc_dump(d->d);
0332         d = d->n;
0333     }
0334 }
0335 #endif