none
System reboots if PCI device triggers IRQ RRS feed

  • Question

  • Hello community,

    I'm trying to implement a stream driver for a PCI device. It get  found by the PCI bus enumerator and gets the correct information in \Driver\BuiltIn\PCI\Instance\. In the Init-function of my stream driver I use DDKReg_GetPciInfo, DDKReg_GetIsrInfo and DDKReg_GetMemInfo to get the information provided by the registry. After that, I can use BusTransBusAddrToVirtual() to transfer my bus specific address for the I/O-space in a virtual one (value stays the same, because I'm on x86). Up to now, everything works fine, I can use READ_PORT_ULONG and WRITE_PORT_ULONG to communicate with all provided I/O registers. The next step would be implementing a simple IRQ-handling.

    The device has a free running counter, and a compare register, which together can trigger a timer IRQ if they match. I can read the timer-value, add a value for 5 seconds, poll every second on the IRQ status register, and after 5 polls the status register tells me that the IRQ is pending. What does not work, is if I enable the IRQ to trigger a PCI IRQ. This leads to a system reboot. I guess the IRQ doesn't get acknowledged, however I couldn't find out why not.

    I tried to follow the explanations in the "Exam Preparation"-PDf as well as other sources I found, but I must have missed a step. Here is what I have done so far:

    In the Init function of my stream driver:

    *) Use LoadIntChainHandler with "giisr.dll", "ISRHandler" and my IRQ number (I get the values from the registry)

    *) Fill a GIISR_INFO structure with

    GiisrInfo.SysIntr = pInst->IsrInfo.dwSysintr;
    GiisrInfo.CheckPort = TRUE;
    GiisrInfo.PortIsIO = TRUE;
    GiisrInfo.PortAddr = (DWORD) (pInst->pVirtIO + 0x14);
    GiisrInfo.PortSize = sizeof( DWORD );
    GiisrInfo.Mask = 0xFF000000;
    GiisrInfo.UseMaskReg = FALSE;
    and call
    KernelLibIoControl( pInst->hISR, IOCTL_GIISR_INFO, &GiisrInfo, sizeof(GiisrInfo), NULL, 0, &dwKernIoSuccess )

    *) Create an Event for the IST to wait on

    *) Create the IST with the CREATE_SUSPENDED flag

    *) Call InterruptInitialize() to link Event & dwSysintr

    *) Call SetThreadPriority() to set priority of IST to THREAD_PRIORITY_TIME_CRITICAL

    *) Start the Thread using ResumeThread()

    All return values are checked, so I can be sure all functions are successful.

    The IST looks like all the examples I have found on the net, expanded for the specific HW handling for my PCI device.

    DWORD WINAPI IrqHandler(LPVOID lpArg)
    {
        OMAC_INSTANCE *pInst;
        ULONG TmpLong;

        pInst = (OMAC_INSTANCE *) lpArg;

        DEBUGMSG( TRUE, (L"* IRQ starts up *\n" ) );

        do
        {
            if( FALSE == pInst->ContinueIRQ )
            {
                return 0; // End IST if device driver gets unloaded
            }

            WaitForSingleObject( pInst->hIrqEvent, INFINITE );

            DEBUGMSG( TRUE, (L"*****************************\n" ) );
            DEBUGMSG( TRUE, (L"* IRQ catched EVENT *\n" ) );
            DEBUGMSG( TRUE, (L"*****************************\n" ) );

            // Read current time
            TmpLong = READ_PORT_ULONG( (PULONG) ((PCHAR) pInst->pVirtIO + HW_IO_REG_MACTIMVAL) );

            TmpLong += 250000000; // Add 5 seconds (20ns time base)
            WRITE_PORT_ULONG( (PULONG) (pInst->pVirtIO + HW_IO_REG_MACTIMCMP), TmpLong );

            TmpLong = 0x00FF0000; // Ack all IRQs, including TimerIRQ
            WRITE_PORT_ULONG( (PULONG) (pInst->pVirtIO + HW_IO_REG_IRQ), TmpLong );

            // Acknowledge IRQ
            InterruptDone( pInst->IsrInfo.dwSysintr );
       }
       while( TRUE == pInst->ContinueIRQ );

       DEBUGMSG( TRUE, (L"* IRQ handler shutting down *\n" ) );

       return 0;
    }

     

    As additional info about the device, here are the contents of the registry:

    REGEDIT4

    [HKEY_LOCAL_MACHINE\Drivers\BuiltIn\PCI\Instance\OMD1]
    "Flags"=dword:00000000
    "SysIntr"=dword:00000020
    "Irq"=dword:00000006
    "IoLen"=dword:00000040
    "IoBase"=dword:00006400
    "MemLen"=dword:00004000
    "MemBase"=dword:e0200000
    "FunctionNumber"=dword:00000000
    "DeviceNumber"=dword:00000004
    "BusNumber"=dword:00000002
    "InterfaceType"=dword:00000005
    "SubSystemID"=dword:00001000
    "SubVendorID"=dword:00000000
    "RevisionID"=dword:00000022
    "IsrHandler"="ISRHandler"
    "IsrDll"="giisr.dll"
    "Order"=dword:000003e6
    "Index"=dword:00000001
    "Prefix"="OMD"
    "Dll"="OpenMacDriver.dll"
    "ProgIF"=dword:00000080
    "SubClass"=dword:00000000
    "Class"=dword:00000002
    "VendorID"=dword:00001234
    "DeviceID"=dword:00009999
    "InstanceIndex"=dword:00000001

    After all the initialisation in my Init function, it calls

    TmpLong = 0x00000004; // Enable TimerIRQ<br/>
    WRITE_PORT_ULONG( (PULONG) (pInst->pVirtIO + HW_IO_REG_IRQ), TmpLong );

    which leads to system reboot after some seconds. The last thing I see in the debug output of Platform Builder is

    1104065 PID:1300006 TID:c20002 [NOTIFY] HandleSystemEvent 7 /ADD OMD1:
    1104101 PID:400002 TID:2ce0002 R
    1104101 PID:400002 TID:2ce0002 U
    1109061 PID:400002 TID:4eb0002 Faulted in KCall, pCurThread->dwStartAddr = c0287e40, PageFreeCount = 0001c00b!!
    1109061 PID:400002 TID:4eb0002 Original Context when thread faulted:
    1109061 PID:400002 TID:4eb0002 Exception Access Violation (14): Thread-Id=04eb0002(pth=89e6a2b8), Proc-Id=00400002(pprc=81bb7c80) 'NK.EXE', VM-active=01f70002(pprc=9f3efe1c) 'shell.exe'
    1109061 PID:400002 TID:4eb0002 EIP=8025da11 Flags=00003246 EA=00000000
    1109061 PID:400002 TID:4eb0002 Eax=00000102 Ebx=00000000 Ecx=00000000 Edx=da13f954
    1109061 PID:400002 TID:4eb0002 Esi=00000000 Edi=80270ff0 Ebp=da13f8e8 Esp=da13f8e4
    1109061 PID:400002 TID:4eb0002 CS=0019 DS=0040 ES=0040 SS=0021 FS=0060 GS=0000
    1109061 PID:400002 TID:4eb0002 Context when faulted in KCall:
    1109061 PID:400002 TID:4eb0002 Exception Access Violation (14): Thread-Id=04eb0002(pth=89e6a2b8), Proc-Id=00400002(pprc=81bb7c80) 'NK.EXE', VM-active=01f70002(pprc=9f3efe1c) 'shell.exe'
    1109061 PID:400002 TID:4eb0002 EIP=00000000 Flags=00013292 EA=00000000
    1109061 PID:400002 TID:4eb0002 Eax=00000005 Ebx=81b69800 Ecx=81b62f98 Edx=00000000
    1109061 PID:400002 TID:4eb0002 Esi=80228420 Edi=81b62ee8 Ebp=81b62ec4 Esp=81b62ebc
    1109061 PID:400002 TID:4eb0002 CS=0008 DS=0040 ES=0040 SS=0010 FS=80250060 GS=81b60000
    1109061 PID:400002 TID:4eb0002 Exception 'Access Violation' (14): Thread-Id=04eb0002(pth=89e6a2b8), Proc-Id=00400002(pprc=81bb7c80) 'NK.EXE', VM-active=01f70002(pprc=9f3efe1c) 'shell.exe'
    1109061 PID:400002 TID:4eb0002 PC=00000000(???+0x00000000) RA=802285bc(NK.EXE+0x000085bc)
    SP=802277e2, BVA=00000000

     

    If anyone has additional ideas on how to debug this issue, please share them with me.

    Best regards,

    Wolfgang Wallner


    PS: Am I the only one who has to fight with the formating tools of this forum? Somehow my posts always show up very different than I insert them ...

    PPS: I tried to insert only a few lines of source code to avoid blowing up this post even more. If additional source is needed to clarify things, feel free to ask.

    Friday, August 13, 2010 5:21 PM

All replies

  • Wolfgang:

    I am not sure what is happening, or what in your BSP/Board would cause the reset. 

    There is an access violation in Shell.exe, and while it could be a bug in Shell.exe it is more likely the result of something that your code is doing.  How do you intialize pInst->pVirtIO?  It should be a statically mapped virtual address.

    BTW, SetThreadPriority() is a function for Windows CE 3.0 and prior.  Although it can still be used, it may not be doing what you need it to do.  Take a look at CeSetThreadPriority().  This is in no way a cause of the problem that you currently have though, but later on when you come back and question why your driver is blocked by something, it will be.


    Bruce Eitman (eMVP)
    Senior Engineer
    Bruce.Eitman AT Eurotech DOT com
    My BLOG http://geekswithblogs.net/bruceeitman

    Eurotech Inc.
    www.Eurotech.com
    Friday, August 13, 2010 6:04 PM
    Moderator
  • Hello,

    pVirtIO is the virtual address for the IO space of the PCI device. I get it from calling BusTransBusAddrToVirtual(). However, accessing IO-space works fine (at least during the Init-function). As stated above, I can access & modify all the bits and bytes the HW provides.

    What exactly do you mean with 'a statically mapped virtual address' (especially the statically-part) ?

    Any further debug-ideas? It would be interesting how far the IRQ handling gets before things start to go wrong. Is there a way to verify if the ISRHandler of giisr gets ever called, or to verify if my IRQ-Handler ever gets its event signaled?

    Is the way I use all the functions correct in general?

    Best regards,

    Wolfgang Wallner

    PS: Thanks for the tip with CeSetThreadPriority. I have already read about the issue of SetThreadPriority vs CeSetThreadPriority in Douglas Boling's WindowsCE book and decided I will take care about that point later on.
    Saturday, August 14, 2010 12:39 PM
  • Hello,

    I have just read the MSDN page of TransBusAddrToStatic. It seems to be what I need. As it also states that it is deprecated, and one should use BusTransBusAddrToStatic instead, this will be the next thing to try on monday.

    However, I'm not sure if this will make a difference? BusTransBusAddrToVirtual tends to return the same value as it is given if AddressSpace == 1 (IO-space). Will BusTransBusAddrToStatic do anything different?

    Best regards,

    Wolfgang Wallner

     

    Saturday, August 14, 2010 1:09 PM
  • BusTransBusAddrToVirtual should create an address that will be valid for use in GIISR where it will be used.
    Bruce Eitman (eMVP)
    Senior Engineer
    Bruce.Eitman AT Eurotech DOT com
    My BLOG http://geekswithblogs.net/bruceeitman

    Eurotech Inc.
    www.Eurotech.com
    Saturday, August 14, 2010 1:37 PM
    Moderator
  • Hello,

    1) I have just tried BusTransBusAddrToStatic, but with no success. I keep getting the same error. And as expected, BusTransBusAddrToStatic returns the same value as BusTransBusAddrToVirtual, because the I have the AddressSpace-parameter set to '1' (both functions return 0x6400, which is the same value I get from the registry).

    If would set AddressSpace to '0', it would call CreateStaticMapping instead of MmMapIoSpace, but I don't think this would be correct?

    I'm still not sure about how to handle the AddressSpace-parameter (Compare to my other post concerning this issue ).

    I handle it like this:

    If I would like to translate the address of memory space of the PCI device, i set it to '0' on input.
    If I would like to translate the address of I/O space of the PCI device, i set it to '1' on input.

    The value that comes out tells me if I need to call MmUnmapIoSpace.

    Is this correct?

    2) As another approach, I have tried studying the debug output (Using the information found on a WinCE Blog ): The output
    Faulted in KCall, pCurThread->dwStartAddr = c0b5a113 , PageFreeCount = 0001c008!!
    4294882095 PID:400002 TID:38f0002 Original Context when thread faulted:
    4294882095 PID:400002 TID:38f0002 Exception Access Violation (14): Thread-Id=038f0002(pth=89f75dc0), Proc-Id=00400002(pprc=81bb7c80) 'NK.EXE' , VM-active=01f70002(pprc=9f3efe1c) 'shell.exe'

    together with

    4294768484 PID:400002 TID:bb0002 OSAXST1: >>> Loading Module 'pcibus.dll ' (0x9F57A8F8) at address 0xC0B20000-0xC0B3A000 in Process 'NK.EXE' (0x81BB7C80)

    indicates that the error is happening somewhere inside 'pcibus.dll'. However, I don't know yet how this information will help.

    As always, I'm glad for additional advice,

    best regards, Wolfgang Wallner

     

     

    Monday, August 16, 2010 5:39 AM
  • In your IST you do:
     
            // Read current time
            TmpLong = READ_PORT_ULONG( (PULONG) ((PCHAR) pInst->pVirtIO + HW_IO_REG_MACTIMVAL) );

            TmpLong += 250000000; // Add 5 seconds (20ns time base)
            WRITE_PORT_ULONG( (PULONG) (pInst->pVirtIO + HW_IO_REG_MACTIMCMP), TmpLong );
    Which is the type of pVirtIO ? I ask because you cast it to (PCHAR) to add an offset (in bytes I guess) when you read but not when you write. Maybe you're writing outside the mapped I/O range 
     
     

    --
    Luca Calligaris (MVP-Windows Embedded)
    lucaDOTcalligarisATeurotechDOTcom
    www.eurotech.com
     
     
    "Wolfgang Wallner" <=?utf-8?B?V29sZmdhbmcgV2FsbG5lcg==?=> ha scritto nel messaggio news:a06126df-8cd9-4659-bde6-baca2b307509...

    Hello,

    1) I have just tried BusTransBusAddrToStatic, but with no success. I keep getting the same error. And as expected, BusTransBusAddrToStatic returns the same value as BusTransBusAddrToVirtual, because the I have the AddressSpace-parameter set to '1' (both functions return 0x6400, which is the same value I get from the registry).

    If would set AddressSpace to '0', it would call CreateStaticMapping instead of MmMapIoSpace, but I don't think this would be correct?

    I'm still not sure about how to handle the AddressSpace-parameter (Compare to my other post concerning this issue ).

    I handle it like this:

    If I would like to translate the address of memory space of the PCI device, i set it to '0' on input.
    If I would like to translate the address of I/O space of the PCI device, i set it to '1' on input.

    The value that comes out tells me if I need to call MmUnmapIoSpace.

    Is this correct?

    2) As another approach, I have tried studying the debug output (Using the information found on a WinCE Blog ): The output
    Faulted in KCall, pCurThread->dwStartAddr = c0b5a113 , PageFreeCount = 0001c008!!
    4294882095 PID:400002 TID:38f0002 Original Context when thread faulted:
    4294882095 PID:400002 TID:38f0002 Exception Access Violation (14): Thread-Id=038f0002(pth=89f75dc0), Proc-Id=00400002(pprc=81bb7c80) 'NK.EXE' , VM-active=01f70002(pprc=9f3efe1c) 'shell.exe'

    together with

    4294768484 PID:400002 TID:bb0002 OSAXST1: >>> Loading Module 'pcibus.dll ' (0x9F57A8F8) at address 0xC0B20000-0xC0B3A000 in Process 'NK.EXE' (0x81BB7C80)

    indicates that the error is happening somewhere inside 'pcibus.dll'. However, I don't know yet how this information will help.

    As always, I'm glad for additional advice,

    best regards, Wolfgang Wallner

     

     


    Luca Calligaris (MVP-Windows Embedded) lucaDOTcalligarisATeurotechDOTcom www.eurotech.com
    Monday, August 16, 2010 8:48 AM
  • Hello,

    Yes, the offsets in the defines are in Bytes. pVirtIO is of type PUCHAR, so this should be OK. I don't know why I left it out in the WRITE_PORT_ULONG.

    I was thinking of another debug-approach. Is there a way to reconfigure which IRQ my device gets? As I see in the registry, I have to share IRQ 6 with some USB driver. If I could modify it, so that my device gets its own IRQ, i could try GiisrInfo.CheckPort = FALSE; so that ISRHandler always returns SysIntr when my IRQ occures. Does anyone know how to do this?

    If this would still lead to the same error, I would at least know that it has nothing to do with the port reading.

    Best regards, Wolfgang Wallner

     

    Monday, August 16, 2010 9:16 AM
  • Hi,

    I just had another thought on how to verify if something goes wrong in giisr.dll or if the code even comes this far.

    If I remove the calls to LoadIntChainHandler and KernelLibIoControl, I guess my WinCE system can have no idea that it should call this ISR. The behaviour of the system however keeps the same (also same debug output).

    So activating an IRQ on my device that is not handled by an ISR results in an Access Violation inside pcibus.dll

    Would this be the expected behaviour of a system not handling an IRQ?

    regards, Wolfgang Wallner

    Monday, August 16, 2010 10:21 AM
  • Hello,

    Update: I disabled the the USB controller device that shared the same IRQ as my PCI device in the BIOS configuration. The behaviour has changed now. The device doesn't reset any more, it just ignores my IRQ.

    I can verify that my timer is running and the IRQ flag is pending as I can read the IO registers.

    The giisr.dll IRQ-Handler is configured with LoadIntChainHandler and KernelLibIoControl as described in my first post. Are their any further steps necessary the enable IRQ handling?

    Best regards, Wolfgang Wallner

    Monday, August 16, 2010 1:53 PM
  • Something (relatively) strange is the fact that your PCI INT is routed by the BIOS on IRQ6 which in standard XT architecture is used by the floppy disk controller. Anyway typically the BIOS knows what to do with its own HW so...
     
    Can you check if the PCI interrupt line and the IRQ6 line are really active? Typically the interrupt pending flag can be set even if IRQ generation is disabled
     
    --
    Luca Calligaris (MVP-Windows Embedded)
    lucaDOTcalligarisATeurotechDOTcom
    www.eurotech.com
     
     
    "Wolfgang Wallner" <=?utf-8?B?V29sZmdhbmcgV2FsbG5lcg==?=> ha scritto nel messaggio news:3441fcd2-755f-4e7f-92de-ebb766a8f23e...

    Hello,

    Update: I disabled the the USB controller device that shared the same IRQ as my PCI device in the BIOS configuration. The behaviour has changed now. The device doesn't reset any more, it just ignores my IRQ.

    I can verify that my timer is running and the IRQ flag is pending as I can read the IO registers.

    The giisr.dll IRQ-Handler is configured with LoadIntChainHandler and KernelLibIoControl as described in my first post. Are their any further steps necessary the enable IRQ handling?

    Best regards, Wolfgang Wallner


    Luca Calligaris (MVP-Windows Embedded) lucaDOTcalligarisATeurotechDOTcom www.eurotech.com
    Monday, August 16, 2010 3:01 PM
  • Hi,
    Something (relatively) strange is the fact that your PCI INT is routed by the BIOS on IRQ6 which in standard XT architecture is used by the floppy disk controller. Anyway typically the BIOS knows what to do with its own HW so...
    There is no floppy on my target system. In the BIOS, i can configure 4 IRQ lines, IRQ line 4 is the one with my PCI device. I have tried moving the IRQ number for IRQ line 4, and tried the numbers 6, 7, 12. Doesn't make any difference at all. As the USB device I mentionend always gets the same IRQ number as my PCI device, I simply disabled it. Now the system doesn't react any more on my timer IRQs.
    Can you check if the PCI interrupt line and the IRQ6 line are really active? Typically the interrupt pending flag can be set even if IRQ generation is disabled

    How to check that?

    regards, Wolfgang

    Monday, August 16, 2010 3:27 PM
  • If I understand correctly the BIOS setup allows you to configure the routing of PCI INT lines to IRQ and your PCI device and the USB host always share the same IRQ: have you got another free PCI slot to put your PCI device into? This, according to  the typical routing mechanism, should result in using two different IRQ lines (see for example PCI 2.2 sepcs ..
     
    You can check thh INT and IRQ lines with an oscilloscope: if, for some reason, the disabled USB host keep the INT line high (inactive) maybe your device cannot assert it
     

    --
    Luca Calligaris (MVP-Windows Embedded)
    lucaDOTcalligarisATeurotechDOTcom
    www.eurotech.com
     
     
    "Wolfgang Wallner" <=?utf-8?B?V29sZmdhbmcgV2FsbG5lcg==?=> ha scritto nel messaggio news:9974ff46-b2b0-4f2d-8fff-b226b9551575...
    Hi,
    Something (relatively) strange is the fact that your PCI INT is routed by the BIOS on IRQ6 which in standard XT architecture is used by the floppy disk controller. Anyway typically the BIOS knows what to do with its own HW so...
    There is no floppy on my target system. In the BIOS, i can configure 4 IRQ lines, IRQ line 4 is the one with my PCI device. I have tried moving the IRQ number for IRQ line 4, and tried the numbers 6, 7, 12. Doesn't make any difference at all. As the USB device I mentionend always gets the same IRQ number as my PCI device, I simply disabled it. Now the system doesn't react any more on my timer IRQs.
    Can you check if the PCI interrupt line and the IRQ6 line are really active? Typically the interrupt pending flag can be set even if IRQ generation is disabled

    How to check that?

    regards, Wolfgang


    Luca Calligaris (MVP-Windows Embedded) lucaDOTcalligarisATeurotechDOTcom www.eurotech.com
    Tuesday, August 17, 2010 5:49 AM
  • Hi,

    If I understand correctly the BIOS setup allows you to configure the routing of PCI INT lines to IRQ and your PCI device and the USB host always share the same IRQ: 
    Yes, correct.
    have you got another free PCI slot to put your PCI device into? This, according to  the typical routing mechanism, should result in using two different IRQ lines (see for example PCI 2.2 sepcs ..
    No, the device has only one PCI slot. However, I talked to a colleague about changing the IRQ pin used (currently function 0 of the device uses pin C). Changing the pin should result in another IRQ number (at least I hope so :) ).
    You can check thh INT and IRQ lines with an oscilloscope: if, for some reason, the disabled USB host keep the INT line high (inactive) maybe your device cannot assert it

    Ok, this will be one of my next steps.

    Thanks for you help so far,

    Best regards, Wolfgang Wallner

     

    Tuesday, August 17, 2010 7:37 AM
  • Hello community,

    We have swapped the IRQ pins of the device, now PCI function 0 uses Pin A and function 1 uses Pin C.
    Function 1 is unused, function 0 is the one I write the driver for. Now function 0 gets its own IRQ pin and everything works fine.
    The software is unchanged, so the problem was really hardware specific. Now I can see in the debugger that my IST catches its event every 5 seconds.
    Why an IRQ on pin C with our current configuration can cause a system restart will be subject to further investigations by my colleagues.

    Thanks a lot for your help,

    Best regards, Wolfgang Wallner

    Tuesday, August 17, 2010 9:00 AM