3.1.3.1 Providing Interrupt Support
A miniport can, but is not always required to, provide an interrupt handler. For instance, a miniport that manages a non-interrupting device and polls its device with a MiniportTimer function cannot depend on interrupts and thus does not have an interrupt handler. A miniport for a NIC with a shared interrupt must always provide an interrupt handler. The definition of the interrupt function follows.
VOID
MiniportISR(
OUT PBOOLEAN InterruptRecognized,
OUT PBOOLEAN QueueMiniportHandleInterrupt,
IN NDIS_HANDLE MiniportAdapterContext
);
When any network device interrupts, NDIS fields the interrupt; that is, NDIS is always called first when a NIC interrupts. NDIS determines which miniport the interrupt belongs to. Then NDIS either calls the appropriate miniport’s MiniportISR function, or handles the interrupt for the miniport if the miniport has specified in its call to NdisMRegisterInterrupt that it does not want to have its ISR called. If NDIS does not call a miniport’s ISR function, NDIS disables further interrupts by calling the miniport’s MiniportDisableInterrupt function and then queues the miniport’s MiniportHandleInterrupt DPC function.
If a miniport must or chooses to handle its device interrupts, it registers its ISR handler in NDIS_MINIPORT_CHARACTERISTICS and indicates that it wants its ISR handler called by setting the RequestIsr argument of NdisMRegisterInterrupt to TRUE.
A miniport for a NIC that interrupts must provide an ISR handler if any of the following is true.
·If the interrupt is shared, a miniport must have an ISR and must set RequestIsr to TRUE when it calls NdisMRegisterInterrupt. In this case, when the device interrupts, the ISR of the driver for each device on the bus is called. Each ISR must determine if the interrupt was generated by its device. A miniport’s ISR returns TRUE in the InterruptRecognized argument to MiniportISR if its NIC generated the interrupt and, in addition, if the miniport wants its DPC queued, it returns TRUE in the QueueMiniportHandleInterrupt argument. If the miniport does not recognize the interrupt, its ISR returns FALSE as soon as possible in the InterruptRecognized argument, and FALSE in QueueMiniportHandleInterrupt. For some types of interrupts, a miniport can return InterruptRecognized equal to TRUE and QueueMiniportHandleInterrupt equal to FALSE, for instance if it can quickly and completely process the interrupt in the ISR.
·If there is state in the device registers that must be captured at DIRQL, a miniport must have an ISR. When NDIS handles an interrupt, it does not save any NIC state on behalf of the miniport. Therefore, state that disappears when the ISR returns control can be captured only if the miniport registers and uses an ISRHandler.
If a device interrupts but the interrupt is not shared, the miniport can request that NDIS completely process the interrupt by specifying RequestIsr to FALSE in the miniport’s NdisMRegisterInterrupt call. When NDIS gets the interrupt, NDIS calls the miniport’s MiniportDisableInterrupt function, to disable further interrupts, queues the miniport’s MiniportHandleInterrupt function and returns TRUE to notify the I/O system that it recognizes the interrupt. MiniportHandleInterrupt must re-enable interrupts as soon as practical, otherwise, NDIS reenables interrupts by calling the miniport’s MiniportEnableInterrupt function if one exists.
Even if a miniport of a device that interrupts sets RequestIsr to FALSE, the miniport sometimes must provide an ISRHandler. If a NIC can generate an interrupt during the miniport’s initialization or when it is halting, such an interrupt will not be handled by NDIS but will be passed to the miniport. Therefore such a miniport must provide a MiniportISR function.
In summary, a miniport must provide an ISR handler if it manages a device that can interrupt during initialization or during a halt operation, if its NIC shares an IRQ, or if, when its device interrupts, it must capture interrupt-specific data at DIRQL. A miniport can specify that NDIS handle its interrupts if interrupts are not shared, if there is no device state that must be captured in the ISR at DIRQL, and if it can guarantee its NIC will not interrupt during initialization or halting. The miniport requests that NDIS handle interrupts by calling NdisMRegisterInterrupt with RequestIsr set to FALSE and SharedInterrupt set to FALSE.
If a driver manages a device that does not interrupt, it typically polls its device using a timer. This type of driver must initialize any timers it requires for its operation in MiniportInitialize. See Section 3.2.5 for more information.
Enabling and Disabling Interrupts
If the NIC does not generate an interrupt, the miniport does not need to provide a MiniportEnableInterrupt or MiniportDisableInterrupt function. If a miniport always handles its interrupts in a MiniportISR function, and schedules a MiniportHandleInterrupt function, it might not provide specific MiniportEnableInterrupt or MiniportDisableInterrupt functions. Instead, such a miniport can choose to disable interrupts within its ISR and enable them within its DPC, without providing specific functions for this purpose. If a miniport specifies that NDIS handle its interrupts, it must supply a MiniportDisableInterrupt function and if it does not reenable interrupts in its MiniportHandleInterrupt function, it must have a MiniportEnableInterrupt function.
Combining Interrupts and Polling
Sometimes a driver developer can improve the performance of a driver by combining polling a NIC with the use of interrupts. For instance, a driver can be designed to enable interrupts for receive indications but disable them for send-complete indications. A miniport might set a timer and, at timer expiration, check for send completions. In addition, when an interrupt on a receive occurs, the miniport also checks for send-completes. This is a reasonable strategy when network traffic is high: the number of interrupts handled is minimized, and no packets are missed.
A driver that implements this strategy can also sample the traffic on the network and, if traffic is high, it uses the strategy just described. If traffic on the network is low, the driver should enable both send-complete and receive interrupts because the number of interrupts is expected to be lower than in a high traffic environment and the possibility of adversely affecting the driver’s send performance exists.
A driver that uses both polling and interrupts disables interrupts when it is using polling to manage its device and enables interrupts when using interrupts to manage its device. The driver also can have NDIS process its device’s interrupts when they are enabled, subject to the same restrictions as already described. That is, that the interrupt is not shared, that any information needed by the miniport can be captured in its MiniportHandleInterrupt function, and that its NIC will never interrupt during initialization or halting.