📄 ixatmschserviceif.c
字号:
/* This function is used to remove the real-time VC from the list */PRIVATE voidixAtmSchRtVcRemove(IxAtmLogicalPort port, IxAtmSchedulerVcId vcId){ IxAtmSchedulerVcId thisVc = ixAtmSchRtQueueHead[port]; IxAtmSchedulerVcId prevVc = IX_ATMSCH_NULL_INDEX; while (thisVc != IX_ATMSCH_NULL_INDEX) { if (thisVc == vcId) { /* VC is found */ if (prevVc == IX_ATMSCH_NULL_INDEX) { /* The required VC to be removed is at the head of the list */ ixAtmSchRtQueueHead[port] = ixAtmSchVcTable[vcId].nextVc; } else { /* VC found somewhere in the list. Hence, the predecessor now contains the removed VC's nextVc value */ ixAtmSchVcTable[prevVc].nextVc = ixAtmSchVcTable[vcId].nextVc; } /* Decrements the allocated port capacity */ if (schTd[vcId].atmService == IX_ATM_CBR) { /* This is CBR */ ixAtmSchCacPortAllocated[port] -= schTd[vcId].pcr; /* break from the while loop */ break; } else { /* this is VBR */ ixAtmSchCacPortAllocated[port] -= schTd[vcId].scr; /* break from the while loop */ break; } } else { prevVc = thisVc; thisVc = ixAtmSchVcTable[thisVc].nextVc; } } /* while */ if (thisVc == IX_ATMSCH_NULL_INDEX) { IX_ATMSCH_ERROR_REPORT("VC not in real-time chain when removed."); }}/************************************************************************//* This function is used to insert UBR in a circular chain */PRIVATE voidixAtmSchUbrChainVcInsert(IxAtmLogicalPort port, IxAtmSchedulerVcId vcId){ IX_ATMSCH_ASSERT(vcId != IX_ATMSCH_NULL_INDEX); ixAtmSchVcTable[vcId].atmService = schTd[vcId].atmService; if (ixAtmSchNextUbrToBeScheduled[port] == IX_ATMSCH_NULL_INDEX) { /* This is true for the first VC in the queue */ ixAtmSchVcTable[vcId].nextVc = vcId; ixAtmSchNextUbrToBeScheduled[port] = vcId; } else { /* It is important to update the nextVc fields in this order * as this table may be simultaneously accessed by the * updateTable interrupt. The insert into the chain is atomic. */ IX_ATMSCH_ASSERT(ixAtmSchVcTable[ixAtmSchNextUbrToBeScheduled[port]].nextVc != IX_ATMSCH_NULL_INDEX); ixAtmSchVcTable[vcId].nextVc = ixAtmSchVcTable[ixAtmSchNextUbrToBeScheduled[port]].nextVc; ixAtmSchVcTable[ixAtmSchNextUbrToBeScheduled[port]].nextVc = vcId; }}/* This function is used to remove the UBR VC from the circular chain*/PRIVATE voidixAtmSchUbrChainVcRemove(IxAtmLogicalPort port, IxAtmSchedulerVcId vcId) { IxAtmSchedulerVcId i = 0; for (i=0; i<IX_ATM_MAX_NUM_AAL_OAM_TX_VCS; i++) { if ( (ixAtmSchVcTable[i].inUse == TRUE ) && (ixAtmSchVcTable[i].nextVc == vcId) && (ixAtmSchVcTable[i].port == port)) { IX_ATMSCH_ASSERT(ixAtmSchVcTable[vcId].nextVc != IX_ATMSCH_NULL_INDEX); ixAtmSchVcTable[i].nextVc = ixAtmSchVcTable[vcId].nextVc; if (ixAtmSchNextUbrToBeScheduled[port] == vcId) { /* This code is interruptible by the scheduler * function while modifying the value of * ixAtmSchNextUbrToBeScheduled, but the worst consequence is * that it would cause a UBR Vc to be skipped in the * chain */ if (ixAtmSchVcTable[vcId].nextVc == vcId) { /* this vc is the only one in the chain */ ixAtmSchNextUbrToBeScheduled[port] = IX_ATMSCH_NULL_INDEX; } else { ixAtmSchNextUbrToBeScheduled[port] = ixAtmSchVcTable[vcId].nextVc; } } return; } } if (i == IX_ATM_MAX_NUM_AAL_OAM_TX_VCS) { IX_ATMSCH_ERROR_REPORT("UBR VC not in UBR chain when removed."); }}/************************************************************************//* This function sets the scheduler model */PUBLIC IX_STATUSixAtmSchVcModelSetup(IxAtmLogicalPort port, IxAtmTrafficDescriptor *trafficDesc, IxAtmSchedulerVcId *vcId){ IX_STATUS retval; IxAtmSchedulerVcId schVcId; if (!schInitDone|| (port<IX_UTOPIA_PORT_0)|| (port>=IX_UTOPIA_MAX_PORTS)|| !ixAtmSchedulingEnabled[port]) { return IX_FAIL; } retval = ixAtmSchCac(port ,trafficDesc); if (retval != IX_SUCCESS) { return retval; } schVcId = ixAtmSchFreeVcIdGet(); if (schVcId == IX_ATMSCH_NULL_INDEX) { return IX_ATMSCH_RET_NOT_ADMITTED; } /* Save the port */ ixAtmSchVcTable[schVcId].port = port; /* Initialize the VC table for the registered VC */ ixAtmSchVcTable[schVcId].count = 0; ixAtmSchVcTable[schVcId].vbrPcrCellsCnt = 0; ixAtmSchVcTable[schVcId].vbrScrCellsCnt = 0; ixAtmSchVcTable[schVcId].connId = IX_ATM_IDLE_CELLS_CONNID; ixAtmSchVcTable[schVcId].schInfo.cet = 0; ixAtmSchVcTable[schVcId].schInfo.cetPcr = 0; ixAtmSchVcTable[schVcId].schInfo.cetScr = 0; ixAtmSchVcTable[schVcId].schInfo.bt = 0; ixAtmSchVcTable[schVcId].schInfo.usPcr = 0; ixAtmSchVcTable[schVcId].schInfo.usScr = 0; /* Save the trafficDescriptor into a global variable */ schTd[schVcId] = *trafficDesc; if (schTd[schVcId].atmService == IX_ATM_UBR) { /* insert UBR VC into list */ ixAtmSchUbrChainVcInsert(port,schVcId); } else if ((schTd[schVcId].atmService == IX_ATM_RTVBR) || (schTd[schVcId].atmService == IX_ATM_VBR) || (schTd[schVcId].atmService == IX_ATM_CBR) ) { /* Insert real time VC into list */ retval = ixAtmSchRtVcInsert(port, schVcId); if (IX_SUCCESS != retval) { /* Failed to insert the VC due to failure to set * the base timer (this is for VBR only). * Ensure that parameters are set correctly */ return IX_FAIL; } } else { /* Unknown service type! */ IX_ATMSCH_ASSERT( FALSE ); } /* Set the status of the VC inUse to TRUE indicating that this VC table is in use */ ixAtmSchVcTable[schVcId].inUse = TRUE; /* The vcId is passed back to the caller */ *vcId = schVcId; return IX_SUCCESS;}/************************************************************************/PRIVATE BOOLixAtmSchParamIsValid(IxAtmLogicalPort port, IxAtmSchedulerVcId vcId){ if ((vcId >= IX_ATM_MAX_NUM_AAL_OAM_TX_VCS) || (vcId < 0)|| (ixAtmSchVcTable[vcId].inUse == FALSE)|| (ixAtmSchVcTable[vcId].port != port)) { return FALSE; } return TRUE;}/************************************************************************/PUBLIC IX_STATUSixAtmSchVcConnIdSet( IxAtmLogicalPort port, IxAtmSchedulerVcId vcId, IxAtmConnId connId){ if (!schInitDone|| ixAtmSchParamIsValid(port, vcId) == FALSE) { return IX_FAIL; } ixAtmSchVcTable[vcId].connId = connId; return IX_SUCCESS;}/************************************************************************/PUBLIC IX_STATUSixAtmSchVcModelRemove(IxAtmLogicalPort port, IxAtmSchedulerVcId vcId){ if (!schInitDone|| ixAtmSchParamIsValid(port, vcId) == FALSE) { return IX_FAIL; } if (schTd[vcId].atmService == IX_ATM_UBR) { ixAtmSchUbrChainVcRemove( port, vcId ); } else if ((schTd[vcId].atmService == IX_ATM_RTVBR) || (schTd[vcId].atmService == IX_ATM_VBR) || (schTd[vcId].atmService == IX_ATM_CBR)) { ixAtmSchRtVcRemove(port,vcId); } else /* Invalid atm service type */ { IX_ATMSCH_ASSERT( FALSE ); } if (ixAtmSchVcTable[vcId].count != 0) { IX_ATMSCH_WARNING_REPORT( "Removal of VC with pending cells!"); } /* Set the remove VC's inUse status to FALSE indicating that * it will be overwritten. */ ixAtmSchVcTable[vcId].inUse = FALSE; ixAtmSchVcTable[vcId].port = IX_UTOPIA_MAX_PORTS; /* Reset the base timer and scheduler timer to zero for the case * where all the VCs (UBR, VBR and CBR) are removed. If there are * VCs in either one of them, the timer remains */ if ((ixAtmSchRtQueueHead[port] == IX_ATMSCH_NULL_INDEX) && (ixAtmSchNextUbrToBeScheduled[port] == IX_ATMSCH_NULL_INDEX)) { ixAtmSchBaseTime[port] = 0; ixAtmSchTime[port] = 0; } return IX_SUCCESS;}/************************************************************************//* Setting the base time for a real-time VC. */IX_STATUSixAtmSchBaseTimeSet (IxAtmLogicalPort port, UINT32 baseTime){ UINT32 increment; IxAtmSchedulerVcId rtQPtr; UINT32 newMask = 0x0; /* Verify whether the basetime is equal or greater than the MASK (right * shift by 1). This is to ensure that the overrun would occur * earlier.*/ if (baseTime & (IX_ATMSCH_UINT_MASK)) { /* Fail as the base time has to be less than the MASK value */ return IX_FAIL; } increment = baseTime - ixAtmSchBaseTime[port]; ixAtmSchBaseTime[port] = baseTime; if (ixAtmSchTime[port] < ixAtmSchBaseTime[port]) { ixAtmSchTime[port] = ixAtmSchBaseTime[port]; } /* This is applicable when there are more than one VC in the list. */ rtQPtr = ixAtmSchRtQueueHead[port]; while (rtQPtr != IX_ATMSCH_NULL_INDEX) { if ( (ixAtmSchVcTable[rtQPtr].schInfo.cet & IX_ATMSCH_UINT_MASK) != ((ixAtmSchVcTable[rtQPtr].schInfo.cet + increment) & IX_ATMSCH_UINT_MASK) ) { /* i.e. Adding the increment will cause a timer overflow. * This should happen only *VERY* rarely if a low-bandwidth VC * is added just as the timer is about to overflow. */ newMask = ixAtmSchVcTable[rtQPtr].schInfo.cet & IX_ATMSCH_UINT_MASK; ixAtmSchVcTable[rtQPtr].schInfo.cet = ixAtmSchTime[port] | newMask; ixAtmSchVcTable[rtQPtr].schInfo.cetScr = ixAtmSchTime[port] | newMask; ixAtmSchVcTable[rtQPtr].schInfo.cetPcr = ixAtmSchTime[port] | newMask; } else { ixAtmSchVcTable[rtQPtr].schInfo.cetScr = ixAtmSchVcTable[rtQPtr].schInfo.cetPcr = (ixAtmSchVcTable[rtQPtr].schInfo.cet += increment); } rtQPtr = ixAtmSchVcTable[rtQPtr].nextVc; } return IX_SUCCESS;}/************************************************************************//* This is to sort the real-time VC list based on the cet values */voidixAtmSchBubbleSortRtVcQueue(IxAtmLogicalPort port){ IxAtmSchedulerVcId thisRtVc; IxAtmSchedulerVcId nextRtVc; IxAtmSchedulerVcId prevRtVc = IX_ATMSCH_NULL_INDEX; BOOL swap = TRUE; while (swap) { swap = FALSE; /* save the head of the queue. thisRtVc will be moving forward * in the list*/ thisRtVc = ixAtmSchRtQueueHead[port]; while ((thisRtVc != IX_ATMSCH_NULL_INDEX) && (ixAtmSchVcTable[thisRtVc].nextVc != IX_ATMSCH_NULL_INDEX)) { /* Use nextRtVc to point to the thisRtVc's neighbour */ nextRtVc = ixAtmSchVcTable[thisRtVc].nextVc; if (ixAtmSchVcTable[thisRtVc].schInfo.cet > ixAtmSchVcTable[nextRtVc].schInfo.cet) { /* Perform swap here */ ixAtmSchVcTable[thisRtVc].nextVc = ixAtmSchVcTable[nextRtVc].nextVc; ixAtmSchVcTable[nextRtVc].nextVc = thisRtVc; if (prevRtVc == IX_ATMSCH_NULL_INDEX) { /* position the sappwed VC to be at the head of the list */ ixAtmSchRtQueueHead[port] = nextRtVc; } else { /* position the VC in the list */ ixAtmSchVcTable[prevRtVc].nextVc = nextRtVc; } /* perform the swap again */ swap = TRUE; } /* Search the next VC in the list. Repeat the process of sorting * base on the the cet value*/ prevRtVc = thisRtVc; thisRtVc = ixAtmSchVcTable[thisRtVc].nextVc; } /* inner while*/ } /* outer while */}/************************************************************************//* This funstion is called infrequently from within the * bcAtmSchTableUpdate function, which is in turn invoked from * an FIQ interrupts, and is therefore uninterruptible. */voidixAtmSchTimerOverrun (IxAtmLogicalPort port){ IxAtmSchedulerVcId thisRtVc; UINT32 newCet; /* Time counter overrun. Need to reset schTime back to base value * for all VCs. This should happen once every ~35 minutes * (i.e. (2^31 - schBaseTime) us */ ixAtmSchTime[port] = ixAtmSchBaseTime[port]; thisRtVc = ixAtmSchRtQueueHead[port]; while (thisRtVc != IX_ATMSCH_NULL_INDEX) { if (ixAtmSchVcTable[thisRtVc].schInfo.cet & (IX_ATMSCH_UINT_MASK >> 1)) { if (ixAtmSchVcTable[thisRtVc].count != 0) { /* CET on VC has overrun also. Ryesetting the cet back to schBaseTime * will cause conformance errors, but this happens so infrequently that * it shouldn't cause a problem */ newCet = ixAtmSchBaseTime[port]; } else { newCet = ixAtmSchBaseTime[port] | IX_ATMSCH_UINT_MASK; } } else { newCet = ixAtmSchBaseTime[port]; } if ((ixAtmSchVcTable[thisRtVc].atmService == IX_ATM_VBR) || (ixAtmSchVcTable[thisRtVc].atmService == IX_ATM_RTVBR)) { /* If there are PCR cells bursting */ if (ixAtmSchVcTable[thisRtVc].vbrPcrCellsCnt > 0) { ixAtmSchVcTable[thisRtVc].schInfo.bt = (ixAtmSchVcTable[thisRtVc].vbrPcrCellsCnt) * (ixAtmSchVcTable[thisRtVc].schInfo.usScr - ixAtmSchVcTable[thisRtVc].schInfo.usPcr); } else if (ixAtmSchVcTable[thisRtVc].vbrPcrCellsCnt == ixAtmSchVcTable[thisRtVc].schInfo.mbs) { /* Restore the BT value when at MBS */ ixAtmSchVcTable[thisRtVc].schInfo.bt = ixAtmSchVcTable[thisRtVc].schInfo.baseBt; } else if (ixAtmSchVcTable[thisRtVc].vbrPcrCellsCnt == 0) { ixAtmSchVcTable[thisRtVc].schInfo.bt = 0; } } /* Need to reset cetScr & cetPcr values back down to new time or the * VC will block until almost the next timer overflow. This will * clear the burst history for VBR Vcs, resulting in non-conforming * cells. Again, this happens only very infrequently however. */ ixAtmSchVcTable[thisRtVc].schInfo.cetPcr = ixAtmSchVcTable[thisRtVc].schInfo.cetScr = (ixAtmSchVcTable[thisRtVc].schInfo.cet = newCet); thisRtVc = ixAtmSchVcTable[thisRtVc].nextVc; } ixAtmSchBubbleSortRtVcQueue(port);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -