411 lines
14 KiB
C
411 lines
14 KiB
C
/* private/smpArmP.h - ARM/XScale-specific definitions for SMP support */
|
|
|
|
/*
|
|
* Copyright (c) 2007-2011 Wind River Systems, Inc.
|
|
*
|
|
* The right to copy, distribute, modify or otherwise make use
|
|
* of this software may be licensed only pursuant to the terms
|
|
* of an applicable Wind River license agreement.
|
|
*/
|
|
|
|
/*
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Any compilation using definitions from this file will not *
|
|
* be binary-compatible between the UP and SMP environments. *
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
*/
|
|
|
|
/*
|
|
modification history
|
|
--------------------
|
|
01r,10sep12,ggm updated for tes.
|
|
01q,02dec11,jdw Add _fpStatus per WIND00129622
|
|
01p,30nov10,j_b add unified FIQ/IRQ handling support
|
|
01o,29jul10,pad Moved extern C statement after include statements.
|
|
01n,07jul10,jdw Add _WRS_ARCH_HAS_OBJ_SAFE
|
|
01m,21may10,m_h Thumb-2 Support
|
|
01l,15may09,gls moved VX_INSTR_BARRIER() to vxAtomicArchLibCommon.h
|
|
01k,25feb09,j_b merge ARM SMP support:
|
|
03feb09,j_b define _WRS_SNOOP_NEEDS_DMA_MALLOC_SUPPORT so
|
|
cacheAimArch6DmaMalloc/Free are used with CACHE_SNOOP_ENABLE
|
|
04oct07,j_b define _WRS_ARCH_REQUIRES_CACHE_TEXT_UPDATE_CPC
|
|
31aug07,m_h Fix _ARM_PER_CPU_* macros for CPU != 0
|
|
18jun07,m_h syntax error non-SMP _ARM_CPU_INDEX_GET
|
|
01j,18sep08,gls added _WRS_KERNEL_LOCK_VAR_ALIGN
|
|
01i,27aug08,jpb Renamed VSB header file
|
|
01h,24jun08,jpb Added include path for kernel configurations options set in
|
|
vsb. Renamed _WRS_VX_SMP to _WRS_CONFIG_SMP.
|
|
01g,20jun08,zl replaced _WRS_ASM() with _WRS_BARRIER()
|
|
01f,10jan08,gls added VX_INSTR_BARRIER()
|
|
01e,09may07,lei renamed reschedNeeded to reschedMode.
|
|
01d,09may07,m_h Fix per-CPU SMP macros, cleanup kernel global offsets
|
|
01c,03may07,m_h SMP definitions
|
|
01b,20apr07,m_h SMP Private definitions
|
|
01a,04apr07,m_h written.
|
|
*/
|
|
|
|
#ifndef __INCsmpArmPh
|
|
#define __INCsmpArmPh
|
|
|
|
#include <vsbConfig.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#ifdef _WRS_CONFIG_SMP
|
|
|
|
/*
|
|
* ARM has been adapted to use the new object safe count feature for SMP.
|
|
* When all architectures have been adapted this can be removed from
|
|
* the code.
|
|
*/
|
|
|
|
#define _WRS_ARCH_HAS_OBJ_SAFE
|
|
|
|
/*
|
|
* Much like the _WRS_WIND_VARS_ALIGN the _WRS_KERNEL_LOCK_VAR_ALIGN macro
|
|
* must be defined for the common CPU build variants (e.g. PPC32, MIPS32,
|
|
* XSCALE, etc), representing the maximum cache line size of the variants of
|
|
* the respective arch.
|
|
*
|
|
* For ARM this is 128 bytes.
|
|
*/
|
|
|
|
#define _WRS_KERNEL_LOCK_VAR_ALIGN 128
|
|
|
|
/*
|
|
* ARM11 MPCore does not support cache coherency with DMA agents or
|
|
* shared memory, so uncached memory must be returned by cacheDmaMalloc()
|
|
* (via cacheAimArch6DmaMalloc) when CACHE_SNOOP_ENABLE is defined
|
|
* (ex., in SMP mode).
|
|
* See usage in target\src\os\mm\cacheLib.c:cacheFuncsSet().
|
|
*/
|
|
|
|
#define _WRS_SNOOP_NEEDS_DMA_MALLOC_SUPPORT
|
|
|
|
/* Trigger software cacheTextUpdate CPC */
|
|
|
|
#define _WRS_ARCH_REQUIRES_CACHE_TEXT_UPDATE_CPC
|
|
|
|
/* ARM specific extension fields to the WIND_VARS struct */
|
|
|
|
#ifndef _ASMLANGUAGE
|
|
|
|
typedef struct wind_vars_arch
|
|
{
|
|
long cpu_intNestingLevel;
|
|
long cpu_maxIntNestingLevel;
|
|
UINT32 cpu_cacheArchState;
|
|
char * cpu_undefSaveArea;
|
|
char * cpu_abortSaveArea;
|
|
char * cpu_swiSaveArea;
|
|
char * cpu_irqStack;
|
|
UINT32 cpu_fpStatus;
|
|
#ifdef _WRS_CONFIG_UNIFIED_FIQ_IRQ
|
|
long cpu_fiqNestingLevel;
|
|
long cpu_maxFiqNestingLevel;
|
|
char * cpu_fiqStack;
|
|
#endif /* _WRS_CONFIG_UNIFIED_FIQ_IRQ */
|
|
} WIND_VARS_ARCH;
|
|
|
|
#define _WRS_WIND_VARS_ARCH WIND_VARS_ARCH cpu_archVars
|
|
|
|
/* macro to access the arch-specific fields of the vxKernelVars struct */
|
|
#define _WRS_WIND_VARS_ARCH_ACCESS(glob) \
|
|
_WRS_KERNEL_GLOBAL_ACCESS (archVars.cpu_##glob)
|
|
|
|
#define _WRS_WIND_VARS_ARCH_SET(cpuid,glob,var) \
|
|
_WRS_KERNEL_CPU_GLOBAL_SET(cpuid,archVars.cpu_##glob,var)
|
|
|
|
#define _WRS_WIND_VARS_ARCH_GET(cpuid,glob) \
|
|
_WRS_KERNEL_CPU_GLOBAL_GET(cpuid,archVars.cpu_##glob)
|
|
|
|
#define _WRS_ARCH_LOCKED_GLOBAL_SET(glob, var) \
|
|
_WRS_KERNEL_LOCKED_GLOBAL_SET(archVars.cpu_##glob,var)
|
|
|
|
#define _WRS_ARCH_LOCKED_GLOBAL_GET(glob, var) \
|
|
_WRS_KERNEL_LOCKED_GLOBAL_GET(archVars.cpu_##glob,var)
|
|
|
|
|
|
/* TODO optimization work needed in regsArm.h (etc) */
|
|
#undef _WRS_ARCH_SUPPORTS_VX_CPU_STATE_INIT
|
|
|
|
#else /* !_ASMLANGUAGE */
|
|
|
|
/* offsets required for assembly macros */
|
|
|
|
#define WIND_VARS_ARCH_BASE (_WRS_WIND_VARS_OFFSET_archVars)
|
|
|
|
#endif /* _ASMLANGUAGE */
|
|
|
|
/*
|
|
* _WRS_WIND_VARS_ALIGN sets the alignment constraint for vxKernelVars. The
|
|
* value must be: a power of two no smaller than sizeof(vxKernelVars), and a
|
|
* multiple of the cache line size (which is 32) on every ARM variant that
|
|
* supports SMP.
|
|
*/
|
|
#define _WRS_WIND_VARS_ALIGN 128
|
|
#define _WRS_WIND_VARS_ALIGN_SHIFT 7
|
|
|
|
/*
|
|
* _ARM_ATOMIC_OPS_SEPARATION defines the minimum desirable separation between
|
|
* words on which SMP-atomic operations (including spinlock) will be
|
|
* performed. This is the cache line size on ARM MP.
|
|
*/
|
|
|
|
#define _ARM_ATOMIC_OPS_SEPARATION _CPU_CACHE_ALIGN_SIZE
|
|
|
|
# ifdef _CPU_CACHE_ALIGN_SIZE
|
|
/*
|
|
* Validate _WRS_WIND_VARS_ALIGN vs current build's _CPU_CACHE_ALIGN_SIZE
|
|
*
|
|
* If any SMP-enabled variant fails this test, _WRS_WIND_VARS_ALIGN must be
|
|
* increased. Since this limit also applies to any subsequent arch-only
|
|
* release against the same generic binary release, it may be desirable to
|
|
* allow for growth.
|
|
*/
|
|
|
|
|
|
# if (_CPU_CACHE_ALIGN_SIZE > _WRS_WIND_VARS_ALIGN)
|
|
#error Must increase "_WRS_WIND_VARS_ALIGN" to at least _CPU_CACHE_ALIGN_SIZE
|
|
# endif /* _CPU_CACHE_ALIGN_SIZE > _WRS_WIND_VARS_ALIGN */
|
|
|
|
/*
|
|
* Sanity check on _ARM_ATOMIC_OPS_SEPARATION
|
|
*
|
|
* A miss here generates a warning instead of an error, since it is merely
|
|
* likely (not inevitable) that the lwarx/stwcx. granularity matches the
|
|
* cache line size; also the performance penalty is less. (Two instances of
|
|
* vxKernelVars within the same cache line will cause continual interference,
|
|
* but two atoms within the same reservation granule will only occasionally
|
|
* cause additional trips around the lwarx/stwcx. loop due to loss of the
|
|
* reservation to an unrelated store.)
|
|
*/
|
|
# if (_CPU_CACHE_ALIGN_SIZE > _ARM_ATOMIC_OPS_SEPARATION)
|
|
#warning Check "_ARM_ATOMIC_OPS_SEPARATION" setting; it likely should be at least _CPU_CACHE_ALIGN_SIZE
|
|
# endif /* _CPU_CACHE_ALIGN_SIZE > _ARM_ATOMIC_OPS_SEPARATION */
|
|
# endif /* _CPU_CACHE_ALIGN_SIZE */
|
|
|
|
/*
|
|
* Just call the (assembly) function for now, but to optimize
|
|
* performance this should eventually become a C-callable
|
|
* _WRS_ASM construct (whose syntax varies depending on TOOL).
|
|
*/
|
|
#define _WRS_CPU_INDEX_GET() vxCpuIndexGet()
|
|
#else /* _WRS_CONFIG_SMP */
|
|
|
|
/* macro to access the arch-specific fields */
|
|
#define _WRS_WIND_VARS_ARCH_ACCESS(glob) \
|
|
_WRS_KERNEL_GLOBAL_ACCESS (glob)
|
|
|
|
#define _WRS_WIND_VARS_ARCH_SET(ignored,glob,var) \
|
|
_WRS_KERNEL_CPU_GLOBAL_SET(ignored,glob,var)
|
|
|
|
#define _WRS_WIND_VARS_ARCH_GET(ignored,glob) \
|
|
_WRS_KERNEL_CPU_GLOBAL_GET(ignored,archVars.cpu_##glob)
|
|
|
|
#define _WRS_ARCH_LOCKED_GLOBAL_SET(glob, var) \
|
|
_WRS_KERNEL_LOCKED_GLOBAL_SET(glob,var)
|
|
|
|
#define _WRS_ARCH_LOCKED_GLOBAL_GET(glob, var) \
|
|
_WRS_KERNEL_LOCKED_GLOBAL_GET(glob,var)
|
|
|
|
|
|
#define _WRS_CPU_INDEX_GET() 0
|
|
#endif /* _WRS_CONFIG_SMP */
|
|
|
|
|
|
#ifdef _ASMLANGUAGE
|
|
|
|
#include <private/windLibP.h>
|
|
|
|
# ifdef _WRS_CONFIG_SMP
|
|
|
|
#include <private/kernelLockLibP.h>
|
|
|
|
/*
|
|
* Sticking a "#" in the middle of a complex #define generates garbage
|
|
* passed to the assembler which results in a syntax error. ARM_HASH is
|
|
* used by this file in order to tell the assembler to use an immediate
|
|
* value.
|
|
*/
|
|
|
|
#define ARM_HASH #
|
|
|
|
#define _ARM_WIND_VARS_OFFSET(label) _WRS_WIND_VARS_OFFSET_##label
|
|
#define _ARM_WIND_VARS_OFFSET_reschedMode \
|
|
#_WRS_WIND_VARS_OFFSET_reschedMode
|
|
|
|
/* ARM specific per-CPU globals */
|
|
#define _WRS_WIND_VARS_OFFSET_intNestingLevel \
|
|
(_WRS_WIND_VARS_OFFSET_archVars+0x0)
|
|
|
|
#define _WRS_WIND_VARS_OFFSET_maxIntNestingLevel \
|
|
(_WRS_WIND_VARS_OFFSET_archVars+0x4)
|
|
|
|
#define _WRS_WIND_VARS_OFFSET_cacheArchState \
|
|
(_WRS_WIND_VARS_OFFSET_archVars+0x8)
|
|
|
|
#define _WRS_WIND_VARS_OFFSET_undefSaveArea \
|
|
(_WRS_WIND_VARS_OFFSET_archVars+0xC)
|
|
|
|
|
|
#define _WRS_WIND_VARS_OFFSET_abortSaveArea \
|
|
(_WRS_WIND_VARS_OFFSET_archVars+0x10)
|
|
|
|
|
|
#define _WRS_WIND_VARS_OFFSET_swiSaveArea \
|
|
(_WRS_WIND_VARS_OFFSET_archVars+0x14)
|
|
|
|
|
|
#define _WRS_WIND_VARS_OFFSET_irqStack \
|
|
(_WRS_WIND_VARS_OFFSET_archVars+0x18)
|
|
|
|
#define _WRS_WIND_VARS_OFFSET_fpStatus \
|
|
(_WRS_WIND_VARS_OFFSET_archVars+0x1C)
|
|
|
|
#ifdef _WRS_CONFIG_UNIFIED_FIQ_IRQ
|
|
|
|
#define _WRS_WIND_VARS_OFFSET_fiqNestingLevel \
|
|
(_WRS_WIND_VARS_OFFSET_archVars+0x20)
|
|
|
|
#define _WRS_WIND_VARS_OFFSET_maxFiqNestingLevel \
|
|
(_WRS_WIND_VARS_OFFSET_archVars+0x24)
|
|
|
|
#define _WRS_WIND_VARS_OFFSET_fiqStack \
|
|
(_WRS_WIND_VARS_OFFSET_archVars+0x28)
|
|
|
|
#endif /* _WRS_CONFIG_UNIFIED_FIQ_IRQ */
|
|
|
|
|
|
#define _ARM_CPU_ID_MASK #0xF
|
|
|
|
#define ARM_WIND_VARS_ALIGN_SHIFT #(_WRS_WIND_VARS_ALIGN_SHIFT)
|
|
|
|
/* Using CPU ID, get the index into the CPU's vxKernelVars */
|
|
/* Note: reading CPU ID requires CPU privileged mode */
|
|
#define _ARM_CPU_INDEX_GET(r) \
|
|
MRC p15, 0, r, c0, c0, 5 ; \
|
|
AND r, r, _ARM_CPU_ID_MASK
|
|
|
|
/* place the address of label into register r */
|
|
#define _ARM_PER_CPU_ADRS_GET(r, scratch, label) \
|
|
_ARM_CPU_INDEX_GET(r) ; \
|
|
LDR scratch, L$_vxKernelVars ; \
|
|
ADD scratch, scratch, r, LSL ARM_WIND_VARS_ALIGN_SHIFT ; \
|
|
ADD r, scratch, ARM_HASH _ARM_WIND_VARS_OFFSET(label) ; \
|
|
|
|
/*
|
|
* In some configurations (e.g. Thumb-2) there are special restrictions on
|
|
* usage of the sp register. Also there appears to be a defect in some
|
|
* versions of the Wind River assembler related to similar use of the lr
|
|
* register. So use these macros for setting up sp or lr.
|
|
*/
|
|
|
|
#define _ARM_PER_CPU_ADRS_GET_SPLR(r_sp, scratch, label) \
|
|
_ARM_PER_CPU_ADRS_GET(r_sp, scratch, label)
|
|
|
|
/* place the value at label into register r */
|
|
#define _ARM_PER_CPU_VALUE_GET_SPLR(r_sp, scratch, label) \
|
|
_ARM_PER_CPU_VALUE_GET(r_sp, scratch, label)
|
|
|
|
/* place the value at label into register r */
|
|
#define _ARM_PER_CPU_VALUE_GET(r,scratch,label) \
|
|
_ARM_CPU_INDEX_GET(r) ; \
|
|
LDR scratch, L$_vxKernelVars ; \
|
|
ADD scratch, scratch, r, LSL ARM_WIND_VARS_ALIGN_SHIFT ; \
|
|
ADD scratch, scratch, ARM_HASH _ARM_WIND_VARS_OFFSET(label) ; \
|
|
LDR r, [scratch]
|
|
|
|
/* place value at label in rv, also place address at label in ra */
|
|
#define _ARM_PER_CPU_VALUE_AND_ADRS_GET(rv,ra,label) \
|
|
_ARM_CPU_INDEX_GET(rv) ; \
|
|
LDR ra, L$_vxKernelVars ; \
|
|
ADD ra, ra, rv, LSL ARM_WIND_VARS_ALIGN_SHIFT ; \
|
|
ADD ra, ra, ARM_HASH _ARM_WIND_VARS_OFFSET(label) ; \
|
|
LDR rv, [ra]
|
|
|
|
/*
|
|
* ro = register to store kernel lock owner
|
|
* ri = register to store cpu index
|
|
*
|
|
* typedef struct smpLock
|
|
* {
|
|
* volatile int state; /@ state of lock (free/taken) @/
|
|
* volatile int owner; /@ CPU which owns the lock @/
|
|
* int count; /@ recursive ownership nesting count @/
|
|
* int options; /@ options applicable to this lock @/
|
|
*/
|
|
|
|
#define _ARM_KERNEL_LOCK_OWNER_AND_INDEX_GET(ro, ri) \
|
|
_ARM_CPU_INDEX_GET(ri) ; \
|
|
LDR ro, L$_kernelStateLock ; \
|
|
ADD ro, ro, ARM_HASH _WRS_KERNEL_LOCK_OFFSET_cpuIndex ; \
|
|
LDR ro, [ro] /* kernel spin lock owner */ ; \
|
|
|
|
|
|
# else /* _WRS_CONFIG_SMP */
|
|
|
|
#define IMM0 #0
|
|
/* Macro unconditionally returns 0 when built for UP */
|
|
#define _ARM_CPU_INDEX_GET(r) MOV r, IMM0
|
|
|
|
/*
|
|
* WARNING: UP build assumes that scratch register is not used.
|
|
* There is only one scratch register available in
|
|
* excEnterCommon
|
|
*/
|
|
|
|
/* place the address of label into register r */
|
|
#define _ARM_PER_CPU_ADRS_GET(r, scratch, label) \
|
|
LDR r, L$_##label
|
|
|
|
/* place the value at label into register r */
|
|
#define _ARM_PER_CPU_VALUE_GET(r, scratch, label) \
|
|
LDR r, L$_##label ; \
|
|
LDR r, [r]
|
|
|
|
/* place value at label in ra, also place address at label in rv */
|
|
#define _ARM_PER_CPU_VALUE_AND_ADRS_GET(rv,ra,label) \
|
|
LDR ra, L$_##label ; \
|
|
LDR rv, [ra]
|
|
|
|
|
|
/*
|
|
* In some configurations (e.g. Thumb-2) there are special restrictions on
|
|
* usage of the sp register. Also there appears to be a defect in some
|
|
* versions of the Wind River assembler related to similar use of the lr
|
|
* register. So use these macros for setting up sp or lr.
|
|
*/
|
|
|
|
# if (ARM_THUMB2)
|
|
/* place the address of label into register r */
|
|
#define _ARM_PER_CPU_ADRS_GET_SPLR(r_sp, scratch, label) \
|
|
LDR scratch, L$_##label ; \
|
|
MOV r_sp, scratch
|
|
|
|
/* place the value at label into register r */
|
|
#define _ARM_PER_CPU_VALUE_GET_SPLR(r_sp, scratch, label) \
|
|
LDR scratch, L$_##label ; \
|
|
LDR r_sp, [scratch]
|
|
|
|
# else /* (ARM_THUMB2) */
|
|
/* place the address of label into register r */
|
|
#define _ARM_PER_CPU_ADRS_GET_SPLR(r_sp, scratch, label) \
|
|
_ARM_PER_CPU_ADRS_GET(r_sp, scratch, label)
|
|
|
|
/* place the value at label into register r */
|
|
#define _ARM_PER_CPU_VALUE_GET_SPLR(r_sp, scratch, label) \
|
|
_ARM_PER_CPU_VALUE_GET(r_sp, scratch, label)
|
|
# endif /* (ARM_THUMB2) */
|
|
|
|
# endif /* _WRS_CONFIG_SMP */
|
|
#endif /* _ASMLANGUAGE */
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* __INCsmpArmPh */
|