Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

A generic up_doirq() might look like the following. It can be very simple because interrupts are disabled:

Code Block

  uint32_t *up_doirq(int irq, uint32_t *regs)
  {
    /* Current regs non-zero indicates that we are processing an interrupt;
   * current_regs is also used to manage interrupt level context switches.

...

Code Block
   */

  current_regs = regs;
Code Block
    /* Deliver the IRQ */
Code Block
    irq_dispatch(irq, regs);
Code Block
    /* If a context switch occurred while processing the interrupt then
   * current_regs may have change value.  If we return any value

...

Code Block

     different
   * from the input regs, then the lower level will know that a context
   * switch occurred during interrupt processing.
   */

  regs = (uint32_t*)current_regs;
    current_regs = NULL;
    return regs;
  }

What has to change to support nested interrupts is:

...

So the modified version of up_doirq() would be as follows. Here we assume that interrupts are enabled.

Code Block

  uint32_t *up_doirq(int irq, uint32_t *regs)
  {
    irqstate_t flags;
Code Block
    /* Current regs non-zero indicates that we are processing an interrupt;
   * regs holds the state of the interrupted logic; current_regs holds

...

 the
   * state of the interrupted user task.  current_regs should, therefor,

...


   * only be modified for outermost interrupt handler (when g_nestlevel == 0)

...

Code Block
   */

  flags = irqsave();
    if (g_nestlevel == 0)
      {
        current_regs = regs;
      }
    g_nestlevel++
    irqrestore(flags);
Code Block
    /* Deliver the IRQ */
Code Block
    irq_dispatch(irq, regs);
Code Block
    /* Context switches are indicated by the returned value of this function.
   * If a context switch occurred while processing the interrupt

...

 then
   * current_regs may have change value.  If we return any value

...

Code Block

     different
   * from the input regs, then the lower level will know that a context
   * switch occurred during interrupt processing.  Context switching should
   * only be performed when the outermost interrupt handler returns.
   */

  flags = irqsave();
    g_nestlevel--;
    if (g_nestlevel == 0)
      {
        regs = (uint32_t*)current_regs;
        current_regs = NULL;
      }
Code Block
    /* Note that interrupts are left disabled.  This needed if context switch
   * will be performed.  But, any case, the correct interrupt state

...

Code Block
 should
   * be restored when returning from the interrupt.
   */

  return regs;
  }

NOTE: An alternative, cleaner design might also be possible. If one were to defer all context switching to a PendSV handler, then the interrupts could vector to the do_irq() logic and then all interrupts would be naturally nestable.

...