devLib2  2.12
devLibVME.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2010 Brookhaven Science Associates, as Operator of
3 * Brookhaven National Laboratory.
4 * Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
5 * National Laboratory.
6 * Copyright (c) 2002 The Regents of the University of California, as
7 * Operator of Los Alamos National Laboratory.
8 * EPICS BASE is distributed subject to a Software License Agreement found
9 * in file LICENSE that is included with this distribution.
10 \*************************************************************************/
11 /* devLib.c - support for allocation of common device resources */
12 /* $Id$ */
13 
14 /*
15  * Original Author: Marty Kraimer
16  * Author: Jeff Hill
17  * Date: 03-10-93
18  *
19  * NOTES:
20  * .01 06-14-93 joh needs devAllocInterruptVector() routine
21  *
22  * This is a stripped down version of the similarly named file from EPICS Base
23  */
24 
25 static const char sccsID[] = "@(#) $Id$";
26 
27 #include <string.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 
31 #define epicsExportSharedSymbols
32 #include "dbDefs.h"
33 #include "epicsMutex.h"
34 #include "errlog.h"
35 #include "ellLib.h"
36 
37 #define NO_DEVLIB_COMPAT
38 #include "devLibVME.h"
39 
40 static ELLLIST addrAlloc[atLast];
41 static ELLLIST addrFree[atLast];
42 
43 static size_t addrLast[atLast] = {
44  0xffff,
45  0xffffff,
46  0xffffffff,
47  0xffffff,
48  0xffffff,
49  };
50 
51 static unsigned addrHexDig[atLast] = {
52  4,
53  6,
54  8,
55  6,
56  6
57  };
58 
59 static long addrFail[atLast] = {
60  S_dev_badA16,
61  S_dev_badA24,
62  S_dev_badA32,
63  S_dev_badA24,
64  S_dev_badA24
65  };
66 
67 static epicsMutexId addrListLock;
68 static char devLibInitFlag;
69 
70 const char *epicsAddressTypeName2[]
71  = {
72  "VME A16",
73  "VME A24",
74  "VME A32",
75  "ISA",
76  "VME CR/CSR"
77  };
78 
79 typedef struct{
80  ELLNODE node;
81  const char *pOwnerName;
82  volatile void *pPhysical;
83  /*
84  * first, last is used here instead of base, size
85  * so that we can store a block that is the maximum size
86  * available in type size_t
87  */
88  size_t begin;
89  size_t end;
90 }rangeItem;
91 
92 /*
93  * These routines are not exported
94  */
95 
96 static long devLibInit(void);
97 
98 static long addrVerify(
99  epicsAddressType addrType,
100  size_t base,
101  size_t size);
102 
103 static long blockFind (
104  epicsAddressType addrType,
105  const rangeItem *pRange,
106  /* size needed */
107  size_t requestSize,
108  /* n ls bits zero in base addr */
109  unsigned alignment,
110  /* base address found */
111  size_t *pFirst);
112 
113 static void report_conflict(
114  epicsAddressType addrType,
115  size_t base,
116  size_t size,
117  const char *pOwnerName);
118 
119 static void report_conflict_device(
120  epicsAddressType addrType,
121  const rangeItem *pRange);
122 
123 static void devInsertAddress(
124  ELLLIST *pRangeList,
125  rangeItem *pNewRange);
126 
127 static long devListAddressMap(
128  ELLLIST *pRangeList);
129 
130 static long devCombineAdjacentBlocks(
131  ELLLIST *pRangeList,
132  rangeItem *pRange);
133 
134 static long devInstallAddr(
135  rangeItem *pRange, /* item on the free list to be split */
136  const char *pOwnerName,
137  epicsAddressType addrType,
138  size_t base,
139  size_t size,
140  volatile void **ppPhysicalAddress);
141 
142 #define SUCCESS 0
143 
144 /*
145  * devBusToLocalAddr()
146  */
148  epicsAddressType addrType,
149  size_t busAddr,
150  volatile void **ppLocalAddress)
151 {
152  long status;
153  volatile void *localAddress;
154 
155  /*
156  * Make sure that devLib has been intialized
157  */
158  if (!devLibInitFlag) {
159  status = devLibInit();
160  if(status){
161  return status;
162  }
163  }
164 
165  /*
166  * Make sure we have a valid bus address
167  */
168  status = addrVerify (addrType, busAddr, 4);
169  if (status) {
170  return status;
171  }
172 
173  /*
174  * Call the virtual os routine to map the bus address to a CPU address
175  */
176  status = (*pdevLibVirtualOS->pDevMapAddr) (addrType, 0, busAddr, 4, &localAddress);
177  if (status) {
178  errPrintf (status, __FILE__, __LINE__, "%s bus address =0X%X\n",
179  epicsAddressTypeName[addrType], (unsigned int)busAddr);
180  return status;
181  }
182 
183  /*
184  * Return the local CPU address if the pointer is supplied
185  */
186  if (ppLocalAddress) {
187  *ppLocalAddress = localAddress;
188  }
189 
190  return SUCCESS;
191 
192 }/*end devBusToLocalAddr()*/
193 
194 
195 /*
196  * devRegisterAddress()
197  */
199  const char *pOwnerName,
200  epicsAddressType addrType,
201  size_t base,
202  size_t size,
203  volatile void **ppPhysicalAddress)
204 {
205  rangeItem *pRange;
206  long s;
207 
208  if (!devLibInitFlag) {
209  s = devLibInit();
210  if(s){
211  return s;
212  }
213  }
214 
215  s = addrVerify (addrType, base, size);
216  if (s) {
217  return s;
218  }
219 
220  if (size == 0) {
221  return S_dev_lowValue;
222  }
223 
224 #ifdef DEBUG
225  errlogPrintf ("Req Addr 0X%X Size 0X%X\n", base, size);
226 #endif
227 
228  epicsMutexMustLock(addrListLock);
229  pRange = (rangeItem *) ellFirst(&addrFree[addrType]);
230  while (TRUE) {
231  if (pRange->begin > base) {
232  pRange = NULL;
233 # ifdef DEBUG
234  errlogPrintf ("Unable to locate a free block\n");
235  devListAddressMap (&addrFree[addrType]);
236 # endif
237  break;
238  }
239  else if (base + (size - 1) <= pRange->end) {
240 # ifdef DEBUG
241  errlogPrintf ("Found free block Begin 0X%X End 0X%X\n",
242  pRange->begin, pRange->end);
243 # endif
244  break;
245  }
246 
247  pRange = (rangeItem *) ellNext (&pRange->node);
248  }
249  epicsMutexUnlock(addrListLock);
250 
251  if (pRange==NULL) {
252  report_conflict (addrType, base, size, pOwnerName);
253  return S_dev_addressOverlap;
254  }
255 
256  s = devInstallAddr(
257  pRange, /* item on the free list to be split */
258  pOwnerName,
259  addrType,
260  base,
261  size,
262  ppPhysicalAddress);
263 
264  return s;
265 }
266 
267 /*
268  * devInstallAddr()
269  */
270 static long devInstallAddr (
271  rangeItem *pRange, /* item on the free list to be split */
272  const char *pOwnerName,
273  epicsAddressType addrType,
274  size_t base,
275  size_t size,
276  volatile void **ppPhysicalAddress)
277 {
278  volatile void *pPhysicalAddress;
279  rangeItem *pNewRange;
280  size_t reqEnd = base + (size-1);
281  long status;
282 
283  /*
284  * does it start below the specified block
285  */
286  if (base < pRange->begin) {
287  return S_dev_badArgument;
288  }
289 
290  /*
291  * does it end above the specified block
292  */
293  if (reqEnd > pRange->end) {
294  return S_dev_badArgument;
295  }
296 
297  /*
298  * always map through the virtual os in case the memory
299  * management is set up there
300  */
301  status = (*pdevLibVirtualOS->pDevMapAddr) (addrType, 0, base,
302  size, &pPhysicalAddress);
303  if (status) {
304  errPrintf (status, __FILE__, __LINE__, "%s base=0X%X size = 0X%X",
305  epicsAddressTypeName[addrType], (unsigned int)base, (unsigned int)size);
306  return status;
307  }
308 
309  /*
310  * set the callers variable if the pointer is supplied
311  */
312  if (ppPhysicalAddress) {
313  *ppPhysicalAddress = pPhysicalAddress;
314  }
315 
316  /*
317  * does it start at the beginning of the block
318  */
319  if (pRange->begin == base) {
320  if (pRange->end == reqEnd) {
321  epicsMutexMustLock(addrListLock);
322  ellDelete(&addrFree[addrType], &pRange->node);
323  epicsMutexUnlock(addrListLock);
324  free ((void *)pRange);
325  }
326  else {
327  pRange->begin = base + size;
328  }
329  }
330  /*
331  * does it end at the end of the block
332  */
333  else if (pRange->end == reqEnd) {
334  pRange->end = base-1;
335  }
336  /*
337  * otherwise split the item on the free list
338  */
339  else {
340 
341  pNewRange = (rangeItem *) calloc (1, sizeof(*pRange));
342  if(!pNewRange){
343  return S_dev_noMemory;
344  }
345 
346  pNewRange->begin = base + size;
347  pNewRange->end = pRange->end;
348  pNewRange->pOwnerName = "<fragmented block>";
349  pNewRange->pPhysical = NULL;
350  pRange->end = base - 1;
351 
352  /*
353  * add the node after the old item on the free list
354  * (blocks end up ordered by address)
355  */
356  epicsMutexMustLock(addrListLock);
357  ellInsert(&addrFree[addrType], &pRange->node, &pNewRange->node);
358  epicsMutexUnlock(addrListLock);
359  }
360 
361  /*
362  * allocate a new address range entry and add it to
363  * the list
364  */
365  pNewRange = (rangeItem *)calloc (1, sizeof(*pRange));
366  if (!pNewRange) {
367  return S_dev_noMemory;
368  }
369 
370  pNewRange->begin = base;
371  pNewRange->end = reqEnd;
372  pNewRange->pOwnerName = pOwnerName;
373  pNewRange->pPhysical = pPhysicalAddress;
374 
375  devInsertAddress (&addrAlloc[addrType], pNewRange);
376 
377  return SUCCESS;
378 }
379 
380 /*
381  * report_conflict()
382  */
383 static void report_conflict (
384  epicsAddressType addrType,
385  size_t base,
386  size_t size,
387  const char *pOwnerName
388 )
389 {
390  const rangeItem *pRange;
391 
392  errPrintf (
393  S_dev_addressOverlap,
394  __FILE__,
395  __LINE__,
396  "%10s 0X%08X - OX%08X Requested by %s",
397  epicsAddressTypeName[addrType],
398  (unsigned int)base,
399  (unsigned int)(base+size-1),
400  pOwnerName);
401 
402  pRange = (rangeItem *) ellFirst(&addrAlloc[addrType]);
403  while (pRange) {
404 
405  if (pRange->begin <= base + (size-1) && pRange->end >= base) {
406  report_conflict_device (addrType, pRange);
407  }
408 
409  pRange = (rangeItem *) pRange->node.next;
410  }
411 }
412 
413 /*
414  * report_conflict_device()
415  */
416 static void report_conflict_device(epicsAddressType addrType, const rangeItem *pRange)
417 {
418  errPrintf (
419  S_dev_identifyOverlap,
420  __FILE__,
421  __LINE__,
422  "%10s 0X%08X - 0X%08X Owned by %s",
423  epicsAddressTypeName[addrType],
424  (unsigned int)pRange->begin,
425  (unsigned int)pRange->end,
426  pRange->pOwnerName);
427 }
428 
429 /*
430  * devUnregisterAddress()
431  */
433  epicsAddressType addrType,
434  size_t baseAddress,
435  const char *pOwnerName)
436 {
437  rangeItem *pRange;
438  int s;
439 
440  if (!devLibInitFlag) {
441  s = devLibInit();
442  if(s) {
443  return s;
444  }
445  }
446 
447  s = addrVerify (addrType, baseAddress, 1);
448  if (s != SUCCESS) {
449  return s;
450  }
451 
452  epicsMutexMustLock(addrListLock);
453  pRange = (rangeItem *) ellFirst(&addrAlloc[addrType]);
454  while (pRange) {
455  if (pRange->begin == baseAddress) {
456  break;
457  }
458  if (pRange->begin > baseAddress) {
459  pRange = NULL;
460  break;
461  }
462  pRange = (rangeItem *) ellNext(&pRange->node);
463  }
464  epicsMutexUnlock(addrListLock);
465 
466  if (!pRange) {
467  return S_dev_addressNotFound;
468  }
469 
470  if (strcmp(pOwnerName,pRange->pOwnerName)) {
471  s = S_dev_addressOverlap;
472  errPrintf (
473  s,
474  __FILE__,
475  __LINE__,
476  "unregister address for %s at 0X%X failed because %s owns it",
477  pOwnerName,
478  (unsigned int)baseAddress,
479  pRange->pOwnerName);
480  return s;
481  }
482 
483  epicsMutexMustLock(addrListLock);
484  ellDelete (&addrAlloc[addrType], &pRange->node);
485  epicsMutexUnlock(addrListLock);
486 
487  pRange->pOwnerName = "<released fragment>";
488  devInsertAddress (&addrFree[addrType], pRange);
489  s = devCombineAdjacentBlocks (&addrFree[addrType], pRange);
490  if(s){
491  errMessage (s, "devCombineAdjacentBlocks error");
492  return s;
493  }
494 
495  return SUCCESS;
496 }
497 
498 /*
499  * devCombineAdjacentBlocks()
500  */
501 static long devCombineAdjacentBlocks(
502  ELLLIST *pRangeList,
503  rangeItem *pRange)
504 {
505  rangeItem *pBefore;
506  rangeItem *pAfter;
507 
508  pBefore = (rangeItem *) ellPrevious (&pRange->node);
509  pAfter = (rangeItem *) ellNext (&pRange->node);
510 
511  /*
512  * combine adjacent blocks
513  */
514  if (pBefore) {
515  if (pBefore->end == pRange->begin-1) {
516  epicsMutexMustLock(addrListLock);
517  pRange->begin = pBefore->begin;
518  ellDelete (pRangeList, &pBefore->node);
519  epicsMutexUnlock(addrListLock);
520  free ((void *)pBefore);
521  }
522  }
523 
524  if (pAfter) {
525  if (pAfter->begin == pRange->end+1) {
526  epicsMutexMustLock(addrListLock);
527  pRange->end = pAfter->end;
528  ellDelete (pRangeList, &pAfter->node);
529  epicsMutexUnlock(addrListLock);
530  free((void *)pAfter);
531  }
532  }
533 
534  return SUCCESS;
535 }
536 
537 /*
538  * devInsertAddress()
539  */
540 static void devInsertAddress(
541 ELLLIST *pRangeList,
542 rangeItem *pNewRange)
543 {
544  rangeItem *pBefore;
545  rangeItem *pAfter;
546 
547  epicsMutexMustLock(addrListLock);
548  pAfter = (rangeItem *) ellFirst (pRangeList);
549  while (pAfter) {
550  if (pNewRange->end < pAfter->begin) {
551  break;
552  }
553  pAfter = (rangeItem *) ellNext (&pAfter->node);
554  }
555 
556  if (pAfter) {
557  pBefore = (rangeItem *) ellPrevious (&pAfter->node);
558  ellInsert (pRangeList, &pBefore->node, &pNewRange->node);
559  }
560  else {
561  ellAdd (pRangeList, &pNewRange->node);
562  }
563  epicsMutexUnlock(addrListLock);
564 }
565 
566 /*
567  * devAllocAddress()
568  */
570  const char *pOwnerName,
571  epicsAddressType addrType,
572  size_t size,
573  unsigned alignment, /* n ls bits zero in base addr*/
574  volatile void ** pLocalAddress )
575 {
576  int s;
577  rangeItem *pRange;
578  size_t base = 0;
579 
580  if (!devLibInitFlag) {
581  s = devLibInit();
582  if(s){
583  return s;
584  }
585  }
586 
587  s = addrVerify (addrType, 0, size);
588  if(s){
589  return s;
590  }
591 
592  if (size == 0) {
593  return S_dev_lowValue;
594  }
595 
596  epicsMutexMustLock(addrListLock);
597  pRange = (rangeItem *) ellFirst (&addrFree[addrType]);
598  while (pRange) {
599  if ((pRange->end - pRange->begin) + 1 >= size){
600  s = blockFind (
601  addrType,
602  pRange,
603  size,
604  alignment,
605  &base);
606  if (s==SUCCESS) {
607  break;
608  }
609  }
610  pRange = (rangeItem *) pRange->node.next;
611  }
612  epicsMutexUnlock(addrListLock);
613 
614  if(!pRange){
615  s = S_dev_deviceDoesNotFit;
616  errMessage(s, epicsAddressTypeName[addrType]);
617  return s;
618  }
619 
620  s = devInstallAddr (pRange, pOwnerName, addrType, base,
621  size, pLocalAddress);
622 
623  return s;
624 }
625 
626 /*
627  * addrVerify()
628  *
629  * care has been taken here not to overflow type size_t
630  */
631 static long addrVerify(epicsAddressType addrType, size_t base, size_t size)
632 {
633  if (addrType>=atLast) {
634  return S_dev_uknAddrType;
635  }
636 
637  if (size == 0) {
638  return addrFail[addrType];
639  }
640 
641  if (size-1 > addrLast[addrType]) {
642  return addrFail[addrType];
643  }
644 
645  if (base > addrLast[addrType]) {
646  return addrFail[addrType];
647  }
648 
649  if (size - 1 > addrLast[addrType] - base) {
650  return addrFail[addrType];
651  }
652 
653  return SUCCESS;
654 }
655 
656 /*
657  * devLibInit()
658  */
659 static long devLibInit (void)
660 {
661  rangeItem *pRange;
662  int i;
663 
664 
665  if(devLibInitFlag) return(SUCCESS);
666  if(!pdevLibVirtualOS) {
667  epicsPrintf ("pdevLibVirtualOS is NULL\n");
668  return S_dev_internal;
669  }
670 
671  if (NELEMENTS(addrAlloc) != NELEMENTS(addrFree)) {
672  return S_dev_internal;
673  }
674 
675  addrListLock = epicsMutexMustCreate();
676 
677  epicsMutexMustLock(addrListLock);
678  for (i=0; i<NELEMENTS(addrAlloc); i++) {
679  ellInit (&addrAlloc[i]);
680  ellInit (&addrFree[i]);
681  }
682 
683  for (i=0; i<NELEMENTS(addrAlloc); i++) {
684  pRange = (rangeItem *) malloc (sizeof(*pRange));
685  if (!pRange) {
686  return S_dev_noMemory;
687  }
688  pRange->pOwnerName = "<Vacant>";
689  pRange->pPhysical = NULL;
690  pRange->begin = 0;
691  pRange->end = addrLast[i];
692  ellAdd (&addrFree[i], &pRange->node);
693  }
694  epicsMutexUnlock(addrListLock);
695  devLibInitFlag = TRUE;
696  return pdevLibVirtualOS->pDevInit();
697 }
698 
699 /*
700  * devAddressMap()
701  */
702 long devAddressMap2(void)
703 {
704  return devListAddressMap(addrAlloc);
705 }
706 
707 /*
708  * devListAddressMap()
709  */
710 static long devListAddressMap(ELLLIST *pRangeList)
711 {
712  rangeItem *pri;
713  int i;
714 
715  if (!devLibInitFlag) {
716  long s = devLibInit ();
717  if (s) {
718  return s;
719  }
720  }
721  errlogFlush();
722 
723  epicsMutexMustLock(addrListLock);
724  for (i=0; i<NELEMENTS(addrAlloc); i++) {
725  pri = (rangeItem *) ellFirst(&pRangeList[i]);
726  if (pri) {
727  errlogPrintf ("%s Address Map\n", epicsAddressTypeName[i]);
728  }
729  while (pri) {
730  errlogPrintf ("\t0X%0*lX - 0X%0*lX physical base %p %s\n",
731  addrHexDig[i],
732  (unsigned long) pri->begin,
733  addrHexDig[i],
734  (unsigned long) pri->end,
735  pri->pPhysical,
736  pri->pOwnerName);
737  pri = (rangeItem *) ellNext (&pri->node);
738  }
739  }
740  epicsMutexUnlock(addrListLock);
741 
742  return SUCCESS;
743 }
744 
745 
746 /*
747  *
748  * blockFind()
749  *
750  * Find unoccupied block in a large block
751  *
752  */
753 static long blockFind (
754  epicsAddressType addrType,
755  const rangeItem *pRange,
756  /* size needed */
757  size_t requestSize,
758  /* n ls bits zero in base addr */
759  unsigned alignment,
760  /* base address found */
761  size_t *pBase)
762 {
763  int s = SUCCESS;
764  size_t bb;
765  size_t mask;
766  size_t newBase;
767  size_t newSize;
768 
769  /*
770  * align the block base
771  */
772  mask = devCreateMask (alignment);
773  newBase = pRange->begin;
774  if ( mask & newBase ) {
775  newBase |= mask;
776  newBase++;
777  }
778 
779  if ( requestSize == 0) {
780  return S_dev_badRequest;
781  }
782 
783  /*
784  * align size of block
785  */
786  newSize = requestSize;
787  if (mask & newSize) {
788  newSize |= mask;
789  newSize++;
790  }
791 
792  if (pRange->end - pRange->begin + 1 < newSize) {
793  return S_dev_badRequest;
794  }
795 
796  bb = pRange->begin;
797  while (bb <= (pRange->end + 1) - newSize) {
798  s = devNoResponseProbe (addrType, bb, newSize);
799  if (s==SUCCESS) {
800  *pBase = bb;
801  return SUCCESS;
802  }
803  bb += newSize;
804  }
805 
806  return s;
807 }
808 
809 #include <epicsExport.h>
810 
812 {
814 }
815 
#define SUCCESS
Definition: devLibVME.c:142
long devAddressMap2(void)
Definition: devLibVME.c:702
volatile void * pPhysical
Definition: devLibVME.c:82
epicsExportRegistrar(devReplaceVirtualOS)
long devRegisterAddress2(const char *pOwnerName, epicsAddressType addrType, size_t base, size_t size, volatile void **ppPhysicalAddress)
Definition: devLibVME.c:198
devLibVirtualOS * pdevLibVirtualOS
Definition: devlib_dummy.c:86
long devUnregisterAddress2(epicsAddressType addrType, size_t baseAddress, const char *pOwnerName)
Definition: devLibVME.c:432
devLibVirtualOS * pdevLibVME2
size_t end
Definition: devLibVME.c:89
ELLNODE node
Definition: devLibVME.c:80
const char * pOwnerName
Definition: devLibVME.c:81
void devReplaceVirtualOS(void)
Definition: devLibVME.c:811
long devNoResponseProbe(epicsAddressType addrType, size_t base, size_t size)
Definition: devlib_dummy.c:30
long devBusToLocalAddr2(epicsAddressType addrType, size_t busAddr, volatile void **ppLocalAddress)
Definition: devLibVME.c:147
long devAllocAddress2(const char *pOwnerName, epicsAddressType addrType, size_t size, unsigned alignment, volatile void **pLocalAddress)
Definition: devLibVME.c:569
size_t begin
Definition: devLibVME.c:88
const char * epicsAddressTypeName[]
Definition: devlib_dummy.c:24
#define atLast
Definition: devLibVME.h:40
const char * epicsAddressTypeName2[]
Definition: devLibVME.c:71