This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MDIO USERACCESS1 Interrupt on the C6670 seems to trigger twice per transaction.

I am currently attempting to write my own driver software for the MDIO module on the C6670. I am using the MDIO module to perform external register reads/writes on a PHY device using the USERACCESS1 register. Additionally, I have enabled interrupts to trigger whenever a transaction has completed through the USER_ACCESS_REG. The problem I am seeing is my ISR() function runs twice every time I send data out of the MDIO port using the USERACCESS1 register. I have confirmed this with a global debug counter.

My ISR()
extern "C"{
void MdioTransferIsr(void)
{
    InterruptCounter++;

    CSL_MDIO_clearMaskedUserCmdCompleteInt(1);
    CSL_MDIO_clearUnmaskedUserCmdCompleteInt(1);
}}

My routing of the interrupt is done with the following lines:
CpIntc_dispatchPlug(CSL_INTC0_MDIO_USER_INTR1, (CpIntc_FuncPtr)MdioTransferIsr, (UArg)0, TRUE);
CpIntc_mapSysIntToHostInt(0, CSL_INTC0_MDIO_USER_INTR1, 10);

// Enable the Host Interrupts. All MDIO Interrupts are on CIC0.
CpIntc_enableHostInt(0, 10);

// Enable the System Interrupt.
CpIntc_enableSysInt(0, CSL_INTC0_MDIO_USER_INTR1);

// Get the event id associated with the host interrupt and Plug the CPINTC Dispatcher.
n32EventId = CpIntc_getEventId(10);
EventCombiner_dispatchPlug(n32EventId, (EventCombiner_FuncPtr)CpIntc_dispatch, 10, TRUE);

Then, sometime later, a send is performed.
CSL_MDIO_USERACCESS oMdioUserAccess;

// Fill in oMdioUserAccess.
// ...

// Perform the read.
hMdioRegs->USER_GROUP[1].USER_ACCESS_REG = CSL_FMK (MDIO_USER_ACCESS_REG_DATA, oMdioUserAccess.data) |
                                        CSL_FMK (MDIO_USER_ACCESS_REG_PHYADR, oMdioUserAccess.phyAddr) |
                                        CSL_FMK (MDIO_USER_ACCESS_REG_REGADR, oMdioUserAccess.regAddr) |
                                        CSL_FMK (MDIO_USER_ACCESS_REG_WRITE, 0) |
                                        CSL_FMK (MDIO_USER_ACCESS_REG_GO, oMdioUserAccess.go);

As a side note, the CSL_MDIO_setUserAccessRegister() function seems to only support writing to registers, so a workaround to the CSL was required here.

  • Has anyone had a chance to look into this?

    I have a workaround (use CSL_MDIO_isMaskedUserCmdCompleteIntSet() inside the ISR to see if interrupt is real) at the moment, but am hoping to get this software configured correctly:

    void MdioTransferIsr(void)
    {
        CSL_MDIO_USERACCESS oReg;

        CSL_MDIO_getUserAccessRegister(1, &oReg);

        // Only post to the mailbox if legitimate interrupt went off.
        // TODO: Fix this.
        if(CSL_MDIO_isMaskedUserCmdCompleteIntSet(1))
        {
            Mailbox_post(mbx_mdio_rcv, &oReg, 0);
        }

        // Clear the interrupts.
        CSL_MDIO_clearMaskedUserCmdCompleteInt(1);
        CSL_MDIO_clearUnmaskedUserCmdCompleteInt(1);
    }

  • Hi Lance,

    I'll be looking into this. One question though, are you turning on the MDIO state machine for link monitoring?

    Regards,

    Javier

  • Javier,

    Yes, I have got the state machine running for link monitoring. However, I am not enabling or routing the link status interrupts.

    I have gotten questionable results from polling the LINK register in the MDIO module, but was going to save that issue for a separate future forum post (problem is very similar to this post: http://e2e.ti.com/support/dsp/c6000_multi-core_dsps/f/639/t/167106.aspx).

  • Additionally, I have included a test project that clearly illustrates the issue. The project will basically read the control register (Register 0) of the PHY device 50 times and print the data value to the console window. After the test completes, the state of the counter that is incremented in the ISR will also be printed.

    By running the attached executable on the C6670 EVM will produce the following output:
    [C66xx_0] enter main()
    [C66xx_0] Starting MDIO test task.
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: ffff, ACK 0
    [C66xx_0] Received Message: 1141, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 2281, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Received Message: 1140, ACK 1
    [C66xx_0] Completed MDIO test task. Received 100 Interrupts for 50 transfers.

    Note, there are actually two problems:
    1) The ISR seems to trigger twice per MDIO transaction, as noted before.
    2) Occasionally, a bad value is read from the control register (some reserved bits set). I would expect this value to remain unchanged, as it is never written to. When this error occurs, sometimes the ACK bit in the USERACCESS1 register is set and sometimes it is not.

    6574.MdioTestProject.zip

  • Hi Javier,

    Have you had a chance to look at the example project provided on the previous post? A couple additional comments: I am using v2.1.1.4 of the MCSDK and v6.33.6.50 of SYS/BIOS. The procedure I used for routing the MDIO interrupts from the Chip Interrupt Controller through the Event Combiner has worked for me in the past when working on a different interface. And that procedure was partially documented in: http://processors.wiki.ti.com/index.php/Configuring_Interrupts_on_Keystone_Devices.

  • Hi Lance

    I've imported your project and looked through your code. From an interrupt perspective you seem to have setup things correctly using the BIOS APIs. You are also clearing the interrupt at the end of the ISR, which looks right. The next step would be to check whether the interrupt is in fact getting cleared. I will look into this on Friday and get back to you. In the meantime, I'd suggest looking into this; the GEL file on the wiki you mentioned could be useful here.

  • Thanks Uday,

    I think the interrupt gets cleared, since I never miss an interrupt. I am just not certain if any action needs to be taken by me to clear the interrupt anywhere else throughout the chain of chip interrupt controller, event combiner, or hardware interrupt.

  • Lance,

    Just wanted to let you know that I've been looking at this today but haven't reached a solution yet. I will try and get back to you again by the end of this week.

  • Hi Lance

    We've been working through your code and here's what we've observed so far.

    • The flow in your code relates accurately to the instructions for ‘reading data from a PHY register’ given in EMAC/MDIO user guide section 2.7.2.3
    • For completion of each read operation, interrupt bits are correctly set in both the USERINTRAW and the USERINTMASKSET register
    • We’ve verified that bits set in USERINTRAW and USERINTMASKSET registers only trigger one ISR, i.e. there is one ISR trigger per read transaction based on these register bits being set
    • Since we are observing TWO ISR runs per read transaction, we now know that the second ISR run is NOT related to USERINTRAW or USERINTMASKSET. 
    • We tried to eliminate the use of the Event Combiner and use the HWI APIs instead to map directly from host interrupt to interrupt vector on the core. However, the two ISRs per transaction behavior is observed with/without use of Event Combiner.
    • We're in the process of figuring out what is causing the second ISR (per read transaction) to be triggered. Btw, we're also seen similar behavior with a write transaction.
    • To ensure that the second interrupt is not being triggered from within the ISR, we:
      • disabled/restored interrupts when entering/exiting ISR
      • polled on clearing of interrupt bits in USERINTRAW and USERINTMASKSET before exiting ISR
    • In addition to the code verification we had done to ensure correct channel mapping, this time we used a GEL script to verify that channel mapping is correct, i.e. CSL_INTC0_MDIO_USER_INTR1 system event is mapped to CICO_OUT is mapped to event combiner (EVT2) and finally to interrupt vector 9 on the core. We do not see any other events being tied to the event combiner or to the interrupt vector. 
    • We're in the process of trying to figure out what in addition to the USERINTRAW or USERINTMASKSET registers could set the MDIO_USER_INT1 system interrupt. We'll get back to you as soon as we have more information on this.

     

  • Lance,

    I've tried all I can think of from a software perspective. Javier has been looking at this from a hardware perspective to ensure that there is no MDIO link interrupt instability. I'll let him comment on his observations.

  • Hi Lance,

    Could you please test the following on your EVM and let us know if it solves the issue of two interrupts per read at your end:

    Modify the code in your ISR so that the clearing of the system interrupt is added after the clearing of the MDIO user command complete interrupts. When we were testing this earlier, we had the system interrupt clearing code before the clearing of MDIO user command complete interrupts, and we continued to observe twice the number of interrupts. However, when we follow the order as below we see a single interrupt for every read. The order seems to matter. Let us know what you observe at your end:

    void MdioTransferIsr(void)

    {
    . . . . 
    . . . .

    CSL_MDIO_clearUnmaskedUserCmdCompleteInt(1);
    CSL_MDIO_clearMaskedUserCmdCompleteInt(1);
    CpIntc_clearSysInt(0, CSL_INTC0_MDIO_USER_INTR1);

    }

    Thanks