Share via


Shared IST for NDIS (Windows Embedded CE 6.0)

1/6/2010

Typically, the Windows Embedded CE Network Driver Interface Specification (NDIS) implementation creates one interrupt service thread (IST) for each adapter instance interrupt request (IRQ). In routing scenarios, you can often improve throughput by combining interrupt handling into one IST that services all IRQs. This reduces the number of thread switches during the routing processing. However, because performance can be specific to network configuration, OS, and hardware, you should profile your system performance with and without the shared IST to confirm that it improves performance.

To achieve a performance improvement, the miniport driver must indicate multiple packets, for example, using NdisMIndicateReceivePacket. The miniport driver must also receive NDIS_STATUS_SUCCESS, allowing it to keep the packets for processing.

To enable the shared IST behavior, you must also implement changes in the OEM abstraction layer (OAL) code. The following list shows the global variables that you must add between NDIS and the interrupt service routine (ISR):

  • OEMIntrMask stores the bitmask value of the 1 << IRQ.
  • OEMIntrEnable stores the IRQ number.

If the query for IOCTL_HAL_SYSINTR_NETWORK_SHARED returns FALSE, the shared IST functionality is not enabled, and the system behaves as before.

The following code example shows how NDIS uses the IOCTL_HAL_SYSINTR_NETWORK_SHARED to query the address of the OEMIntrMask and OEMIntrEnable variables:

ULONG OEMIntrEnable = 0;
ULONG OEMIntrMask = 0;
  
BOOL OEMIoControl(
   DWORD code, PVOID pInpBuffer, DWORD inpSize, PVOID pOutBuffer, DWORD outSize,
   DWORD *pOutSize
) {      
   BOOL ok = TRUE;
 
....
   case IOCTL_HAL_SYSINTR_NETWORK_SHARED:
      if (outSize < 2*sizeof(ULONG) || pOutBuffer == NULL) {
         ok = FALSE;
         SetLastError(ERROR_INVALID_PARAMETER);
         break;
      }
      ((ULONG*)pOutBuffer)[0] = (ULONG)&OEMIntrMask;
      ((ULONG*)pOutBuffer)[1] = (ULONG)&OEMIntrEnable;
      if (pOutSize != NULL) *pOutSize = 2*sizeof(ULONG);
      break;
...
return ok;
}

The following MIPS code example shows how the OEMIntrMask variable is updated by the ISR code as SYSINTR_NETWORK_SHARED is returned:

    la   a0, OEMIntrMask
    lw   a1, 0(a0)
    or   a1, (1 << IRQ_MAC1)
    sw   a1, 0(a0)
    j    ra
    li   v0, SYSINTR_NETWORK_SHARED

The OEMIntrEnable variable is updated by NDIS before it calls InterruptDone and InterurptDisable, which map to OEMInterruptEnable and OEMInterruptDisable respectively.

The following code example shows how the HAL code must then consider OEMIntrEnable to determine the interrupt to enable or disable:

   BOOL OEMInterruptEnable(DWORD sysIntr, LPVOID pvData, DWORD cbData)
   {
      DEBUGMSG(FALSE, (L"+OEMInterruptEnable %d\n", sysIntr));
      switch (sysIntr) {
         case SYSINTR_NETWORK_SHARED:
            if (OEMIntrEnable == IRQ_PCI) {
               OUT32(PCI_BASE + PCI_INTMASK, PCI_INT_PA);
               OEMIntrEnable = 0x00;
          }
          break;

See Also

Concepts

Improving Performance of an NDIS Miniport Driver