RTEMS CPU Kit with SuperCore  4.11.2
percpu.h
Go to the documentation of this file.
1 
8 /*
9  * COPYRIGHT (c) 1989-2011.
10  * On-Line Applications Research Corporation (OAR).
11  *
12  * The license and distribution terms for this file may be
13  * found in the file LICENSE in this distribution or at
14  * http://www.rtems.org/license/LICENSE.
15  */
16 
17 #ifndef _RTEMS_PERCPU_H
18 #define _RTEMS_PERCPU_H
19 
20 #include <rtems/score/cpu.h>
21 
22 #if defined( ASM )
23  #include <rtems/asm.h>
24 #else
25  #include <rtems/score/assert.h>
26  #include <rtems/score/isrlevel.h>
27  #include <rtems/score/smp.h>
28  #include <rtems/score/smplock.h>
29  #include <rtems/score/timestamp.h>
30 #endif
31 
32 #ifdef __cplusplus
33 extern "C" {
34 #endif
35 
36 #if defined( RTEMS_SMP )
37  /*
38  * This ensures that on SMP configurations the individual per-CPU controls
39  * are on different cache lines to prevent false sharing. This define can be
40  * used in assembler code to easily get the per-CPU control for a particular
41  * processor.
42  */
43  #if defined( RTEMS_PROFILING )
44  #define PER_CPU_CONTROL_SIZE_LOG2 8
45  #else
46  #define PER_CPU_CONTROL_SIZE_LOG2 7
47  #endif
48 
49  #define PER_CPU_CONTROL_SIZE ( 1 << PER_CPU_CONTROL_SIZE_LOG2 )
50 #endif
51 
52 #if !defined( ASM )
53 
54 struct Thread_Control;
55 
56 struct Scheduler_Context;
57 
71 #if defined( RTEMS_SMP )
72 
106 typedef enum {
115  PER_CPU_STATE_INITIAL,
116 
131  PER_CPU_STATE_READY_TO_START_MULTITASKING,
132 
141  PER_CPU_STATE_REQUEST_START_MULTITASKING,
142 
146  PER_CPU_STATE_UP,
147 
151  PER_CPU_STATE_SHUTDOWN
152 } Per_CPU_State;
153 
154 #endif /* defined( RTEMS_SMP ) */
155 
159 typedef struct {
160 #if defined( RTEMS_PROFILING )
161 
166  CPU_Counter_ticks thread_dispatch_disabled_instant;
167 
172  CPU_Counter_ticks max_thread_dispatch_disabled_time;
173 
181  CPU_Counter_ticks max_interrupt_time;
182 
187  CPU_Counter_ticks max_interrupt_delay;
188 
195  uint64_t thread_dispatch_disabled_count;
196 
206  uint64_t total_thread_dispatch_disabled_time;
207 
214  uint64_t interrupt_count;
215 
224  uint64_t total_interrupt_time;
225 #endif /* defined( RTEMS_PROFILING ) */
226 } Per_CPU_Stats;
227 
233 typedef struct Per_CPU_Control {
234  #if CPU_PER_CPU_CONTROL_SIZE > 0
235 
238  CPU_Per_CPU_control cpu_per_cpu;
239  #endif
240 
241  #if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE) || \
242  (CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE)
243 
248 
254  #endif
255 
260  uint32_t isr_nest_level;
261 
266  volatile uint32_t thread_dispatch_disable_level;
267 
279 
293 
308  volatile bool dispatch_necessary;
309 
312 
313  #if defined( RTEMS_SMP )
314 
322  SMP_ticket_lock_Control Lock;
323 
324  #if defined( RTEMS_PROFILING )
325 
328  SMP_lock_Stats Lock_stats;
329 
333  SMP_lock_Stats_context Lock_stats_context;
334  #endif
335 
340  SMP_lock_Context Giant_lock_context;
341 
348  Atomic_Ulong message;
349 
353  const struct Scheduler_Context *scheduler_context;
354 
362  Per_CPU_State state;
363 
368  bool started;
369  #endif
370 
371  Per_CPU_Stats Stats;
373 
374 #if defined( RTEMS_SMP )
375 typedef struct {
376  Per_CPU_Control per_cpu;
377  char unused_space_for_cache_line_alignment
378  [ PER_CPU_CONTROL_SIZE - sizeof( Per_CPU_Control ) ];
380 #else
381 typedef struct {
382  Per_CPU_Control per_cpu;
383 } Per_CPU_Control_envelope;
384 #endif
385 
391 extern Per_CPU_Control_envelope _Per_CPU_Information[] CPU_STRUCTURE_ALIGNMENT;
392 
393 #if defined( RTEMS_SMP )
394 #define _Per_CPU_Acquire( cpu ) \
395  _SMP_ticket_lock_Acquire( \
396  &( cpu )->Lock, \
397  &( cpu )->Lock_stats, \
398  &( cpu )->Lock_stats_context \
399  )
400 #else
401 #define _Per_CPU_Acquire( cpu ) \
402  do { \
403  (void) ( cpu ); \
404  } while ( 0 )
405 #endif
406 
407 #if defined( RTEMS_SMP )
408 #define _Per_CPU_Release( cpu ) \
409  _SMP_ticket_lock_Release( \
410  &( cpu )->Lock, \
411  &( cpu )->Lock_stats_context \
412  )
413 #else
414 #define _Per_CPU_Release( cpu ) \
415  do { \
416  (void) ( cpu ); \
417  } while ( 0 )
418 #endif
419 
420 #if defined( RTEMS_SMP )
421 #define _Per_CPU_ISR_disable_and_acquire( cpu, isr_cookie ) \
422  do { \
423  _ISR_Disable_without_giant( isr_cookie ); \
424  _Per_CPU_Acquire( cpu ); \
425  } while ( 0 )
426 #else
427 #define _Per_CPU_ISR_disable_and_acquire( cpu, isr_cookie ) \
428  do { \
429  _ISR_Disable( isr_cookie ); \
430  (void) ( cpu ); \
431  } while ( 0 )
432 #endif
433 
434 #if defined( RTEMS_SMP )
435 #define _Per_CPU_Release_and_ISR_enable( cpu, isr_cookie ) \
436  do { \
437  _Per_CPU_Release( cpu ); \
438  _ISR_Enable_without_giant( isr_cookie ); \
439  } while ( 0 )
440 #else
441 #define _Per_CPU_Release_and_ISR_enable( cpu, isr_cookie ) \
442  do { \
443  (void) ( cpu ); \
444  _ISR_Enable( isr_cookie ); \
445  } while ( 0 )
446 #endif
447 
448 #if defined( RTEMS_SMP )
449 #define _Per_CPU_Acquire_all( isr_cookie ) \
450  do { \
451  uint32_t ncpus = _SMP_Get_processor_count(); \
452  uint32_t cpu; \
453  _ISR_Disable( isr_cookie ); \
454  for ( cpu = 0 ; cpu < ncpus ; ++cpu ) { \
455  _Per_CPU_Acquire( _Per_CPU_Get_by_index( cpu ) ); \
456  } \
457  } while ( 0 )
458 #else
459 #define _Per_CPU_Acquire_all( isr_cookie ) \
460  _ISR_Disable( isr_cookie )
461 #endif
462 
463 #if defined( RTEMS_SMP )
464 #define _Per_CPU_Release_all( isr_cookie ) \
465  do { \
466  uint32_t ncpus = _SMP_Get_processor_count(); \
467  uint32_t cpu; \
468  for ( cpu = 0 ; cpu < ncpus ; ++cpu ) { \
469  _Per_CPU_Release( _Per_CPU_Get_by_index( cpu ) ); \
470  } \
471  _ISR_Enable( isr_cookie ); \
472  } while ( 0 )
473 #else
474 #define _Per_CPU_Release_all( isr_cookie ) \
475  _ISR_Enable( isr_cookie )
476 #endif
477 
478 /*
479  * If we get the current processor index in a context which allows thread
480  * dispatching, then we may already run on another processor right after the
481  * read instruction. There are very few cases in which this makes sense (here
482  * we can use _Per_CPU_Get_snapshot()). All other places must use
483  * _Per_CPU_Get() so that we can add checks for RTEMS_DEBUG.
484  */
485 #if defined( _CPU_Get_current_per_CPU_control )
486  #define _Per_CPU_Get_snapshot() _CPU_Get_current_per_CPU_control()
487 #else
488  #define _Per_CPU_Get_snapshot() \
489  ( &_Per_CPU_Information[ _SMP_Get_current_processor() ].per_cpu )
490 #endif
491 
492 #if defined( RTEMS_SMP )
493 static inline Per_CPU_Control *_Per_CPU_Get( void )
494 {
495  Per_CPU_Control *cpu_self = _Per_CPU_Get_snapshot();
496 
497  _Assert(
498  cpu_self->thread_dispatch_disable_level != 0 || _ISR_Get_level() != 0
499  );
500 
501  return cpu_self;
502 }
503 #else
504 #define _Per_CPU_Get() _Per_CPU_Get_snapshot()
505 #endif
506 
507 static inline Per_CPU_Control *_Per_CPU_Get_by_index( uint32_t index )
508 {
509  return &_Per_CPU_Information[ index ].per_cpu;
510 }
511 
512 static inline uint32_t _Per_CPU_Get_index( const Per_CPU_Control *cpu )
513 {
514  const Per_CPU_Control_envelope *per_cpu_envelope =
515  ( const Per_CPU_Control_envelope * ) cpu;
516 
517  return ( uint32_t ) ( per_cpu_envelope - &_Per_CPU_Information[ 0 ] );
518 }
519 
520 static inline bool _Per_CPU_Is_processor_started(
521  const Per_CPU_Control *cpu
522 )
523 {
524 #if defined( RTEMS_SMP )
525  return cpu->started;
526 #else
527  (void) cpu;
528 
529  return true;
530 #endif
531 }
532 
533 #if defined( RTEMS_SMP )
534 
535 static inline void _Per_CPU_Send_interrupt( const Per_CPU_Control *cpu )
536 {
537  _CPU_SMP_Send_interrupt( _Per_CPU_Get_index( cpu ) );
538 }
539 
545 void _Per_CPU_Initialize(void);
546 
547 void _Per_CPU_State_change(
548  Per_CPU_Control *cpu,
549  Per_CPU_State new_state
550 );
551 
577 bool _Per_CPU_State_wait_for_non_initial_state(
578  uint32_t cpu_index,
579  uint32_t timeout_in_ns
580 );
581 
582 #endif /* defined( RTEMS_SMP ) */
583 
584 /*
585  * On a non SMP system, the _SMP_Get_current_processor() is defined to 0.
586  * Thus when built for non-SMP, there should be no performance penalty.
587  */
588 #define _Thread_Dispatch_disable_level \
589  _Per_CPU_Get()->thread_dispatch_disable_level
590 #define _Thread_Heir \
591  _Per_CPU_Get()->heir
592 #define _Thread_Executing \
593  _Per_CPU_Get()->executing
594 #define _ISR_Nest_level \
595  _Per_CPU_Get()->isr_nest_level
596 #define _CPU_Interrupt_stack_low \
597  _Per_CPU_Get()->interrupt_stack_low
598 #define _CPU_Interrupt_stack_high \
599  _Per_CPU_Get()->interrupt_stack_high
600 #define _Thread_Dispatch_necessary \
601  _Per_CPU_Get()->dispatch_necessary
602 #define _Thread_Time_of_last_context_switch \
603  _Per_CPU_Get()->time_of_last_context_switch
604 
615 {
616  struct Thread_Control *executing;
617 
618  #if defined( RTEMS_SMP )
619  ISR_Level level;
620 
621  _ISR_Disable_without_giant( level );
622  #endif
623 
624  executing = _Thread_Executing;
625 
626  #if defined( RTEMS_SMP )
627  _ISR_Enable_without_giant( level );
628  #endif
629 
630  return executing;
631 }
632 
635 #endif /* !defined( ASM ) */
636 
637 #if defined( ASM ) || defined( _RTEMS_PERCPU_DEFINE_OFFSETS )
638 
639 #if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE) || \
640  (CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE)
641  /*
642  * If this CPU target lets RTEMS allocates the interrupt stack, then
643  * we need to have places in the per CPU table to hold them.
644  */
645  #define PER_CPU_INTERRUPT_STACK_LOW \
646  CPU_PER_CPU_CONTROL_SIZE
647  #define PER_CPU_INTERRUPT_STACK_HIGH \
648  PER_CPU_INTERRUPT_STACK_LOW + CPU_SIZEOF_POINTER
649  #define PER_CPU_END_STACK \
650  PER_CPU_INTERRUPT_STACK_HIGH + CPU_SIZEOF_POINTER
651 
652  #define INTERRUPT_STACK_LOW \
653  (SYM(_Per_CPU_Information) + PER_CPU_INTERRUPT_STACK_LOW)
654  #define INTERRUPT_STACK_HIGH \
655  (SYM(_Per_CPU_Information) + PER_CPU_INTERRUPT_STACK_HIGH)
656 #else
657  #define PER_CPU_END_STACK \
658  CPU_PER_CPU_CONTROL_SIZE
659 #endif
660 
661 /*
662  * These are the offsets of the required elements in the per CPU table.
663  */
664 #define PER_CPU_ISR_NEST_LEVEL \
665  PER_CPU_END_STACK
666 #define PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL \
667  PER_CPU_ISR_NEST_LEVEL + 4
668 #define PER_CPU_OFFSET_EXECUTING \
669  PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL + 4
670 #define PER_CPU_OFFSET_HEIR \
671  PER_CPU_OFFSET_EXECUTING + CPU_SIZEOF_POINTER
672 #define PER_CPU_DISPATCH_NEEDED \
673  PER_CPU_OFFSET_HEIR + CPU_SIZEOF_POINTER
674 
675 #define THREAD_DISPATCH_DISABLE_LEVEL \
676  (SYM(_Per_CPU_Information) + PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL)
677 #define ISR_NEST_LEVEL \
678  (SYM(_Per_CPU_Information) + PER_CPU_ISR_NEST_LEVEL)
679 #define DISPATCH_NEEDED \
680  (SYM(_Per_CPU_Information) + PER_CPU_DISPATCH_NEEDED)
681 
682 #endif /* defined( ASM ) || defined( _RTEMS_PERCPU_DEFINE_OFFSETS ) */
683 
684 #ifdef __cplusplus
685 }
686 #endif
687 
688 #endif
689 /* end of include file */
Per-CPU statistics.
Definition: percpu.h:159
void * interrupt_stack_high
This contains a pointer to the interrupt stack pointer for this CPU.
Definition: percpu.h:253
Definition: media-server.c:33
Scheduler context.
Definition: scheduler.h:180
struct Thread_Control * heir
This is the heir thread for this processor.
Definition: percpu.h:292
#define RTEMS_INLINE_ROUTINE
The following (in conjunction with compiler arguments) are used to choose between the use of static i...
Definition: basedefs.h:135
Helpers for Manipulating Timestamps.
ISR Level Type.
SuperCore SMP Support API.
#define _ISR_Get_level()
Return current interrupt level.
Definition: isrlevel.h:120
Per_CPU_Control_envelope _Per_CPU_Information [] CPU_STRUCTURE_ALIGNMENT
Set of Per CPU Core Information.
Definition: cpu.h:797
Definition: percpu.h:381
The CPU specific per-CPU control.
Definition: cpu.h:367
uint32_t ISR_Level
The following type defines the control block used to manage the interrupt level portion of the status...
Definition: isrlevel.h:42
This structure defines the Thread Control Block (TCB).
Definition: thread.h:671
Per CPU Core Structure.
Definition: percpu.h:233
uint32_t isr_nest_level
This contains the current interrupt nesting level on this CPU.
Definition: percpu.h:260
void * interrupt_stack_low
This contains a pointer to the lower range of the interrupt stack for this CPU.
Definition: percpu.h:247
#define _Assert(_e)
Assertion similar to assert() controlled via RTEMS_DEBUG instead of NDEBUG.
Definition: assert.h:83
volatile bool dispatch_necessary
This is set to true when this processor needs to run the dispatcher.
Definition: percpu.h:308
struct bintime Timestamp_Control
Define the Timestamp control type.
Definition: timestamp.h:55
struct Per_CPU_Control Per_CPU_Control
Per CPU Core Structure.
struct Thread_Control * executing
This is the thread executing on this processor.
Definition: percpu.h:278
SMP Lock API.
volatile uint32_t thread_dispatch_disable_level
The thread dispatch critical section nesting counter which is used to prevent context switches at ino...
Definition: percpu.h:266
Timestamp_Control time_of_last_context_switch
This is the time of the last context switch on this CPU.
Definition: percpu.h:311
RTEMS_INLINE_ROUTINE struct Thread_Control * _Thread_Get_executing(void)
Returns the thread control block of the executing thread.
Definition: percpu.h:614