📄 atmoc3rxcp.c
字号:
/* * Copyright (c) 2000,2001, 2002 C-Port Corporation,A Motorola Company * All Rights Reserved * * The information contained in this file is confidential and proprietary. * Any reproduction, use or disclosure, in whole or in part, of this * program, including any attempt to obtain a human-readable version of this * program, without the express, prior written consent of C-Port * Corporation or Motorola Incorporated is strictly prohibited. * * File : atmRx.c * * Receive side of the ATM cell switch */#include <dcpPduSvcs.h>#include <dcpQueueSvcs.h>#include <dcpTableSvcs.h>#include <dcpKernelSvcs.h>#include <dcpDiagSvcs.h>#include "atm.h"#include "atmStatus.h"#include "atmIf.h"#include "atmPrivate.h"#include "atmCellDesc.h"#include "atmVcTable.h"#include "rcSdpAtmApiIf.h"#include "errorHandling.h"static QsMessage ALIGNED64 atmRxCellDescMsg;static Boolean payloadEnqueue = FALSE;static BsBufHandle lastBufferEnqueued = 0;int32u atmCpQmuIrqHandler(void *irqInfo);extern KsContext atmRxNextContext;extern int32u atmPortNum;/* * atmRx() - Dispatch a cell to the egress CP */int32uatmRx(void* arg){ AtmExtract* atmExtract; BsBufHandle bufHandle; int32u* ptr; VcIngress* vi; CellDescriptor* atmRxCellDesc; PduHandle pduHandle; Boolean circuitValid = FALSE; int destination = 0; TsStatus status; /* QsQueueLevel trafficClass = 0; */ /* * Setup the Cell Descriptor memory * Write it once with zeroes to work around the Simulator's * read before write feature */ atmRxCellDesc = qsMessageGetData(&atmRxCellDescMsg); memset(atmRxCellDesc, 0, sizeof(CellDescriptor)); /* Register the QMU IRQ handler */ ksEventRegisterInterrupt(ksEventIdQmuError, (KsFunc)&atmCpQmuIrqHandler, (void*)0 ); while (1) { MSG_EVENT("CPRC: ATMRX wait for scope"); /* * Wait for the DCP to signal the reception of a cell header */ while ((pduHandle = pduRxAllocate()) == NULL) { ksContextSwitch(atmRxNextContext); } MSG_EVENT("CPRC: ATMRX got scope"); /* * Record the payload buffer handle in the cell descriptor */ bufHandle = pduRxBufHandleGet(pduHandle); atmRxCellDesc->Bh = bufHandle; atmExtract = (AtmExtract*)pduRxHeaderGet(pduHandle); /* * Record the number of cells dropped by rxByte while * awaiting scope from the RC - if this count is incrementing, * the RC cannot keep up with the line. */ atmStatsBuffer.rxCongestDrops += atmExtract->congestionDrops;#ifdef SIM if (atmExtract->congestionDrops) ksPrintf("Cells dropped due to congestion: %x\n", atmExtract->congestionDrops);#endif /* * If there is no header error */ if (!atmExtract->pduHdrStatus) { /* * Record the Payload Type Indicator and Cell Loss Priority bits * in the cell descriptor */ atmRxCellDesc->payloadType = atmExtract->encodedPti; MSG_EVENT("CPRC: ATMRX wait for VC lookup"); /* * The SDP microcode launched a lookup of the Vc entry. * Wait for the Vc entry lookup response to arrive here. * The response is a VC Control Block */ while (!(status=tsLookupResponseValid(viTag))) { ksContextSwitch(atmRxNextContext); } MSG_EVENT("CPRC: ATMRX got VC lookup"); /* * Set up the VC control block pointer * The VC Control block is always received in ringbus receive slot0 */ ptr = (int32u*)tsLookupGetResponse(viTag); /* * If the cell is on an established connection... */ if(ptr!=NULL) { ptr+=2; vi=(VcIngress*)ptr; if((circuitValid = BitIsSet(vi->VcUnicastIngress.Flags, VCFLAGS_VALID_CONNECTION))) { /* ... if pt-to-pt... */ if (BitIsClear(vi->VcUnicastIngress.Flags, VCFLAGS_MULTICAST)) { /* if not OAM/RM */ if (!atmRxCellDesc->payloadType) { /* * Egress VPI and VCI are being stored in the * ATM cell header. Ingress VcIndex will be * stored in case of AAL2 payloads. Switching * is done in AAL2 layer for these cells */ atmRxCellDesc->CellHeader.word = (int32u) vi->VcUnicastIngress.atmEgressKey; destination = vi->VcUnicastIngress.QueueId; atmRxCellDesc->VcIndex = vi->VcUnicastIngress.VcIndex; atmRxCellDesc->MulticastFlag = 0; atmStatsBuffer.rxGoodCells++; /* else OAM/RM */ } else { atmRxCellDesc->CellHeader.word = (atmExtract->cellHeader.word & 0xfffffff0) | atmPortNum; destination = ATM_CONTROL_PLANE_QUEUE; atmRxCellDesc->MulticastFlag = 0; atmStatsBuffer.rxOamCells++; } /* else pt-mpt */ } else { ksPrintf ("ATM Multi-cast support not provided in Aal2 Switch App") ; /* destination =(int) (vi->VcMulticastIngress.MulticastVector); atmRxCellDesc->VcIndex = vi->VcMulticastIngress.VcIndex; */ atmRxCellDesc->MulticastFlag = -1; /* trafficClass = vi->VcMulticastIngress.TrafficClass; atmStatsBuffer.rxGoodCells++; */ } } ptr = NULL; } /* * We are now finished with the VC Control Block * so release the response holding register back to the DCP */ tsLookupRelease(viTag); atmRxCellDesc->crc10Err = atmExtract->crc10Indicator; if (circuitValid) { MSG_EVENT("CPRC: ATMRX wait for payload"); /* * Wait for the cell payload to be fully transfered * into the DRAM buffer */ while (!pduRxPayloadDone(pduHandle)) { ksContextSwitch(atmRxNextContext); } MSG_EVENT("CPRC: ATMRX got payload"); if (atmRxCellDesc->MulticastFlag == 0) { /* * The last buffer enqueued is used when an * enqueue failed. This buffer must be deallocated * if the enqueue fails; otherwise, the buffer * is lost. Because the SONET monitoring code * enqueues control information to the XPU * without any buffer associated with it, we need * to mark this enqueue as one with payload. * The payloadEnqueue flag does this. */ lastBufferEnqueued = atmRxCellDesc->Bh; payloadEnqueue = TRUE; qsMessageSend(destination, &atmRxCellDescMsg); MSG_EVENT("CPRC: ATMRX wait for buffer allocate"); /* * Allocate a new buffer handle * for for using with the PDU services. */ while (bsError(bufHandle = bsBufferAllocate(poolId))) { ksContextSwitch(atmRxNextContext); } MSG_EVENT("CPRC: ATMRX buffer allocate done"); } else { ksPrintf ("ATM Multi-cast support not provided in Aal2 Switch App") ; /* qsMessageSendMulti(destination, trafficClass, &atmRxCellDescMsg); */ /* * Use the same buffer handle for the next set of * PDU services. */ bufHandle = pduRxBufHandleGet(pduHandle); } circuitValid = FALSE; pduRxBufHandleSet(pduHandle, bufHandle); pduRxPayloadSet(pduHandle, 0); pduRxFree(pduHandle); MSG_EVENT("CPRC: ATMRX scope released"); } else /* Invalid VC */ { while (!pduRxPayloadDone(pduHandle)) { ksContextSwitch(atmRxNextContext); } bufHandle = pduRxBufHandleGet(pduHandle); pduRxBufHandleSet(pduHandle, bufHandle); pduRxPayloadSet(pduHandle, 0); pduRxFree(pduHandle); atmStatsBuffer.rxInvalidVc++; dcpTrace1(("Invalid circuit: CP%d CellHeader=0x%08x", ksCpId, atmExtract->cellHeader)); } } /* * Else there is a header error, free extract space and reuse buffer */ else { dcpTrace1(("atmRx: Header Error: status=0x%x CellHeader=0x%08x", atmExtract->pduHdrStatus, atmExtract->cellHeader.word)); atmStatsBuffer.rxHecErrored++; while (!pduRxPayloadDone(pduHandle)) { ksContextSwitch(atmRxNextContext); } bufHandle = pduRxBufHandleGet(pduHandle); pduRxBufHandleSet(pduHandle, bufHandle); pduRxPayloadSet(pduHandle, 0); pduRxFree(pduHandle); } } /* end while forever */} /* end atmRx() *//* * Function: atmCpQmuIrqHandler() * * Description: This function is interrupt handler for QMU errors. It is typically * called under normal congestion conditions when an enqueue fails * to succeed due to the target queue being full. When this occurs * this irq handler must free the buffer associated with the last * enqueue. * * Arguments: An eventInfo block passed in by kernel services. * * Returns: */int32u atmCpQmuIrqHandler(void *irqInfo){ KsEventInfo *eventInfo = (KsEventInfo *)irqInfo; if(eventInfo->eventId == ksEventIdQmuError) { dcpTrace1(("Queue irq, queue %d", eventInfo->address)); /* Only free the buffer associated with the last enqueue if the failed enqueue * was a unicast operation with payload information. */ // if(eventInfo->command == qsCmdUnicastEnqueue) { if(payloadEnqueue == TRUE ) { // ksPrintf("Event address: %d, command: %d", // eventInfo->address, eventInfo->command); /* Save any context before doing an operation. */ ksEventContextSave(); /* Free the buffer associated with the last enqueue. */ bsBufferFree(lastBufferEnqueued); /* Wait until operation is done and then restore any context. */ while(!bsBufferWriteComplete()); ksEventContextRestore(); payloadEnqueue = FALSE; atmStatsBuffer.enqueueFail++; } else { atmStatsBuffer.otherEnqueueFail++; } // } } return(0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -