Windows NT 4.0 source code leak
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

/*++
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;
}