Not getting all interrupts in KMDF driver

Hello,

I’m trying to port an existing linux device driver to windows. It’s mostly working, but there’s a weird issue - sometimes device won’t interrupt or the interrupt is lost.
Interrupts are only lost when I’m not actively debugging.

My ISR and dpc look like this:

 //isr
  pDE  = xGetDeviceContext(WdfInterruptGetDevice(Interrupt));
  intrv = READ_REG_32(pDE, OFFSET_INTERRUPT_REG);
  pDE->interruptMask = READ_REG_32(pDE, OFFSET_INTERRUPT_MASK_REG);
  
  intrv &= pDE->interruptMask;
  if(intrv == 0){
	  return FALSE;
  }
  pDE->interruptStatus |= intrv; //trying to save values in case different interrupts come too fast for dpc
  WdfInterruptQueueDpcForIsr( pDE->m_Interrupt);
//DPC
 pDE  = xGetDeviceContext(WdfInterruptGetDevice(Interrupt));
 WdfInterruptAcquireLock(Interrupt);
 nMainIntStatus = pDE->interruptStatus;
 pDE->interruptStatus = 0;
 WdfInterruptReleaseLock(Interrupt);
 
 if(nManIntStatus & interrupt_mask_event_1){
   KeSetEvent(&pDE->interrupt_event_1, IO_SOUND_INCREMENT, FALSE);
 }
 //and so on...
//in my code I'm waiting on pDE->interrupt_event_1:
 status = KeWaitForSingleObject(&pDE->interrupt_event_1, Executive, KernelMode, TRUE, &timeout);

I tried enabling automatic serialization in interrupt config, but this did not resolve my issue.

I’m currently out of options, I suspect either improper synchronization or that I should be using a different wait method.
Please give me any advice you could think of.

Hmmmmm… did you set a breakpoint or do a DbgPrint in your ISR?

How do you know your ISR is not firing?

If you mean you’re not getting one DPC callback for each ISR invocation… then, that’s the way Windows works. If you follow up by saying that’s what you mean, I’ll explain further.

Peter

On, and by the way… you can not call KeSetEvent from your ISR. The IRQL is too high.

Your design appears to have some challenges…

Peter

You can replace these four lines:

WdfInterruptAcquireLock(Interrupt);
nMainIntStatus = pDE->interruptStatus;
pDE->interruptStatus = 0;
WdfInterruptReleaseLock(Interrupt);
with
nMainIntStatus = InterlockedExchange( &pDE->InterruptStatus, 0 );

Does reading the interrupt register clear the interrupts?

On, and by the way… you can not call KeSetEvent from your ISR. The IRQL is too high.

Actually, the OP does not do it - the only thing that the OP does in ISR is queuing a DPC, and KeSetEvent() is already invoked by DPC routine at the time when interrupt spinlock is not held. Therefore, the OP’s code seems to be correct in this respect.

Concerning his actual question, I think it may well be just a misinterpretation of the situation. Judging from the code his has shown us in so far, he expects one-to-one correspondence between the number of interrupts and the number of times his waiting thread gets released
(let’s assume he uses two separate counters that he expects to match one another - otherwise, as you have already pointed out, he simply has no way of evaluating the situation).

Let’s assume he increments the thread counter immediately after KeWaitxxx() returns control. Now consider what happens if his interrupt fires while the target thread is on the runqueue, i.e. it had been already released but did not yet get a chance to actually get to the CPU. In this case his ISR counter (which indicates the number of times his DPC gets queued and,hence, KeSetEvent() gets invoked) is going to exceed the thread one. The OP seems to be (mis) taking this mismatch for a lost interrupt. Therefore, it seems to be just the question of the wrong interpretation…

Anton Bassov