1695 lines
42 KiB
C
1695 lines
42 KiB
C
|
/*++
|
|||
|
|
|||
|
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);
|
|||
|
|
|||
|
}
|