Xtensa: Add xtensa_coproc.h

This commit is contained in:
Gregory Nutt 2016-10-28 10:33:20 -06:00
parent 5b1a3e6fe0
commit be2a801e30
7 changed files with 219 additions and 59 deletions

View File

@ -38,17 +38,6 @@ config XTENSA_CALL0_ABI
The Window ABI is not supported. Only the CALL0 ABI is supported in the
current implementation.
config XTENSA_CP_LAZY
bool "Lazy Co-processor Save"
default y
---help---
If this option is selected, then the co-processor state will be saved
only on context switches. As a consequency of this, co-processors
may NOT be used within interrupt handlers. If you must use co-
processors in interrupt handling, then disable this option. There
will be a significant interrupt latency performance impact if this
option is disabled.
config XTENSA_USE_OVLY
bool
default n

View File

@ -52,6 +52,7 @@
#include <arch/chip/core-isa.h>
#include <arch/xtensa/xtensa_specregs.h>
#include <arch/xtensa/xtensa_corebits.h>
#include <arch/xtensa/xtensa_coproc.h>
/* Include architecture-specific IRQ definitions */
@ -158,6 +159,12 @@ struct xcptcontext
uint32_t regs[XCPTCONTEXT_REGS];
#if XCHAL_CP_NUM > 0
/* Co-processor save area */
struct struct xtensa_cpstate_s cpstate;
#endif
#ifdef CONFIG_LIB_SYSCALL
/* The following array holds the return address and the exc_return value
* needed to return from each nested system call.

View File

@ -0,0 +1,152 @@
/****************************************************************************
* arch/xtensa/include/xtensa/xtensa_coproc.h
*
* Adapted from use in NuttX by:
*
* Copyright (C) 2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Derives from logic originally provided by Cadence Design Systems Inc.
*
* Copyright (c) 2006-2015 Cadence Design Systems Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
****************************************************************************/
#ifndef __ARCH_XTENSA_INCLUDE_XTENSA_XTENSA_COPROC_H
#define __ARCH_XTENSA_INCLUDE_XTENSA_XTENSA_COPROC_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <arch/exp32/core-isa.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#if XCHAL_CP_NUM > 0
/* Align a value up/down to nearest n-byte boundary, where n is a power of 2. */
#define _CP_MASK(n) ((n) - 1)
#define _CP_ALIGNUP(n,val) (((val) + _CP_MASK(n)) & ~_CP_MASK(n))
#define _CP_ALIGNDOWN(n,val) ((val) & ~_CP_MASK(n))
/* CO-PROCESSOR STATE SAVE AREA FOR A THREAD
*
* NuttX provides an area per thread to save the state of co-processors when
* that thread does not have control. Co-processors are context-switched
* lazily (on demand) only when a new thread uses a co-processor instruction,
* otherwise a thread retains ownership of the co-processor even when it
* loses control of the processor. An Xtensa co-processor exception is
* triggered when any co-processor instruction is executed by a thread that
* is not the owner, and the context switch of that co-processor is then
* peformed by the handler. Ownership represents which thread's state is
* currently in the co-processor.
*
* Co-processors may not be used by interrupt or exception handlers. If an
* co-processor instruction is executed by an interrupt or exception handler,
* the co-processor exception handler will trigger a kernel panic and freeze.
* This restriction is introduced to reduce the overhead of saving and
* restoring co-processor state (which can be quite large) and in particular
* remove that overhead from interrupt handlers.
*
* The co-processor state save area may be in any convenient per-thread
* location such as in the thread control block or above the thread stack
* area. It need not be in the interrupt stack frame since interrupts don't
* use co-processors.
*
* Along with the save area for each co-processor, two bitmasks with flags
* per co-processor (laid out as in the CPENABLE reg) help manage context-
* switching co-processors as efficiently as possible:
*
* XTENSA_CPENABLE
* The contents of a non-running thread's CPENABLE register.
* It represents the co-processors owned (and whose state is still needed)
* by the thread. When a thread is preempted, its CPENABLE is saved here.
* When a thread solicits a context-swtich, its CPENABLE is cleared - the
* compiler has saved the (caller-saved) co-proc state if it needs to.
* When a non-running thread loses ownership of a CP, its bit is cleared.
* When a thread runs, it's XTENSA_CPENABLE is loaded into the CPENABLE reg.
* Avoids co-processor exceptions when no change of ownership is needed.
*
* XTENSA_CPSTORED
* A bitmask with the same layout as CPENABLE, a bit per co-processor.
* Indicates whether the state of each co-processor is saved in the state
* save area. When a thread enters the kernel, only the state of co-procs
* still enabled in CPENABLE is saved. When the co-processor exception
* handler assigns ownership of a co-processor to a thread, it restores
* the saved state only if this bit is set, and clears this bit.
*
* XTENSA_CPCSST
* A bitmask with the same layout as CPENABLE, a bit per co-processor.
* Indicates whether callee-saved state is saved in the state save area.
* Callee-saved state is saved by itself on a solicited context switch,
* and restored when needed by the coprocessor exception handler.
* Unsolicited switches will cause the entire coprocessor to be saved
* when necessary.
*
* XTENSA_CPASA
* Pointer to the aligned save area. Allows it to be aligned more than
* the overall save area (which might only be stack-aligned or TCB-aligned).
* Especially relevant for Xtensa cores configured with a very large data
* path that requires alignment greater than 16 bytes (ABI stack alignment).
*/
/* Offsets of each coprocessor save area within the 'aligned save area': */
#define XTENSA_CP0_SA 0
#define XTENSA_CP1_SA _CP_ALIGNUP(XCHAL_CP1_SA_ALIGN, XTENSA_CP0_SA + XCHAL_CP0_SA_SIZE)
#define XTENSA_CP2_SA _CP_ALIGNUP(XCHAL_CP2_SA_ALIGN, XTENSA_CP1_SA + XCHAL_CP1_SA_SIZE)
#define XTENSA_CP3_SA _CP_ALIGNUP(XCHAL_CP3_SA_ALIGN, XTENSA_CP2_SA + XCHAL_CP2_SA_SIZE)
#define XTENSA_CP4_SA _CP_ALIGNUP(XCHAL_CP4_SA_ALIGN, XTENSA_CP3_SA + XCHAL_CP3_SA_SIZE)
#define XTENSA_CP5_SA _CP_ALIGNUP(XCHAL_CP5_SA_ALIGN, XTENSA_CP4_SA + XCHAL_CP4_SA_SIZE)
#define XTENSA_CP6_SA _CP_ALIGNUP(XCHAL_CP6_SA_ALIGN, XTENSA_CP5_SA + XCHAL_CP5_SA_SIZE)
#define XTENSA_CP7_SA _CP_ALIGNUP(XCHAL_CP7_SA_ALIGN, XTENSA_CP6_SA + XCHAL_CP6_SA_SIZE)
#define XTENSA_CP_SA_SIZE _CP_ALIGNUP(16, XTENSA_CP7_SA + XCHAL_CP7_SA_SIZE)
/* Offsets within the overall save area: */
#define XTENSA_CPENABLE 0 /* (2 bytes) coprocessors active for this thread */
#define XTENSA_CPSTORED 2 /* (2 bytes) coprocessors saved for this thread */
#define XTENSA_CPCSST 4 /* (2 bytes) coprocessor callee-saved regs stored for this thread */
#define XTENSA_CPASA 8 /* (4 bytes) ptr to aligned save area */
/****************************************************************************
* Public Types
****************************************************************************/
#ifndef __ASSEMBLY__
struct xtensa_cpstate_s
{
uint16_t cpenable; /* (2 bytes) coprocessors active for this thread */
uint16_t cpstored; /* (2 bytes) coprocessors saved for this thread */
uint16_t cpcsst /* (2 bytes) coprocessor callee-saved regs stored for this thread */
uint16_t unused; /* (2 bytes) unused */
uint32_t *cpasa; /* (4 bytes) ptr to aligned save area */
}
#endif /* __ASSEMBLY__ */
#endif /* #if XCHAL_CP_NUM > 0 */
#endif /* __ARCH_XTENSA_INCLUDE_XTENSA_XTENSA_COPROC_H */

View File

@ -195,13 +195,15 @@ _xtensa_coproc_savestate:
rsr a2, CPENABLE /* a2 = which CPs are enabled */
beqz a2, .Ldone /* Quick exit if none */
mov a14, a0 /* Save return address */
call0 XT_RTOS_CP_STATE /* Get address of CP save area */
mov a0, a14 /* Restore return address */
beqz a15, .Ldone /* if none then nothing to do */
s16i a2, a15, XT_CP_CS_ST /* Save mask of CPs being stored */
s16i a2, a15, XTENSA_CPCSST /* Save mask of CPs being stored */
movi a13, _xt_coproc_sa_offset /* Array of CP save offsets */
l32i a15, a15, XT_CP_ASA /* a15 = base of aligned save area */
l32i a15, a15, XTENSA_CPASA /* a15 = base of aligned save area */
#if XTENSA_CP0_SA_SIZE > 0
bbci.l a2, 0, 2f /* CP 0 not enabled */
@ -308,11 +310,13 @@ _xtensa_coproc_restorestate:
call0 XT_RTOS_CP_STATE /* Get address of CP save area */
mov a0, a14 /* Restore return address */
beqz a15, .Ldone2 /* if none then nothing to do */
l16ui a3, a15, XT_CP_CS_ST /* a3 = which CPs have been saved */
l16ui a3, a15, XTENSA_CPCSST /* a3 = which CPs have been saved */
xor a3, a3, a2 /* Clear the ones being restored */
s32i a3, a15, XT_CP_CS_ST /* Update saved CP mask */
s32i a3, a15, XTENSA_CPCSST /* Update saved CP mask */
movi a13, _xt_coproc_sa_offset /* Array of CP save offsets */
l32i a15, a15, XT_CP_ASA /* a15 = base of aligned save area */
l32i a15, a15, XTENSA_CPASA /* a15 = base of aligned save area */
#if XTENSA_CP0_SA_SIZE
bbci.l a2, 0, 2f /* CP 0 not enabled */

View File

@ -47,6 +47,8 @@
#include <nuttx/kmalloc.h>
#include <nuttx/arch.h>
#include <nuttx/board.h>
#include <arch/xtensa/xtensa_coproc.h>
#include <arch/board/board.h>
#include "xtensa.h"
@ -57,13 +59,11 @@
/* XTENSA requires at least a 4-byte stack alignment. For floating point use,
* however, the stack must be aligned to 8-byte addresses.
*
* REVIST: Is this true? Comes from ARM EABI
*/
#ifdef CONFIG_LIBC_FLOATINGPOINT
# define STACK_ALIGNMENT 8
#else
# define STACK_ALIGNMENT 4
#endif
#define STACK_ALIGNMENT 8
/* Stack alignment macros */
@ -114,6 +114,12 @@
int up_create_stack(FAR struct tcb_s *tcb, size_t stack_size, uint8_t ttype)
{
#if XCHAL_CP_NUM > 0
uintptr_t cpstart;
uintptr_t cpend;
size_t cpsize;
#endif
/* Is there already a stack allocated of a different size? Because of
* alignment issues, stack_size might erroneously appear to be of a
* different size. Fortunately, this is not a critical operation.
@ -126,6 +132,16 @@ int up_create_stack(FAR struct tcb_s *tcb, size_t stack_size, uint8_t ttype)
up_release_stack(tcb, ttype);
}
#if XCHAL_CP_NUM > 0
/* Add the size of the co-processor save area to the stack allocation.
* REVISIT: This may waste memory. Increasing the caller's requested
* stack size should only be necessary if the requested size could not
* hold the co-processor save area.
*/
stack_size += XTENSA_CP_SA_SIZE;
#endif
/* Do we need to allocate a new stack? */
if (!tcb->stack_alloc_ptr)
@ -163,15 +179,15 @@ int up_create_stack(FAR struct tcb_s *tcb, size_t stack_size, uint8_t ttype)
if (tcb->stack_alloc_ptr)
{
size_t top_of_stack;
uintptr_t top_of_stack;
size_t size_of_stack;
#ifdef CONFIG_STACK_COLORATION
/* Yes.. If stack debug is enabled, then fill the stack with a
* recognizable value that we can use later to test for high
* water marks.
*/
#ifdef CONFIG_STACK_COLORATION
memset(tcb->stack_alloc_ptr, 0xaa, stack_size);
#endif
@ -181,15 +197,36 @@ int up_create_stack(FAR struct tcb_s *tcb, size_t stack_size, uint8_t ttype)
* the stack are referenced as positive word offsets from sp.
*/
top_of_stack = (uint32_t)tcb->stack_alloc_ptr + stack_size - 4;
top_of_stack = (uintptr_t)tcb->stack_alloc_ptr + stack_size - 4;
/* The XTENSA stack must be aligned at word (4 byte) boundaries; for
* floating point use, the stack must be aligned to 8-byte addresses.
* If necessary top_of_stack must be rounded down to the next
* boundary to meet these alignment requirements.
#if XCHAL_CP_NUM > 0
/* Allocate the co-processor save area at the top of the (push down)
* stack.
*
* REVISIT: This is not secure. In secure built configurations it
* be more appropriate to use kmm_memalign() to allocte protected
* memory rather than using the stack.
*/
top_of_stack = STACK_ALIGN_DOWN(top_of_stack);
cpstart = (uintptr_t)_CP_ALIGNDOWN(top_of_stack - XCHAL_CP1_SA_ALIGN);
top_of_stack = cpstart;
/* Initialize the coprocessor save area (see xtensa_coproc.h) */
xcp->cpstate.cpenable = 0; /* No coprocessors active for this thread */
xcp->cpstate.cpstored = 0; /* No coprocessors saved for this thread */
xcp->cpstate.cpcsst = 0; /* No oprocessor callee-saved regs stored for this thread */
xcp->cpstate.unused = 0; /* unused */
xcp->cpstate.cpasa = (uint32_t *)cpstart; /* Start of aligned save area */
#endif
/* The XTENSA stack must be aligned. If necessary top_of_stack must be
* rounded down to the next boundary to meet this alignment requirement.
*
* NOTE: Co-processor save area not included in the size of the stack.
*/
top_of_stack = STACK_ALIGN_DOWN(top_of_stack);
size_of_stack = top_of_stack - (uint32_t)tcb->stack_alloc_ptr + 4;
/* Save the adjusted stack values in the struct tcb_s */

View File

@ -71,11 +71,6 @@
void up_initial_state(struct tcb_s *tcb)
{
struct xcptcontext *xcp = &tcb->xcp;
#if 0 /* REVISIT */
#if XCHAL_CP_NUM > 0
uint32_t *ptr;
#endif
#endif /* REVISIT */
/* Initialize the initial exception register context structure */
@ -99,20 +94,4 @@ void up_initial_state(struct tcb_s *tcb)
xcp->regs[REG_PS] = PS_UM | PS_EXCM | PS_WOE | PS_CALLINC(1);
#endif
#warning REVISIT co-processor support
#if 0 /* REVISIT */
#if XCHAL_CP_NUM > 0
/* Init the coprocessor save area (see xtensa_context.h)
*
* No access to TCB here, so derive indirectly. Stack growth is top to bottom.
* //ptr = (uint32_t *) xMPUSettings->coproc_area;
*/
ptr = (uint32_t *)(((uint32_t)tcb->adj_stack_ptr - XT_CP_SIZE) & ~0xf);
ptr[0] = 0;
ptr[1] = 0;
ptr[2] = (((uint32_t)ptr) + 12 + XTENSA_TOTAL_SA_ALIGN - 1) & -XTENSA_TOTAL_SA_ALIGN;
#endif
#endif /* REVISIT */
}

View File

@ -81,12 +81,6 @@ uint32_t *xtensa_irq_dispatch(int irq, uint32_t *regs)
CURRENT_REGS = regs;
#if XCHAL_CP_NUM > 0 && !defined(CONFIG_XTENSA_CP_LAZY)
/* Save the current co processor state on entry int each interrupt. */
esp32_coproc_savestate(tcb->xcp.cpstate);
#endif
/* Deliver the IRQ */
irq_dispatch(irq, regs);
@ -99,7 +93,6 @@ uint32_t *xtensa_irq_dispatch(int irq, uint32_t *regs)
if (regs != CURRENT_REGS)
{
#if XCHAL_CP_NUM > 0
#ifdef CONFIG_XTENSA_CP_LAZY
/* If an interrupt level context switch has occurred, then save the
* co-processor state in in the suspended thread's co-processor save
* area.
@ -110,9 +103,8 @@ uint32_t *xtensa_irq_dispatch(int irq, uint32_t *regs)
*/
esp32_coproc_savestate(tcb->xcp.cpstate);
#endif
/* Set up the co-processor state for the to-be-started thread.
/* Then set up the co-processor state for the to-be-started thread.
*
* NOTE: The current thread for this CPU is the to-be-started
* thread.