/* * MTL_TX.C - trasmit side processing for MTL */ #include #include #include #include #include #include #include #include #include #include #include extern DRIVER_BLOCK Pcimac; /* local prototypes */ BOOLEAN IsWanPacketTxFifoEmpty(MTL*); VOID AddToWanPacketTxFifo(MTL*, NDIS_WAN_PACKET*); MTL_TX_PKT* GetLocalTxDescriptor(MTL*); VOID FreeLocalTxDescriptor(MTL*, MTL_TX_PKT*); VOID TryToXmitFrags(MTL*); VOID SetTxDescriptorInWanPacket(MTL*,NDIS_WAN_PACKET*,MTL_TX_PKT*); VOID CheckWanPacketTimeToLive(MTL *mtl); VOID ReleaseTxDescriptor(MTL *mtl, MTL_TX_PKT *MtlTxPacket); #define IsWanPacketMarkedForCompletion(_WanPacket) \ ((_WanPacket)->MacReserved2 == (PVOID)TRUE) #define ClearTxDescriptorInWanPacket(_WanPacket) \ (_WanPacket)->MacReserved1 = (PVOID)NULL #define ClearReadyToCompleteInWanPacket(_WanPacket) \ (_WanPacket)->MacReserved2 = (PVOID)NULL #define SetTimeToLiveInWanPacket(_WanPacket, _TimeOut) \ (_WanPacket)->MacReserved3 = (PVOID)_TimeOut #define DecrementTimeToLiveForWanPacket(_WanPacket, _Decrement) \ (ULONG)((_WanPacket)->MacReserved3) -= (ULONG)_Decrement #define GetWanPacketTimeToLive(_WanPacket) \ (ULONG)((_WanPacket)->MacReserved3) #define GetTxDescriptorFromWanPacket(_WanPacket) \ ((MTL_TX_PKT*)((_WanPacket)->MacReserved1)) #define MarkWanPacketForCompletion(_WanPacket) \ (_WanPacket)->MacReserved2 = (PVOID)TRUE #define SetTxDescriptorInWanPacket(_WanPacket, _TxDescriptor) \ (_WanPacket)->MacReserved1 = (PVOID)_TxDescriptor #define IncrementGlobalCount(_Counter) \ { \ NdisAcquireSpinLock(&Pcimac.lock); \ _Counter++; \ NdisReleaseSpinLock(&Pcimac.lock); \ } ULONG GlobalSends = 0; ULONG GlobalSendsCompleted = 0; ULONG MtlSends1 = 0; ULONG MtlSends2 = 0; ULONG MtlSends3 = 0; ULONG MtlSends4 = 0; ULONG MtlSends5 = 0; /* trasmit side timer tick */ VOID mtl__tx_tick(MTL *mtl) { D_LOG(D_NEVER, ("mtl__tx_tick: entry, mtl: 0x%lx\n", mtl)); NdisAcquireSpinLock(&mtl->lock); // // try to transmit frags to the adapter // TryToXmitFrags(mtl); // // Check time to live on wan packet tx fifo // CheckWanPacketTimeToLive(mtl); NdisReleaseSpinLock(&mtl->lock); } VOID MtlSendCompleteFunction( ADAPTER *Adapter ) { ULONG n; for ( n = 0; n < MAX_MTL_PER_ADAPTER; n++) { MTL *mtl = Adapter->MtlTbl[n] ; if (mtl && !IsWanPacketTxFifoEmpty(mtl)) { // // try to complete any wan packets ready for completion // IndicateTxCompletionToWrapper(mtl); } } } // // process a wan packet for transmition to idd level // // all packets will stay on one queue and the MacReserved fields will be used // to indicate what state the packet is in // // we will use the MacReserved fields provided in the NdisWanPacket as follows: // // MacReserved1 - Store a pointer to our local tx descriptor // MacReserved2 - This will be a boolean flag that will be set when this packet // can be completed (NdisMWanSendComplete) // MacReserved3 - This will be the time to live counter for the wanpacket. // If it is not completed we will go ahead and complete it. // // MacReserved4 // VOID mtl__tx_packet( MTL *mtl, NDIS_WAN_PACKET *WanPacket ) { UINT BytesLeftToTx, FragDataLength, FragNumber, FragSize; UINT TotalPacketLength; UCHAR *FragDataPtr; MTL_TX_PKT *MtlTxPacket; MTL_HDR MtlHeader; USHORT TxFlags; ADAPTER *Adapter = mtl->Adapter; PUCHAR MyStartBuffer; CM *cm = (CM*)mtl->cm; D_LOG(D_ENTRY, ("mtl_tx_packet: entry, mtl: 0x%lx, WanPacket: 0x%lx\n", mtl, WanPacket)); NdisAcquireSpinLock(&mtl->lock); IncrementGlobalCount(GlobalSends); // // queue up the wanpacket // AddToWanPacketTxFifo(mtl, WanPacket); // // get a local packet descriptor // MtlTxPacket = GetLocalTxDescriptor(mtl); // // make sure this is a valid descriptor // if (!MtlTxPacket) { D_LOG(DIGIMTL, ("mtl__tx_proc: Got a NULL Packet off of Local Descriptor Free List\n")); // // grab wan packet fifo lock // NdisAcquireSpinLock(&mtl->WanPacketFifo.lock); MarkWanPacketForCompletion(WanPacket); // // release the wan packet fifo lock // NdisReleaseSpinLock(&mtl->WanPacketFifo.lock); goto exit_code; } // // grab wan packet fifo lock // NdisAcquireSpinLock(&mtl->WanPacketFifo.lock); SetTxDescriptorInWanPacket(WanPacket, MtlTxPacket); // // release the wan packet fifo lock // NdisReleaseSpinLock(&mtl->WanPacketFifo.lock); // // grab the descriptor lock // NdisAcquireSpinLock(&MtlTxPacket->lock); IncrementGlobalCount(MtlSends1); /* if not connected, give up */ if ( !mtl->is_conn || cm->PPPToDKF) { D_LOG(DIGIMTL, ("mtl__tx_proc: packet on non-connected mtl, ignored\n")); IncrementGlobalCount(MtlSends2); goto xmit_error; } D_LOG(DIGIMTL, ("mtl__tx_proc: LocalPkt: 0x%lx, WanPkt: 0x%lx, WanPktLen: %d\n", MtlTxPacket, WanPacket, WanPacket->CurrentLength)); // // get length of wan packet // TotalPacketLength = WanPacket->CurrentLength; // // my start buffer is WanPacket->CurrentBuffer - 14 // MyStartBuffer = WanPacket->CurrentBuffer - 14; if (mtl->SendFramingBits & RAS_FRAMING) { D_LOG(DIGIMTL, ("mtl__tx_proc: Transmit WrapperFrameType: RAS\n")); // add dest eaddr // StartBuffer + 0 // NdisMoveMemory (MyStartBuffer + DST_ADDR_INDEX, cm->DstAddr, 6); // // add source eaddr // StartBuffer + 6 // NdisMoveMemory (MyStartBuffer + SRC_ADDR_INDEX, cm->SrcAddr, 6); // // add new length to buffer // StartBuffer + 12 // MyStartBuffer[12] = TotalPacketLength >> 8; MyStartBuffer[13] = TotalPacketLength & 0xFF; // // data now begins at MyStartBuffer // MtlTxPacket->frag_buf = MyStartBuffer; // // new transmit length is a mac header larger // TotalPacketLength += 14; } else if (mtl->SendFramingBits & PPP_FRAMING) { D_LOG(DIGIMTL, ("mtl__tx_proc: Transmit WrapperFrameType: PPP\n")); // // data now begins at CurrentBuffer // MtlTxPacket->frag_buf = WanPacket->CurrentBuffer; } else { // // unknown framing - what to do what to do // D_LOG(DIGIMTL, ("mtl__tx_proc: Packet sent with uknown framing, ignored\n")); IncrementGlobalCount(MtlSends3); goto xmit_error; } if (TotalPacketLength > MTL_MAC_MTU) { D_LOG(DIGIMTL, ("mtl__tx_proc: packet too long, TotalPacketLength: %d\n", TotalPacketLength)); IncrementGlobalCount(MtlSends4); goto xmit_error; } /* step 4: calc number of fragments */ D_LOG(DIGIMTL, ("mtl__tx_proc: calc frag num, TotalPacketLength: %d\n", TotalPacketLength)); // // Calculate the number of fragments per link given // the size of data we can give the adapter. // MtlTxPacket->NumberOfFrags = (USHORT)(TotalPacketLength / mtl->chan_tbl.num / mtl->idd_mtu); if ( TotalPacketLength != (USHORT)(MtlTxPacket->NumberOfFrags * mtl->chan_tbl.num * mtl->idd_mtu) ) MtlTxPacket->NumberOfFrags++; MtlTxPacket->NumberOfFrags *= mtl->chan_tbl.num; if ( MtlTxPacket->NumberOfFrags > MTL_MAX_FRAG ) { D_LOG(DIGIMTL, ("mtl__tx_proc: pkt has too many frags, NumberOfFrags: %d\n", \ MtlTxPacket->NumberOfFrags)); IncrementGlobalCount(MtlSends5); goto xmit_error; } D_LOG(DIGIMTL, ("mtl__tx_proc: NumberOfFrags: %d\n", MtlTxPacket->NumberOfFrags)); /* step 5: build generic header */ if (mtl->IddTxFrameType & IDD_FRAME_DKF) { MtlHeader.sig_tot = MtlTxPacket->NumberOfFrags | 0x50; MtlHeader.seq = (UCHAR)(mtl->tx_tbl.seq++); MtlHeader.ofs = 0; } /* step 6: build fragments */ // // bytes left to send is initially the packet size // BytesLeftToTx = TotalPacketLength; // // FragDataPtr initially points to begining of frag buffer // FragDataPtr = MtlTxPacket->frag_buf; // // initial txflags are for a complete frame // TxFlags = 0; for ( FragNumber = 0 ; FragNumber < MtlTxPacket->NumberOfFrags ; FragNumber++ ) { MTL_TX_FRAG *FragPtr = &MtlTxPacket->frag_tbl[FragNumber]; IDD_MSG *FragMsg = &FragPtr->frag_msg; MTL_CHAN *chan; /* if it's first channel, establish next fragment size */ if ( !(FragNumber % mtl->chan_tbl.num) ) FragSize = MIN((BytesLeftToTx / mtl->chan_tbl.num), mtl->idd_mtu); /* establish related channel */ chan = mtl->chan_tbl.tbl + (FragNumber % mtl->chan_tbl.num); /* calc size of this fragment */ if ( FragNumber == (USHORT)(MtlTxPacket->NumberOfFrags - 1) ) FragDataLength = BytesLeftToTx; else FragDataLength = FragSize; D_LOG(DIGIMTL, ("mtl__proc_tx: FragNumber: %d, FragDataPtr: 0x%lx, FragLength: %d\n", \ FragNumber, FragDataPtr, FragDataLength)); if (mtl->IddTxFrameType & IDD_FRAME_DKF) { DKF_FRAG *DkfFrag = &FragPtr->DkfFrag; IDD_FRAG *IddFrag0 = &DkfFrag->IddFrag[0]; IDD_FRAG *IddFrag1 = &DkfFrag->IddFrag[1]; D_LOG(DIGIMTL, ("mtl__tx_proc: Transmit IddFrameType: DKF\n")); // // setup fragment descriptor for DKF data // /* setup fragment header */ DkfFrag->MtlHeader = MtlHeader; /* set pointer to header */ IddFrag0->len = sizeof(MTL_HDR); IddFrag0->ptr = (CHAR*)(&DkfFrag->MtlHeader); /* set pointer to data */ IddFrag1->len = FragDataLength; IddFrag1->ptr = FragDataPtr; // // fill idd message // FragMsg->buflen = sizeof(DKF_FRAG) | TX_FRAG_INDICATOR; // // this assumes that the DKF_FRAG structure is the first // member of the MTL_TX_FRAG structure !!!!! // FragMsg->bufptr = (UCHAR*)FragPtr; } else { D_LOG(DIGIMTL, ("mtl__tx_proc: Transmit IddFrameType: PPP\n")); // // setup fragment descriptor for ppp frame // if (BytesLeftToTx <= mtl->idd_mtu ) { // // if all that is left can be sent this is the end // FragMsg->buflen = FragDataLength | TxFlags; } else { // // if there is still more this is not end // FragMsg->buflen = FragDataLength | TxFlags | H_TX_N_END; } // // setup data pointer // FragMsg->bufptr = (UCHAR*)FragDataPtr; } FragPtr->FragSent = 0; FragPtr->frag_idd = chan->idd; FragPtr->frag_bchan = chan->bchan; FragPtr->frag_arg = MtlTxPacket; /* update variables */ TxFlags = H_TX_N_BEG; BytesLeftToTx -= FragDataLength; FragDataPtr += FragDataLength; MtlHeader.ofs += FragDataLength; } /* step 7: setup more fields */ MtlTxPacket->WanPacket = WanPacket; MtlTxPacket->FragReferenceCount = MtlTxPacket->NumberOfFrags; MtlTxPacket->mtl = mtl; MtlTxPacket->NumberOfFragsSent = 0; mtl->FramesXmitted++; mtl->BytesXmitted += TotalPacketLength; // // release the lock befor xmitting // NdisReleaseSpinLock(&MtlTxPacket->lock); // // put this tx descriptor on list for transmition // NdisAcquireSpinLock(&mtl->tx_tbl.lock); InsertTailList(&mtl->tx_tbl.head, &MtlTxPacket->TxPacketQueue); NdisReleaseSpinLock(&mtl->tx_tbl.lock); // // Try to xmit some frags // TryToXmitFrags(mtl); goto exit_code; // // error while setting up for transmition // xmit_error: ClearTxDescriptorInWanPacket(WanPacket); // // free tx descriptor // FreeLocalTxDescriptor(mtl, MtlTxPacket); // // free descriptors lock // NdisReleaseSpinLock(&MtlTxPacket->lock); // // grab wan packet fifo lock // NdisAcquireSpinLock(&mtl->WanPacketFifo.lock); // // mark wan packet for completion // MarkWanPacketForCompletion(WanPacket); // // release the wan packet fifo lock // NdisReleaseSpinLock(&mtl->WanPacketFifo.lock); // // exit code // release spinlock and return // exit_code: NdisReleaseSpinLock(&mtl->lock); } // // Try to transmit fragments to idd // VOID TryToXmitFrags( MTL *mtl ) { LIST_ENTRY *MtlTxPacketQueueHead; MTL_TX_TBL *MtlTxTbl = &mtl->tx_tbl; MTL_TX_PKT *MtlTxPacket; ULONG Ret = IDD_E_SUCC; BOOLEAN WeCanXmit = 1; // // get tx table spin lock // NdisAcquireSpinLock(&MtlTxTbl->lock); MtlTxPacketQueueHead = &MtlTxTbl->head; // // while we can still transmit and we are not at the end of the list // while (WeCanXmit && !IsListEmpty(MtlTxPacketQueueHead)) { USHORT n, NumberOfFragsToSend; MtlTxPacket = (MTL_TX_PKT*)MtlTxPacketQueueHead->Flink; // // get the number of frags we will try to send // NdisAcquireSpinLock(&MtlTxPacket->lock); NumberOfFragsToSend = MtlTxPacket->NumberOfFrags; NdisReleaseSpinLock(&MtlTxPacket->lock); for (n = 0; n < NumberOfFragsToSend; n++) { MTL_TX_FRAG *FragToSend; NdisAcquireSpinLock(&MtlTxPacket->lock); FragToSend = &MtlTxPacket->frag_tbl[n]; NdisReleaseSpinLock(&MtlTxPacket->lock); // // if this frag has already been sent get the next one // if (FragToSend->FragSent) continue; D_LOG(DIGIMTL, ("TryToXmitFrag: mtl: 0x%x\n", mtl)); D_LOG(DIGIMTL, ("Next Packet To Xmit: MtlTxPacket: 0x%x\n", MtlTxPacket)); D_LOG(DIGIMTL, ("Xmitting Packet: MtlTxPacket: 0x%x\n", MtlTxPacket)); D_LOG(DIGIMTL, ("TryToXmitFrag: FragToSend: 0x%x\n", FragToSend)); D_LOG(DIGIMTL, ("TryToXmitFrag: Idd: 0x%x, Msg: 0x%x, Bchan: 0x%x, Arg: 0x%x\n", \ FragToSend->frag_idd, &FragToSend->frag_msg, \ FragToSend->frag_bchan, FragToSend->frag_arg)); // // Something was ready to send // release all locks before sending // NdisReleaseSpinLock(&MtlTxTbl->lock); Ret = idd_send_msg(FragToSend->frag_idd, &FragToSend->frag_msg, FragToSend->frag_bchan, (VOID*)mtl__tx_cmpl_handler, FragToSend->frag_arg); // // acquire Tx Tbl fifo lock // exit code expects the lock to be held // NdisAcquireSpinLock(&MtlTxTbl->lock); if (Ret == IDD_E_SUCC) { // // this means frag was sent to idd // all locks will be released before next frag is sent // // // acquire descriptor lock // exit code expects the lock to be held // NdisAcquireSpinLock(&MtlTxPacket->lock); // // message was queued or sent! // MtlTxPacket->NumberOfFragsSent++; FragToSend->FragSent++; if (MtlTxPacket->NumberOfFragsSent == MtlTxPacket->NumberOfFrags) { // // if things are working ok this guy will be on top // ASSERT((PVOID)MtlTxPacketQueueHead->Flink == (PVOID)MtlTxPacket); // // take a guy off of the to be transmitted list // RemoveEntryList(&MtlTxPacket->TxPacketQueue); } // // release the lock for this descriptor // NdisReleaseSpinLock(&MtlTxPacket->lock); } else { // // if this frag is not sent to idd // then stop xmitting // WeCanXmit = 0; } } } // // release the tx tbl fifo lock // NdisReleaseSpinLock(&MtlTxTbl->lock); } /* trasmit completion routine */ VOID mtl__tx_cmpl_handler( MTL_TX_PKT *MtlTxPacket, USHORT port, IDD_MSG *msg ) { MTL *mtl; PNDIS_WAN_PACKET WanPacket; D_LOG(D_ENTRY, ("mtl__tx_cmpl_handler: entry, MtlTxPacket: 0x%lx, port: %d, msg: 0x%lx\n", \ MtlTxPacket, port, msg)); NdisAcquireSpinLock(&MtlTxPacket->lock); mtl = MtlTxPacket->mtl; // // if this guy was set free from a disconnect while he was // on the idd tx queue. Just throw him away! // if this is not the last reference to the packet get the hell out!!! // if (!MtlTxPacket->InUse || --MtlTxPacket->FragReferenceCount ) { NdisReleaseSpinLock(&MtlTxPacket->lock); return; } D_LOG(DIGIMTL, ("mtl__tx_cmpl_handler: FragReferenceCount==0, mtl: 0x%lx\n", mtl)); // // Get hold of PNDIS_WAN_PACKET associated with this descriptor // WanPacket = MtlTxPacket->WanPacket; if (!WanPacket) { ASSERT(WanPacket); NdisReleaseSpinLock(&MtlTxPacket->lock); return; } ClearTxDescriptorInWanPacket(WanPacket); // // return local packet descriptor to free list // FreeLocalTxDescriptor(mtl, MtlTxPacket); NdisReleaseSpinLock(&MtlTxPacket->lock); // // grab wan packet fifo lock // NdisAcquireSpinLock(&mtl->WanPacketFifo.lock); // // mark wan packet as being ready for completion // MarkWanPacketForCompletion(WanPacket); // // release the wan packet fifo lock // NdisReleaseSpinLock(&mtl->WanPacketFifo.lock); } // // get a local packet descriptor off of the free list // MTL_TX_PKT* GetLocalTxDescriptor( MTL *mtl ) { MTL_TX_PKT* FreePkt = NULL; MTL_TX_TBL* TxTbl = &mtl->tx_tbl; NdisAcquireSpinLock (&mtl->tx_tbl.lock); // // get next available freepkt // FreePkt = TxTbl->TxPacketTbl + (TxTbl->NextFree % MTL_TX_BUFS); // // if still in use we have a wrap // if (FreePkt->InUse) { ASSERT(!FreePkt->InUse); NdisReleaseSpinLock (&mtl->tx_tbl.lock); return(NULL); } // // mark as being used // FreePkt->InUse = 1; // // bump pointer to next free // TxTbl->NextFree++; NdisReleaseSpinLock (&mtl->tx_tbl.lock); return(FreePkt); } // // return a local packet descriptor to free pool // assumes that the MtlTxPacket lock is held // VOID FreeLocalTxDescriptor( MTL *mtl, MTL_TX_PKT *MtlTxPacket ) { ASSERT(MtlTxPacket->InUse); MtlTxPacket->InUse = 0; MtlTxPacket->WanPacket = NULL; } // // see if wan packet fifo is empty // BOOLEAN IsWanPacketTxFifoEmpty( MTL *mtl ) { BOOLEAN Result; NdisAcquireSpinLock (&mtl->WanPacketFifo.lock); Result = IsListEmpty(&mtl->WanPacketFifo.head); NdisReleaseSpinLock (&mtl->WanPacketFifo.lock); return(Result); } // // add a wan packet to the wan packet fifo // VOID AddToWanPacketTxFifo( MTL *mtl, NDIS_WAN_PACKET *WanPacket ) { MTL_WANPACKET_FIFO *WanPacketFifo = &mtl->WanPacketFifo; PLIST_ENTRY TempQueue; D_LOG(D_ENTRY, ("AddToWanPacketTxFifo: mtl: 0x%x, head: 0x%x\n", mtl, WanPacketFifo->head)); NdisAcquireSpinLock (&WanPacketFifo->lock); // // We do a little consistency check and make sure we don't have // have this wan packet allready on the queue. // TempQueue = &WanPacketFifo->head; #if DBG while( TempQueue->Flink != &WanPacketFifo->head ) { NDIS_WAN_PACKET *TempWanPacket; TempWanPacket = CONTAINING_RECORD( TempQueue->Flink, NDIS_WAN_PACKET, WanPacketQueue ); ASSERT( TempWanPacket != NULL ); ASSERT( TempWanPacket != WanPacket ); TempQueue = TempQueue->Flink; } #endif ClearReadyToCompleteInWanPacket(WanPacket); SetTimeToLiveInWanPacket(WanPacket, 5000); ClearTxDescriptorInWanPacket(WanPacket); InsertTailList(&WanPacketFifo->head, &WanPacket->WanPacketQueue); WanPacketFifo->Count++; if (WanPacketFifo->Count > WanPacketFifo->Max) WanPacketFifo->Max = WanPacketFifo->Count; NdisReleaseSpinLock (&WanPacketFifo->lock); } // // indicate xmit completion of wan packet to wrapper // VOID IndicateTxCompletionToWrapper( MTL *mtl ) { ADAPTER *Adapter = (ADAPTER*)mtl->Adapter; NDIS_WAN_PACKET *WanPacket; LIST_ENTRY *WanPacketFifoHead; MTL_WANPACKET_FIFO *WanPacketFifo = &mtl->WanPacketFifo; // // acquire wan packet fifo lock // NdisAcquireSpinLock(&WanPacketFifo->lock); // // get head of wan packet fifo // WanPacketFifoHead = &WanPacketFifo->head; // // visit the first packet on the tx list // WanPacket = (NDIS_WAN_PACKET*)WanPacketFifoHead->Flink; // // if the list is not empty and this packet is ready to be completed // while (((PVOID)WanPacket != (PVOID)WanPacketFifoHead) && IsWanPacketMarkedForCompletion(WanPacket)) { WanPacket = (PNDIS_WAN_PACKET)RemoveHeadList(&WanPacketFifo->head); WanPacketFifo->Count--; if (!WanPacket) break; IncrementGlobalCount(GlobalSendsCompleted); ClearReadyToCompleteInWanPacket(WanPacket); // // release wan packet fifo lock // NdisReleaseSpinLock(&WanPacketFifo->lock); NdisMWanSendComplete(Adapter->Handle, WanPacket, NDIS_STATUS_SUCCESS); // // acquire wan packet fifo lock // NdisAcquireSpinLock(&WanPacketFifo->lock); // // visit the new head of the list // WanPacket = (NDIS_WAN_PACKET*)WanPacketFifoHead->Flink; } // // release wan packet fifo lock // NdisReleaseSpinLock(&WanPacketFifo->lock); } VOID MtlFlushWanPacketTxQueue( MTL *mtl ) { LIST_ENTRY *WanPacketFifoHead; MTL_WANPACKET_FIFO *WanPacketFifo = &mtl->WanPacketFifo; NDIS_WAN_PACKET *WanPacket; MTL_TX_PKT *MtlTxPacket; // // acquire wan packet fifo lock // NdisAcquireSpinLock(&WanPacketFifo->lock); // // get head of wan packet fifo // WanPacketFifoHead = &WanPacketFifo->head; // // visit the first packet on the tx list // WanPacket = (NDIS_WAN_PACKET*)WanPacketFifoHead->Flink; // // if the wan packet queue is not empty // we need to drain it! // while ((PVOID)WanPacket != (PVOID)WanPacketFifoHead) { // // get the associated MtlTxPacket // if (MtlTxPacket = GetTxDescriptorFromWanPacket(WanPacket)) ReleaseTxDescriptor(mtl, MtlTxPacket); // // mark wan packet for completion // MarkWanPacketForCompletion(WanPacket); // // get the next packet on the list // WanPacket = (NDIS_WAN_PACKET*)(WanPacket->WanPacketQueue).Flink; } // // release wan packet fifo lock // NdisReleaseSpinLock(&WanPacketFifo->lock); } // // walk through the WanPacketFifo and see if anyone has been sitting there // too long! This could happen if there was some kind of xmit failure to // the adapter. // VOID CheckWanPacketTimeToLive( MTL *mtl ) { LIST_ENTRY *WanPacketFifoHead; MTL_WANPACKET_FIFO *WanPacketFifo = &mtl->WanPacketFifo; NDIS_WAN_PACKET *WanPacket; // MTL_TX_PKT *MtlTxPacket; // // acquire wan packet fifo lock // NdisAcquireSpinLock(&WanPacketFifo->lock); // // get head of wan packet fifo // WanPacketFifoHead = &WanPacketFifo->head; // // visit the first packet on the tx list // WanPacket = (NDIS_WAN_PACKET*)WanPacketFifoHead->Flink; // // if the wan packet is not empty // while ((PVOID)WanPacket != (PVOID)WanPacketFifoHead) { // // decrement the count by 25ms // DecrementTimeToLiveForWanPacket(WanPacket, 25); // // if the count has gone to zero this guy has // been waiting for more then 1sec so complete him // if (!GetWanPacketTimeToLive(WanPacket)) { // if (IsWanPacketMarkedForCompletion(WanPacket)) // DbgPrint("PCIMAC.SYS: WanPacket was already marked for completion!\n"); // // // // // get the associated MtlTxPacket and free // // // if (MtlTxPacket = GetTxDescriptorFromWanPacket(WanPacket)) // ReleaseTxDescriptor(mtl, MtlTxPacket); // // // // // mark the packet for completion // // // MarkWanPacketForCompletion(WanPacket); } // // get the next packet on the list // WanPacket = (NDIS_WAN_PACKET*)(WanPacket->WanPacketQueue).Flink; } // // release wan packet fifo lock // NdisReleaseSpinLock(&WanPacketFifo->lock); } VOID ReleaseTxDescriptor( MTL *mtl, MTL_TX_PKT *MtlTxPacket ) { LIST_ENTRY *MtlTxPacketQueueHead; MTL_TX_TBL *MtlTxTbl = &mtl->tx_tbl; MTL_TX_PKT *NextMtlTxPacket; // // act like this local descriptor was sent // keeps desriptor table pointers in line // NdisAcquireSpinLock(&MtlTxTbl->lock); MtlTxPacketQueueHead = &MtlTxTbl->head; // // get the descriptor lock // NdisAcquireSpinLock(&MtlTxPacket->lock); // // visit the first packet on the list // NextMtlTxPacket = (MTL_TX_PKT*)MtlTxPacketQueueHead->Flink; // // break if the list has been traversed or if we find the packet // while (((PVOID)NextMtlTxPacket != MtlTxPacketQueueHead) && (NextMtlTxPacket != MtlTxPacket)) NextMtlTxPacket = (MTL_TX_PKT*)(NextMtlTxPacket->TxPacketQueue).Flink; // // if this descriptor is marked for transmition // we should remove it from the tx descriptor list // if (NextMtlTxPacket == MtlTxPacket) RemoveEntryList(&MtlTxPacket->TxPacketQueue); FreeLocalTxDescriptor(mtl, MtlTxPacket); NdisReleaseSpinLock(&MtlTxPacket->lock); NdisReleaseSpinLock(&MtlTxTbl->lock); }