smLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:38k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* smLib.c - VxWorks common shared memory library */
  2. /* Copyright 1984-2002 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 02s,03may02,mas  cache flush and volatile fix (SPR 68334); bridge flush fix
  7.  (SPR 68844)
  8. 02r,14nov01,mas  added smLibInit() for future common code base upgrade
  9. 02q,24oct01,mas  doc update (SPR 71149)
  10. 02p,20sep01,jws  eliminate min 5000 tries in smLockTake() (SPR68418)
  11. 02o,17mar99,dat  added docs about SM_INT_USER_1/2, SPR 25804
  12. 02n,21feb99,jdi  doc: listed errnos.
  13. 02m,18mar98,dat  added exponential backoff with limits, (more SPR 9312)
  14. 02l,05dec97,dat  rework SPR 9312, add global variable smLockTakeDelayCnt.
  15. 02k,29sep97,dat  SPR 9312, fixed smLockTake retry loop.
  16. 02j,14jul93,wmd  Removed ntohl for anchorLocalAddr in smSetup() (SPR #2282).
  17. 02i,10feb93,pme  Changed smLockTake retry time calculation.
  18. 02h,29sep92,pme  Suppressed warning message in smLockTake.
  19.  Added write pipe flush calls where needed.
  20. 02g,02aug92,kdl  Uncommented include of "copyright_wrs.h".
  21. 02f,24jul92,elh  Moved heartbeat from anchor to header.
  22. 02e,13jul92,elh  Added tasClear functionality. Added pme's changes to
  23.  smLockTake.
  24. 02d,02jun92,elh  the tree shuffle
  25. 02c,27may92,elh  Further split up the library.  Changed to use offsets,
  26.  Made completely independent.  General cleanup.
  27. 02b,20may92,pme+ Removed pkt specific data structures (and routines
  28.     elh  that use them to their corrosponding files.
  29. 02a,14may92,pme  Splitted to keep only routines common to backplane driver
  30.  and shared memory objects.
  31. 01e,20feb92,elh  Added in ntohl, and htonl for 960, Added USE_OFFSET.
  32.  Extracted and renamed OS specific calls & moved to
  33.  smUtilLib.  Also removed function pointers
  34.  shMemIntGenFunc and shMemHwTasFunc.
  35.  made TAS_CHECKS 10 TAS_TRIES 5000.
  36.  modified parameters passed to intGen function.
  37. 01d,10feb92,kdl+ Changed shMemDetach to flush input queue.
  38.     elh  Removed references to OK_WAS{EMPTY, NT_EMPTY}.
  39.  Made shMemSend return an ERROR if packet too large.
  40.  Changed shMemSend to return silently (no
  41.  interrupts generated) if sending to self.
  42.  Misc code review changes.
  43. 01c,05feb92,elh  ansified.
  44. 01b,27jan92,elh  added masterCpu to shared memory anchor.
  45.  changed shMemBeat to take pAnchor as argument.
  46.  changed arguments to shMemIsAlive.
  47.  changed shMemSetup to probe memory.
  48.  changed copyright.
  49. 01a,15aug90,kdl  written.
  50. */
  51. /*
  52. DESCRIPTION
  53. This library contains the shared memory routines which are common
  54. to the shared memory libraries: smPktLib and smObjLib.  
  55. It provides basic shared memory functionality such as shared 
  56. memory attachment, detachment and lock synchronization.
  57. SHARED MEMORY MASTER CPU
  58. One CPU node acts as the shared memory master.  This CPU initializes
  59. the shared memory header and sets up the shared memory anchor.  These
  60. steps are performed by the master calling the smSetup() routine.
  61. This routine should be called only by the shared memory master CPU,
  62. and it should only be called once for a given shared memory region.
  63. (It is, however, possible to maintain and use multiple separate
  64. shared memory regions.)
  65. Once smSetup() has completed successfully, there is little functional
  66. difference between the master CPU and other CPU's using shared memory,
  67. except that the master is responsible for maintaining the shared memory
  68. packet and shared memory object heartbeats in
  69. the shared memory header regions.
  70. SHARED MEMORY ANCHOR
  71. The shared memory anchor is a small data structure which is at
  72. a predetermined location, to allow all CPU's using shared memory to
  73. find it.  The shared memory anchor contains the base offset to the
  74. actual shared memory header.  (This allows the master CPU to 
  75. dynamically allocate the shared memory region.)  Another field in 
  76. the anchor contains a "ready value" which is set to a specific 
  77. value when the master CPU has completed initializing the shared memory 
  78. region.
  79. The shared memory anchor does not have to be defined as part of the
  80. shared memory region.  However, it must be located in a similar 
  81. address space; the address translation constants which CPU boards use 
  82. to convert local addresses to bus addresses must apply equally to the 
  83. anchor and the regular shared memory region.
  84. ATTACHING TO SHARED MEMORY
  85. Each CPU, master or non-master, which will use the shared memory region
  86. must attach itself to the shared memory.  The shared memory region must
  87. have already been initialized by the master CPU calling smSetup().
  88. The first step in attaching to shared memory is for each CPU to allocate and
  89. initialize a shared memory descriptor (SM_DESC).  This structure describes
  90. the individual CPU's attachment to the shared memory region and is used
  91. in all subsequent shared memory calls to identify which shared memory
  92. region is being used.  Since the shared memory descriptor is used only
  93. by the local CPU, it is not necessary for the descriptor itself to be
  94. located in shared memory.  In fact, it is preferable for the descriptor
  95. to be allocated from the CPU's local memory, since local memory is usually
  96. more efficient to access.
  97. The shared memory descriptor is initialized by calling the smInit()
  98. routine.  This routine takes a number of parameters which specify the
  99. characteristics of this CPU and its access to shared memory.
  100. After the shared memory descriptor has been initialized, the CPU may
  101. attach itself to the shared memory region.  This is done by calling the
  102. smAttach() routine. 
  103. DETACHING FROM SHARED MEMORY
  104. The attachment of a CPU to shared memory may be ended by calling
  105. smDetach().  This routine will mark the calling CPU as no longer
  106. attached.  The CPU may re-attach itself to the shared memory region by 
  107. later calling smAttach().  (When re-attaching, the original shared 
  108. memory descriptor may be re-used if the CPU's configuration remains 
  109. the same, or new values may be specified via smInit().)
  110. INTERRUPTS
  111. There must be some method for a CPU to be notified of an occuring event.
  112. The preferred method is for the CPU initiating the event to interrupt the 
  113. affected CPU.  This will be highly dependent on the specific hardware being 
  114. used.  If interrupts cannot be used, a polling scheme may be employed, but 
  115. this is much less efficient.
  116. Three types of interrupts are supported, mailbox interrupts, vme
  117. bus interrupts, and user defined interrupts.  Mailbox interrupts are the
  118. first preferred method (SM_INT_MAILBOX), followed by bus (backplane) interrupts
  119. (SM_INT_BUS).  If interrupts cannot be used, a polling scheme may be employed 
  120. (SM_INT_NONE), but this is much less efficient. 
  121. The user interrupt types (SM_INT_USER_1 and SM_INT_USER_2) allow the BSP
  122. writer to specify a routine to be used
  123. to generate an interrupt in another CPU.  The three interrupt arguments
  124. are passed to the
  125. user's routine.  When using this method, the user is responsible for calling
  126. the smUtilIntRoutine(), when an incoming signal (interrupt) is detected.
  127. The routine smUtilIntRoutine() will process any data packets in the list
  128. for the local cpu.  The global variable <smUtilUser1Rtn> is a pointer to the
  129. user routine for SM_INT_USER_1 .  The variable <smUtilUser2Rtn> is the pointer
  130. for the SM_INT_USER_2 routine.
  131. When a CPU initailizes its shared memory descriptor via the smInit() call, 
  132. it passes in an interrupt type as well as three interrupt arguments.  This 
  133. describes how the cpu wishes to be notified of events.  The interrupt 
  134. types recognized by this library are listed in smLib.h. These values may 
  135. be obtained for any attached CPU by calling smCpuInfoGet().  
  136. The default interrupt method for a particular target is defined by 
  137. the configuration parameters: SM_INT_TYPE, SM_INT_ARG1, SM_INT_ARG2, 
  138. and SM_INT_ARG3 .
  139. When a CPU wishs to notify a destination CPU of an event, the sending 
  140. CPU will call smUtilIntGen(), to interrupt the destination CPU.
  141. smUtilIntGen() should return OK if the destination CPU was
  142. successfully notified, or ERROR if it was not.
  143. If it is not possible to use interrupts to notify receiving CPU's, a
  144. polling method may be used.  
  145. INTERNAL
  146. This file runs under only vxWorks.  SunOS is no longer supported.
  147. The shared memory libaries are split into mulitple files.
  148. Below is the internal layout of the shared memory libraries:
  149.                    ___________
  150. shared memory object              | smObjLib|
  151. library                       / __________ 
  152.                  /
  153. shared memory ____________     /
  154. packet library | smPktLib |    / 
  155. ____________   /
  156.      |       /
  157.      v       /
  158. ____________v
  159. common shared memory | smLib     |
  160. library _____________
  161.      |
  162.      v
  163. shared memory           _____________   
  164. support routines | smUtilLib |
  165. _____________
  166. is
  167. i `smObjLib'
  168. Contains the share memory object routines.
  169. i `smPktLib'
  170. Contains the shared memory packet routines.  It provides 
  171. packet passing functionality to send and retreive data packets over 
  172. the backplane using shared memory.  It is used by the backplane driver.
  173. i `smLib'
  174. Contains routines the shared memory routines that are common
  175. to backplane driver and the shared memory objects:  
  176. i `smUtilLib'
  177. Contains the OS specific routines needed by the shared 
  178. memory libraries.  This module should be provided for each OS 
  179. for which shared memory is ported and must 
  180. contain at a minimum the following routines:
  181. cs
  182. smUtilMemProbe - probe memory to see if it exists 
  183. smUtilSofTas - software test-and-set routine 
  184. smUtilTas - hardware test-and-set routine
  185. smUtilTasClear - clear hardware test-and-set routine
  186. smUtilProcNumGet- get processor number
  187. smUtilDelay - delay for specified number of time 
  188. smUtilRateGet - get number of ticks per second 
  189. intLock - lock out interrupts
  190. intUnlock - unlock interrupts
  191. smUtilIntGen - interrupt generation routine
  192. smUtilIntConnect- connect one or more routine to shared memory 
  193.           interrupt.
  194. smUtilIntRoutine- shared memory interrupt routine
  195. smUtilPollTask  - shared memory polling task
  196. ce
  197. ie
  198. SHARED MEMORY LOCK
  199. The routines smLockTake() and smLockGive() are used to achieve the necessary
  200. inter-processor locks.  The routine that is called to perform a Test and
  201. Set (TAS) primitive is one of the calling arguments.  The delay algorithm
  202. between TAS attempts is an exponential one.  The delay between retries is
  203. twice as great as the previous delay, until the delay reaches a maximum
  204. value and is then reset to its starting value.  The following variables
  205. can be tuned to give best performance for any specific CPU and clock
  206. combination.
  207. cs
  208.    int smLockTakeDelayMin = 256;
  209.    int smLockTakeDelayMax = 1*1024*1024;
  210. ce
  211. The minimum number of retries (>= 1) to be attempted is specified as an
  212. argument to smLockTake().  (One retry is always made if the first attempt
  213. fails, even if the minimum number of retries is specified as zero.)
  214. INTERNAL
  215. There needs to be better documentation discussing the interfaces
  216. and functionality of the OS specific library, smUtilLib.
  217. SEE ALSO: tb VxWorks Programmer's Guide: Shared-Memory Objects,  
  218. tb VxWorks Network Programmer's Guide: Data Link Layer Network Components.
  219. */
  220. /* Includes */
  221. #include "vxWorks.h"
  222. #include "cacheLib.h"
  223. #include "smLib.h"
  224. #include "smUtilLib.h"
  225. /* Defines */
  226. #define SM_VERSION 1 /* protocol version for sh mem anchor */
  227. /* Globals */
  228. int smAliveTimeout   = DEFAULT_ALIVE_TIMEOUT;
  229. /* current maximum # of tries to get lock used for statistics */
  230. int  smCurMaxTries = 0;
  231. int smLockTakeDelayMin = 256;
  232. int smLockTakeDelayMax = 1*1024*1024;
  233. /* Locals */
  234. LOCAL BOOL smLibInitialized = FALSE;
  235. LOCAL int smRegionsMax   = SM_REGIONS_MAX;
  236. LOCAL SM_REGION smRegions [SM_REGIONS_MAX];
  237. /* Forward declarations */
  238. LOCAL int smRegionGet (SM_ANCHOR * anchorLocalAdrs);
  239. LOCAL int smRegionFind (SM_ANCHOR * anchorLocalAdrs);
  240. /******************************************************************************
  241. *
  242. * smLibInit - initialize the shared memory library and shared memory region
  243. *
  244. * This routine is normally called only by the system startup code during
  245. * kernel initialization.  It prepares the library and locates the shared
  246. * memory region via either static lookup or dynamic allocation.  A static
  247. * lookup is first attempted if <pRgnCfgTbl> is not NULL.  If the shared
  248. * memory region is not found or <pRgnCfgTbl> is NULL, an uncached shared
  249. * memory region of size <objSize> + <netSize> is allocated from the kernel
  250. * heap.
  251. *
  252. * INTERNAL
  253. * This routine is a place holder until a common code base version of smLib is
  254. * created.  The input arguments are identical with those used in AE.
  255. *
  256. * RETURNS: N/A
  257. *
  258. * NOMANUAL
  259. */
  260. void smLibInit
  261.     (
  262.     void * pRgnCfgTbl, /* address of memory configuration table */
  263.     UINT   objSize, /* shared object region size */
  264.     UINT   netSize /* shared memory network region size */
  265.     )
  266.     {
  267.     /* NOT YET IMPLEMENTED */
  268.     if (pRgnCfgTbl == NULL)
  269.         ;
  270.     if (objSize == netSize)
  271.         ;
  272.     }
  273. /******************************************************************************
  274. *
  275. * smSetup - set up shared memory (master CPU only)
  276. *
  277. * This routine should be called only by the master CPU using shared
  278. * memory.  It initializes the specified memory area for use by the
  279. * shared memory protocol.  This includes initializing the shared memory
  280. * anchor and the shared memory header.
  281. *
  282. * After the shared memory has been initialized, this and other CPU's
  283. * may initialize a shared memory descriptor to it, using smInit(),
  284. * and then attach to the shared memory area, using smAttach().
  285. *
  286. * The <anchorLocalAdrs> parameter is the memory address by which the master
  287. * CPU accesses the actual shared memory anchor region to be initialized.
  288. *
  289. * The <smLocalAdrs> parameter is the memory address by which the master
  290. * CPU accesses the actual shared memory region to be initialized.
  291. *
  292. * The shared memory routines must be able to obtain exclusive access to
  293. * shared data structures.  To allow this, a test-and-set operation is
  294. * used.  It is preferable to use a genuine test-and-set instruction, if
  295. * the hardware being used permits this.  If this is not possible, smLib
  296. * provides a software emulation of test-and-set.  The <tasType> parameter
  297. * specifies what method of test-and-set is to be used.
  298. *
  299. * The <maxCpus> parameter specifies the maximum number of CPU's which may
  300. * use the shared memory region.
  301. *
  302. * The amount of shared memory taken as a result of the call, gets returned
  303. * in <pMemUsed>
  304. *
  305. * INTERNAL
  306. * The first item in the shared memory area is the shared memory header (SM_HDR).
  307. * Following this is an array of CPU descriptors (SM_CPU_DESC); this table
  308. * contains one CPU descriptor for each possible CPU, as specified by <maxCpus>.
  309. *
  310. * RETURNS: OK, or ERROR.
  311. *
  312. * ERRNO: S_smLib_MEMORY_ERROR
  313. */
  314. STATUS smSetup
  315.     (
  316.     SM_ANCHOR * anchorLocalAdrs, /* local addr of anchor */
  317.     char * smLocalAdrs, /* local addr of sh mem area */
  318.     int tasType, /* method of test-and-set */
  319.     int maxCpus, /* max number of cpu's */
  320.     int * pMemUsed /* amount of memory used */
  321.     )
  322.     {
  323.     SM_ANCHOR volatile * pAnchorv = (SM_ANCHOR volatile *) anchorLocalAdrs;
  324.     SM_HDR volatile *  pHdr; /* local addr of sh mem hdr */
  325.     char  temp = 0; /* temp location */
  326.     /* Initialize shared memory region table */
  327.     if (!smLibInitialized)
  328. {
  329. bzero ((char *) smRegions, sizeof (smRegions));
  330. smLibInitialized = TRUE;
  331. }
  332.     /* Probe shared memory */
  333.     if (smUtilMemProbe (smLocalAdrs, VX_WRITE, sizeof (char), &temp) != OK)
  334.         {
  335.         errno = S_smLib_MEMORY_ERROR;
  336. return (ERROR);
  337. }
  338.     /* Find the Region */
  339.     if (smRegionFind (anchorLocalAdrs) != ERROR)
  340. {
  341. pHdr = SM_OFFSET_TO_LOCAL (ntohl (pAnchorv->smHeader), (int) pAnchorv,
  342.                                    SM_HDR volatile *);
  343. if ((ntohl (pHdr->maxCpus) != maxCpus) ||
  344.     (ntohl (pHdr->tasType) != tasType))
  345.     printf ("smSetup:Warning! previous parameters differ!n");
  346. *pMemUsed = 0;
  347. return (OK);
  348. }
  349.     if (smRegionGet (anchorLocalAdrs) == ERROR)
  350. return (ERROR);
  351.     *pMemUsed = sizeof (SM_HDR) + (maxCpus * sizeof (SM_CPU_DESC));
  352.     /* Partially initialize shared memory header */
  353.     bzero (smLocalAdrs, *pMemUsed);
  354.     pHdr     = (SM_HDR volatile *) smLocalAdrs; /* header = SM start */
  355.     pHdr->tasType  = htonl (tasType); /* test-and-set method */
  356.     pHdr->maxCpus  = htonl (maxCpus); /* max number of cpu's */
  357.     pHdr->cpuTable = htonl (SM_LOCAL_TO_OFFSET (pHdr + sizeof (SM_HDR),
  358.         (int) anchorLocalAdrs));
  359.     /* Set up the anchor */
  360.     bzero ((char *) pAnchorv, sizeof (SM_ANCHOR));
  361.     pAnchorv->version    = htonl (SM_VERSION);  /* sh mem version */
  362.     pAnchorv->smHeader   = htonl (SM_LOCAL_TO_OFFSET (pHdr, (int) pAnchorv));
  363.     pAnchorv->masterCpu  = htonl (SM_MASTER); /* sh mem  master */
  364.     pAnchorv->readyValue = htonl (SM_READY);  /* sh mem available */
  365.     CACHE_PIPE_FLUSH ();                /* CACHE FLUSH   [SPR 68334] */
  366.     maxCpus = pHdr->maxCpus; /* BRIDGE FLUSH  [SPR 68334] */
  367.     return (OK); /* shared mem init complete */
  368.     }
  369. /******************************************************************************
  370. *
  371. * smInit - initialize shared memory descriptor
  372. *
  373. * This routine initializes a shared memory descriptor.  The descriptor
  374. * must have been previously allocated (generally in the CPU's local
  375. * memory).  Once the descriptor has been initialized by this routine,
  376. * the CPU may attach itself to the shared memory area by calling
  377. * smAttach().
  378. *
  379. * Only the shared memory descriptor itself is modified by this routine.
  380. * No structures in shared memory are affected.
  381. *
  382. * The <pSmDesc> paramter is the address of the shared memory descriptor
  383. * which is to be initialized; this structure must have already been
  384. * allocated before smInit() is called.
  385. *
  386. * The <anchorLocalAdrs> parameter is the memory address by which the local
  387. * CPU may access the shared memory anchor.  This address may vary for
  388. * different CPU's because of address offsets (particularly if the anchor is
  389. * located in one CPU's dual-ported memory).
  390. *
  391. * The <ticksPerBeat> parameter specifies the frequency of the shared memory
  392. * anchor's heartbeat.  The frequency is expressed in terms of how many CPU
  393. * ticks on the local CPU correspond to one heartbeat period.
  394. *
  395. * The <intType>, <intArg1>, <intArg2>, and <intArg3> parameters allow a
  396. * CPU to announce the method by which it is to be notified of input packets
  397. * which have been queued to it.  Once this CPU has attached to the shared
  398. * memory region, other CPU's will be able to determine these interrupt
  399. * parameters by calling smCpuInfoGet().  
  400. *
  401. * RETURNS: N/A
  402. */
  403. void smInit
  404.     (
  405.     SM_DESC * pSmDesc,  /* sh mem descr to init*/
  406.     SM_ANCHOR * anchorLocalAdrs, /* local addr of sh mem anchor*/
  407.     int ticksPerBeat,  /* cpu ticks per heartbeat */
  408.     int intType,  /* interrupt method */
  409.     int intArg1,  /* interrupt argument #1 */
  410.     int intArg2,  /* interrupt argument #2 */
  411.     int intArg3  /* interrupt argument #3 */
  412.     )
  413.     {
  414.     if (pSmDesc == NULL)
  415. return; /* don't use null ptr */
  416.     bzero ((char *) pSmDesc, sizeof (SM_DESC));
  417.     /* Copy input parameters */
  418.     pSmDesc->anchorLocalAdrs  = anchorLocalAdrs;
  419.     pSmDesc->base       = (int) anchorLocalAdrs;
  420.     pSmDesc->cpuNum       = smUtilProcNumGet ();
  421.     pSmDesc->ticksPerBeat     = (ticksPerBeat == 0) ? smUtilRateGet () :
  422.       ticksPerBeat;
  423.     pSmDesc->intType       = intType;
  424.     pSmDesc->intArg1       = intArg1;
  425.     pSmDesc->intArg2       = intArg2;
  426.     pSmDesc->intArg3       = intArg3;
  427.     pSmDesc->status       = SM_CPU_NOT_ATTACHED; /* initial status */
  428.     }
  429. /******************************************************************************
  430. *
  431. * smIsAlive - determine if shared memory is initialized and active
  432. *
  433. * This routine examines the shared memory anchor and heartbeat to
  434. * determine whether the shared memory has been initialized and that
  435. * it is running.  The shared memory is specified by <pAnchor>, the
  436. * address of the shared memory anchor.  If the shared
  437. * memory network is active, TRUE is returned; otherwise, FALSE is
  438. * returned.  <pHeader> points to the location of the header containing
  439. * the heartbeat.  <base> is the base address from which to calculate the
  440. * address of the heartbeat counter in the header in shared memory.
  441. *
  442. * The anchor ready-value must contain the special value SM_READY to
  443. * indicate that the master CPU has successfully initialized the shared
  444. * memory region.  The heartbeat must increment at least twice
  445. * within the timeout period to be recognized as active.
  446. *
  447. * <heartBeats> specifies the number of beats to wait for a correct
  448. * ready-value and active heartbeat before timing out.  A zero value
  449. * indicates the use of a default value, specified by the global variable 
  450. * 'smAliveTimeout'.
  451. *
  452. * <ticksPerBeat> specifies the number of ticks per heartbeat.
  453. *
  454. * This routine safely probes the anchor addresses to avoid bus errors
  455. * (in case the anchor address is not yet accessable).  Occasional
  456. * messages are written to standard output if a bus error occurs but is
  457. * handled.  Occasional messages will also appear to indicate the most
  458. * recently obtained values for the ready-value and heartbeat.
  459. *
  460. * This routine may not be called from interrupt level.
  461. *
  462. * This routine does not set errno.
  463. *
  464. * RETURNS: TRUE or FALSE.
  465. */
  466. BOOL smIsAlive
  467.     (
  468.     SM_ANCHOR * pAnchor, /* ptr to shared mem anchor */
  469.     int * pHeader, /* {smObj/smPkt} header */
  470.     int base, /* base */
  471.     int heartBeats, /* heartbeat periods */
  472.     int  ticksPerBeat    /* ticks per beat */
  473.     )
  474.     {
  475.     UINT readyValue;        /* ready value from anchor */
  476.     UINT newHeartBeat;      /* beat value from anchor */
  477.     UINT oldHeartBeat;      /* saved beat value */
  478.     int incCnt;            /* number of beat increments observed*/
  479.     int * pHeartBeat = NULL; /* ptr to heartbeat */
  480.     int temp;              /* temp storage */
  481.     newHeartBeat = 0; /* init beat values */
  482.     oldHeartBeat = 0;
  483.     incCnt = 0;
  484.     /* Determine number of heartbeat periods to wait */
  485.     if (ticksPerBeat == 0)
  486.         {
  487. ticksPerBeat = smUtilRateGet ();
  488.         }
  489.     if (heartBeats == 0)
  490.         {
  491. heartBeats = smAliveTimeout * (smUtilRateGet ()) / ticksPerBeat;
  492.         }
  493.     /* Check anchor and heartbeat until ready or countdown expires */
  494.     while (heartBeats-- > 0)
  495. {
  496. /* XXX - invalidate data cache here ?? */
  497. /* Probe and get anchor ready-value */
  498. if (smUtilMemProbe ((char *) &pAnchor->readyValue, VX_READ, 
  499.     sizeof (int), (char *) &readyValue) != OK)
  500.     {
  501.     if ((heartBeats % 10) == 8) /* print error occasionally */
  502.                 {
  503.                 printf ("nsmIsAlive: bus error checking anchorn");
  504.                 }
  505.     }
  506. readyValue = ntohl (readyValue);
  507. if (readyValue == SM_READY) /* if anchor appears ready */
  508.     {
  509.     /*
  510.      * Calculate the location of the heartbeat.
  511.      * The heartbeat must be the first location in {smPkt/smObj}
  512.      * header. 
  513.      */
  514.             CACHE_PIPE_FLUSH (); /* FLUSH BUFFER  [SPR 68334] */
  515.             temp = *(int *)pHeader; /* PCI bridge bug [SPR 68844]*/
  516.     pHeartBeat = SM_OFFSET_TO_LOCAL (ntohl (*pHeader), base, int *);
  517.     /* Probe and get heartbeat value */
  518.     if (smUtilMemProbe ((char *) pHeartBeat, VX_READ, sizeof (int),
  519. (char *) &newHeartBeat) == OK)
  520. {
  521. newHeartBeat = ntohl (newHeartBeat);
  522.      /* Check if heartbeat incremented */
  523.      if ((newHeartBeat <= oldHeartBeat) || (oldHeartBeat == 0))
  524.          {
  525.          oldHeartBeat = newHeartBeat; /* no beat - try again */
  526.          }
  527.      else /* beat incremented! */
  528.          {
  529.     if (++incCnt >= 2) /* if 2 incr's have been seen*/
  530.         {
  531.           return (TRUE); /* SHARED MEM IS ALIVE & WELL*/
  532.         }
  533.          }
  534. }
  535.     else /* could not probe heartbeat */
  536.      {
  537. if ((heartBeats % 10) == 8) /* print error occasionally */
  538.     {
  539.          printf ("nsmIsAlive: bus error getting heartbeatn");
  540.     }
  541.      }
  542.     }  /* end if (readyValue) */
  543. /* Occasionally display last obtained ready-value and heartbeat */
  544. if ((heartBeats % 10) == 6)
  545.     {
  546.     printf ("smIsAlive:  readyValue = 0x%x, heartbeat = 0x%xn",
  547.     readyValue, newHeartBeat);
  548.     }
  549. /* Wait before checking heartbeat again */
  550. if (smUtilDelay ((char *) pHeartBeat, ticksPerBeat) != OK)
  551.     { /* wait enough for 1 beat */
  552.     return (FALSE); /* called from int level?? */
  553.     }
  554. }  /* end while */
  555.     return (FALSE); /* timed out */
  556.     }
  557. /******************************************************************************
  558. *
  559. * smAttach - attach a node to shared memory
  560. *
  561. * This routine "attaches" the local CPU to a shared memory area.  The
  562. * shared memory area is identified by the shared memory descriptor
  563. * whose address specified by <pSmDesc>.  The descriptor must have
  564. * already been initialized by calling smInit().
  565. *
  566. * This routine should get called only after and when the shared memory has
  567. * been initialized by the master CPU.  To determine this, smIsAlive() must
  568. * have been called to check the shared memory anchor for both the proper 
  569. * value (SM_READY_VALUE) in the anchor's ready-value field and an 
  570. * active heartbeat.
  571. *
  572. * The attachment to shared memory may be ended by calling smDetach().
  573. *
  574. * RETURNS: OK, or ERROR.
  575. *
  576. * ERRNO: S_smLib_INVALID_CPU_NUMBER
  577. *
  578. * SEE ALSO: smIsAlive(), smInit()
  579. */
  580. STATUS smAttach
  581.     (
  582.     SM_DESC * pSmDesc /* ptr to shared mem descriptor */
  583.     )
  584.     {
  585.     SM_HDR volatile *    pHdr;        /* ptr to shared mem header */
  586.     SM_CPU_DESC volatile * pCpuDesc;    /* ptr to shared mem cpu descriptor */
  587.     int    cpuNum;      /* this cpu's number */
  588.     int    temp;        /* temp storage */
  589.     cpuNum = pSmDesc->cpuNum;
  590.     /* Get local address for shared mem header */
  591.     CACHE_PIPE_FLUSH (); /* FLUSH BUFFER  [SPR 68334] */
  592.     temp = pSmDesc->anchorLocalAdrs->smHeader; /* PCI bridge bug [SPR 68844]*/
  593.     pHdr = SM_OFFSET_TO_LOCAL (ntohl (pSmDesc->anchorLocalAdrs->smHeader),
  594.                                pSmDesc->base, SM_HDR volatile *);
  595.     pSmDesc->headerLocalAdrs = (SM_HDR *) pHdr;
  596.     /* Copy data from shared mem header */
  597.     pSmDesc->maxCpus         = ntohl (pHdr->maxCpus);
  598.     pSmDesc->cpuTblLocalAdrs = SM_OFFSET_TO_LOCAL (ntohl (pHdr->cpuTable),
  599.                                                    pSmDesc->base,
  600.                                                    SM_CPU_DESC *);
  601.     /* Determine test-and-set routine to use */
  602.     pSmDesc->tasClearRoutine = NULL;
  603.     if (ntohl (pHdr->tasType) == SM_TAS_HARD)   /* if using hardware tas */
  604. {
  605.         pSmDesc->tasRoutine = smUtilTas;
  606.         pSmDesc->tasClearRoutine = (FUNCPTR) smUtilTasClear; 
  607. }
  608.     else
  609.         pSmDesc->tasRoutine = smUtilSoftTas;    /* use software tas routine */
  610.     /* Init entry in cpu table */
  611.     if (cpuNum < 0  ||  cpuNum >= pSmDesc->maxCpus)
  612.         {
  613.         errno = S_smLib_INVALID_CPU_NUMBER;
  614.         return (ERROR);                         /* cpu number out of range */
  615.         }
  616.     /* calculate addr of cpu desc in global table.  */
  617.     pCpuDesc = (SM_CPU_DESC volatile *) &((pSmDesc->cpuTblLocalAdrs) [cpuNum]);
  618.     pCpuDesc->intType = htonl (pSmDesc->intType); /* interrupt method */
  619.     pCpuDesc->intArg1 = htonl (pSmDesc->intArg1); /* interrupt argument #1 */
  620.     pCpuDesc->intArg2 = htonl (pSmDesc->intArg2); /* interrupt argument #2 */
  621.     pCpuDesc->intArg3 = htonl (pSmDesc->intArg3); /* interrupt argument #3 */
  622.     pCpuDesc->status  = htonl (SM_CPU_ATTACHED);  /* mark cpu as attached */
  623.     pSmDesc->status = SM_CPU_ATTACHED;          /* also mark sh mem descr */
  624.     CACHE_PIPE_FLUSH (); /* FLUSH BUFFER  [SPR 68334] */
  625.     cpuNum = pCpuDesc->intArg1; /* BRIDGE FLUSH  [SPR 68334] */
  626.     return (OK);                                /* attach complete */
  627.     }
  628. /******************************************************************************
  629. *
  630. * smDetach - detach CPU from shared memory
  631. *
  632. * This routine ends the "attachment" between the calling CPU and
  633. * the shared memory area specified by <pSmDesc>.  No further shared
  634. * memory operations may be performed until a subsequent smAttach()
  635. * is completed.
  636. *
  637. * RETURNS: OK, or ERROR.
  638. *
  639. * ERRNO: S_smLib_NOT_ATTACHED
  640. */
  641. STATUS smDetach
  642.     (
  643.     SM_DESC * pSmDesc       /* ptr to shared mem descriptor */
  644.     )
  645.     {
  646.     SM_CPU_DESC volatile * pCpuDesc;  /* ptr to cpu descriptor in sh mem hdr*/
  647.     int    temp;      /* temp value */
  648.     /* Check that this cpu is connected to shared memory */
  649.     if (pSmDesc->status != SM_CPU_ATTACHED)
  650.         {
  651.         errno = S_smLib_NOT_ATTACHED;
  652.         return (ERROR);                         /* local cpu is not attached */
  653.         }
  654.     /* get addr of cpu descriptor */
  655.     pCpuDesc = (SM_CPU_DESC volatile *) &((pSmDesc->cpuTblLocalAdrs) 
  656.                                            [pSmDesc->cpuNum]);
  657.     pCpuDesc->status = htonl (SM_CPU_NOT_ATTACHED);/* mark as not attached */
  658.     pSmDesc->status  = SM_CPU_NOT_ATTACHED;       /* also mark sh mem descr */
  659.     CACHE_PIPE_FLUSH (); /* FLUSH BUFFER  [SPR 68334] */
  660.     temp = pCpuDesc->status; /* BRIDGE FLUSH  [SPR 68334] */
  661.     return (OK);
  662.     }
  663. /******************************************************************************
  664. *
  665. * smInfoGet - get current status information about shared memory
  666. *
  667. * This routine obtains various pieces of information which describe the
  668. * current state of the shared memory area specified by <pSmDesc>.  The
  669. * current information is returned in a special data structure, SM_INFO,
  670. * whose address is specified by <pInfo>.  The structure must have been
  671. * allocated before this routine is called.
  672. *
  673. * RETURNS: OK, or ERROR if this CPU is not attached to shared memory area.
  674. *
  675. * ERRNO: S_smLib_NOT_ATTACHED
  676. */
  677. STATUS smInfoGet
  678.     (
  679.     SM_DESC * pSmDesc, /* ptr to shared memory descriptor */
  680.     SM_INFO * pInfo /* ptr to info structure to fill */
  681.     )
  682.     {
  683.     SM_HDR volatile *    pHdr; /* ptr to shared memory header */
  684.     SM_CPU_DESC volatile * pCpuDesc; /* ptr to cpu descriptor */
  685.     int    ix; /* index variable */
  686.     int    temp;        /* temp value */
  687.     /* Check that this cpu is connected to shared memory */
  688.     if (pSmDesc->status != SM_CPU_ATTACHED)
  689. {
  690. errno = S_smLib_NOT_ATTACHED;
  691. return (ERROR); /* local cpu is not attached */
  692. }
  693.     /* Get protocol version number */
  694.     CACHE_PIPE_FLUSH (); /* FLUSH BUFFER  [SPR 68334] */
  695.     temp = pSmDesc->anchorLocalAdrs->version; /* PCI bridge bug [SPR 68844]*/
  696.     pInfo->version = ntohl (pSmDesc->anchorLocalAdrs->version);
  697.     /* Get info from shared memory header */
  698.     pHdr = (SM_HDR volatile *) pSmDesc->headerLocalAdrs;
  699.     pInfo->tasType     = ntohl (pHdr->tasType);    /* test-and-set method */
  700.     pInfo->maxCpus     = ntohl (pHdr->maxCpus);    /* max number of cpu's */
  701.     /* Get count of attached cpu's starting with first cpu table entry */
  702.     pCpuDesc = (SM_CPU_DESC volatile *) pSmDesc->cpuTblLocalAdrs;
  703.     pInfo->attachedCpus = 0;
  704.     for (ix = 0;  ix < pInfo->maxCpus;  ix++)
  705. {
  706. if (ntohl (pCpuDesc->status) == SM_CPU_ATTACHED)
  707.     pInfo->attachedCpus++;
  708. pCpuDesc++; /* next entry */
  709. }
  710.     return (OK);
  711.     }
  712. /******************************************************************************
  713. *
  714. * smCpuInfoGet - get information about a single CPU using shared memory
  715. *
  716. * This routine obtains a variety of information describing the CPU specified
  717. * by <cpuNum>.  If <cpuNum> is NONE (-1), this routine returns information
  718. * about the local (calling) CPU.  The information is returned in a special
  719. * structure, SM_CPU_INFO, whose address is specified by <pCpuInfo>.  (The
  720. * structure must have been allocated before this routine is called.)
  721. *
  722. * RETURNS: OK, or ERROR.
  723. *
  724. * ERRNO: S_smLib_NOT_ATTACHED, S_smLib_INVALID_CPU_NUMBER
  725. */
  726. STATUS smCpuInfoGet
  727.     (
  728.     SM_DESC * pSmDesc, /* ptr to shared memory descriptor */
  729.     int cpuNum, /* number of cpu to get info about */
  730.     SM_CPU_INFO * pCpuInfo /* cpu info structure to fill */
  731.     )
  732.     {
  733.     SM_CPU_DESC volatile * pCpuDesc; /* ptr to cpu descriptor */
  734.     int    temp;        /* temp value */
  735.     /* Check that the local cpu is connected to shared memory */
  736.     if (pSmDesc->status != SM_CPU_ATTACHED)
  737. {
  738. errno = S_smLib_NOT_ATTACHED;
  739. return (ERROR); /* local cpu is not attached */
  740. }
  741.     /* Report on local cpu if NONE specified */
  742.     if (cpuNum == NONE)
  743.         {
  744. cpuNum = pSmDesc->cpuNum;
  745.         }
  746.     /* Get info from cpu descriptor */
  747.     if (cpuNum < 0  ||  cpuNum >= pSmDesc->maxCpus)
  748. {
  749. errno = S_smLib_INVALID_CPU_NUMBER;
  750. return (ERROR); /* cpu number out of range */
  751. }
  752.     /* get address of cpu descr */
  753.     pCpuDesc = (SM_CPU_DESC volatile *) &(pSmDesc->cpuTblLocalAdrs [cpuNum]);
  754.     pCpuInfo->cpuNum  = cpuNum;    /* actual cpu number */
  755.     CACHE_PIPE_FLUSH (); /* FLUSH BUFFER  [SPR 68334] */
  756.     temp = pCpuDesc->status; /* PCI bridge bug [SPR 68844]*/
  757.     pCpuInfo->status  = ntohl (pCpuDesc->status);  /* attached/not attached */
  758.     pCpuInfo->intType = ntohl (pCpuDesc->intType); /* interrupt type */
  759.     pCpuInfo->intArg1 = ntohl (pCpuDesc->intArg1); /* interrupt argument #1 */
  760.     pCpuInfo->intArg2 = ntohl (pCpuDesc->intArg2); /* interrupt argument #2 */
  761.     pCpuInfo->intArg3 = ntohl (pCpuDesc->intArg3); /* interrupt argument #3 */
  762.     return (OK);
  763.     }
  764. /******************************************************************************
  765. *
  766. * smLockTake - take a mutual exclusion lock
  767. *
  768. * This routine repeatedly attempts to obtain a mutual exclusion lock
  769. * by using the specified test-and-set routine.  If the lock is not
  770. * obtained within the specified number of attempts, an error is returned.
  771. *
  772. * If the lock was successfully taken, interrupts will be disabled when
  773. * this routine returns and the old interrupt mask level will be copied
  774. * to the location pointed to by <pOldLvl>.
  775. *
  776. * If the lock was not taken, interrupts will be enabled upon return (at
  777. * the interrupt level which was in effect prior to calling this routine).
  778. *
  779. * This routine does not set errno.
  780. *
  781. * INTERNAL 
  782. *
  783. * RETURNS: OK, or ERROR if lock not taken.
  784. */
  785. STATUS smLockTake
  786.     (
  787.     int * lockLocalAdrs, /* local addr of lock */
  788.     FUNCPTR tasRoutine, /* test-and-set routine to use */
  789.     int numTries, /* number of times to try to take lock */
  790.     int * pOldLvl /* where to put old int lvl if success */
  791.     )
  792.     {
  793.     int         oldLvl;         /* previous interrupt level */
  794.     int         delay;          /* time between tries to get lock */
  795.     int         ix; /* index */
  796.     int dummy = 0; /* dummy counter for delay */
  797.     volatile int dummy2; /* dummy to avoid warning in delay */
  798.     int         curNumTries;    /* current number of tries */
  799.  
  800.     /* First try to get lock. */
  801.  
  802.     oldLvl = intLock ();                /* lock out interrupts */
  803.     if ((*tasRoutine) (lockLocalAdrs) == TRUE)
  804.         {
  805.         *pOldLvl = oldLvl;              /* pass back old int level */
  806. /*
  807.  * XXXdat These PIPE_FLUSH operations should not be needed.
  808.  * The tasRoutine should be taking care of the cache issues
  809.  * related to tas activity.
  810.  */
  811. CACHE_PIPE_FLUSH (); /* flush write buffer */
  812.         dummy2 = *(int *)lockLocalAdrs; /* BRIDGE FLUSH  [SPR 68334] */
  813.         return (OK);             /* done! */
  814.         }
  815.     intUnlock (oldLvl);         /* unlock interrupts before retry */
  816.  
  817.     /* 
  818.      * The first try has failed so now we insert a decrementing
  819.      * delay between each tries to reduce bus contention and deadlock.
  820.      *
  821.      * Set maximum delay to a different value for each processor. 
  822.      * Note that this scheme gives a lowest priority to CPUs with
  823.      * high processor number. A better version would implement
  824.      * a random delay.
  825.      */
  826.  
  827.     delay = smLockTakeDelayMin;
  828.     curNumTries = 1;
  829.  
  830.     do
  831.         {
  832.         for (ix = 0; ix <= delay; ix++) /* delay loop */
  833.     dummy2 = dummy++;           /* volatile!! */
  834.  
  835.         oldLvl = intLock ();            /* lock out interrupts */
  836.  
  837.         if ((*tasRoutine) (lockLocalAdrs) == TRUE)
  838.             {
  839.             *pOldLvl = oldLvl;          /* pass back old int level */
  840.     CACHE_PIPE_FLUSH (); /* flush write buffer */
  841.             dummy2 = *(int *)lockLocalAdrs; /* BRIDGE FLUSH  [SPR 68334] */
  842.             return (OK);                /* done! */
  843.             }
  844.  
  845.         intUnlock (oldLvl);             /* unlock interrupts before retry */
  846.  
  847. /* Exponential delay, with a limit */
  848. delay <<= 1;
  849. if (delay > smLockTakeDelayMax)
  850.     {
  851.     delay = smLockTakeDelayMin;
  852.     }
  853.         curNumTries++;
  854.  
  855.         /* keep track of maximum number of attempts */
  856.         if (curNumTries > smCurMaxTries)
  857.             {
  858.             smCurMaxTries = curNumTries;
  859.             }
  860.  
  861.         } while (--numTries > 0);       /* do for spec'd number of tries */
  862.  
  863.     return (ERROR);                     /* cannot take lock */
  864.     }
  865. /******************************************************************************
  866. *
  867. * smLockGive - give a mutual exclusion lock
  868. *
  869. * This routine gives up a mutual exclusion lock taken previously by smLockTake.
  870. *
  871. * RETURNS: N/A
  872. */
  873. void smLockGive
  874.     (
  875.     int * lockLocalAdrs, /* local address of lock */
  876.     FUNCPTR tasClearRoutine, /* test and set clear routine to use */
  877.     int oldLvl /* old interrupt level */
  878.     )
  879.     {
  880.     int volatile * pLockv = (int volatile *) lockLocalAdrs;
  881.     int            temp; /* temp value */
  882.     if (tasClearRoutine != NULL) /* hardware test-and-set */
  883.         {
  884. (*tasClearRoutine) (lockLocalAdrs);
  885.         }
  886.     else
  887.         {
  888.      *pLockv = 0;
  889.         }
  890.     CACHE_PIPE_FLUSH (); /* FLUSH BUFFER  [SPR 68334] */
  891.     temp = *pLockv; /* BRIDGE FLUSH  [SPR 68334] */
  892.     intUnlock (oldLvl);
  893.     }
  894. /******************************************************************************
  895. *
  896. * smRegionFind - find a shared memory region.
  897. *
  898. * This routine finds the shared memory region associated with
  899. * <anchorLocalAdrs>.
  900. *
  901. * RETURNS:  index of the region, or ERROR if not found
  902. */
  903. LOCAL int smRegionFind
  904.     (
  905.     SM_ANCHOR * anchorLocalAdrs /* local address of anchor */
  906.     )
  907.     {
  908.     int ix; /* index */
  909.     for (ix = 0; (smRegions [ix].anchor != NULL) && (ix < smRegionsMax); ix++)
  910. {
  911. if (smRegions [ix].anchor == anchorLocalAdrs)
  912.     {
  913.     return (ix); /* region already initialized*/
  914.     }
  915. }
  916.     return (ERROR);
  917.     }
  918. /******************************************************************************
  919. *
  920. * smRegionGet - get a shared memory region
  921. *
  922. * smRegionGet reserves a space in the smRegion table for a shared memory
  923. * region specified by <anchorLocalAdrs>.
  924. *
  925. * RETURNS: the index of the region, or ERROR if out of space.
  926. */
  927. LOCAL int smRegionGet
  928.     (
  929.     SM_ANCHOR * anchorLocalAdrs /* anchor address */
  930.     )
  931.     {
  932.     int ix; /* index */
  933.     for (ix = 0; (smRegions [ix].anchor != NULL) && (ix < smRegionsMax); ix++)
  934. ;
  935.     if (ix == smRegionsMax)
  936. {
  937. printf ("Out of shared memory regions!!n");
  938. errno = S_smLib_NO_REGIONS;
  939. return (ERROR); /* no space in table */
  940. }
  941.     smRegions [ix].anchor = anchorLocalAdrs;
  942.     return (ix);
  943.     }