📄 ixatmdtxtransport.c
字号:
{ /* check if all cells are from the current PDU */ if (cellCount <= vcDescriptor->remainingPduCellCount) { /* update the current cell count for this pdu */ vcDescriptor->remainingPduCellCount -= cellCount; /* reuse the same descriptor and transmit the data */ ixAtmdAccCellTx (qMgrEntryPtr, vcDescriptor->currentNpeDesc->atmd.physicalAddress, cellCount, NPE_TX_DATACELL); /* update stats */ IX_ATMDACC_FULL_STATS( ixAtmdAccTxTransportStats[vcDescriptor->port].dataCellScheduledCount += cellCount; ); /* all data is transmitted, update the current cell count */ cellCount = 0; } /* end of if(cellCount) */ else { /* we may have to cross a PDU boundary this occur when * the scheduler schedule cells over PDU boundaries, or * when the last pdu is completely sent on a previous call */ if (vcDescriptor->remainingPduCellCount > 0) { /* now send the remaining of current PDU */ ixAtmdAccCellTx (qMgrEntryPtr, vcDescriptor->currentNpeDesc->atmd.physicalAddress, vcDescriptor->remainingPduCellCount, NPE_TX_DATACELL); /* update stats */ IX_ATMDACC_FULL_STATS( ixAtmdAccTxTransportStats[vcDescriptor->port].dataCellScheduledCount += vcDescriptor->remainingPduCellCount; ); /* update the current cell count */ cellCount -= vcDescriptor->remainingPduCellCount; } /* end of if(vcDescriptor) */ /* are there any more PDUs to transmit ? */ if (!IX_ATMDACC_TXQ_SCHEDULE_PENDING (txSwQueue)) { /* no data available for TX : this should never occur */ /* transmit idle cells as a possible workaround, */ ixAtmdAccCellTx (qMgrEntryPtr, NPE_TX_IDLECELL_ADDRESS, cellCount, NPE_TX_IDLECELL); /* invalidate the current PDU cell count so that on subsequent * invocation we behave correctly */ /* update stats */ IX_ATMDACC_FULL_STATS( ixAtmdAccTxTransportStats[vcDescriptor->port].overScheduledCellCount += cellCount; ); cellCount = 0; vcDescriptor->remainingPduCellCount = 0; } /* end of if(IX_ATMDACC_TXQ_SCHEDULE_PENDING) */ else { /* there are more PDUs to transmit * get the next descriptor with the PDU attached */ /* check unreachable conditions */ IX_ATMDACC_ENSURE (IX_ATMDACC_TXQ_CONSISTENT (txSwQueue), "corrupted sw tx queue"); /* get the current npeDescriptor from the sw queue */ vcDescriptor->currentNpeDesc = IX_ATMDACC_TXQ_TAIL_ENTRY_GET (txSwQueue); IX_ATMDACC_TXQ_TAIL_INCR (txSwQueue); /* check unreachable conditions */ IX_ATMDACC_ENSURE (IX_ATMDACC_TXQ_CONSISTENT (txSwQueue), "corrupted sw tx queue"); /* update the remaining PDU cell count from the PDU size in cells */ vcDescriptor->remainingPduCellCount = vcDescriptor->currentNpeDesc->atmd.totalCell; /* update stats */ IX_ATMDACC_FULL_STATS( ixAtmdAccTxTransportStats[vcDescriptor->port].pduScheduledCount++; ); } /* end of if-else(IX_ATMDACC_TXQ_SCHEDULE_PENDING) */ } /* end of if-else(cellCount) */ } /* end of while(cellCount) */}/* -----------------------------------------------------* process the tx schedule array* - qMgrEntryPtr : pointer to a storage area containing requests to the NPE* - scheduleTableEntryPtr : array of entries* - lastScheduleTableEntry : number of entries*/PRIVATE voidixAtmdAccTxScheduleProcess (UINT32 **qMgrEntryPtr, IxAtmScheduleTableEntry *scheduleTableEntryPtr, unsigned int lastScheduleTableEntry){ /* iterate through each entry of scheduler table */ IxAtmConnId connId; unsigned int descriptorIndex; unsigned int cellCount; IxAtmdAccTxVcDescriptor *vcDescriptor; IxAtmScheduleTableEntry *lastScheduleTableEntryPtr; IX_ATMDACC_FULL_STATS( IxAtmdAccTxTransportStats *portStats; ); /* pointer to the last table entry + 1 : this is used as an address comparison * to check the end of table (more efficient than an index and a loop) */ lastScheduleTableEntryPtr = &scheduleTableEntryPtr[lastScheduleTableEntry]; /* Iterate through the schedule table and transmit idle * or data cells on each VC as requested */ while (scheduleTableEntryPtr != lastScheduleTableEntryPtr) { /* get the connection Id from this table entry */ connId = scheduleTableEntryPtr->connId; /* get the cell count from this table entry */ cellCount = scheduleTableEntryPtr->numberOfCells; /* extract the VC descriptor pool index from the connId */ descriptorIndex = IX_ATMDACC_TX_VC_INDEX_GET (connId); vcDescriptor = &ixAtmdAccTxVcDescriptor[descriptorIndex]; IX_ATMDACC_FULL_STATS( portStats = &ixAtmdAccTxTransportStats[vcDescriptor->port]; ); /* adavnce to the next table entry */ scheduleTableEntryPtr++; if(cellCount != 0) { if (connId == IX_ATM_IDLE_CELLS_CONNID) { /* transmit idle cells */ ixAtmdAccCellTx (qMgrEntryPtr, NPE_TX_IDLECELL_ADDRESS, cellCount, NPE_TX_IDLECELL); /* update stats */ IX_ATMDACC_FULL_STATS( portStats->idleCellScheduledCount += cellCount; ); } /* end of if(connId) */ else { if (vcDescriptor->connId == connId) { /* transmit data cells as requested */ ixAtmdAccChannelTx (qMgrEntryPtr, vcDescriptor, cellCount); } else { /* check for disconnected channels */ if (IX_ATMDACC_TX_DISCONNECTCHECK(connId,vcDescriptor->connId)) { /* the connId is obsolete, this may occur if the scheduling entity is * processing is schedule table exactly during a disconnect. The * action is to transmit data cells as requested. This way, recycling * can be complete through txDone mechanism */ ixAtmdAccChannelTx (qMgrEntryPtr, vcDescriptor, cellCount); /* update stats */ IX_ATMDACC_FULL_STATS( portStats->disconnectScheduledCount++; ); } /* end of if(vcDescriptor) */ else { /* The connId provided is obsolete. To fullfill the port * contract, idle cells are transmitted instead of data cells */ ixAtmdAccCellTx (qMgrEntryPtr, NPE_TX_IDLECELL_ADDRESS, cellCount, NPE_TX_IDLECELL); /* update stats */ IX_ATMDACC_FULL_STATS( portStats->wrongConnIdScheduledCount++; portStats->idleCellScheduledCount += cellCount; ); } /* end of if-else(vcDescriptor) */ } /* end of if-else(vcDescriptor) */ } /* end of if-else(connId) */ } else { /* update stats */ IX_ATMDACC_FULL_STATS( portStats->zeroCellCount++; ); } /* end of if-else(cellCount) */ } /* end of for(scheduleEntry) */}/* -----------------------------------------------------* process the tx schedule table for this port* the schedule table contains the following fields :* - a table size* - an array pointer* Each elementy of the array contains a connId and a * cell count (the number of cells to be transmitted * for the connection referenced by the connId)*/PUBLIC IX_STATUSixAtmdAccPortTxProcess (IxAtmLogicalPort port, IxAtmScheduleTable * scheduleTablePtr){ IxAtmdAccPortDescriptor *portDescriptor; unsigned int scheduleTableSizeInEntries; UINT32 *qMgrEntryPtr; unsigned int numberOfExtraEntriesRequired; unsigned int scheduleNewTableSizeInEntries; IxAtmConnId connId; unsigned int numberOfCells; IxAtmScheduleTableEntry *scheduleNewTableEntryPtr; IX_STATUS returnStatus; IX_ATMDACC_FULL_STATS( IxAtmdAccTxTransportStats *portStats; ); returnStatus = IX_SUCCESS; IX_ATMDACC_PARAMS_CHECK( /* check the port range and schedule table validity */ if ((port >= IX_UTOPIA_MAX_PORTS) || (port < IX_UTOPIA_PORT_0) || (scheduleTablePtr == NULL) || (scheduleTablePtr->table == NULL) || (scheduleTablePtr->totalCellSlots >= IX_ATMDACC_TX_SCHEDULE_TABLE_SIZE) || (scheduleTablePtr->tableSize >= IX_ATMDACC_TX_SCHEDULE_TABLE_SIZE) || (scheduleTablePtr->tableSize == 0)) { IX_ATMDACC_FULL_STATS( /* update the stats per port if the port range is valid */ if ((port < IX_UTOPIA_MAX_PORTS) && (port >= IX_UTOPIA_PORT_0)) { portStats = &ixAtmdAccTxTransportStats[port]; IX_ATMDACC_FULL_STATS( portStats->txProcessFailedCount++; ); }); return IX_FAIL; }); scheduleTableSizeInEntries = scheduleTablePtr->tableSize; portDescriptor = &ixAtmdAccPortDescriptor[port]; qMgrEntryPtr = portDescriptor->qMgrEntries; IX_ATMDACC_FULL_STATS( portStats = &ixAtmdAccTxTransportStats[port]; portStats->txProcessInvokeCount++; ); /* indicate that schedule processing is in progress * i.e. it is not safe to disconnect */ portDescriptor->schedulingInProgress = TRUE; if (portDescriptor->status == IX_ATMDACC_PORT_UP) { /* check if there is a threshold set. If so, fill the * tx queue with single cells to meet the threshold requirements */ if (portDescriptor->txQueueThreshold > 0) { /* move scheduled entries from the schedule table to * a temporary table,and fill this table with single entries. * This will guarantee the accuracy of the threshold event. */ numberOfExtraEntriesRequired = portDescriptor->txQueueThreshold + 1; scheduleNewTableSizeInEntries = 0; scheduleNewTableEntryPtr = &portDescriptor->scheduleTable[IX_ATMDACC_TX_SCHEDULE_TABLE_SIZE - 1]; /* reads backwards the schedule table and fill an other schedule * table containing the exact number of entries required, with * one cell per entry. */ while (scheduleTableSizeInEntries > 0 && numberOfExtraEntriesRequired > 0) { /* remove the last schedule table entry */ scheduleTableSizeInEntries--; connId = scheduleTablePtr->table[scheduleTableSizeInEntries].connId; numberOfCells = scheduleTablePtr->table[scheduleTableSizeInEntries].numberOfCells; /* build many new entries with this last schedule table entry */ while (numberOfCells > 0 && numberOfExtraEntriesRequired > 0) { /* add 1 table entry per 1 cell */ scheduleNewTableEntryPtr--; scheduleNewTableSizeInEntries++; scheduleNewTableEntryPtr->connId = connId; scheduleNewTableEntryPtr->numberOfCells = 1; numberOfExtraEntriesRequired--; numberOfCells--; } if (numberOfCells > 0) { /* update the current new entry with remaining cells */ scheduleNewTableEntryPtr->numberOfCells += numberOfCells; } } IX_ATMDACC_FULL_STATS( if ((scheduleTableSizeInEntries + scheduleNewTableSizeInEntries) <= portDescriptor->txQueueThreshold) { portStats->txProcessUnderscheduledCount++; }); /* process the initial schedule table (if any remaining) */ if (scheduleTableSizeInEntries > 0) { /* process the schedule table */ ixAtmdAccTxScheduleProcess (&qMgrEntryPtr, scheduleTablePtr->table, scheduleTableSizeInEntries); } /* process the additional schedule table (if any generated) */ if (scheduleNewTableSizeInEntries > 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -