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.
1300 lines
28 KiB
1300 lines
28 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
pc586snd.c
|
|
|
|
Abstract:
|
|
|
|
This file contains the code for putting a packet through the
|
|
staged 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 thos ring entries to the hardware.
|
|
|
|
NOTE: ZZZ There is a potential priority inversion problem when
|
|
allocating the packet. For nt it looks like we need to raise
|
|
the irql to dpc when we start the allocation.
|
|
|
|
Author:
|
|
|
|
Anthony V. Ercolano (Tonye) 12-Sept-1990
|
|
|
|
Environment:
|
|
|
|
Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include <ntos.h>
|
|
#include <ndis.h>
|
|
#include <filter.h>
|
|
#include <pc586hrd.h>
|
|
#include <pc586sft.h>
|
|
|
|
|
|
|
|
|
|
//
|
|
// ZZZ This macro implementation is peculiar to NT. It will poke the
|
|
// pc586 hardware into noticing that there is a packet available
|
|
// for transmit.
|
|
//
|
|
// Note that there is the assumption that the register address
|
|
// port (RAP) is already set to zero.
|
|
//
|
|
#define PROD_TRANSMIT(A) \
|
|
PC586_WRITE_RDP( \
|
|
A->RDP, \
|
|
PC586_CSR0_TRANSMIT_DEMAND | PC586_CSR0_INTERRUPT_ENABLE \
|
|
);
|
|
|
|
|
|
static
|
|
BOOLEAN
|
|
PacketShouldBeSent(
|
|
IN NDIS_HANDLE MacBindingHandle,
|
|
IN PNDIS_PACKET Packet
|
|
);
|
|
|
|
static
|
|
VOID
|
|
SetupAllocate(
|
|
IN PPC586_ADAPTER Adapter,
|
|
IN NDIS_HANDLE MacBindingHandle,
|
|
IN NDIS_HANDLE RequestHandle,
|
|
IN PNDIS_PACKET Packet
|
|
);
|
|
|
|
static
|
|
VOID
|
|
StagedAllocation(
|
|
IN PPC586_ADAPTER Adapter
|
|
);
|
|
|
|
static
|
|
BOOLEAN
|
|
AcquireTransmitRingEntries(
|
|
IN PPC586_ADAPTER Adapter,
|
|
IN PNDIS_PACKET Packet,
|
|
OUT PUINT RingIndex
|
|
);
|
|
|
|
static
|
|
VOID
|
|
AssignPacketToRings(
|
|
IN PPC586_ADAPTER Adapter,
|
|
IN PNDIS_PACKET Packet,
|
|
IN UINT RingIndex
|
|
);
|
|
|
|
static
|
|
VOID
|
|
MovePacketToStage2(
|
|
IN PPC586_ADAPTER Adapter
|
|
);
|
|
|
|
static
|
|
VOID
|
|
MovePacketToStage3(
|
|
IN PPC586_ADAPTER Adapter
|
|
);
|
|
|
|
static
|
|
VOID
|
|
RemovePacketFromStage3(
|
|
IN PPC586_ADAPTER Adapter
|
|
);
|
|
|
|
static
|
|
VOID
|
|
RelinquishPacket(
|
|
IN PPC586_ADAPTER Adapter,
|
|
IN PNDIS_PACKET Packet,
|
|
);
|
|
|
|
static
|
|
VOID
|
|
CalculatePacketConstraints(
|
|
IN PPC586_ADAPTER Adapter,
|
|
IN PNDIS_PACKET Packet
|
|
);
|
|
|
|
static
|
|
BOOLEAN
|
|
ConstrainPacket(
|
|
IN PPC586_ADAPTER Adapter,
|
|
IN PNDIS_PACKET Packet
|
|
);
|
|
|
|
|
|
extern
|
|
NDIS_STATUS
|
|
Pc586Send(
|
|
IN NDIS_HANDLE MacBindingHandle,
|
|
IN NDIS_HANDLE RequestHandle,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The Pc586Send request instructs a MAC to transmit a packet through
|
|
the adapter onto the medium.
|
|
|
|
Arguments:
|
|
|
|
MacBindingHandle - The context value returned by the MAC when the
|
|
adapter was opened. In reality, it is a pointer to PC586_OPEN.
|
|
|
|
RequestHandle - A value supplied by the NDIS interface that the MAC
|
|
must use when completing this request with the NdisCompleteRequest
|
|
service, if the MAC completes this request asynchronously.
|
|
|
|
Packet - A pointer to a descriptor for the packet that is to be
|
|
transmitted.
|
|
|
|
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.
|
|
//
|
|
PPC586_ADAPTER Adapter;
|
|
|
|
Adapter = PPC586_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
|
|
NdisAcquireSpinLock(&Adapter->Lock);
|
|
Adapter->References++;
|
|
|
|
if (!Adapter->ResetInProgress) {
|
|
|
|
PPC586_OPEN Open;
|
|
|
|
Open = PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
|
|
|
|
if (!Open->BindingShuttingDown) {
|
|
|
|
UINT TotalPacketSize;
|
|
|
|
//
|
|
// Increment the references on the open while we are
|
|
// accessing it in the interface.
|
|
//
|
|
|
|
Open->References++;
|
|
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
|
|
//
|
|
// It is reasonable to do a quick check and fail if the packet
|
|
// is larger than the maximum an ethernet can handle.
|
|
//
|
|
|
|
NdisQueryPacket(
|
|
Packet,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&TotalPacketSize
|
|
);
|
|
|
|
if ((!TotalPacketSize) ||
|
|
(TotalPacketSize > PC586_LARGE_BUFFER_SIZE)) {
|
|
|
|
StatusToReturn = NDIS_INSUFFICIENT_RESOURCES;
|
|
NdisAcquireSpinLock(&Adapter->Lock);
|
|
|
|
} else {
|
|
|
|
//
|
|
// NOTE NOTE NOTE !!!!!!
|
|
//
|
|
// There is an assumption in the code that no pointer
|
|
// (which are really handles) to an ndis packet will have
|
|
// its low bit set. (Always have even byte alignment.)
|
|
//
|
|
|
|
ASSERT(!((UINT)Packet & 1));
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
// If it doesn't need to be placed on the wire then we can
|
|
// simply put it onto the loopback queue.
|
|
//
|
|
|
|
if (PacketShouldBeSent(
|
|
MacBindingHandle,
|
|
Packet
|
|
)) {
|
|
|
|
//
|
|
// The packet needs to be placed out on the wire.
|
|
//
|
|
|
|
SetupAllocate(
|
|
Adapter,
|
|
MacBindingHandle,
|
|
RequestHandle,
|
|
Packet
|
|
);
|
|
|
|
//
|
|
// Only try to push it through the stage queues
|
|
// if somebody else isn't already doing it and
|
|
// there is some hope of moving some packets
|
|
// ahead.
|
|
//
|
|
|
|
NdisAcquireSpinLock(&Adapter->Lock);
|
|
while ((!(Adapter->AlreadyProcessingStage4 ||
|
|
Adapter->AlreadyProcessingStage3 ||
|
|
Adapter->AlreadyProcessingStage2)
|
|
) &&
|
|
((Adapter->FirstStage3Packet &&
|
|
Adapter->Stage4Open) ||
|
|
(Adapter->FirstStage2Packet &&
|
|
Adapter->Stage3Open) ||
|
|
(Adapter->FirstStage1Packet &&
|
|
Adapter->Stage2Open)
|
|
)
|
|
) {
|
|
|
|
Pc586StagedAllocation(Adapter);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
PPC586_RESERVED Reserved;
|
|
|
|
Reserved = PPC586_RESERVED_FROM_PACKET(Packet);
|
|
Reserved->MacBindingHandle = MacBindingHandle;
|
|
Reserved->RequestHandle = RequestHandle;
|
|
|
|
NdisAcquireSpinLock(&Adapter->Lock);
|
|
|
|
Pc586PutPacketOnLoopBack(
|
|
Adapter,
|
|
Packet,
|
|
TRUE
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// The interface is no longer referencing the open.
|
|
//
|
|
|
|
Open->References--;
|
|
|
|
} else {
|
|
|
|
StatusToReturn = NDIS_CLOSING;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
|
|
|
|
}
|
|
|
|
PC586_DO_DEFERRED(Adapter);
|
|
return StatusToReturn;
|
|
}
|
|
|
|
static
|
|
BOOLEAN
|
|
PacketShouldBeSent(
|
|
IN NDIS_HANDLE MacBindingHandle,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determines whether the packet should go out on the wire at all.
|
|
The way it does this is to see if the destination address is
|
|
equal to the source address.
|
|
|
|
Arguments:
|
|
|
|
MacBindingHandle - Is a pointer to the open binding.
|
|
|
|
Packet - Packet whose source and destination addresses are tested.
|
|
|
|
Return Value:
|
|
|
|
Returns FALSE if the source is equal to the destination.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Holds the source address from the packet.
|
|
//
|
|
CHAR Source[MAC_LENGTH_OF_ADDRESS];
|
|
|
|
//
|
|
// Holds the destination address from the packet.
|
|
//
|
|
CHAR Destination[MAC_LENGTH_OF_ADDRESS];
|
|
|
|
//
|
|
// variable to hold the length of the source address.
|
|
//
|
|
UINT AddressLength;
|
|
|
|
//
|
|
// Will hold the result of the comparasion of the two MAC_NETWORD_ADDRESSes.
|
|
//
|
|
INT Result;
|
|
|
|
Pc586CopyFromPacketToBuffer(
|
|
Packet,
|
|
0,
|
|
MAC_LENGTH_OF_ADDRESS,
|
|
Destination,
|
|
&AddressLength
|
|
);
|
|
ASSERT(AddressLength == MAC_LENGTH_OF_ADDRESS);
|
|
|
|
|
|
Pc586CopyFromPacketToBuffer(
|
|
Packet,
|
|
MAC_LENGTH_OF_ADDRESS,
|
|
MAC_LENGTH_OF_ADDRESS,
|
|
Source,
|
|
&AddressLength
|
|
);
|
|
ASSERT(AddressLength == MAC_LENGTH_OF_ADDRESS);
|
|
|
|
MAC_COMPARE_NETWORK_ADDRESSES(
|
|
Source,
|
|
Destination,
|
|
&Result
|
|
);
|
|
|
|
//
|
|
// If the result is 0 then the two addresses are equal and the
|
|
// packet shouldn't go out on the wire.
|
|
//
|
|
|
|
return ((!Result)?(FALSE):(TRUE));
|
|
|
|
}
|
|
|
|
static
|
|
VOID
|
|
SetupAllocate(
|
|
IN PPC586_ADAPTER Adapter,
|
|
IN NDIS_HANDLE MacBindingHandle,
|
|
IN NDIS_HANDLE RequestHandle,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This sets up the MAC reserved portion of the packet so that
|
|
later allocation routines can determine what is left to be
|
|
done in the allocation cycle.
|
|
|
|
Arguments:
|
|
|
|
Adapter - The adapter that this packet is coming through.
|
|
|
|
MacBindingHandle - Points to the open binding structure.
|
|
|
|
RequestHandle - Protocol supplied value. It is saved so that when
|
|
the send finnaly completes it can be used to indicate to the protocol.
|
|
|
|
Packet - The packet that is to be transmitted.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Points to the MAC reserved portion of this packet. This
|
|
// interpretation of the reserved section is only valid during
|
|
// the allocation phase of the packet.
|
|
//
|
|
PPC586_RESERVED Reserved = PPC586_RESERVED_FROM_PACKET(Packet);
|
|
|
|
|
|
ASSERT(sizeof(PC586_RESERVED) <=
|
|
sizeof(Packet->MacReserved));
|
|
|
|
Reserved->STAGE.ClearStage = 0;
|
|
Reserved->MacBindingHandle = MacBindingHandle;
|
|
Reserved->RequestHandle = RequestHandle;
|
|
|
|
//
|
|
// Determine if and how much adapter space would need to be allocated
|
|
// to meet hardware constraints.
|
|
//
|
|
|
|
CalculatePacketConstraints(
|
|
Adapter,
|
|
Packet
|
|
);
|
|
|
|
NdisAcquireSpinLock(&Adapter->Lock);
|
|
|
|
//
|
|
// Put on the stage 1 queue.
|
|
//
|
|
|
|
if (!Adapter->LastStage1Packet) {
|
|
|
|
Adapter->FirstStage1Packet = Packet;
|
|
|
|
} else {
|
|
|
|
PPC586_RESERVED_FROM_PACKET(Adapter->LastStage1Packet)->Next = Packet;
|
|
|
|
}
|
|
|
|
Adapter->LastStage1Packet = Packet;
|
|
|
|
Reserved->Next = NULL;
|
|
|
|
//
|
|
// Increment the reference on the open since it
|
|
// will be leaving this packet around on the transmit
|
|
// queues.
|
|
//
|
|
|
|
PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle)->References++;
|
|
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
|
|
}
|
|
|
|
extern
|
|
VOID
|
|
Pc586StagedAllocation(
|
|
IN PPC586_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine attempts to take a packet through a stage of allocation.
|
|
|
|
Arguments:
|
|
|
|
Adapter - The adapter that the packets are coming through.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// For each stage, we check to see that it is open,
|
|
// that somebody else isn't already processing,
|
|
// and that there is some work from the previous
|
|
// stage to do.
|
|
//
|
|
|
|
if (Adapter->Stage2Open &&
|
|
!Adapter->AlreadyProcessingStage2 &&
|
|
Adapter->FirstStage1Packet) {
|
|
|
|
//
|
|
// Holds whether the packet has been constrained
|
|
// to the hardware requirements.
|
|
//
|
|
BOOLEAN SuitableForHardware;
|
|
|
|
PNDIS_PACKET FirstPacket = Adapter->FirstStage1Packet;
|
|
|
|
Adapter->AlreadyProcessingStage2 = TRUE;
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
|
|
SuitableForHardware = ConstrainPacket(
|
|
Adapter,
|
|
FirstPacket
|
|
);
|
|
|
|
NdisAcquireSpinLock(&Adapter->Lock);
|
|
if (SuitableForHardware) {
|
|
|
|
MovePacketToStage2(Adapter);
|
|
Adapter->Stage2Open = FALSE;
|
|
}
|
|
|
|
Adapter->AlreadyProcessingStage2 = FALSE;
|
|
|
|
}
|
|
if (Adapter->Stage3Open &&
|
|
!Adapter->AlreadyProcessingStage3 &&
|
|
Adapter->FirstStage2Packet) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PNDIS_PACKET FirstPacket = Adapter->FirstStage2Packet;
|
|
|
|
Adapter->AlreadyProcessingStage3 = TRUE;
|
|
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
|
|
//
|
|
// We look to see if there are enough ring entries.
|
|
// If there aren't then stage 3 will close.
|
|
//
|
|
// AcquireTransmitRingEntries will hold a spin lock
|
|
// for a short time.
|
|
//
|
|
|
|
// the Acquire/Assign procs below may be used later for 586 command chaining
|
|
|
|
// if (AcquireTransmitRingEntries(
|
|
// Adapter,
|
|
// FirstPacket,
|
|
// &RingIndex
|
|
// )) {
|
|
|
|
//
|
|
// We have the number of buffers that we need.
|
|
// We assign all of the buffers to the ring entries.
|
|
//
|
|
|
|
// AssignPacketToRings(
|
|
// Adapter,
|
|
// FirstPacket,
|
|
// RingIndex
|
|
// );
|
|
|
|
//
|
|
// We need exclusive access to the tranmit ring so
|
|
// that we can move this packet on to the next stage.
|
|
//
|
|
|
|
|
|
NdisAcquireSpinLock(&Adapter->Lock);
|
|
|
|
MovePacketToStage3(Adapter);
|
|
|
|
|
|
// } else {
|
|
//
|
|
// Adapter->Stage3Open = FALSE;
|
|
//
|
|
// }
|
|
|
|
Adapter->AlreadyProcessingStage3 = FALSE;
|
|
|
|
}
|
|
if (Adapter->Stage4Open &&
|
|
!Adapter->AlreadyProcessingStage4 &&
|
|
Adapter->FirstStage3Packet) {
|
|
|
|
//
|
|
// Holds a pointer to packet at the head of the
|
|
// stage 3.
|
|
//
|
|
PNDIS_PACKET Packet = Adapter->FirstStage3Packet;
|
|
|
|
//
|
|
// We have a packet to work with.
|
|
//
|
|
// Take the packet off of the transmit work queue.
|
|
//
|
|
|
|
RemovePacketFromStage3(Adapter);
|
|
|
|
Adapter->AlreadyProcessingStage4 = TRUE;
|
|
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
|
|
RelinquishPacket(
|
|
Adapter,
|
|
Packet
|
|
);
|
|
|
|
NdisAcquireSpinLock(&Adapter->Lock);
|
|
|
|
Adapter->AlreadyProcessingStage4 = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static
|
|
BOOLEAN
|
|
ConstrainPacket(
|
|
IN PPC586_ADAPTER Adapter,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a packet and if necessary attempt to acquire adapter
|
|
buffer resources so that the packet meets pc586 hardware
|
|
contraints.
|
|
|
|
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.
|
|
//
|
|
PPC586_RESERVED Reserved = PPC586_RESERVED_FROM_PACKET(Packet);
|
|
|
|
|
|
if (Reserved->STAGE.STAGE1.MinimumBufferRequirements) {
|
|
|
|
//
|
|
// Will point into the virtual address space addressed
|
|
// by the adapter buffer if one was successfully allocated.
|
|
//
|
|
PCHAR CurrentDestination;
|
|
|
|
//
|
|
// used to clear padding bytes in short packets
|
|
//
|
|
PUSHORT Clearing;
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
PUCHAR SourceData;
|
|
|
|
//
|
|
// Will point to the number of bytes of data in the source
|
|
// buffer.
|
|
//
|
|
UINT SourceLength;
|
|
|
|
//
|
|
// Simple iteration variable.
|
|
//
|
|
INT i;
|
|
|
|
//
|
|
// the number of ndis buffers in an ndis packet
|
|
//
|
|
UINT BufferCount;
|
|
|
|
// the 586 can only be touched on 16-bit boundries
|
|
|
|
PUSHORT ShortAddr1, ShortAddr2;
|
|
|
|
WaitScb(Adapter);
|
|
|
|
if ( (Adapter->Cb->CmdStatus & CSBUSY) ||
|
|
!(Adapter->Cb->CmdStatus & CSCMPLT) ) return FALSE;
|
|
|
|
//
|
|
// Fill in the adapter buffer with the data from the users
|
|
// buffers.
|
|
//
|
|
// FIRST FILL IN THE 586 COMMAND BLOCK
|
|
|
|
|
|
NdisQueryPacket(
|
|
Packet,
|
|
NULL,
|
|
&BufferCount,
|
|
&SourceBuffer,
|
|
NULL
|
|
);
|
|
|
|
NdisQueryBuffer(
|
|
SourceBuffer,
|
|
NULL,
|
|
&(PVOID)SourceData,
|
|
&SourceLength
|
|
);
|
|
|
|
if (SourceLength < 14) {
|
|
DbgPrint("pc586 ConstrainPacket(): can't handle fragmented xmt buffers\n");
|
|
SourceLength = 14; // ???
|
|
}
|
|
Adapter->Cb->CmdStatus = 0;
|
|
Adapter->Cb->CmdCmd = CSEL | CSCMDXMIT | CSINT;
|
|
Adapter->Cb->CmdNxtOfst = OFFSETCU; // only one Cb, points to self
|
|
|
|
Adapter->Cb->PRMTR.PrmXmit.XmtTbdOfst = OFFSETTBD;
|
|
|
|
ShortAddr2 = (PUSHORT)(Adapter->Cb->PRMTR.PrmXmit.XmtDest);
|
|
ShortAddr1 = (PUSHORT)SourceData;
|
|
|
|
*ShortAddr2++ = *ShortAddr1++;
|
|
*ShortAddr2++ = *ShortAddr1++;
|
|
*ShortAddr2++ = *ShortAddr1++;
|
|
|
|
SourceData+=12; // skip over dest and source addresses
|
|
SourceLength-=12;
|
|
|
|
ShortAddr1 = (PUSHORT)SourceData;
|
|
|
|
Adapter->Cb->PRMTR.PrmXmit.XmtLength = *ShortAddr1;
|
|
|
|
SourceData+=2; // skip over length field
|
|
SourceLength-=2;
|
|
|
|
// SECOND FILL IN XMT BUFFER DESCRIPTOR
|
|
|
|
Adapter->Tbd->TbdNxtOfst = 0xffff;
|
|
Adapter->Tbd->TbdBuff = OFFSETTBUF;
|
|
Adapter->Tbd->TbdBuffBase = 0;
|
|
|
|
|
|
// THIRD FILL IN XMT DATA
|
|
|
|
|
|
// 64 is minimum packet length, incl 6 source, 6 dest addr, 2 len
|
|
if (SourceLength < 64 - 14) {
|
|
Clearing = (PUSHORT)(Adapter->CommandBuffer);
|
|
for (i = 0; i <= 64 - 14; i +=2)
|
|
*Clearing++ = 0;
|
|
}
|
|
|
|
CurrentDestination = (PCHAR)(Adapter->CommandBuffer);
|
|
|
|
for (
|
|
i = Reserved->STAGE.STAGE1.NdisBuffersToMove;
|
|
i;
|
|
i--
|
|
) {
|
|
|
|
|
|
Pc586MoveToAdapter(
|
|
(PVOID)CurrentDestination,
|
|
(PVOID)SourceData,
|
|
SourceLength
|
|
);
|
|
|
|
CurrentDestination = (PCHAR)(CurrentDestination + SourceLength);
|
|
|
|
TotalDataMoved += SourceLength;
|
|
|
|
if (i > 1) {
|
|
|
|
NdisGetNextBuffer(
|
|
SourceBuffer,
|
|
&SourceBuffer
|
|
);
|
|
|
|
if (SourceBuffer == NULL) {
|
|
DbgPrint("PC586 ConstrainPacket(): NULL NDIS BUFFER\n");
|
|
break;
|
|
}
|
|
|
|
NdisQueryBuffer(
|
|
SourceBuffer,
|
|
NULL,
|
|
&(PVOID)SourceData,
|
|
&SourceLength
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
if (TotalDataMoved < 64 - 14 ) TotalDataMoved = 64 - 14; //required by 802.3
|
|
Adapter->Tbd->TbdCount = (USHORT)TotalDataMoved | (USHORT)CSEOF;
|
|
|
|
// Reserved->STAGE.STAGE2.UsedPc586Buffer = TRUE; might be used later
|
|
Reserved->STAGE.ClearStage = 0;
|
|
Adapter->OwningPacket = Packet;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static
|
|
VOID
|
|
CalculatePacketConstraints(
|
|
IN PPC586_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.
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// ZZZ This is not a portable routine. The MDLs that make
|
|
// up the physical address are not available on OS/2 and
|
|
// DOS.
|
|
//
|
|
|
|
|
|
//
|
|
// A basic principle here is that the reallocation of some or
|
|
// all of the user buffers to adapter buffers will only allocate
|
|
// a single adapter buffer.
|
|
//
|
|
|
|
//
|
|
// Points to the reserved portion of the packet.
|
|
//
|
|
PPC586_RESERVED Reserved = PPC586_RESERVED_FROM_PACKET(Packet);
|
|
|
|
//
|
|
// The number of ndis buffers in the packet.
|
|
//
|
|
UINT NdisBufferCount;
|
|
|
|
//
|
|
// The number of physical buffers in the entire packet.
|
|
//
|
|
UINT PhysicalBufferCount;
|
|
|
|
//
|
|
// Points to the current ndis buffer being walked.
|
|
//
|
|
PNDIS_BUFFER CurrentBuffer;
|
|
|
|
//
|
|
// Points to the mdl for the current ndis buffer.
|
|
//
|
|
NDIS_PHYSICAL_ADDRESS PointerToMdl;
|
|
|
|
//
|
|
// The virtual address of the current ndis buffer.
|
|
//
|
|
PVOID VirtualAddress;
|
|
|
|
//
|
|
// The length in bytes of the current ndis buffer.
|
|
//
|
|
UINT CurrentVirtualLength;
|
|
|
|
//
|
|
// The total amount of data contained within the ndis packet.
|
|
//
|
|
UINT TotalVirtualLength;
|
|
|
|
//
|
|
// Pointer into an array of physical pages numbers for the mdl.
|
|
//
|
|
PULONG PhysicalAddressElement;
|
|
|
|
//
|
|
// An actual physical address.
|
|
//
|
|
PHYSICAL_ADDRESS PhysicalAddress;
|
|
|
|
//
|
|
// The amount of memory used in the current physical
|
|
// page for the buffer.
|
|
//
|
|
UINT LengthOfPhysicalBuffer;
|
|
|
|
//
|
|
// Holds the number of Ndis buffers that we have queried.
|
|
//
|
|
UINT NdisBuffersExamined;
|
|
|
|
//
|
|
// The total amount of virtual memory in bytes contained in all of the
|
|
// ndis buffers examined.
|
|
//
|
|
UINT VirtualMemoryPassed;
|
|
|
|
|
|
//
|
|
// Get the first buffer.
|
|
//
|
|
|
|
NdisQueryPacket(
|
|
Packet,
|
|
&PhysicalBufferCount,
|
|
&NdisBufferCount,
|
|
&CurrentBuffer,
|
|
&TotalVirtualLength
|
|
);
|
|
|
|
NdisQueryBuffer(
|
|
CurrentBuffer,
|
|
&PointerToMdl,
|
|
&VirtualAddress,
|
|
&CurrentVirtualLength
|
|
);
|
|
|
|
//
|
|
// Certain hardware implementation (Decstation) use a dual ported
|
|
// memory to communicate with the hardware. This is reasonable since
|
|
// it reduces bus contention. When using the dual ported memory, all
|
|
// send data must be moved to buffers allocated from the dual ported
|
|
// memory.
|
|
//
|
|
// #ifdef PC586_USE_HARDWARE_MEMORY
|
|
|
|
VirtualMemoryPassed = TotalVirtualLength;
|
|
NdisBuffersExamined = NdisBufferCount;
|
|
|
|
// #else // PC586_USE_HARDWARE_MEMORY
|
|
|
|
//
|
|
// In the interests of keeping silo underflow from occuring
|
|
// we might want to disable data chaining. In this case the
|
|
// only time we don't copy to the adapters buffers is if there
|
|
// is only one physical buffer in the packet and it is greater
|
|
// than the minimum single buffer length.
|
|
|
|
// #endif // PC586_USE_HARDDWARE_MEMORY
|
|
|
|
Reserved->STAGE.STAGE1.MinimumBufferRequirements = 3;
|
|
|
|
Reserved->STAGE.STAGE1.NdisBuffersToMove = NdisBuffersExamined;
|
|
|
|
}
|
|
|
|
|
|
static
|
|
VOID
|
|
MovePacketToStage2(
|
|
IN PPC586_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Move a packet from the stage 1 allocation to stage 2 allocation.
|
|
|
|
Arguments:
|
|
|
|
Adapter - The adapter that the packets are coming through.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PNDIS_PACKET PacketToMove = Adapter->FirstStage1Packet;
|
|
|
|
//
|
|
// First remove it from the stage 1 queue;
|
|
//
|
|
|
|
Adapter->FirstStage1Packet =
|
|
PPC586_RESERVED_FROM_PACKET(PacketToMove)->Next;
|
|
|
|
if (!Adapter->FirstStage1Packet) {
|
|
|
|
Adapter->LastStage1Packet = NULL;
|
|
|
|
}
|
|
|
|
//
|
|
// Now put it on the stage 2 queue.
|
|
//
|
|
|
|
if (!Adapter->FirstStage2Packet) {
|
|
|
|
Adapter->FirstStage2Packet = PacketToMove;
|
|
|
|
} else {
|
|
|
|
PPC586_RESERVED_FROM_PACKET(Adapter->LastStage2Packet)->Next =
|
|
PacketToMove;
|
|
|
|
|
|
}
|
|
|
|
Adapter->LastStage2Packet = PacketToMove;
|
|
PPC586_RESERVED_FROM_PACKET(PacketToMove)->Next = NULL;
|
|
}
|
|
|
|
static
|
|
VOID
|
|
MovePacketToStage3(
|
|
IN PPC586_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Move a packet from the stage 2 allocation to stage 3 allocation.
|
|
|
|
Arguments:
|
|
|
|
Adapter - The adapter that the packets are coming through.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PNDIS_PACKET PacketToMove = Adapter->FirstStage2Packet;
|
|
|
|
//
|
|
// First remove it from the stage 2 queue.
|
|
//
|
|
|
|
Adapter->FirstStage2Packet =
|
|
PPC586_RESERVED_FROM_PACKET(PacketToMove)->Next;
|
|
|
|
if (!Adapter->FirstStage2Packet) {
|
|
|
|
Adapter->LastStage2Packet = NULL;
|
|
|
|
}
|
|
|
|
//
|
|
// Now put it on the stage 3 queue.
|
|
//
|
|
|
|
if (!Adapter->FirstStage3Packet) {
|
|
|
|
Adapter->FirstStage3Packet = PacketToMove;
|
|
|
|
} else {
|
|
|
|
PPC586_RESERVED_FROM_PACKET(Adapter->LastStage3Packet)->Next =
|
|
PacketToMove;
|
|
|
|
|
|
}
|
|
|
|
Adapter->LastStage3Packet = PacketToMove;
|
|
PPC586_RESERVED_FROM_PACKET(PacketToMove)->Next = NULL;
|
|
|
|
}
|
|
|
|
static
|
|
VOID
|
|
RemovePacketFromStage3(
|
|
IN PPC586_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes a the packet from the from of the stage 3 allocation
|
|
list.
|
|
|
|
Arguments:
|
|
|
|
Adapter - The adapter that the packets are coming through.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PNDIS_PACKET PacketToRemove = Adapter->FirstStage3Packet;
|
|
|
|
//
|
|
// Holds the destination address of the packet.
|
|
//
|
|
CHAR Address[MAC_LENGTH_OF_ADDRESS];
|
|
|
|
//
|
|
// Holds the length of data we got from getting the
|
|
// address from the packet.
|
|
//
|
|
UINT AddressLength;
|
|
|
|
|
|
//
|
|
// First remove it from stage 3.
|
|
//
|
|
|
|
Adapter->FirstStage3Packet =
|
|
PPC586_RESERVED_FROM_PACKET(PacketToRemove)->Next;
|
|
|
|
if (!Adapter->FirstStage3Packet) {
|
|
|
|
Adapter->LastStage3Packet = NULL;
|
|
|
|
}
|
|
|
|
//
|
|
// Do a quick check to see if the packet has a high likelyhood
|
|
// of needing to loopback. (NOTE: This means that if the packet
|
|
// must be loopbacked then this function will return true. If
|
|
// the packet doesn't need to be loopbacked then the function
|
|
// will probably return false.)
|
|
//
|
|
|
|
Pc586CopyFromPacketToBuffer(
|
|
PacketToRemove,
|
|
0,
|
|
MAC_LENGTH_OF_ADDRESS,
|
|
Address,
|
|
&AddressLength
|
|
);
|
|
ASSERT(AddressLength == MAC_LENGTH_OF_ADDRESS);
|
|
|
|
if (MacShouldAddressLoopBack(
|
|
Adapter->FilterDB,
|
|
Address
|
|
)) {
|
|
|
|
Pc586PutPacketOnLoopBack(
|
|
Adapter,
|
|
PacketToRemove,
|
|
FALSE
|
|
);
|
|
|
|
} else {
|
|
|
|
Pc586PutPacketOnFinishTrans(
|
|
Adapter,
|
|
PacketToRemove
|
|
);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
static
|
|
VOID
|
|
RelinquishPacket(
|
|
IN PPC586_ADAPTER Adapter,
|
|
IN PNDIS_PACKET Packet,
|
|
)
|
|
|
|
/*++
|
|
|
|
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 first ring
|
|
entry for the packet.
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
// FOURTH MAKE 586 DO A TRANSMIT
|
|
|
|
NdisAcquireSpinLock(&Adapter->Lock);
|
|
WaitScb(Adapter);
|
|
|
|
Adapter->Scb->ScbCmd = SCBCUCSTRT;
|
|
ChanAttn(Adapter);
|
|
|
|
NdisReleaseSpinLock(&Adapter->Lock);
|
|
|
|
}
|
|
|
|
|