Hardware Interrupt controller with ARM

Hi!

I have ARM920T CPU (Atmel’s AT91RM9200) and I can’t understand how to use
internal vectored interrupt controller in my processor. AFAIK QNX use only
Interrupt exception to dispatch interrupts in ARM, but there’s other
archetictures (x86, MIPS) where present interrupt controller and QNX uses
that hardware.

Maybe I need to fill intrinfo structure in startup with some kind of
information, as described in ‘Building Embedded Systems’ guide, but
there’s no info about interrupt controllers with ARM, just “… all ARM
interrupts are handled via the IRQ exception”.

Any thoughts?

Artyom Migaev <migaev@telecard.com.ua> wrote:

Hi!

I have ARM920T CPU (Atmel’s AT91RM9200) and I can’t understand how to use
internal vectored interrupt controller in my processor. AFAIK QNX use only
Interrupt exception to dispatch interrupts in ARM, but there’s other
archetictures (x86, MIPS) where present interrupt controller and QNX uses
that hardware.

Maybe I need to fill intrinfo structure in startup with some kind of
information, as described in ‘Building Embedded Systems’ guide, but
there’s no info about interrupt controllers with ARM, just “… all ARM
interrupts are handled via the IRQ exception”.

Any thoughts?

Hi Artyom,

It’s a fairly indepth topic, but basically, you will need to write
interrupt callouts for the interrupt controller on the Atmel processor,
and describe the callouts in the init_intrinfo.c routine of your board’s
startup code. ARM interrupt controllers are dealt with in the same way
as on other CPUs that QNX supports; the note in the ‘Building Embedded
Systems’ docs that you mention, which refers to ARM interrupts being
handled via the IRQ exception, really means, “…handled via the IRQ
exception, as opposed to the FIQ exception, which we don’t deal with.”
So, basically, you need to configure the Atmel interrupt controller
to route all interrupts to its IRQ output, not its FIQ output.

It’s a good idea to examine interrupt callouts and the associated
init_intrinfo() routines for other ARM CPUs, which can be found in
the startup library code, and the board level startup directories,
respectively.

\

David Green (dgreen@qnx.com)
QNX Software Systems Ltd.
http://www.qnx.com

Dave Green wrote:

Artyom Migaev <> migaev@telecard.com.ua> > wrote:
Hi!

I have ARM920T CPU (Atmel’s AT91RM9200) and I can’t understand how to use
internal vectored interrupt controller in my processor. AFAIK QNX use only
Interrupt exception to dispatch interrupts in ARM, but there’s other
archetictures (x86, MIPS) where present interrupt controller and QNX uses
that hardware.

Maybe I need to fill intrinfo structure in startup with some kind of
information, as described in ‘Building Embedded Systems’ guide, but
there’s no info about interrupt controllers with ARM, just “… all ARM
interrupts are handled via the IRQ exception”.

Any thoughts?

Hi Artyom,

It’s a fairly indepth topic, but basically, you will need to write
interrupt callouts for the interrupt controller on the Atmel processor,
and describe the callouts in the init_intrinfo.c routine of your board’s
startup code. ARM interrupt controllers are dealt with in the same way
as on other CPUs that QNX supports; the note in the ‘Building Embedded
Systems’ docs that you mention, which refers to ARM interrupts being
handled via the IRQ exception, really means, “…handled via the IRQ
exception, as opposed to the FIQ exception, which we don’t deal with.”
So, basically, you need to configure the Atmel interrupt controller
to route all interrupts to its IRQ output, not its FIQ output.

It’s a good idea to examine interrupt callouts and the associated
init_intrinfo() routines for other ARM CPUs, which can be found in
the startup library code, and the board level startup directories,
respectively.


David Green (> dgreen@qnx.com> )
QNX Software Systems Ltd.
http://www.qnx.com

Hello David,

before opening this post, I’ve examined the code at BSP6.2.1, but there is
no vectored interrupt controller example. I mean, when the IRQ exception
occures, QNX cathces it, and performes some tasks (interrupt
identification, dispatching, context switch, etc). But can I force QNX to
“interrupt” without IRQ exception, using intrinfo structure, or other
methods? I mean in QNX by default we have (hypothetically):

ARM IRQ exception vector @ 0x00000018

ldr pc, [pc,#QNX_INTERRUPT_DISPATCHER]

and I want to make it by this way:

ARM IRQ exception vector @ 0x00000018

ldr pc, [pc,#SOME_REGISTER_WITH_VECTOR]

so the value “SOME_REGISTER_WITH_VECTOR” generated by hardware. To ensure
that interrupts that I use in OS are correctly serviced I’ll program
corresponding vectors to “QNX_INTERRUPT_DISPATCHER” in init_intrinfo()
function.

Maybe you’re a little bit confused - “is there a real need to process some
interrupts outside the OS?” Yes, there is. Of course, if it’s not
impossible to handle IRQ’s in such way - I’ll do it thru OS, but it will
take more time.

And another question - how QNX handles other ARM exceptions (undefined
instruction, data abort, address abort), if they occure? I found only this
code in startup library (init_cpuinfo.c) to setup’em:

/*

  • Set up the trap entry point to be “ldr pc, [pc, #0x18]”
  • These jump slot addresses are all zero, so until these have
  • been properly set up, any exception will result in a loop.
    */
    for (i = 0; i < 8; i++) {
    *((unsigned *)pa + i) = 0xe59ff018;
    }

Thank you very much for your help.

Artyom,

PowerPC BookE processors use a similar vectored interrupt controller
method, and we have added support for these processors under QNX 6.3.0.
However, this involved a new kernel variant, as well as changes to the
startup library.

I think that using the vectored interrupt capability of the Atmel
processor is possible, but it would likely require a custom kernel.

As for your question about how QNX handles other ARM exceptions;
this would be better addressed by the ARM kernel developer, but
in the ARM kernel, there is a succession of fault handlers in place
to attempt to deal with data aborts, prefetch aborts, and undefined
instructions.


Artyom Migaev <migaev@telecard.com.ua> wrote:

Dave Green wrote:

Artyom Migaev <> migaev@telecard.com.ua> > wrote:
Hi!

I have ARM920T CPU (Atmel’s AT91RM9200) and I can’t understand how to use
internal vectored interrupt controller in my processor. AFAIK QNX use only
Interrupt exception to dispatch interrupts in ARM, but there’s other
archetictures (x86, MIPS) where present interrupt controller and QNX uses
that hardware.

Maybe I need to fill intrinfo structure in startup with some kind of
information, as described in ‘Building Embedded Systems’ guide, but
there’s no info about interrupt controllers with ARM, just “… all ARM
interrupts are handled via the IRQ exception”.

Any thoughts?

Hi Artyom,

It’s a fairly indepth topic, but basically, you will need to write
interrupt callouts for the interrupt controller on the Atmel processor,
and describe the callouts in the init_intrinfo.c routine of your board’s
startup code. ARM interrupt controllers are dealt with in the same way
as on other CPUs that QNX supports; the note in the ‘Building Embedded
Systems’ docs that you mention, which refers to ARM interrupts being
handled via the IRQ exception, really means, “…handled via the IRQ
exception, as opposed to the FIQ exception, which we don’t deal with.”
So, basically, you need to configure the Atmel interrupt controller
to route all interrupts to its IRQ output, not its FIQ output.

It’s a good idea to examine interrupt callouts and the associated
init_intrinfo() routines for other ARM CPUs, which can be found in
the startup library code, and the board level startup directories,
respectively.


David Green (> dgreen@qnx.com> )
QNX Software Systems Ltd.
http://www.qnx.com



Hello David,

before opening this post, I’ve examined the code at BSP6.2.1, but there is
no vectored interrupt controller example. I mean, when the IRQ exception
occures, QNX cathces it, and performes some tasks (interrupt
identification, dispatching, context switch, etc). But can I force QNX to
“interrupt” without IRQ exception, using intrinfo structure, or other
methods? I mean in QNX by default we have (hypothetically):

ARM IRQ exception vector @ 0x00000018

ldr pc, [pc,#QNX_INTERRUPT_DISPATCHER]

and I want to make it by this way:

ARM IRQ exception vector @ 0x00000018

ldr pc, [pc,#SOME_REGISTER_WITH_VECTOR]

so the value “SOME_REGISTER_WITH_VECTOR” generated by hardware. To ensure
that interrupts that I use in OS are correctly serviced I’ll program
corresponding vectors to “QNX_INTERRUPT_DISPATCHER” in init_intrinfo()
function.

Maybe you’re a little bit confused - “is there a real need to process some
interrupts outside the OS?” Yes, there is. Of course, if it’s not
impossible to handle IRQ’s in such way - I’ll do it thru OS, but it will
take more time.

And another question - how QNX handles other ARM exceptions (undefined
instruction, data abort, address abort), if they occure? I found only this
code in startup library (init_cpuinfo.c) to setup’em:

/*

  • Set up the trap entry point to be “ldr pc, [pc, #0x18]”
  • These jump slot addresses are all zero, so until these have
  • been properly set up, any exception will result in a loop.
    */
    for (i = 0; i < 8; i++) {
    *((unsigned *)pa + i) = 0xe59ff018;
    }

Thank you very much for your help.

David Green (dgreen@qnx.com)
QNX Software Systems Ltd.
http://www.qnx.com

Dave Green wrote:

I think that using the vectored interrupt capability of the Atmel
processor is possible, but it would likely require a custom kernel.

Huh? Am I reading this right? Correct me if I’m wrong but you appear to be saying that IRQ sharing is the only option for using ARM interrupts under QNX, or are you just saying that the vectoring, that QSSL loves so much, is still being added?


Evan

before opening this post, I’ve examined the code at BSP6.2.1, but there is
no vectored interrupt controller example. I mean, when the IRQ exception
occures, QNX cathces it, and performes some tasks (interrupt
identification, dispatching, context switch, etc). But can I force QNX to
“interrupt” without IRQ exception, using intrinfo structure, or other
methods? I mean in QNX by default we have (hypothetically):

ARM IRQ exception vector @ 0x00000018

ldr pc, [pc,#QNX_INTERRUPT_DISPATCHER]

and I want to make it by this way:

ARM IRQ exception vector @ 0x00000018

ldr pc, [pc,#SOME_REGISTER_WITH_VECTOR]

so the value “SOME_REGISTER_WITH_VECTOR” generated by hardware. To ensure
that interrupts that I use in OS are correctly serviced I’ll program
corresponding vectors to “QNX_INTERRUPT_DISPATCHER” in init_intrinfo()
function.

You can’t really do this - remember QNX implements a
multitasking OS where each process runs in a separate
address space. The underlying kernel is a microkernel
so all drivers (including the associated interrupt
handlers) run within their own address space.

This means the “vector address” you want to set in the
interrupt controller is only valid when that driver’s
address space is active.

The actual operation performed by the kernel when an
IRQ exception occurs is essentially:

  • save register context
  • call id callout to determine what interrupt occurred
  • use the “vector #” returned by the id callout to index
    an internal data structure representing the interrupt
  • if the interrupt has a handler function:
    . switch address space to that driver’s address space
    . invoke the handler function
    . if handler returns a sigevent, queue it for processing
  • if the interrupt does not have a handler:
    . call mask callout to mask the interrupt
    [ sigevent handler must call InterruptUnmask() to
    re-enable the interrupt source]
    . queue sigevent registered for the interrupt
  • call eoi callout to acknowledge the interrupt
  • process pending sigevents
  • return from IRQ exception (which may preempt the interrupted
    code if a sigevent causes preemption)

Maybe you’re a little bit confused - “is there a real need to process some
interrupts outside the OS?” Yes, there is. Of course, if it’s not
impossible to handle IRQ’s in such way - I’ll do it thru OS, but it will
take more time.

I had a quick look through the 9200 data sheet, and it looks
like you will have to use IRQID in the id callout to report
what interrupt occurred and let the kernel do the appropriate
dispatching. As described above, you cannot directly branch
to a handler address because you need to switch to the correct
address space first.

I didn’t look too closely to figure out exactly what needs to
be done wrt IVR and EOICR registers to correctly deal with the
possible nesting done by the prioritised interrupts.

And another question - how QNX handles other ARM exceptions (undefined
instruction, data abort, address abort), if they occure? I found only this
code in startup library (init_cpuinfo.c) to setup’em:

/*

  • Set up the trap entry point to be “ldr pc, [pc, #0x18]”
  • These jump slot addresses are all zero, so until these have
  • been properly set up, any exception will result in a loop.
    */
    for (i = 0; i < 8; i++) {
    *((unsigned *)pa + i) = 0xe59ff018;
    }

The kernel places the addresses of its exception handlers in
the jump slots that those instructions load from.
In essence:

  • undefined handler deals with breakpoints or generates SIGTRAP
  • prefetch/data aborts handle page faults: allocate page for
    MAP_LAZY pages or generate a SIGBUS/SIGSEGV otherwise

Sunil.

Sunil, you mention for the no handler case that the kernel masks the
interrupt. Is this not the case for an ISR as well? i.e.:

  • save register context
  • call id callout to determine what interrupt occurred
  • use the “vector #” returned by the id callout to index
    an internal data structure representing the interrupt
  • if the interrupt has a handler function:
    . switch address space to that driver’s address space

call mask callout to mask the interrupt

. invoke the handler function
. if handler returns a sigevent, queue it for processing

call unmask callout to mask the interrupt

  • if the interrupt does not have a handler:
    . call mask callout to mask the interrupt
    [ sigevent handler must call InterruptUnmask() to
    re-enable the interrupt source]
    . queue sigevent registered for the interrupt
  • call eoi callout to acknowledge the interrupt
  • process pending sigevents
  • return from IRQ exception (which may preempt the interrupted
    code if a sigevent causes preemption)

Chris Foran wrote:

Sunil, you mention for the no handler case that the kernel masks the
interrupt. Is this not the case for an ISR as well? i.e.:

The interrupt is masked at the controller by the id callout
and will be unmasked by the eoi callout (iff the mask count
is 0). The sigevent case will increment the mask count so
the interrupt will not be re-enabled by the eoi callout.

Sunil.

  • save register context
  • call id callout to determine what interrupt occurred
  • use the “vector #” returned by the id callout to index
    an internal data structure representing the interrupt
  • if the interrupt has a handler function:
    . switch address space to that driver’s address space


    call mask callout to mask the interrupt

. invoke the handler function
. if handler returns a sigevent, queue it for processing


call unmask callout to mask the interrupt

  • if the interrupt does not have a handler:
    . call mask callout to mask the interrupt
    [ sigevent handler must call InterruptUnmask() to
    re-enable the interrupt source]
    . queue sigevent registered for the interrupt
  • call eoi callout to acknowledge the interrupt
  • process pending sigevents
  • return from IRQ exception (which may preempt the interrupted
    code if a sigevent causes preemption)