Hi all,
E100BEX is a miniport driver given as a sample with PB 5.0. It handles
Intel's 825xx Ethernet PCI chips and illustrates a few useful techniques for
writing NDIS 5.1 miniport drivers. Unfortunately, there is a problem in the
way E100BEX handles the interrupts.
This can be seen when E100BEX is used with GIISR.DLL on a shared interrupt
level.
For instance, a typical Registry entry for this driver is:
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\PCI\Template\E100BEX]
;PCI Bus Enumeration Information
"Class"=dword:02
"SubClass"=dword:00
"ProgIF"=dword:0
"VendorID"=multi_sz:"8086","8086","8086"
"DeviceID"=multi_sz:"1209","1229","2449"
"Dll"="NDIS.dll"
"Entry"="NdisPCIBusDeviceInit"
"Transceiver"=dword:3
;Installable ISR Handler Information
"IsrDll"="giisr.dll"
"IsrHandler"="ISRHandler"
"PortIsIO"=dword:0
"PortOffset"=dword:0
"PortSize"=dword:4
"PortMask"=dword:F000
When the 825xx interrupt fires, it is handled by PeRPISR that calls
NKCallIntChain for the active level.
NKCallIntChain then calls GIISR's ISRHandle, that tests active bits of the
ScbStatus register of the controller against PortMask.
As the result of the test is positive, ISRHandle returns a valid SysIntr for
the interrupt and the matching IST in NDIS is eventually called.
The IST in NDIS calls MPIsr in E100BEX, that read 2 controller registers:
ScbCommandHigh to check that the interrupt is not masked at the controller
level and ScbStatus, indicating what interrupt sources (Rx, Tx, etc.) are
currently active. When both the interrupts are unmasked and active sources
can be seen, MPIsr writes ScbCommandHigh to mask the controller interrupts
and return TRUE to NDIS.
NDIS then calls InterruptDone: new interrupts can occur on the same level.
When E100BEX is the only possible interrupt source on this level, after
having called InterruptDone, NDIS posts a DPC that ends in E100BEX
MPHandleInterrupt routine.
MPHandleInterrupt reads ScbStatus again and writes it back to clear the bits
of the active sources. Then it processes the controller interrupts and
finally writes to ScbCommandHigh to enable the controller interrupts again.
When another device shares the same interrupt level and is located in the
interrupt chain *after* the ISRHandler instance of E100BEX, things usually
go bad. As an illustration, imagine this scenario:
1) A 825xx interrupt is processed up to the point where NDIS calls
InterruptDone, after MPIsr. The controller interrupt is disabled in
ScbCommandHigh but the active interrupt sources are still set in ScbStatus.
2) Right after InterruptDone, an interrupt pending on the other device
is processed. NKCallIntChain is called starting with GIISR's ISRHandle for
E100BEX. Unfortunately, the ScbStatus bits are still set and the SysIntr for
NDIS/E100BEX is improperly returned.
3) MPIsr is called but as the controller interrupt is masked, it returns
FALSE.
4) InterruptDone is called and as the interrupt of the other device is
still active, we restart to 2): the system is hanged.
The problem can easily be fixed by resetting ScbStatus bits in MPIsr instead
of MPHandleInterrupt.
Remi