2020-09-30 17:12:29 +02:00

1067 lines
23 KiB
C

/*
* MTL_TX.C - trasmit side processing for MTL
*/
#include <ndis.h>
//#include <ndismini.h>
#include <ndiswan.h>
#include <mytypes.h>
#include <mydefs.h>
#include <disp.h>
#include <util.h>
#include <opcodes.h>
#include <adapter.h>
#include <idd.h>
#include <mtl.h>
#include <cm.h>
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%p", 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%p, WanPacket: 0x%p", 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(D_ALWAYS, ("mtl__tx_proc: Got a NULL Packet off of Local Descriptor Free List"));
//
// 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(D_ALWAYS, ("mtl__tx_proc: packet on non-connected mtl, ignored"));
IncrementGlobalCount(MtlSends2);
goto xmit_error;
}
D_LOG(D_ALWAYS, ("mtl__tx_proc: LocalPkt: 0x%p, WanPkt: 0x%p, WanPktLen: %d", 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(D_ALWAYS, ("mtl__tx_proc: Transmit WrapperFrameType: RAS"));
// 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(D_ALWAYS, ("mtl__tx_proc: Transmit WrapperFrameType: PPP"));
//
// data now begins at CurrentBuffer
//
MtlTxPacket->frag_buf = WanPacket->CurrentBuffer;
}
else
{
//
// unknown framing - what to do what to do
//
D_LOG(D_ALWAYS, ("mtl__tx_proc: Packet sent with uknown framing, ignored"));
IncrementGlobalCount(MtlSends3);
goto xmit_error;
}
if (TotalPacketLength > MTL_MAC_MTU)
{
D_LOG(D_ALWAYS, ("mtl__tx_proc: packet too long, TotalPacketLength: %d", TotalPacketLength));
IncrementGlobalCount(MtlSends4);
goto xmit_error;
}
/* step 4: calc number of fragments */
D_LOG(D_ALWAYS, ("mtl__tx_proc: calc frag num, TotalPacketLength: %d", TotalPacketLength));
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(D_ALWAYS, ("mtl__tx_proc: pkt has too many frags, NumberOfFrags: %d", \
MtlTxPacket->NumberOfFrags));
IncrementGlobalCount(MtlSends5);
goto xmit_error;
}
D_LOG(D_ALWAYS, ("mtl__tx_proc: NumberOfFrags: %d", 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(D_ALWAYS, ("mtl__proc_tx: FragNumber: %d, FragDataPtr: 0x%p, FragLength: %d", \
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(D_ALWAYS, ("mtl__tx_proc: Transmit IddFrameType: DKF"));
//
// 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(D_ALWAYS, ("mtl__tx_proc: Transmit IddFrameType: PPP"));
//
// 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(D_ALWAYS, ("TryToXmitFrag: mtl: 0x%x", mtl));
D_LOG(D_ALWAYS, ("Next Packet To Xmit: MtlTxPacket: 0x%x", MtlTxPacket));
D_LOG(D_ALWAYS, ("Xmitting Packet: MtlTxPacket: 0x%x", MtlTxPacket));
D_LOG(D_ALWAYS, ("TryToXmitFrag: FragToSend: 0x%x", FragToSend));
D_LOG(D_ALWAYS, ("TryToXmitFrag: Idd: 0x%x, Msg: 0x%x, Bchan: 0x%x, Arg: 0x%x", \
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%p, port: %d, msg: 0x%p", \
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(D_ALWAYS, ("mtl__tx_cmpl_handler: FragReferenceCount==0, mtl: 0x%p", 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;
D_LOG(D_ENTRY, ("AddToWanPacketTxFifo: mtl: 0x%x, head: 0x%x", mtl, WanPacketFifo->head));
NdisAcquireSpinLock (&WanPacketFifo->lock);
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);
}