diff options
Diffstat (limited to 'private/ntos/ndis/sonic')
-rw-r--r-- | private/ntos/ndis/sonic/alloc.c | 1137 | ||||
-rw-r--r-- | private/ntos/ndis/sonic/i386/sonicdet.h | 68 | ||||
-rw-r--r-- | private/ntos/ndis/sonic/interrup.c | 1694 | ||||
-rw-r--r-- | private/ntos/ndis/sonic/makefile | 6 | ||||
-rw-r--r-- | private/ntos/ndis/sonic/mips/sonicdet.h | 89 | ||||
-rw-r--r-- | private/ntos/ndis/sonic/request.c | 890 | ||||
-rw-r--r-- | private/ntos/ndis/sonic/send.c | 1305 | ||||
-rw-r--r-- | private/ntos/ndis/sonic/sonic.c | 2800 | ||||
-rw-r--r-- | private/ntos/ndis/sonic/sonic.rc | 39 | ||||
-rw-r--r-- | private/ntos/ndis/sonic/sonichrd.h | 791 | ||||
-rw-r--r-- | private/ntos/ndis/sonic/sonicsft.h | 1039 | ||||
-rw-r--r-- | private/ntos/ndis/sonic/sources | 61 | ||||
-rw-r--r-- | private/ntos/ndis/sonic/transfer.c | 247 |
13 files changed, 10166 insertions, 0 deletions
diff --git a/private/ntos/ndis/sonic/alloc.c b/private/ntos/ndis/sonic/alloc.c new file mode 100644 index 000000000..354461735 --- /dev/null +++ b/private/ntos/ndis/sonic/alloc.c @@ -0,0 +1,1137 @@ +/*++ + +Copyright (c) 1990-1992 Microsoft Corporation + +Module Name: + + alloc.c + +Abstract: + + This file contains the code for allocating and freeing adapter + resources for the National Semiconductor SONIC Ethernet controller. + This driver conforms to the NDIS 3.0 miniport interface. + +Author: + + Adam Barr (adamba) 14-Nov-1990 + +Environment: + + Kernel Mode - Or whatever is the equivalent. + +Revision History: + + +--*/ + +#include <ndis.h> +#include <sonichrd.h> +#include <sonicsft.h> + + + +STATIC +PNDIS_BUFFER +AllocateFlushBuffer( + IN PSONIC_ADAPTER Adapter, + IN PVOID VirtualAddress, + IN ULONG Length + ); + + +#pragma NDIS_INIT_FUNCTION(AllocateFlushBuffer) + +STATIC +PNDIS_BUFFER +AllocateFlushBuffer( + IN PSONIC_ADAPTER Adapter, + IN PVOID VirtualAddress, + IN ULONG Length + ) + +/*++ + +Routine Description: + + Allocates an NDIS_BUFFER for the specified address and length. + This function is intended to create NDIS_BUFFERs for flushing. + +Arguments: + + Adapter - The adapter the buffer is for. It must have a + FlushBufferPoolHandle that points to a valid buffer pool. + + VirtualAddress - A pointer to the buffer to describe. + + Length - The length of the buffer. + +Return Value: + + The NDIS_BUFFER if one was allocated. + NULL if an NDIS_BUFFER could not be allocated. + +--*/ + +{ + PNDIS_BUFFER ReturnBuffer; + NDIS_STATUS Status; + + NdisAllocateBuffer( + &Status, + &ReturnBuffer, + Adapter->FlushBufferPoolHandle, + VirtualAddress, + Length + ); + + if (Status != NDIS_STATUS_SUCCESS) { + +#if DBG + DbgPrint("SONIC: Could not allocate flush buffer, %x\n", Status); +#endif + ReturnBuffer = (PNDIS_BUFFER)NULL; + } + + + return ReturnBuffer; +} + + +#pragma NDIS_INIT_FUNCTION(AllocateAdapterMemory) + +extern +BOOLEAN +AllocateAdapterMemory( + IN PSONIC_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine allocates memory for: + + - Transmit ring entries + + - Receive ring entries + + - Receive buffers + + - Adapter buffers for use if user transmit buffers don't meet hardware + contraints + + - Structures to map transmit ring entries back to the packets. + +Arguments: + + Adapter - The adapter to allocate memory for. + +Return Value: + + Returns FALSE if some memory needed for the adapter could not + be allocated. It does NOT call DeleteAdapterMemory in this + case. + +--*/ + +{ + + // + // Pointer to a transmit ring entry. Used while initializing + // the TDA. + // + PSONIC_TRANSMIT_DESCRIPTOR CurrentTransmitDescriptor; + + // + // Pointer to a receive buffer. Used while allocated the + // RBAs. + // + PVOID * CurrentReceiveBuffer; + + // + // Pointer to a receive descriptor. Used while initialing + // the RDA. + // + PSONIC_RECEIVE_DESCRIPTOR CurrentReceiveDescriptor; + + // + // Used for determining physical addresses. + // + SONIC_PHYSICAL_ADDRESS SonicPhysicalAdr; + + // + // Used for NDIS allocation routines that return an NDIS_PHYSICAL_ADDRESS + // + NDIS_PHYSICAL_ADDRESS NdisPhysicalAdr; + + // + // Simple iteration variable. + // + UINT i; + + // + // Used to flush buffers that only need to be flushed once. + // + PNDIS_BUFFER FlushBuffer; + + // + // The size of the buffer pool needed. + // + UINT PoolBuffersNeeded; + + // + // Holds the result of calls to SONIC_ALLOC_MEMORY + // + NDIS_STATUS AllocStatus; + + + + // + // We need some NDIS_BUFFERs to describe memory that we + // allocate (generally either to flush the buffer, or + // because we need its physical address). To do this + // we need a buffer pool, so we have to determine how + // many buffers we need. + // + PoolBuffersNeeded = + 1 + // for CamDescriptorArea + 1 + // for ReceiveResourceArea + 1 + // for BlankBuffer + Adapter->NumberOfReceiveBuffers + // for flushing cached receive buffers. + SONIC_NUMBER_OF_SMALL_BUFFERS + + SONIC_NUMBER_OF_MEDIUM_BUFFERS + + SONIC_NUMBER_OF_LARGE_BUFFERS ; + + NdisAllocateBufferPool( + &AllocStatus, + &Adapter->FlushBufferPoolHandle, + PoolBuffersNeeded + ); + + if (AllocStatus != NDIS_STATUS_SUCCESS) { + +#if DBG + DbgPrint("SONIC: Could not allocate flush buffer pool\n"); +#endif + return FALSE; + + } + + + + // + // Allocate the transmit ring descriptors. + // + + NdisMAllocateSharedMemory( + Adapter->MiniportAdapterHandle, + sizeof(SONIC_TRANSMIT_DESCRIPTOR)* + Adapter->NumberOfTransmitDescriptors, + FALSE, // non-cached + (PVOID *)&Adapter->TransmitDescriptorArea, + &Adapter->TransmitDescriptorAreaPhysical + ); + + if (Adapter->TransmitDescriptorArea == NULL) { + +#if DBG + DbgPrint("SONIC: TransmitDescriptorArea memory invalid\n"); +#endif + return FALSE; + + } + + if (NdisGetPhysicalAddressHigh(Adapter->TransmitDescriptorAreaPhysical) != 0) { + +#if DBG + DbgPrint("SONIC: TransmitDescriptorArea memory too high\n"); +#endif + return FALSE; + } + + + + // + // Clean the above memory + // + + SONIC_ZERO_MEMORY( + Adapter->TransmitDescriptorArea, + (sizeof(SONIC_TRANSMIT_DESCRIPTOR)*Adapter->NumberOfTransmitDescriptors) + ); + + + // + // We have the transmit ring descriptors. Initialize the Link + // fields. + // + + for ( + i = 0, CurrentTransmitDescriptor = Adapter->TransmitDescriptorArea; + i < Adapter->NumberOfTransmitDescriptors; + i++,CurrentTransmitDescriptor++ + ) { + + SonicPhysicalAdr = NdisGetPhysicalAddressLow(Adapter->TransmitDescriptorAreaPhysical) + + (i * sizeof(SONIC_TRANSMIT_DESCRIPTOR)); + + if (i == 0) { + + Adapter->TransmitDescriptorArea[Adapter->NumberOfTransmitDescriptors-1].Link = SonicPhysicalAdr; + + } else { + + (CurrentTransmitDescriptor-1)->Link = SonicPhysicalAdr; + + } + + } + + + // + // Allocate the ring to packet structure. + // + + SONIC_ALLOC_MEMORY( + &AllocStatus, + &Adapter->DescriptorToPacket, + sizeof(SONIC_DESCRIPTOR_TO_PACKET) + *Adapter->NumberOfTransmitDescriptors + ); + + if (AllocStatus != NDIS_STATUS_SUCCESS) { + return FALSE; + } + + + // + // We have to do this now. The PrevLinkPointer field is used + // to point to where the Link field of the previous transmit + // descriptor is; it is normally set when the previous + // transmit descriptor is filled. For the very first packet + // transmitted there will have been no previous transmit + // descriptor, so we fill it in ourselves. We use the + // Link field of the last transmit descriptor (the actual + // location used doesn't really matter, as long as it is + // a valid address). + // + + Adapter->DescriptorToPacket->PrevLinkPointer = + &(Adapter->TransmitDescriptorArea[ + Adapter->NumberOfTransmitDescriptors-1].Link); + + + // + // Allocate the receive resource area and the + // CAM descriptor area. These are allocated together + // since they must have the same high 16 bits in + // their addresses. + // + + NdisMAllocateSharedMemory( + Adapter->MiniportAdapterHandle, + (sizeof(SONIC_RECEIVE_RESOURCE)*Adapter->NumberOfReceiveBuffers) + + sizeof(SONIC_CAM_DESCRIPTOR_AREA), + TRUE, // CACHED! + (PVOID *)&Adapter->ReceiveResourceArea, + &Adapter->ReceiveResourceAreaPhysical + ); + + if (Adapter->ReceiveResourceArea == NULL) { + +#if DBG + DbgPrint("SONIC: ReceiveResourceArea memory invalid\n"); +#endif + return FALSE; + + } + + if (NdisGetPhysicalAddressHigh(Adapter->ReceiveResourceAreaPhysical) != 0) { + +#if DBG + DbgPrint("SONIC: ReceiveResourceArea memory too high\n"); +#endif + return FALSE; + + } + + + // + // The CAM Descriptor Area is immediately after the RRA. + // + + Adapter->CamDescriptorArea = (PSONIC_CAM_DESCRIPTOR_AREA) + (Adapter->ReceiveResourceArea + Adapter->NumberOfReceiveBuffers); + + Adapter->CamDescriptorAreaPhysical = + NdisGetPhysicalAddressLow(Adapter->ReceiveResourceAreaPhysical) + + ((PUCHAR)Adapter->CamDescriptorArea - + (PUCHAR)Adapter->ReceiveResourceArea); + + + // + // Allocate the NDIS_BUFFER to flush the CAM Descriptor Area. + // + Adapter->CamDescriptorAreaFlushBuffer = AllocateFlushBuffer( + Adapter, + Adapter->CamDescriptorArea, + sizeof(SONIC_CAM_DESCRIPTOR_AREA) + ); + + if (!Adapter->CamDescriptorAreaFlushBuffer) { + return FALSE; + } + + SONIC_ZERO_MEMORY( + Adapter->CamDescriptorArea, + sizeof(SONIC_CAM_DESCRIPTOR_AREA) + ); + + SONIC_FLUSH_WRITE_BUFFER(Adapter->CamDescriptorAreaFlushBuffer); + + +#if DBG + if (SonicDbg) { + DbgPrint("SONIC: Cam Descriptor Area: %lx physical: %lx\n", + Adapter->CamDescriptorArea, + Adapter->CamDescriptorAreaPhysical); + } +#endif + + // + // Allocate the array to hold pointers to the RBAs. + // + + SONIC_ALLOC_MEMORY( + &AllocStatus, + &Adapter->ReceiveBufferArea, + sizeof(PVOID) * Adapter->NumberOfReceiveBuffers + ); + + if (AllocStatus != NDIS_STATUS_SUCCESS) { + + return FALSE; + } + + // + // Allocate the array to hold pointers to the receive ndis + // (flush) buffers. + // + + SONIC_ALLOC_MEMORY( + &AllocStatus, + &Adapter->ReceiveNdisBufferArea, + sizeof(PNDIS_BUFFER) * Adapter->NumberOfReceiveBuffers + ); + + if (AllocStatus != NDIS_STATUS_SUCCESS) { + + return FALSE; + } + +#if DBG + if (SonicDbg) { + DbgPrint("SONIC: Receive Buffer Area: %lx\n", + (ULONG)Adapter->ReceiveBufferArea); + } +#endif + + + // + // We have the receive buffer pointers. Allocate the buffer + // for each entry and zero them. + // + // For each receive buffer, the Physical address and length + // will be in Adapter->ReceiveResourceArea[i], while the + // virtual address will be in Adapter->ReceiveBufferArea[i]. + // + + for ( + i = 0, CurrentReceiveBuffer = Adapter->ReceiveBufferArea; + i < Adapter->NumberOfReceiveBuffers; + i++,CurrentReceiveBuffer++ + ) { + + // + // Allocate the next [cached] receive buffer. + // + + NdisMAllocateSharedMemory( + Adapter->MiniportAdapterHandle, + SONIC_SIZE_OF_RECEIVE_BUFFERS, + TRUE, // CACHED! + CurrentReceiveBuffer, + &NdisPhysicalAdr + ); + + // + // Did the allocation fail? + // + + if ( *CurrentReceiveBuffer == NULL ) { + + return FALSE; + } + + if ( NdisGetPhysicalAddressHigh(NdisPhysicalAdr) != 0) { + + return FALSE; + } + + // + // Zero the [cached] receive buffer. + // + + SONIC_ZERO_MEMORY( + *CurrentReceiveBuffer, + SONIC_SIZE_OF_RECEIVE_BUFFERS + ); + + + // + // Allocate an NDIS_BUFFER for this receive buffer. + // + + Adapter->ReceiveNdisBufferArea[i] = AllocateFlushBuffer( + Adapter, + *CurrentReceiveBuffer, + SONIC_SIZE_OF_RECEIVE_BUFFERS + ); + + if ( Adapter->ReceiveNdisBufferArea[i] == NULL ) { + + return FALSE; + + } + + SONIC_SET_RECEIVE_RESOURCE_ADDRESS( + &Adapter->ReceiveResourceArea[i], + NdisGetPhysicalAddressLow(NdisPhysicalAdr) + ); + + SONIC_SET_RECEIVE_RESOURCE_LENGTH( + &Adapter->ReceiveResourceArea[i], + SONIC_SIZE_OF_RECEIVE_BUFFERS + ); + } + + + // + // The Receive Resource Area is set up, we can flush + // it now since it does not change. + // + + FlushBuffer = AllocateFlushBuffer( + Adapter, + (PVOID)Adapter->ReceiveResourceArea, + (sizeof(SONIC_RECEIVE_RESOURCE)*Adapter->NumberOfReceiveBuffers) + ); + + if (!FlushBuffer) { + return FALSE; + } + + SONIC_FLUSH_WRITE_BUFFER(FlushBuffer); + + NdisFreeBuffer(FlushBuffer); + + // + // Allocate memory to hold the receive descriptor pointers. + // + + NdisMAllocateSharedMemory( + Adapter->MiniportAdapterHandle, + sizeof(SONIC_RECEIVE_DESCRIPTOR) * Adapter->NumberOfReceiveDescriptors, + FALSE, // NON-CACHED! + (PVOID *)&Adapter->ReceiveDescriptorArea, + &Adapter->ReceiveDescriptorAreaPhysical + ); + + + if (Adapter->ReceiveDescriptorArea == NULL) { + +#if DBG + DbgPrint("SONIC: ReceiveDescriptorArea memory invalid\n"); +#endif + return FALSE; + + } + + if (NdisGetPhysicalAddressHigh(Adapter->ReceiveDescriptorAreaPhysical) != 0) { + +#if DBG + DbgPrint("SONIC: ReceiveDescriptorArea memory too high\n"); +#endif + return FALSE; + + } + + + + // + // Clean the above memory + // + + SONIC_ZERO_MEMORY( + Adapter->ReceiveDescriptorArea, + (sizeof(SONIC_RECEIVE_DESCRIPTOR)*Adapter->NumberOfReceiveDescriptors) + ); + + + // + // Now set up the Link fields in the receive descriptors. + // + + for ( + i = 0, CurrentReceiveDescriptor = Adapter->ReceiveDescriptorArea; + i < Adapter->NumberOfReceiveDescriptors; + i++,CurrentReceiveDescriptor++ + ) { + + // + // belongs to SONIC. + // + + CurrentReceiveDescriptor->InUse = SONIC_OWNED_BY_SONIC; + + SonicPhysicalAdr = NdisGetPhysicalAddressLow(Adapter->ReceiveDescriptorAreaPhysical) + + (i * sizeof(SONIC_RECEIVE_DESCRIPTOR)); + + if (i == 0) { + + Adapter->ReceiveDescriptorArea[ + Adapter->NumberOfReceiveDescriptors-1].Link = + SonicPhysicalAdr | SONIC_END_OF_LIST; + + } else { + + Adapter->ReceiveDescriptorArea[i-1].Link = SonicPhysicalAdr; + + } + + } + + + // + // Allocate the array of buffer descriptors. + // + + SONIC_ALLOC_MEMORY( + &AllocStatus, + &Adapter->SonicBuffers, + sizeof(SONIC_BUFFER_DESCRIPTOR)* + (SONIC_NUMBER_OF_SMALL_BUFFERS + + SONIC_NUMBER_OF_MEDIUM_BUFFERS + + SONIC_NUMBER_OF_LARGE_BUFFERS) + ); + + if (AllocStatus != NDIS_STATUS_SUCCESS) { + return FALSE; + } + + // + // Zero the memory of all the descriptors so that we can + // know which buffers wern't allocated incase we can't allocate + // them all. + // + SONIC_ZERO_MEMORY( + Adapter->SonicBuffers, + sizeof(SONIC_BUFFER_DESCRIPTOR)* + (SONIC_NUMBER_OF_SMALL_BUFFERS + + SONIC_NUMBER_OF_MEDIUM_BUFFERS + + SONIC_NUMBER_OF_LARGE_BUFFERS) + ); + + + // + // Allocate space for the small sonic buffers and fill in the + // buffer descriptors. + // + + Adapter->SonicBufferListHeads[0] = -1; + Adapter->SonicBufferListHeads[1] = 0; + + NdisMAllocateSharedMemory( + Adapter->MiniportAdapterHandle, + SONIC_SMALL_BUFFER_SIZE * SONIC_NUMBER_OF_SMALL_BUFFERS, + TRUE, // CACHED! + &Adapter->SmallSonicBuffers, + &NdisPhysicalAdr + ); + + if (NdisGetPhysicalAddressHigh(NdisPhysicalAdr) != 0) { + + return FALSE; + } + + if ( Adapter->SmallSonicBuffers == NULL ) { + + return FALSE; + } + + for ( + i = 0; + i < SONIC_NUMBER_OF_SMALL_BUFFERS; + i++ + ) { + + Adapter->SonicBuffers[i].VirtualSonicBuffer = (PVOID) + ((PUCHAR)Adapter->SmallSonicBuffers + + (i * SONIC_SMALL_BUFFER_SIZE)); + + NdisSetPhysicalAddressHigh( + Adapter->SonicBuffers[i].PhysicalSonicBuffer, + 0); + + NdisSetPhysicalAddressLow( + Adapter->SonicBuffers[i].PhysicalSonicBuffer, + NdisGetPhysicalAddressLow(NdisPhysicalAdr) + + (i * SONIC_SMALL_BUFFER_SIZE)); + + Adapter->SonicBuffers[i].FlushBuffer = + AllocateFlushBuffer( + Adapter, + Adapter->SonicBuffers[i].VirtualSonicBuffer, + SONIC_SMALL_BUFFER_SIZE + ); + + if (!Adapter->SonicBuffers[i].FlushBuffer) { + return FALSE; + } + + Adapter->SonicBuffers[i].Next = i+1; + + } + + // + // Make sure that the last buffer correctly terminates the free list. + // + + Adapter->SonicBuffers[i-1].Next = -1; + + // + // Do the medium buffers now. + // + + Adapter->SonicBufferListHeads[2] = i; + + NdisMAllocateSharedMemory( + Adapter->MiniportAdapterHandle, + SONIC_MEDIUM_BUFFER_SIZE * SONIC_NUMBER_OF_MEDIUM_BUFFERS, + TRUE, // CACHED! + &Adapter->MediumSonicBuffers, + &NdisPhysicalAdr + ); + + + if (Adapter->MediumSonicBuffers == NULL) { + return FALSE; + } + + if (NdisGetPhysicalAddressHigh(NdisPhysicalAdr) != 0) { + return FALSE; + } + + + + for ( + ; + i < SONIC_NUMBER_OF_SMALL_BUFFERS + SONIC_NUMBER_OF_MEDIUM_BUFFERS; + i++ + ) { + + Adapter->SonicBuffers[i].VirtualSonicBuffer = (PVOID) + ((PUCHAR)Adapter->MediumSonicBuffers + + ((i - SONIC_NUMBER_OF_SMALL_BUFFERS) * SONIC_MEDIUM_BUFFER_SIZE)); + + NdisSetPhysicalAddressHigh( + Adapter->SonicBuffers[i].PhysicalSonicBuffer, + 0); + + NdisSetPhysicalAddressLow( + Adapter->SonicBuffers[i].PhysicalSonicBuffer, + NdisGetPhysicalAddressLow(NdisPhysicalAdr) + + ((i - SONIC_NUMBER_OF_SMALL_BUFFERS) * SONIC_MEDIUM_BUFFER_SIZE)); + + + Adapter->SonicBuffers[i].FlushBuffer = + AllocateFlushBuffer( + Adapter, + Adapter->SonicBuffers[i].VirtualSonicBuffer, + SONIC_MEDIUM_BUFFER_SIZE + ); + + if (!Adapter->SonicBuffers[i].FlushBuffer) { + return FALSE; + } + + + Adapter->SonicBuffers[i].Next = i+1; + + } + + // + // Make sure that the last buffer correctly terminates the free list. + // + + Adapter->SonicBuffers[i-1].Next = -1; + + // + // Now do the large buffers; note that they have one + // Physical address per buffer. + // + + Adapter->SonicBufferListHeads[3] = i; + + for ( + ; + i < SONIC_NUMBER_OF_SMALL_BUFFERS + + SONIC_NUMBER_OF_MEDIUM_BUFFERS + + SONIC_NUMBER_OF_LARGE_BUFFERS; + i++ + ) { + + NdisMAllocateSharedMemory( + Adapter->MiniportAdapterHandle, + SONIC_LARGE_BUFFER_SIZE, + TRUE, // CACHED! + (PVOID *)&Adapter->SonicBuffers[i].VirtualSonicBuffer, + &Adapter->SonicBuffers[i].PhysicalSonicBuffer + ); + + if (Adapter->SonicBuffers[i].VirtualSonicBuffer == NULL) { + + return FALSE; + } + + if (NdisGetPhysicalAddressHigh(Adapter->SonicBuffers[i].PhysicalSonicBuffer) != 0) { + return FALSE; + } + + Adapter->SonicBuffers[i].FlushBuffer = + AllocateFlushBuffer( + Adapter, + Adapter->SonicBuffers[i].VirtualSonicBuffer, + SONIC_LARGE_BUFFER_SIZE + ); + + if (!Adapter->SonicBuffers[i].FlushBuffer) { + return FALSE; + } + + + Adapter->SonicBuffers[i].Next = i+1; + + } + + // + // Make sure that the last buffer correctly terminates the free list. + // + + Adapter->SonicBuffers[i-1].Next = -1; + + + // + // Allocate the BlankBuffer + // + + NdisMAllocateSharedMemory( + Adapter->MiniportAdapterHandle, + SONIC_SMALL_BUFFER_SIZE, + TRUE, // CACHED! + (PVOID *)&Adapter->BlankBuffer, + &Adapter->BlankBufferAddress + ); + + if (Adapter->BlankBuffer == NULL) { + return FALSE; + } + + if (NdisGetPhysicalAddressHigh(Adapter->BlankBufferAddress) != 0) { + return FALSE; + } + + for (i=0; i < SONIC_SMALL_BUFFER_SIZE; i++) { + + Adapter->BlankBuffer[i] = ' '; + + } + + + // + // Flush the blank buffer now, it never changes. + // + + FlushBuffer = AllocateFlushBuffer( + Adapter, + Adapter->BlankBuffer, + SONIC_SMALL_BUFFER_SIZE + ); + + if (!FlushBuffer) { + return FALSE; + } + + SONIC_FLUSH_WRITE_BUFFER(FlushBuffer); + + // + // We are done with the FlushBuffer. + // + + NdisFreeBuffer(FlushBuffer); + + + return TRUE; + +} + + +extern +VOID +DeleteAdapterMemory( + IN PSONIC_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine deallocates memory for: + + - Transmit ring entries + + - Receive ring entries + + - Receive buffers + + - Adapter buffers for use if user transmit buffers don't meet hardware + contraints + + - Structures to map transmit ring entries back to the packets. + +Arguments: + + Adapter - The adapter to deallocate memory for. + +Return Value: + + None. + +--*/ + +{ + + if (Adapter->TransmitDescriptorArea) { + + NdisMFreeSharedMemory( + Adapter->MiniportAdapterHandle, + sizeof(SONIC_TRANSMIT_DESCRIPTOR)* + Adapter->NumberOfTransmitDescriptors, + FALSE, + Adapter->TransmitDescriptorArea, + Adapter->TransmitDescriptorAreaPhysical + ); + + } + + if (Adapter->CamDescriptorAreaFlushBuffer) { + + NdisFreeBuffer(Adapter->CamDescriptorAreaFlushBuffer); + + } + + if (Adapter->ReceiveBufferArea) { + + UINT i; + NDIS_PHYSICAL_ADDRESS PhysicalAddr; + + for ( + i = 0; + i < Adapter->NumberOfReceiveBuffers; + i++ + ) { + + // + // Free the receive flush buffer. + // + + if ( Adapter->ReceiveNdisBufferArea[i] != NULL ) { + + NdisFreeBuffer(Adapter->ReceiveNdisBufferArea[i]); + + } + + // + // Free the receive buffer. + // + + if ( Adapter->ReceiveBufferArea[i] != NULL ) { + + NdisSetPhysicalAddressHigh(PhysicalAddr, 0); + + NdisSetPhysicalAddressLow( + PhysicalAddr, + SONIC_GET_RECEIVE_RESOURCE_ADDRESS(&Adapter->ReceiveResourceArea[i])); + + NdisMFreeSharedMemory( + Adapter->MiniportAdapterHandle, + SONIC_SIZE_OF_RECEIVE_BUFFERS, + TRUE, //... CACHED! + Adapter->ReceiveBufferArea[i], + PhysicalAddr + ); + } + } + + SONIC_FREE_MEMORY( + Adapter->ReceiveBufferArea, + sizeof(PVOID) * Adapter->NumberOfReceiveBuffers + ); + + SONIC_FREE_MEMORY( + Adapter->ReceiveNdisBufferArea, + sizeof(PNDIS_BUFFER) * Adapter->NumberOfReceiveBuffers + ); + } + + if (Adapter->ReceiveResourceArea) { + + NdisMFreeSharedMemory( + Adapter->MiniportAdapterHandle, + (sizeof(SONIC_RECEIVE_RESOURCE)*Adapter->NumberOfReceiveBuffers) + + sizeof(SONIC_CAM_DESCRIPTOR_AREA), + TRUE, + Adapter->ReceiveResourceArea, + Adapter->ReceiveResourceAreaPhysical + ); + + } + + if (Adapter->ReceiveDescriptorArea) { + + NdisMFreeSharedMemory( + Adapter->MiniportAdapterHandle, + sizeof(SONIC_RECEIVE_DESCRIPTOR) * + Adapter->NumberOfReceiveDescriptors, + FALSE, + Adapter->ReceiveDescriptorArea, + Adapter->ReceiveDescriptorAreaPhysical + ); + + } + + if (Adapter->DescriptorToPacket) { + + SONIC_FREE_MEMORY(Adapter->DescriptorToPacket, + sizeof(SONIC_DESCRIPTOR_TO_PACKET) + *Adapter->NumberOfTransmitDescriptors); + + } + + + if (Adapter->SmallSonicBuffers) { + + NdisMFreeSharedMemory( + Adapter->MiniportAdapterHandle, + SONIC_SMALL_BUFFER_SIZE * SONIC_NUMBER_OF_SMALL_BUFFERS, + TRUE, + Adapter->SmallSonicBuffers, + Adapter->SonicBuffers[0].PhysicalSonicBuffer + ); + + } + + if (Adapter->MediumSonicBuffers) { + + NdisMFreeSharedMemory( + Adapter->MiniportAdapterHandle, + SONIC_MEDIUM_BUFFER_SIZE * SONIC_NUMBER_OF_MEDIUM_BUFFERS, + TRUE, + Adapter->MediumSonicBuffers, + Adapter->SonicBuffers[SONIC_NUMBER_OF_SMALL_BUFFERS].PhysicalSonicBuffer + ); + + } + + if (Adapter->SonicBuffers) { + + UINT i; + + // + // First free the large buffers. + // + + for ( + i = SONIC_NUMBER_OF_SMALL_BUFFERS + + SONIC_NUMBER_OF_MEDIUM_BUFFERS; + i < SONIC_NUMBER_OF_SMALL_BUFFERS + + SONIC_NUMBER_OF_MEDIUM_BUFFERS + + SONIC_NUMBER_OF_LARGE_BUFFERS; + i++) { + + if (Adapter->SonicBuffers[i].VirtualSonicBuffer) { + + NdisMFreeSharedMemory( + Adapter->MiniportAdapterHandle, + SONIC_LARGE_BUFFER_SIZE, + TRUE, + Adapter->SonicBuffers[i].VirtualSonicBuffer, + Adapter->SonicBuffers[i].PhysicalSonicBuffer + ); + + } else { + + break; + + } + + } + + // + // Now free the flush buffers. + // + + for ( + i = 0; + i < SONIC_NUMBER_OF_SMALL_BUFFERS + + SONIC_NUMBER_OF_MEDIUM_BUFFERS + + SONIC_NUMBER_OF_LARGE_BUFFERS; + i++) { + + if (Adapter->SonicBuffers[i].FlushBuffer) { + NdisFreeBuffer(Adapter->SonicBuffers[i].FlushBuffer); + } + + } + + SONIC_FREE_MEMORY(Adapter->SonicBuffers, + sizeof(SONIC_BUFFER_DESCRIPTOR)* + (SONIC_NUMBER_OF_SMALL_BUFFERS + + SONIC_NUMBER_OF_MEDIUM_BUFFERS + + SONIC_NUMBER_OF_LARGE_BUFFERS) + ); + + } + + + if (Adapter->BlankBuffer) { + + NdisMFreeSharedMemory( + Adapter->MiniportAdapterHandle, + SONIC_SMALL_BUFFER_SIZE, + TRUE, + Adapter->BlankBuffer, + Adapter->BlankBufferAddress + ); + + } + + + if (Adapter->FlushBufferPoolHandle) { + + NdisFreeBufferPool(Adapter->FlushBufferPoolHandle); + + } + +} diff --git a/private/ntos/ndis/sonic/i386/sonicdet.h b/private/ntos/ndis/sonic/i386/sonicdet.h new file mode 100644 index 000000000..e318ed667 --- /dev/null +++ b/private/ntos/ndis/sonic/i386/sonicdet.h @@ -0,0 +1,68 @@ +/*++ + +Copyright (c) 1990-1992 Microsoft Corporation + +Module Name: + + sonicdet.h + +Abstract: + + This file has processor-specific definitions. + + The overall structure is taken from the Lance driver + by Tony Ercolano. + +Author: + + Anthony V. Ercolano (tonye) creation-date 19-Jun-1990 + Adam Barr (adamba) 5-Nov-1991 + +Environment: + + This driver is expected at the equivalent of kernel mode. + + Architecturally, there is an assumption in this driver that we are + on a little endian machine. + +Revision History: + + +--*/ + + +// +// Handy macros to read out of sonic ports. +// +// Because the use of PortShift makes the code more complicated, +// we make some assumptions about when it is needed. On x86, we +// only support the EISA card; on MIPS, we only support the +// internal version unless MIPS_EISA_SONIC is defined. +// +// We define two constants, SONIC_EISA and SONIC_INTERNAL, if +// that particular adapter type is supported by this driver. +// This is to prevent unneeded code from being compiled in. +// + + +// +// x86, only the EISA card is supported, the registers are always 16 bits. +// + +#define SONIC_WRITE_PORT(_Adapter, _Port, _Value) \ + NdisRawWritePortUshort((_Adapter)->SonicPortAddress + (_Port * 2), (USHORT)(_Value)) + +#define SONIC_READ_PORT(_Adapter, _Port, _Value) \ + NdisRawReadPortUshort((_Adapter)->SonicPortAddress + (_Port * 2), (PUSHORT)(_Value)) + + +#define SONIC_EISA +#undef SONIC_INTERNAL +#undef MIPS_EISA_SONIC // just in case it is defined + + +// +// The default adapter type is EISA +// + +#define SONIC_ADAPTER_TYPE_DEFAULT SONIC_ADAPTER_TYPE_EISA diff --git a/private/ntos/ndis/sonic/interrup.c b/private/ntos/ndis/sonic/interrup.c new file mode 100644 index 000000000..f3034f80e --- /dev/null +++ b/private/ntos/ndis/sonic/interrup.c @@ -0,0 +1,1694 @@ +/*++ + +Copyright (c) 1990-1992 Microsoft Corporation + +Module Name: + + interrup.c + +Abstract: + + This is a part of the driver for the National Semiconductor SONIC + Ethernet controller. It contains the interrupt-handling routines. + This driver conforms to the NDIS 3.0 miniport interface. + +Author: + + Adam Barr (adamba) 16-Jan-1991 + +Environment: + + Kernel Mode - Or whatever is the equivalent. + +Revision History: + + +--*/ + +#include <ndis.h> + +#include <sonichrd.h> +#include <sonicsft.h> + +#define REMOVE_EOL_AND_ACK(A,L) \ +{ \ + PSONIC_ADAPTER _A = A; \ + SONIC_REMOVE_END_OF_LIST(L); \ + if ((_A)->ReceiveDescriptorsExhausted) { \ + SONIC_WRITE_PORT((_A), SONIC_INTERRUPT_STATUS, \ + SONIC_INT_RECEIVE_DESCRIPTORS \ + ); \ + (_A)->ReceiveDescriptorsExhausted = FALSE; \ + } \ +} + +#define WRITE_RWP_AND_ACK(A,RWP) \ +{ \ + PSONIC_ADAPTER _A = A; \ + SONIC_WRITE_PORT((_A), SONIC_RESOURCE_WRITE, (RWP)); \ + if ((_A)->ReceiveBuffersExhausted) { \ + SONIC_WRITE_PORT((_A), SONIC_INTERRUPT_STATUS, \ + SONIC_INT_RECEIVE_BUFFERS \ + ); \ + (_A)->ReceiveBuffersExhausted = FALSE; \ + } \ +} + + +VOID +SonicDisableInterrupt( + IN NDIS_HANDLE MiniportAdapterContext + ) +/*++ + +Routine Description: + + This routine is used to turn off all interrupts from the adapter. + +Arguments: + + Context - A pointer to the adapter block + +Return Value: + + None. + +--*/ +{ + PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); + + SONIC_WRITE_PORT(Adapter, SONIC_INTERRUPT_MASK, + 0 + ); + +} + +VOID +SonicEnableInterrupt( + IN NDIS_HANDLE MiniportAdapterContext + ) +/*++ + +Routine Description: + + This routine is used to turn on all interrupts from the adapter. + +Arguments: + + Context - A pointer to the adapter block + +Return Value: + + None. + +--*/ +{ + PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); + + SONIC_WRITE_PORT(Adapter, SONIC_INTERRUPT_MASK, + SONIC_INT_DEFAULT_VALUE + ); + +} + + + + + +STATIC +BOOLEAN +ProcessReceiveInterrupts( + IN PSONIC_ADAPTER Adapter + ); + +STATIC +BOOLEAN +ProcessTransmitInterrupts( + IN PSONIC_ADAPTER Adapter + ); + +STATIC +VOID +ProcessInterrupt( + IN PSONIC_ADAPTER Adapter + ); + + +extern +VOID +SonicInterruptService( + OUT PBOOLEAN InterruptRecognized, + OUT PBOOLEAN QueueDpc, + IN PVOID Context + ) + +/*++ + +Routine Description: + + Interrupt service routine for the sonic. This routine only gets + called during initial initialization of the adapter. + +Arguments: + + InterruptRecognized - Boolean value which returns TRUE if the + ISR recognizes the interrupt as coming from this adapter. + + QueueDpc - TRUE if a DPC should be queued. + + Context - Really a pointer to the adapter. + +Return Value: + + Returns true if the card ISR is non-zero. + +--*/ + +{ + + // + // Will hold the value from the ISR. + // + USHORT LocalIsrValue; + + // + // Holds the pointer to the adapter. + // + PSONIC_ADAPTER Adapter = Context; + + + SONIC_READ_PORT(Adapter, SONIC_INTERRUPT_STATUS, &LocalIsrValue); + + if (LocalIsrValue != 0x0000) { + +#if DBG + if (SonicDbg) { + if (LocalIsrValue & ( + SONIC_INT_BUS_RETRY | + SONIC_INT_LOAD_CAM_DONE | + SONIC_INT_PROG_INTERRUPT | + SONIC_INT_TRANSMIT_ERROR | + SONIC_INT_RECEIVE_DESCRIPTORS | + SONIC_INT_RECEIVE_BUFFERS | + SONIC_INT_RECEIVE_OVERFLOW | + SONIC_INT_CRC_TALLY_ROLLOVER | + SONIC_INT_FAE_TALLY_ROLLOVER | + SONIC_INT_MP_TALLY_ROLLOVER + )) { + DbgPrint("ISR %x\n", LocalIsrValue); + } + } +#endif + + // + // Check for exhausted receive descriptors. + // + + if ( LocalIsrValue & SONIC_INT_RECEIVE_DESCRIPTORS ) { + + Adapter->ReceiveDescriptorsExhausted = TRUE; + + LocalIsrValue &= ~SONIC_INT_RECEIVE_DESCRIPTORS; + } + + // + // Check for exhausted receive buffers. + // + + if ( LocalIsrValue & SONIC_INT_RECEIVE_BUFFERS ) { + + Adapter->ReceiveBuffersExhausted = TRUE; + + LocalIsrValue &= ~SONIC_INT_RECEIVE_BUFFERS; + } + + // + // It's our interrupt. Clear only those bits that we got + // in this read of ISR. + // + + *InterruptRecognized = TRUE; + + SONIC_WRITE_PORT( + Adapter, + SONIC_INTERRUPT_STATUS, + (USHORT)(LocalIsrValue) + ); + + // + // If we got a LOAD_CAM_DONE interrupt, it may be + // because our first initialization is complete. + // We check this here because on some systems the + // DeferredProcessing call might not interrupt + // the initialization process. + // + + if (LocalIsrValue & SONIC_INT_LOAD_CAM_DONE) { + + if (Adapter->FirstInitialization) { + + Adapter->FirstInitialization = FALSE; + +#if DBG + { + USHORT PortValue; + + SONIC_READ_PORT(Adapter, SONIC_SILICON_REVISION, &PortValue); + if (SonicDbg) { + DbgPrint("SONIC Initialized: Revision %d\n", PortValue); + } + } +#endif + + } + } + + // + // No deferred processing is needed. + // + *QueueDpc = FALSE; + + return; + + } else { + + *InterruptRecognized = FALSE; + *QueueDpc = FALSE; + return; + + } + +} + +VOID +SonicHandleInterrupt( + IN NDIS_HANDLE MiniportAdapterContext + ) + +/*++ + +Routine Description: + + This DPR routine is queued by the wrapper after every interrupt + and also by other routines within the driver that notice that + some deferred processing needs to be done. It's main + job is to call the interrupt processing code. + +Arguments: + + MiniportAdapterContext - Really a pointer to the adapter. + +Return Value: + + None. + +--*/ + +{ + + // + // A pointer to the adapter object. + // + PSONIC_ADAPTER Adapter = (PSONIC_ADAPTER)MiniportAdapterContext; + + // + // Holds a value of the Interrupt Status register. + // + USHORT Isr; + USHORT ThisIsrValue; + + // + // TRUE if the main loop did something. + // + BOOLEAN DidSomething = TRUE; + + // + // TRUE if ReceiveComplete needs to be indicated. + // + BOOLEAN IndicateReceiveComplete = FALSE; + + // + // Grab any simulated interrupts + // + Isr = Adapter->SimulatedIsr; + Adapter->SimulatedIsr = 0; + + // + // Loop until there are no more processing sources. + // + +#if DBG + if (SonicDbg) { + + DbgPrint("In Dpr\n"); + } +#endif + + // + // If the hardware has failed, do nothing until the reset completes + // + if (Adapter->HardwareFailure) { + + return; + + } + + while (DidSomething) { + + // + // Set this FALSE now, so if nothing happens we + // will exit. + // + + DidSomething = FALSE; + + // + // Read in all outstanding interrupt reasons. + // + + SONIC_READ_PORT(Adapter, SONIC_INTERRUPT_STATUS, &ThisIsrValue); + + // + // Check for exhausted receive descriptors. + // + + if ( ThisIsrValue & SONIC_INT_RECEIVE_DESCRIPTORS ) { + + Adapter->ReceiveDescriptorsExhausted = TRUE; + + ThisIsrValue &= ~SONIC_INT_RECEIVE_DESCRIPTORS; + } + + // + // Check for exhausted receive buffers. + // + + if ( ThisIsrValue & SONIC_INT_RECEIVE_BUFFERS ) { + + Adapter->ReceiveBuffersExhausted = TRUE; + + ThisIsrValue &= ~SONIC_INT_RECEIVE_BUFFERS; + } + + // + // Acknowledge these interrupts + // + + SONIC_WRITE_PORT(Adapter, SONIC_INTERRUPT_STATUS, ThisIsrValue); + + // + // Save these bits. + // + Isr |= ThisIsrValue; + + // + // Check for receive interrupts. + // + + if (Isr & SONIC_INT_PACKET_RECEIVED) { + + DidSomething = TRUE; + + } else { + + goto DoneProcessingReceives; + + } + + // + // After we process any + // other interrupt source we always come back to the top + // of the loop to check if any more receive packets have + // come in. This is to lessen the probability that we + // drop a receive. + // + // ProcessReceiveInterrupts may exit early if it has + // processed too many receives in a row. In this case + // it returns FALSE, we don't clear the PACKET_RECEIVED + // bit, and we will loop through here again. + // + + if (ProcessReceiveInterrupts(Adapter)) { + Isr &= ~SONIC_INT_PACKET_RECEIVED; + } + + // + // If the hardware failed, then exit + // + if (Adapter->HardwareFailure) { + return; + } + + IndicateReceiveComplete = TRUE; + + // + // We set ProcessingReceiveInterrupt to FALSE here so + // that we can issue new receive indications while + // the rest of the loop is proceeding. + // + +DoneProcessingReceives:; + + // + // Check the interrupt source and other reasons + // for processing. If there are no reasons to + // process then exit this loop. + // + + if ((Isr & (SONIC_INT_LOAD_CAM_DONE | + SONIC_INT_PROG_INTERRUPT | + SONIC_INT_PACKET_TRANSMITTED | + SONIC_INT_TRANSMIT_ERROR | + SONIC_INT_CRC_TALLY_ROLLOVER | + SONIC_INT_FAE_TALLY_ROLLOVER | + SONIC_INT_MP_TALLY_ROLLOVER))) { + + DidSomething = TRUE; + + } else { + + goto DoneProcessingGeneral; + + } + + // + // Check for a Load CAM completing. + // + // This can happen due to a change in the CAM, due to + // initialization (in which case we won't save the bit + // and will not come through this code), or a reset + // (in which case ResetInProgress will be TRUE). + // + + // + // Check for non-packet related happenings. + // + + if (Isr & SONIC_INT_LOAD_CAM_DONE) { + + Isr &= ~SONIC_INT_LOAD_CAM_DONE; + + if (Adapter->ResetInProgress) { + + // + // This initialization is from a reset. + // + + Adapter->ResetInProgress = FALSE; + + // + // Restart the chip. + // + + SonicStartChip(Adapter); + + // + // Complete the reset. + // + + NdisMResetComplete( + Adapter->MiniportAdapterHandle, + NDIS_STATUS_SUCCESS, + TRUE + ); + + } else { // ResetInProgress FALSE + + NdisMSetInformationComplete( + Adapter->MiniportAdapterHandle, + NDIS_STATUS_SUCCESS); + + } + + } + + // + // Now process any remaining interrupts. + // + + if (Isr & (SONIC_INT_CRC_TALLY_ROLLOVER | + SONIC_INT_FAE_TALLY_ROLLOVER | + SONIC_INT_MP_TALLY_ROLLOVER)) { + + // + // If any of the counters overflowed, then we update + // the counter by adding one to the high sixteen bits + // and reading the register for the low sixteen bits. + // + + if (Isr & SONIC_INT_CRC_TALLY_ROLLOVER) { + + USHORT CrcError; + SONIC_READ_PORT(Adapter, SONIC_CRC_ERROR, &CrcError); + + Adapter->GeneralOptional[GO_RECEIVE_CRC - GO_ARRAY_START] = + (Adapter->GeneralOptional[GO_RECEIVE_CRC - GO_ARRAY_START] & 0xffff0000) + + 0x10000 + + CrcError; + + } + + if (Isr & SONIC_INT_FAE_TALLY_ROLLOVER) { + + USHORT FaError; + SONIC_READ_PORT(Adapter, SONIC_FRAME_ALIGNMENT_ERROR, &FaError); + + Adapter->MediaMandatory[MM_RECEIVE_ERROR_ALIGNMENT] = + (Adapter->MediaMandatory[MM_RECEIVE_ERROR_ALIGNMENT] & 0xffff0000) + + 0x10000 + + FaError; + + } + + if (Isr & SONIC_INT_MP_TALLY_ROLLOVER) { + + USHORT MissedPacket; + SONIC_READ_PORT(Adapter, SONIC_MISSED_PACKET, &MissedPacket); + + Adapter->GeneralMandatory[GM_RECEIVE_NO_BUFFER] = + (Adapter->GeneralMandatory[GM_RECEIVE_NO_BUFFER] & 0xffff0000) + + 0x10000 + + MissedPacket; + + } + + Isr &= ~(SONIC_INT_CRC_TALLY_ROLLOVER | + SONIC_INT_FAE_TALLY_ROLLOVER | + SONIC_INT_MP_TALLY_ROLLOVER); + + } + + // + // Process the transmit interrupts if there are any. + // + + if (Isr & (SONIC_INT_PROG_INTERRUPT | + SONIC_INT_PACKET_TRANSMITTED | + SONIC_INT_TRANSMIT_ERROR)) { + + { + + if (!ProcessTransmitInterrupts(Adapter)) { + + // + // Process interrupts returns false if it + // finds no more work to do. If this so we + // turn off the transmitter interrupt source. + // + + Isr &= ~ (SONIC_INT_PROG_INTERRUPT | + SONIC_INT_PACKET_TRANSMITTED | + SONIC_INT_TRANSMIT_ERROR); + + } + + } + + } + + +DoneProcessingGeneral:; + + } + + if (IndicateReceiveComplete) { + + // + // We have indicated at least one packet, we now + // need to signal that the receives are complete. + // + + NdisMEthIndicateReceiveComplete(Adapter->MiniportAdapterHandle); + + } + +} + +#define SONIC_RECEIVE_LIMIT 10 + + +STATIC +BOOLEAN +ProcessReceiveInterrupts( + IN PSONIC_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + Process the packets that have finished receiving. + +Arguments: + + Adapter - The adapter to indicate to. + +Return Value: + + FALSE if we exit because we have indicated SONIC_RECEIVE_LIMIT + packets, TRUE if there are no more packets. + +--*/ + +{ + + // + // We don't get here unless there was a receive. Loop through + // the receive descriptors starting at the last known descriptor + // owned by the hardware that begins a packet. + // + // Examine each receive ring descriptor for errors. + // + // We keep an array whose elements are indexed by the ring + // index of the receive descriptors. The arrays elements are + // the virtual addresses of the buffers pointed to by + // each ring descriptor. + // + // When we have the entire packet (and error processing doesn't + // prevent us from indicating it), we give the routine that + // processes the packet through the filter, the buffers virtual + // address (which is always the lookahead size) and as the + // MAC context the index to the first and last ring descriptors + // comprising the packet. + // + + + // + // Pointer to the receive descriptor being examined. + // + PSONIC_RECEIVE_DESCRIPTOR CurrentDescriptor = + &Adapter->ReceiveDescriptorArea[ + Adapter->CurrentReceiveDescriptorIndex]; + + // + // Index of the RBA that the next packet should + // come out of. + // + UINT CurrentRbaIndex = Adapter->CurrentReceiveBufferIndex; + + // + // Virtual address of the start of that RBA. + // + PVOID CurrentRbaVa = Adapter->ReceiveBufferArea[CurrentRbaIndex]; + + // + // Physical address of the start of that RBA. + // + SONIC_PHYSICAL_ADDRESS CurrentRbaPhysical = + SONIC_GET_RECEIVE_RESOURCE_ADDRESS(&Adapter->ReceiveResourceArea[CurrentRbaIndex]); + + // + // The size of the packet. + // + UINT PacketSize; + + // + // The amount of data received in the RBA (will be PacketSize + + // 4 for the CRC). + + USHORT ByteCount; + + // + // The amount of lookahead data to indicate. + // + UINT LookAheadSize; + + // + // The offset of the start of the packet in its receive buffer. + // + UINT PacketOffsetInRba; + + // + // The Physical address of the packet. + // + SONIC_PHYSICAL_ADDRESS PacketPhysical; + + // + // A pointer to the link field at the end of the receive + // descriptor before the one we are processing. + // + PSONIC_PHYSICAL_ADDRESS PrevLinkFieldAddr; + + // + // The virtual address of the packet. + // + PVOID PacketVa; + + // + // The status of the packet. + // + USHORT ReceiveStatus; + + // + // Is the descriptor in use by the sonic. + // + USHORT InUse; + + // + // Used tempoerarily to determine PacketPhysical. + // + USHORT PacketAddress; + + // + // How many packets we have indicated this time. + // + UINT PacketsIndicated = 0; + + // + // Used with update shared memory. + // + + NDIS_PHYSICAL_ADDRESS TempAddress; + +#if DBG + // + // For debugging, save the previous receive descriptor. + // + static SONIC_RECEIVE_DESCRIPTOR PreviousDescriptor; +#endif + + + do { + + // + // Ensure that the system memory copy of the + // receive descriptor is up-to-date. + // + + NdisMUpdateSharedMemory( + Adapter->MiniportAdapterHandle, + sizeof(SONIC_RECEIVE_DESCRIPTOR) * + Adapter->NumberOfReceiveDescriptors, + Adapter->ReceiveDescriptorArea, + Adapter->ReceiveDescriptorAreaPhysical + ); + + + // + // Check to see whether we own the packet. If + // we don't then simply return to the caller. + // + + NdisReadRegisterUshort(&CurrentDescriptor->InUse, &InUse); + + if (InUse != SONIC_OWNED_BY_SYSTEM) { + + return TRUE; + } + + // + // Figure out the virtual address of the packet. + // + + NdisReadRegisterUshort((PUSHORT)&CurrentDescriptor->LowPacketAddress, + (PUSHORT)&PacketAddress); + PacketPhysical = PacketAddress; + NdisReadRegisterUshort((PUSHORT)&CurrentDescriptor->HighPacketAddress, + (PUSHORT)&PacketAddress); + PacketPhysical += PacketAddress << 16; + + if ((PacketPhysical < CurrentRbaPhysical) || + (PacketPhysical > (CurrentRbaPhysical + SONIC_SIZE_OF_RECEIVE_BUFFERS)) ) { + + // + // Something is wrong, the packet is not in the + // receive buffer that we expect it in. + // + + SONIC_PHYSICAL_ADDRESS ResourcePhysical; + PSONIC_RECEIVE_RESOURCE CurrentReceiveResource; + UINT i; + + if (Adapter->WrongRbaErrorLogCount++ < 5) { + + // + // Log an error the first five times this happens. + // + + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_HARDWARE_FAILURE, + 6, + processReceiveInterrupts, + SONIC_ERRMSG_WRONG_RBA, + (ULONG)CurrentRbaPhysical, + (ULONG)PacketPhysical, + (ULONG)CurrentDescriptor, + (ULONG)Adapter->ReceiveDescriptorArea + ); + +#if DBG + DbgPrint("SONIC: RBA at %lx [%lx], Packet at %lx\n", CurrentRbaPhysical, CurrentRbaVa, PacketPhysical); + + DbgPrint("descriptor %lx, start %lx, prev %lx\n", + (ULONG)CurrentDescriptor, + (ULONG)Adapter->ReceiveDescriptorArea, + &PreviousDescriptor); +#endif + } + + // + // Attempt to recover by advancing the relevant pointers + // to where the SONIC thinks the packet is. First we need + // to find the receive buffer that matches the indicated + // physical address. + // + + for ( + i = 0, CurrentReceiveResource = Adapter->ReceiveResourceArea; + i < Adapter->NumberOfReceiveBuffers; + i++,CurrentReceiveResource++ + ) { + + ResourcePhysical = SONIC_GET_RECEIVE_RESOURCE_ADDRESS(CurrentReceiveResource); + if ((PacketPhysical >= ResourcePhysical) && + (PacketPhysical < + (ResourcePhysical + SONIC_SIZE_OF_RECEIVE_BUFFERS))) { + + // + // We found the receive resource. + // + break; + + } + + } + + if (i == Adapter->NumberOfReceiveBuffers) { + + // + // Quit now, there is a failure by the chip, and we + // cannot find the receive. + // + + Adapter->HardwareFailure = TRUE; + + return FALSE; + } + + // + // Update our pointers. + // + + Adapter->CurrentReceiveBufferIndex = i; + + CurrentRbaIndex = i; + + CurrentRbaVa = Adapter->ReceiveBufferArea[i]; + + CurrentRbaPhysical = + SONIC_GET_RECEIVE_RESOURCE_ADDRESS(&Adapter->ReceiveResourceArea[i]); + + // + // Flush the receive buffer. + // + + NdisFlushBuffer( + Adapter->ReceiveNdisBufferArea[i], + FALSE + ); + + // + // Ensure that we release buffers before this one + // back to the sonic. + // + + WRITE_RWP_AND_ACK( + Adapter, + (USHORT)(CurrentRbaPhysical & 0xffff) + ); + + } + + + PacketOffsetInRba = PacketPhysical - CurrentRbaPhysical; + + + // + // Check that the packet was received correctly...note that + // we always compute PacketOffsetInRba and ByteCount, + // which are needed to skip the packet even if we do not + // indicate it. + // + + NdisReadRegisterUshort(&CurrentDescriptor->ReceiveStatus, &ReceiveStatus); + + NdisReadRegisterUshort(&CurrentDescriptor->ByteCount, &ByteCount); + + if (!(ReceiveStatus & SONIC_RCR_PACKET_RECEIVED_OK)) { + +#if DBG + if (SonicDbg) { + + DbgPrint("SONIC: Skipping %lx\n", ReceiveStatus); + } +#endif + + goto SkipIndication; + + } + + // + // Prepare to indicate the packet. + // + + PacketSize = ByteCount - 4; + + if ( PacketSize > 1514 ) { + +#if DBG + DbgPrint("SONIC: Skipping packet, length %d\n", PacketSize); +#endif + + goto SkipIndication; + } + + + if (PacketSize < SONIC_INDICATE_MAXIMUM) { + + LookAheadSize = PacketSize; + + } else { + + LookAheadSize = SONIC_INDICATE_MAXIMUM; + + } + + PacketVa = (PUCHAR) CurrentRbaVa + PacketOffsetInRba; + + // + // Ensure that the system memory version of this RBA is up-to-date. + // + + NdisFlushBuffer( + Adapter->ReceiveNdisBufferArea[CurrentRbaIndex], + FALSE + ); + + NdisSetPhysicalAddressLow( + TempAddress, + SONIC_GET_RECEIVE_RESOURCE_ADDRESS(&Adapter->ReceiveResourceArea[CurrentRbaIndex]) + ); + + NdisSetPhysicalAddressHigh(TempAddress, 0); + + NdisMUpdateSharedMemory( + Adapter->MiniportAdapterHandle, + SONIC_SIZE_OF_RECEIVE_BUFFERS, + Adapter->ReceiveBufferArea[CurrentRbaIndex], + TempAddress + ); + + // + // Indicate the packet to the protocol. + // + + if ( PacketSize < 14 ) { + + // + // Must have at least the destination address + // + + if (PacketSize >= ETH_LENGTH_OF_ADDRESS) { + + // + // Runt packet + // + + NdisMEthIndicateReceive( + Adapter->MiniportAdapterHandle, + (NDIS_HANDLE)((PUCHAR)PacketVa + 14), // context + PacketVa, // header buffer + PacketSize, // header buffer size + NULL, // lookahead buffer + 0, // lookahead buffer size + 0 // packet size + ); + + } + + } else { + + NdisMEthIndicateReceive( + Adapter->MiniportAdapterHandle, + (NDIS_HANDLE)((PUCHAR)PacketVa + 14), // context + PacketVa, // header buffer + 14, // header buffer size + (PUCHAR)PacketVa + 14, // lookahead buffer + LookAheadSize - 14, // lookahead buffer size + PacketSize - 14 // packet size + ); + + } + +SkipIndication:; + +#if DBG + SONIC_MOVE_MEMORY (&PreviousDescriptor, CurrentDescriptor, sizeof(SONIC_RECEIVE_DESCRIPTOR)); +#endif + + // + // Give the packet back to the hardware. + // + + NdisWriteRegisterUlong(&CurrentDescriptor->InUse, SONIC_OWNED_BY_SONIC); + + // + // And re-set the EOL fields correctly. + // + + SONIC_SET_END_OF_LIST( + &(CurrentDescriptor->Link) + ); + + if (CurrentDescriptor == Adapter->ReceiveDescriptorArea) { + + // + // we are at the first one + // + + PrevLinkFieldAddr = &(Adapter->LastReceiveDescriptor->Link); + + } else { + + PrevLinkFieldAddr = &((CurrentDescriptor-1)->Link); + + } + + REMOVE_EOL_AND_ACK( + Adapter, + PrevLinkFieldAddr + ); + + // + // Now figure out if the RBA is done with. + // + + if (ReceiveStatus & SONIC_RCR_LAST_PACKET_IN_RBA) { + + // + // Advance which RBA we are looking at. + // + + ++CurrentRbaIndex; + + if (CurrentRbaIndex == Adapter->NumberOfReceiveBuffers) { + + CurrentRbaIndex = 0; + + } + + Adapter->CurrentReceiveBufferIndex = CurrentRbaIndex; + + CurrentRbaVa = Adapter->ReceiveBufferArea[CurrentRbaIndex]; + + CurrentRbaPhysical = + SONIC_GET_RECEIVE_RESOURCE_ADDRESS(&Adapter->ReceiveResourceArea[CurrentRbaIndex]); + + WRITE_RWP_AND_ACK( + Adapter, + (USHORT)(CurrentRbaPhysical & 0xffff) + ); + + } + + // + // Update statistics now based on the receive status. + // + + if (ReceiveStatus & SONIC_RCR_PACKET_RECEIVED_OK) { + + ++Adapter->GeneralMandatory[GM_RECEIVE_GOOD]; + + if (ReceiveStatus & SONIC_RCR_BROADCAST_RECEIVED) { + + ++Adapter->GeneralOptionalFrameCount[GO_BROADCAST_RECEIVES]; + SonicAddUlongToLargeInteger( + &Adapter->GeneralOptionalByteCount[GO_BROADCAST_RECEIVES], + PacketSize); + + } else if (ReceiveStatus & SONIC_RCR_MULTICAST_RECEIVED) { + + ++Adapter->GeneralOptionalFrameCount[GO_MULTICAST_RECEIVES]; + SonicAddUlongToLargeInteger( + &Adapter->GeneralOptionalByteCount[GO_MULTICAST_RECEIVES], + PacketSize); + + } else { + + ++Adapter->GeneralOptionalFrameCount[GO_DIRECTED_RECEIVES]; + SonicAddUlongToLargeInteger( + &Adapter->GeneralOptionalByteCount[GO_DIRECTED_RECEIVES], + PacketSize); + + } + + } else { + + ++Adapter->GeneralMandatory[GM_RECEIVE_BAD]; + + if (ReceiveStatus & SONIC_RCR_CRC_ERROR) { + ++Adapter->GeneralOptional[GO_RECEIVE_CRC - GO_ARRAY_START]; + } else if (ReceiveStatus & SONIC_RCR_FRAME_ALIGNMENT) { + ++Adapter->MediaMandatory[MM_RECEIVE_ERROR_ALIGNMENT]; + } + + } + + // + // Advance our pointers to the next packet. + + if (CurrentDescriptor == Adapter->LastReceiveDescriptor) { + + Adapter->CurrentReceiveDescriptorIndex = 0; + + } else { + + ++(Adapter->CurrentReceiveDescriptorIndex); + + } + + CurrentDescriptor = &Adapter->ReceiveDescriptorArea[ + Adapter->CurrentReceiveDescriptorIndex]; + + ++PacketsIndicated; + + } while (PacketsIndicated < SONIC_RECEIVE_LIMIT); + + // + // Indicate that we returned because we indicated SONIC_RECEIVE_ + // LIMIT packets, not because we ran out of packets to indicate. + // + + return FALSE; + +} + +STATIC +BOOLEAN +ProcessTransmitInterrupts( + IN PSONIC_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + Process the packets that have finished transmitting. + +Arguments: + + Adapter - The adapter that was sent from. + +Return Value: + + This function will return TRUE if it finished up the + send on a packet. It will return FALSE if for some + reason there was no packet to process. + +--*/ + +{ + // + // Index into the ring to packet structure. This index points + // to the first ring entry for the first buffer used for transmitting + // the packet. + // + UINT DescriptorIndex; + + // + // The transmit desctiptor for the packet at Transmitting Descriptor + // + PSONIC_TRANSMIT_DESCRIPTOR TransmitDescriptor; + + // + // Temporarily holds the transmit descriptor after TransmitDescriptor + // + PSONIC_TRANSMIT_DESCRIPTOR NextTransmitDescriptor; + + // + // Pointer to the packet that started this transmission. + // + PNDIS_PACKET OwningPacket; + + // + // Points to the reserved part of the OwningPacket. + // + PSONIC_PACKET_RESERVED Reserved; + + // + // Used to hold the ring to packet mapping information so that + // we can release the ring entries as quickly as possible. + // + SONIC_DESCRIPTOR_TO_PACKET SavedDescriptorMapping; + + // + // The status of the transmit. + // + USHORT TransmitStatus; + + // + // Get hold of the first transmitted packet. + // + + // + // First we check that this is a packet that was transmitted + // but not already processed. Recall that this routine + // will be called repeatedly until this tests false, Or we + // hit a packet that we don't completely own. + // + + if (Adapter->TransmittingDescriptor != + Adapter->FirstUncommittedDescriptor) { + + DescriptorIndex = + Adapter->TransmittingDescriptor - Adapter->TransmitDescriptorArea; + + } else { + + return FALSE; + + } + + // + // We put the mapping into a local variable so that we + // can return the mapping as soon as possible. + // + + SavedDescriptorMapping = Adapter->DescriptorToPacket[DescriptorIndex]; + + // + // Get a pointer to the transmit descriptor for this packet. + // + + TransmitDescriptor = Adapter->TransmitDescriptorArea + DescriptorIndex; + + // + // Get a pointer to the owning packet and the reserved part of + // the packet. + // + + OwningPacket = SavedDescriptorMapping.OwningPacket; + + Reserved = PSONIC_RESERVED_FROM_PACKET(OwningPacket); + + + // + // Check that status bits were written into the transmit + // descriptor. + // + + NdisReadRegisterUshort((PUSHORT)&TransmitDescriptor->TransmitStatus, &TransmitStatus); + + if (!(TransmitStatus & SONIC_TCR_STATUS_MASK)) { + + // + // The transmit has not completed. + // + + return FALSE; + + } else { + + // + // Holds whether the packet successfully transmitted or not. + // + BOOLEAN Successful = TRUE; + + // + // Length of the packet + // + UINT PacketLength; + + // + // Points to data in NDIS_BUFFER + // + PUCHAR BufferVa; + + // + // Points to the current ndis buffer being walked. + // + PNDIS_BUFFER CurrentBuffer; + + Adapter->WakeUpTimeout = FALSE; + + if (SavedDescriptorMapping.UsedSonicBuffer) { + + // + // This packet used adapter buffers. We can + // now return these buffers to the adapter. + // + + // + // The adapter buffer descriptor that was allocated to this packet. + // + PSONIC_BUFFER_DESCRIPTOR BufferDescriptor = Adapter->SonicBuffers + + SavedDescriptorMapping.SonicBuffersIndex; + + // + // Index of the listhead that heads the list that the adapter + // buffer descriptor belongs too. + // + INT ListHeadIndex = BufferDescriptor->Next; + + + // + // Put the adapter buffer back on the free list. + // + + BufferDescriptor->Next = Adapter->SonicBufferListHeads[ListHeadIndex]; + Adapter->SonicBufferListHeads[ListHeadIndex] = SavedDescriptorMapping.SonicBuffersIndex; + + } else { + + // + // Which map register we use for this buffer. + // + UINT CurMapRegister; + + // + // The transmit is finished, so we can release + // the physical mapping used for it. + // + + NdisQueryPacket( + OwningPacket, + NULL, + NULL, + &CurrentBuffer, + NULL + ); + + CurMapRegister = DescriptorIndex * SONIC_MAX_FRAGMENTS; + + while (CurrentBuffer) { + + NdisMCompleteBufferPhysicalMapping( + Adapter->MiniportAdapterHandle, + CurrentBuffer, + CurMapRegister + ); + + ++CurMapRegister; + + NdisGetNextBuffer( + CurrentBuffer, + &CurrentBuffer + ); + + } + + } + + + // + // Now release the transmit descriptor, since we have + // gotten all the information we need from it. + // + + if (TransmitDescriptor == Adapter->LastTransmitDescriptor) { + + NextTransmitDescriptor = Adapter->TransmitDescriptorArea; + + } else { + + NextTransmitDescriptor = Adapter->TransmittingDescriptor + 1; + + } + + if (TransmitStatus & + (SONIC_TCR_EXCESSIVE_DEFERRAL | + SONIC_TCR_EXCESSIVE_COLLISIONS | + SONIC_TCR_FIFO_UNDERRUN | + SONIC_TCR_BYTE_COUNT_MISMATCH)) { + + // + // If the packet completed with an abort state, then we + // need to restart the transmitter unless we are the + // last transmit queued up. We set CTDA to point after + // this descriptor in any case. + // + +#if DBG + if (SonicDbg) { + DbgPrint ("SONIC: Advancing CTDA after abort\n"); + } +#endif + + SONIC_WRITE_PORT(Adapter, SONIC_CURR_TRANSMIT_DESCRIPTOR, + SONIC_GET_LOW_PART_ADDRESS( + NdisGetPhysicalAddressLow(Adapter->TransmitDescriptorAreaPhysical) + + ((PUCHAR)NextTransmitDescriptor - + (PUCHAR)Adapter->TransmitDescriptorArea)) + ); + + if (Adapter->FirstUncommittedDescriptor != NextTransmitDescriptor) { +#if DBG + if (SonicDbg) { + DbgPrint ("SONIC: Restarting transmit after abort\n"); + } +#endif + SONIC_WRITE_PORT(Adapter, SONIC_COMMAND, SONIC_CR_TRANSMIT_PACKETS); + } + + } + + Adapter->TransmittingDescriptor = NextTransmitDescriptor; + Adapter->NumberOfAvailableDescriptors++; + + // + // Check if the packet completed OK, and update statistics. + // + + if (!(TransmitStatus & SONIC_TCR_PACKET_TRANSMITTED_OK)) { + +#if DBG + if (SonicDbg) { + DbgPrint("SONIC: Transmit failed: %lx\n", TransmitStatus); + } +#endif + Successful = FALSE; + + ++Adapter->GeneralMandatory[GM_TRANSMIT_BAD]; + + if (TransmitStatus & SONIC_TCR_EXCESSIVE_COLLISIONS) { + ++Adapter->MediaOptional[MO_TRANSMIT_MAX_COLLISIONS]; + } + + if (TransmitStatus & SONIC_TCR_FIFO_UNDERRUN) { + ++Adapter->MediaOptional[MO_TRANSMIT_UNDERRUN]; + } + + } else { + + INT Collisions = (TransmitStatus & SONIC_TCR_COLLISIONS_MASK) >> SONIC_TCR_COLLISIONS_SHIFT; + + UINT Tmp; + + Successful = TRUE; + + ++Adapter->GeneralMandatory[GM_TRANSMIT_GOOD]; + + if (Collisions > 0) { + if (Collisions == 1) { + ++Adapter->MediaMandatory[MM_TRANSMIT_ONE_COLLISION]; + } else { + ++Adapter->MediaMandatory[MM_TRANSMIT_MORE_COLLISIONS]; + } + } + + if (TransmitStatus & + (SONIC_TCR_DEFERRED_TRANSMISSION | + SONIC_TCR_NO_CARRIER_SENSE | + SONIC_TCR_CARRIER_LOST | + SONIC_TCR_OUT_OF_WINDOW)) { + + if (TransmitStatus & SONIC_TCR_DEFERRED_TRANSMISSION) { + ++Adapter->MediaOptional[MO_TRANSMIT_DEFERRED]; + } + if (TransmitStatus & SONIC_TCR_NO_CARRIER_SENSE) { + ++Adapter->MediaOptional[MO_TRANSMIT_HEARTBEAT_FAILURE]; + } + if (TransmitStatus & SONIC_TCR_CARRIER_LOST) { + ++Adapter->MediaOptional[MO_TRANSMIT_TIMES_CRS_LOST]; + } + if (TransmitStatus & SONIC_TCR_OUT_OF_WINDOW) { + ++Adapter->MediaOptional[MO_TRANSMIT_LATE_COLLISIONS]; + } + } + + NdisQueryPacket( + OwningPacket, + NULL, + NULL, + &CurrentBuffer, + &PacketLength + ); + + NdisQueryBuffer( + CurrentBuffer, + (PVOID *)&BufferVa, + &Tmp + ); + + if (BufferVa[0] == 0xFF) { + + ++Adapter->GeneralOptionalFrameCount[GO_BROADCAST_TRANSMITS]; + SonicAddUlongToLargeInteger( + &Adapter->GeneralOptionalByteCount[GO_BROADCAST_TRANSMITS], + PacketLength); + + } else if (BufferVa[0] & 0x01) { + + ++Adapter->GeneralOptionalFrameCount[GO_MULTICAST_TRANSMITS]; + SonicAddUlongToLargeInteger( + &Adapter->GeneralOptionalByteCount[GO_MULTICAST_TRANSMITS], + PacketLength); + + } else { + + ++Adapter->GeneralOptionalFrameCount[GO_DIRECTED_TRANSMITS]; + SonicAddUlongToLargeInteger( + &Adapter->GeneralOptionalByteCount[GO_DIRECTED_TRANSMITS], + PacketLength); + + } + + } + + // + // Remove packet from queue. + // + + if (Adapter->LastFinishTransmit == OwningPacket) { + + Adapter->FirstFinishTransmit = NULL; + Adapter->LastFinishTransmit = NULL; + + } else { + + Adapter->FirstFinishTransmit = Reserved->Next; + } + +#ifdef CHECK_DUP_SENDS + { + VOID SonicRemovePacketFromList(PSONIC_ADAPTER, PNDIS_PACKET); + SonicRemovePacketFromList(Adapter, OwningPacket); + } +#endif + + NdisMSendComplete( + Adapter->MiniportAdapterHandle, + OwningPacket, + ((Successful)?(NDIS_STATUS_SUCCESS):(NDIS_STATUS_FAILURE)) + ); + + Adapter->PacketsSinceLastInterrupt = 0; + + return TRUE; + } + +} + +BOOLEAN +SonicCheckForHang( + IN PVOID MiniportAdapterContext + ) + +/*++ + +Routine Description: + + This routine checks on the transmit descriptor ring. This is + to solve problems where no status is written into the currently + transmitting transmit descriptor, which hangs our transmit + completion processing. If we detect this state, we simulate + a transmit interrupt. + +Arguments: + + MiniportAdapterContext - Really a pointer to the adapter. + +Return Value: + + FALSE - This routine actually does a wake up, rather than having + the wrapper do it. + +--*/ +{ + PSONIC_ADAPTER Adapter = (PSONIC_ADAPTER)MiniportAdapterContext; + UINT DescriptorIndex; + PSONIC_TRANSMIT_DESCRIPTOR TransmitDescriptor; + USHORT TransmitStatus; + + // + // If hardware failed, then return now + // + if (Adapter->HardwareFailure) { + return(TRUE); + } + + if (Adapter->WakeUpTimeout) { + + // + // We had a pending send the last time we ran, + // and it has not been completed...we need to fake + // its completion. + // + + ASSERT (Adapter->TransmittingDescriptor != + Adapter->FirstUncommittedDescriptor); + + DescriptorIndex = + Adapter->TransmittingDescriptor - Adapter->TransmitDescriptorArea; + + TransmitDescriptor = Adapter->TransmitDescriptorArea + DescriptorIndex; + NdisReadRegisterUshort((PUSHORT)&TransmitDescriptor->TransmitStatus, &TransmitStatus); + + if (!(TransmitStatus & SONIC_TCR_STATUS_MASK)) { + + NdisWriteRegisterUshort ((PUSHORT)&TransmitDescriptor->TransmitStatus, + SONIC_TCR_PACKET_TRANSMITTED_OK); + +#if DBG + DbgPrint ("SONIC: Woke up descriptor at %lx\n", TransmitDescriptor); +#endif + + } + + Adapter->SimulatedIsr |= SONIC_INT_PACKET_TRANSMITTED; + + Adapter->WakeUpTimeout = FALSE; + + if (Adapter->WakeUpErrorCount < 10) { + + Adapter->WakeUpErrorCount++; + + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_HARDWARE_FAILURE, + 1, + (ULONG)0xFFFFFFFF + ); + } + + } else if (Adapter->TransmittingDescriptor != + Adapter->FirstUncommittedDescriptor) { + + DescriptorIndex = + Adapter->TransmittingDescriptor - Adapter->TransmitDescriptorArea; + + TransmitDescriptor = Adapter->TransmitDescriptorArea + DescriptorIndex; + NdisReadRegisterUshort((PUSHORT)&TransmitDescriptor->TransmitStatus, &TransmitStatus); + + if (!(TransmitStatus & SONIC_TCR_STATUS_MASK)) { + + Adapter->WakeUpTimeout = TRUE; + + } + + } + + return(FALSE); + +} diff --git a/private/ntos/ndis/sonic/makefile b/private/ntos/ndis/sonic/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/ntos/ndis/sonic/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/ntos/ndis/sonic/mips/sonicdet.h b/private/ntos/ndis/sonic/mips/sonicdet.h new file mode 100644 index 000000000..9325bec47 --- /dev/null +++ b/private/ntos/ndis/sonic/mips/sonicdet.h @@ -0,0 +1,89 @@ +/*++ + +Copyright (c) 1990-1992 Microsoft Corporation + +Module Name: + + sonicdet.h + +Abstract: + + This file has processor-specific definitions. + + The overall structure is taken from the Lance driver + by Tony Ercolano. + +Author: + + Anthony V. Ercolano (tonye) creation-date 19-Jun-1990 + Adam Barr (adamba) 5-Nov-1991 + +Environment: + + This driver is expected to work at the equivalent of kernel mode. + + Architecturally, there is an assumption in this driver that we are + on a little endian machine. + +Revision History: + + +--*/ + + +// +// Handy macros to read out of sonic ports. +// +// Because the use of PortShift makes the code more complicated, +// we make some assumptions about when it is needed. On MIPS, we +// only support the internal version unless MIPS_EISA_SONIC +// is defined, in which case we support both. +// +// We define two constants, SONIC_EISA and SONIC_INTERNAL, if +// that particular adapter type is supported by this driver. +// This is to prevent unneeded code from being compiled in. +// + + +#ifdef MIPS_EISA_SONIC + + +// +// mips, with support for the EISA card; we have to use PortShift. +// + +#define SONIC_WRITE_PORT(_Adapter, _Port, _Value) \ + NdisRawWritePortUshort((_Adapter)->SonicPortAddress + (_Port << (_Adapter)->PortShift), (USHORT)(_Value)) + +#define SONIC_READ_PORT(_Adapter, _Port, _Value) \ + NdisRawReadPortUshort((_Adapter)->SonicPortAddress + (_Port << (_Adapter)->PortShift), (PUSHORT)(_Value)) + +#define SONIC_EISA +#define SONIC_INTERNAL + + +#else // MIPS_EISA_SONIC + + +// +// mips, internal support only, the registers are always 32 bits +// + +#define SONIC_WRITE_PORT(_Adapter, _Port, _Value) \ + NdisRawWritePortUshort((_Adapter)->SonicPortAddress + (_Port * 4), (USHORT)(_Value)) + +#define SONIC_READ_PORT(_Adapter, _Port, _Value) \ + NdisRawReadPortUshort((_Adapter)->SonicPortAddress + (_Port * 4), (PUSHORT)(_Value)) + +#undef SONIC_EISA +#define SONIC_INTERNAL + + +#endif // MIPS_EISA_SONIC + + +// +// The default adapter type for mips is Internal +// + +#define SONIC_ADAPTER_TYPE_DEFAULT SONIC_ADAPTER_TYPE_INTERNAL diff --git a/private/ntos/ndis/sonic/request.c b/private/ntos/ndis/sonic/request.c new file mode 100644 index 000000000..d17d67791 --- /dev/null +++ b/private/ntos/ndis/sonic/request.c @@ -0,0 +1,890 @@ +/*++ + +Copyright (c) 1990-1992 Microsoft Corporation + +Module Name: + + request.c + +Abstract: + + This is the cose to handle requests for the National Semiconductor + SONIC Ethernet controller. This driver conforms to the NDIS 3.0 + miniport interface. + +Author: + + Adam Barr (adamba) 14-Nov-1990 + +Environment: + + Kernel Mode - Or whatever is the equivalent. + +Revision History: + + +--*/ + +#include <ndis.h> + +#include <sonichrd.h> +#include <sonicsft.h> + + + +// +// This macro determines if the directed address +// filtering in the CAM is actually necessary given +// the current filter. +// + +#define CAM_DIRECTED_SIGNIFICANT(_Filter) \ + ((((_Filter) & NDIS_PACKET_TYPE_DIRECTED) && \ + (!((_Filter) & NDIS_PACKET_TYPE_PROMISCUOUS))) ? 1 : 0) + + +// +// This macro determines if the multicast filtering in +// the CAM are actually necessary given the current filter. +// + +#define CAM_MULTICAST_SIGNIFICANT(_Filter) \ + ((((_Filter) & NDIS_PACKET_TYPE_MULTICAST) && \ + (!((_Filter) & (NDIS_PACKET_TYPE_ALL_MULTICAST | \ + NDIS_PACKET_TYPE_PROMISCUOUS)))) ? 1 : 0) + + +STATIC +NDIS_STATUS +ChangeClassDispatch( + IN PSONIC_ADAPTER Adapter, + IN UINT NewFilterClasses + ); + +STATIC +NDIS_STATUS +ChangeAddressDispatch( + IN PSONIC_ADAPTER Adapter, + IN UINT AddressCount, + IN CHAR Addresses[][ETH_LENGTH_OF_ADDRESS] + ); + + + + +extern +NDIS_STATUS +SonicQueryInformation( + IN NDIS_HANDLE MiniportAdapterContext, + IN NDIS_OID Oid, + IN PVOID InformationBuffer, + IN ULONG InformationBufferLength, + OUT PULONG BytesWritten, + OUT PULONG BytesNeeded + ) + +/*++ + +Routine Description: + + SonicQueryInformation handles a query operation for a + single OID. + +Arguments: + + MiniportAdapterContext - Context registered with the wrapper, really + a pointer to the adapter. + + Oid - The OID of the query. + + InformationBuffer - Holds the result of the query. + + InformationBufferLength - The length of InformationBuffer. + + BytesWritten - If the call is successful, returns the number + of bytes written to InformationBuffer. + + BytesNeeded - If there is not enough room in InformationBuffer + to satisfy the OID, returns the amount of storage needed. + +Return Value: + + NDIS_STATUS_SUCCESS + NDIS_STATUS_PENDING + NDIS_STATUS_INVALID_LENGTH + NDIS_STATUS_INVALID_OID + +--*/ + +{ + PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); + INT i; + INT SupportedOids; + NDIS_OID MaskOid; + PVOID SourceBuffer; + ULONG SourceBufferLength; + ULONG GenericUlong; + USHORT GenericUshort; + UCHAR VendorId[4]; +#ifdef SONIC_EISA + static const UCHAR EisaDescriptor[] = "SONIC EISA Bus Master Ethernet Adapter (DP83932EB-EISA)"; +#endif +#ifdef SONIC_INTERNAL + static const UCHAR InternalDescriptor[] = "MIPS R4000 on-board network controller"; +#endif + + static const NDIS_OID SonicSupportedOids[] = { + OID_GEN_SUPPORTED_LIST, + OID_GEN_HARDWARE_STATUS, + OID_GEN_MEDIA_SUPPORTED, + OID_GEN_MEDIA_IN_USE, + OID_GEN_MAXIMUM_LOOKAHEAD, + OID_GEN_MAXIMUM_FRAME_SIZE, + OID_GEN_MAXIMUM_TOTAL_SIZE, + OID_GEN_MAC_OPTIONS, + OID_GEN_PROTOCOL_OPTIONS, + OID_GEN_LINK_SPEED, + OID_GEN_TRANSMIT_BUFFER_SPACE, + OID_GEN_RECEIVE_BUFFER_SPACE, + OID_GEN_TRANSMIT_BLOCK_SIZE, + OID_GEN_RECEIVE_BLOCK_SIZE, + OID_GEN_VENDOR_ID, + OID_GEN_VENDOR_DESCRIPTION, + OID_GEN_DRIVER_VERSION, + OID_GEN_CURRENT_PACKET_FILTER, + OID_GEN_CURRENT_LOOKAHEAD, + OID_GEN_XMIT_OK, + OID_GEN_RCV_OK, + OID_GEN_XMIT_ERROR, + OID_GEN_RCV_ERROR, + OID_GEN_RCV_NO_BUFFER, + OID_GEN_DIRECTED_BYTES_XMIT, + OID_GEN_DIRECTED_FRAMES_XMIT, + OID_GEN_MULTICAST_BYTES_XMIT, + OID_GEN_MULTICAST_FRAMES_XMIT, + OID_GEN_BROADCAST_BYTES_XMIT, + OID_GEN_BROADCAST_FRAMES_XMIT, + OID_GEN_DIRECTED_BYTES_RCV, + OID_GEN_DIRECTED_FRAMES_RCV, + OID_GEN_MULTICAST_BYTES_RCV, + OID_GEN_MULTICAST_FRAMES_RCV, + OID_GEN_BROADCAST_BYTES_RCV, + OID_GEN_BROADCAST_FRAMES_RCV, + OID_GEN_RCV_CRC_ERROR, + OID_GEN_TRANSMIT_QUEUE_LENGTH, + OID_802_3_PERMANENT_ADDRESS, + OID_802_3_CURRENT_ADDRESS, + OID_802_3_MULTICAST_LIST, + OID_802_3_MAXIMUM_LIST_SIZE, + OID_802_3_RCV_ERROR_ALIGNMENT, + OID_802_3_XMIT_ONE_COLLISION, + OID_802_3_XMIT_MORE_COLLISIONS, + OID_802_3_XMIT_DEFERRED, + OID_802_3_XMIT_MAX_COLLISIONS, + OID_802_3_RCV_OVERRUN, + OID_802_3_XMIT_UNDERRUN, + OID_802_3_XMIT_HEARTBEAT_FAILURE, + OID_802_3_XMIT_TIMES_CRS_LOST, + OID_802_3_XMIT_LATE_COLLISIONS + }; + + // + // Check that the OID is valid. + // + + SupportedOids = sizeof(SonicSupportedOids)/sizeof(ULONG); + + for (i=0; i<SupportedOids; i++) { + if (Oid == SonicSupportedOids[i]) { + break; + } + } + + if (i == SupportedOids) { + *BytesWritten = 0; + return NDIS_STATUS_INVALID_OID; + } + + // + // Initialize these once, since this is the majority + // of cases. + // + + SourceBuffer = &GenericUlong; + SourceBufferLength = sizeof(ULONG); + + switch (Oid & OID_TYPE_MASK) { + + case OID_TYPE_GENERAL_OPERATIONAL: + + switch (Oid) { + + case OID_GEN_MAC_OPTIONS: + + GenericUlong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | + NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | + NDIS_MAC_OPTION_RECEIVE_SERIALIZED | + NDIS_MAC_OPTION_NO_LOOPBACK + ); + + break; + + case OID_GEN_SUPPORTED_LIST: + + SourceBuffer = (PVOID)SonicSupportedOids; + SourceBufferLength = SupportedOids * sizeof(ULONG); + break; + + case OID_GEN_HARDWARE_STATUS: + + GenericUlong = NdisHardwareStatusReady; + break; + + case OID_GEN_MEDIA_SUPPORTED: + + GenericUlong = NdisMedium802_3; + break; + + case OID_GEN_MEDIA_IN_USE: + + GenericUlong = NdisMedium802_3; + break; + + case OID_GEN_MAXIMUM_LOOKAHEAD: + + GenericUlong = (SONIC_INDICATE_MAXIMUM-14 < SONIC_LOOPBACK_MAXIMUM) ? + SONIC_INDICATE_MAXIMUM-14 : SONIC_LOOPBACK_MAXIMUM; + break; + + case OID_GEN_MAXIMUM_FRAME_SIZE: + + GenericUlong = 1500; + break; + + case OID_GEN_MAXIMUM_TOTAL_SIZE: + + GenericUlong = 1514; + break; + + case OID_GEN_LINK_SPEED: + + GenericUlong = 100000; // 10 Mbps in 100 bps units + break; + + case OID_GEN_TRANSMIT_BUFFER_SPACE: + + GenericUlong = SONIC_LARGE_BUFFER_SIZE * SONIC_NUMBER_OF_TRANSMIT_DESCRIPTORS; + break; + + case OID_GEN_RECEIVE_BUFFER_SPACE: + + GenericUlong = SONIC_LARGE_BUFFER_SIZE * SONIC_NUMBER_OF_RECEIVE_DESCRIPTORS; + break; + + case OID_GEN_TRANSMIT_BLOCK_SIZE: + + GenericUlong = SONIC_LARGE_BUFFER_SIZE; + break; + + case OID_GEN_RECEIVE_BLOCK_SIZE: + + GenericUlong = SONIC_LARGE_BUFFER_SIZE; + break; + + case OID_GEN_VENDOR_ID: + + SONIC_MOVE_MEMORY(VendorId, Adapter->PermanentNetworkAddress, 3); + VendorId[3] = 0x0; + SourceBuffer = VendorId; + SourceBufferLength = sizeof(VendorId); + break; + + case OID_GEN_VENDOR_DESCRIPTION: + + switch (Adapter->AdapterType) { +#ifdef SONIC_EISA + case SONIC_ADAPTER_TYPE_EISA: + SourceBuffer = (PVOID)EisaDescriptor; + SourceBufferLength = sizeof(EisaDescriptor); + break; +#endif +#ifdef SONIC_INTERNAL + case SONIC_ADAPTER_TYPE_INTERNAL: + SourceBuffer = (PVOID)InternalDescriptor; + SourceBufferLength = sizeof(InternalDescriptor); + break; +#endif + default: + ASSERT(FALSE); + break; + } + break; + + case OID_GEN_DRIVER_VERSION: + + GenericUshort = (SONIC_NDIS_MAJOR_VERSION << 8) + SONIC_NDIS_MINOR_VERSION; + SourceBuffer = &GenericUshort; + SourceBufferLength = sizeof(USHORT); + break; + + case OID_GEN_CURRENT_PACKET_FILTER: + + GenericUlong = Adapter->CurrentPacketFilter; + break; + + case OID_GEN_CURRENT_LOOKAHEAD: + + GenericUlong = (SONIC_INDICATE_MAXIMUM-14 < SONIC_LOOPBACK_MAXIMUM) ? + SONIC_INDICATE_MAXIMUM-14 : SONIC_LOOPBACK_MAXIMUM; + break; + + default: + + ASSERT(FALSE); + break; + + } + + break; + + case OID_TYPE_GENERAL_STATISTICS: + + MaskOid = (Oid & OID_INDEX_MASK) - 1; + + switch (Oid & OID_REQUIRED_MASK) { + + case OID_REQUIRED_MANDATORY: + + ASSERT (MaskOid < GM_ARRAY_SIZE); + + if (MaskOid == GM_RECEIVE_NO_BUFFER) { + + // + // This one is read off the card, update unless our + // counter is more (which indicates an imminent + // overflow interrupt, so we don't update). + // + + USHORT MissedPacket; + SONIC_READ_PORT(Adapter, SONIC_FRAME_ALIGNMENT_ERROR, &MissedPacket); + + if ((Adapter->GeneralMandatory[GM_RECEIVE_NO_BUFFER] & 0xffff) < + MissedPacket) { + + Adapter->GeneralMandatory[GM_RECEIVE_NO_BUFFER] = + (Adapter->GeneralMandatory[GM_RECEIVE_NO_BUFFER] & 0xffff0000) + + MissedPacket; + + } + } + + GenericUlong = Adapter->GeneralMandatory[MaskOid]; + break; + + case OID_REQUIRED_OPTIONAL: + + ASSERT (MaskOid < GO_ARRAY_SIZE); + + if (MaskOid == GO_RECEIVE_CRC) { + + // + // This one is read off the card, update unless our + // counter is more (which indicates an imminent + // overflow interrupt, so we don't update). + // + + USHORT CrcError; + SONIC_READ_PORT(Adapter, SONIC_FRAME_ALIGNMENT_ERROR, &CrcError); + + if ((Adapter->GeneralOptional[GO_RECEIVE_CRC - GO_ARRAY_START] & 0xffff) < + CrcError) { + + Adapter->GeneralOptional[GO_RECEIVE_CRC - GO_ARRAY_START] = + (Adapter->GeneralOptional[GO_RECEIVE_CRC - GO_ARRAY_START] & 0xffff0000) + + CrcError; + + } + } + + if ((MaskOid / 2) < GO_COUNT_ARRAY_SIZE) { + + if (MaskOid & 0x01) { + // Frame count + GenericUlong = Adapter->GeneralOptionalFrameCount[MaskOid / 2]; + } else { + // Byte count + SourceBuffer = &Adapter->GeneralOptionalByteCount[MaskOid / 2]; + SourceBufferLength = sizeof(LARGE_INTEGER); + } + + } else { + + GenericUlong = Adapter->GeneralOptional[MaskOid - GO_ARRAY_START]; + + } + + break; + + default: + + ASSERT(FALSE); + break; + + } + + break; + + case OID_TYPE_802_3_OPERATIONAL: + + switch (Oid) { + + case OID_802_3_PERMANENT_ADDRESS: + + SourceBuffer = Adapter->PermanentNetworkAddress; + SourceBufferLength = 6; + break; + + case OID_802_3_CURRENT_ADDRESS: + + SourceBuffer = Adapter->CurrentNetworkAddress; + SourceBufferLength = 6; + break; + + case OID_802_3_MAXIMUM_LIST_SIZE: + + GenericUlong = SONIC_CAM_ENTRIES - 1; + break; + + default: + + ASSERT(FALSE); + break; + + } + + break; + + case OID_TYPE_802_3_STATISTICS: + + MaskOid = (Oid & OID_INDEX_MASK) - 1; + + switch (Oid & OID_REQUIRED_MASK) { + + case OID_REQUIRED_MANDATORY: + + ASSERT (MaskOid < MM_ARRAY_SIZE); + + if (MaskOid == MM_RECEIVE_ERROR_ALIGNMENT) { + + // + // This one is read off the card, update unless our + // counter is more (which indicates an imminent + // overflow interrupt, so we don't update). + // + + USHORT FaError; + SONIC_READ_PORT(Adapter, SONIC_FRAME_ALIGNMENT_ERROR, &FaError); + + if ((Adapter->MediaMandatory[MM_RECEIVE_ERROR_ALIGNMENT] & 0xffff) < + FaError) { + + Adapter->MediaMandatory[MM_RECEIVE_ERROR_ALIGNMENT] = + (Adapter->MediaMandatory[MM_RECEIVE_ERROR_ALIGNMENT] & 0xffff0000) + + FaError; + + } + } + + GenericUlong = Adapter->MediaMandatory[MaskOid]; + break; + + case OID_REQUIRED_OPTIONAL: + + ASSERT (MaskOid < MO_ARRAY_SIZE); + GenericUlong = Adapter->MediaOptional[MaskOid]; + break; + + default: + + ASSERT(FALSE); + break; + + } + + break; + + } + + if (SourceBufferLength > InformationBufferLength) { + *BytesNeeded = SourceBufferLength; + return NDIS_STATUS_INVALID_LENGTH; + } + + SONIC_MOVE_MEMORY (InformationBuffer, SourceBuffer, SourceBufferLength); + *BytesWritten = SourceBufferLength; + + return NDIS_STATUS_SUCCESS; + +} + + +STATIC +NDIS_STATUS +SonicSetInformation( + IN NDIS_HANDLE MiniportAdapterContext, + IN NDIS_OID Oid, + IN PVOID InformationBuffer, + IN ULONG InformationBufferLength, + OUT PULONG BytesRead, + OUT PULONG BytesNeeded + ) + +/*++ + +Routine Description: + + SonicQueryInformation handles a set operation for a + single OID. + +Arguments: + + MiniportAdapterContext - Context registered with the wrapper, really + a pointer to the adapter. + + Oid - The OID of the set. + + InformationBuffer - Holds the data to be set. + + InformationBufferLength - The length of InformationBuffer. + + BytesRead - If the call is successful, returns the number + of bytes read from InformationBuffer. + + BytesNeeded - If there is not enough data in InformationBuffer + to satisfy the OID, returns the amount of storage needed. + +Return Value: + + NDIS_STATUS_SUCCESS + NDIS_STATUS_PENDING + NDIS_STATUS_INVALID_LENGTH + NDIS_STATUS_INVALID_OID + +--*/ + +{ + + PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); + NDIS_STATUS Status; + ULONG PacketFilter; + + // + // Now check for the most common OIDs + // + + switch (Oid) { + + case OID_802_3_MULTICAST_LIST: + + if (InformationBufferLength % ETH_LENGTH_OF_ADDRESS != 0) { + + // + // The data must be a multiple of the Ethernet + // address size. + // + + return NDIS_STATUS_INVALID_DATA; + + } +#if DBG + if (SonicDbg) { + DbgPrint("Processing Change Multicast List request\n"); + } +#endif + + // + // Now make the change. + // + + Status = ChangeAddressDispatch( + Adapter, + InformationBufferLength / ETH_LENGTH_OF_ADDRESS, + InformationBuffer + ); + + *BytesRead = InformationBufferLength; + + return Status; + + break; + + case OID_GEN_CURRENT_PACKET_FILTER: + + if (InformationBufferLength != 4) { + + *BytesNeeded = 4; + return NDIS_STATUS_INVALID_LENGTH; + + } + +#if DBG + if (SonicDbg) { + DbgPrint("Processing Change Packet Filter request\n"); + } +#endif + + // + // Now call the filter package to set the packet filter. + // + + SONIC_MOVE_MEMORY ((PVOID)&PacketFilter, InformationBuffer, sizeof(ULONG)); + + // + // Verify bits + // + + if (PacketFilter & (NDIS_PACKET_TYPE_SOURCE_ROUTING | + NDIS_PACKET_TYPE_SMT | + NDIS_PACKET_TYPE_MAC_FRAME | + NDIS_PACKET_TYPE_FUNCTIONAL | + NDIS_PACKET_TYPE_ALL_FUNCTIONAL | + NDIS_PACKET_TYPE_GROUP + )) { + + *BytesRead = 4; + *BytesNeeded = 0; + + return NDIS_STATUS_NOT_SUPPORTED; + + } + + Status = ChangeClassDispatch( + Adapter, + PacketFilter + ); + + *BytesRead = 4; + return Status; + + break; + + case OID_GEN_CURRENT_LOOKAHEAD: + + // + // No need to record requested lookahead length since we + // always indicate the whole packet. + // + + *BytesRead = 4; + return NDIS_STATUS_SUCCESS; + break; + + default: + + return NDIS_STATUS_INVALID_OID; + break; + + } + +} + +STATIC +NDIS_STATUS +ChangeClassDispatch( + IN PSONIC_ADAPTER Adapter, + IN UINT NewFilterClasses + ) + +/*++ + +Routine Description: + + Modifies the Receive Control Register and Cam Enable registers, + then re-loads the CAM if necessary. + +Arguments: + + Adapter - The adapter. + + NewFilterClasses - New set of filters. + +Return Value: + + NDIS_STATUS_PENDING - if the CAM was reloaded. + NDIS_STATUS_SUCCESS - otherwise. + +--*/ + +{ + // + // The new value for the RCR. + // + USHORT NewReceiveControl = SONIC_RCR_DEFAULT_VALUE; + + // + // First take care of the Receive Control Register. + // + + if (NewFilterClasses & NDIS_PACKET_TYPE_PROMISCUOUS) { + + NewReceiveControl |= SONIC_RCR_PROMISCUOUS_PHYSICAL | + SONIC_RCR_ACCEPT_BROADCAST | + SONIC_RCR_ACCEPT_ALL_MULTICAST; + + } else { + + if (NewFilterClasses & NDIS_PACKET_TYPE_ALL_MULTICAST) { + + NewReceiveControl |= SONIC_RCR_ACCEPT_ALL_MULTICAST; + + } + + if (NewFilterClasses & NDIS_PACKET_TYPE_BROADCAST) { + + NewReceiveControl |= SONIC_RCR_ACCEPT_BROADCAST; + + } + + } + + Adapter->ReceiveControlRegister = NewReceiveControl; + + SONIC_WRITE_PORT(Adapter, SONIC_RECEIVE_CONTROL, + Adapter->ReceiveControlRegister + ); + + if (CAM_DIRECTED_SIGNIFICANT(NewFilterClasses)) { + + Adapter->CamDescriptorArea->CamEnable |= 1; + + } else { + + Adapter->CamDescriptorArea->CamEnable &= ~1; + + } + + if (CAM_MULTICAST_SIGNIFICANT(NewFilterClasses)) { + + Adapter->CamDescriptorArea->CamEnable |= + Adapter->MulticastCamEnableBits; + + } else { + + Adapter->CamDescriptorArea->CamEnable &= 1; + + } + + // + // This will cause a LOAD_CAM interrupt when it is done. + // + + SonicStartCamReload(Adapter); + + Adapter->CurrentPacketFilter = NewFilterClasses; + + return NDIS_STATUS_PENDING; + +} + +STATIC +NDIS_STATUS +ChangeAddressDispatch( + IN PSONIC_ADAPTER Adapter, + IN UINT AddressCount, + IN CHAR Addresses[][ETH_LENGTH_OF_ADDRESS] + ) + +/*++ + +Routine Description: + + Modifies the Receive Control Register and Cam Enable registers, + then re-loads the CAM if necessary. + +Arguments: + + Adapter - The adapter. + + AddressCount - The number of addresses in Addresses + + Addresses - The new multicast address list. + +Return Value: + + NDIS_STATUS_PENDING - if the CAM was reloaded. + NDIS_STATUS_SUCCESS - otherwise. + +--*/ + +{ + + ULONG EnableBit; + NDIS_STATUS Status; + UINT i; + + // + // The first entry in the CAM is for our address. + // + + Adapter->MulticastCamEnableBits = 1; + EnableBit = 1; + + // + // Loop through, copying the addresses into the CAM. + // + + for (i=0; i<AddressCount; i++) { + + EnableBit <<= 1; + Adapter->MulticastCamEnableBits |= EnableBit; + + SONIC_LOAD_CAM_FRAGMENT( + &Adapter->CamDescriptorArea->CamFragments[i+1], + i+1, + Addresses[i] + ); + + } + + Adapter->CamDescriptorAreaSize = AddressCount + 1; + + // + // Now see if we have to worry about re-loading the + // CAM also. + // + + if (CAM_MULTICAST_SIGNIFICANT(Adapter->CurrentPacketFilter)) { + + Adapter->CamDescriptorArea->CamEnable = Adapter->MulticastCamEnableBits; + + // + // This will cause a LOAD_CAM interrupt when it is done. + // + + SonicStartCamReload(Adapter); + +#if DBG + if (SonicDbg) { + DbgPrint("Processing Address request pended\n"); + } +#endif + + + Status = NDIS_STATUS_PENDING; + + } else { + +#if DBG + if (SonicDbg) { + DbgPrint("Processing Address request succeeded\n"); + } +#endif + + Status = NDIS_STATUS_SUCCESS; + + } + + return Status; + +} + diff --git a/private/ntos/ndis/sonic/send.c b/private/ntos/ndis/sonic/send.c new file mode 100644 index 000000000..7f41a8f07 --- /dev/null +++ b/private/ntos/ndis/sonic/send.c @@ -0,0 +1,1305 @@ +/*++ + +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); + + } + +} + + diff --git a/private/ntos/ndis/sonic/sonic.c b/private/ntos/ndis/sonic/sonic.c new file mode 100644 index 000000000..b8322cef4 --- /dev/null +++ b/private/ntos/ndis/sonic/sonic.c @@ -0,0 +1,2800 @@ +/*++ + +Copyright (c) 1990-1992 Microsoft Corporation + +Module Name: + + sonic.c + +Abstract: + + This is the main file for the National Semiconductor SONIC + Ethernet controller. This driver conforms to the NDIS 3.0 + miniport interface. + +Author: + + Adam Barr (adamba) 14-Nov-1990 + +Environment: + + Kernel Mode - Or whatever is the equivalent. + +Revision History: + + +--*/ + +#include <ndis.h> + +#include <sonichrd.h> +#include <sonicsft.h> + + + +// +// This variable is used to control debug output. +// + +#if DBG +INT SonicDbg = 0; +#endif + + +STATIC +VOID +SonicHalt( + IN NDIS_HANDLE MiniportAdapterContext + ); + +STATIC +VOID +SonicShutdown( + IN NDIS_HANDLE MiniportAdapterContext + ); + +STATIC +NDIS_STATUS +SonicInitalize( + OUT PNDIS_STATUS OpenErrorStatus, + OUT PUINT SelectedMediumIndex, + IN PNDIS_MEDIUM MediumArray, + IN UINT MediumArraySize, + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_HANDLE ConfigurationHandle + ); + +STATIC +NDIS_STATUS +SonicReset( + OUT PBOOLEAN AddressingReset, + IN NDIS_HANDLE MiniportAdapterContext + ); + +STATIC +BOOLEAN +SonicSynchClearIsr( + IN PVOID Context + ); + +STATIC +VOID +SonicStopChip( + IN PSONIC_ADAPTER Adapter + ); + +STATIC +BOOLEAN +SetupRegistersAndInit( + IN PSONIC_ADAPTER Adapter + ); + +STATIC +BOOLEAN +SonicInitialInit( + IN PSONIC_ADAPTER Adapter + ); + + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ); + + +STATIC +NDIS_STATUS +SonicRegisterAdapter( + IN NDIS_HANDLE NdisMacHandle, + IN NDIS_HANDLE ConfigurationHandle, + IN PUCHAR NetworkAddress, + IN UCHAR AdapterType, + IN UINT SlotNumber, + IN UINT Controller, + IN UINT MultifunctionAdapter, + IN UINT SonicInterruptVector, + IN UINT SonicInterruptLevel, + IN NDIS_INTERRUPT_MODE SonicInterruptMode + ); + +typedef enum { + SonicHardwareOk, + SonicHardwareChecksum, + SonicHardwareConfig +} SONIC_HARDWARE_STATUS; + +STATIC +SONIC_HARDWARE_STATUS +SonicHardwareGetDetails( + IN PSONIC_ADAPTER Adapter, + IN UINT SlotNumber, + IN UINT Controller, + IN UINT MultifunctionAdapter, + OUT PULONG InitialPort, + OUT PULONG NumberOfPorts, + IN OUT PUINT InterruptVector, + IN OUT PUINT InterruptLevel, + OUT ULONG ErrorLogData[3] + ); + +STATIC +BOOLEAN +SonicHardwareGetAddress( + IN PSONIC_ADAPTER Adapter, + OUT ULONG ErrorLogData[3] + ); + +#ifdef SONIC_INTERNAL + +// +// These routines are support reading the address for the +// sonic internal implementation on the R4000 motherboards. +// + +STATIC +NTSTATUS +SonicHardwareSaveInformation( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ); + +STATIC +BOOLEAN +SonicHardwareVerifyChecksum( + IN PSONIC_ADAPTER Adapter, + IN PUCHAR EthernetAddress, + OUT ULONG ErrorLogData[3] + ); + +#endif + + + +SONIC_DRIVER SonicDriver; + +#pragma NDIS_INIT_FUNCTION(DriverEntry) + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) + +/*++ + +Routine Description: + + This is the primary initialization routine for the sonic driver. + It is simply responsible for the intializing the wrapper and registering + the MAC. It then calls a system and architecture specific routine that + will initialize and register each adapter. + +Arguments: + + DriverObject - Pointer to driver object created by the system. + +Return Value: + + The status of the operation. + +--*/ + +{ + + // + // Receives the status of the NdisRegisterMac operation. + // + NDIS_STATUS Status; + + NDIS_HANDLE SonicWrapperHandle; + + static const NDIS_STRING MacName = NDIS_STRING_CONST("SONIC"); + NDIS_MINIPORT_CHARACTERISTICS SonicChar; + +#if NDIS_WIN + UCHAR pIds[sizeof (EISA_MCA_ADAPTER_IDS) + sizeof (ULONG)]; +#endif + +#if NDIS_WIN + ((PEISA_MCA_ADAPTER_IDS)pIds)->nEisaAdapters=1; + ((PEISA_MCA_ADAPTER_IDS)pIds)->nMcaAdapters=0; + *(PULONG)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray)=SONIC_COMPRESSED_ID; + (PVOID) DriverObject = (PVOID) pIds; +#endif + + // + // Initialize the wrapper. + // + + NdisMInitializeWrapper( + &SonicWrapperHandle, + DriverObject, + RegistryPath, + NULL + ); + + SonicDriver.WrapperHandle = SonicWrapperHandle; + + // + // Initialize the miniport characteristics for the call to + // NdisMRegisterMiniport. + // + + SonicChar.MajorNdisVersion = SONIC_NDIS_MAJOR_VERSION; + SonicChar.MinorNdisVersion = SONIC_NDIS_MINOR_VERSION; + SonicChar.CheckForHangHandler = SonicCheckForHang; + SonicChar.DisableInterruptHandler = SonicDisableInterrupt; + SonicChar.EnableInterruptHandler = SonicEnableInterrupt; + SonicChar.HaltHandler = SonicHalt; + SonicChar.HandleInterruptHandler = SonicHandleInterrupt; + SonicChar.InitializeHandler = SonicInitialize; + SonicChar.ISRHandler = SonicInterruptService; + SonicChar.QueryInformationHandler = SonicQueryInformation; + SonicChar.ReconfigureHandler = NULL; + SonicChar.ResetHandler = SonicReset; + SonicChar.SendHandler = SonicSend; + SonicChar.SetInformationHandler = SonicSetInformation; + SonicChar.TransferDataHandler = SonicTransferData; + + Status = NdisMRegisterMiniport( + SonicWrapperHandle, + &SonicChar, + sizeof(SonicChar) + ); + + if (Status == NDIS_STATUS_SUCCESS) { + + return NDIS_STATUS_SUCCESS; + + } + + + // + // We can only get here if something went wrong with registering + // the mac or *all* of the adapters. + // + + NdisTerminateWrapper(SonicWrapperHandle, NULL); + + return NDIS_STATUS_FAILURE; + +} + +#if DBG +PVOID SonicAdapterAddress; +#endif + + +#pragma NDIS_INIT_FUNCTION(SonicRegisterAdapter) + +STATIC +NDIS_STATUS +SonicRegisterAdapter( + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_HANDLE ConfigurationHandle, + IN PUCHAR NetworkAddress, + IN UCHAR AdapterType, + IN UINT SlotNumber, + IN UINT Controller, + IN UINT MultifunctionAdapter, + IN UINT SonicInterruptVector, + IN UINT SonicInterruptLevel, + IN NDIS_INTERRUPT_MODE SonicInterruptMode + ) + +/*++ + +Routine Description: + + This routine is responsible for the allocation of the datastructures + for the driver as well as any hardware specific details necessary + to talk with the device. + +Arguments: + + MiniportAdapterHandle - The handle given back to the driver from ndis when + the driver registered itself. + + ConfigurationHandle - Config handle passed to MacAddAdapter. + + NetworkAddress - The network address, or NULL if the default + should be used. + + AdapterType - The type of the adapter; currently SONIC_ADAPTER_TYPE_EISA + and SONIC_ADAPTER_TYPE_INTERNAL are supported, + + SlotNumber - The slot number for the EISA card. + + Controller - The controller number for INTERNAL chips. + + MultifunctionAdapter - The INTERNAL bus number for INTERNAL chips. + + SonicInterruptVector - The interrupt vector to use for the adapter. + + SonicInterruptLevel - The interrupt request level to use for this + adapter. + + SonicInterruptMode - The interrupt mode to be use for this adapter. + +Return Value: + + Returns a failure status if anything occurred that prevents the + initialization of the adapter. + +--*/ + +{ + + // + // Pointer for the adapter root. + // + PSONIC_ADAPTER Adapter; + + // + // Status of various NDIS calls. + // + NDIS_STATUS Status; + + // + // Number of ports needed + // + ULONG InitialPort; + ULONG NumberOfPorts; + + // + // Returned from SonicHardwareGetDetails; if it failed, + // we log an error and exit. + // + SONIC_HARDWARE_STATUS HardwareDetailsStatus; + + // + // Used to store error log data from SonicHardwareGetDetails. + // + ULONG ErrorLogData[3]; + + // + // We put in this assertion to make sure that ushort are 2 bytes. + // if they aren't then the initialization block definition needs + // to be changed. + // + // Also all of the logic that deals with status registers assumes + // that control registers are only 2 bytes. + // + + ASSERT(sizeof(USHORT) == 2); + + // + // The Sonic uses four bytes four physical addresses, so we + // must ensure that this is the case (SONIC_PHYSICAL_ADDRESS) + // is defined as a ULONG). + // + + ASSERT(sizeof(SONIC_PHYSICAL_ADDRESS) == 4); + + // + // Allocate the Adapter block. + // + + SONIC_ALLOC_MEMORY(&Status, &Adapter, sizeof(SONIC_ADAPTER)); + + if (Status == NDIS_STATUS_SUCCESS) { +#if DBG + SonicAdapterAddress = Adapter; +#endif + + SONIC_ZERO_MEMORY( + Adapter, + sizeof(SONIC_ADAPTER) + ); + + Adapter->MiniportAdapterHandle = MiniportAdapterHandle; + + Adapter->AdapterType = AdapterType; + if (SonicInterruptMode == NdisInterruptLatched) { + Adapter->InterruptLatched = TRUE; + } + Adapter->PermanentAddressValid = FALSE; + + // + // Set the attributes + // + + NdisMSetAttributes( + MiniportAdapterHandle, + (NDIS_HANDLE)Adapter, + TRUE, + (AdapterType == SONIC_ADAPTER_TYPE_EISA) ? + NdisInterfaceEisa : + NdisInterfaceInternal + ); + + + // + // Allocate the map registers + // + + Status = NdisMAllocateMapRegisters( + MiniportAdapterHandle, + 0, + FALSE, + SONIC_MAX_FRAGMENTS * SONIC_NUMBER_OF_TRANSMIT_DESCRIPTORS, + SONIC_LARGE_BUFFER_SIZE + ); + + if (Status != NDIS_STATUS_SUCCESS) { + + SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER)); + return NDIS_STATUS_RESOURCES; + + } + + // + // This returns the I/O ports used by the Sonic and may + // modify SonicInterruptVector and SonicInterruptLevel, + // as well as modiying some fields in Adapter. + // + + if ((HardwareDetailsStatus = + SonicHardwareGetDetails( + Adapter, + SlotNumber, + Controller, + MultifunctionAdapter, + &InitialPort, + &NumberOfPorts, + &SonicInterruptVector, + &SonicInterruptLevel, + ErrorLogData)) != SonicHardwareOk) { + + // + // Error out. + // + + NdisWriteErrorLogEntry( + MiniportAdapterHandle, + NDIS_ERROR_CODE_NETWORK_ADDRESS, + 6, + hardwareDetails, + SONIC_ERRMSG_HARDWARE_ADDRESS, + NDIS_STATUS_FAILURE, + ErrorLogData[0], + ErrorLogData[1], + ErrorLogData[2] + ); + + NdisMFreeMapRegisters(MiniportAdapterHandle); + SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER)); + return NDIS_STATUS_FAILURE; + + } + + // + // Register the port addresses. + // + + Status = NdisMRegisterIoPortRange( + (PVOID *)(&(Adapter->SonicPortAddress)), + MiniportAdapterHandle, + InitialPort, + NumberOfPorts + ); + + + if (Status != NDIS_STATUS_SUCCESS) { + + NdisMFreeMapRegisters(MiniportAdapterHandle); + SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER)); + return NDIS_STATUS_FAILURE; + + } + + Adapter->NumberOfPorts = NumberOfPorts; + Adapter->InitialPort = InitialPort; + + // + // Allocate memory for all of the adapter structures. + // + + Adapter->NumberOfTransmitDescriptors = + SONIC_NUMBER_OF_TRANSMIT_DESCRIPTORS; + Adapter->NumberOfReceiveBuffers = + SONIC_NUMBER_OF_RECEIVE_BUFFERS; + Adapter->NumberOfReceiveDescriptors = + SONIC_NUMBER_OF_RECEIVE_DESCRIPTORS; + + + if (AllocateAdapterMemory(Adapter)) { + + // + // Get the network address. This writes + // an error log entry if it fails. This routine + // may do nothing on some systems, if + // SonicHardwareGetDetails has already determined + // the network address. + // + + if (!SonicHardwareGetAddress(Adapter, ErrorLogData)) { + + NdisWriteErrorLogEntry( + MiniportAdapterHandle, + NDIS_ERROR_CODE_NETWORK_ADDRESS, + 6, + hardwareDetails, + SONIC_ERRMSG_HARDWARE_ADDRESS, + NDIS_STATUS_FAILURE, + ErrorLogData[0], + ErrorLogData[1], + ErrorLogData[2] + ); + + DeleteAdapterMemory(Adapter); + NdisMFreeMapRegisters(MiniportAdapterHandle); + NdisMDeregisterIoPortRange( + MiniportAdapterHandle, + InitialPort, + NumberOfPorts, + (PVOID)Adapter->SonicPortAddress + ); + SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER)); + return NDIS_STATUS_FAILURE; + + } + + // + // Initialize the current hardware address. + // + + SONIC_MOVE_MEMORY( + Adapter->CurrentNetworkAddress, + (NetworkAddress != NULL) ? + NetworkAddress : + Adapter->PermanentNetworkAddress, + ETH_LENGTH_OF_ADDRESS); + + Adapter->LastTransmitDescriptor = + Adapter->TransmitDescriptorArea + + (Adapter->NumberOfTransmitDescriptors-1); + Adapter->NumberOfAvailableDescriptors = + Adapter->NumberOfTransmitDescriptors; + Adapter->AllocateableDescriptor = + Adapter->TransmitDescriptorArea; + Adapter->TransmittingDescriptor = + Adapter->TransmitDescriptorArea; + Adapter->FirstUncommittedDescriptor = + Adapter->TransmitDescriptorArea; + Adapter->PacketsSinceLastInterrupt = 0; + + Adapter->CurrentReceiveBufferIndex = 0; + Adapter->CurrentReceiveDescriptorIndex = 0; + Adapter->LastReceiveDescriptor = + &Adapter->ReceiveDescriptorArea[ + Adapter->NumberOfReceiveDescriptors-1]; + + // + // Flush the current receive buffer, which is the first one. + // + + NdisFlushBuffer( + Adapter->ReceiveNdisBufferArea[0], + FALSE + ); + + Adapter->ReceiveDescriptorsExhausted = FALSE; + Adapter->ReceiveBuffersExhausted = FALSE; + Adapter->ReceiveControlRegister = SONIC_RCR_DEFAULT_VALUE; + + Adapter->FirstFinishTransmit = NULL; + Adapter->LastFinishTransmit = NULL; + + Adapter->ResetInProgress = FALSE; + Adapter->FirstInitialization = TRUE; + + SONIC_ZERO_MEMORY (&Adapter->GeneralMandatory, GM_ARRAY_SIZE * sizeof(ULONG)); + SONIC_ZERO_MEMORY (&Adapter->GeneralOptionalByteCount, GO_COUNT_ARRAY_SIZE * sizeof(SONIC_LARGE_INTEGER)); + SONIC_ZERO_MEMORY (&Adapter->GeneralOptionalFrameCount, GO_COUNT_ARRAY_SIZE * sizeof(ULONG)); + SONIC_ZERO_MEMORY (&Adapter->GeneralOptional, (GO_ARRAY_SIZE - GO_ARRAY_START) * sizeof(ULONG)); + SONIC_ZERO_MEMORY (&Adapter->MediaMandatory, MM_ARRAY_SIZE * sizeof(ULONG)); + SONIC_ZERO_MEMORY (&Adapter->MediaOptional, MO_ARRAY_SIZE * sizeof(ULONG)); + + // + // Initialize the CAM and associated things. + // At the beginning nothing is enabled since + // our filter is 0, although we do store + // our network address in the first slot. + // + + Adapter->MulticastCamEnableBits = 0x0000; + Adapter->CurrentPacketFilter = 0; + Adapter->CamDescriptorArea->CamEnable = 0x0000; + Adapter->CamDescriptorsUsed = 0x0001; + Adapter->CamDescriptorAreaSize = 1; + + SONIC_LOAD_CAM_FRAGMENT( + &Adapter->CamDescriptorArea->CamFragments[0], + 0, + Adapter->CurrentNetworkAddress + ); + + // + // Initialize the interrupt. + // + + Status = NdisMRegisterInterrupt( + &Adapter->Interrupt, + MiniportAdapterHandle, + SonicInterruptVector, + SonicInterruptLevel, + FALSE, + FALSE, + SonicInterruptMode + ); + + if (Status != NDIS_STATUS_SUCCESS) { + + NdisWriteErrorLogEntry( + MiniportAdapterHandle, + NDIS_ERROR_CODE_INTERRUPT_CONNECT, + 2, + registerAdapter, + SONIC_ERRMSG_INIT_INTERRUPT + ); + + DeleteAdapterMemory(Adapter); + NdisMFreeMapRegisters(MiniportAdapterHandle); + NdisMDeregisterIoPortRange( + MiniportAdapterHandle, + InitialPort, + NumberOfPorts, + (PVOID)Adapter->SonicPortAddress + ); + SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER)); + return Status; + + } + + // + // Start the card up. This writes an error + // log entry if it fails. + // + + if (!SonicInitialInit(Adapter)) { + + NdisMDeregisterInterrupt(&Adapter->Interrupt); + DeleteAdapterMemory(Adapter); + NdisMFreeMapRegisters(MiniportAdapterHandle); + NdisMDeregisterIoPortRange( + MiniportAdapterHandle, + InitialPort, + NumberOfPorts, + (PVOID)Adapter->SonicPortAddress + ); + SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER)); + return NDIS_STATUS_FAILURE; + + } else { + + // + // Register our shutdown handler. + // + + NdisMRegisterAdapterShutdownHandler( + Adapter->MiniportAdapterHandle, // miniport handle. + Adapter, // shutdown context. + SonicShutdown // shutdown handler. + ); + + // + // All done. + // + return NDIS_STATUS_SUCCESS; + + } + + + } else { + + // + // Call to AllocateAdapterMemory failed. + // + + NdisWriteErrorLogEntry( + MiniportAdapterHandle, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 2, + registerAdapter, + SONIC_ERRMSG_ALLOC_MEMORY + ); + + DeleteAdapterMemory(Adapter); + NdisMFreeMapRegisters(MiniportAdapterHandle); + NdisMDeregisterIoPortRange( + MiniportAdapterHandle, + InitialPort, + NumberOfPorts, + (PVOID)Adapter->SonicPortAddress + ); + SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER)); + return NDIS_STATUS_RESOURCES; + + } + + } else { + + // + // Couldn't allocate adapter object. + // + + return NDIS_STATUS_RESOURCES; + + } + +} + + +#pragma NDIS_INIT_FUNCTION(SonicInitialInit) + +STATIC +BOOLEAN +SonicInitialInit( + IN PSONIC_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine sets up the initial init of the driver. + +Arguments: + + Adapter - The adapter for the hardware. + +Return Value: + + None. + +--*/ + +{ + + UINT Time = 50; + + // + // First we make sure that the device is stopped. + // + + SonicStopChip(Adapter); + + // + // Set up the registers. + // + + if (!SetupRegistersAndInit(Adapter)) { + + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_ADAPTER_NOT_FOUND, + 3, + registerAdapter, + SONIC_ERRMSG_INITIAL_INIT + ); + + return FALSE; + + } + + + // + // Delay execution for 1/2 second to give the sonic + // time to initialize. + // + + while (Time > 0) { + + if (!Adapter->FirstInitialization) { + break; + } + + NdisStallExecution(10000); + Time--; + + } + + + // + // The only way that first initialization could have + // been turned off is if we actually initialized. + // + + if (!Adapter->FirstInitialization) { + + ULONG PortValue; + + // + // We actually did get the initialization. + // + // We can start the chip. We may not + // have any bindings to indicate to but this + // is unimportant. + // + + SonicStartChip(Adapter); + + NdisStallExecution(25000); + + SONIC_READ_PORT(Adapter, SONIC_COMMAND, &PortValue); + + return TRUE; + + + } else { + + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_TIMEOUT, + 2, + registerAdapter, + SONIC_ERRMSG_INITIAL_INIT + ); + + return FALSE; + + } + +} + + +STATIC +BOOLEAN +SonicSynchClearIsr( + IN PVOID Context + ) + +/*++ + +Routine Description: + + This routine is used during a reset. It ensures that no + interrupts will come through, and that any DPRs that run + will find no interrupts to process. + +Arguments: + + Context - A pointer to a SONIC_ADAPTER structure. + +Return Value: + + Always returns true. + +--*/ + +{ + + PSONIC_ADAPTER Adapter = (PSONIC_ADAPTER)Context; + + SONIC_WRITE_PORT(Adapter, SONIC_INTERRUPT_STATUS, 0xffff); + Adapter->SimulatedIsr = 0; + + return TRUE; + +} + +extern +VOID +SonicStartChip( + IN PSONIC_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine is used to start an already initialized sonic. + +Arguments: + + Adapter - The adapter for the SONIC to start. + +Return Value: + + None. + +--*/ + +{ + + // + // Take us out of reset mode if we are in it. + // + + SONIC_WRITE_PORT(Adapter, SONIC_COMMAND, + 0x0000 + ); + + SONIC_WRITE_PORT(Adapter, SONIC_COMMAND, + SONIC_CR_RECEIVER_ENABLE + ); + +} + +STATIC +VOID +SonicStopChip( + IN PSONIC_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine is used to stop a sonic. + + This routine is *not* portable. It is specific to the 386 + implementation of the sonic. On the bus master card the ACON bit + must be set in csr3, whereas on the decstation, csr3 remains clear. + +Arguments: + + Adapter - The adapter for the SONIC to stop. + +Return Value: + + None. + +--*/ + +{ + + SONIC_WRITE_PORT(Adapter, SONIC_COMMAND, + SONIC_CR_RECEIVER_DISABLE | + SONIC_CR_SOFTWARE_RESET + ); + +} + +extern +VOID +SonicStartCamReload( + IN PSONIC_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine starts a CAM reload, which will cause an + interrupt when it is done. + +Arguments: + + Adapter - The adapter for the SONIC to reload. + +Return Value: + + None. + +--*/ + +{ + + // + // Move CAM Enable into the appropriate spot. + // + + SONIC_LOAD_CAM_ENABLE( + &Adapter->CamDescriptorArea->CamFragments[ + Adapter->CamDescriptorAreaSize], + Adapter->CamDescriptorArea->CamEnable + ); + + + // + // Flush the CAM before we start the reload. + // + + SONIC_FLUSH_WRITE_BUFFER(Adapter->CamDescriptorAreaFlushBuffer); + + + SONIC_WRITE_PORT(Adapter, SONIC_CAM_DESCRIPTOR, + SONIC_GET_LOW_PART_ADDRESS(Adapter->CamDescriptorAreaPhysical) + ); + + SONIC_WRITE_PORT(Adapter, SONIC_CAM_DESCRIPTOR_COUNT, + (USHORT)Adapter->CamDescriptorAreaSize + ); + + + // + // Start the Load CAM, which will cause an interrupt + // when it is done. + // + + SONIC_WRITE_PORT(Adapter, SONIC_COMMAND, + SONIC_CR_LOAD_CAM + ); + +} + +STATIC +VOID +SonicHalt( + IN NDIS_HANDLE MiniportAdapterContext + ) + +/*++ + +Routine Description: + + SonicUnload is called when the driver is to remove itself. + +Arguments: + + MiniportAdapterContext - Context registered with the wrapper, really + a pointer to the adapter. + +Return Value: + + None. + +--*/ + +{ + PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); + + // + // Stop the chip. + // + + SonicStopChip (Adapter); + + NdisMDeregisterInterrupt(&Adapter->Interrupt); + + DeleteAdapterMemory(Adapter); + NdisMFreeMapRegisters(Adapter->MiniportAdapterHandle); + NdisMDeregisterIoPortRange( + Adapter->MiniportAdapterHandle, + Adapter->InitialPort, + Adapter->NumberOfPorts, + (PVOID)Adapter->SonicPortAddress + ); + SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER)); + + return; + +} + + + +STATIC +VOID +SonicShutdown( + IN NDIS_HANDLE MiniportAdapterContext + ) + +/*++ + +Routine Description: + + SonicShutdown is called when the system is shutdown or it bugchecks. + +Arguments: + + MiniportAdapterContext - Context registered with the wrapper, really + a pointer to the adapter. + +Return Value: + + None. + +--*/ + +{ + PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); + + // + // Stop the chip. + // + + SonicStopChip (Adapter); + + return; + +} + + +#pragma NDIS_INIT_FUNCTION(SonicInitialize) + +STATIC +NDIS_STATUS +SonicInitialize( + OUT PNDIS_STATUS OpenErrorStatus, + OUT PUINT SelectedMediumIndex, + IN PNDIS_MEDIUM MediumArray, + IN UINT MediumArraySize, + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_HANDLE ConfigurationHandle + ) + +/*++ + +Routine Description: + + SonicInitialize adds an adapter to the list supported + by this driver. + +Arguments: + + OpenErrorStatus - Extra status bytes for opening token ring adapters. + + SelectedMediumIndex - Index of the media type chosen by the driver. + + MediumArray - Array of media types for the driver to chose from. + + MediumArraySize - Number of entries in the array. + + MiniportAdapterHandle - Handle for passing to the wrapper when + referring to this adapter. + + ConfigurationHandle - A handle to pass to NdisOpenConfiguration. + +Return Value: + + NDIS_STATUS_SUCCESS + NDIS_STATUS_FAILURE + +--*/ + +{ + + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + NDIS_HANDLE ConfigHandle; + NDIS_STRING AdapterTypeString = NDIS_STRING_CONST("AdapterType"); +#ifdef SONIC_INTERNAL + NDIS_STRING MultifunctionAdapterString = NDIS_STRING_CONST("MultifunctionAdapter"); + NDIS_STRING NetworkControllerString = NDIS_STRING_CONST("NetworkController"); +#endif + PNDIS_CONFIGURATION_PARAMETER ReturnedValue; + PUCHAR NetworkAddress; + UINT NetworkAddressLength; + UCHAR AdapterType; + UINT InterruptVector; + UINT InterruptLevel; + NDIS_INTERRUPT_MODE InterruptMode; + UINT SlotNumber; + UINT Controller = 0; + UINT MultifunctionAdapter = 0; + UINT i; + + // + // Search for the 802.3 media type + // + + for (i=0; i<MediumArraySize; i++) { + + if (MediumArray[i] == NdisMedium802_3) { + break; + } + + } + + if (i == MediumArraySize) { + + return NDIS_STATUS_UNSUPPORTED_MEDIA; + + } + + *SelectedMediumIndex = i; + + // + // Open the configuration info. + // + + NdisOpenConfiguration( + &Status, + &ConfigHandle, + ConfigurationHandle + ); + + if (Status != NDIS_STATUS_SUCCESS) { + return Status; + } + + + // + // Check that adapter type is supported. + // The default depends on the processor type. + // + + AdapterType = SONIC_ADAPTER_TYPE_DEFAULT; + + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &AdapterTypeString, + NdisParameterInteger + ); + + if (Status == NDIS_STATUS_SUCCESS) { + + // + // See if the adapter type is valid. We skip to AdapterTypeRecognized + // if the AdapterType is known to this driver. + // + +#ifdef SONIC_EISA + if (ReturnedValue->ParameterData.IntegerData == SONIC_ADAPTER_TYPE_EISA) { + goto AdapterTypeRecognized; + } +#endif + +#ifdef SONIC_INTERNAL + if (ReturnedValue->ParameterData.IntegerData == SONIC_ADAPTER_TYPE_INTERNAL) { + goto AdapterTypeRecognized; + } +#endif + + // + // Card type not supported by this driver + // + +#if DBG + DbgPrint("SONIC: Error in adapter type: %lx\n", ReturnedValue->ParameterData.IntegerData); +#endif + NdisCloseConfiguration(ConfigHandle); + return NDIS_STATUS_FAILURE; + + +AdapterTypeRecognized: + + AdapterType = (UCHAR)ReturnedValue->ParameterData.IntegerData; + } + + switch (AdapterType) { + +#ifdef SONIC_EISA + + case SONIC_ADAPTER_TYPE_EISA: + { + + NDIS_EISA_FUNCTION_INFORMATION EisaData; + USHORT Portzc88; + UCHAR zc88Value; + UCHAR Mask; + UCHAR InitType; + UCHAR PortValue; + USHORT PortAddress; + PUCHAR CurrentChar; + BOOLEAN LastEntry; + + NdisReadEisaSlotInformation( + &Status, + ConfigurationHandle, + &SlotNumber, + &EisaData + ); + + if (Status != NDIS_STATUS_SUCCESS) { + +#if DBG + DbgPrint("SONIC: Could not read EISA data\n"); +#endif + NdisCloseConfiguration(ConfigHandle); + return NDIS_STATUS_FAILURE; + + } + + CurrentChar = EisaData.InitializationData; + + Portzc88 = (SlotNumber << 12) + 0xc88; + + LastEntry = FALSE; + while (!LastEntry) { + InitType = *(CurrentChar++); + PortAddress = *((USHORT UNALIGNED *)CurrentChar); + CurrentChar += sizeof(USHORT); + + if ((InitType & 0x80) == 0) { + LastEntry = TRUE; + } + + PortValue = *(CurrentChar++); + + if (InitType & 0x40) { + Mask = *(CurrentChar++); + } else { + Mask = 0; + } + + // + // The only port we care about is zc88 (z is the + // slot number) since it has the interrupt in it. + // + + if (PortAddress != Portzc88) { + continue; + } + + zc88Value &= Mask; + zc88Value |= PortValue; + + } + + switch ((zc88Value & 0x06) >> 1) { + case 0: + InterruptVector = 5; break; + case 1: + InterruptVector = 9; break; + case 2: + InterruptVector = 10; break; + case 3: + InterruptVector = 11; break; + } + + InterruptLevel = InterruptVector; + + if ((zc88Value & 0x01) != 0) { + InterruptMode = NdisInterruptLatched; + } else { + InterruptMode = NdisInterruptLevelSensitive; + } + + break; + + } + +#endif // SONIC_EISA + +#ifdef SONIC_INTERNAL + + case SONIC_ADAPTER_TYPE_INTERNAL: + { + + // + // For the internal adapter, we read the MultifunctionAdapter number + // and NetworkController number, which are both optional. For + // passing to SonicRegisterAdapter. + // + + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &MultifunctionAdapterString, + NdisParameterInteger + ); + + if (Status == NDIS_STATUS_SUCCESS) { + + MultifunctionAdapter = ReturnedValue->ParameterData.IntegerData; + + } + + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &NetworkControllerString, + NdisParameterInteger + ); + + if (Status == NDIS_STATUS_SUCCESS) { + + Controller = ReturnedValue->ParameterData.IntegerData; + + } + + // + // These are filled in by SonicHardwareGetDetails. + // + + InterruptVector = 0; + InterruptLevel = 0; + + // + // The internal adapter is level-sensitive. + // + + InterruptMode = NdisInterruptLevelSensitive; + + break; + + } + +#endif // SONIC_INTERNAL + + default: + + ASSERT(FALSE); + break; + + } + + + // + // Read network address + // + + NdisReadNetworkAddress( + &Status, + (PVOID *)&NetworkAddress, + &NetworkAddressLength, + ConfigHandle); + + + // + // Make sure that the address is the right length asnd + // at least one of the bytes is non-zero. + // + + if ((Status == NDIS_STATUS_SUCCESS) && + (NetworkAddressLength == ETH_LENGTH_OF_ADDRESS) && + ((NetworkAddress[0] | + NetworkAddress[1] | + NetworkAddress[2] | + NetworkAddress[3] | + NetworkAddress[4] | + NetworkAddress[5]) != 0)) { + +#if DBG + if (SonicDbg) { + DbgPrint("SONIC: New Address = %.2x-%.2x-%.2x-%.2x-%.2x-%.2x\n", + NetworkAddress[0], + NetworkAddress[1], + NetworkAddress[2], + NetworkAddress[3], + NetworkAddress[4], + NetworkAddress[5]); + } +#endif + + } else { + + // + // Tells SonicRegisterAdapter to use the + // burned-in address. + // + + NetworkAddress = NULL; + + } + + // + // Used passed-in adapter name to register. + // + + Status = SonicRegisterAdapter( + MiniportAdapterHandle, + ConfigurationHandle, + NetworkAddress, + AdapterType, + SlotNumber, + Controller, + MultifunctionAdapter, + InterruptVector, + InterruptLevel, + InterruptMode + ); + + + NdisCloseConfiguration(ConfigHandle); + + + return Status; // should be NDIS_STATUS_SUCCESS + +} + +STATIC +NDIS_STATUS +SonicReset( + OUT PBOOLEAN AddressingReset, + IN NDIS_HANDLE MiniportAdapterContext + ) +/*++ + +Routine Description: + + The SonicReset request instructs the driver to issue a hardware reset + to the network adapter. The driver also resets its software state. See + the description of MiniportMReset for a detailed description of this request. + +Arguments: + + MiniportAdapterContext - Pointer to the adapter structure. + + AddressingReset - Does the adapter need the addressing information reloaded. + +Return Value: + + The function value is the status of the operation. + + +--*/ + +{ + PSONIC_ADAPTER Adapter = + PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); + + *AddressingReset = FALSE; + + SetupForReset(Adapter); + StartAdapterReset(Adapter); + + return NDIS_STATUS_PENDING; + +} + +extern +VOID +StartAdapterReset( + IN PSONIC_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This is the first phase of resetting the adapter hardware. + + It makes the following assumptions: + + 1) That the hardware has been stopped. + + 2) That it can not be preempted. + + 3) That no other adapter activity can occur. + + When this routine is finished all of the adapter information + will be as if the driver was just initialized. + +Arguments: + + Adapter - The adapter whose hardware is to be reset. + +Return Value: + + None. + +--*/ +{ + + // + // These are used for cleaning the rings. + // + + PSONIC_RECEIVE_DESCRIPTOR CurrentReceiveDescriptor; + PSONIC_TRANSMIT_DESCRIPTOR CurrentTransmitDescriptor; + UINT i; + SONIC_PHYSICAL_ADDRESS SonicPhysicalAdr; + + + // + // Shut down the chip. We won't be doing any more work until + // the reset is complete. + // + + SonicStopChip(Adapter); + + // + // Once the chip is stopped we can't get any more interrupts. + // Any interrupts that are "queued" for processing could + // only possibly service this reset. It is therefore safe for + // us to clear the adapter global csr value. + // + Adapter->SimulatedIsr = 0; + + + Adapter->LastTransmitDescriptor = + Adapter->TransmitDescriptorArea + + (Adapter->NumberOfTransmitDescriptors-1); + Adapter->NumberOfAvailableDescriptors = + Adapter->NumberOfTransmitDescriptors; + Adapter->AllocateableDescriptor = + Adapter->TransmitDescriptorArea; + Adapter->TransmittingDescriptor = + Adapter->TransmitDescriptorArea; + Adapter->FirstUncommittedDescriptor = + Adapter->TransmitDescriptorArea; + Adapter->PacketsSinceLastInterrupt = 0; + + Adapter->CurrentReceiveBufferIndex = 0; + Adapter->CurrentReceiveDescriptorIndex = 0; + Adapter->LastReceiveDescriptor = + &Adapter->ReceiveDescriptorArea[ + Adapter->NumberOfReceiveDescriptors-1]; + + // + // Flush the current receive buffer, which is the first one. + // + + NdisFlushBuffer( + Adapter->ReceiveNdisBufferArea[0], + FALSE + ); + + Adapter->ReceiveDescriptorsExhausted = FALSE; + Adapter->ReceiveBuffersExhausted = FALSE; + Adapter->ReceiveControlRegister = SONIC_RCR_DEFAULT_VALUE; + Adapter->HardwareFailure = FALSE; + + // + // Clean the receive descriptors and initialize the link + // fields. + // + + SONIC_ZERO_MEMORY( + Adapter->ReceiveDescriptorArea, + (sizeof(SONIC_RECEIVE_DESCRIPTOR)*Adapter->NumberOfReceiveDescriptors) + ); + + for ( + i = 0, CurrentReceiveDescriptor = Adapter->ReceiveDescriptorArea; + i < Adapter->NumberOfReceiveDescriptors; + i++,CurrentReceiveDescriptor++ + ) { + + CurrentReceiveDescriptor->InUse = SONIC_OWNED_BY_SONIC; + + SonicPhysicalAdr = NdisGetPhysicalAddressLow(Adapter->ReceiveDescriptorAreaPhysical) + + (i * sizeof(SONIC_RECEIVE_DESCRIPTOR)); + + if (i == 0) { + + Adapter->ReceiveDescriptorArea[ + Adapter->NumberOfReceiveDescriptors-1].Link = + SonicPhysicalAdr | SONIC_END_OF_LIST; + + } else { + + Adapter->ReceiveDescriptorArea[i-1].Link = SonicPhysicalAdr; + + } + + } + + + // + // Clean the transmit descriptors and initialize the link + // fields. + // + + SONIC_ZERO_MEMORY( + Adapter->TransmitDescriptorArea, + (sizeof(SONIC_TRANSMIT_DESCRIPTOR)*Adapter->NumberOfTransmitDescriptors) + ); + + for ( + i = 0, CurrentTransmitDescriptor = Adapter->TransmitDescriptorArea; + i < Adapter->NumberOfTransmitDescriptors; + i++,CurrentTransmitDescriptor++ + ) { + + SonicPhysicalAdr = NdisGetPhysicalAddressLow(Adapter->TransmitDescriptorAreaPhysical) + + (i * sizeof(SONIC_TRANSMIT_DESCRIPTOR)); + + if (i == 0) { + + Adapter->TransmitDescriptorArea[Adapter->NumberOfTransmitDescriptors-1].Link = SonicPhysicalAdr; + + } else { + + (CurrentTransmitDescriptor-1)->Link = SonicPhysicalAdr; + + } + + } + + + // + // Recover all of the adapter buffers. + // + + { + + UINT i; + + for ( + i = 0; + i < (SONIC_NUMBER_OF_SMALL_BUFFERS + + SONIC_NUMBER_OF_MEDIUM_BUFFERS + + SONIC_NUMBER_OF_LARGE_BUFFERS); + i++ + ) { + + Adapter->SonicBuffers[i].Next = i+1; + + } + + Adapter->SonicBufferListHeads[0] = -1; + Adapter->SonicBufferListHeads[1] = 0; + Adapter->SonicBuffers[SONIC_NUMBER_OF_SMALL_BUFFERS-1].Next = -1; + Adapter->SonicBufferListHeads[2] = SONIC_NUMBER_OF_SMALL_BUFFERS; + Adapter->SonicBuffers[(SONIC_NUMBER_OF_SMALL_BUFFERS+ + SONIC_NUMBER_OF_MEDIUM_BUFFERS)-1].Next = -1; + Adapter->SonicBufferListHeads[3] = SONIC_NUMBER_OF_SMALL_BUFFERS + + SONIC_NUMBER_OF_MEDIUM_BUFFERS; + Adapter->SonicBuffers[(SONIC_NUMBER_OF_SMALL_BUFFERS+ + SONIC_NUMBER_OF_MEDIUM_BUFFERS+ + SONIC_NUMBER_OF_LARGE_BUFFERS)-1].Next = -1; + + } + + (VOID)SetupRegistersAndInit(Adapter); + +} + +STATIC +BOOLEAN +SetupRegistersAndInit( + IN PSONIC_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + It is this routines responsibility to make sure that the + initialization block is filled and the chip is initialized + *but not* started. + + NOTE: This routine assumes that it is called with the lock + acquired OR that only a single thread of execution is working + with this particular adapter. + +Arguments: + + Adapter - The adapter whose hardware is to be initialized. + +Return Value: + + TRUE if the registers are initialized successfully. + +--*/ +{ + + USHORT CommandRegister; + UINT Time; + + + SONIC_WRITE_PORT(Adapter, SONIC_DATA_CONFIGURATION, + Adapter->DataConfigurationRegister + ); + + SONIC_WRITE_PORT(Adapter, SONIC_RECEIVE_CONTROL, + Adapter->ReceiveControlRegister + ); + + SONIC_WRITE_PORT(Adapter, SONIC_INTERRUPT_MASK, + SONIC_INT_DEFAULT_VALUE + ); + + SONIC_WRITE_PORT(Adapter, SONIC_INTERRUPT_STATUS, + (USHORT)0xffff + ); + + + + SONIC_WRITE_PORT(Adapter, SONIC_UPPER_TRANSMIT_DESCRIPTOR, + SONIC_GET_HIGH_PART_ADDRESS( + NdisGetPhysicalAddressLow(Adapter->TransmitDescriptorAreaPhysical)) + ); + + SONIC_WRITE_PORT(Adapter, SONIC_CURR_TRANSMIT_DESCRIPTOR, + SONIC_GET_LOW_PART_ADDRESS( + NdisGetPhysicalAddressLow(Adapter->TransmitDescriptorAreaPhysical)) + ); + + + SONIC_WRITE_PORT(Adapter, SONIC_UPPER_RECEIVE_DESCRIPTOR, + SONIC_GET_HIGH_PART_ADDRESS( + NdisGetPhysicalAddressLow(Adapter->ReceiveDescriptorAreaPhysical)) + ); + + SONIC_WRITE_PORT(Adapter, SONIC_CURR_RECEIVE_DESCRIPTOR, + SONIC_GET_LOW_PART_ADDRESS( + NdisGetPhysicalAddressLow(Adapter->ReceiveDescriptorAreaPhysical)) + ); + + + // + // The EOBC value cannot be odd (since the card register + // wants it in words); in addition it appears that the + // value in the register must be even, so this number + // has to be a multiple of 4. + // + ASSERT((SONIC_END_OF_BUFFER_COUNT & 0x3) == 0); + + switch (Adapter->AdapterType) { + +#ifdef SONIC_EISA + + case SONIC_ADAPTER_TYPE_EISA: + + // + // For the EISA card, set EOBC to 2 words more than real + // size. + // + // Add the appropriate correction for the rev. C problem. + // + + SONIC_WRITE_PORT(Adapter, SONIC_END_OF_BUFFER_WORD_COUNT, + ((SONIC_END_OF_BUFFER_COUNT+SONIC_EOBC_REV_C_CORRECTION) / 2) + 2 + ); + break; + +#endif // SONIC_EISA + +#ifdef SONIC_INTERNAL + + case SONIC_ADAPTER_TYPE_INTERNAL: + + // + // Add the appropriate correction for the rev. C problem. + // + + SONIC_WRITE_PORT(Adapter, SONIC_END_OF_BUFFER_WORD_COUNT, + (SONIC_END_OF_BUFFER_COUNT+SONIC_EOBC_REV_C_CORRECTION) / 2 + ); + break; + +#endif // SONIC_INTERNAL + + default: + + ASSERT(FALSE); + break; + + } + + + SONIC_WRITE_PORT(Adapter, SONIC_UPPER_RECEIVE_RESOURCE, + SONIC_GET_HIGH_PART_ADDRESS( + NdisGetPhysicalAddressLow(Adapter->ReceiveResourceAreaPhysical)) + ); + + SONIC_WRITE_PORT(Adapter, SONIC_RESOURCE_START, + SONIC_GET_LOW_PART_ADDRESS( + NdisGetPhysicalAddressLow(Adapter->ReceiveResourceAreaPhysical)) + ); + + SONIC_WRITE_PORT(Adapter, SONIC_RESOURCE_END, + (USHORT)(SONIC_GET_LOW_PART_ADDRESS( + NdisGetPhysicalAddressLow(Adapter->ReceiveResourceAreaPhysical)) + + sizeof(SONIC_RECEIVE_RESOURCE) * + Adapter->NumberOfReceiveBuffers) + ); + + SONIC_WRITE_PORT(Adapter, SONIC_RESOURCE_READ, + SONIC_GET_LOW_PART_ADDRESS( + NdisGetPhysicalAddressLow(Adapter->ReceiveResourceAreaPhysical)) + ); + + SONIC_WRITE_PORT(Adapter, SONIC_RESOURCE_WRITE, + SONIC_GET_LOW_PART_ADDRESS( + NdisGetPhysicalAddressLow(Adapter->ReceiveResourceAreaPhysical)) + ); + + + // + // Now take us out of reset mode... + // + + SONIC_WRITE_PORT(Adapter, SONIC_COMMAND, + 0x0000 + ); + + // + // ...and issue the Read RRA command. + // + + SONIC_WRITE_PORT(Adapter, SONIC_COMMAND, + SONIC_CR_READ_RRA + ); + + + + // + // Wait for 1/5 second for Read RRA to finish. + // + + Time = 20; + + while (Time > 0) { + + NdisStallExecution(10000); + + SONIC_READ_PORT(Adapter, SONIC_COMMAND, &CommandRegister); + if ((CommandRegister & SONIC_CR_READ_RRA) == 0) { + break; + } + + Time--; + + } + + if (Time == 0) { + +#if DBG + DbgPrint("SONIC: Could not read RRA\n"); +#endif + return FALSE; + + } + + + // + // This will cause a LOAD_CAM interrupt when it is done. + // + + SonicStartCamReload(Adapter); + + return TRUE; + +} + +extern +VOID +SetupForReset( + IN PSONIC_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine is used to fill in the who and why a reset is + being set up as well as setting the appropriate fields in the + adapter. + +Arguments: + + Adapter - The adapter whose hardware is to be initialized. + +Return Value: + + None. + +--*/ +{ + // + // Ndis buffer mapped + // + PNDIS_BUFFER CurrentBuffer; + + // + // Map register that was used + // + UINT CurMapRegister; + + // + // Packet to abort + // + PNDIS_PACKET Packet; + + // + // Reserved Section of packet + // + PSONIC_PACKET_RESERVED Reserved; + + + // + // Shut down the chip. We won't be doing any more work until + // the reset is complete. We take it out of reset mode, however. + // + + SonicStopChip(Adapter); + + Adapter->ResetInProgress = TRUE; + + + // + // Once the chip is stopped we can't get any more interrupts. + // This call ensures that any ISR which is just about to run + // will find no bits in the ISR, and any DPR which fires will + // find nothing queued to do. + // + + NdisMSynchronizeWithInterrupt( + &Adapter->Interrupt, + SonicSynchClearIsr, + (PVOID)Adapter); + + // + // Un-map all outstanding transmits + // + while (Adapter->FirstFinishTransmit != NULL) { + + // + // Remove first packet from the queue + // + Packet = Adapter->FirstFinishTransmit; + Reserved = PSONIC_RESERVED_FROM_PACKET(Packet); + Adapter->FirstFinishTransmit = Reserved->Next; + + if (Reserved->UsedSonicBuffer) { + continue; + } + + // + // The transmit is finished, so we can release + // the physical mapping used for it. + // + NdisQueryPacket( + Packet, + NULL, + NULL, + &CurrentBuffer, + NULL + ); + + // + // Get starting map register + // + CurMapRegister = Reserved->DescriptorIndex * SONIC_MAX_FRAGMENTS; + + // + // For each buffer + // + while (CurrentBuffer) { + + // + // Finish the mapping + // + NdisMCompleteBufferPhysicalMapping( + Adapter->MiniportAdapterHandle, + CurrentBuffer, + CurMapRegister + ); + + ++CurMapRegister; + + NdisGetNextBuffer( + CurrentBuffer, + &CurrentBuffer + ); + + } + + } + +} + +#ifdef SONIC_INTERNAL + +// +// The next routines are to support reading the registry to +// obtain information about the internal sonic on the +// MIPS R4000 motherboards. +// + +// +// This structure is used as the Context in the callbacks +// to SonicHardwareSaveInformation. +// + +typedef struct _SONIC_HARDWARE_INFO { + + // + // These are read out of the "Configuration Data" + // data. + // + + CCHAR InterruptVector; + KIRQL InterruptLevel; + USHORT DataConfigurationRegister; + LARGE_INTEGER PortAddress; + BOOLEAN DataValid; + UCHAR EthernetAddress[8]; + BOOLEAN AddressValid; + + // + // This is set to TRUE if "Identifier" is equal to + // "SONIC". + // + + BOOLEAN SonicIdentifier; + +} SONIC_HARDWARE_INFO, *PSONIC_HARDWARE_INFO; + + +#pragma NDIS_INIT_FUNCTION(SonicHardwareSaveInformation) + +STATIC +NTSTATUS +SonicHardwareSaveInformation( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ) + +/*++ + +Routine Description: + + This routine is a callback routine for RtlQueryRegistryValues. + It is called back with the data for the "Identifier" value + and verifies that it is "SONIC", then is called back with + the resource list and records the ports, interrupt number, + and DCR value. + +Arguments: + + ValueName - The name of the value ("Identifier" or "Configuration + Data"). + + ValueType - The type of the value (REG_SZ or REG_BINARY). + + ValueData - The null-terminated data for the value. + + ValueLength - The length of ValueData (ignored). + + Context - A pointer to the SONIC_HARDWARE_INFO structure. + + EntryContext - FALSE for "Identifier", TRUE for "Configuration Data". + +Return Value: + + STATUS_SUCCESS + +--*/ + +{ + PSONIC_HARDWARE_INFO HardwareInfo = (PSONIC_HARDWARE_INFO)Context; + + if ((BOOLEAN)EntryContext) { + + // + // This is the "Configuration Data" callback. + // + + if ((ValueType == REG_BINARY || ValueType == REG_FULL_RESOURCE_DESCRIPTOR) && + (ValueLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR))) { + + BOOLEAN InterruptRead = FALSE; + BOOLEAN PortAddressRead = FALSE; + BOOLEAN DeviceSpecificRead = FALSE; + UINT i; + + PCM_PARTIAL_RESOURCE_LIST ResourceList; + PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor; + PCM_SONIC_DEVICE_DATA SonicDeviceData; + + ResourceList = + &((PCM_FULL_RESOURCE_DESCRIPTOR)ValueData)->PartialResourceList; + + for (i = 0; i < ResourceList->Count; i++) { + + ResourceDescriptor = &(ResourceList->PartialDescriptors[i]); + + switch (ResourceDescriptor->Type) { + + case CmResourceTypePort: + + HardwareInfo->PortAddress = ResourceDescriptor->u.Port.Start; + PortAddressRead = TRUE; + break; + + case CmResourceTypeInterrupt: + + HardwareInfo->InterruptVector = (CCHAR)ResourceDescriptor->u.Interrupt.Vector; + HardwareInfo->InterruptLevel = (KIRQL)ResourceDescriptor->u.Interrupt.Level; + InterruptRead = TRUE; + break; + + case CmResourceTypeDeviceSpecific: + + if (i == ResourceList->Count-1) { + + SonicDeviceData = (PCM_SONIC_DEVICE_DATA) + &(ResourceList->PartialDescriptors[ResourceList->Count]); + + // + // Make sure we have enough room for each element we read. + // + + if (ResourceDescriptor->u.DeviceSpecificData.DataSize >= + (ULONG)(FIELD_OFFSET (CM_SONIC_DEVICE_DATA, EthernetAddress[0]))) { + + HardwareInfo->DataConfigurationRegister = + SonicDeviceData->DataConfigurationRegister; + DeviceSpecificRead = TRUE; + + // + // Version.Revision later than 0.0 means that + // the ethernet address is there too. + // + + if ((SonicDeviceData->Version != 0) || + (SonicDeviceData->Revision != 0)) { + + if (ResourceDescriptor->u.DeviceSpecificData.DataSize >= + (ULONG)(FIELD_OFFSET (CM_SONIC_DEVICE_DATA, EthernetAddress[0]) + 8)) { + + SONIC_MOVE_MEMORY( + HardwareInfo->EthernetAddress, + SonicDeviceData->EthernetAddress, + 8); + + HardwareInfo->AddressValid = TRUE; + + } + + } + + } + + } + + break; + + } + + } + + // + // Make sure we got all we wanted. + // + + if (PortAddressRead && InterruptRead && DeviceSpecificRead) { + HardwareInfo->DataValid = TRUE; + } + + } + + } else { + + static const WCHAR SonicString[] = L"SONIC"; + + // + // This is the "Identifier" callback. + // + + if ((ValueType == REG_SZ) && + (ValueLength >= sizeof(SonicString)) && + (RtlCompareMemory (ValueData, (PVOID)&SonicString, sizeof(SonicString)) == sizeof(SonicString))) { + + HardwareInfo->SonicIdentifier = TRUE; + + } + + } + + return STATUS_SUCCESS; + +} + + +#pragma NDIS_INIT_FUNCTION(SonicHardwareVerifyChecksum) + +STATIC +BOOLEAN +SonicHardwareVerifyChecksum( + IN PSONIC_ADAPTER Adapter, + IN PUCHAR EthernetAddress, + OUT ULONG ErrorLogData[3] + ) + +/*++ + +Routine Description: + + This routine verifies that the checksum on the address + for an internal sonic on a MIPS R4000 system is correct. + +Arguments: + + Adapter - The adapter which is being verified. + + EthernetAddress - A pointer to the address, with the checksum + following it. + + ErrorLogData - If the checksum is bad, returns the address + and the checksum we expected. + +Return Value: + + TRUE if the checksum is correct. + +--*/ + +{ + + // + // Iteration variable. + // + UINT i; + + // + // Holds the checksum value. + // + USHORT CheckSum = 0; + + + // + // The network address is stored in the first 6 bytes of + // EthernetAddress. Following that is a zero byte followed + // by a value such that the sum of a checksum on the six + // bytes and this value is 0xff. The checksum is computed + // by adding together the six bytes, with the carry being + // wrapped back to the first byte. + // + + for (i=0; i<6; i++) { + + CheckSum += EthernetAddress[i]; + if (CheckSum > 0xff) { + CheckSum -= 0xff; + } + + } + + + if ((EthernetAddress[6] != 0x00) || + ((EthernetAddress[7] + CheckSum) != 0xff)) { + + ErrorLogData[0] = ((ULONG)(EthernetAddress[3]) << 24) + + ((ULONG)(EthernetAddress[2]) << 16) + + ((ULONG)(EthernetAddress[1]) << 8) + + ((ULONG)(EthernetAddress[0])); + ErrorLogData[1] = ((ULONG)(EthernetAddress[7]) << 24) + + ((ULONG)(EthernetAddress[6]) << 16) + + ((ULONG)(EthernetAddress[5]) << 8) + + ((ULONG)(EthernetAddress[4])); + ErrorLogData[2] = 0xff - CheckSum; + + return FALSE; + + } + + return TRUE; + +} + +#endif // SONIC_INTERNAL + + +#pragma NDIS_INIT_FUNCTION(SonicHardwareGetDetails) + +STATIC +SONIC_HARDWARE_STATUS +SonicHardwareGetDetails( + IN PSONIC_ADAPTER Adapter, + IN UINT SlotNumber, + IN UINT Controller, + IN UINT MultifunctionAdapter, + OUT PULONG InitialPort, + OUT PULONG NumberOfPorts, + IN OUT PUINT InterruptVector, + IN OUT PUINT InterruptLevel, + OUT ULONG ErrorLogData[3] + ) + +/*++ + +Routine Description: + + This routine gets the initial port and number of ports for + the Sonic. It also sets Adapter->PortShift. The ports are + numbered 0, 1, 2, etc. but may appear as 16- or 32-bit + ports, so PortShift will be 1 or 2 depending on how wide + the ports are. + + It also sets the value of Adapter->DataConfigurationRegister, + and may modify InterruptVector, InterruptLevel, and + Adapter->PermanentNetworkAddress. + +Arguments: + + Adapter - The adapter in question. + + SlotNumber - For the EISA card this is the slot number that the + card is in. + + Controller - For the internal version, it is the + NetworkController number. + + MultifunctionAdapter - For the internal version, it is the adapter number. + + InitialPort - The base of the Sonic ports. + + NumberOfPorts - The number of bytes of ports to map. + + InterruptVector - A pointer to the interrupt vector. Depending + on the card type, this may be passed in or returned by + this function. + + InterruptLevel - A pointer to the interrupt level. Depending + on the card type, this may be passed in or returned by + this function. + + ErrorLogData - If the return status is SonicHardwareChecksum, + this returns 3 longwords to be included in the error log. + +Return Value: + + SonicHardwareOk if successful, SonicHardwareChecksum if the + checksum is bad, SonicHardwareConfig for other problems. + +--*/ + +{ + + switch (Adapter->AdapterType) { + +#ifdef SONIC_EISA + + case SONIC_ADAPTER_TYPE_EISA: + + *InitialPort = (SlotNumber << 12); + *NumberOfPorts = 0xD00; + Adapter->PortShift = 1; + Adapter->DataConfigurationRegister = + SONIC_DCR_PROGRAMMABLE_OUTPUT_1 | + SONIC_DCR_USER_DEFINABLE_1 | + SONIC_DCR_3_WAIT_STATE | + SONIC_DCR_BLOCK_MODE_DMA | + SONIC_DCR_32_BIT_DATA_WIDTH | + SONIC_DCR_8_WORD_RECEIVE_FIFO | + SONIC_DCR_8_WORD_TRANSMIT_FIFO; + + return SonicHardwareOk; + break; + +#endif // SONIC_EISA + +#ifdef SONIC_INTERNAL + + case SONIC_ADAPTER_TYPE_INTERNAL: + { + + // + // For MIPS R4000 systems, we have to query the registry to obtain + // information about ports, interrupts, and the value to be + // stored in the DCR register. + // + + // + // NOTE: The following code is NT-specific, since that is + // currently the only system that runs on the MIPS R4000 hardware. + // + // We initialize an RTL_QUERY_TABLE to retrieve the Identifer + // and ConfigurationData strings from the registry. + // + + PWSTR ConfigDataPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter\\#\\NetworkController\\#"; + PWSTR IdentifierString = L"Identifier"; + PWSTR ConfigDataString = L"Configuration Data"; + RTL_QUERY_REGISTRY_TABLE QueryTable[4]; + SONIC_HARDWARE_INFO SonicHardwareInfo; + NTSTATUS Status; + + + // + // Set up QueryTable to do the following: + // + + // + // 1) Call SonicSaveHardwareInformation for the "Identifier" + // value. + // + + QueryTable[0].QueryRoutine = SonicHardwareSaveInformation; + QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED; + QueryTable[0].Name = IdentifierString; + QueryTable[0].EntryContext = (PVOID)FALSE; + QueryTable[0].DefaultType = REG_NONE; + + // + // 2) Call SonicSaveHardwareInformation for the "Configuration Data" + // value. + // + + QueryTable[1].QueryRoutine = SonicHardwareSaveInformation; + QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED; + QueryTable[1].Name = ConfigDataString; + QueryTable[1].EntryContext = (PVOID)TRUE; + QueryTable[1].DefaultType = REG_NONE; + + // + // 3) Stop + // + + QueryTable[2].QueryRoutine = NULL; + QueryTable[2].Flags = 0; + QueryTable[2].Name = NULL; + + + // + // Modify ConfigDataPath to replace the two # symbols with + // the MultifunctionAdapter number and NetworkController number. + // + + ConfigDataPath[67] = (WCHAR)('0' + MultifunctionAdapter); + ConfigDataPath[87] = (WCHAR)('0' + Controller); + + SonicHardwareInfo.DataValid = FALSE; + SonicHardwareInfo.AddressValid = FALSE; + SonicHardwareInfo.SonicIdentifier = FALSE; + + Status = RtlQueryRegistryValues( + RTL_REGISTRY_ABSOLUTE, + ConfigDataPath, + QueryTable, + (PVOID)&SonicHardwareInfo, + NULL); + + if (!NT_SUCCESS(Status)) { +#if DBG + DbgPrint ("SONIC: Could not read hardware information\n"); +#endif + return SonicHardwareConfig; + } + + if (SonicHardwareInfo.DataValid && SonicHardwareInfo.SonicIdentifier) { + + *InterruptVector = (UINT)SonicHardwareInfo.InterruptVector; + *InterruptLevel = (UINT)SonicHardwareInfo.InterruptLevel; + *InitialPort = SonicHardwareInfo.PortAddress.LowPart; + *NumberOfPorts = 192; + Adapter->PortShift = 2; + Adapter->DataConfigurationRegister = + SonicHardwareInfo.DataConfigurationRegister; + + if (SonicHardwareInfo.AddressValid) { + + if (!SonicHardwareVerifyChecksum(Adapter, SonicHardwareInfo.EthernetAddress, ErrorLogData)) { +#if DBG + DbgPrint("SONIC: Invalid registry network address checksum!!\n"); +#endif + return SonicHardwareChecksum; + } + + SONIC_MOVE_MEMORY( + Adapter->PermanentNetworkAddress, + SonicHardwareInfo.EthernetAddress, + 8); + Adapter->PermanentAddressValid = TRUE; + + } + + return SonicHardwareOk; + + } else { + +#if DBG + DbgPrint ("SONIC: Incorrect registry hardware information\n"); +#endif + return SonicHardwareConfig; + + } + + break; + + } + +#endif // SONIC_INTERNAL + + default: + + ASSERT(FALSE); + break; + + } + + return SonicHardwareConfig; + +} + + + +#pragma NDIS_INIT_FUNCTION(SonicHardwareGetAddress) + +STATIC +BOOLEAN +SonicHardwareGetAddress( + IN PSONIC_ADAPTER Adapter, + IN ULONG ErrorLogData[3] + ) + +/*++ + +Routine Description: + + This routine gets the network address from the hardware. + +Arguments: + + Adapter - Where to store the network address. + + ErrorLogData - If the checksum is bad, returns the address + and the checksum we expected. + +Return Value: + + TRUE if successful. + +--*/ + +{ +#define NVRAM_READ_ONLY_BASE 0x8000b000 + + // + // Iteration variable. + // + UINT i; + + + switch (Adapter->AdapterType) { + +#ifdef SONIC_EISA + + case SONIC_ADAPTER_TYPE_EISA: + + // + // The EISA card has the address stored at ports xC90 to xC95, + // where x is the slot number. + // + + for (i = 0; i < 6; i++) { + + NdisRawReadPortUchar( + Adapter->SonicPortAddress + 0xc90 + i, + &Adapter->PermanentNetworkAddress[i]); + + } + + break; + +#endif // SONIC_EISA + +#ifdef SONIC_INTERNAL + + case SONIC_ADAPTER_TYPE_INTERNAL: + { + + NDIS_STATUS Status; + USHORT SiliconRevision; + + if (!Adapter->PermanentAddressValid) { + + // + // Physical addresses for call to NdisMapIoSpace. + // + + NDIS_PHYSICAL_ADDRESS NvRamPhysical = + NDIS_PHYSICAL_ADDRESS_CONST(NVRAM_READ_ONLY_BASE, 0); + + // + // Temporarily maps the NVRAM into our address space. + // + PVOID NvRamMapping; + + + + // + // If PermanentAddressValid is still FALSE then the address + // was not read by SonicHardwareGetDetails, so we must do it + // here. + // + + Status = NdisMMapIoSpace ( + &NvRamMapping, + Adapter->MiniportAdapterHandle, + NvRamPhysical, + 8 + ); + + if (Status != NDIS_STATUS_SUCCESS) { + + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_RESOURCE_CONFLICT, + 0 + ); + + return(FALSE); + + } + + // + // Verify that the checksum matches. + // + + if (!SonicHardwareVerifyChecksum(Adapter, (PUCHAR)NvRamMapping, ErrorLogData)) { + +#if DBG + DbgPrint("SONIC: Invalid NVRAM network address checksum!!\n"); +#endif + NdisMUnmapIoSpace(Adapter->MiniportAdapterHandle, NvRamMapping, 8); + return FALSE; + + } + + // + // Checksum is OK, save the address. + // + + for (i=0; i<6; i++) { + Adapter->PermanentNetworkAddress[i] = *((PUCHAR)NvRamMapping+i); + } + Adapter->PermanentAddressValid = TRUE; + + NdisMUnmapIoSpace(Adapter->MiniportAdapterHandle, NvRamMapping, 8); + + } + + // + // The Data Configuration Register is already set up, but we + // change the FIFO initialization for old revisions. + // + + SONIC_READ_PORT(Adapter, SONIC_SILICON_REVISION, &SiliconRevision); + + if (SiliconRevision < 4) { + + Adapter->DataConfigurationRegister = + (Adapter->DataConfigurationRegister & SONIC_DCR_FIFO_MASK) | + SONIC_DCR_8_WORD_RECEIVE_FIFO | + SONIC_DCR_8_WORD_TRANSMIT_FIFO; + + } + + break; + + } + +#endif // SONIC_INTERNAL + + default: + + ASSERT(FALSE); + break; + + } + + +#if DBG + if (SonicDbg) { + DbgPrint("SONIC: "); + DbgPrint("[ %x-%x-%x-%x-%x-%x ]\n", + (UCHAR)Adapter->PermanentNetworkAddress[0], + (UCHAR)Adapter->PermanentNetworkAddress[1], + (UCHAR)Adapter->PermanentNetworkAddress[2], + (UCHAR)Adapter->PermanentNetworkAddress[3], + (UCHAR)Adapter->PermanentNetworkAddress[4], + (UCHAR)Adapter->PermanentNetworkAddress[5]); + DbgPrint("\n"); + } +#endif + + return TRUE; + +} diff --git a/private/ntos/ndis/sonic/sonic.rc b/private/ntos/ndis/sonic/sonic.rc new file mode 100644 index 000000000..311a777c2 --- /dev/null +++ b/private/ntos/ndis/sonic/sonic.rc @@ -0,0 +1,39 @@ +#include <windows.h> +#include <ntverp.h> + +/*-----------------------------------------------*/ +/* the following lines are specific to this file */ +/*-----------------------------------------------*/ + +/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR + * and VER_INTERNALNAME_STR must be defined before including COMMON.VER + * The strings don't need a '\0', since common.ver has them. + */ +#define VER_FILETYPE VFT_DRV +/* possible values: VFT_UNKNOWN + VFT_APP + VFT_DLL + VFT_DRV + VFT_FONT + VFT_VXD + VFT_STATIC_LIB +*/ +#define VER_FILESUBTYPE VFT2_DRV_NETWORK +/* possible values VFT2_UNKNOWN + VFT2_DRV_PRINTER + VFT2_DRV_KEYBOARD + VFT2_DRV_LANGUAGE + VFT2_DRV_DISPLAY + VFT2_DRV_MOUSE + VFT2_DRV_NETWORK + VFT2_DRV_SYSTEM + VFT2_DRV_INSTALLABLE + VFT2_DRV_SOUND + VFT2_DRV_COMM +*/ +#define VER_FILEDESCRIPTION_STR "ARC Built-In Ethernet network driver" +#define VER_INTERNALNAME_STR "SONIC.SYS" +#define VER_ORIGINALFILENAME_STR "SONIC.SYS" + +#include "common.ver" + diff --git a/private/ntos/ndis/sonic/sonichrd.h b/private/ntos/ndis/sonic/sonichrd.h new file mode 100644 index 000000000..470f18383 --- /dev/null +++ b/private/ntos/ndis/sonic/sonichrd.h @@ -0,0 +1,791 @@ +/*++ + +Copyright (c) 1990-1992 Microsoft Corporation + +Module Name: + + sonichrd.h + +Abstract: + + This file contains the hardware-related definitions for + the SONIC driver. + + The overall structure is taken from the Lance driver + by Tony Ercolano. + +Author: + + Anthony V. Ercolano (tonye) creation-date 19-Jun-1990 + Adam Barr (adamba) 16-Nov-1990 + +Environment: + + This driver is expected to work in DOS, OS2 and NT at the equivalent + of kernel mode. + + Architecturally, there is an assumption in this driver that we are + on a little endian machine. + +Revision History: + + +--*/ + +#ifndef _SONICHARDWARE_ +#define _SONICHARDWARE_ + + +// +// Include processor-specific definitions needed by the sonic. +// This defines the SONIC_READ_PORT and SONIC_WRITE_PORT macros, +// as well as whether SONIC_EISA and SONIC_INTERNAL are defined. +// + +#include <sonicdet.h> + +// +// Compressed ID for the adapter +// + +#define SONIC_COMPRESSED_ID 0x01109841 + + +// +// Offsets from the base of the Sonic registers. +// +// All registers are 16 bits. +// + +#define SONIC_COMMAND 0x00 +#define SONIC_DATA_CONFIGURATION 0x01 +#define SONIC_RECEIVE_CONTROL 0x02 +#define SONIC_TRANSMIT_CONTROL 0x03 +#define SONIC_INTERRUPT_MASK 0x04 +#define SONIC_INTERRUPT_STATUS 0x05 + +#define SONIC_UPPER_TRANSMIT_DESCRIPTOR 0x06 +#define SONIC_CURR_TRANSMIT_DESCRIPTOR 0x07 + +#define SONIC_UPPER_RECEIVE_DESCRIPTOR 0x0d +#define SONIC_CURR_RECEIVE_DESCRIPTOR 0x0e +#define SONIC_END_OF_BUFFER_WORD_COUNT 0x13 +#define SONIC_UPPER_RECEIVE_RESOURCE 0x14 +#define SONIC_RESOURCE_START 0x15 +#define SONIC_RESOURCE_END 0x16 +#define SONIC_RESOURCE_READ 0x17 +#define SONIC_RESOURCE_WRITE 0x18 +#define SONIC_RECEIVE_SEQUENCE 0x2b + +#define SONIC_CAM_ENTRY_POINTER 0x21 +#define SONIC_CAM_ADDRESS_PORT_2 0x22 +#define SONIC_CAM_ADDRESS_PORT_1 0x23 +#define SONIC_CAM_ADDRESS_PORT_0 0x24 +#define SONIC_CAM_ENABLE 0x25 +#define SONIC_CAM_DESCRIPTOR 0x26 +#define SONIC_CAM_DESCRIPTOR_COUNT 0x27 + +#define SONIC_CRC_ERROR 0x2c +#define SONIC_FRAME_ALIGNMENT_ERROR 0x2d +#define SONIC_MISSED_PACKET 0x2e + +#define SONIC_WATCHDOG_TIMER_0 0x29 +#define SONIC_WATCHDOG_TIMER_1 0x2a + +#define SONIC_SILICON_REVISION 0x28 + + +// +// Constants for the SONIC_COMMAND register. +// + +#define SONIC_CR_LOAD_CAM ((USHORT)(0x0200)) +#define SONIC_CR_READ_RRA ((USHORT)(0x0100)) +#define SONIC_CR_SOFTWARE_RESET ((USHORT)(0x0080)) +#define SONIC_CR_START_TIMER ((USHORT)(0x0020)) +#define SONIC_CR_STOP_TIMER ((USHORT)(0x0010)) +#define SONIC_CR_RECEIVER_ENABLE ((USHORT)(0x0008)) +#define SONIC_CR_RECEIVER_DISABLE ((USHORT)(0x0004)) +#define SONIC_CR_TRANSMIT_PACKETS ((USHORT)(0x0002)) +#define SONIC_CR_HALT_TRANSMISSION ((USHORT)(0x0001)) + + +// +// Constants for the SONIC_DATA_CONFIGURATION register. +// + +#define SONIC_DCR_LATCHED_BUS_RETRY ((USHORT)(0x2000)) +#define SONIC_DCR_PROGRAMMABLE_OUTPUT_1 ((USHORT)(0x1000)) +#define SONIC_DCR_PROGRAMMABLE_OUTPUT_0 ((USHORT)(0x0800)) +#define SONIC_DCR_SYNCH_TERMINATION ((USHORT)(0x0400)) +#define SONIC_DCR_USER_DEFINABLE_1 ((USHORT)(0x0200)) +#define SONIC_DCR_USER_DEFINABLE_0 ((USHORT)(0x0100)) +#define SONIC_DCR_0_WAIT_STATE ((USHORT)(0x0000)) +#define SONIC_DCR_1_WAIT_STATE ((USHORT)(0x0040)) +#define SONIC_DCR_2_WAIT_STATE ((USHORT)(0x0080)) +#define SONIC_DCR_3_WAIT_STATE ((USHORT)(0x00c0)) +#define SONIC_DCR_32_BIT_DATA_WIDTH ((USHORT)(0x0020)) +#define SONIC_DCR_16_BIT_DATA_WIDTH ((USHORT)(0x0000)) +#define SONIC_DCR_BLOCK_MODE_DMA ((USHORT)(0x0010)) +#define SONIC_DCR_EMPTY_FILL_DMA ((USHORT)(0x0000)) +#define SONIC_DCR_FIFO_MASK ((USHORT)(0xfff0)) +#define SONIC_DCR_12_WORD_RECEIVE_FIFO ((USHORT)(0x000c)) +#define SONIC_DCR_8_WORD_RECEIVE_FIFO ((USHORT)(0x0008)) +#define SONIC_DCR_4_WORD_RECEIVE_FIFO ((USHORT)(0x0004)) +#define SONIC_DCR_2_WORD_RECEIVE_FIFO ((USHORT)(0x0000)) +#define SONIC_DCR_14_WORD_TRANSMIT_FIFO ((USHORT)(0x0003)) +#define SONIC_DCR_12_WORD_TRANSMIT_FIFO ((USHORT)(0x0002)) +#define SONIC_DCR_8_WORD_TRANSMIT_FIFO ((USHORT)(0x0001)) +#define SONIC_DCR_4_WORD_TRANSMIT_FIFO ((USHORT)(0x0000)) + + +// +// Constants for the SONIC_RECEIVE_CONTROL register. +// + +#define SONIC_RCR_ACCEPT_CRC_ERRORS ((USHORT)(0x8000)) +#define SONIC_RCR_ACCEPT_RUNT_PACKETS ((USHORT)(0x4000)) +#define SONIC_RCR_ACCEPT_BROADCAST ((USHORT)(0x2000)) +#define SONIC_RCR_PROMISCUOUS_PHYSICAL ((USHORT)(0x1000)) +#define SONIC_RCR_ACCEPT_ALL_MULTICAST ((USHORT)(0x0800)) +#define SONIC_RCR_TRANSCEIVER_LOOPBACK ((USHORT)(0x0600)) +#define SONIC_RCR_ENDEC_LOOPBACK ((USHORT)(0x0400)) +#define SONIC_RCR_MAC_LOOPBACK ((USHORT)(0x0200)) +#define SONIC_RCR_NO_LOOPBACK ((USHORT)(0x0000)) + +#define SONIC_RCR_MULTICAST_RECEIVED ((USHORT)(0x0100)) +#define SONIC_RCR_BROADCAST_RECEIVED ((USHORT)(0x0080)) +#define SONIC_RCR_LAST_PACKET_IN_RBA ((USHORT)(0x0040)) +#define SONIC_RCR_CARRIER_SENSE ((USHORT)(0x0020)) +#define SONIC_RCR_COLLISION ((USHORT)(0x0010)) +#define SONIC_RCR_CRC_ERROR ((USHORT)(0x0008)) +#define SONIC_RCR_FRAME_ALIGNMENT ((USHORT)(0x0004)) +#define SONIC_RCR_LOOPBACK_RECEIVED ((USHORT)(0x0002)) +#define SONIC_RCR_PACKET_RECEIVED_OK ((USHORT)(0x0001)) + + +// +// This is needed due to a problem with the SONIC while attempting +// to ignore these packets. +// + +#define SONIC_RCR_DEFAULT_VALUE ((USHORT) \ + (SONIC_RCR_ACCEPT_CRC_ERRORS | \ + SONIC_RCR_ACCEPT_RUNT_PACKETS)) + + +// +// Constants for the SONIC_TRANSMIT_CONTROL register. +// + +#define SONIC_TCR_PROG_INTERRUPT ((USHORT)(0x8000)) +#define SONIC_TCR_CRC_INHIBIT ((USHORT)(0x2000)) +#define SONIC_TCR_EXCESSIVE_DEFERRAL ((USHORT)(0x0400)) +#define SONIC_TCR_DEFERRED_TRANSMISSION ((USHORT)(0x0200)) +#define SONIC_TCR_NO_CARRIER_SENSE ((USHORT)(0x0100)) +#define SONIC_TCR_CARRIER_LOST ((USHORT)(0x0080)) +#define SONIC_TCR_EXCESSIVE_COLLISIONS ((USHORT)(0x0040)) +#define SONIC_TCR_OUT_OF_WINDOW ((USHORT)(0x0020)) +#define SONIC_TCR_FIFO_UNDERRUN ((USHORT)(0x0004)) +#define SONIC_TCR_BYTE_COUNT_MISMATCH ((USHORT)(0x0002)) +#define SONIC_TCR_PACKET_TRANSMITTED_OK ((USHORT)(0x0001)) + +#define SONIC_TCR_STATUS_MASK ((USHORT)(0x07ff)) +#define SONIC_TCR_COLLISIONS_MASK ((USHORT)(0xf800)) +#define SONIC_TCR_COLLISIONS_SHIFT 11 + + +// +// Constants for the SONIC_INTERRUPT_MASK and +// SONIC_INTERRUPT_STATUS registers. +// + +#define SONIC_INT_BUS_RETRY ((USHORT)(0x4000)) +#define SONIC_INT_HEARTBEAT_LOST ((USHORT)(0x2000)) +#define SONIC_INT_LOAD_CAM_DONE ((USHORT)(0x1000)) +#define SONIC_INT_PROG_INTERRUPT ((USHORT)(0x0800)) +#define SONIC_INT_PACKET_RECEIVED ((USHORT)(0x0400)) +#define SONIC_INT_PACKET_TRANSMITTED ((USHORT)(0x0200)) +#define SONIC_INT_TRANSMIT_ERROR ((USHORT)(0x0100)) +#define SONIC_INT_TIMER_COMPLETE ((USHORT)(0x0080)) +#define SONIC_INT_RECEIVE_DESCRIPTORS ((USHORT)(0x0040)) +#define SONIC_INT_RECEIVE_BUFFERS ((USHORT)(0x0020)) +#define SONIC_INT_RECEIVE_OVERFLOW ((USHORT)(0x0010)) +#define SONIC_INT_CRC_TALLY_ROLLOVER ((USHORT)(0x0008)) +#define SONIC_INT_FAE_TALLY_ROLLOVER ((USHORT)(0x0004)) +#define SONIC_INT_MP_TALLY_ROLLOVER ((USHORT)(0x0002)) + +// +// By default, the interrupts we unmask. +// + +#define SONIC_INT_DEFAULT_VALUE ((USHORT) \ + (SONIC_INT_BUS_RETRY | \ + SONIC_INT_LOAD_CAM_DONE | \ + SONIC_INT_PROG_INTERRUPT | \ + SONIC_INT_PACKET_RECEIVED | \ + SONIC_INT_PACKET_TRANSMITTED | \ + SONIC_INT_TRANSMIT_ERROR | \ + SONIC_INT_RECEIVE_DESCRIPTORS | \ + SONIC_INT_RECEIVE_BUFFERS | \ + SONIC_INT_RECEIVE_OVERFLOW | \ + SONIC_INT_CRC_TALLY_ROLLOVER | \ + SONIC_INT_FAE_TALLY_ROLLOVER | \ + SONIC_INT_MP_TALLY_ROLLOVER)) + +// +// The interrupts we acknowledge immediately. +// + +#define SONIC_INT_IMMEDIATE_ACK ((USHORT) \ + (SONIC_INT_DEFAULT_VALUE & \ + ~(SONIC_INT_RECEIVE_DESCRIPTORS | \ + SONIC_INT_RECEIVE_BUFFERS))) + + + +// +// The maximum number of fragments that a transmit descriptor +// can hold. If a packet has more than this, we have to merge +// it into a single buffer before we transmit it. Increasing +// this will prevent us from merging packets with more fragments +// (which are rare) but use more memory in our transmit descriptors +// (which are permanently allocated). For every one that we +// increase this, memory usage goes up by 12 bytes in each +// descriptor. +// + +#define SONIC_MAX_FRAGMENTS 4 + + +// +// The smallest size that a fragment can be. This is due to +// their potentially being underrun problems if a fragment +// shorted than this is transmitted. If a packet has a fragment +// that is too short, we merge it into a single buffer before +// we transmit it. This should not change unless the hardware +// changes in some way. +// + +#define SONIC_MIN_FRAGMENT_SIZE 12 + + +// +// The smallest Ethernet packet size. Packets smaller than this +// have blanks appended to pad them out to this length. +// + +#define SONIC_MIN_PACKET_SIZE 60 + + +// +// The number of entries in the CAM. The CAM (Content Addressable +// Memory) holds the directed and multicast addresses that we +// monitor. We reserve one of these spots for our directed address, +// allowing us SONIC_CAM_ENTRIES - 1 multicast addresses. Changing +// this allows us to handle more multicast addresses without +// forcing the protocol into "all multicast" mode, but allocates +// more memory in the CAM (16 bytes per entry). +// + +#define SONIC_CAM_ENTRIES 16 + + +// +// The number of transmit descriptors in the ring we allocate, +// each of which can hold SONIC_MAX_FRAGMENTS fragments. +// The size of a transmit descriptor is ~100 bytes, varying +// based on SONIC_MAX_FRAGMENTS. +// + +#define SONIC_NUMBER_OF_TRANSMIT_DESCRIPTORS 5 + + +// +// The number and size of the receive buffers we allocate, +// which hold the actual data received off the network. Increasing +// this allows us to receive more large packets, but the +// number of receive descriptors also needs to be increased. +// + +#define SONIC_NUMBER_OF_RECEIVE_BUFFERS 10 +#define SONIC_SIZE_OF_RECEIVE_BUFFERS 4000 + + +// +// This seems to have to be a multiple of four +// (not just two). When there is less than this +// amount left in a Receive Buffer after packet +// reception, the sonic will use the next +// ReceiveBuffer for the next packet. We define it +// larger than the maximum Ethernet packet size, +// so we never get a buffer overflow. +// + +#define SONIC_END_OF_BUFFER_COUNT 1520 + +// +// ERRATA: This is the amount we have to add to +// the EOBC value to account for the bug in revision +// C of the chip, which decrements the RBWC registers +// by two words (four bytes) less than they should be +// on each packet reception. To handle this we +// overestimate EOBC by four bytes times the maximum +// number of packets we could receive in a buffer. +// + +#define SONIC_EOBC_REV_C_CORRECTION ((SONIC_SIZE_OF_RECEIVE_BUFFERS / 64) * 4) + + +// +// The number of receive descriptors we allocate, which hold +// pointers to packets received in the receive buffers. This +// is now kept at twice the number of receive buffers since +// two full-size packets can be received into each receive +// buffer. +// + +#define SONIC_NUMBER_OF_RECEIVE_DESCRIPTORS 20 + + +// +// The small, medium and large buffers are used for merging +// packets that violate our constraints (two many fragments, +// fragments too small). The packet is merged into the smallest +// buffer that can hold it. These should not be increased unless +// there is a problem with many packets being merged; in that +// case it might be better to increase SONIC_MAX_FRAGMENTS +// first (if the problem is too many fragments). +// + +#define SONIC_SMALL_BUFFER_SIZE ((UINT)64) +#define SONIC_MEDIUM_BUFFER_SIZE ((UINT)256) +#define SONIC_LARGE_BUFFER_SIZE ((UINT)1514) + +#define SONIC_NUMBER_OF_SMALL_BUFFERS ((UINT)10) +#define SONIC_NUMBER_OF_MEDIUM_BUFFERS ((UINT)10) +#define SONIC_NUMBER_OF_LARGE_BUFFERS ((UINT)3) + + +// +// This bit in a link field signifies "end of list" to the +// sonic. +// + +#define SONIC_END_OF_LIST 0x01 + + +// +// These are used in the InUse field of Receive Descriptors. +// + +#define SONIC_OWNED_BY_SYSTEM 0x00 +#define SONIC_OWNED_BY_SONIC 0x01 + + +// +// This type defines the physical addresses used by the Sonic +// chip itself. This should always be four bytes. +// + +typedef ULONG SONIC_PHYSICAL_ADDRESS, *PSONIC_PHYSICAL_ADDRESS; + + + +// +// Describes a Receive Buffer Area; the Receive Resource +// Area is an array of these structures. In 32-bit mode the +// upper 16 bits of all the elements are not used. +// + +typedef struct _SONIC_RECEIVE_RESOURCE { + + // + // Pointer to the receive buffer. It must be + // longword (4 bytes) aligned. + // + + SONIC_PHYSICAL_ADDRESS LowBufferAddress; + SONIC_PHYSICAL_ADDRESS HighBufferAddress; + + // + // The number of WORDS in the receive buffer. + // + + UINT LowBufferWordCount; + UINT HighBufferWordCount; + +} SONIC_RECEIVE_RESOURCE, * PSONIC_RECEIVE_RESOURCE; + + +// +// A receive descriptor; the Receive Descriptor Area is a +// linked list of these structures. +// + +typedef struct _SONIC_RECEIVE_DESCRIPTOR { + + // + // After reception this field will contain the contents + // of the SONIC_RECEIVE_CONTROL register. Bits 8-0 are + // status bits. + // + + UINT ReceiveStatus; + + // + // The length of the packet (including the CRC field). + // + + UINT ByteCount; + + // + // A pointer to the location in the RBA where the packet + // resides. A packet is always received into a contiguous + // piece of memory. + // + + SONIC_PHYSICAL_ADDRESS LowPacketAddress; + SONIC_PHYSICAL_ADDRESS HighPacketAddress; + + // + // Contains the RBA and packet sequence number. + // + + UINT SequenceNumber; + + // + // A link to the next receive descriptor. This is set up + // at initialization and is not modified by the SONIC. + // The low bit is the EOL bit, indicating the end of + // the linked list of receive descriptors. + // + + SONIC_PHYSICAL_ADDRESS Link; + + // + // Denotes the ownership of this receive descriptor. + // 0 = driver, non-zero = SONIC. + // + + UINT InUse; + +} SONIC_RECEIVE_DESCRIPTOR, * PSONIC_RECEIVE_DESCRIPTOR; + + + +// +// Describes a fragment of a packet. +// + +typedef struct _SONIC_TRANSMIT_FRAGMENT { + + // + // A pointer to the fragment. May be aligned on any + // byte boundary. + // + + SONIC_PHYSICAL_ADDRESS LowFragmentAddress; + SONIC_PHYSICAL_ADDRESS HighFragmentAddress; + + // + // The size of the fragment. + // + + UINT FragmentByteCount; + +} SONIC_TRANSMIT_FRAGMENT, * PSONIC_TRANSMIT_FRAGMENT; + + +// +// A transmit descriptor for a packet (containing up to +// SONIC_MAX_PACKET_FRAGMENTS pieces); the Transmit +// Descriptor Area is a linked list of these structures. +// If there are fewer than SONIC_MAX_PACKET_FRAGMENTS +// pieces, then the Link field will not be used and +// the link value will instead be put in +// PacketFragments[FragmentCount].FragmentPointerLsb; +// however at initialization the value will be put in +// Link and that is the value that must be used. +// + +typedef struct _SONIC_TRANSMIT_DESCRIPTOR { + + // + // Contains the status after transmission. The status + // is bits 10-0 of the SONIC_TRANSMIT_CONTROL register. + // + + UINT TransmitStatus; + + // + // Before transmission, bits 15-12 of this field are + // copied into the SONIC_TRANSMIT_CONTROL register. + // + + UINT TransmitConfiguration; + + // + // The size of the packet to be transmitted, in bytes. + // + + UINT PacketSize; + + // + // The number of fragments in the packet. + // + + UINT FragmentCount; + + // + // Location and size of each fragment. + // + + SONIC_TRANSMIT_FRAGMENT Fragments[SONIC_MAX_FRAGMENTS]; + + // + // A pointer to the next Transmit Descriptor. This will + // be set at initialization time and will not change. + // However, its value will be copied into the beginning + // of the first unused Fragments[] structure if FragmentCount + // is less than SONIC_MAX_FRAGMENTS (since the Link field + // must follow the last fragment descriptor). + // + + SONIC_PHYSICAL_ADDRESS Link; + +} SONIC_TRANSMIT_DESCRIPTOR, * PSONIC_TRANSMIT_DESCRIPTOR; + + + +// +// Describes an entry in the CAM Descriptor Area. +// + +typedef struct _SONIC_CAM_FRAGMENT { + + // + // The index (0-15) of the CAM entry + // + + UINT CamEntryPointer; + + // + // The Ethernet address, divided into three pieces in + // order from most significant to least significant. + // In each piece only the low-order 16 bits are + // used. I.e., for an Ethernet address 01-02-03-04-05-06, + // CamAddressPort0 would be 0x0102, CamAddressPort1 + // would be 0x0304, and CamAddressPort2 would be 0x0506. + // + + UINT CamAddressPort0; + UINT CamAddressPort1; + UINT CamAddressPort2; + +} SONIC_CAM_FRAGMENT, * PSONIC_CAM_FRAGMENT; + + + +// +// The entire CAM Descriptor Area. In general, the CamEnable +// field is not needed; the value will be stored in the +// CamEntryPointer of the SONIC_CAM_FRAGMENT after the last +// one used. However, the current value will also be +// maintained in CamEnable. +// + +typedef struct _SONIC_CAM_DESCRIPTOR_AREA { + + // + // Holds the index and value of each of the entries. + // + + SONIC_CAM_FRAGMENT CamFragments[SONIC_CAM_ENTRIES]; + + // + // A bit mask indicating which of the entries are enabled + // (only the low 16 bits are used). + // + + UINT CamEnable; + +} SONIC_CAM_DESCRIPTOR_AREA, * PSONIC_CAM_DESCRIPTOR_AREA; + + + +// +// Identifies the AdapterType values that the driver supports. +// + +#define SONIC_ADAPTER_TYPE_EISA 1 +#define SONIC_ADAPTER_TYPE_INTERNAL 2 + + +// +// Macros to get MSB and LSB of an address. +// + +#define SONIC_GET_LOW_PART_ADDRESS(Adr) ((USHORT)((Adr) & 0xffff)) +#define SONIC_GET_HIGH_PART_ADDRESS(Adr) ((USHORT)(((Adr) & 0xffff0000) >> 16)) + + +// +// Set up a SONIC_CAM_FRAGMENT given the entry pointer and +// Ethernet address. +// +// Cfp is a pointer to a CAM Fragment. +// +// Ep is the entry pointer. +// +// Addr is the Ethernet address. +// + +#define SONIC_LOAD_CAM_FRAGMENT(Cfp, Ep, Addr) \ +{ \ + PSONIC_CAM_FRAGMENT _Cfp = (Cfp); \ + UINT _Ep = (Ep); \ + PVOID _Addr = (Addr); \ + _Cfp->CamEntryPointer = _Ep; \ + NdisWriteRegisterUlong((PULONG)(&_Cfp->CamAddressPort0), (ULONG)(((PUSHORT)Addr)[0])); \ + NdisWriteRegisterUlong((PULONG)(&_Cfp->CamAddressPort1), (ULONG)(((PUSHORT)Addr)[1])); \ + NdisWriteRegisterUlong((PULONG)(&_Cfp->CamAddressPort2), (ULONG)(((PUSHORT)Addr)[2])); \ +} + + +// +// Set up a SONIC_CAM_FRAGMENT to hold the CamEnable value +// in it. +// +// Cfp is a pointer to the CAM Fragment. +// +// Ce is the value for CAM Enable. +// + +#define SONIC_LOAD_CAM_ENABLE(_Cfp, _Ce) \ + NdisWriteRegisterUlong((PULONG)(&(_Cfp)->CamEntryPointer), (ULONG)(_Ce)) + + +// +// Set a link field to be the end of a list. +// +// Plink is a pointer to a link field. +// + +#define SONIC_SET_END_OF_LIST(Plink) \ + { \ + ULONG _Data; \ + NdisReadRegisterUlong((PULONG)(Plink), (PULONG)(&_Data)); \ + NdisWriteRegisterUlong((PULONG)(Plink),(ULONG)(_Data | SONIC_END_OF_LIST)); \ + } + +// +// Set a link field to not be the end of a list. +// +// Plink is a pointer to a link field. +// + +#define SONIC_REMOVE_END_OF_LIST(Plink) \ + { \ + ULONG _Data; \ + NdisReadRegisterUlong((PULONG)(Plink), (PULONG)(&_Data)); \ + NdisWriteRegisterUlong((PULONG)(Plink), (ULONG)(_Data & ~SONIC_END_OF_LIST)); \ + } + +// +// Used to set the address of a transmit descriptor fragment. +// +// Tdf is a pointer to a transmit descriptor fragment. +// +// Adr is a *physical* address. +// + +#define SONIC_SET_TRANSMIT_FRAGMENT_ADDRESS(Tdf,Adr) \ +{ \ + SONIC_PHYSICAL_ADDRESS _Adr = (Adr); \ + PSONIC_TRANSMIT_FRAGMENT _Tdf = (Tdf); \ + _Tdf->LowFragmentAddress = (SONIC_PHYSICAL_ADDRESS)_Adr; \ + _Tdf->HighFragmentAddress = (SONIC_PHYSICAL_ADDRESS)(SONIC_GET_HIGH_PART_ADDRESS(_Adr)); \ +} + + +// +// Used to retrieve the address of a transmit descriptor fragment. +// It takes advantage of the fact that we store the entire address +// at LowFragmentAddress, not just the low bits. +// +// Tdf is a pointer to a transmit descriptor fragment. +// +#define SONIC_GET_TRANSMIT_FRAGMENT_ADDRESS(Tdf) \ + (Tdf)->LowFragmentAddress + + +// +// Used to set the length of the transmit descriptor fragment. +// +// Tdf is a pointer to a transmit descriptor fragment. +// +// Len is the unsigned short length of the buffer. +// +#define SONIC_SET_TRANSMIT_FRAGMENT_LENGTH(Tdf,Len) \ + (Tdf)->FragmentByteCount = (UINT)(Len) + + +// +// Used to put the link field on top of a transmit descriptor +// fragment. +// +// Tdf is a pointer to a transmit descriptor fragment. +// +// Link is the link field to copy. +// +#define SONIC_SET_TRANSMIT_LINK(Tdf,Link) \ + NdisWriteRegisterUlong((PULONG)(&(Tdf)->LowFragmentAddress), (ULONG)((Link) | SONIC_END_OF_LIST)) + + + +// +// Used to set the address of a receive resource. +// +// Rrp is a pointer to a receive resource. +// +// Adr is a *physical* address. +// +#define SONIC_SET_RECEIVE_RESOURCE_ADDRESS(Rrp,Adr) \ +{ \ + SONIC_PHYSICAL_ADDRESS _Adr = (Adr); \ + PSONIC_RECEIVE_RESOURCE _Rrp = (Rrp); \ + NdisWriteRegisterUlong((PULONG)(&_Rrp->LowBufferAddress), (ULONG)(_Adr)); \ + NdisWriteRegisterUlong((PULONG)(&_Rrp->HighBufferAddress), (ULONG)(SONIC_GET_HIGH_PART_ADDRESS(_Adr))); \ +} + + +// +// Used to retrieve the address of a receive resource. +// It takes advantage of the fact that we store the entire address +// at LowBufferAddress, not just the low bits. +// +// Rrp is a pointer to a receive resource. +// +#define SONIC_GET_RECEIVE_RESOURCE_ADDRESS(Rrp) \ + (Rrp)->LowBufferAddress + + +// +// Used to set the length of a receive resource. +// +// Rrp is a pointer to a receive resource. +// +// Len is the length of the buffer. +// +#define SONIC_SET_RECEIVE_RESOURCE_LENGTH(Rrp,Len) \ +{ \ + ULONG _Len = (Len); \ + PSONIC_RECEIVE_RESOURCE _Rrp = (Rrp); \ + NdisWriteRegisterUlong((PULONG)(&_Rrp->LowBufferWordCount), (ULONG)(((_Len) & 0x1ffff) >> 1)); \ + NdisWriteRegisterUlong((PULONG)(&_Rrp->HighBufferWordCount), (ULONG)((_Len) >> 17)); \ +} + + +#endif // _SONICHARDWARE_ + diff --git a/private/ntos/ndis/sonic/sonicsft.h b/private/ntos/ndis/sonic/sonicsft.h new file mode 100644 index 000000000..24967e32c --- /dev/null +++ b/private/ntos/ndis/sonic/sonicsft.h @@ -0,0 +1,1039 @@ +/*++ + +Copyright (c) 1990-1992 Microsoft Corporation + +Module Name: + + sonicsft.h + +Abstract: + + The main header for a SONIC NDIS driver. + + The overall structure is taken from the Lance driver + by Tony Ercolano. + +Author: + + Anthony V. Ercolano (tonye) creation-date 19-Jun-1990 + Adam Barr (adamba) 20-Nov-1990 + +Environment: + + This driver is expected to work in DOS, OS2 and NT at the equivalent + of kernel mode. + + Architecturally, there is an assumption in this driver that we are + on a little endian machine. + +Revision History: + + +--*/ + +#ifndef _SONICSFT_ +#define _SONICSFT_ + + +// +// We use STATIC to define procedures that will be static in the +// final build but which we now make extern to allow them to be +// debugged (breakpoints can be set on them). +// + +#if DEVL +#define STATIC +#else +#define STATIC static +#endif + + +// +// This variable is used to control debug output. +// + +#if DBG +extern INT SonicDbg; +#endif + + + +// +// Used when registering ourselves with NDIS. +// + +#define SONIC_NDIS_MAJOR_VERSION 3 +#define SONIC_NDIS_MINOR_VERSION 0 + + +// +// The maximum number of bytes that we will pass to an NDIS +// indication (since we receive packets contiguously, there is +// no reason to limit this). This number includes header and +// data. +// + +#define SONIC_INDICATE_MAXIMUM 1514 + +// +// The maximum number of bytes we will pass to a loopback +// indication (unless it all is in one buffer). This number +// includes only data, not the header. +// + +#define SONIC_LOOPBACK_MAXIMUM 208 + +// +// Used for parsing OIDs +// + +#define OID_TYPE_MASK 0xffff0000 +#define OID_TYPE_GENERAL_OPERATIONAL 0x00010000 +#define OID_TYPE_GENERAL_STATISTICS 0x00020000 +#define OID_TYPE_802_3_OPERATIONAL 0x01010000 +#define OID_TYPE_802_3_STATISTICS 0x01020000 + +#define OID_REQUIRED_MASK 0x0000ff00 +#define OID_REQUIRED_MANDATORY 0x00000100 +#define OID_REQUIRED_OPTIONAL 0x00000200 + +#define OID_INDEX_MASK 0x000000ff + +// +// Indexes in the GeneralMandatory array. +// + +#define GM_TRANSMIT_GOOD 0x00 +#define GM_RECEIVE_GOOD 0x01 +#define GM_TRANSMIT_BAD 0x02 +#define GM_RECEIVE_BAD 0x03 +#define GM_RECEIVE_NO_BUFFER 0x04 +#define GM_ARRAY_SIZE 0x05 + +// +// Indexes in the GeneralOptional array. There are +// two sections, the ones up to COUNT_ARRAY_SIZE +// have entries for number (4 bytes) and number of +// bytes (8 bytes), the rest are a normal array. +// + +#define GO_DIRECTED_TRANSMITS 0x00 +#define GO_MULTICAST_TRANSMITS 0x01 +#define GO_BROADCAST_TRANSMITS 0x02 +#define GO_DIRECTED_RECEIVES 0x03 +#define GO_MULTICAST_RECEIVES 0x04 +#define GO_BROADCAST_RECEIVES 0x05 +#define GO_COUNT_ARRAY_SIZE 0x06 + +#define GO_ARRAY_START 0x0C +#define GO_RECEIVE_CRC 0x0C +#define GO_TRANSMIT_QUEUE_LENGTH 0x0D +#define GO_ARRAY_SIZE 0x0E + +// +// Indexes in the MediaMandatory array. +// + +#define MM_RECEIVE_ERROR_ALIGNMENT 0x00 +#define MM_TRANSMIT_ONE_COLLISION 0x01 +#define MM_TRANSMIT_MORE_COLLISIONS 0x02 +#define MM_ARRAY_SIZE 0x03 + +// +// Indexes in the MediaOptional array. +// + +#define MO_TRANSMIT_DEFERRED 0x00 +#define MO_TRANSMIT_MAX_COLLISIONS 0x01 +#define MO_RECEIVE_OVERRUN 0x02 +#define MO_TRANSMIT_UNDERRUN 0x03 +#define MO_TRANSMIT_HEARTBEAT_FAILURE 0x04 +#define MO_TRANSMIT_TIMES_CRS_LOST 0x05 +#define MO_TRANSMIT_LATE_COLLISIONS 0x06 +#define MO_ARRAY_SIZE 0x07 + + + +// +// Macros used for memory allocation and deallocation. +// +// Note that for regular memory we put no limit on the physical +// address, but for contiguous and noncached we limit it to +// 32 bits since that is all the card can handle (presumably +// such memory will be DMAed to/from by the card). +// + +#define SONIC_ALLOC_MEMORY(_Status, _Address, _Length) \ + { \ + NDIS_PHYSICAL_ADDRESS Temp = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1); \ + *(_Status) = NdisAllocateMemory( \ + (PVOID)(_Address), \ + (_Length), \ + 0, \ + Temp \ + ); \ + } + +#define SONIC_FREE_MEMORY(_Address, _Length) \ + NdisFreeMemory( \ + (PVOID)(_Address), \ + (_Length), \ + 0 \ + ) + + +#define SONIC_ALLOC_CONTIGUOUS_MEMORY(_Status, _Address, _Length) \ + { \ + NDIS_PHYSICAL_ADDRESS Temp = NDIS_PHYSICAL_ADDRESS_CONST(-1, 0); \ + *(_Status) = NdisAllocateMemory( \ + (PVOID)(_Address), \ + (_Length), \ + NDIS_MEMORY_CONTIGUOUS, \ + Temp \ + ); \ + } + +#define SONIC_FREE_CONTIGUOUS_MEMORY(_Address, _Length) \ + NdisFreeMemory( \ + (PVOID)(_Address), \ + (_Length), \ + NDIS_MEMORY_CONTIGUOUS \ + ) + + +#define SONIC_ALLOC_NONCACHED_MEMORY(_Status, _Address, _Length) \ + { \ + NDIS_PHYSICAL_ADDRESS Temp = NDIS_PHYSICAL_ADDRESS_CONST(-1, 0); \ + *(_Status) = NdisAllocateMemory( \ + (PVOID)(_Address), \ + (_Length), \ + NDIS_MEMORY_CONTIGUOUS | NDIS_MEMORY_NONCACHED, \ + Temp \ + ); \ + } + +#define SONIC_FREE_NONCACHED_MEMORY(_Address, _Length) \ + NdisFreeMemory( \ + (PVOID)(_Address), \ + (_Length), \ + NDIS_MEMORY_CONTIGUOUS | NDIS_MEMORY_NONCACHED \ + ) + + + +// +// Macros to move and zero memory. +// + +#define SONIC_MOVE_MEMORY(Destination,Source,Length) NdisMoveMemory(Destination,Source,Length) +#define SONIC_ZERO_MEMORY(Destination,Length) NdisZeroMemory(Destination,Length) + + +// +// Used to record the 8-byte counters. +// + +typedef struct _SONIC_LARGE_INTEGER { + ULONG LowPart; + ULONG HighPart; +} SONIC_LARGE_INTEGER, *PSONIC_LARGE_INTEGER; + +// +// This initializes an 8-byte counter. +// + +#define SonicZeroLargeInteger(LargeInteger) \ +{ \ + LargeInteger.LowPart = 0L;\ + LargeInteger.HighPart = 0L; \ +} + +// +// This adds a longword to an 8-byte counter. +// + +#define SonicAddUlongToLargeInteger(LargeInteger, Ulong) \ +{ \ + PSONIC_LARGE_INTEGER TmpLarge = (LargeInteger); \ + TmpLarge->LowPart += (ULONG)Ulong; \ + if (TmpLarge->LowPart < (ULONG)Ulong) { \ + ++TmpLarge->HighPart; \ + } \ +} + + + +// +// This flushes a buffer for write. +// + +#define SONIC_FLUSH_WRITE_BUFFER(Buffer) \ + NdisFlushBuffer( \ + Buffer, \ + TRUE \ + ) + + +// +// This record type is used to store sonic global data. +// + +typedef struct _SONIC_DRIVER { + + // + // The handle returned by NdisMInitializeWrapper. + // + + NDIS_HANDLE WrapperHandle; + +} SONIC_DRIVER, *PSONIC_DRIVER; + + +// +// This identifies the type of the packet for quick reference +// in the SONIC_PACKET_RESERVED.PacketType field. +// + +#define SONIC_DIRECTED 1 +#define SONIC_MULTICAST 2 +#define SONIC_BROADCAST 3 +#define SONIC_LOOPBACK 4 + + +// +// This record type is inserted into the MiniportReserved portion +// of the packet header. +// +typedef struct _SONIC_PACKET_RESERVED { + + // + // Points to the next packet in the chain of queued packets + // being allocated, or waiting for the finish of transmission. + // + // The packet will either be on the stage list for allocation, + // or on an adapter wide doubly linked list (see below) for + // post transmission processing. + // + PNDIS_PACKET Next; + + // + // If TRUE then the packet caused an adapter buffer to + // be allocated. + // + BOOLEAN UsedSonicBuffer; + + // + // If the previous field was TRUE then this gives the + // index into the array of adapter buffer descriptors that + // contains the old packet information. + // + UCHAR SonicBuffersIndex; + + // + // Gives the index into the ring to packet structure as well + // as the ring descriptors. + // + USHORT DescriptorIndex; + +} SONIC_PACKET_RESERVED,*PSONIC_PACKET_RESERVED; + + +// +// This macro will return a pointer to the sonic reserved portion +// of a packet given a pointer to a packet. +// +#define PSONIC_RESERVED_FROM_PACKET(Packet) \ + ((PSONIC_PACKET_RESERVED)((PVOID)((Packet)->MiniportReserved))) + + +// +// The return code from a multicast operation. +// +typedef enum { CAM_LOADED, CAM_NOT_LOADED } MULTICAST_STATUS; + + +// +// This structure is used to map entries in the ring descriptors +// back to the packets from which the data in the ring descriptor +// originated. +// + +typedef struct _SONIC_DESCRIPTOR_TO_PACKET { + + // + // Points to the packet from which data is being transmitted + // through this ring entry. + // + PNDIS_PACKET OwningPacket; + + // + // Location of our link field. + // + SONIC_PHYSICAL_ADDRESS * LinkPointer; + + // + // Location of the previous link field. + // + SONIC_PHYSICAL_ADDRESS * PrevLinkPointer; + + // + // When a packet is submitted to the hardware we record + // here whether it used adapter buffers and if so, the buffer + // index. + // + UINT SonicBuffersIndex; + BOOLEAN UsedSonicBuffer; + +} SONIC_DESCRIPTOR_TO_PACKET,*PSONIC_DESCRIPTOR_TO_PACKET; + + +// +// If an ndis packet does not meet the hardware contraints then +// an adapter buffer will be allocated. Enough data will be copied +// out of the ndis packet so that by using a combination of the +// adapter buffer and remaining ndis buffers the hardware +// constraints are satisfied. +// +// In the SONIC_ADAPTER structure three threaded lists are kept in +// one array. One points to a list of SONIC_BUFFER_DESCRIPTORS +// that point to small adapter buffers. Another is for medium sized +// buffers and the last for full sized (large) buffers. +// +// The allocation is controlled via a free list head and +// the free lists are "threaded" by a field in the adapter buffer +// descriptor. +// + +typedef struct _SONIC_BUFFER_DESCRIPTOR { + + // + // A Physical pointer to a small, medium, or large buffer. + // + NDIS_PHYSICAL_ADDRESS PhysicalSonicBuffer; + + // + // A virtual pointer to a small, medium, or large buffer. + // + PVOID VirtualSonicBuffer; + + // + // This is used to flush the buffer when it is used. + // + PNDIS_BUFFER FlushBuffer; + + // + // Threads the elements of an array of these descriptors into + // a free list. -1 implies no more entries in the list. + // + INT Next; + + // + // Holds the length of data placed into the buffer. This + // can (and likely will) be less that the actual buffers + // length. + // + UINT DataLength; + +} SONIC_BUFFER_DESCRIPTOR,*PSONIC_BUFFER_DESCRIPTOR; + + +// +// This is the basic structure that defines the state of an +// adapter. There is one of these allocate per adapter that +// the sonic driver supports. +// + +typedef struct _SONIC_ADAPTER { + + // + // Will be true the first time that the hardware is initialized + // by the driver initialization. + // + BOOLEAN FirstInitialization; + + // + // The type of the adapter; current supported values are: + // + // 1: EISA 9010E/B card from National Semiconductor + // 2: Sonic chip on the MIPS R4000 motherbaord. + // + UCHAR AdapterType; + + // + // TRUE if the permanent address is valid. On some cards the + // permanent address is read by SonicHardwareGetDetails; + // if not, it is read later by SonicHardwareGetAddress. + // + BOOLEAN PermanentAddressValid; + + // + // The burned-in network address from the hardware. + // + CHAR PermanentNetworkAddress[ETH_LENGTH_OF_ADDRESS]; + + // + // The current network address from the hardware. + // + CHAR CurrentNetworkAddress[ETH_LENGTH_OF_ADDRESS]; + + // + // This is the buffer pool used to allocate flush buffers + // out of. + // + NDIS_HANDLE FlushBufferPoolHandle; + + // + // Holds the interrupt object for this adapter. + // + NDIS_MINIPORT_INTERRUPT Interrupt; + + // + // TRUE if the adapter is latched, FALSE for level-sensitive. + // + BOOLEAN InterruptLatched; + + // + // Holds a value for simulating an interrupt. + // + USHORT SimulatedIsr; + + // + // The current value to put in the Receive Control Register. + // + USHORT ReceiveControlRegister; + + // + // The value that the Data Configuration Register should be + // initialized to. + // + USHORT DataConfigurationRegister; + + // + // Have we receive an unacknowledged Receive Buffers + // Exhausted interrupt. + // + BOOLEAN ReceiveBuffersExhausted; + + // + // Have we receive an unacknowledged Receive Descriptors + // Exhausted interrupt. + // + BOOLEAN ReceiveDescriptorsExhausted; + + // + // Flag used for checking if a transmit interrupt was dropped. + // + BOOLEAN WakeUpTimeout; + + // + // Used to limit the number of error log entries written. + // + UCHAR WakeUpErrorCount; + + // + // Location of the beginning of the SONIC ports. + // + ULONG SonicPortAddress; + + // + // Number of ports in use + // + UINT NumberOfPorts; + + // + // Hardware address of the first port. + // + UINT InitialPort; + + // + // The number of bits that port numbers need to be shifted left + // before adding them to PortAddress (1 for 16-bit ports, 2 + // for 32-bit ports). + // + UINT PortShift; + + // + // The virtual address of the blank buffer used for padding. + // + PUCHAR BlankBuffer; + + // + // The Physical address of the blank buffer used for padding. + // + NDIS_PHYSICAL_ADDRESS BlankBufferAddress; + + // + // Handle given by NDIS when the adapter was registered. + // + NDIS_HANDLE MiniportAdapterHandle; + + // + // The current packet filter. + // + UINT CurrentPacketFilter; + + // + // The value of the bits in CamEnable, except for + // the first one (which is for our network address); + // as opposed to the value stored in the real CamEnable, + // which may have some bits off if multicast addresses + // are not included in the current packet filter. + // + UINT MulticastCamEnableBits; + + // + // The number of transmit descriptors. + // + UINT NumberOfTransmitDescriptors; + + // + // The number of receive buffers + // + UINT NumberOfReceiveBuffers; + + // + // The number of receive descriptors + // + UINT NumberOfReceiveDescriptors; + + // + // Pointer to the transmit descriptors (this is + // allocated to be of size NumberOfTransmitDescriptors). + // + PSONIC_TRANSMIT_DESCRIPTOR TransmitDescriptorArea; + + // + // The physical address of the transmit descriptor area. + // + NDIS_PHYSICAL_ADDRESS TransmitDescriptorAreaPhysical; + + // + // Pointer to the last transmit descriptor. + // + PSONIC_TRANSMIT_DESCRIPTOR LastTransmitDescriptor; + + // + // Counter that records the number of transmit rings currently + // available for allocation. + // + UINT NumberOfAvailableDescriptors; + + // + // This is used to determine whether to use the programmable + // interrupt on a packet or not. + // + UINT PacketsSinceLastInterrupt; + + // + // Pointer to transmit descriptor ring entry that is the + // first ring entry available for allocation of transmit + // buffers. + // + // Can only be accessed when the adapter lock + // is held. + // + PSONIC_TRANSMIT_DESCRIPTOR AllocateableDescriptor; + + // + // Pointer to a transmit descriptor ring entry that is the + // first ring entry that the MAC currently has made available + // for transmission. + // + // Can only be accessed when the adapter lock + // is held. + // + PSONIC_TRANSMIT_DESCRIPTOR TransmittingDescriptor; + + // + // Pointer to the first packet that has been allocated to + // a transmit packet but has not yet been relinquished to + // the hardware. We need this pointer to keep the transmit + // post processing from running into a packet that has not + // been transmitted. + // + PSONIC_TRANSMIT_DESCRIPTOR FirstUncommittedDescriptor; + + // + // Pointer to an array of structs that map transmit ring entries + // back to a packet (this is allocated to be of size + // NumberOfTransmitDescriptors). + // + PSONIC_DESCRIPTOR_TO_PACKET DescriptorToPacket; + + // + // Pointer to the receive resource area (this is + // allocated to be of size NumberofReceiveBuffers). + // + PSONIC_RECEIVE_RESOURCE ReceiveResourceArea; + + // + // The physical address of ReceiveResourceArea. + // + NDIS_PHYSICAL_ADDRESS ReceiveResourceAreaPhysical; + + // + // Pointer to the array holding the receive buffers (this + // is allocated to be of size NumberofReceiveBuffers). + // + + PVOID * ReceiveBufferArea; + + PNDIS_BUFFER * ReceiveNdisBufferArea; + + // + // The RBA which we are currently taking packets out of + // (will be one of the entries in the ReceiveBufferArea + // array). + // + UINT CurrentReceiveBufferIndex; + + // + // Pointer to the receive descriptor area + // (this is allocated to be of size NumberOfReceiveDescriptors). + // + PSONIC_RECEIVE_DESCRIPTOR ReceiveDescriptorArea; + + // + // The physical address of ReceiveDescriptorArea + // + NDIS_PHYSICAL_ADDRESS ReceiveDescriptorAreaPhysical; + + // + // The last receive descriptor in the area. + // + PSONIC_RECEIVE_DESCRIPTOR LastReceiveDescriptor; + + // + // The index receive descriptor we should look at next (will be + // one of the entries in ReceiveDescriptorArea). + // + UINT CurrentReceiveDescriptorIndex; + + // + // Pointer to the CAM descriptor area. This will be + // located directly after the receive resource area, + // the separate pointer is for convenience. + // + PSONIC_CAM_DESCRIPTOR_AREA CamDescriptorArea; + + // + // The physical address corresponding to CamDescriptorArea. + // This is stored as a 4-byte address since it is just + // a fixed offset from ReceiveResourceAreaPhysical and + // is not allocated with NdisAllocateSharedMemory. + // + SONIC_PHYSICAL_ADDRESS CamDescriptorAreaPhysical; + + // + // This is used to flush the CAM descriptor area. + // + PNDIS_BUFFER CamDescriptorAreaFlushBuffer; + + // + // The last entry in the CAM that is used. + // + UINT CamDescriptorAreaSize; + + // + // An bitmask showing which entries in the CAM are + // used or reserved for use. + // + UINT CamDescriptorsUsed; + + // + // Pointer to the first transmitting packet that is actually + // sending. + // + PNDIS_PACKET FirstFinishTransmit; + + // + // Pointer to the last transmitting packet that is actually + // sending. + // + PNDIS_PACKET LastFinishTransmit; + + // + // Listheads for the adapters buffers. If the list + // head is equal to -1 then there are no free elements + // on the list. + // + // The list heads must only be accessed when the + // adapter lock is held. + // + // Note that the listhead at index 0 will always be -1. + // + INT SonicBufferListHeads[4]; + + // + // Pointers to an array of adapter buffer descriptors. + // The array will actually be threaded together by + // three free lists. The lists will be for small, + // medium and full sized packets. + // + PSONIC_BUFFER_DESCRIPTOR SonicBuffers; + + // + // This holds the actual memory used by the small + // sonic buffers (so that it can be a single piece + // of memory and therefore only use a single physical + // address. + // + PVOID SmallSonicBuffers; + + // + // This holds the memory for the medium sonic buffers. + // + PVOID MediumSonicBuffers; + + // + // Flag that when enabled lets routines know that a reset + // is in progress, for the purposes of blocking other + // requests (except other resets). + // + BOOLEAN ResetInProgress; + + // + // Has there been a hardware failure + // + BOOLEAN HardwareFailure; + + // + // Count how often we log an error from finding a packet in + // the wrong RBA. + // + + USHORT WrongRbaErrorLogCount; + + // + // These hold adapter statistics. + // + ULONG GeneralMandatory[GM_ARRAY_SIZE]; + SONIC_LARGE_INTEGER GeneralOptionalByteCount[GO_COUNT_ARRAY_SIZE]; + ULONG GeneralOptionalFrameCount[GO_COUNT_ARRAY_SIZE]; + ULONG GeneralOptional[GO_ARRAY_SIZE - GO_ARRAY_START]; + ULONG MediaMandatory[MM_ARRAY_SIZE]; + ULONG MediaOptional[MO_ARRAY_SIZE]; + + // + // For indicating loopback packets. + // + + UCHAR Loopback[SONIC_LOOPBACK_MAXIMUM]; + +} SONIC_ADAPTER,*PSONIC_ADAPTER; + + +// +// Given a MacContextHandle return the PSONIC_ADAPTER +// it represents. +// + +#define PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(Handle) \ + ((PSONIC_ADAPTER)((PVOID)(Handle))) + + +// +// procedures which do error logging +// + +typedef enum _SONIC_PROC_ID{ + registerAdapter, + openAdapter, + hardwareDetails, + handleDeferred, + processReceiveInterrupts +} SONIC_PROC_ID; + + +// +// Error log values +// + +#define SONIC_ERRMSG_INIT_INTERRUPT (ULONG)0x01 +#define SONIC_ERRMSG_CREATE_FILTER (ULONG)0x02 +#define SONIC_ERRMSG_ALLOC_MEMORY (ULONG)0x03 +#define SONIC_ERRMSG_REGISTER_ADAPTER (ULONG)0x04 +#define SONIC_ERRMSG_ALLOC_DEVICE_NAME (ULONG)0x05 +#define SONIC_ERRMSG_ALLOC_ADAPTER (ULONG)0x06 +#define SONIC_ERRMSG_INITIAL_INIT (ULONG)0x07 +#define SONIC_ERRMSG_OPEN_DB (ULONG)0x08 +#define SONIC_ERRMSG_ALLOC_OPEN (ULONG)0x09 +#define SONIC_ERRMSG_HARDWARE_ADDRESS (ULONG)0x0A +#define SONIC_ERRMSG_WRONG_RBA (ULONG)0x0B + + + + +// +// Definitions of sonic functions which are used by multiple +// source files. +// + + +// +// alloc.c +// + +extern +BOOLEAN +AllocateAdapterMemory( + IN PSONIC_ADAPTER Adapter + ); + +extern +VOID +DeleteAdapterMemory( + IN PSONIC_ADAPTER Adapter + ); + + +// +// interrup.c +// + +extern +VOID +SonicDisableInterrupt( + IN NDIS_HANDLE MiniportAdapterContext + ); + +extern +VOID +SonicEnableInterrupt( + IN NDIS_HANDLE MiniportAdapterContext + ); + +extern +VOID +SonicHandleInterrupt( + IN NDIS_HANDLE MiniportAdapterContext + ); + +extern +VOID +SonicInterruptService( + OUT PBOOLEAN InterruptRecognized, + OUT PBOOLEAN QueueDpc, + IN PVOID Context + ); + +extern +BOOLEAN +SonicCheckForHang( + IN PVOID MiniportAdapterContext + ); + +// +// request.c +// + +extern +NDIS_STATUS +SonicQueryInformation( + IN NDIS_HANDLE MiniportAdapterContext, + IN NDIS_OID Oid, + IN PVOID InformationBuffer, + IN ULONG InformationBufferLength, + OUT PULONG BytesWritten, + OUT PULONG BytesNeeded + ); + +extern +NDIS_STATUS +SonicSetInformation( + IN NDIS_HANDLE MiniportAdapterContext, + IN NDIS_OID Oid, + IN PVOID InformationBuffer, + IN ULONG InformationBufferLength, + OUT PULONG BytesRead, + OUT PULONG BytesNeeded + ); + +extern +NDIS_STATUS +SonicChangeClass( + IN UINT OldFilterClasses, + IN UINT NewFilterClasses, + IN NDIS_HANDLE NdisBindingContext, + IN PNDIS_REQUEST NdisRequest, + IN BOOLEAN Set + ); + +extern +NDIS_STATUS +SonicChangeAddresses( + IN UINT OldAddressCount, + IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS], + IN UINT NewAddressCount, + IN CHAR NewAddresses[][ETH_LENGTH_OF_ADDRESS], + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_REQUEST NdisRequest, + IN BOOLEAN Set + ); + +// +// send.c +// + +extern +NDIS_STATUS +SonicSend( + IN NDIS_HANDLE MiniportAdapterHandle, + IN PNDIS_PACKET Packet, + IN UINT SendFlags + ); + +// +// sonic.c +// + +extern +VOID +SonicStartChip( + IN PSONIC_ADAPTER Adapter + ); + +extern +VOID +StartAdapterReset( + IN PSONIC_ADAPTER Adapter + ); + +extern +VOID +SetupForReset( + IN PSONIC_ADAPTER Adapter + ); + +extern +VOID +SonicStartCamReload( + IN PSONIC_ADAPTER Adapter + ); + +extern +NDIS_STATUS +SonicInitialize( + OUT PNDIS_STATUS OpenErrorStatus, + OUT PUINT SelectedMediumIndex, + IN PNDIS_MEDIUM MediumArray, + IN UINT MediumArraySize, + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_HANDLE ConfigurationHandle + ); +// +// transfer.c +// + +extern +NDIS_STATUS +SonicTransferData( + OUT PNDIS_PACKET Packet, + OUT PUINT BytesTransferred, + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_HANDLE MiniportReceiveContext, + IN UINT ByteOffset, + IN UINT BytesToTransfer + ); + +#endif // _SONICSFT_ diff --git a/private/ntos/ndis/sonic/sources b/private/ntos/ndis/sonic/sources new file mode 100644 index 000000000..3f3e59baa --- /dev/null +++ b/private/ntos/ndis/sonic/sources @@ -0,0 +1,61 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + Steve Wood (stevewo) 12-Apr-1990 + +NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl + +!ENDIF + +MAJORCOMP=ntos +MINORCOMP=ndis2 + +TARGETNAME=sonic +TARGETPATH=\nt\public\sdk\lib +TARGETTYPE=DRIVER + +TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib + +C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER + +INCLUDES=..\inc;..\..\inc + +SOURCES= + +i386_SOURCES=alloc.c \ + interrup.c \ + request.c \ + send.c \ + sonic.c \ + sonic.rc \ + transfer.c + +MIPS_SOURCES=alloc.c \ + interrup.c \ + request.c \ + send.c \ + sonic.c \ + sonic.rc \ + transfer.c + +ALPHA_SOURCES= + +RELATIVE_DEPTH=..\.. + +MSC_WARNING_LEVEL=/W3 /WX + diff --git a/private/ntos/ndis/sonic/transfer.c b/private/ntos/ndis/sonic/transfer.c new file mode 100644 index 000000000..403e51ee8 --- /dev/null +++ b/private/ntos/ndis/sonic/transfer.c @@ -0,0 +1,247 @@ +/*++ + +Copyright (c) 1990-1992 Microsoft Corporation + +Module Name: + + transfer.c + +Abstract: + + This file contains the code to implement the MacTransferData + API for the NDIS 3.0 miniport interface. + +Author: + + Anthony V. Ercolano (Tonye) 12-Sept-1990 + +Environment: + + Kernel Mode - Or whatever is the equivalent. + +Revision History: + + +--*/ + +#include <ndis.h> + +#include <sonichrd.h> +#include <sonicsft.h> + + +extern +NDIS_STATUS +SonicTransferData( + OUT PNDIS_PACKET Packet, + OUT PUINT BytesTransferred, + IN NDIS_HANDLE MiniportAdapterContext, + IN NDIS_HANDLE MiniportReceiveContext, + IN UINT ByteOffset, + IN UINT BytesToTransfer + ) + +/*++ + +Routine Description: + + A protocol calls the SonicTransferData request (indirectly via + NdisTransferData) from within its Receive event handler + to instruct the driver to copy the contents of the received packet + a specified paqcket buffer. + +Arguments: + + MiniportAdapterContext - Context registered with the wrapper, really + a pointer to the adapter. + + MiniportReceiveContext - The context value passed by the driver on its call + to NdisMEthIndicateReceive. The driver can use this value to determine + which packet, on which adapter, is being received. + + ByteOffset - An unsigned integer specifying the offset within the + received packet at which the copy is to begin. If the entire packet + is to be copied, ByteOffset must be zero. + + BytesToTransfer - An unsigned integer specifying the number of bytes + to copy. It is legal to transfer zero bytes; this has no effect. If + the sum of ByteOffset and BytesToTransfer is greater than the size + of the received packet, then the remainder of the packet (starting from + ByteOffset) is transferred, and the trailing portion of the receive + buffer is not modified. + + Packet - A pointer to a descriptor for the packet storage into which + the MAC is to copy the received packet. + + BytesTransfered - A pointer to an unsigned integer. The MAC writes + the actual number of bytes transferred into this location. This value + is not valid if the return status is STATUS_PENDING. + +Return Value: + + The function value is the status of the operation. + + +--*/ + +{ + // + // Buffer is the buffer to copy from. + // + PCHAR Buffer = (PCHAR)MiniportReceiveContext + ByteOffset; + + // + // Holds the count of the number of ndis buffers comprising the + // destination packet. + // + UINT DestinationBufferCount; + + // + // Points to the buffer into which we are putting data. + // + PNDIS_BUFFER DestinationCurrentBuffer; + + // + // Points to the location in Buffer from which we are extracting data. + // + PUCHAR SourceCurrentAddress; + + // + // Holds the virtual address of the current destination buffer. + // + PVOID DestinationVirtualAddress; + + // + // Holds the length of the current destination buffer. + // + UINT DestinationCurrentLength; + + // + // Keep a local variable of BytesTransferred so we aren't referencing + // through a pointer. + // + UINT LocalBytesTransferred = 0; + + // + // MiniportAdapterContext is not referenced. + // + MiniportAdapterContext; + + // + // Take care of boundary condition of zero length copy. + // + + if (BytesToTransfer == 0) { + *BytesTransferred = 0; + return NDIS_STATUS_SUCCESS; + } + + // + // Get the first buffer of the destination. + // + + NdisQueryPacket( + Packet, + NULL, + &DestinationBufferCount, + &DestinationCurrentBuffer, + NULL + ); + + // + // Could have a null packet. + // + + if (DestinationBufferCount == 0) { + *BytesTransferred = 0; + return NDIS_STATUS_SUCCESS; + } + + NdisQueryBuffer( + DestinationCurrentBuffer, + &DestinationVirtualAddress, + &DestinationCurrentLength + ); + + // + // Set up the source address. + // + + SourceCurrentAddress = Buffer; + + + while (LocalBytesTransferred < BytesToTransfer) { + + // + // Check to see whether we've exhausted the current destination + // buffer. If so, move onto the next one. + // + + if (DestinationCurrentLength == 0) { + + NdisGetNextBuffer( + DestinationCurrentBuffer, + &DestinationCurrentBuffer + ); + + if (DestinationCurrentBuffer == NULL) { + + // + // We've reached the end of the packet. We return + // with what we've done so far. (Which must be shorter + // than requested.) + // + + break; + + } + + NdisQueryBuffer( + DestinationCurrentBuffer, + &DestinationVirtualAddress, + &DestinationCurrentLength + ); + + continue; + + } + + // + // Copy the data. + // + + { + + // + // Holds the amount of data to move. + // + UINT AmountToMove; + + // + // Holds the amount desired remaining. + // + UINT Remaining = BytesToTransfer - LocalBytesTransferred; + + + AmountToMove = DestinationCurrentLength; + + AmountToMove = ((Remaining < AmountToMove)? + (Remaining):(AmountToMove)); + + SONIC_MOVE_MEMORY( + DestinationVirtualAddress, + SourceCurrentAddress, + AmountToMove + ); + + SourceCurrentAddress += AmountToMove; + LocalBytesTransferred += AmountToMove; + DestinationCurrentLength -= AmountToMove; + + } + + } + + *BytesTransferred = LocalBytesTransferred; + return NDIS_STATUS_SUCCESS; +} |