Deadlock on InterruptDisable()

My hardware is a PCIExpress card.
I have an Interrupt Spin Lock in use (WdfInterruptAcquireLock()), to sync fifo operations against the ISR.

Now on DeviceManager “Deactivate” the customer gets (sometimes) a Dead Lock, see below.

I assume that the Interrupt Spin Lock is acquired by an asynchronical DPC or WorkerItem, while KMDF/PnP disables the corresponding Interrupt.

Unfortunately I can only debug by kernel dump produced on a remote customer machine.

I’m out of ideas, so some questions:
How to sync WdfInterruptDisable with use of an interruptLevelLock … is it automatically?
What todo in
EvtDeviceD0Exit
EvtDeviceD0ExitPreInterruptsDisabled
EvtInterruptDisable
?

thanks for caring,
Joerg Hoppe

3: kd> kp

Child-SP RetAddr Call Site

00 ffffab00fd312e18 fffff80009c30f64 nt!KeBugCheckEx
01 ffffab00fd312e20 fffff80009a43343 nt!KeAccumulateTicks+0x1eb3c4
02 ffffab00fd312e80 fffff80009a42e2a nt!KeClockInterruptNotify+0x453
03 ffffab00fd312f30 fffff80009aa7765 nt!HalpTimerClockIpiRoutine+0x1a
04 ffffab00fd312f60 fffff80009bfedca nt!KiCallInterruptServiceRoutine+0xa5
05 ffffab00fd312fb0 fffff80009bff597 nt!KiInterruptSubDispatchNoLockNoEtw+0xfa
06 ffff928e0e8f1aa0 fffff80009b1577c nt!KiInterruptDispatchNoLockNoEtw+0x37
07 ffff928e0e8f1c30 fffff80009a1d9bc nt!KxWaitForSpinLockAndAcquire+0x2c
08 ffff928e0e8f1c60 fffff80009bfe446 nt!KeAcquireSpinLockAtDpcLevel+0x5c
09 ffff928e0e8f1c90 fffff8000bfd4a50 nt!KeSynchronizeExecution+0x36
0a (Inline Function) ---------------- Wdf01000!_SynchronizeExecution(void)+0x1f [minkernel\wdf\framework\shared\inc\private\km\FxInterruptKm.hpp @ 111] 0b ffff928e0e8f1cd0 fffff8000bfd4932 Wdf01000!FxInterrupt::InterruptDisable(void)+0x38 [minkernel\wdf\framework\shared\irphandlers\pnp\interruptobject.cpp @ 1708] 0c ffff928e0e8f1d10 fffff8000bfd48a8 Wdf01000!FxInterrupt::Disconnect(unsigned long NotifyFlags = 4)+0x72 [minkernel\wdf\framework\shared\irphandlers\pnp\interruptobject.cpp @ 1358] 0d ffff928e0e8f1d80 fffff8000c04dd43 Wdf01000!FxPkgPnp::NotifyResourceObjectsDx(unsigned long NotifyFlags = 4)+0x6c [minkernel\wdf\framework\shared\irphandlers\pnp\fxpkgpnp.cpp @ 6489] 0e ffff928e0e8f1de0 fffff8000bfe2556 Wdf01000!FxPkgPnp::PowerGotoD3Stopped(class FxPkgPnp * This = 0xffff800cef8858b0)+0x163 [minkernel\wdf\framework\shared\irphandlers\pnp\powerstatemachine.cpp @ 2631]
0f ffff928e0e8f1e40 fffff8000bfe230a Wdf01000!FxPkgPnp::PowerEnterNewState(_WDF_DEVICE_POWER_STATE State = )+0x156 [minkernel\wdf\framework\shared\irphandlers\pnp\powerstatemachine.cpp @ 1699]
10 ffff928e0e8f1fa0 fffff8000bfe1701 Wdf01000!FxPkgPnp::PowerProcessEventInner(struct FxPostProcessInfo * Info = 0xffff928e0e8f2070)+0xea [minkernel\wdf\framework\shared\irphandlers\pnp\powerstatemachine.cpp @ 1615] 11 ffff928e0e8f2020 fffff8000c0575be Wdf01000!FxPkgPnp::PowerProcessEvent(FxPowerEvent Event = PowerImplicitD3 (0n128), unsigned char ProcessOnDifferentThread = <Value unavailable error>)+0x1d1 [minkernel\wdf\framework\shared\irphandlers\pnp\powerstatemachine.cpp @ 1394] 12 ffff928e0e8f20b0 fffff8000bfe2185 Wdf01000!FxPkgPnp::PowerPolStopping(class FxPkgPnp * This = 0xffff800cef8858b0)+0x1e [minkernel\wdf\framework\shared\irphandlers\pnp\powerpolicystatemachine.cpp @ 7880]
13 ffff928e0e8f20e0 fffff8000bfe1dd8 Wdf01000!FxPkgPnp::PowerPolicyEnterNewState(_WDF_DEVICE_POWER_POLICY_STATE NewState = )+0x155 [minkernel\wdf\framework\shared\irphandlers\pnp\powerpolicystatemachine.cpp @ 4015]
14 ffff928e0e8f2240 fffff8000bfe1a65 Wdf01000!FxPkgPnp::PowerPolicyProcessEventInner(struct FxPostProcessInfo * Info = 0xffff928e0e8f2310)+0x298 [minkernel\wdf\framework\shared\irphandlers\pnp\powerpolicystatemachine.cpp @ 3853] 15 ffff928e0e8f22c0 fffff8000c04aa43 Wdf01000!FxPkgPnp::PowerPolicyProcessEvent(FxPowerPolicyEvent Event = PwrPolStop (0n2))+0x155 [minkernel\wdf\framework\shared\irphandlers\pnp\powerpolicystatemachine.cpp @ 3502] 16 (Inline Function) ---------------- Wdf01000!FxPkgPnp::PnpPowerPolicyStop(void)+0xd [minkernel\wdf\framework\shared\irphandlers\pnp\pnpstatemachine.cpp @ 3762]
17 ffff928e0e8f2360 fffff8000c04a33b Wdf01000!FxPkgPnp::PnpEventStartedStopping(class FxPkgPnp * This = 0xffff800cef8858b0)+0x13 [minkernel\wdf\framework\shared\irphandlers\pnp\pnpstatemachine.cpp @ 1773] 18 ffff928e0e8f2390 fffff8000c04c011 Wdf01000!FxPkgPnp::PnpEnterNewState(_WDF_DEVICE_PNP_STATE State = <Value unavailable error>)+0x15f [minkernel\wdf\framework\shared\irphandlers\pnp\pnpstatemachine.cpp @ 1234] 19 ffff928e0e8f2420 fffff8000c04bdda Wdf01000!FxPkgPnp::PnpProcessEventInner(struct FxPostProcessInfo * Info = 0xffff928e0e8f24e0)+0x1d1 [minkernel\wdf\framework\shared\irphandlers\pnp\pnpstatemachine.cpp @ 1152]
1a ffff928e0e8f2490 fffff8000c053222 Wdf01000!FxPkgPnp::PnpProcessEvent(FxPnpEvent Event = )+0x182 [minkernel\wdf\framework\shared\irphandlers\pnp\pnpstatemachine.cpp @ 933]
1b ffff928e0e8f2520 fffff8000bfdcc60 Wdf01000!FxPkgPnp::_PnpRemoveDevice(class FxPkgPnp * This = 0xffff800cef8858b0, class FxIrp * Irp = 0xffff928e0e8f2600)+0xa2 [minkernel\wdf\framework\shared\irphandlers\pnp\fxpkgpnp.cpp @ 2519]
1c ffff928e0e8f2590 fffff8000bfda867 Wdf01000!FxPkgPnp::Dispatch(struct _IRP * Irp = )+0xb0 [minkernel\wdf\framework\shared\irphandlers\pnp\fxpkgpnp.cpp @ 765]
1d (Inline Function) ---------------- Wdf01000!DispatchWorker(void)+0x6b [minkernel\wdf\framework\shared\core\fxdevice.cpp @ 1589] 1e (Inline Function) ---------------- Wdf01000!FxDevice::Dispatch(void)+0x89 [minkernel\wdf\framework\shared\core\fxdevice.cpp @ 1603]
1f ffff928e0e8f2600 fffff80009a10665 Wdf01000!FxDevice::DispatchWithLock(struct _DEVICE_OBJECT * DeviceObject = 0xffff800ce6f0bde0 Device for "\Driver\PCAN_PCI", struct _IRP * Irp = 0xffff800ceecf4de0)+0x157 [minkernel\wdf\framework\shared\core\fxdevice.cpp @ 1447]
20 ffff928e0e8f2660 fffff80009e8e6d4 nt!IofCallDriver+0x55
21 ffff928e0e8f26a0 fffff80009f420f4 nt!IopSynchronousCall+0xf8
22 ffff928e0e8f2710 fffff80009b71a74 nt!IopRemoveDevice+0x108
23 ffff928e0e8f27c0 fffff80009f41bf6 nt!PnpRemoveLockedDeviceNode+0x1ac

It is quite possible to implement FIFO operations so that no spinlock is required. As long as one side only updates the IN pointer and the other side only updates the OUT pointer, there is no opportunity for a collision. You might be working with slightly out of date information, but that’s OK. You’ll catch up later.

What you need to find out is who is holding the spinlock and not releasing it. No one should be grabbing the spinlock and then waiting.