📄 send.c
字号:
// routine returns, this packet will be ready to send through the
// adapter, and onto the medium.
//
// Arguments:
// Adapter - ptr to Adapter object instance
// Packet - A pointer to a descriptor for the packet that is to be
// transmitted.
// SwTcb - Pointer to a software structure that represents a hardware TCB.
//
// Returns:
// TRUE If we were able to acquire the necessary TBD's or Coalesce buffer
// for the packet in we are attempting to prepare for transmission.
// FALSE If we needed a coalesce buffer, and we didn't have any available.
//-----------------------------------------------------------------------------
BOOLEAN
PrepareForTransmit(PD100_ADAPTER Adapter,
PNDIS_PACKET Packet,
PD100SwTcb SwTcb)
{
PNDIS_BUFFER CurrBuff;
UINT i;
UINT BytesCopied;
PCOALESCE Coalesce;
PTBD_STRUC LastTbd = (PTBD_STRUC) 0;
PNDIS_PHYSICAL_ADDRESS_UNIT p;
UINT ArrayIndex = 0;
// Debug Code
DEBUGFUNC("PrepareForTransmit");
TRACE2(Adapter, ("\n"));
TRACE3(Adapter, ("Preparing to transmit SwTcb %08x Packet %08x\n", SwTcb, Packet));
ASSERT(SwTcb);
// DEBUGCHAR(Adapter,'U');
// Assign the packet
SwTcb->Packet = Packet;
// Init some variables in the SwTcb
SwTcb->MapsUsed = 0;
SwTcb->NumPhysDesc = 0;
SwTcb->TbdsUsed = 0;
SwTcb->Coalesce = (PCOALESCE) 0;
SwTcb->CoalesceBufferLen = 0;
// Get a virtual buffer count and packet length.
NdisQueryPacket(SwTcb->Packet,
&SwTcb->NumPhysDesc,
&SwTcb->BufferCount,
&SwTcb->FirstBuffer,
&SwTcb->PacketLength);
ASSERT(SwTcb->FirstBuffer);
ASSERT(SwTcb->BufferCount);
ASSERT(SwTcb->NumPhysDesc);
ASSERT(SwTcb->PacketLength);
ASSERT(SwTcb->PacketLength <= 1514);
ASSERT(SwTcb->BufferCount <= 512);
ASSERT(SwTcb->NumPhysDesc <= 512);
// if the packet is not a valid length, then error out
if ((!SwTcb->PacketLength) || (SwTcb->PacketLength > MAXIMUM_ETHERNET_PACKET_SIZE))
return FALSE;
// start with the first buffer
CurrBuff = SwTcb->FirstBuffer;
#if DBG
SwTcb->BufferCountCheck = 0;
SwTcb->NumPhysDescCheck = SwTcb->NumPhysDesc;
#endif
// If the packet is less than minimum size, then we'll just copy the packet
// into the data portion of the TCB. This means that we won't be acquiring
// any TBD's. We also won't need to get a coalesce buffer.
if (SwTcb->PacketLength <= MINIMUM_ETHERNET_PACKET_SIZE)
{
TRACE2(Adapter, ("short packet\n"));
CurrBuff = 0;
}
// If there are too many physical mappings, try to get a coalesce buffer.
// We do this because its actually faster for us to copy many fragments
// into a big buffer and give that big buffer to the adapter, than to have
// the hardware fetch numerous small fragments (this often leads to
// underruns). The NDIS tester often asks us to send packets that
// have more than 30 physical components. This method also saves TBD resources.
else if (SwTcb->NumPhysDesc > Adapter->NumTbdPerTcb)
{
// Debug Code
ASSERT(!SwTcb->Coalesce);
TRACE2(Adapter,
("Failed-> Physical descriptors %d > num Tbd per Tcb %d\n",
SwTcb->NumPhysDesc, Adapter->NumTbdPerTcb));
// Try to get the coalesce buffer
if (!AcquireCoalesceBuffer(Adapter, SwTcb))
return (FALSE);
CurrBuff = 0;
}
// Clear NumPhysDesc.
SwTcb->NumPhysDesc = 0;
// If we are not coalescing, and the frame is not short, then for each
// virtual buffer, get the physical components. We'll need these physical
// attributes so that we can instruct the adapter to copy the fragments
// across the bus and into the adapter's internal FIFO.
for (i = 0; CurrBuff; i++)
{
UINT ArraySize = 0;
// If the mapping is successful, and there are not too many, then this
// is where they go.
PNDIS_PHYSICAL_ADDRESS_UNIT pUnit = &SwTcb->PhysDesc[SwTcb->NumPhysDesc];
// Decompose the virtual buffer into one or more physical buffers.
NdisMStartBufferPhysicalMapping(Adapter->D100AdapterHandle,
CurrBuff,
Adapter->NextFreeMapReg,
TRUE,
Adapter->pUnits,
&ArraySize);
#if DBG
if (ArraySize == 0)
{
// TRACESTR(Adapter, ("ZERO Array size -- Buffer %d ArraySize %d\n", i, ArraySize));
ASSERT(CurrBuff);
}
#endif
// Adjust free map register variables. Since map registers are such
// a precious system resource we dynamically use them when necessary,
// rather than allocate so many map registers per TCB.
Adapter->NextFreeMapReg++;
// check for wrap condition
if (Adapter->NextFreeMapReg == Adapter->NumMapRegisters)
Adapter->NextFreeMapReg = 0;
// Debug code
TRACE3(Adapter, ("Buffer %d ArraySize %d\n", i, ArraySize));
// Mark the number of valid buffer mappings and copy
// the new mappings into the transmit descriptor.
SwTcb->MapsUsed++;
NdisMoveMemory((PVOID) pUnit,
(PVOID) Adapter->pUnits,
ArraySize * sizeof(NDIS_PHYSICAL_ADDRESS_UNIT));
SwTcb->NumPhysDesc += ArraySize;
// Flush the current buffer because it could be cached
NdisFlushBuffer(CurrBuff, TRUE);
// point to the next buffer
NdisGetNextBuffer(CurrBuff, &CurrBuff);
#if DBG
SwTcb->BufferCountCheck++;
ASSERT(SwTcb->BufferCountCheck <= SwTcb->BufferCount);
#endif
}
// ------------------------------- NOTE: ----------------------------------
// At this point, we should have either locked down each physical fragment
// through the use of map registers, or we should have a coalesce buffer,
// or we should have a short packet that we'll copy into the TCB data area.
#if DBG
// Check to make sure that our buffer count was valid
if (SwTcb->MapsUsed)
{
ASSERT(SwTcb->BufferCountCheck == SwTcb->BufferCount);
}
#endif
// Check for coalesce buffer
if (SwTcb->Coalesce)
{
ASSERT(SwTcb->CoalesceBufferLen);
ASSERT(!SwTcb->NumPhysDesc);
ASSERT(!SwTcb->MapsUsed);
Coalesce = SwTcb->Coalesce;
ASSERT(Coalesce->OwningTcb == (PVOID) SwTcb);
// Copy the packet into the coalesce buffer
ASSERT(SwTcb->PacketLength <= MAXIMUM_ETHERNET_PACKET_SIZE);
// Copy all of the packet data to our coalesce buffer
D100CopyFromPacketToBuffer(Adapter,
SwTcb->Packet,
SwTcb->PacketLength,
(PCHAR) Coalesce->CoalesceBufferPtr,
SwTcb->FirstBuffer,
&BytesCopied);
ASSERT(BytesCopied == SwTcb->PacketLength);
SwTcb->TbdsUsed = 1;
}
// Check if we a doing a fragmented send with TBDs
else if (SwTcb->NumPhysDesc)
{
SwTcb->TbdsUsed = SwTcb->NumPhysDesc;
ASSERT(!SwTcb->CoalesceBufferLen);
ASSERT(SwTcb->MapsUsed);
}
// check if we are using the TCB's data area with no TBDs. This should
// only happen on frames that are <= the minimum ethernet length
else if ((!SwTcb->NumPhysDesc) && (!SwTcb->Coalesce))
{
ASSERT(!SwTcb->CoalesceBufferLen);
ASSERT(!SwTcb->NumPhysDesc);
ASSERT(!SwTcb->MapsUsed);
ASSERT(SwTcb->PacketLength <= MINIMUM_ETHERNET_PACKET_SIZE);
// Copy the packet into the immediate data portion of the TCB.
D100CopyFromPacketToBuffer(Adapter,
SwTcb->Packet,
SwTcb->PacketLength,
(PCHAR) &SwTcb->Tcb->TxCbData,
SwTcb->FirstBuffer,
&BytesCopied);
ASSERT(BytesCopied == SwTcb->PacketLength);
// // Check for below minimum length packets.
// if (SwTcb->PacketLength < MINIMUM_ETHERNET_PACKET_SIZE)
// {
// NdisZeroMemory(
// ((PCHAR) &SwTcb->Tcb->TxCbData) + SwTcb->PacketLength,
// MINIMUM_ETHERNET_PACKET_SIZE - (SwTcb->PacketLength));
// }
}
// ------------------------------- NOTE: ----------------------------------
// At this point, any copying of of data into a coalesce buffer or into the
// the TCB itself should be complete. Now the last thing left to do in
// this routine is to setup the TBD array if TBDs are being used for this
// particular transmit frame.
for (i = 0; i < SwTcb->TbdsUsed; i++)
{
PTBD_STRUC Tbd;
ULONG OriginalBufferAddress, OriginalBufferCount;
// Setup pointer to the particular TBD
Tbd = SwTcb->FirstTbd + i;
TRACE3(Adapter, ("Setting TBD num %d at virtual addr %x\n", i, Tbd));
// Assign the physical address of the transmit buffer, and the
// TBD count to the TCB.
if (SwTcb->Coalesce)
{
Tbd->TbdBufferAddress = Coalesce->CoalesceBufferPhys;
Tbd->TbdCount = (ULONG) SwTcb->CoalesceBufferLen;
}
else
{
p = &SwTcb->PhysDesc[ArrayIndex];
Tbd->TbdBufferAddress = NdisGetPhysicalAddressLow(p->PhysicalAddress);
Tbd->TbdCount = (ULONG) p->Length;
ASSERT(p->Length <= 0x00003fff);
TRACE3(Adapter, ("Buff %d len %d phys %08x\n", ArrayIndex, p->Length, Tbd->TbdBufferAddress));
}
ArrayIndex++;
}
// DEBUGCHAR(Adapter,'u');
return (TRUE);
}
//-----------------------------------------------------------------------------
// Procedure: AcquireCoalesceBuffer
//
// Description: This routine will attempt to acquire a coalesce buffer, if
// there were too many physical vectors for a single packet.
// The coalesce buffer will allow us to double buffer using a
// only a single destination buffer.
//
// Arguments:
// Adapter - ptr to Adapter object instance
// SwTcb - Pointer to a software structure that represents a hardware TCB.
//
// Returns:
// TRUE If we were able to acquire the necessary Coalesce buffer.
// FALSE If we were not able to get a coalesce buffer.
//-----------------------------------------------------------------------------
BOOLEAN
AcquireCoalesceBuffer(PD100_ADAPTER Adapter,
PD100SwTcb SwTcb
)
{
DEBUGFUNC("AcquireCoalesceBuffer");
TRACE2(Adapter, ("\n"));
// Debug code.
ASSERT(SwTcb);
ASSERT(!SwTcb->Coalesce);
ASSERT(!SwTcb->CoalesceBufferLen);
// ASSERT(!SwTcb->MapsUsed);
// Check preconditions for use. Return FALSE if there are none
// available.
if (QueueEmpty(&Adapter->CoalesceBufferList))
{
TRACE2(Adapter, ("No free coalesce buffers!!!\n"));
return (FALSE);
}
// Allocate the coalesce buffer from the list. The SwTcb will now
// own it until it's returned to the list.
SwTcb->Coalesce = (PCOALESCE) QueuePopHead(&Adapter->CoalesceBufferList);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -