AnsweredAssumed Answered

SGI interferes with EPIT

Question asked by Mike Jones on Oct 28, 2013
Latest reply on Nov 3, 2013 by Mike Jones

I am having a problem with interrupts on an iMX6Q. EPIT interrupts seem to work until a SGI interrupt is sent. The SGI is handled, then EPIT interrupts stop.

 

The basic scenario is:

 

- Setup EPIT for CPU 0.

- Interrupts for EPIT are handled on CPU 0 only without any problems

- CPU 1 sends SGI to CPU 0, and EPIT interrupts stop

 

Here are the details from code using the SDK.

 

I have setup the EPIT from CPU 0 with the following:

 

void hal_clock_initialize(cyg_uint32 period)

{

    hal_epit_counter_enable(2, period, IRQ_MODE);

    _period = period;

}

 

The IRQ number is fetched with this code on CPU 0 when interrupt 89 occurs:

 

int get_IRQ(void)

{

    cyg_uint32 vector_num;

    cyg_uint32 cpu_num;

    cyg_uint32 irq_num;

 

    vector_num = gic_read_irq_ack();

 

    if (vector_num & 0x0200)

    {

        // Spurious interrupt.

        hal_gic_write_end_of_irq(vector_num);

        irq_num = INTERRUPT_NONE;

    }

    else

    {

        cpu_num = (vector_num >> 10) & 0x7;

        irq_num = vector_num & 0x1FF;

       

        if (irq_num < ISR_MIN || irq_num > ISR_MAX)

            irq_num = INTERRUPT_NONE;

 

    }

  return irq_num;

}

 

The interrupt is acknowledged on CPU 0 with the following code, which enables the next interrupt:

 

void hal_interrupt_acknowledge(int vector)

{

    cyg_uint32 irq_num;

    cyg_uint32 cpu_num;

 

    cpu_num = (vector >> 10) & 0x7;

    irq_num = vector & 0x1FF;

 

    if (irq_num != CYGNUM_HAL_INTERRUPT_NONE)

        gic_write_end_of_irq(irq_num);

}

 

On CPU 1, the following code issues the SGI to CPU 0:

 

        hal_gic_send_sgi(SMP_CPU_INTERRUPT_VECTOR(cpu), 1 << cpu, kGicSgiFilter_UseTargetList);

 

On CPU 1 the ISR is handled by calling get_IRQ then calling this:

 

__externC WORD32 cpu_message_isr( WORD32 vector, ADDRWORD data )

{

    SMP_CPU_TYPE me = SMP_CPU_THIS();

    WORD32 ret = 2;

    gic_enable_irq(vector, false);

    interrupt_acknowledge(vector);

    SPINLOCK_SPIN( m->lock );

 

Do Stuff

 

    SPINLOCK_CLEAR( m->lock );

    gic_enable_irq(vector, true);

    return ret; // Indicates to call DSR

}

 

This then calls a DSR:

 

__externC CYG_WORD32 cpu_message_dsr( CYG_WORD32 vector, CYG_ADDRWORD data )

{

    SMP_CPU_TYPE me = SMP_CPU_THIS();

    struct smp_msg_t *m = &smp_msg[me];

    CYG_WORD32 reschedule;

   

    gic_enable_irq(vector, false);

    SPINLOCK_SPIN( m->lock );

   

Do Stuff

 

    SPINLOCK_CLEAR( m->lock );

    gic_enable_irq(vector, true);

       

Do Stuff

}


The ISR and DSR do get called, and and once called, the EPIT interrupts no longer generate an interrupt on CPU 0. By breaking with the debugger, I can see the CPSR is in SVC mode and FIQ and IRQ are not masked on CPU 0. The EPIT is setup with priority 1. The SGI is setup with priority 0. Changing SGI priority to 2 makes no difference. SGIs from CPU 0 to CPU 1 happen more than once. SGIs from CPU 1 to CPU 0 stop EPIT interrupts.

 

From my logging I can see EPIT generate multiple interrupts, then right after the SGI from CPU 1 to CPU 0 is handled, all EPIT interrupts stop.

 

My understanding is that once the SGI is handled, it should no longer block any other interrupts. Perhaps there is some subtle issue with ordering, but I used the disable, ack, enable ordering in my UART driver and EPIT without any problems.

 

Any ideas what might stop the EPIT interrupts?

Any ideas on how to debug the problem?

Outcomes