📄 smpktlib.c
字号:
#endif /* __STDC__ *//******************************************************************************** smPktSetup - set up shared memory (master CPU only)** This routine should be called only by the master CPU using shared* memory. It initializes the specified memory area for use by the* shared memory protocol.** After the shared memory has been initialized, this and other CPU's* may initialize a shared memory packet descriptor to it, using smPktInit(),* and then attach to the shared memory area, using smPktAttach().** The <anchorLocalAdrs> parameter is the memory address by which the master* CPU accesses the shared memory anchor.** The <smLocalAdrs> parameter is the memory address by which the master* CPU accesses the actual shared memory region to be initialized.** The <smSize> parameter is the size, in bytes, of the shared memory* region.** The shared memory routines must be able to obtain exclusive access to* shared data structures. To allow this, a test-and-set operation is* used. It is preferable to use a genuine test-and-set instruction, if* the hardware being used permits this. If this is not possible, smUtilLib* provides a software emulation of test-and-set. The <tasType> parameter* specifies what method of test-and-set is to be used.** The <maxCpus> parameter specifies the maximum number of CPU's which may* use the shared memory region.** The <maxPktBytes> parameter specifies the size, in bytes, of the data* buffer in shared memory packets. This is the largest amount of data* which may be sent in a single packet. If this value is not an exact* multiple of 4 bytes, it will be rounded up to the next multiple of 4.** INTERNAL* The first item in the shared memory area is the shared memory packet* header (SM_PKT_MEM_HDR). Following this is an array of CPU * descriptors (SM_PKT_CPU_DESC); this table contains one CPU descriptor * for each possible CPU, as specified by <maxCpus>.* The shared memory area following the cpu table is allocated to the global* list of free packets (SM_PKT), used for sending data between CPU's. Note* that the shared memory anchor is NOT part of the regular shared memory area.** Since the size of each data packet is not pre-determined, the actual size* is calculated based on the size of the (fixed) packet header and the* data buffer size, specified by <maxPktBytes>.** The standard smPktSllPut routine is used to build the free packet list.* The software test-and-set routine is always used, regardless of the* definition of <tasType>, because no hardware TAS routine has been supplied* yet. (That is done during smPktAttach.) Use of any TAS method at this* stage is mainly a formality, since no other CPU's are able to attach to* the shared memory region.** RETURNS: OK, or ERROR.** ERRNO: S_smPktLib_SHARED_MEM_TOO_SMALL, S_smPktLib_MEMORY_ERROR** INTERNAL: This routine and smObjSetup can not be called at the same time!!!*/STATUS smPktSetup ( SM_ANCHOR * anchorLocalAdrs, /* local addr of anchor */ char * smLocalAdrs, /* local addr of sh mem area */ int smSize, /* size of shared memory area */ int tasType, /* test and set type */ int maxCpus, /* max number of cpus */ int maxPktBytes /* max bytes of packet data */ ) { SM_ANCHOR volatile * pAnchorv = (SM_ANCHOR volatile *) anchorLocalAdrs; SM_PKT_MEM_HDR volatile * smPktHdr; /* local addr of sh mem hdr */ int pktSize; /* actual size of pkt */ STATUS status; /* return status */ SM_PKT volatile * pPkt; /* local addr of free packet */ int memLeft; char temp = 0; int base = (int) anchorLocalAdrs; int bytesUsed = 0; int tmp; /* temp storage */ /* set up default values for parameters */ smSize = (smSize == 0) ? smPktMemSizeDefault : smSize; maxCpus = (maxCpus == 0) ? smPktMaxCpusDefault : maxCpus; maxPktBytes = (maxPktBytes == 0) ? smPktMaxBytesDefault : maxPktBytes; maxPktBytes = ((maxPktBytes + sizeof (int) - 1) / sizeof (int)) * sizeof (int); /* round up buf to int mult */ pktSize = (sizeof (SM_PKT_HDR) + maxPktBytes); /* pkt size incl data buffer */ if (smSetup (anchorLocalAdrs, smLocalAdrs, tasType, maxCpus, &bytesUsed) == ERROR) return (ERROR); smSize -= bytesUsed; smLocalAdrs += bytesUsed; /* * Check that shared mem size is big enough to contain: * the shared memory packet header, the shared memory packet * cpu descriptors and 1 pkt per cpu. */ if (smSize < (sizeof (SM_PKT_MEM_HDR) + (maxCpus * sizeof (SM_PKT_CPU_DESC)) + (maxCpus * pktSize))) { errno = S_smPktLib_SHARED_MEM_TOO_SMALL; return (ERROR); /* not enough sh mem */ } /* Probe beginning and end of shared memory */ if ((smUtilMemProbe (smLocalAdrs , VX_WRITE, sizeof (char), &temp) != OK) || (smUtilMemProbe (smLocalAdrs + smSize - 1, VX_WRITE, sizeof (char), &temp) != OK)) { errno = S_smPktLib_MEMORY_ERROR; return (ERROR); } /* Clear shared memory */ bzero (smLocalAdrs, smSize); /* Fill in header */ smPktHdr = (SM_PKT_MEM_HDR volatile *) smLocalAdrs; smPktHdr->maxPktBytes = htonl (maxPktBytes);/* max size of pkt data buf */ smPktHdr->pktCpuTbl = htonl (SM_LOCAL_TO_OFFSET ((char *) smPktHdr + sizeof (SM_PKT_MEM_HDR), base)); pAnchorv->smPktHeader = htonl (SM_LOCAL_TO_OFFSET (smLocalAdrs, base)); /* Set up list of free packets */ pPkt = (SM_PKT *) (smLocalAdrs + sizeof (SM_PKT_MEM_HDR) + (maxCpus * sizeof (SM_PKT_CPU_DESC))); /* calculate addr of 1st pkt */ memLeft = smSize - ((int) ((char *) pPkt - smLocalAdrs)); /* calculate remaining sh mem */ while (memLeft >= pktSize) { /* allow one more in free list*/ smPktHdr->freeList.limit = htonl (ntohl (smPktHdr->freeList.limit) +1); /* Add packet to list, always use software test-and-set emulation */ status = smPktSllPut (&(smPktHdr->freeList), base, smUtilSoftTas, NULL, &(pPkt->header.node), NULL); if (status == ERROR) { smPktHdr->freeList.limit = htonl (ntohl (smPktHdr->freeList.limit) - 1); return (ERROR); /* error adding to free list */ } pPkt = (SM_PKT *) ((char *) pPkt + pktSize);/* advance pkt pointer */ memLeft -= pktSize; /* decrease mem remaining */ } CACHE_PIPE_FLUSH (); /* CACHE FLUSH [SPR 68334] */ tmp = smPktHdr->freeList.limit; /* BRIDGE FLUSH [SPR 68334] */ return (OK); /* shared mem init complete */ }/******************************************************************************** smPktInit - initialize shared memory packet descriptor** This routine initializes a shared memory packet descriptor. The descriptor* must have been previously allocated (generally in the CPU's local* memory). Once the descriptor has been initialized by this routine,* the CPU may attach itself to the shared memory area by calling* smPktAttach().** Only the shared memory descriptor itself is modified by this routine.* No structures in shared memory are affected.** The <pSmPktDesc> paramter is the address of the shared memory packet * descriptor which is to be initialized; this structure must have * already been allocated before smPktInit is called.** The <anchorLocalAdrs> parameter is the memory address by which the local* CPU may access the shared memory anchor. This address may vary for* different CPU's because of address offsets (particularly if the anchor is* located in one CPU's dual-ported memory).** The <maxInputPkts> parameter specifies the maximum number of incoming* shared memory packets which may be queued to this CPU at one time. If* a remote CPU attempts to send more packets after this limit is reached,* an error will be returned to the remote CPU.** The <ticksPerBeat> parameter specifies the frequency of the shared memory* heartbeat. The frequency is expressed in terms of how many CPU* ticks on the local CPU correspond to one heartbeat period.** The <intType>, <intArg1>, <intArg2>, and <intArg3> parameters allow a* CPU to announce the method by which it is to be notified of input packets* which have been queued to it. Once this CPU has attached to the shared* memory region, other CPU's will be able to determine these interrupt* parameters by calling smPktCpuInfoGet(). The following interrupt * methods are currently recognized by this library: SM_INT_MAILBOX, * SM_INT_BUS, SM_INT_NONE, and SM_INT_USER .** RETURNS: N/A*/void smPktInit ( SM_PKT_DESC * pSmPktDesc, /* ptr to sh mem packet descr */ SM_ANCHOR * anchorLocalAdrs, /* local addr of sh mem anchor*/ int maxInputPkts, /* max queued packets allowed */ int ticksPerBeat, /* cpu ticks per heartbeat */ int intType, /* interrupt method */ int intArg1, /* interrupt argument #1 */ int intArg2, /* interrupt argument #2 */ int intArg3 /* interrupt argument #3 */ ) { if (pSmPktDesc == NULL) return; /* don't use null ptr */ bzero ((char *) pSmPktDesc, sizeof (SM_PKT_DESC)); smInit (&pSmPktDesc->smDesc, anchorLocalAdrs, ticksPerBeat, intType, intArg1, intArg2, intArg3); pSmPktDesc->maxInputPkts = (maxInputPkts == 0) ? smPktMaxInputDefault : maxInputPkts; pSmPktDesc->status = SM_CPU_NOT_ATTACHED; /* initial status */ }/******************************************************************************** smPktAttach - attach to shared memory** This routine "attaches" the local CPU to a shared memory area. The* shared memory area is identified by the shared memory packet descriptor* whose address specified by <pSmPktDesc>. The descriptor must have* already been initialized by calling smPktInit().** This routine will complete the attach process only if and when the* shared memory has been initialized by the master CPU. To determine* this, the shared memory anchor is checked for the proper value* (SM_READY_VALUE) in the anchor's ready-value field and a check is made for* an active heartbeat. This repeated checking continues until either * the ready-value and heartbeat have been verified or a timeout limit * is reached. If the shared memory is not recognized as active within * the timeout period, this routine returns an error (S_smPktLib_DOWN).** The attachment to shared memory may be ended by calling smPktDetach().** RETURNS: OK, or ERROR.** ERRNO: S_smPktLib_DOWN** SEE ALSO: smPktInit()*/STATUS smPktAttach ( SM_PKT_DESC * pSmPktDesc /* packet descriptor */ ) { SM_PKT_MEM_HDR volatile * pHdr; /* sm pkt header */ SM_PKT_CPU_DESC volatile * pPktDesc; /* pkt cpu descriptor */ int cpuNum; /* this cpu's number */ SM_ANCHOR volatile * pAnchor; /* anchor */ int beatsToWait; SM_DESC * pSmDesc = (SM_DESC *) &pSmPktDesc->smDesc; cpuNum = pSmDesc->cpuNum; pAnchor = pSmDesc->anchorLocalAdrs; /* Check that shared memory is initialized and running */ /* * XXX master CPU should only wait DEFAULT_BEATS_TO_WAIT but we don't * know who the master is unless we look in the anchor. The anchor may * not be mapped onto the bus, and we will blow up with a BERR if we * poke around. So we just wait a long time, even if we are the master. * This could be fixed by listing the SM master and local processor * numbers in the packet descriptor so that the two could be compared. * If equal, we would be the master and no waiting would be necessary. */ beatsToWait = DEFAULT_ALIVE_TIMEOUT; if (smIsAlive ((SM_ANCHOR *)pAnchor, (int *)&(pAnchor->smPktHeader), pSmDesc->base, beatsToWait, pSmDesc->ticksPerBeat) == FALSE) { errno = S_smPktLib_DOWN; return (ERROR); /* sh memory not active */ } if (smAttach (pSmDesc) == ERROR) return (ERROR); /* Get local address for shared mem packet header */ pHdr = SM_OFFSET_TO_LOCAL (ntohl (pAnchor->smPktHeader), pSmDesc->base, SM_PKT_MEM_HDR volatile *); pSmPktDesc->hdrLocalAdrs = (SM_PKT_MEM_HDR *) pHdr; pSmPktDesc->maxPktBytes = ntohl (pHdr->maxPktBytes); pSmPktDesc->cpuLocalAdrs = SM_OFFSET_TO_LOCAL (ntohl (pHdr->pktCpuTbl), pSmDesc->base, SM_PKT_CPU_DESC *); pPktDesc = &((pSmPktDesc->cpuLocalAdrs) [cpuNum]); /* calculate addr of cpu desc * in global table. */ pPktDesc->inputList.limit = htonl (pSmPktDesc->maxInputPkts); /* max queued count */ pPktDesc->status = htonl (SM_CPU_ATTACHED);/* mark this cpu as attached */ pSmPktDesc->status = SM_CPU_ATTACHED; /* also mark sh mem descr */ CACHE_PIPE_FLUSH (); /* CACHE FLUSH [SPR 68334] */ cpuNum = pPktDesc->status; /* BRIDGE FLUSH [SPR 68334] */ return (OK); /* attach complete */ }/******************************************************************************** smPktFreeGet - get a shared memory packet from free list** This routine obtains a shared memory packet. The packet is taken* from the global free packet list. No initialization of the packet* contents is performed.** The address of the obtained packet is placed in the location specified* by <ppPkt>. If there were no free packets available, this value will* be NULL.** RETURNS: OK, or ERROR.** ERRNO: S_smPktLib_NOT_ATTACHED*/STATUS smPktFreeGet ( SM_PKT_DESC * pSmPktDesc, /* ptr to shared memory descriptor */ SM_PKT ** ppPkt /* location to put packet address */ ) { SM_DESC * pSmDesc = &pSmPktDesc->smDesc; /* Check that this cpu is connected to shared memory */ if (pSmPktDesc->status != SM_CPU_ATTACHED) { errno = S_smPktLib_NOT_ATTACHED; return (ERROR); /* local cpu is not attached */ } /* Get packet from free list */ return (smPktSllGet (&(pSmPktDesc->hdrLocalAdrs->freeList), pSmDesc->base, pSmDesc->tasRoutine, pSmDesc->tasClearRoutine, (SM_SLL_NODE **) ppPkt)); }/******************************************************************************** smPktSend - send a packet via shared memory** This routine queues a packet (previously acquired via smPktFreeGet)* to be received by another CPU. If the input list for the destination* CPU was previously empty and the destination has not specified polling * as its interrupt type, this routine will interrupt the destination CPU. ** If the specified <destCpu> is SM_BROADCAST, a copy of the packet will* be sent to each CPU which is attached to the shared memory area (except* the sender CPU). If there are not enough free packets to send a copy* to each cpu, or if errors occur when sending to one or more destinations,* an error (S_smPktLib_INCOMPLETE_BROADCAST) is returned.** If ERROR is returned and errno equals S_smPktLib_INCOMPLETE_BROADCAST,* the original packet, <pPkt>, was sent to an attached CPU and does not* have to be freed. A return code of ERROR combined with any other value* of errno indicates that <pPkt> was NOT sent and should be explicitly* freed using smPktFreePut(). (A return value of OK indicates that
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -