diff options
author | Gregory Nutt <gnutt@nuttx.org> | 2014-08-28 07:23:39 -0600 |
---|---|---|
committer | Gregory Nutt <gnutt@nuttx.org> | 2014-08-28 07:23:39 -0600 |
commit | c6aca23cb29f4cc671bb885ee192b8452ae05e86 (patch) | |
tree | c9e0aa08afa1bf510f89a3f69a5c469d898b6c3b /nuttx/arch/sh/src | |
parent | 234d16704c3e18d531637c5af783dd1c2b23d12b (diff) | |
download | nuttx-c6aca23cb29f4cc671bb885ee192b8452ae05e86.tar.gz nuttx-c6aca23cb29f4cc671bb885ee192b8452ae05e86.tar.bz2 nuttx-c6aca23cb29f4cc671bb885ee192b8452ae05e86.zip |
SH: Move address environment switch from the task switchers to the interrupt handler. That may save doing the action multiple times per interrupt
Diffstat (limited to 'nuttx/arch/sh/src')
-rw-r--r-- | nuttx/arch/sh/src/common/up_blocktask.c | 16 | ||||
-rw-r--r-- | nuttx/arch/sh/src/common/up_doirq.c | 92 | ||||
-rw-r--r-- | nuttx/arch/sh/src/common/up_unblocktask.c | 16 |
3 files changed, 64 insertions, 60 deletions
diff --git a/nuttx/arch/sh/src/common/up_blocktask.c b/nuttx/arch/sh/src/common/up_blocktask.c index db097e8ee..f81d9c539 100644 --- a/nuttx/arch/sh/src/common/up_blocktask.c +++ b/nuttx/arch/sh/src/common/up_blocktask.c @@ -49,7 +49,7 @@ #include "up_internal.h" /**************************************************************************** - * Private Definitions + * Pre-processor Definitions ****************************************************************************/ /**************************************************************************** @@ -136,19 +136,11 @@ void up_block_task(struct tcb_s *tcb, tstate_t task_state) rtcb = (struct tcb_s*)g_readytorun.head; - /* Then switch contexts */ + /* Then switch contexts. Any necessary address environment + * changes will be made when the interrupt returns. + */ current_regs = rtcb->xcp.regs; - -#ifdef CONFIG_ARCH_ADDRENV - /* Make sure that the address environment for the previously - * running task is closed down gracefully (data caches dump, - * MMU flushed) and set up the address environment for the new - * thread at the head of the ready-to-run list. - */ - - (void)group_addrenv(rtcb); -#endif } /* Copy the user C context into the TCB at the (old) head of the diff --git a/nuttx/arch/sh/src/common/up_doirq.c b/nuttx/arch/sh/src/common/up_doirq.c index c28d1ede4..ca6c6ee59 100644 --- a/nuttx/arch/sh/src/common/up_doirq.c +++ b/nuttx/arch/sh/src/common/up_doirq.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/sh/src/common/up_doirq.c * - * Copyright (C) 2008-2009, 2011 Gregory Nutt. All rights reserved. + * Copyright (C) 2008-2009, 2011, 2014 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <gnutt@nuttx.org> * * Redistribution and use in source and binary forms, with or without @@ -48,8 +48,10 @@ #include "up_arch.h" #include "up_internal.h" +#include "group/group.h" + /**************************************************************************** - * Definitions + * Pre-processor Definitions ****************************************************************************/ /**************************************************************************** @@ -76,56 +78,74 @@ uint32_t *up_doirq(int irq, uint32_t* regs) #else if ((unsigned)irq < NR_IRQS) { - uint32_t *savestate; - - /* Nested interrupts are not supported in this implementation. If - * you want to implement nested interrupts, you would have to (1) - * change the way that current_regs is handled and (2) the design - * associated with CONFIG_ARCH_INTERRUPTSTACK. The savestate - * variable will not work for that purpose as implemented here - * because only the outermost nested interrupt can result in a - * context switch (it can probably be deleted). - */ - - /* Current regs non-zero indicates that we are processing - * an interrupt; current_regs is also used to manage - * interrupt level context switches. - */ + /* Current regs non-zero indicates that we are processing + * an interrupt; current_regs is also used to manage + * interrupt level context switches. + * + * Nested interrupts are not supported. + */ - savestate = (uint32_t*)current_regs; - current_regs = regs; + DEBUGASSERT(current_regs == NULL); + current_regs = regs; - /* Mask and acknowledge the interrupt (if supported by the chip) */ + /* Mask and acknowledge the interrupt (if supported by the chip) */ #ifndef CONFIG_ARCH_NOINTC - up_maskack_irq(irq); + up_maskack_irq(irq); #endif - /* Deliver the IRQ */ + /* Deliver the IRQ */ - irq_dispatch(irq, regs); + irq_dispatch(irq, regs); - /* Get the current value of regs... it may have changed because - * of a context switch performed during interrupt processing. - */ +#if defined(CONFIG_ARCH_FPU) || defined(CONFIG_ARCH_ADDRENV) + /* Check for a context switch. If a context switch occurred, then + * current_regs will have a different value than it did on entry. If an + * interrupt level context switch has occurred, then restore the floating + * point state and the establish the correct address environment before + * returning from the interrupt. + */ - regs = current_regs; + if (regs != current_regs) + { +#ifdef CONFIG_ARCH_FPU + /* Restore floating point registers */ - /* Restore the previous value of current_regs. NULL would indicate that - * we are no longer in an interrupt handler. It will be non-NULL if we - * are returning from a nested interrupt. - */ + up_restorefpu((uint32_t*)current_regs); +#endif - current_regs = savestate; +#ifdef CONFIG_ARCH_ADDRENV + /* Make sure that the address environment for the previously + * running task is closed down gracefully (data caches dump, + * MMU flushed) and set up the address environment for the new + * thread at the head of the ready-to-run list. + */ - /* Unmask the last interrupt (global interrupts are still - * disabled. - */ + (void)group_addrenv(rtcb); +#endif + } +#endif + /* Get the current value of regs... it may have changed because + * of a context switch performed during interrupt processing. + */ + + regs = current_regs; + + /* Set current_regs to NULL to indicate that we are no longer in an + * interrupt handler. + */ + + current_regs = NULL; + + /* Unmask the last interrupt (global interrupts are still + * disabled. + */ #ifndef CONFIG_ARCH_NOINTC - up_enable_irq(irq); + up_enable_irq(irq); #endif } + board_led_off(LED_INIRQ); #endif return regs; diff --git a/nuttx/arch/sh/src/common/up_unblocktask.c b/nuttx/arch/sh/src/common/up_unblocktask.c index 463dc0bf9..587eafe5d 100644 --- a/nuttx/arch/sh/src/common/up_unblocktask.c +++ b/nuttx/arch/sh/src/common/up_unblocktask.c @@ -49,7 +49,7 @@ #include "up_internal.h" /**************************************************************************** - * Private Definitions + * Pre-processor Definitions ****************************************************************************/ /**************************************************************************** @@ -127,19 +127,11 @@ void up_unblock_task(struct tcb_s *tcb) rtcb = (struct tcb_s*)g_readytorun.head; - /* Then switch contexts */ + /* Then switch contexts. Any necessary address environment + * changes will be made when the interrupt returns. + */ current_regs = rtcb->xcp.regs; - -#ifdef CONFIG_ARCH_ADDRENV - /* Make sure that the address environment for the previously - * running task is closed down gracefully (data caches dump, - * MMU flushed) and set up the address environment for the new - * thread at the head of the ready-to-run list. - */ - - (void)group_addrenv(rtcb); -#endif } /* We are not in an interrupt handler. Copy the user C context |