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

VxWorks

开发平台:

C/C++

  1. /* smPktLib.c - VxWorks shared packet protocol library */
  2. /* Copyright 1984-2002 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 02m,03may02,mas  cache flush and volatile fix (SPR 68334); bridge flush fix
  7.  (SPR 68844)
  8. 02l,24oct01,mas  doc update (SPR 71149)
  9. 02k,09oct01,mas  smPktSend: added error checking (SPR 6004), limited interrupt
  10.  retries (SPR 25341), removed all FAST modifiers, code cleanup
  11. 02j,17oct00,sn   replaced NULL with 0 so htonl works
  12. 02i,21feb99,jdi  doc: listed errnos.
  13. 02h,26aug93,kdl  smPktBroadcast() now checks smPktSllPut() status before 
  14.  interrupting destination CPU  (SPR #2441).
  15. 02g,13nov92,jcf  removed potential bus error during attach.
  16. 02f,02aug92,kdl  Uncommented include of "copyright_wrs.h".
  17. 02e,24jul92,elh  Moved heartbeat from anchor to header.
  18. 02d,23jun92,elh  general cleanup and documentation.
  19. 02c,02jun92,elh  the tree shuffle
  20. 02b,27may92,elh  Made completely independant, changed to use
  21.  offsets, general cleanup.
  22. 02a,14may92,pme  Split to keep only packet passing routines.
  23. 01e,20feb92,elh  Added in ntohl, and htonl for 960, Added USE_OFFSET.
  24.  Extracted and renamed OS specific calls & moved to
  25.  smUtilLib.  Also removed function pointers
  26.  shMemIntGenFunc and shMemHwTasFunc.
  27.  made TAS_CHECKS 10 TAS_TRIES 5000.
  28.  modified parameters passed to intGen function.
  29. 01d,10feb92,kdl+ Changed shMemDetach to flush input queue.
  30.     elh  Removed references to OK_WAS{EMPTY, NT_EMPTY}.
  31.  Made shMemSend return an ERROR if packet too large.
  32.  Changed shMemSend to return silently (no
  33.  interrupts generated) if sending to self.
  34.  Misc code review changes.
  35. 01c,05feb92,elh  ansified.
  36. 01b,27jan92,elh  added masterCpu to shared memory anchor.
  37.  changed shMemBeat to take pAnchor as argument.
  38.  changed arguments to shMemIsAlive.
  39.  changed shMemSetup to probe memory.
  40.  changed copyright.
  41. 01a,15aug90,kdl  written.
  42. */
  43. /*
  44. DESCRIPTION
  45. This library contains routines which allow multiple processors
  46. to communicate over a backplane using shared memory.  All
  47. services for initializing and managing the shared memory are
  48. provided.
  49. Data is sent between CPU's via shared memory "packets".  A packet
  50. is simply a data buffer (of configurable size) with a header
  51. that allows it to be properly identified and manipulated as a node
  52. in a linked list of packets.
  53. SHARED MEMORY MASTER CPU
  54. One CPU node acts as the shared memory master.  This CPU initializes
  55. the shared memory area and sets up the shared memory anchor.  These
  56. steps are performed by the master calling the smPktSetup() routine.
  57. This routine should be called only by the shared memory master CPU,
  58. and it should only be called once for a given shared memory region.
  59. (It is, however, possible to maintain and use multiple separate
  60. shared memory regions.)
  61. Once smPktSetup() has completed successfully, there is little functional
  62. difference between the master CPU and other CPU's using shared memory,
  63. except that the master is responsible for maintaining the heartbeat in
  64. the shared memory packet region header.
  65. SHARED MEMORY ANCHOR
  66. The shared memory anchor is a small data structure which is at
  67. a predetermined location, to allow all CPU's using shared memory to
  68. find it.  The shared memory anchor contains the base offset to the
  69. actual shared memory region which will be used for inter-processor
  70. message passing.  (This allows the master CPU to dynamically allocate
  71. the shared memory region.)
  72. The shared memory anchor does not have to be defined as part of the
  73. shared memory region which will be used for message passing.  However,
  74. it must be located in a similar address space; the address translation
  75. constants which CPU boards use to convert local addresses to bus addresses
  76. must apply equally to the anchor and the regular shared memory region.
  77. ATTACHING TO SHARED MEMORY
  78. Each CPU, master or non-master, which will use the shared memory region
  79. must attach itself to the shared memory.  The shared memory region must
  80. have already been initialized by the master CPU calling smPktSetup().
  81. The first step in attaching to shared memory is for each CPU to allocate and
  82. initialize a shared memory packet descriptor (SM_PKT_DESC).  This structure 
  83. describes the individual CPU's attachment to the shared memory region 
  84. and is used in all subsequent shared memory calls to identify which 
  85. shared memory region is being used.  Since the shared memory descriptor 
  86. is used only by the local CPU, it is not necessary for the descriptor 
  87. itself to be located in shared memory.  In fact, it is preferable for 
  88. the descriptor to be allocated from the CPU's local memory, since local 
  89. memory is usually more efficient to access.
  90. The shared memory packet descriptor is initialized by calling the 
  91. smPktInit() routine.  This routine takes a number of parameters which 
  92. specify the characteristics of this CPU and its access to shared memory.
  93. After the shared memory packet descriptor has been initialized, the CPU may
  94. attach itself to the shared memory region.  This is done by calling the
  95. smPktAttach() routine.
  96. When smPktAttach() is called, it checks that the shared memory anchor 
  97. contains the special ready value and that the heartbeat is incrementing.
  98. If either of these conditions is not met, the routine will check 
  99. periodically until either the ready value and incrementing heartbeat 
  100. are recognized or a time limit is reached.  For non-master CPU's, 
  101. this limit may be set by changing the global variable, smAliveTimeout.  
  102. The limit is expressed in seconds, with 600 seconds (10 minutes) the 
  103. default.  The master CPU will only wait 5 beat periods for a recognized 
  104. heartbeat, since it is the CPU responsible for initializing shared memory 
  105. and incrementing the heartbeat and therefore should not have to wait.  
  106. If the time limit is reached before a valid ready value and heartbeat 
  107. is seen, ERROR is returned and errno is set to S_smPktLib_DOWN .
  108. Once the CPU has attached itself to the shared memory region, it may
  109. send packets to other CPU's or receive packets which have been sent to it.
  110. (Attempts to perform any shared memory operations without first attaching
  111. successfully will return ERROR, with errno set to S_smPktLib_NOT_ATTACHED .)
  112. SENDING PACKETS
  113. To send a packet to another CPU, an application task must first obtain
  114. a shared memory packet from the pool of free packets.  This is
  115. done by calling smPktFreeGet(), as follows:
  116. cs
  117. status = smPktFreeGet (pSmPktDesc, &pPkt);
  118. ce
  119. In this example, <pSmPktDesc> is the address of this CPU's shared memory packet
  120. descriptor.  If status value returned by smPktFreeGet is OK, the address
  121. of the obtained packet will be placed in <pPkt>.  If the packet address is
  122. NULL, no free packets were available.
  123. Once a packet has been obtained, the application task must copy the data
  124. to be sent into the "data" field of the packet structure.  The maximum
  125. number of bytes which may be copied to the packet's data buffer is
  126. <maxPktBytes>, as specified by the master CPU during smPktSetup.  This
  127. limit may be determined by reading a field in the shared memory packet 
  128. descriptor.
  129. The application task may set the "type" field in the packet header (SM_PKT_HDR)
  130. to indicate the specific type of packet being sent.  This field is not used
  131. by smPktLib and may therefore be given any value.
  132. To send the completed packet, the application task calls smPktSend(),
  133. as follows:
  134. cs
  135. status = smPktSend (pSmPktDesc, destCpu, pPkt);
  136. ce
  137. Here, <destCpu> is the number of the destination CPU, and <pPkt> is the
  138. address of the packet to be sent.  If smPktSend() returns a status of OK,
  139. the packet was successfully queued for the destination CPU.
  140. If the destination CPU did not previously have any input packets queued to
  141. it smPktSend() will call the user-provided routine, smUtilIntGen(), to 
  142. interrupt the destination CPU to notify it that a 
  143. packet is available.  See "Interrupts," below, for more information.
  144. If the destination CPU is not attached, ERROR is returned and errno is set
  145. to S_smPktLib_DEST_NOT_ATTACHED .  If the specified destination cpu
  146. number is out of range (i.e. less than zero or greater than the maximum
  147. specified during smPktSetup), ERROR is returned and errno is set to
  148. S_smPktLib_INVALID_CPU_NUMBER .
  149. If the first interrupt fails, a delay of one tick is made and another
  150. interrupt is attempted.  This is repeated up to smPktMaxIntRetries attempts or
  151. until the interrupt is successful.  If not successful, ERROR is returned
  152. and errno is set to S_smPktLib_INCOMPLETE_BROADCAST so that the caller
  153. does not try to remove the packet and place it on the free list.  Doing
  154. so would put the packet in both an input list and the free list!
  155. BROADCAST PACKETS
  156. In some circumstances, it may be desirable to send the same data to
  157. all CPU nodes using the shared memory region.  This may be accomplished
  158. by using a special "broadcast" mode of smPktSend().  This option sends
  159. a copy of the same packet data to each attached CPU (except the sender).
  160. To send a broadcast message, a CPU must first obtain a free shared memory
  161. packet using smPktFreeGet() as usual.  The data area of the packet
  162. is then filled with the message to be sent, again the same as for sending
  163. to a single destination.
  164. Broadcast mode is indicated during smPktSend() by a special value of the
  165. <destCpu> (destination CPU) parameter.  This parameter is set to
  166. SM_BROADCAST, rather than a particular CPU number.
  167. When a broadcast message is sent, a separate packet is obtained for each
  168. attached CPU, the data from the original packet is copied to it, and
  169. the packet is queued to a particular CPU.  Therefore, there must be
  170. sufficient free packets to send one to each CPU.  Broadcast packets are
  171. sent to destination CPU's in cpu-number order.
  172. If there are not enough free packets to send a copy to each CPU,
  173. as many as possible will be sent, but ERROR is returned and errno is
  174. set to S_smPktLib_INCOMPLETE_BROADCAST .  (If there are insufficient
  175. free packets, the original packet passed during smPktSend() will be
  176. sent to a destination CPU, to provide as complete a broadcast as
  177. possible.)
  178. Broadcast packets are received in the same manner as any other packets.
  179. RECEIVING PACKETS
  180. Packets are received by calling the smPktRecv() routine.  This routine
  181. will normally be called by an interrupt handler, in response to a
  182. an interrupt generated by a remote CPU sending a packet.  The smPktRecv()
  183. routine may also be called periodically, in a polling fashion, to check
  184. for received packets in systems which do not use interrupts to notify
  185. the receiving CPU.
  186. To receive a packet, smPktRecv is called as follows:
  187. cs
  188. status = smPktRecv (pSmPktDesc, &pPkt);
  189. ce
  190. If the returned status is OK, <pPkt> will contain either the address of
  191. a received packet, or NULL if no input packets were available.  A returned
  192. status of ERROR indicates that an error occurred while attempting to
  193. obtain received packets.
  194. A sending CPU will interrupt the destination CPU only if there
  195. were no packets previously queued for the destination CPU.  It is
  196. therefore important that an interrupt handler which receives packets
  197. call smPktRecv again after each packet is received, to check for
  198. additional packets.
  199. After a packet has been received, it must be explicitly freed by calling
  200. smPktFreePut().
  201. DETACHING FROM SHARED MEMORY
  202. The attachment of a CPU to shared memory may be ended by calling
  203. smPktDetach().  This routine will mark the calling CPU as no longer
  204. attached.  After this, other CPU's may no longer send packets to it.
  205. The CPU may re-attach itself to the shared memory region by later
  206. calling smPktAttach().  When re-attaching, the original shared
  207. memory descriptor may be re-used if the CPU's configuration remains
  208. the same, or new values may be specified via smPktInit().
  209. INTERRUPTS
  210. When a packet is sent to a CPU, there must be some method for that CPU
  211. to be informed that an input packet is available.  The preferred method
  212. is for the sending CPU to be able to interrupt the receiving CPU.  This
  213. will be highly dependent on the specific hardware being used.  
  214. Two types of interrupts are supported, mailbox interrupts and vme
  215. bus interrupts.  Mailbox interrupts are the first preferred
  216. method (SM_INT_MAILBOX), followed by vme bus interrupts (SM_INT_BUS).
  217. If interrupts cannot be used, a polling scheme may be employed
  218. (SM_INT_NONE), but this is much less efficient.
  219. When a CPU initailizes its shared memory packet descriptor via the
  220. smPktInit() call, it passes in an interrupt type as well as three
  221. interrupt arguments.  This describes how the cpu wishes to be notified
  222. of incomming packets.  The interrupt types recognized by this library
  223. are listed in smLib.h.  These values may be obtained for any attached CPU by
  224. calling smPktCpuInfoGet().
  225. The default interrupt method for a particular target is defined by the
  226. configuration parameters: SM_INT_TYPE, SM_INT_ARG1, SM_INT_ARG2, SM_INT_ARG3 .
  227. When a CPU sends a packet to a destination CPU which did not previously
  228. have any input packets queued to it, the sending CPU will 
  229. interrupt the destination CPU. 
  230. A handler routine which executes in response to such an interrupt
  231. must call smPktRecv() to obtain the input packet.  Since the interrupt
  232. is generated only for the first packet queued when the input list was
  233. previously empty, it is important that the handler routine then call
  234. smPktRecv additional times until no more packets are available.
  235. If it is not possible to use interrupts to notify receiving CPU's, a 
  236. polling method may be used.  The simplest method is for the recieving CPU to
  237. repeatedly call smPktRecv() to check for input packets.  In this case,
  238. no notification routine is used.
  239. OBTAINING STATUS INFORMATION
  240. Two routines are provided to obtain current status information about
  241. the shared memory region and individual CPU's:
  242. The smPktInfoGet() routine gets status information which applies to the
  243. the shared memory region as a whole.  It takes as a parameter a pointer
  244. to a special information structure (SM_PKT_INFO), which it fills before
  245. returning.  
  246. The smPktCpuInfoGet() routine obtains status information for a single
  247. CPU.  The number of the CPU must be specified during the call to
  248. smPktCpuInfoGet().  A CPU number of NONE (-1) indicates that information
  249. on the calling CPU should be returned.  The routine takes as a parameter
  250. a pointer to a special CPU information structure (SM_PKT_CPU_INFO), 
  251. which it fills before returning.  
  252. INTERNAL
  253. This file runs under only vxWorks.  SunOS is no longer supported.
  254. Pointers into shared memory are declared 'volatile' so that compiler
  255. optimization does not disrupt ordering of I/O operations.
  256. Reading of locking semaphores after updates to shared memory but before
  257. release of the semaphores is to cause the flushing of any external bus
  258. bridge read and write FIFOs.  Failure to do so can result in erroneous
  259. reads of shared memory and subsequent deadlock conditions.
  260. */
  261. #ifdef UNIX
  262. #undef INET
  263. #endif
  264. /* includes */
  265. #include "vxWorks.h"
  266. #include "sysLib.h"
  267. #include "taskLib.h"
  268. #include "cacheLib.h"
  269. #include "smPktLib.h"
  270. #include "smLib.h"
  271. #include "smUtilLib.h"
  272. /* defines */
  273. #define SM_LOCK_TAKE(lockLocalAdrs,tasRoutine,numTries,pOldLvl) 
  274. (smLockTake (lockLocalAdrs, tasRoutine, numTries, pOldLvl))
  275. #define SM_LOCK_GIVE(lockLocalAdrs,tasClearRoutine, oldLvl) 
  276. (smLockGive (lockLocalAdrs, tasClearRoutine, oldLvl))
  277. #define DEFAULT_TAS_TRIES 5000 /* default tries for test-and-set */
  278. #ifndef SM_PKT_MAX_INT_RETRIES
  279. # define SM_PKT_MAX_INT_RETRIES 5   /* max #retries of interrupt per pkt */
  280. #endif
  281. /* Globals */
  282. int smPktMemSizeDefault  = DEFAULT_MEM_SIZE; /* memory size */
  283. int  smPktMaxBytesDefault  = DEFAULT_PKT_SIZE;  /* max pkt size */
  284. int  smPktMaxInputDefault = DEFAULT_PKTS_MAX; /* max input pkts */
  285. int  smPktMaxCpusDefault     = DEFAULT_CPUS_MAX; /* max num CPU's */
  286. int smPktTasTries     = DEFAULT_TAS_TRIES;
  287. /* times to try test-and-set */
  288. int     smPktMaxIntRetries      = SM_PKT_MAX_INT_RETRIES;
  289.                                 /* max #int retries to attempt per packet */
  290. /* Forward References */
  291. #ifdef __STDC__
  292. LOCAL STATUS smPktSllGet
  293.     (
  294.     SM_SLL_LIST volatile * listLocalAdrs, /* local addr of packet list */
  295.     int                    baseAddr, /* addr conversion constant */
  296.     FUNCPTR                tasRoutine, /* test-and-set routine addr */
  297.     FUNCPTR                tasClearRoutine, /* test-and-set routine addr */
  298.     SM_SLL_NODE **    pNodeLocalAdrs /* location to put node addr */
  299.     );
  300. LOCAL STATUS smPktSllPut
  301.     (
  302.     SM_SLL_LIST volatile * listLocalAdrs, /* local addr of packet list */
  303.     int    base, /* base address */
  304.     FUNCPTR    tasRoutine, /* test-and-set routine addr */
  305.     FUNCPTR    tasClearRoutine, /* test-and-set routine addr */
  306.     SM_SLL_NODE volatile * nodeLocalAdrs, /* local addr of node */
  307.     BOOL *    pListWasEmpty /* set to true if adding to
  308.                                                  * empty list */
  309.     );
  310. LOCAL STATUS smPktBroadcast
  311.     (
  312.     SM_PKT_DESC * pSmPktDesc, /* sh mem pkt descriptor */
  313.     volatile SM_PKT * pPktOrig /* ptr to original packet */
  314.     );
  315. #else /* __STDC__ */
  316. LOCAL STATUS smPktSllGet ();
  317. LOCAL STATUS smPktSllPut ();
  318. LOCAL STATUS smPktBroadcast ();
  319. #endif /* __STDC__ */
  320. /******************************************************************************
  321. *
  322. * smPktSetup - set up shared memory (master CPU only)
  323. *
  324. * This routine should be called only by the master CPU using shared
  325. * memory.  It initializes the specified memory area for use by the
  326. * shared memory protocol.
  327. *
  328. * After the shared memory has been initialized, this and other CPU's
  329. * may initialize a shared memory packet descriptor to it, using smPktInit(),
  330. * and then attach to the shared memory area, using smPktAttach().
  331. *
  332. * The <anchorLocalAdrs> parameter is the memory address by which the master
  333. * CPU accesses the shared memory anchor.
  334. *
  335. * The <smLocalAdrs> parameter is the memory address by which the master
  336. * CPU accesses the actual shared memory region to be initialized.
  337. *
  338. * The <smSize> parameter is the size, in bytes, of the shared memory
  339. * region.
  340. *
  341. * The shared memory routines must be able to obtain exclusive access to
  342. * shared data structures.  To allow this, a test-and-set operation is
  343. * used.  It is preferable to use a genuine test-and-set instruction, if
  344. * the hardware being used permits this.  If this is not possible, smUtilLib
  345. * provides a software emulation of test-and-set.  The <tasType> parameter
  346. * specifies what method of test-and-set is to be used.
  347. *
  348. * The <maxCpus> parameter specifies the maximum number of CPU's which may
  349. * use the shared memory region.
  350. *
  351. * The <maxPktBytes> parameter specifies the size, in bytes, of the data
  352. * buffer in shared memory packets.  This is the largest amount of data
  353. * which may be sent in a single packet.  If this value is not an exact
  354. * multiple of 4 bytes, it will be rounded up to the next multiple of 4.
  355. *
  356. * INTERNAL
  357. * The first item in the shared memory area is the shared memory packet
  358. * header (SM_PKT_MEM_HDR).  Following this is an array of CPU 
  359. * descriptors (SM_PKT_CPU_DESC); this table contains one CPU descriptor 
  360. * for each possible CPU, as specified by <maxCpus>.
  361. * The shared memory area following the cpu table is allocated to the global
  362. * list of free packets (SM_PKT), used for sending data between CPU's.  Note
  363. * that the shared memory anchor is NOT part of the regular shared memory area.
  364. *
  365. * Since the size of each data packet is not pre-determined, the actual size
  366. * is calculated based on the size of the (fixed) packet header and the
  367. * data buffer size, specified by <maxPktBytes>.
  368. *
  369. * The standard smPktSllPut routine is used to build the free packet list.
  370. * The software test-and-set routine is always used, regardless of the
  371. * definition of <tasType>, because no hardware TAS routine has been supplied
  372. * yet. (That is done during smPktAttach.)  Use of any TAS method at this
  373. * stage is mainly a formality, since no other CPU's are able to attach to
  374. * the shared memory region.
  375. *
  376. * RETURNS: OK, or ERROR.
  377. *
  378. * ERRNO: S_smPktLib_SHARED_MEM_TOO_SMALL, S_smPktLib_MEMORY_ERROR
  379. *
  380. * INTERNAL:  This routine and smObjSetup can not be called at the same time!!!
  381. */
  382. STATUS smPktSetup
  383.     (
  384.     SM_ANCHOR * anchorLocalAdrs,  /* local addr of anchor */
  385.     char *  smLocalAdrs, /* local addr of sh mem area */
  386.     int smSize, /* size of shared memory area */
  387.     int tasType,  /* test and set type */
  388.     int maxCpus, /* max number of cpus */
  389.     int maxPktBytes /* max bytes of packet data */
  390.     )
  391.     {
  392.     SM_ANCHOR volatile * pAnchorv = (SM_ANCHOR volatile *) anchorLocalAdrs;
  393.     SM_PKT_MEM_HDR volatile * smPktHdr; /* local addr of sh mem hdr */
  394.     int pktSize; /* actual size of pkt */
  395.     STATUS status;   /* return status */
  396.     SM_PKT volatile * pPkt; /* local addr of free packet */
  397.     int memLeft;
  398.     char temp = 0;
  399.     int base = (int) anchorLocalAdrs;
  400.     int  bytesUsed = 0;
  401.     int                         tmp;            /* temp storage */
  402.     /* set up default values for parameters */
  403.     smSize  = (smSize == 0)  ?  smPktMemSizeDefault : smSize;
  404.     maxCpus = (maxCpus == 0) ?  smPktMaxCpusDefault : maxCpus;
  405.     maxPktBytes = (maxPktBytes == 0) ?  smPktMaxBytesDefault : maxPktBytes;
  406.     maxPktBytes = ((maxPktBytes + sizeof (int) - 1) / sizeof (int)) *
  407.                   sizeof (int);                 /* round up buf to int mult */
  408.     pktSize = (sizeof (SM_PKT_HDR) + maxPktBytes);
  409.                                                 /* pkt size incl data buffer */
  410.     if (smSetup (anchorLocalAdrs, smLocalAdrs, tasType, maxCpus,
  411.  &bytesUsed) == ERROR)
  412.        return (ERROR);
  413.     smSize  -= bytesUsed;
  414.     smLocalAdrs += bytesUsed;
  415.     /*
  416.      * Check that shared mem size is big enough to contain:
  417.      * the shared memory packet header, the shared memory packet
  418.      * cpu descriptors and 1 pkt per cpu.
  419.      */
  420.     if (smSize < (sizeof (SM_PKT_MEM_HDR) +
  421. (maxCpus * sizeof (SM_PKT_CPU_DESC)) + (maxCpus * pktSize)))
  422.         {
  423.         errno = S_smPktLib_SHARED_MEM_TOO_SMALL;
  424.         return (ERROR);                         /* not enough sh mem */
  425.         }
  426.     /* Probe beginning and end of shared memory */
  427.     if ((smUtilMemProbe (smLocalAdrs , VX_WRITE, sizeof (char), &temp) != OK) ||
  428.         (smUtilMemProbe (smLocalAdrs + smSize - 1, VX_WRITE, sizeof (char),
  429.  &temp) != OK))
  430.         {
  431.         errno = S_smPktLib_MEMORY_ERROR;
  432.         return (ERROR);
  433.         }
  434.     /* Clear shared memory */
  435.     bzero (smLocalAdrs, smSize);
  436.     /* Fill in header */
  437.     smPktHdr = (SM_PKT_MEM_HDR volatile *) smLocalAdrs;
  438.     smPktHdr->maxPktBytes = htonl (maxPktBytes);/* max size of pkt data buf */
  439.     smPktHdr->pktCpuTbl   = htonl (SM_LOCAL_TO_OFFSET ((char *) smPktHdr +
  440.            sizeof (SM_PKT_MEM_HDR),
  441.        base));
  442.     pAnchorv->smPktHeader = htonl (SM_LOCAL_TO_OFFSET (smLocalAdrs, base));
  443.     /* Set up list of free packets */
  444.     pPkt = (SM_PKT *) (smLocalAdrs + sizeof (SM_PKT_MEM_HDR) +
  445.       (maxCpus * sizeof (SM_PKT_CPU_DESC)));
  446. /* calculate addr of 1st pkt */
  447.     memLeft = smSize - ((int) ((char *) pPkt - smLocalAdrs));
  448. /* calculate remaining sh mem */
  449.     while (memLeft >= pktSize)
  450. {
  451. /* allow one more in free list*/
  452. smPktHdr->freeList.limit = htonl (ntohl (smPktHdr->freeList.limit) +1);
  453. /* Add packet to list, always use software test-and-set emulation */
  454. status = smPktSllPut (&(smPktHdr->freeList), base, smUtilSoftTas, NULL,
  455.       &(pPkt->header.node), NULL);
  456. if (status == ERROR)
  457.     {
  458.     smPktHdr->freeList.limit = htonl (ntohl (smPktHdr->freeList.limit)
  459.                                       - 1);
  460.     return (ERROR); /* error adding to free list */
  461.     }
  462. pPkt = (SM_PKT *) ((char *) pPkt + pktSize);/* advance pkt pointer */
  463. memLeft -= pktSize; /* decrease mem remaining */
  464. }
  465.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  466.     tmp = smPktHdr->freeList.limit;             /* BRIDGE FLUSH  [SPR 68334] */
  467.     return (OK); /* shared mem init complete */
  468.     }
  469. /******************************************************************************
  470. *
  471. * smPktInit - initialize shared memory packet descriptor
  472. *
  473. * This routine initializes a shared memory packet descriptor.  The descriptor
  474. * must have been previously allocated (generally in the CPU's local
  475. * memory).  Once the descriptor has been initialized by this routine,
  476. * the CPU may attach itself to the shared memory area by calling
  477. * smPktAttach().
  478. *
  479. * Only the shared memory descriptor itself is modified by this routine.
  480. * No structures in shared memory are affected.
  481. *
  482. * The <pSmPktDesc> paramter is the address of the shared memory packet 
  483. * descriptor which is to be initialized; this structure must have 
  484. * already been allocated before smPktInit is called.
  485. *
  486. * The <anchorLocalAdrs> parameter is the memory address by which the local
  487. * CPU may access the shared memory anchor.  This address may vary for
  488. * different CPU's because of address offsets (particularly if the anchor is
  489. * located in one CPU's dual-ported memory).
  490. *
  491. * The <maxInputPkts> parameter specifies the maximum number of incoming
  492. * shared memory packets which may be queued to this CPU at one time.  If
  493. * a remote CPU attempts to send more packets after this limit is reached,
  494. * an error will be returned to the remote CPU.
  495. *
  496. * The <ticksPerBeat> parameter specifies the frequency of the shared memory
  497. * heartbeat.  The frequency is expressed in terms of how many CPU
  498. * ticks on the local CPU correspond to one heartbeat period.
  499. *
  500. * The <intType>, <intArg1>, <intArg2>, and <intArg3> parameters allow a
  501. * CPU to announce the method by which it is to be notified of input packets
  502. * which have been queued to it.  Once this CPU has attached to the shared
  503. * memory region, other CPU's will be able to determine these interrupt
  504. * parameters by calling smPktCpuInfoGet().  The following interrupt 
  505. * methods are currently recognized by this library: SM_INT_MAILBOX, 
  506. * SM_INT_BUS, SM_INT_NONE, and SM_INT_USER .
  507. *
  508. * RETURNS: N/A
  509. */
  510. void smPktInit
  511.     (
  512.     SM_PKT_DESC * pSmPktDesc,         /* ptr to sh mem packet descr */
  513.     SM_ANCHOR * anchorLocalAdrs,    /* local addr of sh mem anchor*/
  514.     int                 maxInputPkts,       /* max queued packets allowed */
  515.     int                 ticksPerBeat,       /* cpu ticks per heartbeat */
  516.     int                 intType,            /* interrupt method */
  517.     int                 intArg1,            /* interrupt argument #1 */
  518.     int                 intArg2,            /* interrupt argument #2 */
  519.     int                 intArg3             /* interrupt argument #3 */
  520.     )
  521.     {
  522.     if (pSmPktDesc == NULL)
  523.         return;                                 /* don't use null ptr */
  524.     bzero ((char *) pSmPktDesc, sizeof (SM_PKT_DESC));
  525.     smInit (&pSmPktDesc->smDesc, anchorLocalAdrs, ticksPerBeat, intType,
  526.     intArg1, intArg2, intArg3);
  527.     pSmPktDesc->maxInputPkts  = (maxInputPkts == 0) ? smPktMaxInputDefault :
  528.           maxInputPkts;
  529.     pSmPktDesc->status        = SM_CPU_NOT_ATTACHED;    /* initial status */
  530.     }
  531. /******************************************************************************
  532. *
  533. * smPktAttach - attach to shared memory
  534. *
  535. * This routine "attaches" the local CPU to a shared memory area.  The
  536. * shared memory area is identified by the shared memory packet descriptor
  537. * whose address specified by <pSmPktDesc>.  The descriptor must have
  538. * already been initialized by calling smPktInit().
  539. *
  540. * This routine will complete the attach process only if and when the
  541. * shared memory has been initialized by the master CPU.  To determine
  542. * this, the shared memory anchor is checked for the proper value
  543. * (SM_READY_VALUE) in the anchor's ready-value field and a check is made for
  544. * an active heartbeat.  This repeated checking continues until either 
  545. * the ready-value and heartbeat have been verified or a timeout limit 
  546. * is reached.  If the shared memory is not recognized as active within 
  547. * the timeout period, this routine returns an error (S_smPktLib_DOWN).
  548. *
  549. * The attachment to shared memory may be ended by calling smPktDetach().
  550. *
  551. * RETURNS: OK, or ERROR.
  552. *
  553. * ERRNO: S_smPktLib_DOWN
  554. *
  555. * SEE ALSO: smPktInit()
  556. */
  557. STATUS smPktAttach
  558.     (
  559.     SM_PKT_DESC * pSmPktDesc /* packet descriptor */
  560.     )
  561.     {
  562.     SM_PKT_MEM_HDR volatile * pHdr; /* sm pkt header */
  563.     SM_PKT_CPU_DESC volatile * pPktDesc; /* pkt cpu descriptor */
  564.     int cpuNum; /* this cpu's number */
  565.     SM_ANCHOR volatile * pAnchor; /* anchor */
  566.     int beatsToWait;
  567.     SM_DESC * pSmDesc = (SM_DESC *) &pSmPktDesc->smDesc;
  568.     cpuNum  = pSmDesc->cpuNum;
  569.     pAnchor = pSmDesc->anchorLocalAdrs;
  570.     /* Check that shared memory is initialized and running */
  571.     /*
  572.      * XXX master CPU should only wait DEFAULT_BEATS_TO_WAIT but we don't
  573.      * know who the master is unless we look in the anchor.  The anchor may
  574.      * not be mapped onto the bus, and we will blow up with a BERR if we
  575.      * poke around.  So we just wait a long time, even if we are the master.
  576.      * This could be fixed by listing the SM master and local processor
  577.      * numbers in the packet descriptor so that the two could be compared.
  578.      * If equal, we would be the master and no waiting would be necessary.
  579.      */
  580.     beatsToWait = DEFAULT_ALIVE_TIMEOUT;
  581.     if (smIsAlive ((SM_ANCHOR *)pAnchor, (int *)&(pAnchor->smPktHeader),
  582.                    pSmDesc->base, beatsToWait, pSmDesc->ticksPerBeat) == FALSE)
  583.         {
  584.         errno = S_smPktLib_DOWN;
  585.         return (ERROR);                         /* sh memory not active */
  586.         }
  587.     if (smAttach (pSmDesc) == ERROR)
  588. return (ERROR);
  589.     /* Get local address for shared mem packet header */
  590.     pHdr = SM_OFFSET_TO_LOCAL (ntohl (pAnchor->smPktHeader), pSmDesc->base, 
  591.        SM_PKT_MEM_HDR volatile *);
  592.     pSmPktDesc->hdrLocalAdrs = (SM_PKT_MEM_HDR *) pHdr;
  593.     pSmPktDesc->maxPktBytes  = ntohl (pHdr->maxPktBytes);
  594.     pSmPktDesc->cpuLocalAdrs = SM_OFFSET_TO_LOCAL (ntohl (pHdr->pktCpuTbl),
  595.           pSmDesc->base,
  596.         SM_PKT_CPU_DESC *);
  597.     pPktDesc = &((pSmPktDesc->cpuLocalAdrs) [cpuNum]);
  598. /* calculate addr of cpu desc
  599.  * in global table.
  600.  */
  601.     pPktDesc->inputList.limit = htonl (pSmPktDesc->maxInputPkts);
  602. /* max queued count */
  603.     pPktDesc->status  = htonl (SM_CPU_ATTACHED);/* mark this cpu as attached */
  604.     pSmPktDesc->status = SM_CPU_ATTACHED; /* also mark sh mem descr */
  605.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  606.     cpuNum = pPktDesc->status; /* BRIDGE FLUSH  [SPR 68334] */
  607.     return (OK); /* attach complete */
  608.     }
  609. /******************************************************************************
  610. *
  611. * smPktFreeGet - get a shared memory packet from free list
  612. *
  613. * This routine obtains a shared memory packet.  The packet is taken
  614. * from the global free packet list.  No initialization of the packet
  615. * contents is performed.
  616. *
  617. * The address of the obtained packet is placed in the location specified
  618. * by <ppPkt>.  If there were no free packets available, this value will
  619. * be NULL.
  620. *
  621. * RETURNS: OK, or ERROR.
  622. *
  623. * ERRNO: S_smPktLib_NOT_ATTACHED
  624. */
  625. STATUS smPktFreeGet
  626.     (
  627.     SM_PKT_DESC * pSmPktDesc, /* ptr to shared memory descriptor */
  628.     SM_PKT ** ppPkt  /* location to put packet address */
  629.     )
  630.     {
  631.     SM_DESC * pSmDesc = &pSmPktDesc->smDesc;
  632.     /* Check that this cpu is connected to shared memory */
  633.     if (pSmPktDesc->status != SM_CPU_ATTACHED)
  634. {
  635. errno = S_smPktLib_NOT_ATTACHED;
  636. return (ERROR); /* local cpu is not attached */
  637. }
  638.     /* Get packet from free list */
  639.     return (smPktSllGet (&(pSmPktDesc->hdrLocalAdrs->freeList),
  640.  pSmDesc->base, pSmDesc->tasRoutine,
  641.  pSmDesc->tasClearRoutine, (SM_SLL_NODE **) ppPkt));
  642.     }
  643. /******************************************************************************
  644. *
  645. * smPktSend - send a packet via shared memory
  646. *
  647. * This routine queues a packet (previously acquired via smPktFreeGet)
  648. * to be received by another CPU.  If the input list for the destination
  649. * CPU was previously empty and the destination has not specified polling 
  650. * as its interrupt type, this routine will interrupt the destination CPU. 
  651. *
  652. * If the specified <destCpu> is SM_BROADCAST, a copy of the packet will
  653. * be sent to each CPU which is attached to the shared memory area (except
  654. * the sender CPU).  If there are not enough free packets to send a copy
  655. * to each cpu, or if errors occur when sending to one or more destinations,
  656. * an error (S_smPktLib_INCOMPLETE_BROADCAST) is returned.
  657. *
  658. * If ERROR is returned and errno equals S_smPktLib_INCOMPLETE_BROADCAST,
  659. * the original packet, <pPkt>, was sent to an attached CPU and does not
  660. * have to be freed.  A return code of ERROR combined with any other value
  661. * of errno indicates that <pPkt> was NOT sent and should be explicitly
  662. * freed using smPktFreePut().  (A return value of OK indicates that
  663. * <pPkt> was either sent or freed before this routine returned, and no
  664. * further action is required.)
  665. *
  666. * RETURNS: OK, or ERROR.
  667. *
  668. * ERRNO: S_smPktLib_NOT_ATTACHED, S_smPktLib_INVALID_PACKET,
  669. * S_smPktLib_PACKET_TOO_BIG, S_smPktLib_INVALID_CPU_NUMBER,
  670. * S_smPktLib_DEST_NOT_ATTACHED, S_smPktLib_INCOMPLETE_BROADCAST
  671. */
  672. STATUS smPktSend
  673.     (
  674.     SM_PKT_DESC * pSmPktDesc, /* ptr to shared memory descriptor */
  675.     SM_PKT * pPkt, /* local addr of packet to be sent */
  676.     int destCpu /* destination cpu number */
  677.     )
  678.     {
  679.     SM_PKT volatile * pPktv = (SM_PKT volatile *) pPkt;
  680.     STATUS status; /* return status */
  681.     SM_PKT_CPU_DESC volatile * pPktCpuDesc; /* destination cpu pkt descr*/
  682.     SM_CPU_DESC volatile * pCpuDesc; /* destination cpu descr*/
  683.     int i;
  684.     BOOL listWasEmpty; /* list empty */
  685.     SM_DESC * pSmDesc = (SM_DESC *) &pSmPktDesc->smDesc;
  686.     int                         tmp;            /* temp storage */
  687.     /* Check that this cpu is connected to shared memory */
  688.     if (pSmPktDesc->status != SM_CPU_ATTACHED)
  689. {
  690. errno = S_smPktLib_NOT_ATTACHED;
  691. return (ERROR); /* local cpu is not attached */
  692. }
  693.     /* Check for null pointer */
  694.     if (pPkt == NULL)
  695. {
  696. errno = S_smPktLib_INVALID_PACKET;
  697. return (ERROR); /* null packet address */
  698. }
  699.     /* Enforce max data length */
  700.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  701.     tmp = pPktv->header.nBytes;                 /* BRIDGE FLUSH  [SPR 68334] */
  702.     if (pPktv->header.nBytes > pSmPktDesc->maxPktBytes)
  703. {
  704. errno = S_smPktLib_PACKET_TOO_BIG;
  705. return (ERROR); /* too much data ! */
  706. }
  707. /* byte swap info */
  708.     pPktv->header.nBytes = htonl (pPktv->header.nBytes);
  709.     /* Call special routine if doing broadcast */
  710.     if (destCpu == SM_BROADCAST) /* if sending to all cpu's */
  711. return (smPktBroadcast (pSmPktDesc, pPkt));
  712.     /* Make sure destination cpu is valid and attached */
  713.     if (destCpu < 0  ||  destCpu >= pSmDesc->maxCpus)
  714.         {
  715.         errno = S_smPktLib_INVALID_CPU_NUMBER;
  716.         return (ERROR); /* cpu number out of range */
  717.         }
  718.     pPktCpuDesc = &((pSmPktDesc->cpuLocalAdrs) [destCpu]);
  719.     pCpuDesc    = &((pSmDesc->cpuTblLocalAdrs) [destCpu]);
  720.      /* get addr of cpu descriptor */
  721.     if (ntohl (pPktCpuDesc->status) != SM_CPU_ATTACHED)
  722.         {
  723.         errno = S_smPktLib_DEST_NOT_ATTACHED;
  724.         return (ERROR); /* dest cpu is not attached */
  725.         }
  726.     /* Complete packet header info */
  727.     pPktv->header.srcCpu   = htonl (pSmDesc->cpuNum); /* source cpu */
  728.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  729.     i = pPktv->header.srcCpu; /* BRIDGE FLUSH  [SPR 68334] */
  730.     /* Add this packet to destination cpu's input list */
  731.     status = smPktSllPut (&(pPktCpuDesc->inputList), pSmDesc->base,
  732.   pSmDesc->tasRoutine, pSmDesc->tasClearRoutine, 
  733.   &(pPktv->header.node), &listWasEmpty);
  734.     if ((status == OK) && (listWasEmpty) && (destCpu != pSmDesc->cpuNum))
  735.         {
  736. /* Interrupt destination cpu */
  737. if ((status = smUtilIntGen ((SM_CPU_DESC *)pCpuDesc, destCpu)) != OK)
  738.             {
  739.             /*
  740.              * Packet put in input list but interrupt failed.
  741.              * This is not an error.  It means another interrupt will have
  742.              * to be sent after a short delay.  This will be repeated until
  743.              * the interrupt is successful or a timeout occurs.
  744.              * (See SPR 25341, 33771)
  745.              */
  746.             for (i = smPktMaxIntRetries; (status != OK) && (i > 0); --i)
  747.                 {
  748.                 taskDelay (1);
  749.                 status = smUtilIntGen ((SM_CPU_DESC *)pCpuDesc, destCpu);
  750.                 }
  751.             /* time out on interrupt generation */
  752.             if (status != OK)
  753.                 {
  754.                 /* packet still in input list so do NOT delete it */
  755.                 errno = S_smPktLib_INCOMPLETE_BROADCAST;
  756.                 }
  757.             }
  758.         }
  759.     return (status);
  760.     }
  761. /******************************************************************************
  762. *
  763. * smPktBroadcast - send packet data to all attached CPU's via shared memory
  764. *
  765. * This sends a copy of the packet specified by <pPkt> to all CPU's attached
  766. * to the specified shared memory area (except the sending CPU).
  767. *
  768. * This routine attempts to obtain a new packet for each destination CPU,
  769. * copying the packet contents to each newly-acquired packet.  If no new
  770. * packets are available, this routine will go ahead and send the original
  771. * packet to the next destination CPU.  If there are still more destinations
  772. * after the original has been sent, an error (S_smPktLib_INCOMPLETE_BROADCAST)
  773. * is returned.  This same error is returned if one or more destinations did
  774. * not receive the broadcast due to other problems (e.g. the input queue for
  775. * a destination CPU was full).
  776. *
  777. * RETURNS: OK, or ERROR.
  778. *
  779. * ERRNO: S_smPktLib_INCOMPLETE_BROADCAST
  780. */
  781. LOCAL STATUS smPktBroadcast
  782.     (
  783.     SM_PKT_DESC * pSmPktDesc, /* sh mem pkt descriptor */
  784.     SM_PKT volatile * pPktOrig /* ptr to original packet */
  785.     )
  786.     {
  787.     STATUS status; /* return status */
  788.     SM_PKT volatile * pPkt; /* ptr to packet being sent */
  789.     SM_PKT volatile * pPktNew; /* ptr to newly obtained pkt */
  790.     int destCpu; /* destination cpu number */
  791.     SM_CPU_DESC volatile * pCpuDesc; /* destination cpu descriptor*/
  792.     SM_PKT_CPU_DESC volatile * pPktCpuDesc; /* destination cpu descriptor*/
  793.     BOOL destMissed; /* TRUE if a dest was missed */
  794.     BOOL listWasEmpty; /* list added to was empty */
  795.     SM_DESC * pSmDesc = (SM_DESC *) &pSmPktDesc->smDesc;
  796.     pCpuDesc = pSmDesc->cpuTblLocalAdrs;
  797.     pPktCpuDesc = pSmPktDesc->cpuLocalAdrs;
  798.     destMissed = FALSE; /* no destinations missed yet */
  799.     /* Send copy of packet to each attached cpu (except self) */
  800.     for (destCpu = 0;  destCpu < pSmDesc->maxCpus;  destCpu++)
  801.         {
  802.         if ((ntohl (pPktCpuDesc->status) == SM_CPU_ATTACHED)  &&
  803.     (destCpu != pSmDesc->cpuNum))
  804.          {
  805.          if (pPktOrig == NULL) /* if original already used */
  806.           {
  807.           destMissed = TRUE; /* weren't enough free packets*/
  808.           break; /* can't do any more */
  809.           }
  810.     /* Get new packet */
  811.          if (smPktFreeGet (pSmPktDesc, (SM_PKT **)&pPktNew) != OK)
  812.           return (ERROR); /* error getting packet */
  813.          if (pPktNew != NULL) /* if a new pkt was obtained */
  814.           {
  815. pPkt = pPktNew; /* it is the packet to send */
  816.           pPkt->header.type   = pPktOrig->header.type;
  817. /* copy packet type */
  818.           pPkt->header.nBytes = pPktOrig->header.nBytes;
  819. /* copy byte count */
  820.           bcopy ((char *)pPktOrig->data, (char *)pPkt->data,
  821.                  ntohl (pPkt->header.nBytes));
  822.      /* copy packet data */
  823.           }
  824.          else /* if could not get new pkt */
  825.           {
  826.           pPkt = pPktOrig; /*  set up to send original */
  827.           }
  828.          pPkt->header.srcCpu  = htonl (pSmDesc->cpuNum);
  829. /* source cpu number */
  830.          /* Send packet */
  831.             status = smPktSllPut (&(pPktCpuDesc->inputList), pSmDesc->base, 
  832.   pSmDesc->tasRoutine, pSmDesc->tasClearRoutine,
  833.                &(pPkt->header.node), &listWasEmpty);
  834.             if ((status == OK) && listWasEmpty) /* if list previously empty */
  835.          {
  836. /* Interrupt destination CPU */
  837.          if (smUtilIntGen ((SM_CPU_DESC *)pCpuDesc, destCpu) != OK)
  838.     {
  839.     destMissed = TRUE; /* a destination was missed */
  840.     }
  841.          }
  842.          else if (status == ERROR) /* if error sending pkt */
  843. {
  844. /*
  845.  *  NOTE: We do not return just because an error occurred.
  846.  *        The destination cpu's input list may simply have been
  847.  *        full, or some other error may have occurred which
  848.  *   will not affect the remaining destinations.  When
  849.  *   this routine ultimately returns, the broadcast will
  850.  *   be reported as having been incomplete.
  851.  */
  852. destMissed = TRUE; /* a destination was missed */
  853. if (pPkt != pPktOrig) /* if pkt was not the original*/
  854.              {
  855.               /* New packet not sent - return to free pool */
  856.              if (smPktFreePut (pSmPktDesc, (SM_PKT *)pPkt) != OK)
  857.           return (ERROR); /* could not return packet */
  858.     }
  859.           }
  860.          if (pPkt == pPktOrig  &&  status != ERROR)
  861.           { /* if original actually sent */
  862.           pPktOrig = NULL; /*  clear pointer to orig pkt */
  863.           }
  864.          }  /* end if (attached) */
  865.         pCpuDesc++; /* next cpu descriptor */
  866. pPktCpuDesc++;
  867.         }  /* end for */
  868.     /* Free original packet if it wasn't sent during broadcast */
  869.     if (pPktOrig != NULL)
  870.         {
  871.         if (smPktFreePut (pSmPktDesc, (SM_PKT *)pPktOrig) != OK)
  872.          return (ERROR); /* could not free packet */
  873.         }
  874.     if (destMissed) /* if a destination was missed*/
  875. {
  876.      errno = S_smPktLib_INCOMPLETE_BROADCAST;
  877.      return (ERROR); /* broadcast not complete */
  878.      }
  879.     else
  880. {
  881.      return (OK);
  882. }
  883.     }
  884. /******************************************************************************
  885. *
  886. * smPktFreePut - return a shared memory packet to free list
  887. *
  888. * This routine frees a shared memory packet.  The packet is placed
  889. * on the global free packet list.  No modification of the packet
  890. * contents is performed.
  891. *
  892. * The address of the packet to be returned is specified in <pPkt>.
  893. *
  894. * RETURNS: OK, or ERROR.
  895. *
  896. * ERRNO: S_smPktLib_NOT_ATTACHED, S_smPktLib_INVALID_PACKET
  897. */
  898. STATUS smPktFreePut
  899.     (
  900.     SM_PKT_DESC * pSmPktDesc, /* ptr to shared memory descriptor */
  901.     SM_PKT * pPkt /* addr of packet to be returned */
  902.     )
  903.     {
  904.     SM_DESC * pSmDesc = &pSmPktDesc->smDesc;
  905.     /* Check that this cpu is connected to shared memory */
  906.     if (pSmPktDesc->status != SM_CPU_ATTACHED)
  907. {
  908. errno = S_smPktLib_NOT_ATTACHED;
  909. return (ERROR); /* local cpu is not attached */
  910. }
  911.     /* Check for null pointer */
  912.     if (pPkt == NULL)
  913. {
  914. errno = S_smPktLib_INVALID_PACKET;
  915. return (ERROR); /* null packet address */
  916. }
  917.     /* Return packet to free list */
  918.     return (smPktSllPut (&(pSmPktDesc->hdrLocalAdrs->freeList), pSmDesc->base, 
  919.  pSmDesc->tasRoutine, pSmDesc->tasClearRoutine, 
  920.  &(pPkt->header.node), NULL));
  921.     }
  922. /******************************************************************************
  923. *
  924. * smPktRecv - receive a packet sent via shared memory
  925. *
  926. * This routine receives a shared memory packet which was queued to this CPU.
  927. * This routine should be called in response to an interrupt which notifies
  928. * this CPU of the packet, or it can be called repeatedly in a polling
  929. * fashion to check for input packets.  (NOTE: An interrupt will be generated
  930. * only if there previously was not a packet queued to this CPU.  Therefore,
  931. * after a packet is received, this routine should be called again to check
  932. * for more packets.)
  933. *
  934. * Upon return, the location indicated by <ppPkt> will contain the address
  935. * of the received packet, or NULL if there was none.
  936. *
  937. * RETURNS: OK, or ERROR.
  938. *
  939. * ERRNO: S_smPktLib_NOT_ATTACHED
  940. */
  941. STATUS smPktRecv
  942.     (
  943.     SM_PKT_DESC * pSmPktDesc, /* shared memory descriptor */
  944.     SM_PKT ** ppPkt /* location to put pkt addr */
  945.     )
  946.     {
  947.     SM_PKT_CPU_DESC volatile * pPktCpuDesc;
  948.     STATUS status;
  949.     SM_DESC * pSmDesc = (SM_DESC *) &pSmPktDesc->smDesc;
  950.     int                         tmp;         /* temp storage */
  951.     /* Check that this cpu is connected to shared memory */
  952.     if (pSmPktDesc->status != SM_CPU_ATTACHED)
  953. {
  954. errno = S_smPktLib_NOT_ATTACHED;
  955. return (ERROR); /* local cpu is not attached */
  956. }
  957.     /* Get packet (if any) from input list */
  958.     pPktCpuDesc = &((pSmPktDesc->cpuLocalAdrs) [pSmDesc->cpuNum]);
  959.      /* get addr of cpu descriptor */
  960.     status = smPktSllGet (&(pPktCpuDesc->inputList), pSmDesc->base,
  961.               pSmDesc->tasRoutine, pSmDesc->tasClearRoutine, 
  962.   (SM_SLL_NODE **) ppPkt);
  963.     if ((status == OK) && (*ppPkt != NULL))
  964. {
  965. (*ppPkt)->header.nBytes = ntohl ((*ppPkt)->header.nBytes);
  966. (*ppPkt)->header.srcCpu = ntohl ((*ppPkt)->header.srcCpu);
  967.         CACHE_PIPE_FLUSH ();                    /* CACHE FLUSH   [SPR 68334] */
  968.         tmp = (*ppPkt)->header.srcCpu; /* BRIDGE FLUSH  [SPR 68334] */
  969. }
  970.     return (status);
  971.     }
  972. /******************************************************************************
  973. *
  974. * smPktSllGet - get a shared memory node from a singly-linked list
  975. *
  976. * This routine attempts to obtain a shared memory node from the
  977. * specified singly-linked list of nodes.  If a node is available,
  978. * the local address (for this CPU) of the node is placed in the
  979. * location specified by <pNodeLocalAdrs>.  If no node was available
  980. * from the list, a NULL is placed in this location.
  981. *
  982. * This routine uses the specified test-and-set function, <tasRoutine>, to
  983. * obtain exclusive access to the linked list lock.  If the lock cannot
  984. * be acquired within the number of tries specified by the smPktTasTries
  985. * global variable, this routine will return ERROR.
  986. *
  987. * RETURNS: OK, or ERROR if could not acquire list lock.
  988. *
  989. * ERRNO: S_smPktLib_LOCK_TIMEOUT
  990. */
  991. LOCAL STATUS smPktSllGet
  992.     (
  993.     SM_SLL_LIST volatile * listLocalAdrs, /* local addr of packet list */
  994.     int                    baseAddr, /* addr conversion constant */
  995.     FUNCPTR                tasRoutine, /* test-and-set routine addr */
  996.     FUNCPTR                tasClearRoutine, /* test-and-set routine addr */
  997.     SM_SLL_NODE **    pNodeLocalAdrs /* location to put node addr */
  998.     )
  999.     {
  1000.     int                    oldLvl; /* saved interrupt level */
  1001.     int    count; /* temp value */
  1002.     SM_SLL_NODE volatile * pNode; /* pointer to node */
  1003.     /* Take list lock */
  1004.     if (SM_LOCK_TAKE ((int *)&(listLocalAdrs->lock), tasRoutine, smPktTasTries,
  1005.                       &oldLvl) != OK)
  1006.         {
  1007.      errno = S_smPktLib_LOCK_TIMEOUT;
  1008.         return (ERROR);                         /* can't take lock */
  1009.         }
  1010.     /* Get first node from list, if any */
  1011.     if ((pNode = (SM_SLL_NODE volatile *) ntohl (listLocalAdrs->head)) != NULL)
  1012.         {
  1013.         pNode = SM_OFFSET_TO_LOCAL ((int) pNode, baseAddr, SM_SLL_NODE *);
  1014.                                                 /* convert to local address */
  1015.         listLocalAdrs->head = pNode->next;      /* next node (if any) is head */
  1016.         count = ntohl (listLocalAdrs->count) - 1;
  1017.         if (count <= 0)                      /* if list now empty */
  1018.             {
  1019.             listLocalAdrs->tail = htonl (0); /*  clear tail pointer */
  1020.             count = 0;
  1021.             }
  1022.         listLocalAdrs->count = htonl (count);
  1023.         }
  1024.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  1025.     count = listLocalAdrs->limit; /* BRIDGE FLUSH  [SPR 68334] */
  1026.     /* Release list lock */
  1027.     SM_LOCK_GIVE ((int *)&(listLocalAdrs->lock), tasClearRoutine, oldLvl);
  1028.     /* Pass node address back to caller */
  1029.     *pNodeLocalAdrs = (SM_SLL_NODE *) pNode;    /* local node addr, or NULL */
  1030.     return (OK);
  1031.     }
  1032. /******************************************************************************
  1033. *
  1034. * smPktSllPut - add a shared memory node to a singly-linked list
  1035. *
  1036. * This routine attempts to add a shared memory node to the specified
  1037. * singly-linked list.  The node to be added is identified by <nodeLocalAdrs>.
  1038. * Unless the list has reached its maximum number of entries, the node
  1039. * will be added at the tail of the list.  The bus address of the node is
  1040. * used in the list entry.
  1041. *
  1042. * This routine uses the specified test-and-set function, <tasRoutine>, to
  1043. * obtain exclusive access to the linked list lock.  If the lock cannot
  1044. * be acquired within the number of tries specified by the smPktTasTries
  1045. * global variable, this routine will return ERROR.
  1046. *
  1047. * If the list already contains its maximum number of node entries, this
  1048. * routine will return ERROR.
  1049. *
  1050. * If <pListWasEmpty> is non-null and the node is successfully added
  1051. * to the list, this routine will set the BOOL pointed to by
  1052. * <pListWasEmpty> to TRUE if there were no previous nodes in the list.
  1053. *
  1054. * RETURNS: OK, or ERROR if packet ptr is NULL, list full, or could
  1055. * not acquire list lock.
  1056. *
  1057. * ERRNO: S_smPktLib_LOCK_TIMEOUT, S_smPktLib_LIST_FULL
  1058. */
  1059. LOCAL STATUS smPktSllPut
  1060.     (
  1061.     SM_SLL_LIST volatile * listLocalAdrs, /* local addr of packet list */
  1062.     int    base, /* base address */
  1063.     FUNCPTR    tasRoutine, /* test-and-set routine addr */
  1064.     FUNCPTR    tasClearRoutine, /* test-and-set routine addr */
  1065.     SM_SLL_NODE volatile * nodeLocalAdrs, /* local addr of node */
  1066.     BOOL *    pListWasEmpty /* set to true if adding to
  1067.                                                  * empty list */
  1068.     )
  1069.     {
  1070.     int    oldLvl; /* saved interrupt level */
  1071.     int    nodeOff; /* pointer to node */
  1072.     SM_SLL_NODE volatile * tailLocalAdrs; /* pointer to list tail node */
  1073.     nodeLocalAdrs->next = 0;         /* mark node as end of list */
  1074.     nodeOff = htonl (SM_LOCAL_TO_OFFSET (nodeLocalAdrs, base));
  1075.     /* Take list lock */
  1076.     if (SM_LOCK_TAKE ((int *)&(listLocalAdrs->lock), tasRoutine, smPktTasTries,
  1077.                       &oldLvl) != OK)
  1078.         {
  1079.      errno = S_smPktLib_LOCK_TIMEOUT;
  1080.         return (ERROR);                         /* can't take lock */
  1081.         }
  1082.     /* Add node to list */
  1083.     if (ntohl (listLocalAdrs->count) >= ntohl (listLocalAdrs->limit))
  1084.         {
  1085.         SM_LOCK_GIVE ((int *)&(listLocalAdrs->lock), tasClearRoutine, oldLvl);
  1086.         errno = S_smPktLib_LIST_FULL;
  1087.         return (ERROR);                         /* list has max nodes already */
  1088.         }
  1089.                                                 /* if list previously empty */
  1090.     if (ntohl (listLocalAdrs->tail) == 0)
  1091.         {
  1092.         if (pListWasEmpty != NULL)
  1093.             *pListWasEmpty = TRUE;
  1094.         /* node is new head also */
  1095.         listLocalAdrs->head = nodeOff;
  1096.         }
  1097.     else
  1098.         {
  1099.         if (pListWasEmpty != NULL)
  1100.             *pListWasEmpty = FALSE;
  1101.         tailLocalAdrs = SM_OFFSET_TO_LOCAL (ntohl (listLocalAdrs->tail),
  1102.                                             base, SM_SLL_NODE volatile *);
  1103.                                                 /* get addr of tail node */
  1104.         tailLocalAdrs->next = nodeOff;
  1105.                                              /* link new node to old tail */
  1106.         }
  1107.     listLocalAdrs->tail  = nodeOff;
  1108.                                                 /* node is new tail */
  1109.     listLocalAdrs->count = ntohl (htonl (listLocalAdrs->count) + 1);
  1110.                                                 /* one more node in list */
  1111.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  1112.     nodeOff = listLocalAdrs->limit; /* BRIDGE FLUSH  [SPR 68334] */
  1113.     /* Release list lock */
  1114.     SM_LOCK_GIVE ((int *)&(listLocalAdrs->lock), tasClearRoutine, oldLvl);
  1115.     return (OK);
  1116.     }
  1117. /******************************************************************************
  1118. *
  1119. * smPktDetach - detach CPU from shared memory
  1120. *
  1121. * This routine ends the "attachment" between the calling CPU and
  1122. * the shared memory area specified by <pSmPktDesc>.  No further shared
  1123. * memory operations may be performed until a subsequent smPktAttach()
  1124. * is completed.
  1125. *
  1126. * RETURNS: OK, or ERROR.
  1127. *
  1128. * ERRNO: S_smPktLib_NOT_ATTACHED
  1129. */
  1130. STATUS smPktDetach
  1131.     (
  1132.     SM_PKT_DESC * pSmPktDesc, /* ptr to shared mem descriptor */
  1133.     BOOL noFlush /* true if input queue should not
  1134.  * be flushed */
  1135.     )
  1136.     {
  1137.     SM_PKT_CPU_DESC volatile * pPktCpuDesc; /* cpu descriptor */
  1138.     SM_PKT volatile * pPkt; /* pointer to input packet */
  1139.     SM_DESC * pSmDesc = (SM_DESC *) &pSmPktDesc->smDesc;
  1140.     int                         tmp;            /* temp storage */
  1141.     /* Check that this cpu is connected to shared memory */
  1142.     if (pSmPktDesc->status != SM_CPU_ATTACHED)
  1143. {
  1144. errno = S_smPktLib_NOT_ATTACHED;
  1145. return (ERROR); /* local cpu is not attached */
  1146. }
  1147.     if (smDetach (pSmDesc) == ERROR)
  1148. return (ERROR);
  1149.     /* get addr of cpu descriptor */
  1150.     pPktCpuDesc = (SM_PKT_CPU_DESC volatile *) &((pSmPktDesc->cpuLocalAdrs) 
  1151.                                                   [pSmDesc->cpuNum]);
  1152.     pPktCpuDesc->status = htonl (SM_CPU_NOT_ATTACHED);/* mark as not attached */
  1153.     pSmPktDesc->status  = SM_CPU_NOT_ATTACHED;   /* also mark sh mem descr */
  1154.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  1155.     tmp = pPktCpuDesc->status;                  /* BRIDGE FLUSH  [SPR 68334] */
  1156.     if (noFlush == FALSE) /* flush input queue */
  1157. {
  1158. FOREVER
  1159.     {
  1160.     if (smPktSllGet (&(pPktCpuDesc->inputList), pSmDesc->base,
  1161.      pSmDesc->tasRoutine, pSmDesc->tasClearRoutine,
  1162.      (SM_SLL_NODE **) &pPkt) != OK)
  1163. return (ERROR); /* error getting input packet */
  1164.     if (pPkt == NULL)
  1165. break; /* no more input packets */
  1166.     if (smPktSllPut (&(pSmPktDesc->hdrLocalAdrs->freeList),
  1167.      pSmDesc->base, pSmDesc->tasRoutine,
  1168.      pSmDesc->tasClearRoutine,
  1169.             &(pPkt->header.node), NULL) != OK)
  1170. return (ERROR); /* error adding to free list */
  1171.    }
  1172. }
  1173.     return (OK);
  1174.     }
  1175. /******************************************************************************
  1176. *
  1177. * smPktInfoGet - get current status information about shared memory
  1178. *
  1179. * This routine obtains various pieces of information which describe the
  1180. * current state of the shared memory area specified by <pSmPktDesc>.  The
  1181. * current information is returned in a special data structure, SM_PKT_INFO,
  1182. * whose address is specified by <pInfo>.  The structure must have been
  1183. * allocated before this routine is called.
  1184. *
  1185. * RETURNS: OK, or ERROR if this CPU is not attached to shared memory area.
  1186. *
  1187. * ERRNO: S_smPktLib_NOT_ATTACHED
  1188. */
  1189. STATUS smPktInfoGet
  1190.     (
  1191.     SM_PKT_DESC * pSmPktDesc, /* shared memory descriptor */
  1192.     SM_PKT_INFO * pInfo /* info structure to fill */
  1193.     )
  1194.     {
  1195.     SM_PKT_MEM_HDR volatile * pHdr; /* shared memory header */
  1196.     SM_PKT_CPU_DESC volatile * pCpuDesc; /* cpu descriptor */
  1197.     int ix; /* index variable */
  1198.     int                         tmp;            /* temp storage */
  1199.     /* Check that this cpu is connected to shared memory */
  1200.     if (pSmPktDesc->status != SM_CPU_ATTACHED)
  1201. {
  1202. errno = S_smPktLib_NOT_ATTACHED;
  1203. return (ERROR); /* local cpu is not attached */
  1204. }
  1205.     if (smInfoGet (&(pSmPktDesc->smDesc), &(pInfo->smInfo)) == ERROR)
  1206. return (ERROR);
  1207.     /* Use local address to get info from shared memory packet header */
  1208.     pHdr = (SM_PKT_MEM_HDR volatile *) pSmPktDesc->hdrLocalAdrs;
  1209.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  1210.     tmp = pHdr->maxPktBytes;                    /* PCI bridge bug [SPR 68844]*/
  1211.     pInfo->maxPktBytes = ntohl (pHdr->maxPktBytes);/* max data bytes per pkt */
  1212.     pInfo->totalPkts   = ntohl (pHdr->freeList.limit);/* total number */
  1213.     pInfo->freePkts    = ntohl (pHdr->freeList.count);/* number free */
  1214.     /* Get count of attached cpu's starting with first cpu table entry */
  1215.     pCpuDesc = (SM_PKT_CPU_DESC volatile *) pSmPktDesc->cpuLocalAdrs;
  1216.     pInfo->attachedCpus = 0;
  1217.     for (ix = 0;  ix < pInfo->smInfo.maxCpus;  ix++)
  1218. {
  1219. if (ntohl (pCpuDesc->status) == SM_CPU_ATTACHED)
  1220.     pInfo->attachedCpus++;
  1221. pCpuDesc++; /* next entry */
  1222. }
  1223.     return (OK);
  1224.     }
  1225. /******************************************************************************
  1226. *
  1227. * smPktCpuInfoGet - get information about a single CPU using shared memory
  1228. *
  1229. * This routine obtains a variety of information describing the CPU specified
  1230. * by <cpuNum>.  If <cpuNum> is NONE (-1), this routine returns information
  1231. * about the local (calling) CPU.  The information is returned in a special
  1232. * structure, SM_PKT_CPU_INFO, whose address is specified by <pCpuInfo>.  (The
  1233. * structure must have been allocated before this routine is called.)
  1234. *
  1235. * RETURNS: OK, or ERROR.
  1236. *
  1237. * ERRNO: S_smPktLib_NOT_ATTACHED
  1238. */
  1239. STATUS smPktCpuInfoGet
  1240.     (
  1241.     SM_PKT_DESC * pSmPktDesc, /* pkt descriptor */
  1242.     int cpuNum, /* cpu to get info about */
  1243.     SM_PKT_CPU_INFO * pCpuInfo /* structure to fill */
  1244.     )
  1245.     {
  1246.     SM_PKT_CPU_DESC volatile * pCpuDesc; /* ptr to cpu descriptor */
  1247.     int                        tmp;             /* temp storage */
  1248.     /* Check that the local cpu is connected to shared memory */
  1249.     if (pSmPktDesc->status != SM_CPU_ATTACHED)
  1250. {
  1251. errno = S_smPktLib_NOT_ATTACHED;
  1252. return (ERROR); /* local cpu is not attached */
  1253. }
  1254.     if (cpuNum == NONE)
  1255. cpuNum = pSmPktDesc->smDesc.cpuNum;
  1256.     if (smCpuInfoGet (&(pSmPktDesc->smDesc), cpuNum,
  1257.       &(pCpuInfo->smCpuInfo)) == ERROR)
  1258. return (ERROR);
  1259.     /* get address of cpu descr */
  1260.     pCpuDesc = (SM_PKT_CPU_DESC volatile *)&(pSmPktDesc->cpuLocalAdrs[cpuNum]);
  1261.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  1262.     tmp = pCpuDesc->status;                     /* PCI bridge bug [SPR 68844]*/
  1263.     pCpuInfo->status  = ntohl (pCpuDesc->status);/* attached or not attached */
  1264.     /* Get packet counts */
  1265.     pCpuInfo->inputPkts    = ntohl (pCpuDesc->inputList.count);
  1266. /* current pkts in input queue*/
  1267.     pCpuInfo->maxInputPkts = ntohl (pCpuDesc->inputList.limit);
  1268. /* max pkts allowed in queue */
  1269.     /*
  1270.      * XXX - free list counts - for future use when cpu's have free lists...
  1271.      *
  1272.      * pCpuInfo->freePkts  = ntohl (pCpuDesc->freeList.count);
  1273.      * pCpuInfo->totalPkts = ntohl (pCpuDesc->freeList.limit);
  1274.      *
  1275.      */
  1276.     pCpuInfo->freePkts  = 0; /* (future use) */
  1277.     return (OK);
  1278.     }
  1279. /******************************************************************************
  1280. *
  1281. * smPktBeat - increment packet heartbeat in shared memory anchor
  1282. *
  1283. * This routine increments the shared memory packet "heartbeat".  The heartbeat
  1284. * is used by processors using the shared memory packet library to
  1285. * confirm that the shared memory network is active.  The shared memory
  1286. * area whose heartbeat is to be incremented is specifed by <pSmPktHdr>, which
  1287. * is the address of a shared memory packet header region in which the heartbeat
  1288. * count is maintained.
  1289. *
  1290. * This routine should be called periodically by the master CPU.
  1291. *
  1292. * RETURNS: N/A
  1293. */
  1294. void smPktBeat 
  1295.     (
  1296.     SM_PKT_MEM_HDR * pSmPktHdr  /* ptr to sm packet header */
  1297.     )
  1298.     {
  1299.     SM_PKT_MEM_HDR volatile * pPktHdrv = (SM_PKT_MEM_HDR volatile *) pSmPktHdr;
  1300.     int                       tmp;              /* temp storage */
  1301.     /* Increment heartbeat */
  1302.     tmp = pPktHdrv->heartBeat;                  /* PCI bridge bug [SPR 68844]*/
  1303.     pPktHdrv->heartBeat = htonl (ntohl (pPktHdrv->heartBeat) + 1);
  1304.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  1305.     tmp = pPktHdrv->heartBeat;                  /* BRIDGE FLUSH  [SPR 68334] */
  1306.     }