📄 send.c
字号:
--*/
{
PNDIS_PACKET tmpPacket;
PPACKET_RESERVED Reserved;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PSAR_INFO pSar = pXmitSegInfo->Adapter->HardwareInfo->SarInfo;
PXMIT_DMA_QUEUE pXmitDmaQ = &pSar->XmitDmaQ;
NdisAcquireSpinLock(&pXmitSegInfo->lock);
//
// Are they trying to send a specific packet?
//
if (ARGUMENT_PRESENT(Packet))
{
Reserved = PACKET_RESERVED_FROM_PACKET(Packet);
//
// 1. If there is segmentation memory available?
// 2. If there is FreePadTrailerBuffers available?
//
if ((pXmitDmaQ->RemainingTransmitSlots < Reserved->PhysicalBufferCount) ||
(pXmitSegInfo->BeOrBeingUsedPadTrailerBufs >= TBATM155_MAX_PADTRAILER_BUFFERS))
{
//
// Insert the packet to DmaWait queue if
// 1. there is allocated FreePadTrailerBuffers available,
// 2. AAL5 packet, and
// 3. SegWait queue of the VC is empty.
//
if ((pXmitSegInfo->BeOrBeingUsedPadTrailerBufs < TBATM155_MAX_PADTRAILER_BUFFERS) &&
(AAL_TYPE_AAL5 == Reserved->pVc->AALType) &&
(PACKET_QUEUE_EMPTY(&pXmitSegInfo->SegWait)))
{
//
// If we come to this point, it means there is no packets
// of this VC have been sent out. So we queue to DmaWait
// to make sure this packet will be sent out when there
// are resources available.
//
InsertPacketAtTailDpc(&pXmitDmaQ->DmaWait, Packet);
pXmitSegInfo->BeOrBeingUsedPadTrailerBufs++;
NdisReleaseSpinLock(&pXmitSegInfo->lock);
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("<==tbAtm155ProcessSegmentQueue(NDIS_STATUS_PENDING_1)\n"));
return(NDIS_STATUS_PENDING);
}
if ((pXmitSegInfo->BeOrBeingUsedPadTrailerBufs >= TBATM155_MAX_PADTRAILER_BUFFERS) ||
(pXmitDmaQ->RemainingTransmitSlots < MIN_SLOTS_REQUIED_PER_PACKET))
{
//
// No room available in the SAR. We need to queue this
// and do it later.
//
dbgLogSendPacket(
PACKET_RESERVED_FROM_PACKET(Packet)->pVc->DebugInfo,
Packet,
2,
0,
' wsQ');
InsertPacketAtTailDpc(&pXmitSegInfo->SegWait, Packet);
NdisReleaseSpinLock(&pXmitSegInfo->lock);
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("<==tbAtm155ProcessSegmentQueue(NDIS_STATUS_PENDING)\n"));
return(NDIS_STATUS_PENDING);
}
}
//
// Are there any other packets that might be waiting for these
// resources?
//
if (PACKET_QUEUE_EMPTY(&pXmitSegInfo->SegWait) &&
(pXmitSegInfo->BeOrBeingUsedPadTrailerBufs < TBATM155_MAX_PADTRAILER_BUFFERS))
{
//
// Packet queue is empty so we can try and send this packet to
// the transmit DMA engine.
//
NdisReleaseSpinLock(&pXmitSegInfo->lock);
dbgLogSendPacket(Reserved->pVc->DebugInfo, Packet, 0, 0, 'qwdp');
tbAtm155ProcessTransmitDmaWaitQueue(
pXmitSegInfo->Adapter,
Packet,
FALSE);
dbgLogSendPacket( Reserved->pVc->DebugInfo, Packet, 0, 0, 'QWDP');
NdisAcquireSpinLock(&pXmitSegInfo->lock);
Status = NDIS_STATUS_SUCCESS;
}
else
{
//
// Packet queue is not empty so we need to place this packet at
// the end of the queue then we can process the packet queue from
// the beginning (remember we have already determined that we have
// resources in the segmentation memory).
//
dbgLogSendPacket(
PACKET_RESERVED_FROM_PACKET(Packet)->pVc->DebugInfo,
Packet,
3,
0,
' wsQ');
InsertPacketAtTailDpc(&pXmitSegInfo->SegWait, Packet);
Status = NDIS_STATUS_PENDING;
}
}
else
{
//
// Are there any packets to process?
//
if (PACKET_QUEUE_EMPTY(&pXmitSegInfo->SegWait))
{
// No, the queue is empty.
NdisReleaseSpinLock(&pXmitSegInfo->lock);
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("<==tbAtm155ProcessSegmentQueue(NDIS_STATUS_SUCCESS)\n"));
return(NDIS_STATUS_SUCCESS);
}
}
//
// Process the segmentation wait queue.
//
while(!PACKET_QUEUE_EMPTY(&pXmitSegInfo->SegWait))
{
//
// Determine if we have the segmentation resources necessary
// to process the packet.
//
Reserved = PACKET_RESERVED_FROM_PACKET(pXmitSegInfo->SegWait.Head);
if (pXmitDmaQ->RemainingTransmitSlots < Reserved->PhysicalBufferCount)
{
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_ERR, ("Not enough resources.\n"));
break;
}
if ((AAL_TYPE_AAL5 == Reserved->pVc->AALType) &&
(pXmitSegInfo->BeOrBeingUsedPadTrailerBufs >= TBATM155_MAX_PADTRAILER_BUFFERS))
{
//
// All of padtrailerbuffer have been reserved.
// Don't dequeue this packet from the Segwait queue.
//
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("no PadTrailerBuffers.\n"));
break;
}
//
// We have enough resources, remove the packet from the waiting
// queue and note the resources that it will need.
//
dbgLogSendPacket(Reserved->pVc->DebugInfo, Packet, 1, 0, 'wsQD');
RemovePacketFromHead(&pXmitSegInfo->SegWait, &tmpPacket);
NdisReleaseSpinLock(&pXmitSegInfo->lock);
dbgLogSendPacket(Reserved->pVc->DebugInfo, tmpPacket, 0, 0, 'qwdp');
tbAtm155ProcessTransmitDmaWaitQueue(
pXmitSegInfo->Adapter,
tmpPacket,
FALSE);
dbgLogSendPacket(Reserved->pVc->DebugInfo, tmpPacket, 0, 0, 'QWDP');
NdisAcquireSpinLock(&pXmitSegInfo->lock);
}
NdisReleaseSpinLock(&pXmitSegInfo->lock);
return(Status);
}
VOID
tbAtm155QueuePacketsToDmaWaitQueue(
IN PXMIT_SEG_INFO pXmitSegInfo
)
/*++
Routine Description:
This routine will determine if there are enough resources to transmit
the waiting queue of this VC.
If there are enough resources, packets are moved from SegWait queue
and insert to DmaWait queue to wait to be transmitted later.
This routine only queues waiting packets to DmaWait queue.
Arguments:
pXmitSegInfo - Pointer to the segmentation information to process
packets for.
Return Value:
--*/
{
PSAR_INFO pSar = pXmitSegInfo->Adapter->HardwareInfo->SarInfo;
PXMIT_DMA_QUEUE pXmitDmaQ = &pSar->XmitDmaQ;
PPACKET_RESERVED Reserved;
PNDIS_PACKET tmpPacket;
ULONG CurrentRemainingTxSlots;
NdisAcquireSpinLock(&pXmitSegInfo->lock);
CurrentRemainingTxSlots = pSar->XmitDmaQ.RemainingTransmitSlots;
//
// Process the segmentation wait queue.
//
while (!PACKET_QUEUE_EMPTY(&pXmitSegInfo->SegWait))
{
//
// Determine if we have the segmentation resources necessary
// to process the packet.
//
Reserved = PACKET_RESERVED_FROM_PACKET(pXmitSegInfo->SegWait.Head);
if (CurrentRemainingTxSlots < (ULONG)Reserved->PhysicalBufferCount)
{
// we don't have enough resources to process the packet.
break;
}
dbgLogSendPacket(Reserved->pVc->DebugInfo, tmpPacket, 0, 0, 'qptd');
//
// Are there available FreePadTrailerBuffers for padding & trailer?
//
if (pXmitSegInfo->BeOrBeingUsedPadTrailerBufs >= TBATM155_MAX_PADTRAILER_BUFFERS)
{
//
// Too bad, there is no resources available for this Vc.
//
break;
}
//
// Remove from SegWait queue.
//
RemovePacketFromHead(&pXmitSegInfo->SegWait, &tmpPacket);
//
// Insert into DmaWait queue to be transmitted.
//
InsertPacketAtTail(&pXmitDmaQ->DmaWait, tmpPacket);
CurrentRemainingTxSlots -= (ULONG)Reserved->PhysicalBufferCount;
pXmitSegInfo->BeOrBeingUsedPadTrailerBufs++;
dbgLogSendPacket(Reserved->pVc->DebugInfo, tmpPacket, 0, 0, 'qptd');
} // end of while loop
NdisReleaseSpinLock(&pXmitSegInfo->lock);
}
VOID
tbAtm155TxInterruptOnCompletion(
IN PADAPTER_BLOCK pAdapter
)
/*++
Routine Description:
This routine will process the Transmit Interrupt On Completion
for the different transmit buffers. This interrupt will be generated
when a packet has been sent out from a Tx Active Slot list of a VC.
Arguments:
pAdapter - Pointer to the adapter block.
Return Value:
None.
--*/
{
PHARDWARE_INFO pHwInfo = pAdapter->HardwareInfo;
PSAR_INFO pSar = pHwInfo->SarInfo;
PXMIT_DMA_QUEUE pXmitDmaQ = &pSar->XmitDmaQ;
PPACKET_RESERVED Reserved;
PNDIS_PACKET Packet;
PVC_BLOCK pVc;
PTX_REPORT_QUEUE pTxReportQ = &pAdapter->TxReportQueue;
TX_REPORT_PTR TxReportPtrReg;
ULONG CurrentTxReportPtrPa;
UINT CurrentTxReportQIdx;
UINT i;
PTX_REPORT_QUEUE_ENTRY TxReportQueue;
ULONG Vci;
PXMIT_SEG_INFO pXmitSegInfo;
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("==>TbAtm155TxInterruptOnCompletion\n"));
NdisDprAcquireSpinLock(&pXmitDmaQ->lock);
TBATM155_READ_PORT(
&pHwInfo->TbAtm155_SAR->Tx_Report_Ptr,
&TxReportPtrReg.reg);
//
// Got the position of 155 PCI SAR's internal Tx report queue.
// This pointer indicates the address in host memory to whcih 155 SAR
// will write the next Tx report. So we always move the pointer
// (or index) to the previous entry to make sure the entry in the
// report queue is valid.
//
CurrentTxReportPtrPa = TxReportPtrReg.reg & ~0x3;
//
// Calcuate the index of Tx Report Queue which is pointed by controller.
// Save the index to database for XmitDmaQ.
// Handling Rules:
// 1. Only handle up to the entry before this one.
// 2. Each entry of report queue indicates of a transmitted packet.
//
CurrentTxReportQIdx =
(CurrentTxReportPtrPa -
NdisGetPhysicalAddressLow(pTxReportQ->TxReportQptrPa)) /
sizeof(TX_REPORT_QUEUE_ENTRY);
//
// Get the index handled last time.
//
TxReportQueue = (PTX_REPORT_QUEUE_ENTRY)pTxReportQ->TxReportQptrVa;
DBGPRINT(DBG_COMP_TXIOC, DBG_LEVEL_ERR,
("TxIOC CurTxRQIdx(%x), PrevTxRQIdx(%x)\n",
CurrentTxReportQIdx, pXmitDmaQ->PrevTxReportQIndex));
for (i = pXmitDmaQ->PrevTxReportQIndex;
i != CurrentTxReportQIdx;
i = (i == pHwInfo->MaxIdxOfTxReportQ)? 0 : ++i)
{
//
// Get the VC of the packet been sent out.
//
Vci = (ULONG) TxReportQueue[i].TxReportQDWord.VC;
//
// There are more packets have been sent out.
// Let's get information from the queue.
//
pVc = tbAtm155UnHashVc(pAdapter, Vci);
if ((NULL == pVc) || (NULL == pVc->XmitSegInfo))
{
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_ERR,
("There is no VC activated for: %u\n", Vci));
continue;
}
if (!VC_TEST_FLAG(pVc, fVC_ACTIVE) && !VC_TEST_FLAG(pVc, fVC_DEACTIVATING))
{
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_ERR,
("The VC is activated for: %u\n", Vci));
continue;
}
pXmitSegInfo = pVc->XmitSegInfo;
NdisDprAcquireSpinLock(&pXmitSegInfo->lock);
//
// Are there any packets to complete?
//
if (PACKET_QUEUE_EMPTY(&pXmitSegInfo->DmaCompleting))
{
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("There is no any packets to complete of VC: %lx\n", Vci));
NdisDprReleaseSpinLock(&pXmitSegInfo->lock);
continue;
}
//
// Get VC information from VcHashTable based on the VC reported
//
Reserved = PACKET_RESERVED_FROM_PACKET(pVc->XmitSegInfo->DmaCompleting.Head);
//
// A packet has been sent out.
//
RemovePacketFromHead(&pXmitSegInfo->DmaCompleting, &Packet);
if (Reserved->PadTrailerBufIndexInUse != 0x0FF)
{
pXmitSegInfo->FreePadTrailerBuffers++;
//
// Update the number of padtrailerbuffers to allow queuing
// more packets of this VC to the "dmawait" queue later.
//
pXmitSegInfo->BeOrBeingUsedPadTrailerBufs--;
}
NdisDprReleaseSpinLock(&pXmitSegInfo->lock);
pXmitDmaQ->RemainingTransmitSlots += (ULONG) Reserved->PhysicalBufferCount;
dbgLogSendPacket(
pVc->DebugInfo,
Packet,
0,
0,
'pmoc');
//
// Complete the packet back to the protocol.
// Since we always return STATUS_PENDING to the protocol's
// send request, this function need to be called here.
//
//
// Release spinlock before calling NdisMCoSendComplete to avoid a
// deadlock problem. After NdisMCoSendComplete is finished,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -