From f2f211c543d97813bda5331cbf9796db18f62c33 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 31 May 2013 13:59:34 +0200 Subject: smp: Add ARM support --- cpukit/aclocal/enable-smp.m4 | 2 +- cpukit/score/cpu/arm/Makefile.am | 1 + cpukit/score/cpu/arm/arm_exc_interrupt.S | 35 ++++++++- cpukit/score/cpu/arm/cpu_asm.S | 3 + cpukit/score/cpu/arm/preinstall.am | 4 + cpukit/score/cpu/arm/rtems/score/cpu.h | 38 ++++++++++ cpukit/score/cpu/arm/rtems/score/cpusmplock.h | 101 ++++++++++++++++++++++++++ 7 files changed, 181 insertions(+), 3 deletions(-) create mode 100644 cpukit/score/cpu/arm/rtems/score/cpusmplock.h (limited to 'cpukit') diff --git a/cpukit/aclocal/enable-smp.m4 b/cpukit/aclocal/enable-smp.m4 index d2a35653b6..0c29a068ab 100644 --- a/cpukit/aclocal/enable-smp.m4 +++ b/cpukit/aclocal/enable-smp.m4 @@ -6,7 +6,7 @@ AC_ARG_ENABLE(smp, [AS_HELP_STRING([--enable-smp],[enable smp interface])], [case "${enableval}" in yes) case "${RTEMS_CPU}" in - powerpc|sparc|i386) RTEMS_HAS_SMP=yes ;; + arm|powerpc|sparc|i386) RTEMS_HAS_SMP=yes ;; *) RTEMS_HAS_SMP=no ;; esac ;; diff --git a/cpukit/score/cpu/arm/Makefile.am b/cpukit/score/cpu/arm/Makefile.am index 46ce58c1b5..edd72480bd 100644 --- a/cpukit/score/cpu/arm/Makefile.am +++ b/cpukit/score/cpu/arm/Makefile.am @@ -10,6 +10,7 @@ include_rtems_score_HEADERS += rtems/score/armv4.h include_rtems_score_HEADERS += rtems/score/armv7m.h include_rtems_score_HEADERS += rtems/score/types.h include_rtems_score_HEADERS += rtems/score/cpuatomic.h +include_rtems_score_HEADERS += rtems/score/cpusmplock.h noinst_LIBRARIES = libscorecpu.a libscorecpu_a_CPPFLAGS = $(AM_CPPFLAGS) diff --git a/cpukit/score/cpu/arm/arm_exc_interrupt.S b/cpukit/score/cpu/arm/arm_exc_interrupt.S index 708af229f1..8bcd03e8a6 100644 --- a/cpukit/score/cpu/arm/arm_exc_interrupt.S +++ b/cpukit/score/cpu/arm/arm_exc_interrupt.S @@ -90,6 +90,38 @@ _ARMV4_Exception_interrupt: str r0, [r1] #endif +#ifdef RTEMS_SMP + /* ISR enter */ + blx _ISR_SMP_Enter + + /* Remember INT stack pointer */ + mov r1, EXCHANGE_INT_SP + + /* Restore exchange registers from exchange area */ + ldmia r1, EXCHANGE_LIST + + /* Switch stack if necessary and save original stack pointer */ + mov r2, sp + cmp r0, #0 + moveq sp, r1 + stmdb sp!, {r2} + + /* Call BSP dependent interrupt dispatcher */ + blx bsp_interrupt_dispatch + + /* Restore stack pointer */ + ldr sp, [sp] + + /* ISR exit */ + blx _ISR_SMP_Exit + cmp r0, #0 + beq thread_dispatch_done + + /* Thread dispatch */ + blx _Thread_Dispatch + +thread_dispatch_done: +#else /* RTEMS_SMP */ /* Remember INT stack pointer */ mov r1, EXCHANGE_INT_SP @@ -150,8 +182,6 @@ _ARMV4_Exception_interrupt: nop #endif /* __thumb__ */ -do_thread_dispatch: - /* Thread dispatch */ bl _Thread_Dispatch @@ -159,6 +189,7 @@ thread_dispatch_done: /* Switch to ARM instructions if necessary */ SWITCH_FROM_THUMB_TO_ARM +#endif /* RTEMS_SMP */ #ifdef ARM_MULTILIB_VFP_D32 /* Restore VFP context */ diff --git a/cpukit/score/cpu/arm/cpu_asm.S b/cpukit/score/cpu/arm/cpu_asm.S index af8f1531b6..0a91836fe5 100644 --- a/cpukit/score/cpu/arm/cpu_asm.S +++ b/cpukit/score/cpu/arm/cpu_asm.S @@ -64,6 +64,9 @@ DEFINE_FUNCTION_ARM(_CPU_Context_switch) /* Start restoring context */ _restore: +#ifdef RTEMS_SMP + clrex +#endif #ifdef ARM_MULTILIB_VFP_D32 add r3, r1, #ARM_CONTEXT_CONTROL_D8_OFFSET diff --git a/cpukit/score/cpu/arm/preinstall.am b/cpukit/score/cpu/arm/preinstall.am index 4213c552ab..5c9c821ed1 100644 --- a/cpukit/score/cpu/arm/preinstall.am +++ b/cpukit/score/cpu/arm/preinstall.am @@ -55,3 +55,7 @@ $(PROJECT_INCLUDE)/rtems/score/cpuatomic.h: rtems/score/cpuatomic.h $(PROJECT_IN $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/cpuatomic.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/cpuatomic.h +$(PROJECT_INCLUDE)/rtems/score/cpusmplock.h: rtems/score/cpusmplock.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/cpusmplock.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/cpusmplock.h + diff --git a/cpukit/score/cpu/arm/rtems/score/cpu.h b/cpukit/score/cpu/arm/rtems/score/cpu.h index e606146cb7..7020261619 100644 --- a/cpukit/score/cpu/arm/rtems/score/cpu.h +++ b/cpukit/score/cpu/arm/rtems/score/cpu.h @@ -439,6 +439,44 @@ void _CPU_Context_volatile_clobber( uintptr_t pattern ); void _CPU_Context_validate( uintptr_t pattern ); +#ifdef RTEMS_SMP + #define _CPU_Context_switch_to_first_task_smp( _context ) \ + _CPU_Context_restore( _context ) + + static inline void _ARM_Data_memory_barrier( void ) + { + __asm__ volatile ( "dmb" : : : "memory" ); + } + + static inline void _ARM_Data_synchronization_barrier( void ) + { + __asm__ volatile ( "dsb" : : : "memory" ); + } + + static inline void _ARM_Send_event( void ) + { + __asm__ volatile ( "sev" : : : "memory" ); + } + + static inline void _ARM_Wait_for_event( void ) + { + __asm__ volatile ( "wfe" : : : "memory" ); + } + + static inline void _CPU_Processor_event_broadcast( void ) + { + _ARM_Data_synchronization_barrier(); + _ARM_Send_event(); + } + + static inline void _CPU_Processor_event_receive( void ) + { + _ARM_Wait_for_event(); + _ARM_Data_memory_barrier(); + } +#endif + + static inline uint32_t CPU_swap_u32( uint32_t value ) { #if defined(__thumb2__) diff --git a/cpukit/score/cpu/arm/rtems/score/cpusmplock.h b/cpukit/score/cpu/arm/rtems/score/cpusmplock.h new file mode 100644 index 0000000000..46592f432b --- /dev/null +++ b/cpukit/score/cpu/arm/rtems/score/cpusmplock.h @@ -0,0 +1,101 @@ +/** + * @file + * + * @ingroup ScoreSMPLockARM + * + * @brief ARM SMP Lock Implementation + */ + +/* + * Copyright (c) 2013 embedded brains GmbH + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#ifndef _RTEMS_SCORE_ARM_SMPLOCK_H +#define _RTEMS_SCORE_ARM_SMPLOCK_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup ScoreSMPLockARM ARM SMP Locks + * + * @ingroup ScoreSMPLock + * + * A ticket lock implementation is used. + * + * @{ + */ + +typedef struct { + uint32_t next_ticket; + uint32_t now_serving; +} CPU_SMP_lock_Control; + +#define CPU_SMP_LOCK_INITIALIZER { 0, 0 } + +static inline void _CPU_SMP_lock_Initialize( CPU_SMP_lock_Control *lock ) +{ + lock->next_ticket = 0; + lock->now_serving = 0; +} + +static inline void _CPU_SMP_lock_Acquire( CPU_SMP_lock_Control *lock ) +{ + uint32_t my_ticket; + uint32_t next_ticket; + uint32_t status; + + __asm__ volatile ( + "1: ldrex %[my_ticket], [%[next_ticket_addr]]\n" + "add %[next_ticket], %[my_ticket], #1\n" + "strex %[status], %[next_ticket], [%[next_ticket_addr]]\n" + "teq %[status], #0\n" + "bne 1b" + : [my_ticket] "=&r" (my_ticket), + [next_ticket] "=&r" (next_ticket), + [status] "=&r" (status) + : [next_ticket_addr] "r" (&lock->next_ticket) + : "cc", "memory" + ); + + while ( my_ticket != lock->now_serving ) { + _ARM_Wait_for_event(); + } + + _ARM_Data_memory_barrier(); +} + +static inline void _CPU_SMP_lock_Release( CPU_SMP_lock_Control *lock ) +{ + _ARM_Data_memory_barrier(); + ++lock->now_serving; + _ARM_Data_synchronization_barrier(); + _ARM_Send_event(); +} + +#define _CPU_SMP_lock_ISR_disable_and_acquire( lock, isr_cookie ) \ + do { \ + _CPU_ISR_Disable( isr_cookie ); \ + _CPU_SMP_lock_Acquire( lock ); \ + } while (0) + +#define _CPU_SMP_lock_Release_and_ISR_enable( lock, isr_cookie ) \ + do { \ + _CPU_SMP_lock_Release( lock ); \ + _CPU_ISR_Enable( isr_cookie ); \ + } while (0) + +/**@}*/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _RTEMS_SCORE_ARM_SMPLOCK_H */ -- cgit v1.2.3