Handling an Interrupt (NDIS 5.1)
Note NDIS 5. x has been deprecated and is superseded by NDIS 6. x. For new NDIS driver development, see Network Drivers Starting with Windows Vista. For information about porting NDIS 5. x drivers to NDIS 6. x, see Porting NDIS 5.x Drivers to NDIS 6.0.This section describes the handling of interrupts. For more information about registering interrupts, see Registering Handlers for Interrupt Support.
When a network interface card (NIC) generates an interrupt, NDIS fields it and calls the MiniportISRroutine of each miniport driver that registered the interrupt during initialization.
Determines and records the reason for the interrupt
Copies any volatile interrupt-specific information it needs to handle the interrupt into a permanent structure (usually somewhere in the MiniportAdapterContext passed to MiniportISR)
Clears the interrupt on the NIC
The definition of MiniportISRis:
VOID MiniportISR( OUT PBOOLEAN InterruptRecognized, OUT PBOOLEAN QueueMiniportHandleInterrupt, IN NDIS_HANDLE MiniportAdapterContext );
MiniportISRis passed two arguments, InterruptRecognizedand QueueMiniportHandleInterrupt, that must be set before returning. MiniportISRmust set InterruptRecognizedto TRUE if it recognizes the interrupt, or FALSE if it does not. If the interrupt is shared and if the miniport driver does not recognize the interrupt, it returns FALSE.
If MiniportISRrecognizes the interrupt and wants its MiniportHandleInterruptfunction queued, it must set QueueMiniportHandleInterruptto TRUE. NDIS does the actual queuing of the MiniportHandleInterruptfunction when MiniportISRreturns.
While an ISR is executing, all other interrupts on the processor at the same or lower IRQL are masked off. Therefore, it is important for a miniport driver to minimize the time spent in MiniportISR. Otherwise, the overall performance of the system, as well as I/O throughput for the miniport driver, degrades.
It is important for a miniport driver that manages a NIC that shares an interrupt with other devices on the same bus to quickly determine if the interrupt belongs to the miniport driver. If the interrupt does not belong to the miniport driver, the miniport driver should set InterruptRecognizedto FALSE and return immediately.
If the interrupt is shared and belongs to the miniport driver, or if the interrupt is not shared but is recognized by the miniport driver (the interrupt is not spurious), the miniport driver should disable interrupts on its NIC and then capture the interrupt-specific information it needs from the NIC registers. The miniport driver captures the interrupt-specific information immediately in MiniportISR, if absolutely necessary, or preferably, the miniport driver captures the interrupt-specific information in the MiniportHandleInterruptfunction, which runs at a lower IRQL.
MiniportISRmust disable interrupts to ensure that when MiniportHandleInterruptruns, no information in the NIC will be overwritten by a subsequent interrupt. MiniportISRshould read and save only the information that cannot be accessed after it returns. MiniportISRshould then return.
If the miniport driver does not want its MiniportHandleInterruptfunction to be queued and if it previously disabled interrupts in MiniportISR, it must reenable the interrupt on the NIC before returning from MiniportISR.
A miniport driver that controls a NIC that supports power management must always keep track of the NIC's power state. If MiniportISRis called when the NIC is in a low-power state, MiniportISRmust not access the NIC, claim the interrupt by setting InterruptRecognizedto TRUE, or set QueueMiniportHandleInterruptto TRUE.
A miniport driver's MiniportISRfunction and its MiniportDisableInterruptfunction run at DIRQL. Other miniport driver code runs at IRQL <= DISPATCH_LEVEL. To prevent race conditions, any miniport driver function that shares resources with MiniportISRor MiniportDisableInterruptmust synchronize access to the shared resources. A function synchronizes with MiniportISRand MiniportDisableInterruptby calling NdisMSynchronizeWithInterrupt, supplying a MiniportSynchronizeISRfunction. MiniportSynchronizeISRruns at DIRQL and can safely access the shared resource.
For example, MiniportHandleInterruptcalls NdisMSynchronizeWithInterruptbefore clearing an interrupt status register. This NDIS call takes a SynchronizeFunctionargument. Within NdisMSynchronizeWithInterrupt, NDIS calls the miniport driver's SynchronizeFunctionat DIRQL, so that this function can safely clear the interrupt status register and be sure that MiniportISRor MiniportDisableInterruptare not modifying the same register at the same time. SynchronizeFunctionshould execute as quickly as possible, like the MiniportISRand MiniportDisableInterruptfunctions.
The execution of MiniportISRand MiniportDisableInterrupt, both of which run at DIRQL, is synchronized with a spin lock associated with the interrupt object.