Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1940240
  • 博文数量: 1000
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 7921
  • 用 户 组: 普通用户
  • 注册时间: 2013-08-20 09:23
个人简介

storage R&D guy.

文章分类

全部博文(1000)

文章存档

2019年(5)

2017年(47)

2016年(38)

2015年(539)

2014年(193)

2013年(178)

分类: 服务器与存储

2015-02-10 15:50:03

I have been struggling with something similar in the last week. My application is slightly different because I am trying to get plain MSI interrupts rather than MSI-X interrupts to work. But I am using the WDF framework in pretty much the same way.

I realize you posted your original question around April of 2013, but there are no updates. Have you solved your original problem? If so, I would like to see your own solution.

In my WDF driver, I am mapping an incoming hardware resource list and parsing it using the WdfCmResourceListGetDescriptor() function to examine each PCM_PARTIAL_RESOURCE_DESCRIPTOR item in the WDFCMRESLIST list. I was able to obtain a single CmResourceTypeInterrupt descriptor, but it was always for a legacy interrupt instead of MSI interrupt. My device does support MSI. I did not understand why the MSI descriptor was not in the resource list, even after setting up the extra registry entries in my .inf file as you described.

It turns out I had a typo in my .inf file. I had forgotten to append the ".HW" suffix in my device install section. Adding this suffix allows the Bus manager to modify the pcie config addresses in the device and create the appropriate MSI interrupt resource descriptor, which must be hooked by the driver.

[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

;(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 

When the MSI interrupt resource descriptor is found in the resource list (for example in a evtMapHWResources callback), the descriptor is used as an input to the WdfInterruptCreate() function. The "tdvr" prefixes here are for my own driver naming convention.

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;
} 

Like I said hopefully by now you have this all figured out, but I thought I would post something anyway to contribute.

HKR,Interrupt Management\MessageSignaledInterruptProperties,MessageNumberLimit,0x00010001,8

useful link: (v=vs.85).aspx

阅读(1313) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~