【问题标题】:MSI-X interrupts in WDFWDF 中的 MSI-X 中断
【发布时间】:2013-04-20 00:55:54
【问题描述】:

在我们用 WDF / KMDF 编写的 Windows 总线驱动程序中实现 MSI-X 中断时遇到了很多麻烦。 我读过MSDN documentation,那里并没有太多有用的信息。我的理解是它应该真的只是“工作”。

我已更改驱动程序的 INF 文件以添加适当的注册表项,并确认它们已在安装时正常工作。我正在正确查询 PCI 配置空间并确定是否支持 MSI-X 中断。

问题是,一旦我有了这些信息,我不知道如何更改我的代码以专门将中断设置为 MSI-X。我执行标准调用来配置 WDF_INTERRUPT_CONFIG_INIT 结构并调用 WdfInterruptCreate,但创建的中断不是消息信号的,我不知道需要做什么才能真正实现这一点。

是否有 WDF 版本的步骤 here,或者我应该只执行标准的 WDFINTERRUPT 创建步骤 here

有人有这方面的经验吗?任何人都可以提供源示例吗?

【问题讨论】:

    标签: windows driver interrupt kmdf wdf


    【解决方案1】:

    上周我一直在为类似的事情苦苦挣扎。我的应用程序略有不同,因为我试图让普通的 MSI 中断而不是 MSI-X 中断工作。但我使用 WDF 框架的方式几乎相同。

    我知道您在 2013 年 4 月左右发布了您最初的问题,但没有更新。你解决了你原来的问题吗?如果是这样,我想看看你自己的解决方案。

    在我的 WDF 驱动程序中,我正在映射传入的硬件资源列表并使用 WdfCmResourceListGetDescriptor() 函数对其进行解析,以检查 WDFCMRESLIST 列表中的每个 PCM_PARTIAL_RESOURCE_DESCRIPTOR 项。我能够获得单个 CmResourceTypeInterrupt 描述符,但它始终用于旧式中断而不是 MSI 中断。我的设备确实支持 MSI。我不明白为什么 MSI 描述符不在资源列表中,即使按照您的描述在我的 .inf 文件中设置了额外的注册表项。

    原来我的 .inf 文件中有错字。我忘记在我的设备安装部分添加“.HW”后缀。添加此后缀允许总线管理器修改设备中的 pcie 配置地址并创建适当的 MSI 中断资源描述符,该描述符必须由驱动程序挂钩。

    [Standard.NT$ARCH$]
    %tdvr.DeviceDesc%=tdvr_Device, PCI\VEN_104C&DEV_B800 
    
    [tdvr_Device.NT]
    CopyFiles=Drivers_Dir
    
    [tdvr_Device.NT.HW]
    AddReg=MSI_Interrupts
    
    [Drivers_Dir]
    tdvr.sys
    
    ;http://msdn.microsoft.com/en-us/library/windows/hardware/ff544246(v=vs.85).aspx
    ;To receive message-signaled interrupts (MSIs), a driver's INF file must enable MSIs in the 
    ;registry during installation. Use the Interrupt Management\MessageSignaledInterruptProperties 
    ;subkey of the device's hardware key to enable MSI support.
    
    [MSI_Interrupts]
    HKR,Interrupt Management,,0x00000010
    HKR,Interrupt Management\MessageSignaledInterruptProperties,,0x00000010
    HKR,Interrupt Management\MessageSignaledInterruptProperties,MSISupported,0x00010001,1
    

    当在资源列表中找到 MSI 中断资源描述符时(例如在 evtMapHWResources 回调中),该描述符将用作 WdfInterruptCreate() 函数的输入。此处的“tdvr”前缀用于我自己的驱动程序命名约定。

    NTSTATUS
    tdvrConfigureInterrupts(
        _Inout_ PDEVICE_CONTEXT deviceContext,
        _In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR interruptDescRaw,
        _In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR interruptDescTranslated
        )
    {
        NTSTATUS status;
        PAGED_CODE();
        FuncEntry();
    
        // What kind of interrupt has been provided?
        if (CM_RESOURCE_INTERRUPT_MESSAGE & interruptDescTranslated->Flags)
        {
            TraceInterrupt(TRACE_LEVEL_INFORMATION, 
                "Message Interrupt level 0x%0x, Vector 0x%0x, MessageCount %u\n"
                ,interruptDescTranslated->u.MessageInterrupt.Translated.Level
                ,interruptDescTranslated->u.MessageInterrupt.Translated.Vector
                ,interruptDescTranslated->u.MessageInterrupt.Raw.MessageCount
                );
        }
        else
        {
            TraceInterrupt(TRACE_LEVEL_INFORMATION,
                "Legacy Interrupt level: 0x%0x, Vector: 0x%0x\n"
                ,interruptDescTranslated->u.Interrupt.Level
                ,interruptDescTranslated->u.Interrupt.Vector
                );
        }
    
        //
        // Create WDFINTERRUPT object.
        //
        WDF_INTERRUPT_CONFIG interruptConfig;
        WDF_INTERRUPT_CONFIG_INIT(
            &interruptConfig,
            tdvrEvtInterruptIsr,
            tdvrEvtInterruptDpc
            );
    
        // Each interrupt has some context data
        WDF_OBJECT_ATTRIBUTES interruptAttributes;
        WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(
            &interruptAttributes,
            INTERRUPT_CONTEXT
            );
    
        //
        // These first two callbacks will be called at DIRQL.  Their job is to
        // enable and disable interrupts.
        //
        interruptConfig.EvtInterruptEnable  = tdvrEvtInterruptEnable;
        interruptConfig.EvtInterruptDisable = tdvrEvtInterruptDisable;
    
        // If the driver calls WdfInterruptCreate from EvtDriverDeviceAdd, the InterruptRaw and
        // InterruptTranslated members of the WDF_INTERRUPT_CONFIG structure must be NULL. 
        // the driver calls WdfInterruptCreate from EvtDevicePrepareHardware, these members must both be valid.
        interruptConfig.InterruptTranslated = interruptDescTranslated;
        interruptConfig.InterruptRaw = interruptDescRaw;
    
        // Our driver must call WdfInterruptCreate once for each interrupt vector that its device requires. 
        // If the device supports message-signaled interrupts (MSI), the driver must create an interrupt object 
        // for each message that the device can support.
        status = WdfInterruptCreate(
            deviceContext->WdfDevice,
            &interruptConfig,
            &interruptAttributes,
            &deviceContext->WdfInterrupt
            );
    
        if (!NT_SUCCESS(status))
        {
            TraceInterrupt(TRACE_LEVEL_ERROR, "WdfInterruptCreate FAILED: %!STATUS!\n", status);
        }
        else
        {
            PINTERRUPT_CONTEXT interruptContext = InterruptGetContext(deviceContext->WdfInterrupt);
            // do whatever with context info
        }
    
        FuncExit();
        return status;
    }
    

    就像我说的,希望你现在已经弄清楚了,但我想我还是会发布一些东西来贡献。

    【讨论】:

    • 感谢您的贡献!不幸的是,我没有太多要补充的。对我们来说,当我被重新分配到这个项目时,我们意识到调试测试人员正在部署错误的驱动程序,并且我们实际上收到了消息信号中断。我注意到我们做了而你没有做的一件事是在 inf 中设置以下行:HKR, Interrupt Management\MessageSignaledInterruptProperties,MessageNumberLimit,0x00010001,8。我不确定这是否有所作为。抱歉,我无法提供更多帮助,但祝你好运。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-15
    相关资源
    最近更新 更多