mirror of
				https://github.com/0xFEEDC0DE64/arduino-esp32.git
				synced 2025-10-31 22:21:39 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			790 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			790 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /* Customer ID=11656; Build=0x5f626; Copyright (c) 2008-2009 by Tensilica Inc.  ALL RIGHTS RESERVED.
 | |
|    These coded instructions, statements, and computer programs are the
 | |
|    copyrighted works and confidential proprietary information of Tensilica Inc.
 | |
|    They may not be modified, copied, reproduced, distributed, or disclosed to
 | |
|    third parties in any manner, medium, or form, in whole or in part, without
 | |
|    the prior written consent of Tensilica Inc.  */
 | |
| 
 | |
| #ifndef _XMP_LIBRARY_H
 | |
| #define _XMP_LIBRARY_H
 | |
| 
 | |
| #ifdef __cplusplus
 | |
| extern "C" {
 | |
| #endif
 | |
| 
 | |
| #include <xtensa/config/core-isa.h>
 | |
| #include <xtensa/config/core.h>
 | |
| #include <xtensa/tie/xt_core.h>
 | |
| #if XCHAL_HAVE_RELEASE_SYNC
 | |
| #include <xtensa/tie/xt_sync.h>
 | |
| #endif
 | |
| #if XCHAL_HAVE_EXTERN_REGS
 | |
| #include <xtensa/xtensa-xer.h>
 | |
| #endif
 | |
| #include <stdlib.h>
 | |
| #include <stdio.h>
 | |
| 
 | |
| #include "xtensa/system/mpsystem.h"
 | |
| 
 | |
| /* 
 | |
|    W A R N I N G:
 | |
| 
 | |
|    xmp library clients should treat all data structures in this file
 | |
|    as opaque.  They are only public to enable users to declare them
 | |
|    statically.
 | |
| */
 | |
| 
 | |
| 
 | |
| /* -------------------------------------------------------------------------
 | |
|    When using XMP on cache-incoherent systems, these macros are helpful
 | |
|    to ensure that you are not reading stale data, and to ensure that
 | |
|    the data you write makes it all the way back to main memory.
 | |
|  */
 | |
| 
 | |
| #if !XCHAL_DCACHE_IS_COHERENT
 | |
| #define XMP_WRITE_BACK_ELEMENT(x) xthal_dcache_region_writeback((void *)x, sizeof(*x))
 | |
| #define XMP_INVALIDATE_ELEMENT(x) xthal_dcache_region_invalidate((void *)x, sizeof(*x))
 | |
| #define XMP_WRITE_BACK_INVALIDATE_ELEMENT(x) xthal_dcache_region_writeback_inv((void *)x, sizeof(*x))
 | |
| #define XMP_WRITE_BACK_ARRAY(x) xthal_dcache_region_writeback((void *)x, sizeof(x))
 | |
| #define XMP_INVALIDATE_ARRAY(x) xthal_dcache_region_invalidate((void *)x, sizeof(x))
 | |
| #define XMP_WRITE_BACK_INVALIDATE_ARRAY(x) xthal_dcache_region_writeback_inv((void *)x, sizeof(x))
 | |
| #define XMP_WRITE_BACK_ARRAY_ELEMENTS(x, num_elements) xthal_dcache_region_writeback((void *)x, sizeof(*x) * num_elements)
 | |
| #define XMP_INVALIDATE_ARRAY_ELEMENTS(x, num_elements) xthal_dcache_region_invalidate((void *)x, sizeof(*x) * num_elements)
 | |
| #define XMP_WRITE_BACK_INVALIDATE_ARRAY_ELEMENTS(x, num_elements) xthal_dcache_region_writeback_inv((void *)x, sizeof(*x) * num_elements)
 | |
| #else 
 | |
| #define XMP_WRITE_BACK_ELEMENT(x)
 | |
| #define XMP_INVALIDATE_ELEMENT(x)
 | |
| #define XMP_WRITE_BACK_INVALIDATE_ELEMENT(x)
 | |
| #define XMP_WRITE_BACK_ARRAY(x)
 | |
| #define XMP_INVALIDATE_ARRAY(x)
 | |
| #define XMP_WRITE_BACK_INVALIDATE_ARRAY(x)
 | |
| #define XMP_WRITE_BACK_ARRAY_ELEMENTS(x, num_elements)
 | |
| #define XMP_INVALIDATE_ARRAY_ELEMENTS(x, num_elements)
 | |
| #define XMP_WRITE_BACK_INVALIDATE_ARRAY_ELEMENTS(x, num_elements)
 | |
| #endif
 | |
| 
 | |
| /* -------------------------------------------------------------------------
 | |
|    Initialization, error codes, constants and house-keeping
 | |
| 
 | |
|    Every core should call xmp_init with the number of cores in the
 | |
|    system.
 | |
| 
 | |
|    xmp_init should be called before you use any global synchronization
 | |
|    primitive or shared data. 
 | |
| 
 | |
|    Further, before you use a dynamically allocated synchronization
 | |
|    primitives, you need to both initialize it by calling the
 | |
|    xmp_*_init function, and you need to have called xmp_init, which
 | |
|    sets up interrupt handlers and interrupt routing.
 | |
| 
 | |
|    The second parameter sets the interprocessor interrupt
 | |
|    routing. Passing zero instructs the library to use the default
 | |
|    routing, which will be suitable for most users.
 | |
|    
 | |
| */
 | |
|    
 | |
| extern void xmp_init (int num_cores, unsigned int interrupt_routing);
 | |
| 
 | |
| 
 | |
| /* If you want finer-grained control than that provided by xmp_init,
 | |
|    you can the functions below individually--however, this is more
 | |
|    inconvenient and requires greater understanding of the library's
 | |
|    internals.  Don't use them directly unless you have a good reason.
 | |
| */
 | |
| 
 | |
| extern void xmp_unpack_shared (void);
 | |
| extern void xmp_route_interrupts (unsigned int routing);
 | |
| 
 | |
| #if XCHAL_HAVE_MP_INTERRUPTS
 | |
| extern void xmp_enable_ipi_interrupts (void);
 | |
| 
 | |
| /* Turn off certain things enabled by xmp_init  */
 | |
| extern void xmp_disable_ipi_interrupts (void);
 | |
| #endif
 | |
| 
 | |
| extern void xmp_end (void);
 | |
| 
 | |
| /* Only valid after xmp_init.  */
 | |
| extern int xmp_num_cores (void);
 | |
| 
 | |
| /* How many cycles should a core wait before rechecking a
 | |
|    synchronization variable?  Higher values will reduce memory
 | |
|    transactions, but will also result in higher latency in returning
 | |
|    from synchronization.
 | |
| */
 | |
| extern void xmp_spin_wait_set_cycles (unsigned int limit);
 | |
| 
 | |
| /* If you would prefer to provide your own spin wait function,
 | |
|    to go to sleep, etc.  Declare a function of this type, then call
 | |
|    this function.  */
 | |
| typedef void (*xmp_spin_wait_function_t)(void);
 | |
| extern void xmp_spin_wait_set_function (xmp_spin_wait_function_t func);
 | |
| extern void xmp_spin(void);
 | |
| 
 | |
| #define XMP_NO_OWNER        0x07
 | |
| #define XMP_MUTEX_DESTROYED 0xFE
 | |
| #define XMP_ERROR_FATAL     0xFD
 | |
| 
 | |
| #define XMP_MAX_CORES       0x4
 | |
| 
 | |
| 
 | |
| static inline unsigned int xmp_prid (void) 
 | |
| {
 | |
| #if XCHAL_HAVE_PRID
 | |
|   return XT_RSR_PRID() & 0xFF;
 | |
| #else
 | |
|   return 0;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| 
 | |
| /* -------------------------------------------------------------------------
 | |
|    Tracing
 | |
|    
 | |
|    A core must set a trace_file if it wants any synchronization
 | |
|    tracing to occur.  Sharing file descriptors among cores is very
 | |
|    messy, so don't do it.  This, unfortunately, means that two cores
 | |
|    contending for a mutex are not able to trace to the same file.
 | |
| 
 | |
|    Any object (except the atomic integer) can have tracing off or on.   
 | |
| */
 | |
| 
 | |
| extern void xmp_set_trace_file (FILE * file);
 | |
| extern void xmp_trace (const char * fmt, ...);
 | |
| 
 | |
| 
 | |
| /* -------------------------------------------------------------------------
 | |
|    Memory Allocation Functions.
 | |
| 
 | |
|    These do what you would expect, only from shared memory instead of
 | |
|    private memory.
 | |
| */
 | |
| 
 | |
| #if XCHAL_DCACHE_IS_COHERENT
 | |
| extern void * xmp_malloc (size_t size);
 | |
| extern void * xmp_calloc (size_t nmemb, size_t size);
 | |
| extern void xmp_free (void * ptr);
 | |
| #endif
 | |
| extern void * xmp_sbrk(int size);
 | |
| 
 | |
| /* -------------------------------------------------------------------------
 | |
|    xmp_atomic_int_t
 | |
| 
 | |
|    The most basic synchronization primitive in the xmp library.
 | |
|    Atomic ints are sharable among processors, and even interrupt
 | |
|    levels on the same processor. However, their semantics are fairly
 | |
|    rudimentary.  All other primitives are based on these, therefore,
 | |
|    changing this implementation affects all other primitives.
 | |
| 
 | |
| */
 | |
| 
 | |
| typedef unsigned int xmp_atomic_int_t;
 | |
| 
 | |
| static inline xmp_atomic_int_t
 | |
| xmp_coherent_l32ai(xmp_atomic_int_t * address)
 | |
| {
 | |
|   XMP_INVALIDATE_ELEMENT (address);
 | |
|   return  XT_L32AI(address, 0);
 | |
| }
 | |
| 
 | |
| static inline void
 | |
| xmp_coherent_s32ri(xmp_atomic_int_t value, xmp_atomic_int_t  * address)
 | |
| {
 | |
|   XT_S32RI (value, address, 0);
 | |
|   XMP_WRITE_BACK_ELEMENT (address);
 | |
| }
 | |
| 
 | |
| #define XMP_ATOMIC_INT_INITIALIZER(value) (value)
 | |
| 
 | |
| /* xmp_atomic_int_init - Initialize an int prior to use
 | |
| 
 | |
|    Nonsynchronizing, Nonblocking 
 | |
| 
 | |
|    Usage: 
 | |
|       value - initial value
 | |
|       integer - points to an uninitialized integer
 | |
| 
 | |
|    On exit:
 | |
|       initialized to given value
 | |
| 
 | |
|    Errors: none
 | |
| */
 | |
| 
 | |
| static inline void 
 | |
| xmp_atomic_int_init (xmp_atomic_int_t * integer, int value)
 | |
| {
 | |
|   xmp_coherent_s32ri (value, integer);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* xmp_atomic_int_value - Read the value 
 | |
| 
 | |
|    Nonsynchronizing, Nonblocking
 | |
| 
 | |
|    Usage: 
 | |
|       integer - points to an int
 | |
| 
 | |
|    Returns:
 | |
|       the value
 | |
| */
 | |
| 
 | |
| static inline int
 | |
| xmp_atomic_int_value (xmp_atomic_int_t * integer)
 | |
| {
 | |
|   return xmp_coherent_l32ai (integer);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* xmp_atomic_int_conditional_increment - Conditionally increment integer
 | |
| 
 | |
|    Synchronizing, nonblocking
 | |
| 
 | |
|    Usage: 
 | |
|       integer - points to an initialized integer
 | |
|       amount - how much to increment
 | |
|       prev - believed value of the integer
 | |
|                 eg: prev = xmp_atomic_int_value (integer);
 | |
|                     success = xmp_atomic_int_increment (integer, 1, prev);
 | |
| 
 | |
|    Returns: current value of integer - user should check if it matches
 | |
|       the previous value of the integer. If it does, then the update
 | |
|       was successful.
 | |
| 
 | |
| */
 | |
| 
 | |
| #define USE_ASSEMBLY_IMPLEMENTATION 0
 | |
| 
 | |
| static inline int
 | |
| xmp_atomic_int_conditional_increment (xmp_atomic_int_t * integer, int amount, int prev)
 | |
| {
 | |
|   int val;
 | |
|   int saved;
 | |
| 
 | |
| #if USE_ASSEMBLY_IMPLEMENTATION
 | |
|   /* %0 = prev
 | |
|      %1 = saved
 | |
|      %2 = atomic integer pointer
 | |
|      %3 = amount
 | |
|   */
 | |
| 
 | |
|   asm volatile ("wsr.scompare1 %0\n"
 | |
| 		"mov %1, %0\n"
 | |
| 		"add %0, %0, %3\n"
 | |
| 		"s32c1i %0, %2, 0\n"
 | |
| 		: "+&a" (prev), "+&a"(saved) : "a" (integer), "a" (amount));
 | |
| 
 | |
|   return prev;
 | |
| 
 | |
| #else
 | |
| 
 | |
|   XT_WSR_SCOMPARE1 (prev);
 | |
|   val = prev + amount;
 | |
|   saved = val;
 | |
|   XT_S32C1I (val, integer, 0);
 | |
| 
 | |
|   return val;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| 
 | |
| /* xmp_atomic_int_increment - Increment integer
 | |
| 
 | |
|    Synchronizing, blocking
 | |
| 
 | |
|    Usage: 
 | |
|       integer - points to an initialized integer
 | |
|       amount - how much to increment
 | |
| 
 | |
|    Returns: new value of integer
 | |
| 
 | |
| */
 | |
| 
 | |
| static inline int
 | |
| xmp_atomic_int_increment (xmp_atomic_int_t * integer, int amount)
 | |
| {
 | |
|   int val;
 | |
|   int saved;
 | |
| #if USE_ASSEMBLY_IMPLEMENTATION
 | |
|   /* %0 = val
 | |
|      %1 = saved
 | |
|      %2 = atomic integer pointer
 | |
|      %3 = amount
 | |
|   */
 | |
|      
 | |
|   asm volatile ("l32ai %0, %2, 0\n"
 | |
| 		"1:\n"
 | |
| 		"wsr.scompare1 %0\n"
 | |
| 		"mov %1, %0\n"
 | |
| 		"add %0, %0, %3\n"
 | |
| 		"s32c1i %0, %2, 0\n"
 | |
| 		"bne %0, %1, 1b\n" 
 | |
| 		: "+&a" (val), "+&a"(saved) : "a" (integer), "a" (amount));
 | |
| #else
 | |
|   /* Accurately naming "val" is tricky. Sometimes it will be what we
 | |
|      want to be the new value, but sometimes it contains the value
 | |
|      that is currently at the location.  */
 | |
|   
 | |
|   /* Load location's current value  */
 | |
|   val = xmp_coherent_l32ai (integer);
 | |
| 
 | |
|   do {
 | |
|     XT_WSR_SCOMPARE1 (val);
 | |
|     saved = val;
 | |
|     /* Change it to what we would like to store there--"new_val"  */
 | |
|     val = val + amount;
 | |
|     /* Possibly store new_val, but reload location's current value no
 | |
|        matter what. */
 | |
|     XT_S32C1I (val, integer, 0);
 | |
|     if (val != saved)
 | |
|       xmp_spin();
 | |
|   } while (val != saved);
 | |
| 
 | |
| #endif
 | |
|   return val + amount;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* xmp_atomic_int_conditional_set - Set the value of an atomic integer
 | |
| 
 | |
|    Synchronizing, nonblocking
 | |
| 
 | |
|    Usage: 
 | |
|       integer - points to an initialized integer
 | |
|       from - believed value of the integer
 | |
|                 eg: prev = xmp_atomic_int_value (integer);
 | |
|                     success = xmp_atomic_int_conditional_set (integer, 1, prev);
 | |
|       to - new value
 | |
| 
 | |
|    Returns: current value of integer - user should check if it matches
 | |
|       the previous value of the integer. If it does, then the update
 | |
|       was successful.
 | |
| 
 | |
| */
 | |
| 
 | |
| static inline int
 | |
| xmp_atomic_int_conditional_set (xmp_atomic_int_t * integer, int from, int to)
 | |
| {
 | |
|   int val;
 | |
| 
 | |
|   /* Don't even try to update if the integer's value isn't what we
 | |
|      think it should be.  This prevents acquiring this cache-line for
 | |
|      writing and therefore prevents bus transactions when various
 | |
|      cores contend.  */
 | |
|   val = xmp_coherent_l32ai(integer);
 | |
|   if (val == from) {
 | |
|     XT_WSR_SCOMPARE1 (from);
 | |
|     val = to;
 | |
|     /* Possibly store to, but reload location's current value no
 | |
|        matter what. */
 | |
|     XT_S32C1I (val, integer, 0);
 | |
|   }
 | |
|   return val;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Macros to implement trivial spin locks.  These are very primitive, but
 | |
|    can be useful when you don't need the higher-overhead synchronization.
 | |
| 
 | |
|    To use an xmp_atomic_int_t as a trivial spin lock, you should
 | |
|    initialize it to zero first.
 | |
| */
 | |
| 
 | |
| #define XMP_SIMPLE_SPINLOCK_ACQUIRE(atomic_int_ptr)	\
 | |
|   { while (xmp_atomic_int_conditional_set (atomic_int_ptr, 0, xmp_prid() + 1) != 0) \
 | |
|       xmp_spin(); }
 | |
| #define XMP_SIMPLE_SPINLOCK_RELEASE(atomic_int_ptr)	\
 | |
|   { while (xmp_atomic_int_conditional_set (atomic_int_ptr, xmp_prid() + 1, 0) != xmp_prid() + 1) \
 | |
|     xmp_spin(); }
 | |
| 
 | |
| #define XMP_SIMPLE_SPINLOCK_OWNER(atomic_int_ptr) (xmp_atomic_int_value(atomic_int_ptr) - 1)
 | |
| 
 | |
| 
 | |
| /* -------------------------------------------------------------------------
 | |
|    xmp_mutex_t - An even higher-level data structure to enforce
 | |
|    mutual exclusion between cores.  A core which waits on a mutex might
 | |
|    sleep with a waiti and be interrupted by an interrupt.
 | |
| 
 | |
|    Mutexes can be normal or recursive. For a normal mutex, a core
 | |
|    attempting to acquire a mutex it already holds will result in
 | |
|    deadlock. For a recursive mutex, a core will succeed in acquiring a
 | |
|    mutex it already holds, and must release it as many times as it
 | |
|    acquired it.
 | |
| 
 | |
|    Mutexes are not sharable between interrupt levels--because
 | |
|    ownership is tracked by core, not thread.
 | |
| 
 | |
|    Like all xmp data structures, an object of type xmp_mutex_t
 | |
|    should be treated by the programmer as opaque.  They are only
 | |
|    public in this header file to allow them to be declared statically.
 | |
| 
 | |
|    For configurations with 16-byte cache lines, this has the most
 | |
|    frequently used and changed data in the first line.
 | |
| 
 | |
| */
 | |
| 
 | |
| #if XCHAL_DCACHE_IS_COHERENT
 | |
| typedef struct xmp_mutex_t {
 | |
|   xmp_atomic_int_t qlock;
 | |
|   unsigned int qhead;
 | |
|   unsigned int qtail;
 | |
|   unsigned char queue[XMP_MAX_CORES];
 | |
|   unsigned short held;
 | |
| 
 | |
|   unsigned char owner;
 | |
|   unsigned char recursive : 1;
 | |
|   unsigned char trace : 1;
 | |
|   unsigned char system : 1;
 | |
|   unsigned char unused : 5;
 | |
|   const char * name;
 | |
| } xmp_mutex_t __attribute__ ((aligned (XMP_MAX_DCACHE_LINESIZE)));
 | |
| 
 | |
| 
 | |
| #define XMP_MUTEX_INITIALIZER(name)					\
 | |
|   { 0, 0, -1, {XMP_NO_OWNER, XMP_NO_OWNER, XMP_NO_OWNER, XMP_NO_OWNER}, \
 | |
|       0, XMP_NO_OWNER, XMP_MUTEX_FLAG_NORMAL, 0, 0, 0, name }
 | |
| 
 | |
| #define XMP_RECURSIVE_MUTEX_INITIALIZER(name)				\
 | |
|   { 0, 0, -1, {XMP_NO_OWNER, XMP_NO_OWNER, XMP_NO_OWNER, XMP_NO_OWNER}, \
 | |
|       0, XMP_NO_OWNER, XMP_MUTEX_FLAG_RECURSIVE, 0, 0, 0, name }
 | |
| 
 | |
| #define XMP_MUTEX_FLAG_NORMAL 0
 | |
| #define XMP_MUTEX_FLAG_RECURSIVE 1
 | |
| 
 | |
| #define XMP_MUTEX_ACQUIRE_FAILED -1
 | |
| #define XMP_MUTEX_ERROR_DESTROY_OWNED -2
 | |
| #define XMP_MUTEX_ERROR_NOT_OWNED -3
 | |
| #define XMP_MUTEX_ERROR_ALREADY_OWNED -4
 | |
| 
 | |
| /*
 | |
|    xmp_mutex_init
 | |
|    
 | |
|    Nonsynchronizing
 | |
|    Nonblocking 
 | |
| 
 | |
|    Usage: 
 | |
|       mutex - points to an uninitialized mutex
 | |
|       name - name if you want one, NULL if not.
 | |
|       recursive - use recursive semantices      
 | |
| 
 | |
|    Returns
 | |
|       zero on success (always succeeds)
 | |
| 
 | |
| */
 | |
| 
 | |
| extern int xmp_mutex_init (xmp_mutex_t * mutex, 
 | |
| 			    const char * name, 
 | |
| 			    unsigned int recursive);
 | |
| 
 | |
| /*
 | |
|    int xmp_mutex_destroy (xmp_mutex_t * mutex);
 | |
|    
 | |
|    Synchronizing - will fail if mutex is held by anyone -- including 
 | |
|                    current processor
 | |
|    Nonblocking 
 | |
| 
 | |
|    Usage: 
 | |
|       mutex - points to a mutex
 | |
| 
 | |
|    Returns
 | |
|       zero on success
 | |
|       non-zero if mutex is held
 | |
| */
 | |
| 
 | |
| extern int xmp_mutex_destroy (xmp_mutex_t * mutex);
 | |
| 
 | |
| 
 | |
| /*
 | |
|    xmp_mutex_lock -- Synchronizing
 | |
|    xmp_mutex_trylock
 | |
| 
 | |
|    Usage: 
 | |
|       mutex - points to a mutex
 | |
| 
 | |
|    Returns
 | |
|       zero on success
 | |
| */
 | |
| 
 | |
| extern int xmp_mutex_lock (xmp_mutex_t * mutex);
 | |
| extern int xmp_mutex_trylock (xmp_mutex_t * mutex);
 | |
| 
 | |
| 
 | |
| /*
 | |
|    xmp_mutex_unlock
 | |
|    
 | |
|    Synchronizing
 | |
|    Nonblocking 
 | |
| 
 | |
|    Usage: 
 | |
|       mutex - points to a mutex
 | |
| 
 | |
|    Returns
 | |
|       zero on success - mutex is released
 | |
|       non-zero on failure - mutex is owned by another core 
 | |
|                           - prid of processor that does own it
 | |
| 			    note that by the time this function
 | |
| 			    returns, the owner of the core may 
 | |
| 			    have changed.
 | |
| */
 | |
| 
 | |
| extern int xmp_mutex_unlock (xmp_mutex_t * mutex);
 | |
| 
 | |
| 
 | |
| /*
 | |
|    xmp_mutex_name
 | |
|    
 | |
|    Nonsynchronizing
 | |
|    Nonblocking 
 | |
| 
 | |
|    Usage: 
 | |
|       mutex - points to a mutex
 | |
| 
 | |
|    Returns the name of the given mutex, which may be NULL.
 | |
|       
 | |
| */
 | |
| 
 | |
| const char * xmp_mutex_name (const xmp_mutex_t * mutex);
 | |
| 
 | |
| 
 | |
| /* 
 | |
|    xmp_mutex_trace_on
 | |
|    xmp_mutex_trace_off
 | |
| 
 | |
|    Nonsynchronizing
 | |
|    Nonblocking
 | |
| 
 | |
|    Turn off and on tracing for the mutex.
 | |
| 
 | |
|    These functions are only present in the debug version of the library.
 | |
| */
 | |
| 
 | |
| extern void xmp_mutex_trace_on (xmp_mutex_t * mutex);
 | |
| extern void xmp_mutex_trace_off (xmp_mutex_t * mutex);
 | |
| 
 | |
| 
 | |
| /* -------------------------------------------------------------------------
 | |
|    xmp_condition_t
 | |
| 
 | |
|    Condition Variables following Mesa semantics. 
 | |
| 
 | |
|    Condition variables are not sharable among interrupt levels.
 | |
| 
 | |
| */
 | |
| 
 | |
| 
 | |
| typedef struct xmp_condition_t {
 | |
|   unsigned int qhead;
 | |
|   unsigned int qtail;
 | |
|   unsigned char queue[XMP_MAX_CORES];
 | |
|   unsigned int waiting[XMP_MAX_CORES];
 | |
| 
 | |
|   unsigned char trace : 1;
 | |
|   unsigned char unused : 7;
 | |
|   const char * name;
 | |
| } xmp_condition_t __attribute__ ((aligned (XMP_MAX_DCACHE_LINESIZE)));
 | |
| 
 | |
| 
 | |
| #define XMP_CONDITION_INITIALIZER(name)				\
 | |
|   { 0, -1, {XMP_NO_OWNER, XMP_NO_OWNER, XMP_NO_OWNER, XMP_NO_OWNER}, \
 | |
|       {0, 0, 0, 0}, 0, 0, name}
 | |
| 
 | |
| 
 | |
| /* xmp_condition_init - Initialize a condition variable
 | |
| 
 | |
|    Nonsynchronizing, Nonblocking 
 | |
| 
 | |
|    Usage: 
 | |
|       condition - pointer to an xmp_condition_t
 | |
| 
 | |
|    On exit:
 | |
|       condition initialized
 | |
| 
 | |
|    Errors: none
 | |
| */
 | |
| 
 | |
| extern int xmp_condition_init (xmp_condition_t * condition, 
 | |
| 				const char * name);
 | |
| extern int xmp_condition_destroy (xmp_condition_t * condition);
 | |
| 
 | |
| 
 | |
| /* xmp_condition_wait - Wait for a condition variable
 | |
| 
 | |
|    Synchronizing, blocking 
 | |
| 
 | |
|    Usage: 
 | |
|       condition - pointer to an xmp_condition_t
 | |
|       mutex - pointer to an xmp_mutex_t already acquired by the calling
 | |
|               process
 | |
| 
 | |
|    Errors: if the mutex isn't held by this core
 | |
| */
 | |
| 
 | |
| extern int xmp_condition_wait (xmp_condition_t * condition, 
 | |
| 				xmp_mutex_t * mutex);
 | |
| 
 | |
| /* xmp_condition_signal 
 | |
| 
 | |
|    - Signal the first (if any) core waiting on a condition variable
 | |
| 
 | |
|    You must hold the mutex you passed to xmp_condition_wait before
 | |
|    calling this function.
 | |
| 
 | |
|    Synchronizing, nonblocking
 | |
| 
 | |
|    Usage: 
 | |
|       condition - pointer to an xmp_condition_t
 | |
| 
 | |
|    Errors: none
 | |
| */
 | |
| 
 | |
| extern int xmp_condition_signal (xmp_condition_t * condition);
 | |
| 
 | |
| 
 | |
| /* xmp_condition_broadcast
 | |
| 
 | |
|    - Signal all cores waiting on a condition variable
 | |
| 
 | |
|    Synchronizing, nonblocking
 | |
| 
 | |
|    You must hold the mutex you passed to xmp_condition_wait before
 | |
|    calling this function.
 | |
| 
 | |
|    Usage: 
 | |
|       condition - pointer to an xmp_condition_t
 | |
| 
 | |
|    Errors: none
 | |
| */
 | |
| 
 | |
| extern int xmp_condition_broadcast (xmp_condition_t * condition);
 | |
| 
 | |
| 
 | |
| static inline const char * xmp_condition_name (const xmp_condition_t * condition)
 | |
| {
 | |
|   return condition->name;
 | |
| }
 | |
| 
 | |
| /* 
 | |
|    xmp_condition_trace_on
 | |
|    xmp_condition_trace_off
 | |
| 
 | |
|    Nonsynchronizing
 | |
|    Nonblocking
 | |
| 
 | |
|    Turn off and on statistics and tracing for the condition.  For
 | |
|    tracing you must also set a trace file for the core.
 | |
| 
 | |
|    These functions are only present in the debug-version of the library.
 | |
| */
 | |
| 
 | |
| extern void xmp_condition_trace_on (xmp_condition_t * condition);
 | |
| extern void xmp_condition_trace_off (xmp_condition_t * condition);
 | |
| 
 | |
| #endif /* XCHAL_DCACHE_IS_COHERENT */
 | |
| 
 | |
| /* -------------------------------------------------------------------------
 | |
|    xmp_barrier_t
 | |
| 
 | |
|    Classic barriers that stop any core from continuing until a
 | |
|    specified number of cores reach that point. Once the barrier allows
 | |
|    cores through, the barrier is reset and will stop cores from
 | |
|    progressing again.
 | |
| 
 | |
|    Barriers are not sharable among interrupt levels.
 | |
| 
 | |
| */
 | |
| 
 | |
| 
 | |
| typedef struct xmp_barrier_t 
 | |
| { 
 | |
|   xmp_atomic_int_t count; 
 | |
|   xmp_atomic_int_t state;
 | |
|   xmp_atomic_int_t sleeping;
 | |
|   unsigned short num_cores;
 | |
|   unsigned short trace : 1;
 | |
|   unsigned short system : 1;
 | |
|   const char * name;
 | |
| } xmp_barrier_t __attribute__ ((aligned (XMP_MAX_DCACHE_LINESIZE)));
 | |
| 
 | |
| #define XMP_BARRIER_INITIALIZER(number, name)	\
 | |
|   { 0, 0, 0, number, 0, 0, name }
 | |
| 
 | |
| 
 | |
| /* xmp_barrier_init - Initialize a barrier
 | |
| 
 | |
|    Nonsynchronizing, Nonblocking 
 | |
| 
 | |
|    Usage: 
 | |
|       barrier - pointer to an xmp_barrier_t
 | |
|       num_cores - number of cores needed to arrive at the 
 | |
|                   barrier before any are allowed through
 | |
|    On exit:
 | |
|       barrier initialized
 | |
| 
 | |
|    Always returns zero.
 | |
| 
 | |
|    Errors: none
 | |
| */
 | |
| 
 | |
| extern int xmp_barrier_init (xmp_barrier_t * barrier, int num_cores, 
 | |
| 			      const char * name);
 | |
| 
 | |
| 
 | |
| /* xmp_barrier_wait - Wait on a barrier
 | |
| 
 | |
|    Nonsynchronizing, Nonblocking 
 | |
| 
 | |
|    Usage: 
 | |
|       barrier - pointer to an xmp_barrier_t
 | |
|    On exit:
 | |
|       Enough cores (as determined at the barrier's initialization)
 | |
|       have reached the barrier.
 | |
| 
 | |
|    Errors: none
 | |
| */
 | |
| 
 | |
| extern int xmp_barrier_wait (xmp_barrier_t * barrier);
 | |
| 
 | |
| 
 | |
| static inline const char * xmp_barrier_name (const xmp_barrier_t * barrier)
 | |
| {
 | |
|   return barrier->name;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* 
 | |
|    xmp_barrier_trace_on
 | |
|    xmp_barrier_trace_off
 | |
| 
 | |
|    Nonsynchronizing
 | |
|    Nonblocking
 | |
| 
 | |
|    Turn on and off tracing for the barrier.  For
 | |
|    tracing you must also set a trace file for the core.
 | |
| 
 | |
|    These functions are only present in the debug-version of the library.
 | |
| */
 | |
| 
 | |
| extern void xmp_barrier_trace_on (xmp_barrier_t * barrier);
 | |
| extern void xmp_barrier_trace_off (xmp_barrier_t * barrier);
 | |
| 
 | |
| 
 | |
| /* -------------------------------------------------------------------------
 | |
|    Portions of the library that are internal, but belong here for
 | |
|    convenience.
 | |
| */
 | |
| 
 | |
| extern xmp_atomic_int_t _ResetSync;
 | |
| 
 | |
| static inline void 
 | |
| xmp_initial_sync (int num_cores)
 | |
| {
 | |
|   xmp_atomic_int_increment (&_ResetSync, 1);
 | |
|   while (xmp_coherent_l32ai (&_ResetSync) != num_cores)
 | |
|     xmp_spin ();
 | |
| }
 | |
| 
 | |
| #ifdef __cplusplus
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #endif /* _XMP_LIBRARY_H */
 |