summaryrefslogtreecommitdiffstats
path: root/private/ntos/ndis/sonic/interrup.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/ndis/sonic/interrup.c')
-rw-r--r--private/ntos/ndis/sonic/interrup.c1694
1 files changed, 1694 insertions, 0 deletions
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);
+
+}