diff options
Diffstat (limited to 'private/ntos/ndis/ibmtok2i/interrup.c')
-rw-r--r-- | private/ntos/ndis/ibmtok2i/interrup.c | 1376 |
1 files changed, 1376 insertions, 0 deletions
diff --git a/private/ntos/ndis/ibmtok2i/interrup.c b/private/ntos/ndis/ibmtok2i/interrup.c new file mode 100644 index 000000000..8db43f373 --- /dev/null +++ b/private/ntos/ndis/ibmtok2i/interrup.c @@ -0,0 +1,1376 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + interrup.c + +Abstract: + + This module contains the interrupt-processing code for the + TOK162 NDIS 3.0 driver. + +Author: + + Kevin Martin (KevinMa) 26-Jan-1994 + +Environment: + + Kernel Mode. + +Revision History: + +--*/ + +#include <tok162sw.h> + +VOID +TOK162ProcessReceiveInterrupts( + IN PTOK162_ADAPTER Adapter + ); + +VOID +TOK162ProcessCommandInterrupts( + IN PTOK162_ADAPTER Adapter + ); + + +VOID +TOK162Isr( + OUT PBOOLEAN InterruptRecognized, + OUT PBOOLEAN QueueDpc, + IN PVOID Context + ) + +/*++ + +Routine Description: + + Interrupt service routine for the TOK162. Used only during init. + The NdisMRegisterInterrupt() call (reset.c) specified not to call the + ISR for every interrupt. The DPC is called directly instead. + +Arguments: + + Interrupt - Interrupt object for the TOK162. + + Context - Really a pointer to the adapter. + +Return Value: + + Returns true if the interrupt really was from the TOK162 and whether the + wrapper should queue a DPC. + +--*/ + +{ + + // + // Holds the pointer to the adapter structure. + // + PTOK162_ADAPTER Adapter = Context; + + // + // Holds IsrpHigh with some bits masked off. + // + USHORT Sif; + + // + // Indicate that an interrupt has occurred (internal logging and + // debug print's). + // + VERY_LOUD_DEBUG(DbgPrint("TOK162!ISR\n");) + IF_LOG('o'); + + // + // Read the adapter interrupt register + // + READ_ADAPTER_USHORT(Adapter,PORT_OFFSET_STATUS,&Sif); + + // + // Check if this is our interrupt. If it is, set flag indicating that the + // interrupt is recognized. Otherwise indicate that the interrupt is not + // ours. + // + if ((Sif & STATUS_SYSTEM_INTERRUPT) != 0) { + + *InterruptRecognized = TRUE; + + } else { + + *InterruptRecognized = FALSE; + + } + + // + // Mask off the interrupt type portion of the register. + // + Sif = (UCHAR) (Sif & STATUS_INT_CODE_MASK); + + // + // If this is a receive, go ahead and do the DPC. This allows us to keep + // in synch with the card concerning the receive list index. Also, for a + // a receive there is no need to allow the SSB to be updated as the DPC + // routine will do this for us. If it isn't a receive, we need to indicate + // that no DPC is necessary and we also allow the SSB to be updated. + // + if (Sif == STATUS_INT_CODE_RECEIVE_STATUS) { + + IF_LOG('p'); + + *QueueDpc = TRUE; + + // + // If we have a command, then it is the open or an error has occurred. + // Indicate that the Ssb can be cleared after the open info has been + // obtained. + // + } else if (Sif == STATUS_INT_CODE_CMD_STATUS) { + + if (Adapter->Ssb->Command == CMD_DMA_OPEN) { + + Adapter->SsbStatus1 = Adapter->Ssb->Status1; + Adapter->InitialOpenComplete = TRUE; + + } + + // + // Enable updating of the SSB + // + IF_LOG('z'); + + WRITE_ADAPTER_USHORT(Adapter, + PORT_OFFSET_STATUS, + ENABLE_SSB_UPDATE + ); + + + *QueueDpc = FALSE; + + // + // If we get the SCB clear interrupt, then we can do the receive command. + // + } else if (Sif == STATUS_INT_CODE_SCB_CLEAR) { + + DoTheReceive(Adapter); + Adapter->InitialReceiveSent = TRUE; + + } else { + + // + // Enable updating of the SSB + // + IF_LOG('z'); + + WRITE_ADAPTER_USHORT(Adapter, + PORT_OFFSET_STATUS, + ENABLE_SSB_UPDATE + ); + + *QueueDpc = FALSE; + + } + + // + // Indicate the ISR routine has ended. + // + IF_LOG('O'); +} + + +VOID +TOK162DeferredTimer( + IN PVOID SystemSpecific1, + IN PTOK162_ADAPTER Adapter, + IN PVOID SystemSpecific2, + IN PVOID SystemSpecific3 + ) +/*++ + +Routine Description: + + Just an entry point to distinguish between a timer call and the wrapper + calling the DPC directly. + +Arguments: + + Adapter - pointer to current adapter + + The rest are not used, but simply passed on + +Return Value: + + None + +--*/ +{ + // + // Indicate that a timer has expired. + // + VERY_LOUD_DEBUG(DbgPrint("TOK162!Deferred Timer called\n");) + + // + // Call the standard DPC handler. + // + TOK162HandleInterrupt(Adapter); +} + + +VOID +TOK162HandleInterrupt( + IN NDIS_HANDLE MiniportAdapterContext + ) + +/*++ + +Routine Description: + + Main routine for processing interrupts. + +Arguments: + + Adapter - The Adapter to process interrupts for. + +Return Value: + + None. + +--*/ + +{ + // + // Pointer to the TOK162 adapter structure. + // + PTOK162_ADAPTER Adapter = ((PTOK162_ADAPTER)MiniportAdapterContext); + + // + // Holds the value of the interrupt type + // + USHORT IMask = 0; + + // + // If any receive interrupts are processed, we have to indicate that + // the receive work has been completed after all interrupts have been + // processed. + // + BOOLEAN IndicateReceiveComplete = FALSE; + + // + // Indicate that the DPC routine has been called. + // + EXTRA_LOUD_DEBUG(DbgPrint("TOK162!DPC was just called\n");) + IF_LOG('r'); + + // + // Loop through processing interrupts until we have processed them all. + // + while (TRUE) { + + // + // Read the adapter interrupt register + // + READ_ADAPTER_USHORT(Adapter, + PORT_OFFSET_STATUS, + &IMask + ); + + // + // If this is not our interrupt, end DPC processing + // + if ((IMask & STATUS_SYSTEM_INTERRUPT) == 0) { + + // + // Indicate that we received a bad interrupt and break + // out of the loop. + // + IF_LOG('a'); + + break; + + } else { + + // + // Indicatate that the interrupt was found to be ours. + // + IF_LOG('A'); + + // + // Record pertinent information about the interrupt as this + // card/chipset only allows one interrupt to be indicated by + // the card at a time. + // + Adapter->SsbCommand = Adapter->Ssb->Command; + Adapter->SsbStatus1 = Adapter->Ssb->Status1; + Adapter->SsbStatus2 = Adapter->Ssb->Status2; + Adapter->SsbStatus3 = Adapter->Ssb->Status3; + + } + + // + // Figure out the type of interrupt + // + IMask = (UCHAR) (IMask & STATUS_INT_CODE_MASK); + + // + // Indicate the type of interrupt to the debugger. + // + EXTRA_LOUD_DEBUG(DbgPrint("TOK162!New IMask is %x\n",IMask);) + + // + // Process the interrupt based on the type of interrupt. + // + switch(IMask) { + + case STATUS_INT_CODE_RING: + + // + // We have a ring status change. Log this fact. + // + IF_LOG('b'); + + // + // If we have a soft error, it is possible that the + // card has become overrun with receives. Therefore, the + // TOK162ProcessRingInterrupts will return TRUE in this + // case to allow us to call ProcessReceiveInterrupts(). + // In all other cases, TOK162ProcessRingInterrupts() will + // return FALSE. + // + if (TOK162ProcessRingInterrupts(Adapter) == TRUE) { + + TOK162ProcessReceiveInterrupts(Adapter); + + // + // Indicate that we did process receives during this + // DPC. + // + IndicateReceiveComplete = TRUE; + + } + + break; + + case STATUS_INT_CODE_RECEIVE_STATUS: + + // + // We have a receive interrupt. Log this fact. + // + IF_LOG('c'); + + // + // Process the interrupt. + // + TOK162ProcessReceiveInterrupts(Adapter); + + // + // Indicate that we did process a receive during this + // DPC. + // + IndicateReceiveComplete = TRUE; + + break; + + case STATUS_INT_CODE_XMIT_STATUS: + + // + // We have a transmit interrupt. Log this fact. + // + IF_LOG('d'); + + // + // Process the transmit. + // + TOK162ProcessTransmitInterrupts(Adapter); + + break; + + case STATUS_INT_CODE_CMD_STATUS: + + // + // We have a command interrupt to process. Log this fact. + // + IF_LOG('e'); + + // + // If there is a command structure that has been sent to the + // adapter, then we will process that command. Otherwise, we + // simply return. + // + if (Adapter->CommandOnCard != NULL) { + + // + // Process the active command. + // + TOK162ProcessCommandInterrupts(Adapter); + + } + break; + + default: + + // + // The interrupt type is not one that we know (illegal value). + // Indicate this to the debugger. + // + LOUD_DEBUG(DbgPrint("TOK162!Int Command %x, %x\n",Adapter->SsbCommand, + Adapter->SsbStatus1);) + + break; + + } + + // + // Indicate that we are about to dismiss the interrupt. + // + IF_LOG('z'); + + // + // Dismiss the interrupt, allowing the SSB to be updated. + // + WRITE_ADAPTER_USHORT(Adapter, + PORT_OFFSET_STATUS, + ENABLE_SSB_UPDATE + ); + + } + + // + // If we processed any receive interrupts, IndicateReceiveComplete() will + // be set to TRUE. In this case, we need to indicate that all receives + // are complete. + // + if (IndicateReceiveComplete) { + + // + // Indicate to the debugger that we are doing the complete. + // + EXTRA_LOUD_DEBUG(DbgPrint("TOK162!Doing the indicate complete on the receive\n");) + + // + // Call the Token Ring Filter to indicate the receive complete. + // + NdisMTrIndicateReceiveComplete(Adapter->MiniportAdapterHandle); + + } + + // + // Log and indicate to the debugger that we are ending DPC processing. + // + IF_LOG('R'); + EXTRA_LOUD_DEBUG(DbgPrint("TOK162!Ending DPC processing\n");) + +} + + +VOID +TOK162ProcessReceiveInterrupts( + IN PTOK162_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + Process the packets that have finished receiving. + + NOTE: This routine assumes that no other thread of execution + is processing receives! + +Arguments: + + Adapter - The adapter to indicate to. + +Return Value: + + Whether to clear interrupt or not + +--*/ + +{ + + // + // We don't get here unless there was a receive. Loop through + // the receive blocks starting at the last known block owned by + // the hardware. + // + // After we find a packet we give the routine that process the + // packet through the filter, the buffers virtual address (which + // is always the lookahead size) and as the MAC Context the + // index to the receive block. + // + + // + // Pointer to the receive block being examined. + // + PTOK162_SUPER_RECEIVE_LIST CurrentEntry = Adapter->ReceiveQueueCurrent; + + // + // Used during receiveindicate to let the filter know the header size + // of the given buffer. + // + USHORT HeaderSize; + + // + // Used to indicate the total size of the frame to the filter. + // + USHORT FrameSize; + + // + // Points to the beginning of the received buffer. Used to determine the + // size of the frame header (source routing). + // + PUCHAR Temp; + + // + // Log the fact that we are processing a receive. + // + IF_LOG('C'); + + // + // Continue processing receives until we have exhausted them. + // + while (TRUE) { + + // + // Ensure that our Receive Entry is on an even boundary. + // + ASSERT(!(NdisGetPhysicalAddressLow(CurrentEntry->Self) & 1)); + + // + // Send the receive status byte to the debugger. + // + EXTRA_LOUD_DEBUG(DbgPrint( + "TOK162!Receive CSTAT == %x\n",CurrentEntry->Hardware.CSTAT);) + + // + // Check to see if CSTAT has been changed indicating + // the receive entry has been modified + // + if (CurrentEntry->Hardware.CSTAT & RECEIVE_CSTAT_VALID) { + + // + // Record the receive list entry following the last good + // entry as the starting point for the next time receives + // are processed. + // + Adapter->ReceiveQueueCurrent = CurrentEntry; + + // + // Tell the adapter to allow more receives. + // + WRITE_ADAPTER_USHORT(Adapter, + PORT_OFFSET_COMMAND, + ENABLE_RECEIVE_VALID + ); + + return; + + } + + // + // Get a pointer to the first byte of the current receive buffer. + // + Temp = (PUCHAR)CurrentEntry->ReceiveBuffer; + + // + // If the source routing bit is on, figure out the size of the + // MAC Frame header. Otherwise, the size is set to the default + // of 14 (decimal). + // + HeaderSize = 14; + + + if (Temp[8] & 0x80) { + + // + // Source routing bit is on in source address, so calculate + // the frame header size. + // + HeaderSize = (Temp[14] & 0x1f) + 14; + + } + + // + // Save the received header size. + // + Adapter->SizeOfReceivedHeader = HeaderSize; + + // + // Record the fact that we had a good receive. + // + Adapter->GoodReceives++; + + // + // Make sure the adapter and the system are in synch. + // + NdisFlushBuffer(CurrentEntry->FlushBuffer, FALSE); + + // + // Get the frame size of this buffer. + // + FrameSize = BYTE_SWAP(CurrentEntry->Hardware.FrameSize); + + // + // Indicate the frame size to the debugger + // + EXTRA_LOUD_DEBUG(DbgPrint("TOK162!Frame size is %u\n", + FrameSize);) + + // + // If the frame that we have been passed has an invalid length + // (less than the reported header size) then we need to check + // if the frame size is larger than the default address length. + // + if (FrameSize >= HeaderSize) { + + // + // We have a 'normal' packet. Indicate this to the debugger + // and log it. + EXTRA_LOUD_DEBUG(DbgPrint("TOK162!Doing receive indicate\n");) + IF_LOG('q'); + + // + // Do the indication to the filter. + // + NdisMTrIndicateReceive( + Adapter->MiniportAdapterHandle, + (NDIS_HANDLE)( + ((PUCHAR)(CurrentEntry->ReceiveBuffer))+HeaderSize), + CurrentEntry->ReceiveBuffer, + (UINT)HeaderSize, + ((PUCHAR)CurrentEntry->ReceiveBuffer) + HeaderSize, + FrameSize - HeaderSize, + FrameSize - HeaderSize + ); + + } else { + + // + // If the frame size is greater than or equal to the length + // of an address (network address, 12 bytes) then we can + // indicate it as a runt packet to the filter. Otherwise, + // we ignore the received buffer. + // + if (FrameSize >= TOK162_LENGTH_OF_ADDRESS) { + + // + // Indicate this is a runt packet to the debugger + // + VERY_LOUD_DEBUG(DbgPrint( + "TOK162!Doing receive indicate for a runt\n");) + + // + // Indicate the packet to the filter. + // + NdisMTrIndicateReceive( + Adapter->MiniportAdapterHandle, + (NDIS_HANDLE)( + ((PUCHAR)(CurrentEntry->ReceiveBuffer)) + HeaderSize), + (PUCHAR)Temp, + (UINT)FrameSize, + NULL, + 0, + 0 + ); + + } + + } + + // + // Mark the receive list as processed and able to receive another + // buffer. + // + CurrentEntry->Hardware.CSTAT = RECEIVE_CSTAT_REQUEST_RESET; + + // + // Move to the next entry to see if there are more to process. + // + CurrentEntry = CurrentEntry->NextEntry; + + // + // Log the fact that we are telling the card to send us more receives. + // + IF_LOG('Q'); + + // + // Tell the card that we are ready to process more receives. + // + WRITE_ADAPTER_USHORT(Adapter, + PORT_OFFSET_COMMAND, + ENABLE_RECEIVE_VALID + ); + + } + +} + + +VOID +TOK162ProcessCommandInterrupts( + IN PTOK162_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + Process the Command Complete interrupts. + + NOTE: This routine assumes that it is being executed in a + single thread of execution. + +Arguments: + + Adapter - The adapter that was sent from. + +Return Value: + + None. + +--*/ + +{ + + // + // Pointer to command block being processed. + // + PTOK162_SUPER_COMMAND_BLOCK CurrentCommandBlock = Adapter->CommandOnCard; + + // + // Status variable + // + NDIS_STATUS Status; + + // + // NetCard Address Block + // + PTOK162_ADDRESSBLOCK Addresses; + // + // Ensure that the Command Block is on an even boundary. + // + ASSERT(!(NdisGetPhysicalAddressLow(CurrentCommandBlock->Self) & 1)); + + // + // Log the fact that we are processing a command interrupt. + // + IF_LOG('E'); + + // + // Process the command based on the command code. + // + switch(CurrentCommandBlock->Hardware.CommandCode) { + + case CMD_DMA_READ: + + // + // We are processing a read command. The read command is + // generated by a query request. + // + // Indicate we are processing a read command to the + // debugger. + // + VERY_LOUD_DEBUG(DbgPrint("TOK162!DPC for read adapter called\n");) + + // Get a pointer to the block of memory set aside for the + // read command. + // + Addresses = (PTOK162_ADDRESSBLOCK)Adapter->AdapterBuf; + + // + // Check the Oid to see if we are after the permanent card + // address or the current addresses. + // + if (Adapter->Oid == OID_802_5_PERMANENT_ADDRESS) { + // + // Update the permanent node address + // + NdisMoveMemory( + Adapter->NetworkAddress, + Addresses->NodeAddress, + 6 + ); + + } else { + + // + // Update the current network address + // + NdisMoveMemory( + (UNALIGNED PUCHAR)Adapter->CurrentAddress, + Addresses->NodeAddress, + 6); + } + + // + // Finish the query and relenquish the command block + // + TOK162FinishQueryInformation(Adapter); + TOK162RelinquishCommandBlock(Adapter, CurrentCommandBlock); + + break; + + case CMD_DMA_OPEN: + + // + // An open command is generated during a reset command. The + // initial open is called during adapter initialization and + // no DPC is generated. + // + // Indicate we are processing an open to the debugger. + // + VERY_LOUD_DEBUG(DbgPrint("TOK162!Processing the open command.\n");) + + // + // Relinquish the command block associcated with this open. + // + TOK162RelinquishCommandBlock(Adapter, CurrentCommandBlock); + + // + // Check to see if the open succeeded. + // + if ((Adapter->SsbStatus1 & OPEN_COMPLETION_MASK_RESULT) + != OPEN_RESULT_ADAPTER_OPEN) { + + // + // The open failed. Set the current ring state and set the + // return variable to NDIS_STATUS_FAILURE. + // + Adapter->CurrentRingState = NdisRingStateOpenFailure; + Adapter->OpenErrorCode = Adapter->SsbStatus1; + Status = NDIS_STATUS_FAILURE; + + // + // Display the error code on the debugger. + // + VERY_LOUD_DEBUG(DbgPrint( + "TOK162!Error on the open - %x\n",Adapter->SsbStatus1);) + + } else { + + // + // The open succeeded. Set the current ring state and set the + // return variable to NDIS_STATUS_SUCCESS. + // + Adapter->CurrentRingState = NdisRingStateOpened; + Adapter->OpenErrorCode = 0; + Status = NDIS_STATUS_SUCCESS; + + // + // Now send out the receive command. Display the fact that + // DoReceive is being called on the debugger. + // + VERY_LOUD_DEBUG(DbgPrint("Doing the receive\n");) + + // + // Check if the receive command succeeded. If not, set the + // return variable to NDIS_STATUS_FAILURE. It is currently + // set to NDIS_STATUS_SUCCESS, so no change is necessary + // if the receive command succeeds. + // + if (DoTheReceive(Adapter) == FALSE) { + + Status = NDIS_STATUS_FAILURE; + + } + + } + + // + // Indicate to the wrapper the result of the open/receive for + // the original reset request. + // + TOK162DoResetIndications(Adapter, Status); + break; + + case CMD_DMA_READ_ERRLOG: + + LOUD_DEBUG(DbgPrint("TOK162!DPC for read errorlog called\n");) + + // + // Record the values for the error counters + // + Adapter->ReceiveCongestionError += + Adapter->ErrorLog->ReceiveCongestionError; + + Adapter->LineError += Adapter->ErrorLog->LineError; + + Adapter->LostFrameError += Adapter->ErrorLog->LostFrameError; + + Adapter->BurstError += Adapter->ErrorLog->BurstError; + + Adapter->FrameCopiedError += Adapter->ErrorLog->FrameCopiedError; + + Adapter->TokenError += Adapter->ErrorLog->TokenError; + + Adapter->InternalError += Adapter->ErrorLog->InternalError; + + Adapter->ARIFCIError += Adapter->ErrorLog->ARIFCIError; + + Adapter->AbortDelimeter += Adapter->ErrorLog->AbortDelimeter; + + Adapter->DMABusError += Adapter->ErrorLog->DMABusError; + + // + // Indicate the values to the debugger + // + VERY_LOUD_DEBUG(DbgPrint("TOK162!CongestionErrors = %u\n", + Adapter->ErrorLog->ReceiveCongestionError);) + + VERY_LOUD_DEBUG(DbgPrint("TOK162!LineErrors = %u\n", + Adapter->ErrorLog->LineError);) + + VERY_LOUD_DEBUG(DbgPrint("TOK162!LostFrameErrors = %u\n", + Adapter->ErrorLog->LostFrameError);) + + VERY_LOUD_DEBUG(DbgPrint("TOK162!BurstErrors = %u\n", + Adapter->ErrorLog->BurstError);) + + VERY_LOUD_DEBUG(DbgPrint("TOK162!FrameCopiedErrors = %u\n", + Adapter->ErrorLog->FrameCopiedError);) + + VERY_LOUD_DEBUG(DbgPrint("TOK162!TokenErrors = %u\n", + Adapter->ErrorLog->TokenError);) + + VERY_LOUD_DEBUG(DbgPrint("TOK162!InternalErrors = %u\n", + Adapter->ErrorLog->InternalError);) + + VERY_LOUD_DEBUG(DbgPrint("TOK162!ARIFCIErrors = %u\n", + Adapter->ErrorLog->ARIFCIError);) + + VERY_LOUD_DEBUG(DbgPrint("TOK162!AbortDelimeters = %u\n", + Adapter->ErrorLog->AbortDelimeter);) + + VERY_LOUD_DEBUG(DbgPrint("TOK162!DMABusErrors = %u\n", + Adapter->ErrorLog->DMABusError);) + + // + // If a query for information generated this interrupt, finish + // the query. + // + if (Adapter->RequestInProgress) { + + TOK162FinishQueryInformation(Adapter); + + } + + // + // Relinquish the command block associated with this + // readadapterlog. + // + TOK162RelinquishCommandBlock(Adapter, CurrentCommandBlock); + + break; + + + default: + + // + // Did this command come from a set information request? + // + if (CurrentCommandBlock->Set) { + + // + // Relinquish the command block. + // + TOK162RelinquishCommandBlock(Adapter, CurrentCommandBlock); + + // + // Mark the current request state as complete. + // + Adapter->RequestInProgress = FALSE; + + // + // Inform the wrapper the request has been completed. + // + NdisMSetInformationComplete( + Adapter->MiniportAdapterHandle, + NDIS_STATUS_SUCCESS); + + // + // Not from a set. If this is the unique case of where a group + // address and a functional address had to be set to satisfy a + // packet filter change command (two commands for one), then we + // will only do an indication on the last one. The first one, + // however, still needs to have the command block associated + // with it relinquished. + // + } else if ((CurrentCommandBlock->Hardware.CommandCode == CMD_DMA_SET_GRP_ADDR) || + (CurrentCommandBlock->Hardware.CommandCode == CMD_DMA_SET_FUNC_ADDR)) { + + TOK162RelinquishCommandBlock(Adapter, CurrentCommandBlock); + + } + + break; + } + +} + + +VOID +TOK162ProcessTransmitInterrupts( + IN PTOK162_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + Process the Transmit Complete interrupts. + + NOTE: This routine assumes that it is being executed in a + single thread of execution. + +Arguments: + + Adapter - The adapter the transmit was sent from. + +Return Value: + + None. + +--*/ + +{ + // + // Pointer to command block being processed. + // + PTOK162_SUPER_COMMAND_BLOCK CurrentCommandBlock = Adapter->TransmitOnCard; + + // + // Pointer to the packet that started this transmission. + // + PNDIS_PACKET OwningPacket; + + // + // Points to the reserved part of the OwningPacket. + // + PTOK162_RESERVED Reserved; + + // + // Holds CSTAT variable for transmit + // + USHORT Cstat; + + // + // Status variable + // + NDIS_STATUS Status; + + // + // Ensure that the Command Block is on an even boundary. + // + ASSERT(!(NdisGetPhysicalAddressLow(CurrentCommandBlock->Self) & 1)); + + // + // Log the fact that we are processing a transmit interrupt + // + IF_LOG('D'); + + // + // Check if there is any reason to continue with the process. It is + // possible during a reset that not all of the transmits had completed. + // The reset path takes care of aborting all sends that didn't complete + // so we don't want to process anything during a reset. In the general + // case we don't want to process any transmit that doesn't have an + // associated command block. + // + if ((CurrentCommandBlock == NULL) || + (Adapter->ResetInProgress == TRUE)) { + + // + // Log the fact that we received a possibly bogus transmit interrupt. + // + IF_LOG('p'); + return; + + } + + // + // Get a pointer to the owning packet and the reserved part of + // the packet. + // + OwningPacket = CurrentCommandBlock->OwningPacket; + Reserved = PTOK162_RESERVED_FROM_PACKET(OwningPacket); + + // + // Check if this packet was constrained. + // + if (CurrentCommandBlock->UsedTOK162Buffer == FALSE) { + // + // Pointer to the current NDIS_BUFFER that we need to do the + // completemapregister on. + // + PNDIS_BUFFER CurrentBuffer; + + // + // Index to the map register being freed. + // + UINT CurMapRegister; + + // + // The transmit is finished, so we can release + // the physical mapping used for it. + // + NdisQueryPacket( + OwningPacket, + NULL, + NULL, + &CurrentBuffer, + NULL + ); + + // + // Compute the first map register used by this transmit. + // + CurMapRegister = CurrentCommandBlock->CommandBlockIndex * + Adapter->TransmitThreshold; + + // + // Loop through the NDIS_BUFFERs until there are no more. + // + while (CurrentBuffer != NULL) { + + // + // Free the current map register. + // + NdisMCompleteBufferPhysicalMapping( + Adapter->MiniportAdapterHandle, + CurrentBuffer, + CurMapRegister + ); + + // + // Move to the next map register. + // + ++CurMapRegister; + + // + // Get the next NDIS_BUFFER + // + NdisGetNextBuffer( + CurrentBuffer, + &CurrentBuffer + ); + + } + + } + + // + // If there was an error transmitting this + // packet, update our error counters. + // + Cstat = CurrentCommandBlock->Hardware.TransmitEntry.CSTAT; + + // + // Display the completion status for the transmit entry on the debugger. + // + VERY_LOUD_DEBUG(DbgPrint( + "TOK162!Csat for the command block is %x\n",Cstat);) + + // + // Check if there was an error on the transmit. Set Status and increment + // appropriate counter. + // + if ((Cstat & TRANSMIT_CSTAT_XMIT_ERROR) != 0) { + + Adapter->BadTransmits++; + Status = NDIS_STATUS_FAILURE; + + } else { + + Adapter->GoodTransmits++; + Status = NDIS_STATUS_SUCCESS; + + } + + // + // Release the command block. + // + TOK162RelinquishTransmitBlock(Adapter, CurrentCommandBlock); + + // + // Indicate to the filter than the send has been completed. + // + NdisMSendComplete( + Adapter->MiniportAdapterHandle, + OwningPacket, + Status + ); + +} + + + +BOOLEAN +TOK162ProcessRingInterrupts( + IN PTOK162_ADAPTER Adapter + ) +/*++ + +Routine Description: + + Process ring status interrupts. + +Arguments: + + Adapter - The adapter registering the ring interrupt + +Return Value: + + FALSE - Don't need to process receives as a result of the ring condition + TRUE - Need to process receives + +--*/ +{ + // + // Holds the return status value + // + ULONG RingStatus; + + // + // Command block variable used if we need to read the errorlog due to + // an overflow condition. + // + PTOK162_SUPER_COMMAND_BLOCK CommandBlock; + + // + // Return value for the function. Assume we don't need to process + // receives. + // + BOOLEAN SoftError = FALSE; + + // + // Log that we are processing a ring DPC. Display the ring interrupt + // information on the debugger. + // + IF_LOG('B'); + VERY_LOUD_DEBUG(DbgPrint( + "TOK162!Doing ring processing -%04x\n",Adapter->SsbStatus1);) + + // + // Initialize Ring Status to 0 + // + RingStatus = 0; + + // + // Determine the reason for the ring interrupt. + // + if (Adapter->SsbStatus1 & RING_STATUS_SIGNAL_LOSS) { + + RingStatus |= NDIS_RING_SIGNAL_LOSS; + + } else if (Adapter->SsbStatus1 & RING_STATUS_HARD_ERROR) { + + RingStatus |= NDIS_RING_HARD_ERROR; + + } else if (Adapter->SsbStatus1 & RING_STATUS_SOFT_ERROR) { + + // + // If we have a soft error, we should check the receives. + // + RingStatus |= NDIS_RING_SOFT_ERROR; + SoftError = TRUE; + + } else if (Adapter->SsbStatus1 & RING_STATUS_XMIT_BEACON) { + + RingStatus |= NDIS_RING_TRANSMIT_BEACON; + + } else if (Adapter->SsbStatus1 & RING_STATUS_LOBE_WIRE_FAULT) { + + RingStatus |= NDIS_RING_LOBE_WIRE_FAULT; + + } else if (Adapter->SsbStatus1 & RING_STATUS_AUTO_REMOVE_1) { + + RingStatus |= NDIS_RING_AUTO_REMOVAL_ERROR; + + } else if (Adapter->SsbStatus1 & RING_STATUS_REMOVE_RECEIVED) { + + RingStatus |= NDIS_RING_REMOVE_RECEIVED; + + } else if (Adapter->SsbStatus1 & RING_STATUS_OVERFLOW) { + + RingStatus |= NDIS_RING_COUNTER_OVERFLOW; + + } else if (Adapter->SsbStatus1 & RING_STATUS_SINGLESTATION) { + + RingStatus |= NDIS_RING_SINGLE_STATION; + + } else if (Adapter->SsbStatus1 & RING_STATUS_RINGRECOVERY) { + + RingStatus |= NDIS_RING_RING_RECOVERY; + + } + + // + // Display the ring status that we will be indicating to the filter on + // the debugger. + // + VERY_LOUD_DEBUG(DbgPrint( + "TOK162!Indicating ring status - %lx\n",RingStatus);) + + // + // Save the current status for query purposes. + // + Adapter->LastNotifyStatus = RingStatus; + + // + // Indicate to the filter the ring status. + // + NdisMIndicateStatus( + Adapter->MiniportAdapterHandle, + NDIS_STATUS_RING_STATUS, + &RingStatus, + sizeof(ULONG) + ); + + // + // Tell the filter that we have completed the ring status. + // + NdisMIndicateStatusComplete(Adapter->MiniportAdapterHandle); + + // + // If a counter has overflowed, we need to read the stats from + // the adapter to clear this condition. + // + if ((Adapter->SsbStatus1 & RING_STATUS_OVERFLOW) != 0) { + + + // + // Get a command block. + // + TOK162AcquireCommandBlock(Adapter, + &CommandBlock + ); + + + // + // Set up the command block for a read_error_log command. + // + CommandBlock->Set = FALSE; + CommandBlock->NextCommand = NULL; + CommandBlock->Hardware.Status = 0; + CommandBlock->Hardware.NextPending = TOK162_NULL; + CommandBlock->Hardware.CommandCode = CMD_DMA_READ_ERRLOG; + CommandBlock->Hardware.ParmPointer = + NdisGetPhysicalAddressLow(Adapter->ErrorLogPhysical); + + // + // Submit the command to the card. + // + TOK162SubmitCommandBlock(Adapter, + CommandBlock + ); + + } + + // + // Return whether processreceiveinterrupts needs to be called. + // + return(SoftError); + +} + |