2 #include "libtest_misc_internal.h"
5 #define MAX_ARM_ERG_LENGTH_IN_BYTES 2048
9 /****************************************************************************/
10 #if( defined LIBTEST_PAL_LOAD_LINKED && defined LIBTEST_PAL_STORE_CONDITIONAL )
13 struct erg_director_state
22 lfds710_pal_uint_t volatile
24 (*memory_pointer)[ (MAX_ARM_ERG_LENGTH_IN_BYTES+sizeof(lfds710_pal_uint_t)) / sizeof(lfds710_pal_uint_t)],
28 struct erg_helper_state
33 lfds710_pal_uint_t volatile
41 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_erg_director( void *libtest_threadset_per_thread_state );
42 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_erg_helper( void *libtest_threadset_per_thread_state );
44 /****************************************************************************/
45 void libtest_misc_determine_erg( struct libshared_memory_state *ms, lfds710_pal_uint_t (*count_array)[10], enum libtest_misc_determine_erg_result *der, lfds710_pal_uint_t *erg_length_in_bytes )
50 number_logical_processors;
52 lfds710_pal_uint_t volatile LFDS710_PAL_ALIGN( MAX_ARM_ERG_LENGTH_IN_BYTES )
53 memory[ (MAX_ARM_ERG_LENGTH_IN_BYTES+sizeof(lfds710_pal_uint_t)) / sizeof(lfds710_pal_uint_t)];
55 struct erg_director_state
58 struct erg_helper_state
61 struct lfds710_list_asu_element
64 struct lfds710_list_asu_state
65 list_of_logical_processors;
67 struct libtest_logical_processor
70 struct libtest_threadset_per_thread_state
73 struct libtest_threadset_state
76 LFDS710_PAL_ASSERT( ms != NULL );
77 LFDS710_PAL_ASSERT( count_array != NULL );
78 LFDS710_PAL_ASSERT( der != NULL );
79 LFDS710_PAL_ASSERT( erg_length_in_bytes != NULL );
81 /* TRD : ARM chips have a local and a global monitor
82 the local monitor has few guarantees and so you can't figure out ERG from it
83 because you can write even directly TO the LL/SC target and it thinks things are fine
84 so we have to hit the global monitor, which means running threads
85 in test, we know nothing about topology, so we just have to run one thread on each logical core
86 and get them to perform our necessary test memory writes
88 the code itself works by having a buffer of 2048 bytes, aligned at 2048 bytes - so it will
89 be aligned with an ERG
90 we LL/SC always on the first word
91 between the LL and SC, we get the other threads to perform a memory write into the buffer
92 the location of the write is the last word in each progressively larger ERG size, i.e.
93 ERG can be 8, 16, 32, 64, etc, so we LL location 0, then write to 1, 3, 7, 15, etc
94 we can then see which ERG sizes work and which fail
97 for( loop = 0 ; loop < 10 ; loop++ )
98 (*count_array)[loop] = 0;
100 libtest_pal_get_full_logical_processor_set( &list_of_logical_processors, ms );
102 lfds710_list_asu_query( &list_of_logical_processors, LFDS710_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors );
104 if( number_logical_processors == 1 )
106 *der = LIBTEST_MISC_DETERMINE_ERG_RESULT_ONE_PHYSICAL_CORE;
110 pts = libshared_memory_alloc_from_unknown_node( ms, sizeof(struct libtest_threadset_per_thread_state) * number_logical_processors, LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
112 ehs_array = libshared_memory_alloc_from_unknown_node( ms, sizeof(struct erg_helper_state) * (number_logical_processors-1), LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
113 eds = libshared_memory_alloc_from_unknown_node( ms, sizeof(struct erg_director_state), LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
114 eds->ack_pointer_array = libshared_memory_alloc_from_unknown_node( ms, sizeof(lfds710_pal_uint_t *) * (number_logical_processors-1), LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
116 eds->quit_flag = LOWERED;
117 eds->count_array = count_array;
118 eds->number_threads = number_logical_processors - 1;
119 eds->write_pointer = NULL;
120 eds->memory_pointer = &memory;
121 for( loop = 0 ; loop < (number_logical_processors-1) ; loop++ )
122 eds->ack_pointer_array[loop] = NULL;
124 libtest_threadset_init( &ts, NULL );
128 while( LFDS710_LIST_ASU_GET_START_AND_THEN_NEXT(list_of_logical_processors, lasue) )
130 lp = LFDS710_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue );
132 if( loop == number_logical_processors-1 )
133 libtest_threadset_add_thread( &ts, &pts[loop], lp, thread_erg_director, (void *) eds );
136 ehs_array[loop].quit_flag = &eds->quit_flag;
137 ehs_array[loop].thread_number = loop;
138 ehs_array[loop].ack_pointer = &eds->ack_pointer_array[loop];
139 ehs_array[loop].write_pointer = &eds->write_pointer;
140 libtest_threadset_add_thread( &ts, &pts[loop], lp, thread_erg_helper, (void *) &ehs_array[loop] );
146 LFDS710_MISC_BARRIER_STORE;
147 lfds710_misc_force_store();
149 libtest_threadset_run( &ts );
151 libtest_threadset_cleanup( &ts );
153 for( loop = 0 ; loop < 10 ; loop++ )
154 if( count_array[loop] > 0 )
158 *der = LIBTEST_MISC_DETERMINE_ERG_RESULT_ONE_PHYSICAL_CORE_OR_NO_LLSC;
160 if( erg_size >= 1 and erg_size <= 9 )
162 *der = LIBTEST_MISC_DETERMINE_ERG_RESULT_SUCCESS;
163 *erg_length_in_bytes = 1UL < (erg_size+2);
167 *der = LIBTEST_MISC_DETERMINE_ERG_RESULT_NO_LLSC;
172 /****************************************************************************/
173 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_erg_director( void *libtest_threadset_per_thread_state )
180 register_memory_zero,
184 struct erg_director_state
187 struct libtest_threadset_per_thread_state
190 LFDS710_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
192 LFDS710_PAL_ASSERT( libtest_threadset_per_thread_state != NULL );
194 pts = (struct libtest_threadset_per_thread_state *) libtest_threadset_per_thread_state;
196 eds = LIBTEST_THREADSET_GET_USER_STATE_FROM_PER_THREAD_STATE( *pts );
198 libtest_threadset_thread_ready_and_wait( pts );
200 for( loop = 0 ; loop < 1024 ; loop++ )
201 for( erg_length_in_bytes = MAX_ARM_ERG_LENGTH_IN_BYTES, count_index = 9 ; erg_length_in_bytes >= 4 ; erg_length_in_bytes /= 2, count_index-- )
203 LIBTEST_PAL_LOAD_LINKED( register_memory_zero, &(*eds->memory_pointer)[0] );
205 eds->write_pointer = &(*eds->memory_pointer)[erg_length_in_bytes / sizeof(lfds710_pal_uint_t)];
207 // TRD : wait for all threads to change their ack_pointer to the new write_pointer
212 for( subloop = 0 ; subloop < eds->number_threads ; subloop++ )
213 if( eds->ack_pointer_array[subloop] == eds->write_pointer )
215 LFDS710_MISC_BARRIER_LOAD; // TRD : yes, really here!
219 while( ack_count != eds->number_threads );
221 LIBTEST_PAL_STORE_CONDITIONAL( &(*eds->memory_pointer)[0], register_memory_zero, stored_flag );
223 if( stored_flag == 0 )
224 (*eds->count_array)[count_index]++;
227 eds->quit_flag = RAISED;
229 LFDS710_MISC_BARRIER_STORE;
230 lfds710_misc_force_store();
232 return (libshared_pal_thread_return_t) RETURN_SUCCESS;
235 /****************************************************************************/
236 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_erg_helper( void *libtest_threadset_per_thread_state )
238 struct erg_helper_state
241 struct libtest_threadset_per_thread_state
244 LFDS710_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
246 LFDS710_PAL_ASSERT( libtest_threadset_per_thread_state != NULL );
248 pts = (struct libtest_threadset_per_thread_state *) libtest_threadset_per_thread_state;
250 ehs = LIBTEST_THREADSET_GET_USER_STATE_FROM_PER_THREAD_STATE( *pts );
252 libtest_threadset_thread_ready_and_wait( pts );
254 while( *ehs->quit_flag == LOWERED )
256 if( *ehs->write_pointer != NULL )
257 **ehs->write_pointer = ehs->thread_number; // TRD : can be any value though - thread_number just seems nice
258 LFDS710_MISC_BARRIER_STORE;
259 *ehs->ack_pointer = *ehs->write_pointer;
262 LFDS710_MISC_BARRIER_STORE;
263 lfds710_misc_force_store();
265 return (libshared_pal_thread_return_t) RETURN_SUCCESS;
274 /****************************************************************************/
275 #pragma warning( disable : 4100 )
277 #if( !defined LIBTEST_PAL_LOAD_LINKED || !defined LIBTEST_PAL_STORE_CONDITIONAL )
279 void libtest_misc_determine_erg( struct libshared_memory_state *ms, lfds710_pal_uint_t (*count_array)[10], enum libtest_misc_determine_erg_result *der, lfds710_pal_uint_t *erg_length_in_bytes )
284 LFDS710_PAL_ASSERT( ms != NULL );
285 LFDS710_PAL_ASSERT( count_array != NULL );
286 LFDS710_PAL_ASSERT( der != NULL );
287 LFDS710_PAL_ASSERT( erg_length_in_bytes != NULL );
289 for( loop = 0 ; loop < 10 ; loop++ )
290 (*count_array)[loop] = 0;
292 *der = LIBTEST_MISC_DETERMINE_ERG_RESULT_NOT_SUPPORTED;
299 #pragma warning( default : 4100 )