none
How to pass data from ISR to DPC RRS feed

  • Question

  • This article:

    https://msdn.microsoft.com/en-us/windows/hardware/drivers/wdf/servicing-an-interrupt

    instructs me to "quickly save interrupt information" and that one "schedules a deferred procedure call (DPC) to process the saved information later".

    However, it fails to explain how to do this. How does one pass information from ISR to DPC?

    I get an interrupt from the PCIe card, and I can read a register to tell which of the rougly 30 "things" (DMA streams, PIO transfers, events, etc.) on the card needs attention. The hardware has race-free ways of acknowledging and re-arming this. So after the ISR I have a few "mask" sets of work that needs to be done. The registers containing that information have been cleared, so the hardware will trigger a new interrupt if there's more work to be done after that.

    If I just store the mask into the device context, this will cause race conditions when the interrupt fires before the DPC finishes its tasks, and I'll have no place to store the "new" mask set until the DPC has finished processing it.

    There appears to be no way to pass even a simple integer to the DPC.

    Wednesday, April 20, 2016 7:24 AM

Answers

  • You typically do this, by creating a context for the Interrupt (or by using the Device Interrupt) that holds the mask sets.  If you need more than just the mask, or if the mask needs some unique supporting data, you can create a queue head in the context, and have a pre-allocated set of queue elements you fill in indicating the work.  Typically for this you would use either the Interrupt lock in the DPC, or use ExInterlockedInsertTailList/ExInterlockedRemoveHeadList to manage the list.

    No there is no explicit parameter for the ISR when calling the DPC, but you need to remember that if the DPC is queued when you call it to be queued a second time, only one DPC call will occur.


    Don Burn Windows Driver Consulting Website: http://www.windrvr.com

    Wednesday, April 20, 2016 11:07 AM

All replies

  • You typically do this, by creating a context for the Interrupt (or by using the Device Interrupt) that holds the mask sets.  If you need more than just the mask, or if the mask needs some unique supporting data, you can create a queue head in the context, and have a pre-allocated set of queue elements you fill in indicating the work.  Typically for this you would use either the Interrupt lock in the DPC, or use ExInterlockedInsertTailList/ExInterlockedRemoveHeadList to manage the list.

    No there is no explicit parameter for the ISR when calling the DPC, but you need to remember that if the DPC is queued when you call it to be queued a second time, only one DPC call will occur.


    Don Burn Windows Driver Consulting Website: http://www.windrvr.com

    Wednesday, April 20, 2016 11:07 AM
  • Just to be sure: If the DPC is already running, the ISR will still enqueue a new one, right?

    It's okay to only queue one DPC, but once that DPC starts, there'll be a race condition with the IRQ routine unless the IRQ routine can trigger another start of the DPC reliably.

    Wednesday, April 20, 2016 1:14 PM
  • Guess in my case I can just "OR" a status mask context variable with the IRQ registers, inside a spinlock. And in the DPC, fetch the mask from the context and reset it to zero inside that spinlock, and then start processing the queues corresponding to the bits in that mask.

    (The hardware was actually designed to avoid such spinlocks. Pity that there seems to be no way to implement it without spinlocks on Windows)

    Wednesday, April 20, 2016 1:21 PM
  • A way without spinlocks would be to create a DPC for each queue. That would potentially result in a few dozen DPC objects for the driver. I wonder which is worse? What's the "cost" of a DPC object?

    Wednesday, April 20, 2016 1:25 PM
  • Yes once the DPC routine starts running the system can queue the DPC object again. 

    Don Burn Windows Driver Consulting Website: http://www.windrvr.com

    Wednesday, April 20, 2016 1:27 PM
  • A DPC object is pretty lightweight, so having a bunch is not a problem.  Of course if you are just or'ing the bits use InterlockeOr and InterlockedAnd to do this without spinlocks.


    Don Burn Windows Driver Consulting Website: http://www.windrvr.com

    Wednesday, April 20, 2016 1:29 PM
  • Mike: does your PCIe device have a legacy (a.k.a. line-type) interrupt or MSI?

    1. If the interrupt type is  MSI, it is not shared with any other device, so you do not need to read anything in your ISR. You know that this is interrupt from your device.  So you just queue a DPC and do all the work in the DPC. As soon as you read the interrupt status, this acknowledges the set bits (as you wrote) - so a new interrupt can fire, and another DPC may run in parallel. You'll need to stop these subsequent DPCs from interfering. But, what is important -  the ISR does not need to pass any data to the DPC.

    2. If the interrupt is level/line-type, the ISR also does not need to pass anything to the DPC, but it must know whether the interrupt is yours.

    All PCIe devices must have a standard bit in the config space that indicates active interrupt request. You can read this bit in the ISR at DIRQL using this. If it is set, you queue the DPC, then it goes like in previous case.

    Again, the ISR does not need to pass anything to the DPC. Bingo.

    -- pa

    P.S. Since there is a time limit for a single DPC, if it takes too long to handle all the work, you may need to delay some work and re-schedule another DPC or even a passive-level work item. This needs saving some context data aside, but again, the ISR is not involved at all.

     
    • Edited by Pavel A Wednesday, April 20, 2016 4:06 PM
    Wednesday, April 20, 2016 3:58 PM
  • I avoid accessing the config space in an ISR, because at least in older versions of Windows the performance of the GetBusData call was terrible.  The OP has already indicated that performance is a key design element here.


    Don Burn Windows Driver Consulting Website: http://www.windrvr.com

    Wednesday, April 20, 2016 4:13 PM
  • Well, everything has its cost. If the device was designed without supporting Windows in mind (provide a non-destructive interrupt request indication in a BAR) - this has a cost. I hope this device uses a MSI or even several messages to help balancing the work.

    Regards,

     --pa

    Wednesday, April 20, 2016 4:42 PM