Interrupt(5): enable & disable & mask & unmask

InterruptEnable()  — enables all hardware interrupts. can be called from a thread or from an interrupt handler.

__asm {
MRS r1, CPSR      —> copy CPSR to r1
BIC r1, r1, #0x80  —> set bit 7 to 0
MSR CPSR_c, r1   –> copy the modified value back to CPSR
}

InterruptDisable() — disable all hardware interrupts.

__asm {
MRS r1, CPSR      —> copy CPSR to r1
ORR r1, r1, #0x80  —> set bit 7 to 1
MSR CPSR_c, r1   –> copy the modified value back to CPSR
}

Note:

  1. interruptEnable() and InterruptDisable() only work on single processor hardware. Use InterruptLock() and InterruptUnlock() pair, which can be used on either multi-processor or single processor hardware
  2. InterruptLock() calls InterruptDisable() first.
  3. InterruptUnlock() calls Interruptenable() at the end.

InterruptLock(spinlock) — Guards a critical section by locking the specified spinlock.

  • InterruptLock() protects access to shared data structures between an interrupt handler and the thread that owns the handler.
  • InterruptLock() tries to acquire the spinlock (a variable shared between the interrupt handler and a thread) while interrupts are disabled. The code spins in a tight loop until the lock is acquired. It’s important to release the lock as soon as possible.
  • the thread must have the PROCMGR_AID_IO ability enabled.

    It’s important to release the lock as soon as possible.

  • If spinlock isn’t a static variable, you must initialize it by calling:
    memset( spinlock, 0, sizeof( *spinlock ) );

InteruptMask(int IRQ, int id)   Disable a hardware interrupt. id is the interrupt id returned by InterruptAttach().

  • only calls mask() callout if the current ip->mask_cont == 0;
    • otherwise, only increase the mask_count for that intetrupt level: ilp->mask_count++;
  • if the parameter id (itp) is not NULL, ++ itp->mask_count.

note: The id is ignored unless you use the _NTO_INTR_FLAGS_TRK_MSK flag when you attach the handler.

What’s behind InterruptMask() call?

the kernel will  either look for the corresponding “mask” function for this interrupt in SYSPAGE area (if in_interrupt() returns true), or call __interruptMask

in QNX, it is usually implemented as a callout. For ARM based processor,

  • mask() callout will write to ICDICER (distributer Interrupt Clear-Enable register);
  • unmask() callout will write to ICDISER (distributer Interrupt Set-Enable register).
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s