RTEMS
smpmulticastaction.c
1 /*
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (C) 2019 embedded brains GmbH
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 
32 #include <rtems/score/smpimpl.h>
33 #include <rtems/score/assert.h>
34 
35 #define _Per_CPU_Jobs_ISR_disable_and_acquire( cpu, lock_context ) \
36  _ISR_lock_ISR_disable_and_acquire( &( cpu )->Jobs.Lock, lock_context )
37 
38 #define _Per_CPU_Jobs_release_and_ISR_enable( cpu, lock_context ) \
39  _ISR_lock_Release_and_ISR_enable( &( cpu )->Jobs.Lock, lock_context )
40 
42 {
43  ISR_lock_Context lock_context;
44  Per_CPU_Job *job;
45 
46  _Per_CPU_Jobs_ISR_disable_and_acquire( cpu, &lock_context );
47  job = cpu->Jobs.head;
48  cpu->Jobs.head = NULL;
49  _Per_CPU_Jobs_release_and_ISR_enable( cpu, &lock_context );
50 
51  while ( job != NULL ) {
52  const Per_CPU_Job_context *context;
53  Per_CPU_Job *next;
54 
55  context = job->context;
56  next = job->next;
57  ( *context->handler )( context->arg );
58  _Atomic_Store_ulong( &job->done, PER_CPU_JOB_DONE, ATOMIC_ORDER_RELEASE );
59 
60  job = next;
61  }
62 }
63 
65 {
66  ISR_lock_Context lock_context;
67 
68  _Atomic_Store_ulong( &job->done, 0, ATOMIC_ORDER_RELAXED );
69  _Assert( job->next == NULL );
70 
71  _Per_CPU_Jobs_ISR_disable_and_acquire( cpu, &lock_context );
72 
73  if ( cpu->Jobs.head == NULL ) {
74  cpu->Jobs.head = job;
75  } else {
76  *cpu->Jobs.tail = job;
77  }
78 
79  cpu->Jobs.tail = &job->next;
80 
81  _Per_CPU_Jobs_release_and_ISR_enable( cpu, &lock_context );
82 }
83 
84 static void _Per_CPU_Try_perform_jobs( Per_CPU_Control *cpu_self )
85 {
86  unsigned long message;
87 
88  message = _Atomic_Load_ulong( &cpu_self->message, ATOMIC_ORDER_RELAXED );
89 
90  if ( ( message & SMP_MESSAGE_PERFORM_JOBS ) != 0 ) {
91  bool success;
92 
93  success = _Atomic_Compare_exchange_ulong(
94  &cpu_self->message, &message,
95  message & ~SMP_MESSAGE_PERFORM_JOBS, ATOMIC_ORDER_RELAXED,
96  ATOMIC_ORDER_RELAXED
97  );
98 
99  if ( success ) {
100  _Per_CPU_Perform_jobs( cpu_self );
101  }
102  }
103 }
104 
106  const Per_CPU_Control *cpu,
107  const Per_CPU_Job *job
108 )
109 {
110  while (
111  _Atomic_Load_ulong( &job->done, ATOMIC_ORDER_ACQUIRE )
112  != PER_CPU_JOB_DONE
113  ) {
114  switch ( cpu->state ) {
118  _CPU_SMP_Processor_event_broadcast();
119  /* Fall through */
120  case PER_CPU_STATE_UP:
121  /*
122  * Calling this function with the current processor is intentional.
123  * We have to perform our own jobs here in case inter-processor
124  * interrupts are not working.
125  */
126  _Per_CPU_Try_perform_jobs( _Per_CPU_Get() );
127  break;
128  default:
129  _SMP_Fatal( SMP_FATAL_WRONG_CPU_STATE_TO_PERFORM_JOBS );
130  break;
131  }
132  }
133 }
134 
135 typedef struct {
137  Per_CPU_Job Jobs[ CPU_MAXIMUM_PROCESSORS ];
139 
140 static void _SMP_Issue_action_jobs(
141  const Processor_mask *targets,
142  SMP_Multicast_jobs *jobs,
143  uint32_t cpu_max
144 )
145 {
146  uint32_t cpu_index;
147 
148  for ( cpu_index = 0; cpu_index < cpu_max; ++cpu_index ) {
149  if ( _Processor_mask_Is_set( targets, cpu_index ) ) {
150  Per_CPU_Job *job;
151  Per_CPU_Control *cpu;
152 
153  job = &jobs->Jobs[ cpu_index ];
154  job->context = &jobs->Context;
155  cpu = _Per_CPU_Get_by_index( cpu_index );
156 
157  _Per_CPU_Add_job( cpu, job );
159  }
160  }
161 }
162 
163 static void _SMP_Wait_for_action_jobs(
164  const Processor_mask *targets,
165  const SMP_Multicast_jobs *jobs,
166  uint32_t cpu_max
167 )
168 {
169  uint32_t cpu_index;
170 
171  for ( cpu_index = 0; cpu_index < cpu_max; ++cpu_index ) {
172  if ( _Processor_mask_Is_set( targets, cpu_index ) ) {
173  const Per_CPU_Control *cpu;
174  const Per_CPU_Job *job;
175 
176  cpu = _Per_CPU_Get_by_index( cpu_index );
177  job = &jobs->Jobs[ cpu_index ];
178  _Per_CPU_Wait_for_job( cpu, job );
179  }
180  }
181 }
182 
184  const Processor_mask *targets,
185  SMP_Action_handler handler,
186  void *arg
187 )
188 {
189  SMP_Multicast_jobs jobs;
190  uint32_t cpu_max;
191 
192  cpu_max = _SMP_Get_processor_maximum();
193  _Assert( cpu_max <= RTEMS_ARRAY_SIZE( jobs.Jobs ) );
194 
195  jobs.Context.handler = handler;
196  jobs.Context.arg = arg;
197 
198  _SMP_Issue_action_jobs( targets, &jobs, cpu_max );
199  _SMP_Wait_for_action_jobs( targets, &jobs, cpu_max );
200 }
201 
203  SMP_Action_handler handler,
204  void *arg
205 )
206 {
208 }
209 
211  SMP_Action_handler handler,
212  void *arg
213 )
214 {
215  Processor_mask targets;
216 
218  _Processor_mask_Clear( &targets, _SMP_Get_current_processor() );
219  _SMP_Multicast_action( &targets, handler, arg );
220 }
221 
222 static void _SMP_Do_nothing_action( void *arg )
223 {
224  /* Do nothing */
225 }
226 
227 void _SMP_Synchronize( void )
228 {
229  _SMP_Othercast_action( _SMP_Do_nothing_action, NULL );
230 }
The per CPU controls are initialized to zero.
Definition: percpu.h:137
void _Per_CPU_Perform_jobs(Per_CPU_Control *cpu)
Performs the jobs of the specified processor in FIFO order.
Processor is ready to start multitasking.
Definition: percpu.h:153
struct Per_CPU_Job ** tail
Tail of the FIFO list of jobs to be performed by this processor.
Definition: percpu.h:582
Per_CPU_Job_handler handler
The job handler.
Definition: percpu.h:188
void _Per_CPU_Wait_for_job(const Per_CPU_Control *cpu, const Per_CPU_Job *job)
Waits for the job carried out by the specified processor.
struct Per_CPU_Control::@15 Jobs
FIFO list of jobs to be performed by this processor.
A per-processor job.
Definition: percpu.h:209
static __inline__ const Processor_mask * _SMP_Get_online_processors(void)
Gets all online processors.
Definition: smpimpl.h:318
RTEMS_INLINE_ROUTINE void _Processor_mask_Clear(Processor_mask *mask, uint32_t index)
Clears the specified index bit of the mask.
Information for the Assert Handler.
RTEMS_INLINE_ROUTINE bool _Processor_mask_Is_set(const Processor_mask *mask, uint32_t index)
Checks if the specified index bit of the mask is set.
void * arg
The job handler argument.
Definition: percpu.h:193
#define SMP_MESSAGE_PERFORM_JOBS
SMP message to perform per-processor jobs.
Definition: smpimpl.h:50
Per CPU Core Structure.
Definition: percpu.h:347
static void _SMP_Fatal(SMP_Fatal_code code)
Terminates with the given code.
Definition: smpimpl.h:72
void _Per_CPU_Add_job(Per_CPU_Control *cpu, Per_CPU_Job *job)
Adds the job to the tail of the processing list of the specified processor.
Context for per-processor jobs.
Definition: percpu.h:184
Atomic_Ulong done
Indication if the job is done.
Definition: percpu.h:222
struct Per_CPU_Job * next
The next job in the corresponding per-processor job list.
Definition: percpu.h:214
const Per_CPU_Job_context * context
Pointer to the job context to get the handler and argument.
Definition: percpu.h:228
Per_CPU_State state
Indicates the current state of the CPU.
Definition: percpu.h:552
Normal multitasking state.
Definition: percpu.h:168
Test context for spec:/rtems/event/req/send-receive test case.
void _SMP_Synchronize(void)
Ensures that all store operations issued by the current processor before the call this function are v...
#define RTEMS_ARRAY_SIZE(_array)
Returns the element count of the specified array.
Definition: basedefs.h:459
void _SMP_Othercast_action(SMP_Action_handler handler, void *arg)
Initiates an SMP multicast action to the set of all online processors excluding the current processor...
Atomic_Ulong message
Bit field for SMP messages.
Definition: percpu.h:505
void _SMP_Broadcast_action(SMP_Action_handler handler, void *arg)
Initiates an SMP multicast action to the set of all online processors.
RTEMS_INLINE_ROUTINE void _Processor_mask_Assign(Processor_mask *dst, const Processor_mask *src)
Copies the mask to another mask, also considers CPU_MAXIMUM_PROCESSORS.
Definition: processormask.h:95
Local ISR lock context for acquire and release pairs.
Definition: isrlock.h:65
void _SMP_Multicast_action(const Processor_mask *targets, SMP_Action_handler handler, void *arg)
Initiates an SMP multicast action to the set of target processors.
struct Per_CPU_Job * head
Head of the FIFO list of jobs to be performed by this processor.
Definition: percpu.h:572
#define _Assert(_e)
Assertion similar to assert() controlled via RTEMS_DEBUG instead of NDEBUG.
Definition: assert.h:100
void _SMP_Send_message(uint32_t cpu_index, unsigned long message)
Sends an SMP message to a processor.
Definition: smp.c:215
Multitasking start of processor is requested.
Definition: percpu.h:163
SuperCore SMP Implementation.