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.
437 lines
10 KiB
437 lines
10 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
send.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.
|
|
|
|
Author:
|
|
|
|
Anthony V. Ercolano (Tonye) 12-Sept-1990
|
|
|
|
Environment:
|
|
|
|
Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
|
|
|
|
Revision History:
|
|
|
|
31-Jul-1992 R.D. Lanser:
|
|
|
|
Removed PhysicalBuffersContained and UsedLanceBuffer field from
|
|
_ADAPTER structure. SeanSe says that the code related to this
|
|
field was used for adevice that is no longer supported. I removed
|
|
the dependent code(or at least what was obvious) from 'send.c'.
|
|
This old code was generating an erroneous ring buffer count on the
|
|
MIPS R3000. I did not test it on the MIPS R4000. The problem goes
|
|
away with the removal of the offending code.
|
|
|
|
--*/
|
|
|
|
#include <ndis.h>
|
|
#include <lancehrd.h>
|
|
#include <lancesft.h>
|
|
|
|
|
|
//
|
|
// Minimum packet size that a transport can send. We subtract 4 bytes
|
|
// because we add a 4 byte CRC on the end.
|
|
//
|
|
|
|
#define MIN_SINGLE_BUFFER ((UINT)LANCE_SMALL_BUFFER_SIZE - 4)
|
|
|
|
|
|
//
|
|
// It will poke the lance 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) \
|
|
LANCE_WRITE_RDP( \
|
|
A, \
|
|
LANCE_CSR0_TRANSMIT_DEMAND | LANCE_CSR0_INTERRUPT_ENABLE \
|
|
);
|
|
|
|
extern
|
|
NDIS_STATUS
|
|
LanceSend(
|
|
IN NDIS_HANDLE MiniportAdapterContext,
|
|
IN PNDIS_PACKET Packet,
|
|
IN UINT Flags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The LanceSend request instructs a MAC to transmit a packet through
|
|
the adapter onto the medium.
|
|
|
|
Arguments:
|
|
|
|
Status - The status of the operation.
|
|
|
|
MiniportAdapterContext - The context value set by the mini-port.
|
|
|
|
Packet - A pointer to a descriptor for the packet that is to be
|
|
transmitted.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Pointer to the adapter.
|
|
//
|
|
PLANCE_ADAPTER Adapter = (PLANCE_ADAPTER)MiniportAdapterContext;
|
|
|
|
//
|
|
// Pointer to the ring entry to be filled with buffer information.
|
|
//
|
|
PLANCE_TRANSMIT_ENTRY CurrentRingElement;
|
|
|
|
//
|
|
// Pointer to the ring to packet entry that records the info about
|
|
// this packet.
|
|
//
|
|
PLANCE_RING_TO_PACKET RingToPacket;
|
|
|
|
//
|
|
// Length of the packet
|
|
//
|
|
ULONG TotalVirtualLength;
|
|
|
|
//
|
|
// Holds the adapter buffer index available for allocation.
|
|
//
|
|
INT LanceBuffersIndex;
|
|
|
|
//
|
|
// Points to a successfully allocated adapter buffer descriptor.
|
|
//
|
|
PLANCE_BUFFER_DESCRIPTOR BufferDescriptor;
|
|
|
|
//
|
|
// Simple iteration variable.
|
|
//
|
|
INT i;
|
|
|
|
//
|
|
// Size of Lance Buffer needed (1==Small, 2==Medium, 3==Large)
|
|
//
|
|
UCHAR BufferSize;
|
|
|
|
//
|
|
// If we successfully acquire some ring entries, this
|
|
// is the index of the first one.
|
|
//
|
|
UINT RingIndex;
|
|
|
|
//
|
|
// Will point into the virtual address space addressed
|
|
// by the adapter buffer if one was successfully allocated.
|
|
//
|
|
PCHAR CurrentDestination;
|
|
|
|
//
|
|
// 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;
|
|
|
|
NDIS_STATUS Status;
|
|
|
|
#if LANCE_TRACE
|
|
DbgPrint("In LanceSend\n");
|
|
#endif
|
|
|
|
if (Adapter->HardwareFailure) {
|
|
|
|
return(NDIS_STATUS_FAILURE);
|
|
|
|
}
|
|
|
|
LOG(IN_SEND);
|
|
|
|
if (!Adapter->ResetInProgress) {
|
|
|
|
if (Adapter->NumberOfAvailableRings == 0) {
|
|
|
|
return(NDIS_STATUS_RESOURCES);
|
|
|
|
}
|
|
|
|
//
|
|
// 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,
|
|
&SourceBuffer,
|
|
&TotalVirtualLength
|
|
);
|
|
|
|
if ((!TotalVirtualLength) ||
|
|
(TotalVirtualLength > LANCE_LARGE_BUFFER_SIZE)) {
|
|
|
|
return(NDIS_STATUS_RESOURCES);
|
|
|
|
} else {
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
if (TotalVirtualLength <= LANCE_SMALL_BUFFER_SIZE) {
|
|
|
|
BufferSize = 1;
|
|
|
|
} else if (TotalVirtualLength <= LANCE_MEDIUM_BUFFER_SIZE) {
|
|
|
|
BufferSize = 2;
|
|
|
|
} else {
|
|
|
|
BufferSize = 3;
|
|
|
|
}
|
|
|
|
//
|
|
// Find a buffer
|
|
//
|
|
for (
|
|
i = BufferSize;
|
|
i <= 3;
|
|
i++
|
|
) {
|
|
|
|
if ((LanceBuffersIndex = Adapter->LanceBufferListHeads[i]) != -1) {
|
|
|
|
BufferDescriptor = Adapter->LanceBuffers + LanceBuffersIndex;
|
|
Adapter->LanceBufferListHeads[i] = BufferDescriptor->Next;
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (LanceBuffersIndex == -1) {
|
|
|
|
//
|
|
// Nothing available for the packet.
|
|
//
|
|
|
|
return NDIS_STATUS_RESOURCES;
|
|
|
|
}
|
|
|
|
//
|
|
// Save the list head index in the buffer descriptor
|
|
// to permit easy deallocation later.
|
|
//
|
|
BufferDescriptor->Next = i;
|
|
|
|
//
|
|
// Now Acquire the ring
|
|
//
|
|
RingIndex = Adapter->AllocateableRing - Adapter->TransmitRing;
|
|
|
|
//
|
|
// Store the info
|
|
//
|
|
CurrentRingElement = Adapter->AllocateableRing;
|
|
|
|
//
|
|
// NOTE NOTE NOTE NOTE NOTE NOTE
|
|
//
|
|
// We can do the next calculation because we know that the number
|
|
// or ring entries is a power of two!
|
|
//
|
|
|
|
Adapter->AllocateableRing = Adapter->TransmitRing +
|
|
(((RingIndex) + 1) &
|
|
(Adapter->NumberOfTransmitRings-1));
|
|
|
|
Adapter->NumberOfAvailableRings--;
|
|
|
|
//
|
|
// Copy into buffer
|
|
//
|
|
|
|
CurrentDestination = BufferDescriptor->VirtualLanceBuffer;
|
|
|
|
while ( SourceBuffer != NULL ) {
|
|
|
|
NdisQueryBuffer(
|
|
SourceBuffer,
|
|
&SourceData,
|
|
&SourceLength
|
|
);
|
|
|
|
LANCE_MOVE_MEMORY_TO_HARDWARE(
|
|
CurrentDestination,
|
|
SourceData,
|
|
SourceLength
|
|
);
|
|
|
|
CurrentDestination = (PCHAR)CurrentDestination + 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 (TotalVirtualLength < MIN_SINGLE_BUFFER) {
|
|
|
|
LANCE_ZERO_MEMORY_FOR_HARDWARE(
|
|
CurrentDestination,
|
|
MIN_SINGLE_BUFFER - TotalVirtualLength
|
|
);
|
|
|
|
BufferDescriptor->DataLength = MIN_SINGLE_BUFFER;
|
|
|
|
} else {
|
|
|
|
BufferDescriptor->DataLength = TotalVirtualLength;
|
|
|
|
}
|
|
|
|
//
|
|
// Get the position for mapping ring entries to packets.
|
|
// We record the owning packet information in the ring packet packet
|
|
// structure.
|
|
//
|
|
RingToPacket = Adapter->RingToPacket + RingIndex;
|
|
RingToPacket->OwningPacket = Packet;
|
|
RingToPacket->LanceBuffersIndex = LanceBuffersIndex;
|
|
RingToPacket->RingIndex = RingIndex;
|
|
|
|
//
|
|
// Make sure that the ring descriptor is clean.
|
|
//
|
|
|
|
LANCE_ZERO_MEMORY_FOR_HARDWARE((PUCHAR)CurrentRingElement,
|
|
sizeof(LANCE_TRANSMIT_ENTRY)
|
|
);
|
|
|
|
LANCE_SET_TRANSMIT_BUFFER_LENGTH(
|
|
CurrentRingElement,
|
|
BufferDescriptor->DataLength
|
|
);
|
|
|
|
|
|
LANCE_SET_TRANSMIT_BUFFER_ADDRESS(
|
|
Adapter,
|
|
CurrentRingElement,
|
|
BufferDescriptor->VirtualLanceBuffer
|
|
);
|
|
|
|
LOG(TRANSMIT);
|
|
|
|
//
|
|
// We update the ring ownership of the last packet under
|
|
// the protection of the lock so that the uncommitted packet
|
|
// pointer can be updated before the transmit post processing
|
|
// can examine it.
|
|
//
|
|
|
|
LANCE_SET_RING_BITS(
|
|
CurrentRingElement->TransmitSummaryBits,
|
|
LANCE_TRANSMIT_START_OF_PACKET |
|
|
LANCE_TRANSMIT_OWNED_BY_CHIP |
|
|
LANCE_TRANSMIT_END_OF_PACKET
|
|
);
|
|
|
|
|
|
if (RingIndex == (Adapter->NumberOfTransmitRings-1)) {
|
|
|
|
Adapter->FirstUncommittedRing = Adapter->TransmitRing ;
|
|
|
|
} else {
|
|
|
|
Adapter->FirstUncommittedRing = Adapter->TransmitRing + RingIndex + 1;
|
|
|
|
}
|
|
|
|
//
|
|
// Prod the chip into checking for packets to send.
|
|
//
|
|
|
|
PROD_TRANSMIT(Adapter);
|
|
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
} else if (Adapter->ResetRequestType == NdisRequestGeneric1) {
|
|
|
|
Status = NDIS_STATUS_RESET_IN_PROGRESS;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Have the upper layer try again later
|
|
//
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
|
|
}
|
|
|
|
LOG(OUT_SEND);
|
|
|
|
LANCE_DO_DEFERRED(Adapter);
|
|
|
|
#if LANCE_TRACE
|
|
DbgPrint("Out LanceSend\n");
|
|
#endif
|
|
|
|
return Status;
|
|
}
|
|
|