📄 send.c
字号:
/*++
Copyright (c) 2000 Microsoft Corporation. All rights reserved.
File: send.c
Developed for Toshiba by Elisa Research Inc., CA
http://www.elisaresearch.com
(510) 770-4920
Abstract:
Author:
A. Wang
Environment:
Kernel mode
Revision History:
09/23/96 kyleb Fix map register freeing bug
Fix Deactivate VC complete bug.
01/07/97 awang Initial of Toshiba ATM 155 Device Driver.
02/16/99 hhan Use synchronize mode to allocate xmit buffer.
03/03/97 hhan Added in 'ScatterGetherDMA'.
--*/
#include "precomp.h"
#pragma hdrstop
#define MODULE_NUMBER MODULE_SEND
VOID
tbAtm155TransmitPacket(
IN PVC_BLOCK pVc,
IN PNDIS_PACKET Packet
)
/*++
Routine Description:
This routine will set up the DMA operation.
Assume: FreePadTrailerBuffers > 0
- There are two ways to send a packet
1. post the tx buffer(s) from NDIS directly to SAR.
2. if Remaining slot are running low, copy tx data in buffer(s) to
pre-allocated tx buffer and then post the pre-allocate buffer
to SAR.
- After post Tx data of the packet, ALWAYS post a PadTrailerBuffers
for AAL5 packets.
Arguments:
Return Value:
--*/
{
PADAPTER_BLOCK pAdapter = pVc->Adapter;
PHARDWARE_INFO pHwInfo = pVc->HwInfo;
PTBATM155_SAR TbAtm155Sar = pHwInfo->TbAtm155_SAR;
PSAR_INFO pSar = pHwInfo->SarInfo;
PXMIT_SEG_INFO pXmitSegInfo = pVc->XmitSegInfo;
PXMIT_DMA_QUEUE pXmitDmaQ = &pSar->XmitDmaQ;
PPACKET_RESERVED Reserved = PACKET_RESERVED_FROM_PACKET(Packet);
UINT PacketLength;
UINT c;
PMEDIA_SPECIFIC_INFORMATION pMediaInfo;
ULONG SizeMediaInfo;
PATM_AAL_OOB_INFO pAtmOob;
AAL5_PDU_TRAILER Trailer;
ULONG Padding = 0;
PSCATTER_GATHER_LIST psgl;
TX_PENDING_SLOTS_CTL TxPendingSlotCtrlReg;
ULONG TxSlotNum = 0;
PALLOCATION_MAP pPadTrailerBuffer;
dbgLogSendPacket(Reserved->pVc->DebugInfo, Packet, 0, 0, ' cdq');
//
// Place the packet on the completing queue.
//
InsertPacketAtTail(&pXmitSegInfo->DmaCompleting, Packet);
//
// Clear the trailer first.
//
ZERO_MEMORY(&Trailer, sizeof(AAL5_PDU_TRAILER));
//
// Set defaults for the pdu trailer
//
Trailer.UserToUserIndication = 0;
Trailer.CommonPartIndicator = 0;
//
// Do we have any oob data in the packet?
//
NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(Packet, &pMediaInfo, &SizeMediaInfo);
//
// If there is OOB data then it's already been verified.
//
if (0 != SizeMediaInfo)
{
pAtmOob = (PATM_AAL_OOB_INFO)pMediaInfo->ClassInformation;
//
// The contents depends upon the AAL type.
//
if (AAL_TYPE_AAL5 == pAtmOob->AalType)
{
Trailer.UserToUserIndication = pAtmOob->ATM_AAL5_INFO.UserToUserIndication;
Trailer.CommonPartIndicator = pAtmOob->ATM_AAL5_INFO.CommonPartIndicator;
}
}
psgl = NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ScatterGatherListPacketInfo);
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("TbAtm155TransmitPacket: Pkt %x, psgl %x\n", Packet, psgl));
//
// Copy the initial control register value of Tx_Pending_Slots
//
TxPendingSlotCtrlReg.reg = pXmitSegInfo->InitXmitSlotDesc.reg;
for (c = 0; c < psgl->NumberOfElements; c++)
{
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("TbAtm155TransmitPacket: Pkt %x, elem %d, Length %d\n",
Packet, c, psgl->Elements[c].Length));
//
// Initialize the descriptor with the physical buffer info.
// and write to Tx_Pending_slots registers of 155 PCI SAR
//
TxPendingSlotCtrlReg.Slot_Size = psgl->Elements[c].Length;
TBATM155_WRITE_PORT(
&TbAtm155Sar->Tx_Pending_Slots[TxSlotNum].Cntrl,
TxPendingSlotCtrlReg.reg);
TBATM155_WRITE_PORT(
&TbAtm155Sar->Tx_Pending_Slots[TxSlotNum].Base_Addr,
NdisGetPhysicalAddressLow(psgl->Elements[c].Address));
//
// Move to next slot registers for the next posting.
//
TxSlotNum = (TxSlotNum + 1) % MAX_SLOTS_NUMBER;
} // end of FOR
//
// Update the total posted Tx pending slots.
//
Reserved->PhysicalBufferCount = (UCHAR)psgl->NumberOfElements;
//
// Update the total remaining Tx free slots.
//
pXmitDmaQ->RemainingTransmitSlots -= psgl->NumberOfElements;
//
// If this was an AAL5 packet then we need to
// copy out any padding and the AAL5 pdu trailer.
//
if (AAL_TYPE_AAL5 == pVc->AALType)
{
//
// Get the first packet buffer and the number of physical
// segments that comprise the packet.
//
NdisQueryPacket(Packet, NULL, NULL, NULL, &PacketLength);
//
// Build the AAL5 trailer information.
//
Trailer.Length = TBATM155_SWAP_USHORT((USHORT)PacketLength);
//
// Determine the amount of padding bytes.
//
pPadTrailerBuffer = &pXmitSegInfo->PadTrailerBuffers[pXmitSegInfo->PadTrailerBufferIndex];
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO, ("Va=0x%lX\n", pPadTrailerBuffer->Va));
//
// copy Trailer to the buffer.
//
Padding = (ULONG)Reserved->PaddingBytesNeeded;
NdisMoveMemory(
(PUCHAR)pPadTrailerBuffer->Va + Padding,
(PVOID)&Trailer,
(ULONG)sizeof(AAL5_PDU_TRAILER));
//
// Let's to write the last fragment out
//
// Initialize the descriptor with the physical buffer info.
// and write to Tx_Pending_slots registers of 155 PCI SAR
//
TxPendingSlotCtrlReg.Slot_Size = Padding + sizeof(AAL5_PDU_TRAILER);
TxPendingSlotCtrlReg.EOP = 1;
TBATM155_WRITE_PORT(
&TbAtm155Sar->Tx_Pending_Slots[TxSlotNum].Cntrl,
TxPendingSlotCtrlReg.reg);
TBATM155_WRITE_PORT(
&TbAtm155Sar->Tx_Pending_Slots[TxSlotNum].Base_Addr,
pPadTrailerBuffer->Pa);
//
// Flush it out.
//
NdisFlushBuffer(
pPadTrailerBuffer->FlushBuffer,
TRUE
);
Reserved->PadTrailerBufIndexInUse = pXmitSegInfo->PadTrailerBufferIndex;
pXmitSegInfo->FreePadTrailerBuffers--;
pXmitSegInfo->PadTrailerBufferIndex++;
if(pXmitSegInfo->PadTrailerBufferIndex == TBATM155_MAX_PADTRAILER_BUFFERS)
{
pXmitSegInfo->PadTrailerBufferIndex = 0;
}
//
// Update the total posted Tx pending slots.
//
Reserved->PhysicalBufferCount++;
//
// Update the total remaining Tx free slots.
//
pXmitDmaQ->RemainingTransmitSlots--;
}
#if TB_CHK4HANG
ADAPTER_SET_FLAG(pAdapter, fADAPTER_EXPECT_TXIOC);
#endif // end of TB_CHK4HANG
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
("<==tbAtm155TransmitPacket\n"));
}
NDIS_STATUS
tbAtm155ProcessTransmitDmaWaitQueue(
IN PADAPTER_BLOCK pAdapter,
IN PNDIS_PACKET Packet,
IN BOOLEAN fLimitedNoPkts
)
/*++
Routine Description:
This routine will either queue a packet to the transmit DMA queue or
DMA the packet.
Arguments:
pAdapter - Pointer to the ADAPTER_BLOCK
Packet - if equal to NULL, this routine is called in
the interrupt service routine
tbAtm155TxInterruptOnCompletion().
Otherwise, this routine is called from foreground.
Return Value:
NDIS_STATUS_SUCCESS if the packet was successfully sent to the
transmit DMA engine.
NDIS_STATUS_PENDING if it was queued waiting for DMA resources.
--*/
{
PSAR_INFO pSar = pAdapter->HardwareInfo->SarInfo;
PXMIT_DMA_QUEUE pXmitDmaQ = &pSar->XmitDmaQ;
PNDIS_PACKET tmpPacket;
PPACKET_RESERVED Reserved;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PXMIT_SEG_INFO pXmitSegInfo;
PVC_BLOCK pVc;
PHARDWARE_INFO pHwInfo = pAdapter->HardwareInfo;
//
// If a packet was not passed in to transmit then we need to
// grab them off of the pending queue.
//
NdisAcquireSpinLock(&pXmitDmaQ->lock);
if (ARGUMENT_PRESENT(Packet))
{
Reserved = PACKET_RESERVED_FROM_PACKET(Packet);
pVc = Reserved->pVc;
pXmitSegInfo = pVc->XmitSegInfo;
if (AAL_TYPE_AAL5 == pVc->AALType)
{
NdisAcquireSpinLock(&pXmitSegInfo->lock);
pXmitSegInfo->BeOrBeingUsedPadTrailerBufs++;
NdisReleaseSpinLock(&pXmitSegInfo->lock);
}
//
// Are there transmit DMA resources available?
//
if (pXmitDmaQ->RemainingTransmitSlots < Reserved->PhysicalBufferCount)
{
//
// Too bad, there is no resources available.
// Queue to DmaWait list to handle later.
//
dbgLogSendPacket(pVc->DebugInfo, Packet, 1, 0, ' wdq');
InsertPacketAtTail(&pXmitDmaQ->DmaWait, Packet);
NdisReleaseSpinLock(&pXmitDmaQ->lock);
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_ERR,
("<==tbAtm155ProcessTransmitDmaWaitQueue(NDIS_STATUS_PENDING)\n"));
return(NDIS_STATUS_PENDING);
}
//
// Are there any other packets waiting for the DMA engine?
//
if (!PACKET_QUEUE_EMPTY(&pXmitDmaQ->DmaWait))
{
//
// There are other packets waiting for the available DMA
// resources so this guy goes to the end of the list.
//
dbgLogSendPacket(pVc->DebugInfo, Packet, 2, 0, ' wdq');
InsertPacketAtTail(&pXmitDmaQ->DmaWait, Packet);
Status = NDIS_STATUS_PENDING;
}
else
{
//
// Setup the packet for DMA if there are available
// free PadTrailerBuffers.
//
tbAtm155TransmitPacket(Reserved->pVc, Packet);
}
}
//
// Loop through the packets that are waiting for dma resources.
//
while (!PACKET_QUEUE_EMPTY(&pXmitDmaQ->DmaWait))
{
//
// Are there enough resources to process the
// packet?
//
Reserved = PACKET_RESERVED_FROM_PACKET(pXmitDmaQ->DmaWait.Head);
pXmitSegInfo = Reserved->pVc->XmitSegInfo;
if (pXmitSegInfo->FreePadTrailerBuffers == 0)
{
//
// Bad!! We should never get here.
//
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_FATAL,
("ProcessTxDmaWaitQueue: BAD!!(UsedPTB=%u, VC=%lx)\n",
pXmitSegInfo->BeOrBeingUsedPadTrailerBufs, Reserved->pVc->VpiVci.Vci));
break; // no chance, get out.
}
if (pXmitDmaQ->RemainingTransmitSlots < Reserved->PhysicalBufferCount)
{
break; // no chance, get out.
}
dbgLogSendPacket(Reserved->pVc->DebugInfo, Packet, 0, 0, 'WDQD');
RemovePacketFromHead(&pXmitDmaQ->DmaWait, &tmpPacket);
//
// Transmit the packet.
//
tbAtm155TransmitPacket(Reserved->pVc, tmpPacket);
if (TRUE == fLimitedNoPkts)
{
TBATM155_WRITE_PORT(
&pHwInfo->TbAtm155_SAR->Intr_Status,
0);
TBATM155_WRITE_PORT(
&pHwInfo->TbAtm155_SAR->Intr_Status,
0);
}
}
NdisReleaseSpinLock(&pXmitDmaQ->lock);
return(Status);
}
NDIS_STATUS
tbAtm155ProcessSegmentQueue(
IN PXMIT_SEG_INFO pXmitSegInfo,
IN PNDIS_PACKET Packet
)
/*++
Routine Description:
This routine will do one of two things depending on whether or not a valid
Packet was passed in. If a packet is passed in then we will determine if
there are enough resources for segmentation of this packet. If not then
we will process the queue of packets that are waiting for segmentation
resources.
Arguments:
pXmitSegInfo - Pointer to the segmentation information to process
packets for.
Packet - Pointer to the packet to acquire segmentation resources
for or NULL if we are to process the pending queue.
Return Value:
NDIS_STATUS_SUCCESS if the packet was successfully sent to the DMA engine.
NDIS_STATUS_PENDING if the packet was queued some where due to resource
constraints.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -