📄 smpktlib.c
字号:
* <pPkt> was either sent or freed before this routine returned, and no* further action is required.)** RETURNS: OK, or ERROR.** ERRNO: S_smPktLib_NOT_ATTACHED, S_smPktLib_INVALID_PACKET,* S_smPktLib_PACKET_TOO_BIG, S_smPktLib_INVALID_CPU_NUMBER,* S_smPktLib_DEST_NOT_ATTACHED, S_smPktLib_INCOMPLETE_BROADCAST* */STATUS smPktSend ( SM_PKT_DESC * pSmPktDesc, /* ptr to shared memory descriptor */ SM_PKT * pPkt, /* local addr of packet to be sent */ int destCpu /* destination cpu number */ ) { SM_PKT volatile * pPktv = (SM_PKT volatile *) pPkt; STATUS status; /* return status */ SM_PKT_CPU_DESC volatile * pPktCpuDesc; /* destination cpu pkt descr*/ SM_CPU_DESC volatile * pCpuDesc; /* destination cpu descr*/ int i; BOOL listWasEmpty; /* list empty */ SM_DESC * pSmDesc = (SM_DESC *) &pSmPktDesc->smDesc; int tmp; /* temp storage */ /* 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 */ } /* Check for null pointer */ if (pPkt == NULL) { errno = S_smPktLib_INVALID_PACKET; return (ERROR); /* null packet address */ } /* Enforce max data length */ CACHE_PIPE_FLUSH (); /* CACHE FLUSH [SPR 68334] */ tmp = pPktv->header.nBytes; /* BRIDGE FLUSH [SPR 68334] */ if (pPktv->header.nBytes > pSmPktDesc->maxPktBytes) { errno = S_smPktLib_PACKET_TOO_BIG; return (ERROR); /* too much data ! */ } /* byte swap info */ pPktv->header.nBytes = htonl (pPktv->header.nBytes); /* Call special routine if doing broadcast */ if (destCpu == SM_BROADCAST) /* if sending to all cpu's */ return (smPktBroadcast (pSmPktDesc, pPkt)); /* Make sure destination cpu is valid and attached */ if (destCpu < 0 || destCpu >= pSmDesc->maxCpus) { errno = S_smPktLib_INVALID_CPU_NUMBER; return (ERROR); /* cpu number out of range */ } pPktCpuDesc = &((pSmPktDesc->cpuLocalAdrs) [destCpu]); pCpuDesc = &((pSmDesc->cpuTblLocalAdrs) [destCpu]); /* get addr of cpu descriptor */ if (ntohl (pPktCpuDesc->status) != SM_CPU_ATTACHED) { errno = S_smPktLib_DEST_NOT_ATTACHED; return (ERROR); /* dest cpu is not attached */ } /* Complete packet header info */ pPktv->header.srcCpu = htonl (pSmDesc->cpuNum); /* source cpu */ CACHE_PIPE_FLUSH (); /* CACHE FLUSH [SPR 68334] */ i = pPktv->header.srcCpu; /* BRIDGE FLUSH [SPR 68334] */ /* Add this packet to destination cpu's input list */ status = smPktSllPut (&(pPktCpuDesc->inputList), pSmDesc->base, pSmDesc->tasRoutine, pSmDesc->tasClearRoutine, &(pPktv->header.node), &listWasEmpty); if ((status == OK) && (listWasEmpty) && (destCpu != pSmDesc->cpuNum)) { /* Interrupt destination cpu */ if ((status = smUtilIntGen ((SM_CPU_DESC *)pCpuDesc, destCpu)) != OK) { /* * Packet put in input list but interrupt failed. * This is not an error. It means another interrupt will have * to be sent after a short delay. This will be repeated until * the interrupt is successful or a timeout occurs. * (See SPR 25341, 33771) */ for (i = smPktMaxIntRetries; (status != OK) && (i > 0); --i) { taskDelay (1); status = smUtilIntGen ((SM_CPU_DESC *)pCpuDesc, destCpu); } /* time out on interrupt generation */ if (status != OK) { /* packet still in input list so do NOT delete it */ errno = S_smPktLib_INCOMPLETE_BROADCAST; } } } return (status); }/******************************************************************************** smPktBroadcast - send packet data to all attached CPU's via shared memory** This sends a copy of the packet specified by <pPkt> to all CPU's attached* to the specified shared memory area (except the sending CPU).** This routine attempts to obtain a new packet for each destination CPU,* copying the packet contents to each newly-acquired packet. If no new* packets are available, this routine will go ahead and send the original* packet to the next destination CPU. If there are still more destinations* after the original has been sent, an error (S_smPktLib_INCOMPLETE_BROADCAST)* is returned. This same error is returned if one or more destinations did* not receive the broadcast due to other problems (e.g. the input queue for* a destination CPU was full).** RETURNS: OK, or ERROR.** ERRNO: S_smPktLib_INCOMPLETE_BROADCAST*/LOCAL STATUS smPktBroadcast ( SM_PKT_DESC * pSmPktDesc, /* sh mem pkt descriptor */ SM_PKT volatile * pPktOrig /* ptr to original packet */ ) { STATUS status; /* return status */ SM_PKT volatile * pPkt; /* ptr to packet being sent */ SM_PKT volatile * pPktNew; /* ptr to newly obtained pkt */ int destCpu; /* destination cpu number */ SM_CPU_DESC volatile * pCpuDesc; /* destination cpu descriptor*/ SM_PKT_CPU_DESC volatile * pPktCpuDesc; /* destination cpu descriptor*/ BOOL destMissed; /* TRUE if a dest was missed */ BOOL listWasEmpty; /* list added to was empty */ SM_DESC * pSmDesc = (SM_DESC *) &pSmPktDesc->smDesc; pCpuDesc = pSmDesc->cpuTblLocalAdrs; pPktCpuDesc = pSmPktDesc->cpuLocalAdrs; destMissed = FALSE; /* no destinations missed yet */ /* Send copy of packet to each attached cpu (except self) */ for (destCpu = 0; destCpu < pSmDesc->maxCpus; destCpu++) { if ((ntohl (pPktCpuDesc->status) == SM_CPU_ATTACHED) && (destCpu != pSmDesc->cpuNum)) { if (pPktOrig == NULL) /* if original already used */ { destMissed = TRUE; /* weren't enough free packets*/ break; /* can't do any more */ } /* Get new packet */ if (smPktFreeGet (pSmPktDesc, (SM_PKT **)&pPktNew) != OK) return (ERROR); /* error getting packet */ if (pPktNew != NULL) /* if a new pkt was obtained */ { pPkt = pPktNew; /* it is the packet to send */ pPkt->header.type = pPktOrig->header.type; /* copy packet type */ pPkt->header.nBytes = pPktOrig->header.nBytes; /* copy byte count */ bcopy ((char *)pPktOrig->data, (char *)pPkt->data, ntohl (pPkt->header.nBytes)); /* copy packet data */ } else /* if could not get new pkt */ { pPkt = pPktOrig; /* set up to send original */ } pPkt->header.srcCpu = htonl (pSmDesc->cpuNum); /* source cpu number */ /* Send packet */ status = smPktSllPut (&(pPktCpuDesc->inputList), pSmDesc->base, pSmDesc->tasRoutine, pSmDesc->tasClearRoutine, &(pPkt->header.node), &listWasEmpty); if ((status == OK) && listWasEmpty) /* if list previously empty */ { /* Interrupt destination CPU */ if (smUtilIntGen ((SM_CPU_DESC *)pCpuDesc, destCpu) != OK) { destMissed = TRUE; /* a destination was missed */ } } else if (status == ERROR) /* if error sending pkt */ { /* * NOTE: We do not return just because an error occurred. * The destination cpu's input list may simply have been * full, or some other error may have occurred which * will not affect the remaining destinations. When * this routine ultimately returns, the broadcast will * be reported as having been incomplete. */ destMissed = TRUE; /* a destination was missed */ if (pPkt != pPktOrig) /* if pkt was not the original*/ { /* New packet not sent - return to free pool */ if (smPktFreePut (pSmPktDesc, (SM_PKT *)pPkt) != OK) return (ERROR); /* could not return packet */ } } if (pPkt == pPktOrig && status != ERROR) { /* if original actually sent */ pPktOrig = NULL; /* clear pointer to orig pkt */ } } /* end if (attached) */ pCpuDesc++; /* next cpu descriptor */ pPktCpuDesc++; } /* end for */ /* Free original packet if it wasn't sent during broadcast */ if (pPktOrig != NULL) { if (smPktFreePut (pSmPktDesc, (SM_PKT *)pPktOrig) != OK) return (ERROR); /* could not free packet */ } if (destMissed) /* if a destination was missed*/ { errno = S_smPktLib_INCOMPLETE_BROADCAST; return (ERROR); /* broadcast not complete */ } else { return (OK); } }/******************************************************************************** smPktFreePut - return a shared memory packet to free list** This routine frees a shared memory packet. The packet is placed* on the global free packet list. No modification of the packet* contents is performed.** The address of the packet to be returned is specified in <pPkt>.** RETURNS: OK, or ERROR.** ERRNO: S_smPktLib_NOT_ATTACHED, S_smPktLib_INVALID_PACKET*/STATUS smPktFreePut ( SM_PKT_DESC * pSmPktDesc, /* ptr to shared memory descriptor */ SM_PKT * pPkt /* addr of packet to be returned */ ) { 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 */ } /* Check for null pointer */ if (pPkt == NULL) { errno = S_smPktLib_INVALID_PACKET; return (ERROR); /* null packet address */ } /* Return packet to free list */ return (smPktSllPut (&(pSmPktDesc->hdrLocalAdrs->freeList), pSmDesc->base, pSmDesc->tasRoutine, pSmDesc->tasClearRoutine, &(pPkt->header.node), NULL)); }/******************************************************************************** smPktRecv - receive a packet sent via shared memory** This routine receives a shared memory packet which was queued to this CPU.* This routine should be called in response to an interrupt which notifies* this CPU of the packet, or it can be called repeatedly in a polling* fashion to check for input packets. (NOTE: An interrupt will be generated* only if there previously was not a packet queued to this CPU. Therefore,* after a packet is received, this routine should be called again to check* for more packets.)** Upon return, the location indicated by <ppPkt> will contain the address* of the received packet, or NULL if there was none.** RETURNS: OK, or ERROR.** ERRNO: S_smPktLib_NOT_ATTACHED*/STATUS smPktRecv ( SM_PKT_DESC * pSmPktDesc, /* shared memory descriptor */ SM_PKT ** ppPkt /* location to put pkt addr */ ) { SM_PKT_CPU_DESC volatile * pPktCpuDesc; STATUS status; SM_DESC * pSmDesc = (SM_DESC *) &pSmPktDesc->smDesc; int tmp; /* temp storage */ /* 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 (if any) from input list */ pPktCpuDesc = &((pSmPktDesc->cpuLocalAdrs) [pSmDesc->cpuNum]); /* get addr of cpu descriptor */ status = smPktSllGet (&(pPktCpuDesc->inputList), pSmDesc->base, pSmDesc->tasRoutine, pSmDesc->tasClearRoutine, (SM_SLL_NODE **) ppPkt); if ((status == OK) && (*ppPkt != NULL)) { (*ppPkt)->header.nBytes = ntohl ((*ppPkt)->header.nBytes); (*ppPkt)->header.srcCpu = ntohl ((*ppPkt)->header.srcCpu); CACHE_PIPE_FLUSH (); /* CACHE FLUSH [SPR 68334] */ tmp = (*ppPkt)->header.srcCpu; /* BRIDGE FLUSH [SPR 68334] */ } return (status); }/******************************************************************************** smPktSllGet - get a shared memory node from a singly-linked list** This routine attempts to obtain a shared memory node from the* specified singly-linked list of nodes. If a node is available,* the local address (for this CPU) of the node is placed in the* location specified by <pNodeLocalAdrs>. If no node was available* from the list, a NULL is placed in this location.** This routine uses the specified test-and-set function, <tasRoutine>, to* obtain exclusive access to the linked list lock. If the lock cannot* be acquired within the number of tries specified by the smPktTasTries* global variable, this routine will return ERROR.** RETURNS: OK, or ERROR if could not acquire list lock.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -