📄 e100bexadap.cpp
字号:
BOOLEAN E100bexAdapter::PrepareForTransmit(KNdisPacket Packet, PD100SwTcb SwTcb)
{
UINT BytesCopied;
PCOALESCE Coalesce;
PTBD_STRUC LastTbd = (PTBD_STRUC) 0;
PNDIS_PHYSICAL_ADDRESS_UNIT p;
UINT ArrayIndex = 0;
TRACE3(("Preparing to transmit SwTcb %08x Packet %08x\n", SwTcb, Packet))
ASSERT(SwTcb);
// 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.
Packet.Query(
&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
KNdisBuffer 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(("short packet\n"))
CurrBuff = NULL;
}
// 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 > m_NumTbdPerTcb)
{
// Debug Code
ASSERT(!SwTcb->Coalesce);
TRACE2(("Failed-> Physical descriptors %d > num Tbd per Tcb %d\n",
SwTcb->NumPhysDesc, m_NumTbdPerTcb));
// Try to get the coalesce buffer
if (!AcquireCoalesceBuffer(SwTcb))
return (FALSE);
CurrBuff = NULL;
}
// 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 (UINT i = 0; CurrBuff.IsValid(); 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(*this,
CurrBuff,
m_NextFreeMapReg,
TRUE,
m_pUnits,
&ArraySize);
#if DBG
if (ArraySize == 0)
{
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.
m_NextFreeMapReg++;
// check for wrap condition
if (m_NextFreeMapReg == m_NumMapRegisters)
m_NextFreeMapReg = 0;
// Debug code
TRACE3(("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) m_pUnits,
ArraySize * sizeof(NDIS_PHYSICAL_ADDRESS_UNIT));
SwTcb->NumPhysDesc += ArraySize;
// Flush the current buffer because it could be cached
CurrBuff.Flush();
// point to the next buffer
CurrBuff = CurrBuff.GetNext();
#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
CopyFromPacketToBuffer(
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.
CopyFromPacketToBuffer(
SwTcb->Packet,
SwTcb->PacketLength,
(PCHAR) &SwTcb->Tcb->TxCbData,
SwTcb->FirstBuffer,
&BytesCopied);
ASSERT(BytesCopied == 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;
// Setup pointer to the particular TBD
Tbd = SwTcb->FirstTbd + i;
TRACE3(("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(("Buff %d len %d phys %08x\n", ArrayIndex, p->Length, Tbd->TbdBufferAddress))
}
ArrayIndex++;
}
return (TRUE);
}
//-----------------------------------------------------------------------------
// Procedure: E100bexAdapter::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:
// 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 E100bexAdapter::AcquireCoalesceBuffer(PD100SwTcb SwTcb)
{
// 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 (m_CoalesceBufferList.IsEmpty())
{
TRACE2(("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 = m_CoalesceBufferList.RemoveHead();
SwTcb->Coalesce->OwningTcb = (PVOID) SwTcb;
SwTcb->CoalesceBufferLen = SwTcb->PacketLength;
TRACE2(("Acquired CoalesceBuffer %08x \n", SwTcb->Coalesce))
return (TRUE);
}
VOID E100bexAdapter::CopyFromPacketToBuffer(
KNdisPacket Packet,
UINT BytesToCopy,
PCHAR DestBuffer,
KNdisBuffer FirstBuffer,
PUINT BytesCopied)
{
PNDIS_BUFFER CurrentBuffer;
PVOID VirtualAddress;
UINT CurrentLength;
UINT AmountToMove;
*BytesCopied = 0;
if (!BytesToCopy)
return;
CurrentBuffer = FirstBuffer;
NdisQueryBuffer(
CurrentBuffer,
&VirtualAddress,
&CurrentLength);
while (BytesToCopy)
{
while (!CurrentLength)
{
NdisGetNextBuffer(
CurrentBuffer,
&CurrentBuffer);
// If we've reached the end of the packet. We return with what
// we've done so far (which must be shorter than requested).
if (!CurrentBuffer)
return;
NdisQueryBuffer(
CurrentBuffer,
&VirtualAddress,
&CurrentLength);
}
// Compute how much data to move from this fragment
if (CurrentLength > BytesToCopy)
AmountToMove = BytesToCopy;
else
AmountToMove = CurrentLength;
// Copy the data.
NdisMoveMemory(DestBuffer, VirtualAddress, AmountToMove);
// Update destination pointer
DestBuffer = (PCHAR) DestBuffer + AmountToMove;
// Update counters
*BytesCopied +=AmountToMove;
BytesToCopy -=AmountToMove;
CurrentLength = 0;
}
}
////////////////////////////////////////////////////////////////////
// E100bexAdapter::ReturnPacket
//
// This method is called when NDIS returns a packet previuosly
// indicated by IndicateReceive() back to the miniport
//
// Parameters:
// Packet
// Points to a packet descriptor specifying the packet
// IRQL:
// DISPATCH_LEVEL
// Return Mode:
// n/a
// NOTE:
// The packet returns to the "free list" in the Rx area.
// Reclaim() does the necessary reset of the chained buffer
// and OOB data if any.
VOID E100bexAdapter::ReturnPacket(IN PNDIS_PACKET Packet)
{
TRACE("E100bexAdapter::ReturnPacket() Entered Packet=%X\n", Packet);
// Reclaim the packet back into our receive area
// Note: Can't hold spin lock while calling this method
m_pRxArea->Reclaim(Packet);
}
////////////////////////////////////////////////////////////////////
// E100bexAdapter::CheckForHang
// Optional function that reports the state of the NIC or monitors
// the responsiveness of an underlying device driver.
// Parameters:
// none
// IRQL:
// IRQL DISPATCH_LEVEL
// Return Mode:
// Synchronous
// NOTE:
// By default, the NDIS library calls MiniportCheckForHang
// approximately every two seconds. If MiniportCheckForHang returns
// TRUE, NDIS then calls the driver's MiniportReset function.
BOOLEAN E100bexAdapter::CheckForHang(void)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -