mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1305 lines
29 KiB
1305 lines
29 KiB
/*++
|
|
|
|
Copyright (c) 1990-1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
send.c
|
|
|
|
Abstract:
|
|
|
|
This file contains the code for putting a packet through the
|
|
allocation for transmission.
|
|
|
|
This is a process of
|
|
|
|
1) Calculating the what would need to be done to the
|
|
packet so that the packet can be transmitted on the hardware.
|
|
|
|
2) Potentially allocating adapter buffers and copying user data
|
|
to those buffers so that the packet data is transmitted under
|
|
the hardware constraints.
|
|
|
|
3) Allocating enough hardware ring entries so that the packet
|
|
can be transmitted.
|
|
|
|
4) Relinquish those ring entries to the hardware.
|
|
|
|
Author:
|
|
|
|
Adam Barr (adamba) 16-Nov-1990
|
|
|
|
Environment:
|
|
|
|
Kernel Mode - Or whatever is the equivalent.
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
|
|
#include <ndis.h>
|
|
|
|
#include <sonichrd.h>
|
|
#include <sonicsft.h>
|
|
|
|
|
|
|
|
//
|
|
// This macro will poke the sonic hardware into noticing that
|
|
// there is a packet available for transmit.
|
|
//
|
|
|
|
#define START_TRANSMIT(_Adapter) \
|
|
SONIC_WRITE_PORT(_Adapter, SONIC_COMMAND, SONIC_CR_TRANSMIT_PACKETS)
|
|
|
|
|
|
STATIC
|
|
VOID
|
|
AssignPacketToDescriptor(
|
|
IN PSONIC_ADAPTER Adapter,
|
|
IN PNDIS_PACKET Packet,
|
|
IN UINT DescriptorIndex
|
|
);
|
|
|
|
STATIC
|
|
VOID
|
|
RelinquishPacket(
|
|
IN PSONIC_ADAPTER Adapter,
|
|
IN PNDIS_PACKET Packet,
|
|
IN UINT RingIndex
|
|
);
|
|
|
|
STATIC
|
|
VOID
|
|
CalculatePacketConstraints(
|
|
IN PSONIC_ADAPTER Adapter,
|
|
IN PNDIS_PACKET Packet
|
|
);
|
|
|
|
STATIC
|
|
BOOLEAN
|
|
ConstrainPacket(
|
|
IN PSONIC_ADAPTER Adapter,
|
|
IN PNDIS_PACKET Packet
|
|
);
|
|
|
|
|
|
#ifdef CHECK_DUP_SENDS
|
|
|
|
#define PACKET_LIST_SIZE 20
|
|
|
|
PNDIS_PACKET SonicPacketList[PACKET_LIST_SIZE];
|
|
UINT SonicPacketListSize = 0;
|
|
|
|
VOID
|
|
SonicAddPacketToList(
|
|
PSONIC_ADAPTER Adapter,
|
|
PNDIS_PACKET NewPacket
|
|
)
|
|
{
|
|
INT i;
|
|
|
|
for (i=0; i<SonicPacketListSize; i++) {
|
|
|
|
if (SonicPacketList[i] == NewPacket) {
|
|
|
|
DbgPrint("SONIC: dup send of %lx\n", NewPacket);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SonicPacketList[SonicPacketListSize] = NewPacket;
|
|
++SonicPacketListSize;
|
|
|
|
}
|
|
|
|
VOID
|
|
SonicRemovePacketFromList(
|
|
PSONIC_ADAPTER Adapter,
|
|
PNDIS_PACKET OldPacket
|
|
)
|
|
{
|
|
INT i;
|
|
|
|
for (i=0; i<SonicPacketListSize; i++) {
|
|
|
|
if (SonicPacketList[i] == OldPacket) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (i == SonicPacketListSize) {
|
|
|
|
DbgPrint("SONIC: bad remove of %lx\n", OldPacket);
|
|
|
|
} else {
|
|
|
|
--SonicPacketListSize;
|
|
SonicPacketList[i] = SonicPacketList[SonicPacketListSize];
|
|
|
|
}
|
|
|
|
}
|
|
#endif // CHECK_DUP_SENDS
|
|
|
|
|
|
extern
|
|
NDIS_STATUS
|
|
SonicSend(
|
|
IN NDIS_HANDLE MiniportAdapterContext,
|
|
IN PNDIS_PACKET Packet,
|
|
IN UINT SendFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The SonicSend request instructs a driver to transmit a packet through
|
|
the adapter onto the medium.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterContext - Context registered with the wrapper, really
|
|
a pointer to the adapter.
|
|
|
|
Packet - A pointer to a descriptor for the packet that is to be
|
|
transmitted.
|
|
|
|
SendFlags - Optional send flags
|
|
|
|
Return Value:
|
|
|
|
The function value is the status of the operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Holds the status that should be returned to the caller.
|
|
//
|
|
NDIS_STATUS StatusToReturn = NDIS_STATUS_PENDING;
|
|
|
|
//
|
|
// Pointer to the adapter.
|
|
//
|
|
PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
|
|
|
|
PSONIC_PACKET_RESERVED Reserved;
|
|
|
|
//
|
|
// Holds whether the packet has been constrained
|
|
// to the hardware requirements.
|
|
//
|
|
BOOLEAN SuitableForHardware;
|
|
|
|
//
|
|
// If we successfully acquire some ring entries, this
|
|
// is the index of the first one.
|
|
//
|
|
UINT DescriptorIndex;
|
|
|
|
#ifdef CHECK_DUP_SENDS
|
|
SonicAddPacketToList(Adapter, Packet);
|
|
#endif
|
|
|
|
|
|
//
|
|
// Check to see if the packet should even make it out to
|
|
// the media. The primary reason this shouldn't *actually*
|
|
// be sent is if the destination is equal to the source
|
|
// address.
|
|
//
|
|
|
|
Reserved = PSONIC_RESERVED_FROM_PACKET(Packet);
|
|
|
|
//
|
|
// Determine if and how much adapter space would need to be allocated
|
|
// to meet hardware constraints.
|
|
//
|
|
|
|
CalculatePacketConstraints(
|
|
Adapter,
|
|
Packet
|
|
);
|
|
|
|
//
|
|
// We look to see if there are enough ring entries.
|
|
// If there aren't then fail this send.
|
|
//
|
|
|
|
if (Adapter->NumberOfAvailableDescriptors > 1) {
|
|
|
|
DescriptorIndex = Adapter->AllocateableDescriptor - Adapter->TransmitDescriptorArea;
|
|
|
|
if (Adapter->AllocateableDescriptor == Adapter->LastTransmitDescriptor) {
|
|
|
|
Adapter->AllocateableDescriptor = Adapter->TransmitDescriptorArea;
|
|
|
|
} else {
|
|
|
|
++(Adapter->AllocateableDescriptor);
|
|
|
|
}
|
|
|
|
--(Adapter->NumberOfAvailableDescriptors);
|
|
|
|
if (Reserved->UsedSonicBuffer == TRUE) {
|
|
|
|
//
|
|
// ConstrainPacket returns FALSE if an adapter buffer
|
|
// is needed and none is available.
|
|
//
|
|
|
|
SuitableForHardware = ConstrainPacket(
|
|
Adapter,
|
|
Packet
|
|
);
|
|
|
|
if (!SuitableForHardware) {
|
|
|
|
//
|
|
// Return transmit descriptor
|
|
//
|
|
|
|
Adapter->AllocateableDescriptor = Adapter->TransmitDescriptorArea +
|
|
DescriptorIndex;
|
|
|
|
|
|
++(Adapter->NumberOfAvailableDescriptors);
|
|
|
|
StatusToReturn = NDIS_STATUS_RESOURCES;
|
|
|
|
goto FinishWithSend;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Put the packet on the finish transmit queue.
|
|
//
|
|
|
|
if (Adapter->FirstFinishTransmit == NULL) {
|
|
|
|
Adapter->FirstFinishTransmit = Packet;
|
|
|
|
} else {
|
|
|
|
PSONIC_RESERVED_FROM_PACKET(Adapter->LastFinishTransmit)->Next = Packet;
|
|
|
|
}
|
|
|
|
Adapter->LastFinishTransmit = Packet;
|
|
|
|
Reserved->Next = NULL;
|
|
|
|
//
|
|
// We have the number of buffers that we need.
|
|
// We assign all of the buffers to the ring entries.
|
|
//
|
|
|
|
AssignPacketToDescriptor(
|
|
Adapter,
|
|
Packet,
|
|
DescriptorIndex
|
|
);
|
|
|
|
RelinquishPacket(
|
|
Adapter,
|
|
Packet,
|
|
DescriptorIndex
|
|
);
|
|
|
|
} else {
|
|
|
|
StatusToReturn = NDIS_STATUS_RESOURCES;
|
|
|
|
}
|
|
|
|
FinishWithSend:
|
|
|
|
return StatusToReturn;
|
|
}
|
|
|
|
STATIC
|
|
BOOLEAN
|
|
ConstrainPacket(
|
|
IN PSONIC_ADAPTER Adapter,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a packet and necessary attempt to acquire adapter
|
|
buffer resources so that the packet meets sonic hardware
|
|
contraints. If a buffer is needed and is not available then
|
|
return FALSE.
|
|
|
|
The constraints are that the packet must have SONIC_MAX_FRAGMENTS
|
|
or fewer physical pieces and no piece may be less than
|
|
SONIC_MIN_PIECE_SIZE bytes. The first constraint is based on
|
|
the size of the SONIC_TRANSMIT_DESCRIPTOR, and the second
|
|
is to prevent underflow in the Silo.
|
|
|
|
If a packet violates either of the constraints then it
|
|
will be copied in its entirety into an adapter buffer.
|
|
|
|
Arguments:
|
|
|
|
Adapter - The adapter the packet is coming through.
|
|
|
|
Packet - The packet whose buffers are to be constrained.
|
|
The packet reserved section is filled with information
|
|
detailing how the packet needs to be adjusted.
|
|
|
|
Return Value:
|
|
|
|
Returns TRUE if the packet is suitable for the hardware.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Pointer to the reserved section of the packet to be contrained.
|
|
//
|
|
PSONIC_PACKET_RESERVED Reserved = PSONIC_RESERVED_FROM_PACKET(Packet);
|
|
|
|
//
|
|
// Holds the adapter buffer index available for allocation.
|
|
//
|
|
INT SonicBuffersIndex;
|
|
|
|
//
|
|
// Points to a successfully allocated adapter buffer descriptor.
|
|
//
|
|
PSONIC_BUFFER_DESCRIPTOR BufferDescriptor;
|
|
|
|
//
|
|
// Will point into the virtual address space addressed
|
|
// by the adapter buffer if one was successfully allocated.
|
|
//
|
|
PCHAR CurrentDestination;
|
|
|
|
//
|
|
// Will hold the total amount of data copied to the
|
|
// adapter buffer.
|
|
//
|
|
UINT TotalDataMoved = 0;
|
|
|
|
//
|
|
// Will point to the current source buffer.
|
|
//
|
|
PNDIS_BUFFER SourceBuffer;
|
|
|
|
//
|
|
// Points to the virtual address of the source buffers data.
|
|
//
|
|
PVOID SourceData;
|
|
|
|
//
|
|
// Will point to the number of bytes of data in the source
|
|
// buffer.
|
|
//
|
|
UINT SourceLength;
|
|
|
|
//
|
|
// Simple iteration variable.
|
|
//
|
|
INT i;
|
|
|
|
//
|
|
// Total length of the packet
|
|
//
|
|
UINT PacketLength;
|
|
|
|
NdisQueryPacket(
|
|
Packet,
|
|
NULL,
|
|
NULL,
|
|
&SourceBuffer,
|
|
&PacketLength
|
|
);
|
|
|
|
if (PacketLength <= SONIC_SMALL_BUFFER_SIZE) {
|
|
|
|
i = 1;
|
|
|
|
} else if (PacketLength <= SONIC_MEDIUM_BUFFER_SIZE) {
|
|
|
|
i = 2;
|
|
|
|
} else {
|
|
|
|
i = 3;
|
|
|
|
}
|
|
|
|
|
|
for (
|
|
;
|
|
i <= 3;
|
|
i++
|
|
) {
|
|
|
|
if ((SonicBuffersIndex = Adapter->SonicBufferListHeads[i]) != -1) {
|
|
|
|
BufferDescriptor = Adapter->SonicBuffers + SonicBuffersIndex;
|
|
Adapter->SonicBufferListHeads[i] = BufferDescriptor->Next;
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (SonicBuffersIndex == -1) {
|
|
|
|
//
|
|
// Nothing available for the packet.
|
|
//
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
//
|
|
// Save the list head index in the buffer descriptor
|
|
// to permit easy deallocation later.
|
|
//
|
|
|
|
BufferDescriptor->Next = i;
|
|
|
|
//
|
|
// Fill in the adapter buffer with the data from the users
|
|
// buffers.
|
|
//
|
|
|
|
CurrentDestination = BufferDescriptor->VirtualSonicBuffer;
|
|
|
|
while (SourceBuffer) {
|
|
|
|
NdisQueryBuffer(
|
|
SourceBuffer,
|
|
&SourceData,
|
|
&SourceLength
|
|
);
|
|
|
|
SONIC_MOVE_MEMORY(
|
|
CurrentDestination,
|
|
SourceData,
|
|
SourceLength
|
|
);
|
|
|
|
CurrentDestination = (PCHAR)CurrentDestination + SourceLength;
|
|
|
|
TotalDataMoved += SourceLength;
|
|
|
|
NdisGetNextBuffer(
|
|
SourceBuffer,
|
|
&SourceBuffer
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// If the packet is less then the minimum size then we
|
|
// need to zero out the rest of the packet.
|
|
//
|
|
|
|
if (TotalDataMoved < SONIC_MIN_PACKET_SIZE) {
|
|
|
|
SONIC_ZERO_MEMORY(
|
|
CurrentDestination,
|
|
SONIC_MIN_PACKET_SIZE - TotalDataMoved
|
|
);
|
|
|
|
BufferDescriptor->DataLength = SONIC_MIN_PACKET_SIZE;
|
|
|
|
} else {
|
|
|
|
BufferDescriptor->DataLength = TotalDataMoved;
|
|
|
|
}
|
|
|
|
//
|
|
// We need to save in the packet which adapter buffer descriptor
|
|
// it is using so that we can deallocate it later.
|
|
//
|
|
|
|
Reserved->SonicBuffersIndex = SonicBuffersIndex;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
CalculatePacketConstraints(
|
|
IN PSONIC_ADAPTER Adapter,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a packet calculate how the packet will have to be
|
|
adjusted to meet with hardware constraints.
|
|
|
|
The constraints are that the packet must have SONIC_MAX_FRAGMENTS
|
|
or fewer physical pieces and no piece may be less than
|
|
SONIC_MIN_FRAGMENT_SIZE bytes. The first constraint is based on
|
|
the size of the SONIC_TRANSMIT_DESCRIPTOR, and the second
|
|
is to prevent underflow in the Silo (exception: the last
|
|
fragment in a packet may be smaller).
|
|
|
|
If the packet is found to violate the constraints, then
|
|
UsedSonicBuffer will be set to TRUE. This will cause the entire packet to
|
|
be copied into the adapter buffer (which is guaranteed
|
|
to be physically contiguous).
|
|
|
|
Arguments:
|
|
|
|
Adapter - The adapter the packet is coming through.
|
|
|
|
Packet - The packet whose buffers are to be reallocated.
|
|
The packet reserved section is filled with information
|
|
detailing how the packet needs to be adjusted.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Points to the MacReserved portion of the packet.
|
|
//
|
|
PSONIC_PACKET_RESERVED Reserved = PSONIC_RESERVED_FROM_PACKET(Packet);
|
|
|
|
//
|
|
// The number of physical buffers in the entire packet.
|
|
//
|
|
UINT PacketPhysicalSegments;
|
|
|
|
//
|
|
// Points to the current ndis buffer being walked.
|
|
//
|
|
PNDIS_BUFFER CurrentBuffer;
|
|
|
|
//
|
|
// The virtual address of the current ndis buffer.
|
|
//
|
|
UINT BufferOffset;
|
|
|
|
//
|
|
// The length in bytes of the current ndis buffer.
|
|
//
|
|
UINT BufferVirtualLength;
|
|
|
|
//
|
|
// The total amount of data contained within the ndis packet.
|
|
//
|
|
UINT PacketVirtualLength;
|
|
|
|
//
|
|
// The number of physical buffers in a single buffer.
|
|
//
|
|
UINT BufferPhysicalSegments;
|
|
|
|
//
|
|
// TRUE once we find a constraint violation
|
|
//
|
|
BOOLEAN ViolatedConstraints = FALSE;
|
|
|
|
#ifndef NO_CHIP_FIXUP
|
|
//
|
|
// Used to keep track of the total number of fragments
|
|
// that the packet will occupy when assigned to a
|
|
// transmit descriptor (may be more than PacketPhysicalSegments
|
|
// if we have to worry about packets starting or ending
|
|
// on non-longword boundaries.
|
|
//
|
|
UINT TotalTransmitSegments = 0;
|
|
#endif
|
|
|
|
|
|
|
|
//
|
|
// Get the first buffer in the packet.
|
|
//
|
|
|
|
NdisQueryPacket(
|
|
Packet,
|
|
&PacketPhysicalSegments,
|
|
NULL,
|
|
&CurrentBuffer,
|
|
&PacketVirtualLength
|
|
);
|
|
|
|
//
|
|
// We only allow SONIC_MAX_FRAGMENTS physical pieces.
|
|
//
|
|
|
|
if (PacketPhysicalSegments > SONIC_MAX_FRAGMENTS) {
|
|
ViolatedConstraints = TRUE;
|
|
goto DoneExamining;
|
|
}
|
|
|
|
//
|
|
// For short packets we can only allow SONIC_MAX_FRAGMENTS-1
|
|
// (to allow for the blank padding buffer). Also, we can't
|
|
// allow the padding itself to be less than the minimum
|
|
// fragment size.
|
|
//
|
|
|
|
if (PacketVirtualLength < SONIC_MIN_PACKET_SIZE &&
|
|
((PacketPhysicalSegments > (SONIC_MAX_FRAGMENTS-1)) ||
|
|
(PacketVirtualLength >
|
|
(SONIC_MIN_PACKET_SIZE - SONIC_MIN_FRAGMENT_SIZE)))) {
|
|
ViolatedConstraints = TRUE;
|
|
goto DoneExamining;
|
|
}
|
|
|
|
|
|
//
|
|
// Now loop making sure no fragment is less than
|
|
// SONIC_MIN_FRAGMENT_SIZE bytes unless it is the
|
|
// last one.
|
|
//
|
|
|
|
while (CurrentBuffer) {
|
|
|
|
NdisQueryBufferOffset(
|
|
CurrentBuffer,
|
|
&BufferOffset,
|
|
&BufferVirtualLength
|
|
);
|
|
|
|
|
|
//
|
|
// See if there is only one piece in the buffer.
|
|
//
|
|
|
|
NdisGetBufferPhysicalArraySize(
|
|
CurrentBuffer,
|
|
&BufferPhysicalSegments
|
|
);
|
|
|
|
if (BufferPhysicalSegments == 1) {
|
|
|
|
//
|
|
// Only one piece, make sure it is large enough or
|
|
// is the last fragment.
|
|
//
|
|
|
|
if ((BufferVirtualLength < SONIC_MIN_FRAGMENT_SIZE) &&
|
|
(NDIS_BUFFER_LINKAGE(CurrentBuffer) != NULL)) {
|
|
ViolatedConstraints = TRUE;
|
|
goto DoneExamining;
|
|
}
|
|
|
|
#ifndef NO_CHIP_FIXUP
|
|
|
|
//
|
|
// See if the beginning AND end of this piece are
|
|
// not longword-aligned.
|
|
//
|
|
|
|
if (((ULONG)BufferOffset & 0x03) &&
|
|
(((ULONG)BufferOffset + BufferVirtualLength) & 0x03)) {
|
|
|
|
//
|
|
// Now see if this piece is large enough to
|
|
// be split into two.
|
|
//
|
|
|
|
if (BufferVirtualLength >
|
|
(UINT)(4 - ((ULONG)BufferOffset & 0x03) +
|
|
(2*SONIC_MIN_FRAGMENT_SIZE))) {
|
|
|
|
//
|
|
// Have enough to let the first fragment be
|
|
// SONIC_MIN_FRAGMENT_SIZE plus the extra
|
|
// few bytes at the beginning, and the
|
|
// second piece SONIC_MIN_FRAGMENT_SIZE.
|
|
//
|
|
|
|
TotalTransmitSegments += 2;
|
|
|
|
} else {
|
|
|
|
ViolatedConstraints = TRUE;
|
|
goto DoneExamining;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// This piece won't have to be split, so
|
|
// just count it as one.
|
|
//
|
|
|
|
TotalTransmitSegments += 1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
//
|
|
// Multiple pieces. We assume that the relevant low bits
|
|
// will be the same in a physical and virtual address, so
|
|
// we can check using the virtual address whether a
|
|
// physical segment may be too short (we are being over-
|
|
// cautious here, but this allows us to avoid actually
|
|
// querying the physical addresses here.
|
|
//
|
|
|
|
//
|
|
// See if this buffer starts less than MIN_FRAGMENT_SIZE
|
|
// bytes before a page boundary.
|
|
//
|
|
|
|
if (PAGE_SIZE - ((ULONG)BufferOffset & (PAGE_SIZE-1)) <
|
|
SONIC_MIN_FRAGMENT_SIZE) {
|
|
ViolatedConstraints = TRUE;
|
|
goto DoneExamining;
|
|
}
|
|
|
|
//
|
|
// See if this buffer ends less than MIN_FRAGMENT_SIZE
|
|
// bytes after a page boundary.
|
|
//
|
|
|
|
if (((ULONG)BufferOffset + BufferVirtualLength) & (PAGE_SIZE-1) <
|
|
SONIC_MIN_FRAGMENT_SIZE) {
|
|
ViolatedConstraints = TRUE;
|
|
goto DoneExamining;
|
|
}
|
|
|
|
#ifndef NO_CHIP_FIXUP
|
|
|
|
//
|
|
// Add the number of fragments in this piece.
|
|
// We assume that physical gaps will always be
|
|
// on at least a 4 byte boundary, so we won't
|
|
// need to split this piece.
|
|
//
|
|
|
|
TotalTransmitSegments += BufferPhysicalSegments;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
NdisGetNextBuffer(
|
|
CurrentBuffer,
|
|
&CurrentBuffer
|
|
);
|
|
|
|
}
|
|
|
|
|
|
#ifndef NO_CHIP_FIXUP
|
|
|
|
//
|
|
// If the packet is short, we have to allow for the
|
|
// padding fragment at the end.
|
|
//
|
|
|
|
if (PacketVirtualLength < SONIC_MIN_PACKET_SIZE) {
|
|
|
|
TotalTransmitSegments += 1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
DoneExamining: ;
|
|
|
|
#ifndef NO_CHIP_FIXUP
|
|
if (ViolatedConstraints || (TotalTransmitSegments > SONIC_MAX_FRAGMENTS)) {
|
|
#else
|
|
if (ViolatedConstraints) {
|
|
#endif
|
|
|
|
Reserved->UsedSonicBuffer = TRUE;
|
|
|
|
} else {
|
|
|
|
Reserved->UsedSonicBuffer = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
AssignPacketToDescriptor(
|
|
IN PSONIC_ADAPTER Adapter,
|
|
IN PNDIS_PACKET Packet,
|
|
IN UINT DescriptorIndex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a packet and a ring index, assign all of the buffers
|
|
in the packet to ring entries.
|
|
|
|
Arguments:
|
|
|
|
Adapter - The adapter that the packets are coming through.
|
|
|
|
Packet - The packet whose buffers are to be assigned
|
|
ring entries.
|
|
|
|
DescriptorIndex - The index of the start of the ring entries to
|
|
be assigned buffers.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Points to the reserved portion of the packet.
|
|
//
|
|
PSONIC_PACKET_RESERVED Reserved = PSONIC_RESERVED_FROM_PACKET(Packet);
|
|
|
|
//
|
|
// Pointer to the ring entry to be filled with buffer information.
|
|
//
|
|
PSONIC_TRANSMIT_DESCRIPTOR TransmitDescriptor = Adapter->TransmitDescriptorArea
|
|
+ DescriptorIndex;
|
|
|
|
//
|
|
// Pointer to the ring to packet entry that records the info about
|
|
// this packet.
|
|
//
|
|
PSONIC_DESCRIPTOR_TO_PACKET DescriptorToPacket = Adapter->DescriptorToPacket + DescriptorIndex;
|
|
|
|
//
|
|
// The total amount of data in the ndis packet.
|
|
//
|
|
UINT TotalDataLength;
|
|
|
|
//
|
|
// Points to the current ndis buffer being walked.
|
|
//
|
|
PNDIS_BUFFER CurrentBuffer;
|
|
|
|
//
|
|
// The number of physical segments in this buffer.
|
|
//
|
|
UINT BufferPhysicalSegments;
|
|
|
|
//
|
|
// An array to hold the physical segments.
|
|
//
|
|
NDIS_PHYSICAL_ADDRESS_UNIT PhysicalSegmentArray[SONIC_MAX_FRAGMENTS];
|
|
|
|
//
|
|
// We record the owning packet information in the ring packet packet
|
|
// structure.
|
|
//
|
|
|
|
|
|
DescriptorToPacket->OwningPacket = Packet;
|
|
DescriptorToPacket->UsedSonicBuffer = (BOOLEAN)
|
|
Reserved->UsedSonicBuffer;
|
|
DescriptorToPacket->SonicBuffersIndex =
|
|
Reserved->SonicBuffersIndex;
|
|
|
|
|
|
//
|
|
// First initialize the fields that don't depend on
|
|
// how many fragments there are in the packet.
|
|
//
|
|
|
|
TransmitDescriptor->TransmitStatus = 0;
|
|
|
|
//
|
|
// Set the programmable interrupt if it has been a long
|
|
// time since transmit complete interrupts were processed.
|
|
//
|
|
|
|
if (Adapter->PacketsSinceLastInterrupt >=
|
|
(SONIC_NUMBER_OF_TRANSMIT_DESCRIPTORS/2)) {
|
|
|
|
TransmitDescriptor->TransmitConfiguration = (UINT)SONIC_TCR_PROG_INTERRUPT;
|
|
Adapter->PacketsSinceLastInterrupt = 0;
|
|
|
|
} else {
|
|
|
|
TransmitDescriptor->TransmitConfiguration = 0;
|
|
++Adapter->PacketsSinceLastInterrupt;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Now check to see if the packet has been copied into an
|
|
// adapter buffer.
|
|
//
|
|
|
|
if (Reserved->UsedSonicBuffer) {
|
|
|
|
//
|
|
// Points to the adapter buffer descriptor allocated
|
|
// for this packet.
|
|
//
|
|
PSONIC_BUFFER_DESCRIPTOR BufferDescriptor;
|
|
|
|
BufferDescriptor = Adapter->SonicBuffers
|
|
+ Reserved->SonicBuffersIndex;
|
|
|
|
TransmitDescriptor->FragmentCount = 1;
|
|
TransmitDescriptor->PacketSize = (UINT)BufferDescriptor->DataLength;
|
|
|
|
SONIC_SET_TRANSMIT_FRAGMENT_ADDRESS(
|
|
&(TransmitDescriptor->Fragments[0]),
|
|
NdisGetPhysicalAddressLow(BufferDescriptor->PhysicalSonicBuffer)
|
|
);
|
|
|
|
SONIC_SET_TRANSMIT_FRAGMENT_LENGTH(
|
|
&(TransmitDescriptor->Fragments[0]),
|
|
BufferDescriptor->DataLength
|
|
);
|
|
|
|
|
|
//
|
|
// This sets end-of-list for this descriptor.
|
|
//
|
|
|
|
SONIC_SET_TRANSMIT_LINK(
|
|
&(TransmitDescriptor->Fragments[1]),
|
|
TransmitDescriptor->Link
|
|
);
|
|
|
|
DescriptorToPacket->LinkPointer = (SONIC_PHYSICAL_ADDRESS *)
|
|
&(TransmitDescriptor->Fragments[1]);
|
|
|
|
|
|
//
|
|
// Flush the buffer that contains the packet.
|
|
//
|
|
|
|
SONIC_FLUSH_WRITE_BUFFER(BufferDescriptor->FlushBuffer);
|
|
|
|
} else {
|
|
|
|
//
|
|
// The total length of the packet (including padding)
|
|
//
|
|
UINT TotalPacketLength;
|
|
|
|
//
|
|
// Which fragment we are filling;
|
|
//
|
|
UINT CurFragment;
|
|
|
|
//
|
|
// Which map register we use for this buffer.
|
|
//
|
|
UINT CurMapRegister;
|
|
|
|
//
|
|
// Simple iteration variable.
|
|
//
|
|
UINT i;
|
|
|
|
|
|
CurFragment = 0;
|
|
CurMapRegister = DescriptorIndex * SONIC_MAX_FRAGMENTS;
|
|
|
|
NdisQueryPacket(
|
|
Packet,
|
|
NULL,
|
|
NULL,
|
|
&CurrentBuffer,
|
|
&TotalDataLength
|
|
);
|
|
|
|
|
|
while (CurrentBuffer) {
|
|
|
|
NdisMStartBufferPhysicalMapping(
|
|
Adapter->MiniportAdapterHandle,
|
|
CurrentBuffer,
|
|
CurMapRegister,
|
|
TRUE,
|
|
PhysicalSegmentArray,
|
|
&BufferPhysicalSegments
|
|
);
|
|
|
|
++CurMapRegister;
|
|
|
|
//
|
|
// Put the physical segments for this buffer into
|
|
// the transmit descriptors.
|
|
//
|
|
|
|
for (i=0; i<BufferPhysicalSegments; i++) {
|
|
|
|
ASSERT (NdisGetPhysicalAddressHigh(PhysicalSegmentArray[i].PhysicalAddress) == 0);
|
|
|
|
SONIC_SET_TRANSMIT_FRAGMENT_ADDRESS(
|
|
&(TransmitDescriptor->Fragments[CurFragment]),
|
|
NdisGetPhysicalAddressLow(PhysicalSegmentArray[i].PhysicalAddress)
|
|
);
|
|
|
|
SONIC_SET_TRANSMIT_FRAGMENT_LENGTH(
|
|
&(TransmitDescriptor->Fragments[CurFragment]),
|
|
PhysicalSegmentArray[i].Length
|
|
);
|
|
|
|
++CurFragment;
|
|
|
|
#ifndef NO_CHIP_FIXUP
|
|
|
|
//
|
|
// If the fragment starts and ends not on a longword
|
|
// boundary, split it into two fragments, the first
|
|
// being SONIC_MIN_FRAGMENT_SIZE plus the extra bits
|
|
// at the beginning, the other the rest.
|
|
//
|
|
|
|
if ((NdisGetPhysicalAddressLow(PhysicalSegmentArray[i].PhysicalAddress) & 0x03) &&
|
|
((NdisGetPhysicalAddressLow(PhysicalSegmentArray[i].PhysicalAddress) + PhysicalSegmentArray[i].Length) & 0x03)) {
|
|
|
|
UINT FirstSegmentLength;
|
|
|
|
FirstSegmentLength = (4 - ((NdisGetPhysicalAddressLow(PhysicalSegmentArray[i].PhysicalAddress) & 0x03))) +
|
|
SONIC_MIN_FRAGMENT_SIZE;
|
|
|
|
SONIC_SET_TRANSMIT_FRAGMENT_LENGTH(
|
|
&(TransmitDescriptor->Fragments[CurFragment-1]),
|
|
FirstSegmentLength
|
|
);
|
|
|
|
SONIC_SET_TRANSMIT_FRAGMENT_ADDRESS(
|
|
&(TransmitDescriptor->Fragments[CurFragment]),
|
|
SONIC_GET_TRANSMIT_FRAGMENT_ADDRESS(
|
|
&(TransmitDescriptor->Fragments[CurFragment-1])) +
|
|
FirstSegmentLength
|
|
);
|
|
|
|
SONIC_SET_TRANSMIT_FRAGMENT_LENGTH(
|
|
&(TransmitDescriptor->Fragments[CurFragment]),
|
|
PhysicalSegmentArray[i].Length - FirstSegmentLength
|
|
);
|
|
|
|
++CurFragment;
|
|
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
SONIC_FLUSH_WRITE_BUFFER (CurrentBuffer);
|
|
|
|
NdisGetNextBuffer(
|
|
CurrentBuffer,
|
|
&CurrentBuffer
|
|
);
|
|
|
|
}
|
|
|
|
if (TotalDataLength < SONIC_MIN_PACKET_SIZE) {
|
|
|
|
SONIC_SET_TRANSMIT_FRAGMENT_ADDRESS(
|
|
&(TransmitDescriptor->Fragments[CurFragment]),
|
|
NdisGetPhysicalAddressLow(Adapter->BlankBufferAddress)
|
|
);
|
|
|
|
SONIC_SET_TRANSMIT_FRAGMENT_LENGTH(
|
|
&(TransmitDescriptor->Fragments[CurFragment]),
|
|
SONIC_MIN_PACKET_SIZE - TotalDataLength
|
|
);
|
|
|
|
//
|
|
// Note that BlankBuffer has already been flushed.
|
|
//
|
|
|
|
++CurFragment;
|
|
|
|
TotalPacketLength = SONIC_MIN_PACKET_SIZE;
|
|
|
|
} else {
|
|
|
|
TotalPacketLength = TotalDataLength;
|
|
|
|
}
|
|
|
|
//
|
|
// Make sure we didn't mess up and use up too
|
|
// many fragments.
|
|
//
|
|
ASSERT(CurFragment <= SONIC_MAX_FRAGMENTS);
|
|
|
|
TransmitDescriptor->FragmentCount = (UINT)CurFragment;
|
|
TransmitDescriptor->PacketSize = (UINT)TotalPacketLength;
|
|
|
|
|
|
//
|
|
// This sets end-of-list for this descriptor.
|
|
//
|
|
|
|
SONIC_SET_TRANSMIT_LINK(
|
|
&(TransmitDescriptor->Fragments[CurFragment]),
|
|
TransmitDescriptor->Link
|
|
);
|
|
|
|
DescriptorToPacket->LinkPointer = (SONIC_PHYSICAL_ADDRESS *)
|
|
&(TransmitDescriptor->Fragments[CurFragment]);
|
|
|
|
}
|
|
|
|
if (DescriptorIndex == (Adapter->NumberOfTransmitDescriptors-1)) {
|
|
|
|
Adapter->DescriptorToPacket->PrevLinkPointer = DescriptorToPacket->LinkPointer;
|
|
|
|
} else {
|
|
|
|
(DescriptorToPacket+1)->PrevLinkPointer = DescriptorToPacket->LinkPointer;
|
|
|
|
}
|
|
|
|
Reserved->DescriptorIndex = DescriptorIndex;
|
|
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
RelinquishPacket(
|
|
IN PSONIC_ADAPTER Adapter,
|
|
IN PNDIS_PACKET Packet,
|
|
IN UINT RingIndex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Relinquish the ring entries owned by the packet to the chip.
|
|
We also update the first uncommitted ring pointer.
|
|
|
|
Arguments:
|
|
|
|
Adapter - The adapter that points to the ring entry structures.
|
|
|
|
Packet - The packet contains the ring index of the ring
|
|
entry for the packet.
|
|
|
|
RingIndex - Holds the index of the ring entry used
|
|
by this packet.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Holds the previous link pointer, where we turn off
|
|
// end-of-list.
|
|
//
|
|
|
|
PSONIC_PHYSICAL_ADDRESS PrevLinkPointer;
|
|
|
|
#if !BINARY_COMPATIBLE
|
|
|
|
//
|
|
// NOTE: We have to raise the IRQL to POWER_LEVEL around the
|
|
// calls to SONIC_REMOVE_END_OF_LIST and START_TRANSMIT.
|
|
// This is to prevent a delay between these two instructions.
|
|
// If a delay happens right after SONIC_REMOVE_END_OF_LIST, the
|
|
// Sonic could transmit the packet and stop, then the call
|
|
// to START_TRANSMIT would cause it to retransmit all the
|
|
// packets in the descriptor ring.
|
|
//
|
|
// [ChuckL 8/3/94]
|
|
// We believe that this is no longer necessary, but we are leaving
|
|
// it in for RISC builds for safety's sake. We are removing in from
|
|
// x86 builds in order to remain binary-compatible with Chicago.
|
|
//
|
|
|
|
KIRQL OldIrql;
|
|
|
|
#endif
|
|
|
|
PrevLinkPointer = Adapter->DescriptorToPacket[RingIndex].PrevLinkPointer;
|
|
|
|
#if !BINARY_COMPATIBLE
|
|
|
|
//
|
|
// See NOTE above.
|
|
//
|
|
|
|
KeRaiseIrql(POWER_LEVEL, &OldIrql);
|
|
|
|
#endif
|
|
|
|
//
|
|
// Turn off END_OF_LIST for the last one.
|
|
//
|
|
|
|
SONIC_REMOVE_END_OF_LIST(PrevLinkPointer);
|
|
|
|
//
|
|
// This turns on the correct bit in the SONIC_CONTROL
|
|
// register.
|
|
//
|
|
|
|
START_TRANSMIT(Adapter);
|
|
|
|
#if !BINARY_COMPATIBLE
|
|
|
|
//
|
|
// See NOTE above.
|
|
//
|
|
|
|
KeLowerIrql(OldIrql);
|
|
|
|
#endif
|
|
|
|
//
|
|
// We want FirstUncommittedDescriptor to point to right after us.
|
|
//
|
|
|
|
if (RingIndex == (Adapter->NumberOfTransmitDescriptors-1)) {
|
|
|
|
Adapter->FirstUncommittedDescriptor = Adapter->TransmitDescriptorArea;
|
|
|
|
} else {
|
|
|
|
Adapter->FirstUncommittedDescriptor =
|
|
Adapter->TransmitDescriptorArea + (RingIndex + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|