Thanks a lot! On Sat, Feb 27, 2016 at 8:28 PM, Ben Gras <b...@shrike-systems.com> wrote: > All, > > I tested this on current HEAD and verified it fixes a case I'd ran > into trouble with before, namely gpio-triggered irqs. Great to see. I > pushed your change with a commit message based on your original email, > Martin. I hope you like it. > > Thank you! > > > On Sat, Feb 27, 2016 at 10:16 PM, Ben Gras <b...@shrike-systems.com> wrote: >> I'm doing a rebase & build right now, thanks for the reminder. >> >> On Fri, Feb 26, 2016 at 10:32 PM, Martin Galvan >> <martin.gal...@tallertechnologies.com> wrote: >>> Hi Ben! Sorry to bother, were you able to test my changes to the BBB >>> interrupt handler? >>> >>> On Fri, Feb 12, 2016 at 11:09 AM, Martin Galvan >>> <martin.gal...@tallertechnologies.com> wrote: >>>> Thanks Ben! Indeed, any further testing is more than welcome :) >>>> >>>> On Thu, Feb 11, 2016 at 7:55 PM, Ben Gras <b...@shrike-systems.com> wrote: >>>>> This looks like great work. Please let me test it (I'll try the GPIO >>>>> interrupt trigger) & I'll merge it as soon as I have time. >>>>> >>>>> Thank you! >>>>> >>>>> Cheers, >>>>> Ben >>>>> >>>>> >>>>> On Thu, Feb 11, 2016 at 3:27 PM, Martin Galvan >>>>> <martin.gal...@tallertechnologies.com> wrote: >>>>>> This patch makes the following changes to the Beaglebone IRQ handling >>>>>> code: >>>>>> >>>>>> - Disable support for nested interrupts. >>>>>> - Detect spurious IRQs using the SPURIOUSIRQ field of the INTC_SIR_IRQ >>>>>> register. >>>>>> - Acknowledge spurious IRQs by setting the NewIRQAgr bit of the >>>>>> INTC_CONTROL >>>>>> register. This cleans the SPURIOUSIRQ field and allows new interrupts >>>>>> to be generated. >>>>>> - Improve the get_mir_reg function a bit. >>>>>> >>>>>> The Beaglebone bsp_interrupt_dispach function has been troublesome for a >>>>>> while now. >>>>>> We've seen it break the GPIO API >>>>>> (https://lists.rtems.org/pipermail/devel/2015-November/012995.html), >>>>>> the RTEMS interrupt server >>>>>> (https://lists.rtems.org/pipermail/devel/2015-July/011865.html), >>>>>> and now we've been getting spurious interrupts when trying to use the >>>>>> I2C module. >>>>>> >>>>>> We've done a lot of testing and concluded that the cause of most of >>>>>> these issues >>>>>> is the way nested interrupts are being handled. The AM335X manual states >>>>>> that >>>>>> the interrupt handling sequence should be as follows: >>>>>> >>>>>> 1. Identify the IRQ source by reading the ActiveIRQ field of the >>>>>> INTC_SIR_IRQ >>>>>> register. >>>>>> 2. Jump to the corresponding IRQ handler, which should serve the IRQ and >>>>>> deassert the interrupt condition at the peripheral side. >>>>>> 3. Enable the processing of new IRQs at the Interrupt Controller side by >>>>>> setting >>>>>> the NewIRQAgr bit of the INTC_CONTROL register. >>>>>> 4. Finally, enable IRQs at the CPU side. This is done later in >>>>>> _ARMV4_Exception_interrupt. >>>>>> >>>>>> Right now the Beaglebone bsp_interrupt_dispach enables IRQs at the INTC >>>>>> and CPU >>>>>> before jumping to the interrupt handler to allow for nested IRQs. >>>>>> Before doing so, it calls bsp_interrupt_disable to mask the IRQ source >>>>>> and avoid >>>>>> having it constantly fire new IRQs. After it's done it re-enables the IRQ >>>>>> by calling bsp_interrupt_enable. These calls break the GPIO API and the >>>>>> RTEMS interrupt server machinery, and we suspect it's also causing the >>>>>> spurious >>>>>> interrupts we saw with the I2C module. >>>>>> >>>>>> The correct way to enable interrupt nesting according to both the manual >>>>>> and >>>>>> the AM335X StarterWare code is to allow only interrupts of a higher >>>>>> priority >>>>>> to preempt the current one. This can be achieved by setting the >>>>>> INTC_THRESHOLD >>>>>> register to the priority of the current IRQ. However, in our case this >>>>>> isn't >>>>>> necessary since all the interrupt priorities are set to 0 (the highest >>>>>> possible) >>>>>> in bsp_interrupt_facility_initialize. We may implement this in a future >>>>>> patch, >>>>>> if required. >>>>>> >>>>>> We've tested this quite extensively on a number of different >>>>>> applications, and >>>>>> it's working fine. >>>>>> >>>>>> Closes #2580. >>>>>> --- >>>>>> c/src/lib/libbsp/arm/beagle/irq.c | 82 >>>>>> +++++++++++++++-------------- >>>>>> c/src/lib/libcpu/arm/shared/include/omap3.h | 3 +- >>>>>> 2 files changed, 44 insertions(+), 41 deletions(-) >>>>>> >>>>>> diff --git a/c/src/lib/libbsp/arm/beagle/irq.c >>>>>> b/c/src/lib/libbsp/arm/beagle/irq.c >>>>>> index c6485cd..d080a5e 100644 >>>>>> --- a/c/src/lib/libbsp/arm/beagle/irq.c >>>>>> +++ b/c/src/lib/libbsp/arm/beagle/irq.c >>>>>> @@ -18,6 +18,7 @@ >>>>>> #include <bsp.h> >>>>>> #include <bsp/irq-generic.h> >>>>>> #include <bsp/linker-symbols.h> >>>>>> +#include <bsp/fatal.h> >>>>>> >>>>>> #include <rtems/score/armv4.h> >>>>>> >>>>>> @@ -43,77 +44,78 @@ static struct omap_intr omap_intr = { >>>>>> }; >>>>>> #endif >>>>>> >>>>>> -static int irqs_enabled[BSP_INTERRUPT_VECTOR_MAX+1]; >>>>>> +/* Enables interrupts at the Interrupt Controller side. */ >>>>>> +static inline void omap_irq_ack(void) >>>>>> +{ >>>>>> + mmio_write(omap_intr.base + OMAP3_INTCPS_CONTROL, >>>>>> OMAP3_INTR_NEWIRQAGR); >>>>>> >>>>>> -volatile static int level = 0; >>>>>> + /* Flush data cache to make sure all the previous writes are done >>>>>> + before re-enabling interrupts. */ >>>>>> + flush_data_cache(); >>>>>> +} >>>>>> >>>>>> void bsp_interrupt_dispatch(void) >>>>>> { >>>>>> - /* get irq */ >>>>>> - uint32_t reg = mmio_read(omap_intr.base + OMAP3_INTCPS_SIR_IRQ); >>>>>> - int irq; >>>>>> - irq = reg & OMAP3_INTR_ACTIVEIRQ_MASK; >>>>>> + const uint32_t reg = mmio_read(omap_intr.base + OMAP3_INTCPS_SIR_IRQ); >>>>>> >>>>>> - if(!irqs_enabled[irq]) { >>>>>> - /* Ignore spurious interrupt */ >>>>>> - } else { >>>>>> - bsp_interrupt_vector_disable(irq); >>>>>> - >>>>>> - /* enable new interrupts, and flush data cache to make sure >>>>>> - * it hits the intc >>>>>> - */ >>>>>> - mmio_write(omap_intr.base + OMAP3_INTCPS_CONTROL, >>>>>> OMAP3_INTR_NEWIRQAGR); >>>>>> - flush_data_cache(); >>>>>> - mmio_read(omap_intr.base + OMAP3_INTCPS_SIR_IRQ); >>>>>> - flush_data_cache(); >>>>>> - >>>>>> - /* keep current irq masked but enable unmasked ones */ >>>>>> - uint32_t psr = _ARMV4_Status_irq_enable(); >>>>>> - bsp_interrupt_handler_dispatch(irq); >>>>>> - >>>>>> - _ARMV4_Status_restore(psr); >>>>>> + if ((reg & OMAP3_INTR_SPURIOUSIRQ_MASK) != >>>>>> OMAP3_INTR_SPURIOUSIRQ_MASK) { >>>>>> + const rtems_vector_number irq = reg & OMAP3_INTR_ACTIVEIRQ_MASK; >>>>>> >>>>>> - bsp_interrupt_vector_enable(irq); >>>>>> + bsp_interrupt_handler_dispatch(irq); >>>>>> + } else { >>>>>> + /* Ignore spurious interrupts. We'll still ACK it so new interrupts >>>>>> + can be generated. */ >>>>>> } >>>>>> + >>>>>> + omap_irq_ack(); >>>>>> } >>>>>> >>>>>> -static uint32_t get_mir_reg(int vector, uint32_t *mask) >>>>>> +/* There are 4 32-bit interrupt mask registers for a total of 128 >>>>>> interrupts. >>>>>> + The IRQ number tells us which register to use. */ >>>>>> +static uint32_t omap_get_mir_reg(rtems_vector_number vector, uint32_t >>>>>> *const mask) >>>>>> { >>>>>> - *mask = 1UL << (vector % 32); >>>>>> - >>>>>> - if(vector < 0) while(1) ; >>>>>> - if(vector < 32) return OMAP3_INTCPS_MIR0; >>>>>> - if(vector < 64) return OMAP3_INTCPS_MIR1; >>>>>> - if(vector < 96) return OMAP3_INTCPS_MIR2; >>>>>> - if(vector < 128) return OMAP3_INTCPS_MIR3; >>>>>> - while(1) ; >>>>>> + uint32_t mir_reg; >>>>>> + >>>>>> + /* Select which bit to set/clear in the MIR register. */ >>>>>> + *mask = 1ul << (vector % 32u); >>>>>> + >>>>>> + if (vector < 32u) { >>>>>> + mir_reg = OMAP3_INTCPS_MIR0; >>>>>> + } else if (vector < 64u) { >>>>>> + mir_reg = OMAP3_INTCPS_MIR1; >>>>>> + } else if (vector < 96u) { >>>>>> + mir_reg = OMAP3_INTCPS_MIR2; >>>>>> + } else if (vector < 128u) { >>>>>> + mir_reg = OMAP3_INTCPS_MIR3; >>>>>> + } else { >>>>>> + /* Invalid IRQ number. This should never happen. */ >>>>>> + bsp_fatal(0); >>>>>> + } >>>>>> + >>>>>> + return mir_reg; >>>>>> } >>>>>> >>>>>> rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number >>>>>> vector) >>>>>> { >>>>>> uint32_t mask, cur; >>>>>> - uint32_t mir_reg = get_mir_reg(vector, &mask); >>>>>> + uint32_t mir_reg = omap_get_mir_reg(vector, &mask); >>>>>> >>>>>> cur = mmio_read(omap_intr.base + mir_reg); >>>>>> mmio_write(omap_intr.base + mir_reg, cur & ~mask); >>>>>> flush_data_cache(); >>>>>> >>>>>> - irqs_enabled[vector] = 1; >>>>>> - >>>>>> return RTEMS_SUCCESSFUL; >>>>>> } >>>>>> >>>>>> rtems_status_code bsp_interrupt_vector_disable(rtems_vector_number >>>>>> vector) >>>>>> { >>>>>> uint32_t mask, cur; >>>>>> - uint32_t mir_reg = get_mir_reg(vector, &mask); >>>>>> + uint32_t mir_reg = omap_get_mir_reg(vector, &mask); >>>>>> >>>>>> cur = mmio_read(omap_intr.base + mir_reg); >>>>>> mmio_write(omap_intr.base + mir_reg, cur | mask); >>>>>> flush_data_cache(); >>>>>> >>>>>> - irqs_enabled[vector] = 0; >>>>>> - >>>>>> return RTEMS_SUCCESSFUL; >>>>>> } >>>>>> >>>>>> diff --git a/c/src/lib/libcpu/arm/shared/include/omap3.h >>>>>> b/c/src/lib/libcpu/arm/shared/include/omap3.h >>>>>> index f28e5e5..0cc43d6 100644 >>>>>> --- a/c/src/lib/libcpu/arm/shared/include/omap3.h >>>>>> +++ b/c/src/lib/libcpu/arm/shared/include/omap3.h >>>>>> @@ -72,7 +72,8 @@ >>>>>> #define OMAP3_INTR_ILR(base,m) \ >>>>>> (base + OMAP3_INTCPS_ILR0 + 0x4 * (m)) >>>>>> >>>>>> -#define OMAP3_INTR_ACTIVEIRQ_MASK 0x7f /* Active IRQ mask for SIR_IRQ */ >>>>>> +#define OMAP3_INTR_SPURIOUSIRQ_MASK (0x1FFFFFF << 7) /* Spurious IRQ >>>>>> mask for SIR_IRQ */ >>>>>> +#define OMAP3_INTR_ACTIVEIRQ_MASK 0x7F /* Active IRQ mask for SIR_IRQ */ >>>>>> #define OMAP3_INTR_NEWIRQAGR 0x1 /* New IRQ Generation */ >>>>>> >>>>>> #define OMAP3_DM337X_NR_IRQ_VECTORS 96 >>>>>> -- >>>>>> 2.7.1 >>>>>> >>>> >>>> >>>> >>>> -- >>>> >>>> >>>> Martin Galvan >>>> >>>> Software Engineer >>>> >>>> Taller Technologies Argentina >>>> >>>> >>>> San Lorenzo 47, 3rd Floor, Office 5 >>>> >>>> Córdoba, Argentina >>>> >>>> Phone: 54 351 4217888 / +54 351 4218211 >>> >>> >>> >>> -- >>> >>> >>> Martin Galvan >>> >>> Software Engineer >>> >>> Taller Technologies Argentina >>> >>> >>> San Lorenzo 47, 3rd Floor, Office 5 >>> >>> Córdoba, Argentina >>> >>> Phone: 54 351 4217888 / +54 351 4218211
-- Martin Galvan Software Engineer Taller Technologies Argentina San Lorenzo 47, 3rd Floor, Office 5 Córdoba, Argentina Phone: 54 351 4217888 / +54 351 4218211 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel