none
How to write configuration space RRS feed

  • Question

  • Hi,

    The configuration space can be read and write using  FdoData->BusInterface.GetBusData/SetBusData. What is the difference from using IRP_MN_READ_CONFIG/IRP_MN_WRITE_CONFIG?

    Is it safe to write/update without Read/Get first?

    Many data members in the configuration space are ReadOnly - or they are not supposed to be modified. I guess that will be driver-specific, right?

    Thank you

    Tiger

    Tuesday, April 28, 2015 8:56 PM

Answers

  • they do the same thing, just in different form

    d -- This posting is provided "AS IS" with no warranties, and confers no rights.

    Wednesday, April 29, 2015 1:30 AM

All replies

  • What are you trying to achieve?  Why do you think you need to deal with the configuration space?

    Drivers normally do not touch configuration space, and only do it if there are specific fields that the device designer put in the space that are beyond the normal configuration parameters. 


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

    Tuesday, April 28, 2015 9:25 PM
  • they do the same thing, just in different form

    d -- This posting is provided "AS IS" with no warranties, and confers no rights.

    Wednesday, April 29, 2015 1:30 AM
  • Thank you for the answer.

    I don't know what to do with it. It's my first driver program. From the names of the registers in the configuration space, such as Device Control, Link Control, Power Management Control/Status, etc. it seems to me that I need to turn some bits of the control registers to turn on or reset the device. BIST (built-in-self-test) control/status is also in the configuration space.

    I am having troubles to get interrupt working. the PCIe device driver is installed successfully with Bar0 (mem: 64K) and BAR2 (Mem 1K). I can read/write both memory spaces. The device driver FDO is created by system root port PCI bus driver.  Interrupt is MSI. I was not sure the device needs to turn power on(or power state is managed by bus driver/PNP manager) and to enable interrupt. What is the power state of the device after the device driver is installed? Does the device need a soft reset?  I don't know is device generating the interrupts or is something else.

    Thank you,

    Tiger

    Wednesday, April 29, 2015 12:51 PM
  • This is why I asked for what you were doing.  It is likely your setup of interrupts is wrong, and you do not need to touch the configuration space.

    Show us all the code for creating the interrupt object, enabling/disabling interrupts, and the interrupt service routine.


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

    Wednesday, April 29, 2015 12:57 PM
  • I copied some code snippets here:


    //INF file MSI section - IRQ is assigned to 0xFFFFFFFF9(-7)


    ; Message Signalled Interrupts; 3 -

    [UpdateRegistry]

    HKR,

    "Interrupt Management", 0x00000010

    HKR,

    "Interrupt Management\MessageSignaledInterruptProperties", 0x00000010

    HKR,

    "Interrupt Management\MessageSignaledInterruptProperties", MSISupported, 0x00010001, 1



    /////////////////////In device Add


    NTSTATUS PCIeEvtDeviceAdd(_In_  WDFDRIVER Driver, _Inout_ PWDFDEVICE_INIT DeviceInit) {

    ...

    pnpPowerCallbacks.EvtDevicePrepareHardware = KitsPCIeEvtDevicePrepareHardware;

    //.


    pnpPowerCallbacks.EvtDeviceReleaseHardware = KitsPCIeEvtDeviceReleaseHardware;

    // These two callbacks set up and tear down hardware state that must be


    // done every time the device moves in and out of the D0-working state.


    pnpPowerCallbacks.EvtDeviceD0Entry = KitsPCIeEvtDeviceD0Entry;

    //.


    pnpPowerCallbacks.EvtDeviceD0Exit = KitsPCIeEvtDeviceD0Exit;

    // These next two callbacks are for doing work at PASSIVE_LEVEL (low IRQL)


    // after all the interrupts are connected and before they are disconnected.


    //


    // Some drivers need to do device initialization and tear-down while the


    // interrupt is connected.  (This is a problem for these devices, since


    // it opens them up to taking interrupts before they are actually ready


    // to handle them, or to taking them after they have torn down too much


    // to be able to handle them.)  While this hardware design pattern is to


    // be discouraged, it is possible to handle it by doing device init and


    // tear down in these routines rather than in EvtDeviceD0Entry and


    // EvtDeviceD0Exit.


    // In this sample these callbacks don't do anything.


    //?needwork


    pnpPowerCallbacks.EvtDeviceD0EntryPostInterruptsEnabled = PCIeEvtDeviceD0EntryPostInterruptsEnabled;

    pnpPowerCallbacks.EvtDeviceD0ExitPreInterruptsDisabled = PCIeEvtDeviceD0ExitPreInterruptsDisabled;

    ...

    }

    NTSTATUS PCIeAllocateSoftwareResources(IN OUT PFDO_DATA FdoData)

    {

    NTSTATUS                        status = STATUS_SUCCESS;

    WDF_OBJECT_ATTRIBUTES           attributes;

    WDF_IO_QUEUE_CONFIG             ioQueueConfig;

    WDF_DMA_ENABLER_CONFIG          dmaConfig;

    ULONG                           maximumLength, maxLengthSupported;

    ULONG                           maxMapRegistersRequired, miniMapRegisters;

    ULONG                           mapRegistersAllocated;

    PAGED_CODE();

    WDF_OBJECT_ATTRIBUTES_INIT(&attributes);

    attributes.ParentObject = FdoData->WdfDevice;

    status = WdfSpinLockCreate(&attributes, &FdoData->Lock);

    status = WdfFdoQueryForInterface(FdoData->WdfDevice, &GUID_BUS_INTERFACE_STANDARD,

    (PINTERFACE)&FdoData->BusInterface,

    sizeof(BUS_INTERFACE_STANDARD), 1, NULL); //InterfaceSpecificData


    status = PCIeGetDeviceInformation(FdoData);

    PCIeGetDeviceInfSettings(FdoData);

    //.


       

    //I/O Queues...


    WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchParallel);

    ioQueueConfig.EvtIoWrite = PciDrvEvtIoWrite;

    status = WdfIoQueueCreate(FdoData->WdfDevice, &ioQueueConfig,

    WDF_NO_OBJECT_ATTRIBUTES, &FdoData->WriteQueue);

    WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchManual);

       

    //IRQ ...


    #ifndef

    PCIE_CREATE_INTERRUPT_IN_PREPARE_HARDWARE

    // Create WDFINTERRUPT object.


    WDF_INTERRUPT_CONFIG interruptConfig;

    WDF_INTERRUPT_CONFIG_INIT(&interruptConfig, PCIeEvtInterruptIsr, PCIeEvtInterruptDpc);

    //+ Each interrupt has some context data


    //WDF_OBJECT_ATTRIBUTES intAttributes;


    //WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, INTERRUPT_CONTEXT);


    interruptConfig.EvtInterruptEnable = PCIeEvtInterruptEnable;

    interruptConfig.EvtInterruptDisable = PCIeEvtInterruptDisable;

    //interruptConfig.InterruptRaw = WdfCmResourceListGetDescriptor(ResourcesRaw, i);


    //interruptConfig.InterruptTranslated = descriptor;


    status = WdfInterruptCreate(FdoData->WdfDevice, &interruptConfig,

    WDF_NO_OBJECT_ATTRIBUTES, &FdoData->WdfInterrupt);

    if(!NT_SUCCESS(status)){

    Kdf_PrintEx((_DIID, _DIL,

    "PCIeDrv:WdfInterruptCreate [%X]\n", status));

    returnstatus;

    }

    else{

    Kdf_PrintEx((_DIID, _DIL,

    "PCIeDrv:WdfInterruptCreated \n"));

    }


    #endif


       

    //other Code block...


    returnstatus;

    }

    BOOLEAN PCIeEvtInterruptIsr(IN WDFINTERRUPT Interrupt, IN ULONG MessageID)

    {

    BOOLEAN    InterruptRecognized = FALSE;

    PFDO_DATA  FdoData = NULL;

    USHORT     IntStatus;

    Kdf_PrintEx((_DIID, _DIL,

    "PCIeDrv:ISR..\n"));

    FdoData = FdoGetData(WdfInterruptGetDevice(Interrupt));

    // We process the interrupt if it's not disabled and it's active


    if(!NIC_INTERRUPT_DISABLED(FdoData) && NIC_INTERRUPT_ACTIVE(FdoData)) {

    InterruptRecognized = TRUE;

    // Disable the interrupt (will be re-enabled in PCIeEvtInterruptDpc


    PCIeDisableInterrupt(FdoData);

    // Acknowledge the interrupt(s) and get the interrupt status


    ////NIC_ACK_INTERRUPT(FdoData, IntStatus); needwork...


    WdfInterruptQueueDpcForIsr(Interrupt);

    }

    returnInterruptRecognized;

    }

    VOID PCIeEvtInterruptDpc(IN WDFINTERRUPT WdfInterrupt, IN WDFOBJECT WdfDevice)

    {

    UNREFERENCED_PARAMETER(WdfInterrupt);

    UNREFERENCED_PARAMETER(WdfDevice);

    //expected to be called at least once


    Kdf_PrintEx((_DIID, _DIL,

    "PCIeDrv:PCIeEvtInterruptDpc.\n"));

    }



    //this is called


    NTSTATUS KitsPCIeEvtDeviceD0Entry(IN  WDFDEVICE Device, IN  WDF_POWER_DEVICE_STATE PreviousState)

    {

    UNREFERENCED_PARAMETER(Device);

    UNREFERENCED_PARAMETER(PreviousState);

    PFDO_DATA               fdoData;

    Kdf_PrintEx((_DIID, _DIL,

    "PCIeDrv: EvtDeviceD0Entry...:\n"));

    fdoData = FdoGetData(Device);

    ASSERT(PowerDeviceD0 != PreviousState);

    fdoData->DevicePowerState = PowerDeviceD0;

    if(PCIeIsPoMgmtSupported(fdoData)){

    Kdf_PrintEx((_DIID, _DIL,

    "PCIeDrv: Entering fully on state...:\n"));

    PCIeMPSetPowerD0(fdoData);

    //this may have problem...


    }

    Kdf_PrintEx((_DIID, _DIL,

    "PCIeDrv: EvtDeviceD0Entry Ret\n"));

    returnSTATUS_SUCCESS;

    }

    NTSTATUS PCIeEvtInterruptEnable(IN WDFINTERRUPT  Interrupt, IN WDFDEVICE AssociatedDevice)

    {

    PFDO_DATA           fdoData;

    BOOLEAN bRet;

    fdoData = FdoGetData(AssociatedDevice);

    bRet = PCIeEnableInterrupt(Interrupt, fdoData);

    if(bRet == TRUE) {

    Kdf_PrintEx((_DIID, _DIL,

    "PCIeDrv:PCIeEvtInterruptEnable+.\n"));

    }

    else{

    Kdf_PrintEx((_DIID, _DIL,

    "PCIeDrv:PCIeEvtInterruptEnable-.\n"));

    }

    returnSTATUS_SUCCESS;

    }

    NTSTATUS PCIeEvtDeviceD0EntryPostInterruptsEnabled(IN WDFDEVICE Device, IN WDF_POWER_DEVICE_STATE PreviousState)

    {

    PFDO_DATA  fdoData;

    UNREFERENCED_PARAMETER(PreviousState);

    Kdf_PrintEx((_DIID, _DIL,

    "PCIeDrv:PCIeEvtDeviceD0EntryPostInterruptsEnabled.\n"));

    fdoData = FdoGetData(Device);

    returnSTATUS_SUCCESS;

    }

    EVT_WDF_INTERRUPT_SYNCHRONIZE PCIeEnableInterrupt;


    __inline

    BOOLEAN PCIeEnableInterrupt(IN WDFINTERRUPT WdfInterrupt, IN WDFCONTEXT Context)

    {

    UNREFERENCED_PARAMETER(WdfInterrupt);

    UNREFERENCED_PARAMETER(Context);

    //PFDO_DATA FdoData = (PFDO_DATA)Context;


    //FdoData->CSRAddress->ScbCommandHigh = 0;


    //////////////////////////////


       

    //what to do...?


    BOOLEAN bStatus = TRUE;

    returnbStatus;

    }

    ////////////////////////////////////////

    It seems to me that the power state is D3. It may also need to enable IRQ. But I don't know which is IRQ enable control bit.

    Thank you, Don.

    Tiger

    Wednesday, April 29, 2015 2:03 PM
  • Where is PCIeAllocateSoftwareResources called from?  As far as enabling and disabling interrupts, your hardware should have a bit specified in one of the control registers you map into memory, if not there is nothing you can do to control the interrupt.


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

    Wednesday, April 29, 2015 2:13 PM
  • PCIeAllocateSoftwareResources is called inside of the DeviceAdd().

    ...

    fdoAttributes.EvtCleanupCallback = KitsPCIeEvtDeviceContextCleanup;

    status = WdfDeviceCreate(&DeviceInit, &fdoAttributes, &device);

    fdoData = FdoGetData(device);

    fdoData->WdfDevice = device;

    status = PCIeAllocateSoftwareResources(fdoData);

    ...

    I am reviewing the hardware documents to figure out control registers and how to enabling IRQ, etc.

    Tiger

    Wednesday, April 29, 2015 2:26 PM
  • I found that the hardware is not permitted to use MSI. the MSIEnable bit is read as 0.

    Tiger

    Wednesday, April 29, 2015 3:04 PM
  • Remove the MSI settings from the INF file.  Use system restore to roll back to before you tried installing the driver, and then try again with the new INF.


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

    Wednesday, April 29, 2015 3:11 PM
  • Hi Don,

    I removed MSI settings from INF. The IRQ in the Device Manager / Device Property Page is 0x10(16). In the PCIeMapHWResources() function, the descriptor (CmResourceTypeInterrupt) shows legacy interrupt with Interrupt Level as 8, vector 0x82.

    Whether the Altera FPGA PCIe has memory mapped I/O or not is still a question to me. If it is memory mapped, what's the structure is not very clear to me.

    Thank you,

    David

    Wednesday, April 29, 2015 8:23 PM
  • Altera FPGA's for PCIe definitely support memory mapped I/O.  The question is not Altera, but what did the designer of the FPGA code put in there, this could be an Altera design or it could be custom.


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

    Wednesday, April 29, 2015 8:41 PM
  • I am going to close this thread. I think I need to take some time on Altera FPGA.

    Thank you all for the help.

    Tiger

    Thursday, April 30, 2015 12:28 PM