/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */ /* * (C) 2008 by Argonne National Laboratory. * See COPYRIGHT in top-level directory. */ #ifndef OPA_GCC_PPC_H_INCLUDED #define OPA_GCC_PPC_H_INCLUDED /* these need to be aligned on an 8-byte boundary to work on a BG/P */ typedef struct { volatile int v OPA_ATTRIBUTE((aligned (8))); } OPA_int_t; typedef struct { void * volatile v OPA_ATTRIBUTE((aligned (8))); } OPA_ptr_t; #define OPA_INT_T_INITIALIZER(val_) { (val_) } #define OPA_PTR_T_INITIALIZER(val_) { (val_) } /* Aligned loads and stores are atomic. */ static _opa_inline int OPA_load_int(_opa_const OPA_int_t *ptr) { return ptr->v; } /* Aligned loads and stores are atomic. */ static _opa_inline void OPA_store_int(OPA_int_t *ptr, int val) { ptr->v = val; } /* Aligned loads and stores are atomic. */ static _opa_inline void *OPA_load_ptr(_opa_const OPA_ptr_t *ptr) { return ptr->v; } /* Aligned loads and stores are atomic. */ static _opa_inline void OPA_store_ptr(OPA_ptr_t *ptr, void *val) { ptr->v = val; } /* a useful link for PPC memory ordering issues: * http://www.rdrop.com/users/paulmck/scalability/paper/N2745r.2009.02.22a.html * * lwsync: orders L-L, S-S, L-S, but *not* S-L (i.e. gives x86-ish ordering) * eieio: orders S-S (but only for cacheable memory, not for MMIO) * sync: totally orders memops * isync: force all preceeding insns to appear complete before starting * subsequent insns, but w/o cumulativity (very confusing) */ /* helper macros */ #define OPA_ppc_lwsync_() __asm__ __volatile__ ( "lwsync" ::: "memory" ) #define OPA_ppc_hwsync_() __asm__ __volatile__ ( "sync" ::: "memory" ) #define OPA_ppc_eieio_() __asm__ __volatile__ ( "eieio" ::: "memory" ) #define OPA_write_barrier() OPA_ppc_eieio_() #define OPA_read_barrier() OPA_ppc_lwsync_() #define OPA_read_write_barrier() OPA_ppc_hwsync_() #define OPA_compiler_barrier() __asm__ __volatile__ ( "" ::: "memory" ) /* NOTE-PPC-1 we use lwsync, although I think we might be able to use * conditional-branch+isync in some cases (load_acquire?) once we understand it * better */ static _opa_inline int OPA_load_acquire_int(_opa_const OPA_int_t *ptr) { int tmp; tmp = ptr->v; OPA_ppc_lwsync_(); /* NOTE-PPC-1 */ return tmp; } static _opa_inline void OPA_store_release_int(OPA_int_t *ptr, int val) { OPA_ppc_lwsync_(); ptr->v = val; } static _opa_inline void *OPA_load_acquire_ptr(_opa_const OPA_ptr_t *ptr) { void *tmp; tmp = ptr->v; OPA_ppc_lwsync_(); /* NOTE-PPC-1 */ return tmp; } static _opa_inline void OPA_store_release_ptr(OPA_ptr_t *ptr, void *val) { OPA_ppc_lwsync_(); ptr->v = val; } /* load-link/store-conditional (LL/SC) primitives. We LL/SC implement these here, which are arch-specific, then use the generic implementations from opa_emulated.h */ static _opa_inline int OPA_LL_int(OPA_int_t *ptr) { int val; __asm__ __volatile__ ("lwarx %[val],0,%[ptr]" : [val] "=r" (val) : [ptr] "r" (&ptr->v) : "cc"); return val; } /* Returns non-zero if the store was successful, zero otherwise. */ static _opa_inline int OPA_SC_int(OPA_int_t *ptr, int val) { int ret = 1; /* init to non-zero, will be reset to 0 if SC was unsuccessful */ __asm__ __volatile__ ("stwcx. %[val],0,%[ptr];\n" "beq 1f;\n" "li %[ret], 0;\n" "1: ;\n" : [ret] "=r" (ret) : [ptr] "r" (&ptr->v), [val] "r" (val), "0" (ret) : "cc", "memory"); return ret; } /* Pointer versions of LL/SC. */ /* Set OPA_SS (Size Suffix) which is used to choose between lwarx/stwcx and * ldarx/stdcx when using 4 or 8 byte pointer operands */ #if OPA_SIZEOF_VOID_P == 4 #define OPA_SS "w" #elif OPA_SIZEOF_VOID_P == 8 #define OPA_SS "d" #else #error OPA_SIZEOF_VOID_P is not 4 or 8 #endif static _opa_inline void *OPA_LL_ptr(OPA_ptr_t *ptr) { void *val; __asm__ __volatile__ ("l"OPA_SS"arx %[val],0,%[ptr]" : [val] "=r" (val) : [ptr] "r" (&ptr->v) : "cc"); return val; } /* Returns non-zero if the store was successful, zero otherwise. */ static _opa_inline int OPA_SC_ptr(OPA_ptr_t *ptr, void *val) { int ret = 1; /* init to non-zero, will be reset to 0 if SC was unsuccessful */ __asm__ __volatile__ ("st"OPA_SS"cx. %[val],0,%[ptr];\n" "beq 1f;\n" "li %[ret], 0;\n" "1: ;\n" : [ret] "=r" (ret) : [ptr] "r" (&ptr->v), [val] "r" (val), "0" (ret) : "cc", "memory"); return ret; } #undef OPA_SS /* necessary to enable LL/SC emulation support */ #define OPA_LL_SC_SUPPORTED 1 /* Implement all function using LL/SC */ #define OPA_add_int_by_llsc OPA_add_int #define OPA_incr_int_by_llsc OPA_incr_int #define OPA_decr_int_by_llsc OPA_decr_int #define OPA_decr_and_test_int_by_llsc OPA_decr_and_test_int #define OPA_fetch_and_add_int_by_llsc OPA_fetch_and_add_int #define OPA_fetch_and_decr_int_by_llsc OPA_fetch_and_decr_int #define OPA_fetch_and_incr_int_by_llsc OPA_fetch_and_incr_int #define OPA_cas_ptr_by_llsc OPA_cas_ptr #define OPA_cas_int_by_llsc OPA_cas_int #define OPA_swap_ptr_by_llsc OPA_swap_ptr #define OPA_swap_int_by_llsc OPA_swap_int #include "opa_emulated.h" #endif /* OPA_GCC_PPC_H_INCLUDED */