📄 ixatmsch.c
字号:
} \ } \}PRIVATE IX_STATUSixAtmSchValidRtVcSearch(IxAtmLogicalPort port, IxAtmServiceCategory atmService, IxAtmSchedulerVcId* schRtQueueHead){ IxAtmSchedulerVcId thisRtVc = IX_ATMSCH_NULL_INDEX; IxAtmSchedulerVcId tmpRtVc = IX_ATMSCH_NULL_INDEX; thisRtVc = *schRtQueueHead; /* If there is no rt queue && count is zero */ if ((thisRtVc == IX_ATMSCH_NULL_INDEX) || (ixAtmSchVcTable[thisRtVc].count == 0)) { return IX_SUCCESS; } if (ixAtmSchVcTable[thisRtVc].atmService != atmService) { while (((tmpRtVc = ixAtmSchVcTable[thisRtVc].nextVc) != IX_ATMSCH_NULL_INDEX) && !(ixAtmSchVcTable[tmpRtVc].schInfo.cet & IX_ATMSCH_UINT_MASK)) { if ((ixAtmSchVcTable[tmpRtVc].atmService == atmService) && (ixAtmSchVcTable[tmpRtVc].schInfo.cet <= ixAtmSchTime[port]) && (ixAtmSchVcTable[tmpRtVc].count != 0)) { /* found that VC. Swap it to the head of the list */ ixAtmSchVcTable[thisRtVc].nextVc = ixAtmSchVcTable[tmpRtVc].nextVc; ixAtmSchVcTable[tmpRtVc].nextVc = *schRtQueueHead; *schRtQueueHead = tmpRtVc; ixAtmSchRtQueueHead[port] = tmpRtVc; return IX_SUCCESS; } /* continue to search for the next VC of same ATM service category */ thisRtVc = ixAtmSchVcTable[thisRtVc].nextVc; } /* End of the queue is reached, i.e. no VC found in the list * or CET is not complied or count is zero. So return FALSE */ return IX_FAIL; } /* if the rt queue list is actived, search for correct atmService */ return IX_SUCCESS;}IX_STATUSixAtmSchTableUpdate(IxAtmLogicalPort port, unsigned int maxCells, IxAtmScheduleTable **retTable){ int entryCnt; /* a counter to create the sch table */ UINT32 numUbrToSend; /* number of cells (UBR or idle) that can be sched */ UINT32 cellCount = 0; /* counter for the number of cell sched */ IxAtmSchPortSchedulingInfo *portSchInfo; /* contains info for that port */ UINT32 timePerCell; /* the time for each cell */ IxAtmScheduleTable *schTable; /* contains scheduling table info */ /* These variables are used for UBR list */ IxAtmSchedulerVcId prevUBR = IX_ATMSCH_NULL_INDEX; IxAtmSchedulerVcId schNextUbrToBeScheduled; /* thisSchInfo is used to hold the information of the real-time VC * scheduling information */ IxAtmSchVcSchedInfo *thisSchInfo; /* These variables are used for real-time list */ IxAtmSchedulerVcId schRtQueueHead; IxAtmSchedulerVcId prevRtVc; IxAtmSchedulerVcId thisRtVc; IxAtmSchedulerVcId tmpRtVc; /* Update the count for calls to this function */ IX_ATMSCH_STATS(ixAtmSchStats[port].scheduleTableCalls ++;); if ((port>=IX_UTOPIA_PORT_0) && (port< IX_UTOPIA_MAX_PORTS)&& (ixAtmSchedulingEnabled[port])) { portSchInfo = &portSchedulingInfo[port]; /* make a local copy. The time per cell and current * scheduler time for that particular port */ timePerCell = portSchInfo->timePerCell; schNextUbrToBeScheduled = ixAtmSchNextUbrToBeScheduled[port]; schRtQueueHead = ixAtmSchRtQueueHead[port]; /* Point to the scheduler table for this port */ schTable = &portSchInfo->schTable; schTable->tableSize = 0; for (entryCnt=0;(entryCnt < IX_ATMSCH_MAX_TABLE_ENTRIES )&&(cellCount < maxCells); entryCnt++) { RESORT_RT_QUEUE_PRIORITY(port, schRtQueueHead); if ((ixAtmSchTime[port] & (IX_ATMSCH_UINT_MASK >> 1)) || ((schRtQueueHead != IX_ATMSCH_NULL_INDEX) && (ixAtmSchVcTable[schRtQueueHead].schInfo.cet & (IX_ATMSCH_UINT_MASK >> 1)))) { /* This should happen rarely so it is * acceptable to perform a function call as it is so * infrequent */ ixAtmSchTimerOverrun(port); } /* Process for real time VC */ while ((schRtQueueHead != IX_ATMSCH_NULL_INDEX) && (ixAtmSchTime[port] >= ixAtmSchVcTable[schRtQueueHead].schInfo.cet) && (entryCnt < IX_ATMSCH_MAX_TABLE_ENTRIES)) { /* first schedule one real-time cell if there any */ /* make a local copy of the scheduling information of the VC */ thisSchInfo = &ixAtmSchVcTable[schRtQueueHead].schInfo; if (ixAtmSchVcTable[schRtQueueHead].count > 0) { /* Send one real-time cell. Decrement the cell count & * increment the table entry count*/ SEND_CELLS(1, ixAtmSchVcTable[schRtQueueHead].connId, entryCnt); ixAtmSchVcTable[schRtQueueHead].count--; entryCnt++; /* calculate the next tx time for this VC */ if ((ixAtmSchVcTable[schRtQueueHead].atmService == IX_ATM_RTVBR) || (ixAtmSchVcTable[schRtQueueHead].atmService == IX_ATM_VBR)) { /* This is for VBR - based on PCR, SCR and BT value */ thisSchInfo->cetPcr += thisSchInfo->usPcr; thisSchInfo->cetScr += thisSchInfo->usScr; thisSchInfo->cet = MAX(thisSchInfo->cetPcr, thisSchInfo->cetScr - thisSchInfo->bt); if (ixAtmSchVcTable[schRtQueueHead].vbrPcrCellsCnt > 0) { ixAtmSchVcTable[schRtQueueHead].vbrPcrCellsCnt--; } else { if (ixAtmSchVcTable[schRtQueueHead].vbrScrCellsCnt == 0) { ixAtmSchTimerOverrun(port); } if (ixAtmSchVcTable[schRtQueueHead].vbrScrCellsCnt == (ixAtmSchVcTable[schRtQueueHead].schInfo.scr * IX_ATMSCH_SCR_PERIOD_IN_SEC)) { /* Restore MBS value. Burst Tolerance will be calc by * TimerOverrun */ ixAtmSchVcTable[schRtQueueHead].vbrPcrCellsCnt = ixAtmSchVcTable[schRtQueueHead].schInfo.mbs; /* Reset SCR cell count */ ixAtmSchVcTable[schRtQueueHead].vbrScrCellsCnt = 0; ixAtmSchTimerOverrun(port); } else { ixAtmSchVcTable[schRtQueueHead].vbrScrCellsCnt++; } } } else { /* This is for CBR - based on PCR value only */ thisSchInfo->cetPcr += thisSchInfo->usPcr; thisSchInfo->cet = thisSchInfo->cetPcr; } if (ixAtmSchVcTable[schRtQueueHead].count == 0) { /* There are no more cells to be scheduled. Hence set the * cet's MSB with the MASK value. It will be placed at VC (now idle) * at the back of the queue */ ixAtmSchVcTable[schRtQueueHead].schInfo.cet |= IX_ATMSCH_UINT_MASK; } } else { /* There are no cells to be scheduled. The VC becomes idle by * setting the most significant bit */ ixAtmSchVcTable[schRtQueueHead].schInfo.cet|= IX_ATMSCH_UINT_MASK; } RESORT_RT_QUEUE_HEAD(); RESORT_RT_QUEUE_PRIORITY(port,schRtQueueHead); } /* while*/ /* Leading UBR cells in this table, recalculate the * number of UBR cells to send based on the current * schTime. */ if (schRtQueueHead != IX_ATMSCH_NULL_INDEX) { if ((cellCount >= portSchInfo->minCellsToSchedule) && (ixAtmSchVcTable[schRtQueueHead].count == 0)) { /* the cell counter exceeds the min table size and there are no * cells to be schedule */ break; } else if (ixAtmSchVcTable[schRtQueueHead].schInfo.cet & (IX_ATMSCH_UINT_MASK)) { if (cellCount < portSchInfo->minCellsToSchedule) { numUbrToSend = MAX(((INT32)portSchInfo->minCellsToSchedule - (INT32)cellCount), 1); } else { break; /* for (entryCnt ...) */ } } else { numUbrToSend = ((ixAtmSchVcTable[schRtQueueHead].schInfo.cet - ixAtmSchTime[port]) / timePerCell) + 1; } } else { /* No real-time VC registered */ if (cellCount < portSchInfo->minCellsToSchedule) { numUbrToSend = MAX(((INT32)portSchInfo->minCellsToSchedule - (INT32)cellCount), 1); } else { break; /* for (entryCnt...) */ } } /* Modify the number of UBR so the maxCells is not exceeded. * The maxCells and cellCount are cast with INT32 so that the * negative value can be compared. Now the schTable is expecting * an entry (after completing the above's algorithm). Hence the * numUbrToSend must have at least 1. Zero is not valid as it may * cause the system failure (i.e. no such thing as sending zero cell) */ if ( (numUbrToSend+cellCount) > maxCells ) { numUbrToSend = MAX( ((INT32) maxCells - (INT32) cellCount),1); } /* Now fill the gap between real-time cells with cells from the * UBR VCs. */ while ((numUbrToSend > 0) && (entryCnt < IX_ATMSCH_MAX_TABLE_ENTRIES)) { if ( (schNextUbrToBeScheduled != IX_ATMSCH_NULL_INDEX) && (ixAtmSchVcTable[schNextUbrToBeScheduled].count >= numUbrToSend) ) { /* CASE 1 - enough UBR in this VC to fulfill numUbrToSend */ IX_OSAL_ENSURE( (ixAtmSchVcTable[schNextUbrToBeScheduled].port == port), "IxAtmSch Major internal error") ; SEND_CELLS (numUbrToSend, ixAtmSchVcTable[schNextUbrToBeScheduled].connId, entryCnt); ixAtmSchVcTable[schNextUbrToBeScheduled].count -= numUbrToSend; numUbrToSend = 0; } else if ( (schNextUbrToBeScheduled != IX_ATMSCH_NULL_INDEX) && (ixAtmSchVcTable[schNextUbrToBeScheduled].count > 0) ) { /* CASE 2 - some, but not enough UBR in this VC to fulfill numUbrToSend */ IX_OSAL_ENSURE((ixAtmSchVcTable[schNextUbrToBeScheduled].port == port), "IxAtmSch Major internal error") ; SEND_CELLS(ixAtmSchVcTable[schNextUbrToBeScheduled].count, ixAtmSchVcTable[schNextUbrToBeScheduled].connId, entryCnt); numUbrToSend -= ixAtmSchVcTable[schNextUbrToBeScheduled].count; ixAtmSchVcTable[schNextUbrToBeScheduled].count = 0; entryCnt++; } else if ( (schNextUbrToBeScheduled == IX_ATMSCH_NULL_INDEX) || (prevUBR == schNextUbrToBeScheduled) ) { /* CASE 3 - There is no UBR enabled or we * have gone all the way around the UBR * chain and there is no data in it. If we * have real-time cells or we have sent UBR this * time we insert required idle * cells. Otherwise the table is empty. */ if (((schRtQueueHead != IX_ATMSCH_NULL_INDEX) && (ixAtmSchVcTable[schRtQueueHead].count > 0)) || (cellCount > 0) ) { SEND_CELLS(numUbrToSend, IX_ATM_IDLE_CELLS_CONNID, entryCnt); IX_ATMSCH_STATS(ixAtmSchStats[port].idleCellsScheduled += numUbrToSend;); numUbrToSend = 0; } else { *retTable = NULL; ixAtmSchNextUbrToBeScheduled[port] = schNextUbrToBeScheduled; return IX_ATMSCH_RET_QUEUE_EMPTY; } } /* Find the next UBR VC with cells, stop if we * have gone all the way around the UBR chain. */ if (prevUBR != schNextUbrToBeScheduled) { prevUBR = schNextUbrToBeScheduled; do { schNextUbrToBeScheduled = ixAtmSchVcTable[schNextUbrToBeScheduled].nextVc; } while ( (prevUBR != schNextUbrToBeScheduled) && (ixAtmSchVcTable[schNextUbrToBeScheduled].count == 0) ); } } /* while ((numUbrToSend > 0) ... */ } /* for */ ixAtmSchNextUbrToBeScheduled[port] = schNextUbrToBeScheduled; schTable->totalCellSlots = cellCount; IX_ATMSCH_STATS(ixAtmSchStats[port].cellsScheduled += cellCount;); schTable->table = portSchInfo->schTableEntries; *retTable = schTable; return IX_SUCCESS; } return IX_FAIL;}/************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -