summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-08-28 07:23:39 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-08-28 07:23:39 -0600
commitc6aca23cb29f4cc671bb885ee192b8452ae05e86 (patch)
treec9e0aa08afa1bf510f89a3f69a5c469d898b6c3b
parent234d16704c3e18d531637c5af783dd1c2b23d12b (diff)
downloadnuttx-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
-rw-r--r--nuttx/arch/sh/src/common/up_blocktask.c16
-rw-r--r--nuttx/arch/sh/src/common/up_doirq.c92
-rw-r--r--nuttx/arch/sh/src/common/up_unblocktask.c16
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