Invalid Interrupt Vector?

Hmmm… there’s a lot that’s really confusing in your code. At least to me.

First of all, we’re talking MSI here… NOT MSI-X, right? Please confirm. Cuz they’re handled differently.

Assuming you actually DO mean MSI and not MSI-X, then the code you’ve got here isn’t correct. Well, actually, the code you’ve got here isn’t correct for MSI or MSI-X… but, whatever.

You can’t just ASSUME you’re going to be granted the number of interrupts you’ve requested. The number of Interrupts you’ve been granted is defined by (a) the number of Interrupt Resources you receive, and (b) the “message count” provided for each of those resources.

In your code above, you can see that InterruptTranslated->u.MessageInterrupt.Raw.MessageCount is being passed to you as zero. That means you’ve been granted ZERO MSI (as part of this Interrupt Resource). You can not just “assume” you’re going to get one MSI per port. So, doing that little loop based on the number of ports you define is not valid.

You need to look at the Flags field of your Translated Interrupt Resource to determine if the CM_RESOURCE_INTERRUPT_MESSAGE bit is set. If it is, then you have an MSI or MSI-X. If not, you’ve got an LBI. Which is what I bet you’ve got here.

This code should work for MSI or MSI-X resources – This is an updated version of the code I posted a couple of weeks back which was only correct for MSI-X:

            case CmResourceTypeInterrupt: {

                DbgPrint(INFO,"Resource %lu: Interrupt of total so far %u\n", i, totalInterruptsFound);

                if(totalInterruptsFound < MY_DRIVER_EXPECTED_NUMBER_OF_INTERRUPTS) {

                    resourceRaw = WdfCmResourceListGetDescriptor(Resources, i);

                    if(resourceTrans->Flags & CM_RESOURCE_INTERRUPT_MESSAGE) {

                        WDF_INTERRUPT_CONFIG interruptConfig;

                        DbgPrint("\t\tInt type: MSI/MSI-X\n");

                        DbgPrint("\t\tMessages this resource: %u\n", resourceRaw->u.MessageInterrupt.Raw.MessageCount);

                        for(ULONG intNumber = 0; intNumber < resourceRaw->u.MessageInterrupt.Raw.MessageCount; intNumber++) {

                            //
                            // Create WDFINTERRUPT object thereby connecting to the interrupt.
                            //
                            WDF_INTERRUPT_CONFIG_INIT(&interruptConfig,
                                                      MyDriverIsr,
                                                      MyDriverDpcForIsr);
     
                            interruptConfig.EvtInterruptEnable  = MyDriverInterruptEnable;
                            interruptConfig.EvtInterruptDisable = MyDriverInterruptDisable;
                            interruptConfig.InterruptTranslated = resourceTrans;
                            interruptConfig.InterruptRaw        = resourceRaw;

                            status = WdfInterruptCreate(devContext->WdfDevice,
                                                &interruptConfig,
                                                WDF_NO_OBJECT_ATTRIBUTES,
                                                &devContext->InterruptObjects[totalInterruptsFound]);

                            if(!NT_SUCCESS(status)) {

                                DbgPrint("ConnectInterrupt failed for interrupt # %u? Status = 0x%lx\n", intNumber, status);

                                goto done;
                            }

                            DbgPrint("Successfully connected interrupt %u\n", totalInterruptsFound);

                            totalInterruptsFound ++;
                        }

                    } else {

                        DbgPrint("UNEXPECTED Int type LBI found\n");

                        //
                        // Win32: ERROR_INVALID_PARAMETER
                        //
                        status = STATUS_DEVICE_CONFIGURATION_ERROR;

                        goto done;
                    }

BTW, architecturally you are “required” to handle the case when you fall back to use a single LBI when zero messages are granted. I don’t handle that above.

I should probably write a blog post on this topic, because this question comes up periodically and the whole issue of handling MSI/MSI-X is not well handled in the WDK docs.

And don’t forget: You need to enable MSI/MSI-X support and indicate the max number of MSI/MSI-X interrupts you handle, via Registry entries that you make via your INF. See the WDK Docs on this, which are pretty clear.