source: rtems/cpukit/score/src/smpmulticastaction.c @ 85d6e845

5
Last change on this file since 85d6e845 was 85d6e845, checked in by Sebastian Huber <sebastian.huber@…>, on 04/19/19 at 09:01:31

score: Add _Per_CPU_Add_job()

  • Property mode set to 100644
File size: 6.1 KB
Line 
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
41void _Per_CPU_Perform_jobs( Per_CPU_Control *cpu )
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
48  while ( ( job = cpu->Jobs.head ) != NULL ) {
49    const Per_CPU_Job_context *context;
50
51    cpu->Jobs.head = job->next;
52    _Per_CPU_Jobs_release_and_ISR_enable( cpu, &lock_context );
53
54    context = job->context;
55    ( *context->handler )( context->arg );
56    _Atomic_Store_ulong( &job->done, PER_CPU_JOB_DONE, ATOMIC_ORDER_RELEASE );
57
58    _Per_CPU_Jobs_ISR_disable_and_acquire( cpu, &lock_context );
59  }
60}
61
62void _Per_CPU_Add_job( Per_CPU_Control *cpu, Per_CPU_Job *job )
63{
64  ISR_lock_Context lock_context;
65
66  _Atomic_Store_ulong( &job->done, 0, ATOMIC_ORDER_RELAXED );
67  _Assert( job->next == NULL );
68
69  _Per_CPU_Jobs_ISR_disable_and_acquire( cpu, &lock_context );
70
71  if ( cpu->Jobs.head == NULL ) {
72    cpu->Jobs.head = job;
73  } else {
74    *cpu->Jobs.tail = job;
75  }
76
77  cpu->Jobs.tail = &job->next;
78
79  _Per_CPU_Jobs_release_and_ISR_enable( cpu, &lock_context );
80}
81
82static void _Per_CPU_Try_perform_jobs( Per_CPU_Control *cpu_self )
83{
84  unsigned long message;
85
86  message = _Atomic_Load_ulong( &cpu_self->message, ATOMIC_ORDER_RELAXED );
87
88  if ( ( message & SMP_MESSAGE_PERFORM_JOBS ) != 0 ) {
89    bool success;
90
91    success = _Atomic_Compare_exchange_ulong(
92      &cpu_self->message, &message,
93      message & ~SMP_MESSAGE_PERFORM_JOBS, ATOMIC_ORDER_RELAXED,
94      ATOMIC_ORDER_RELAXED
95    );
96
97    if ( success ) {
98      _Per_CPU_Perform_jobs( cpu_self );
99    }
100  }
101}
102
103typedef struct {
104  Per_CPU_Job_context Context;
105  Per_CPU_Job         Jobs[ CPU_MAXIMUM_PROCESSORS ];
106} SMP_Multicast_jobs;
107
108static void _SMP_Issue_action_jobs(
109  const Processor_mask *targets,
110  SMP_Multicast_jobs   *jobs,
111  uint32_t              cpu_max
112)
113{
114  uint32_t cpu_index;
115
116  for ( cpu_index = 0; cpu_index < cpu_max; ++cpu_index ) {
117    if ( _Processor_mask_Is_set( targets, cpu_index ) ) {
118      Per_CPU_Job     *job;
119      Per_CPU_Control *cpu;
120
121      job = &jobs->Jobs[ cpu_index ];
122      job->context = &jobs->Context;
123      cpu = _Per_CPU_Get_by_index( cpu_index );
124
125      _Per_CPU_Add_job( cpu, job );
126      _SMP_Send_message( cpu_index, SMP_MESSAGE_PERFORM_JOBS );
127    }
128  }
129}
130
131static void _SMP_Wait_for_action_jobs(
132  const Processor_mask     *targets,
133  const SMP_Multicast_jobs *jobs,
134  uint32_t                  cpu_max
135)
136{
137  uint32_t cpu_index;
138
139  for ( cpu_index = 0; cpu_index < cpu_max; ++cpu_index ) {
140    if ( _Processor_mask_Is_set( targets, cpu_index ) ) {
141      const Per_CPU_Job *job;
142      Per_CPU_Control   *cpu;
143
144      job = &jobs->Jobs[ cpu_index ];
145      cpu = _Per_CPU_Get_by_index( cpu_index );
146
147      while (
148        _Atomic_Load_ulong( &job->done, ATOMIC_ORDER_ACQUIRE )
149          != PER_CPU_JOB_DONE
150      ) {
151        switch ( cpu->state ) {
152          case PER_CPU_STATE_INITIAL:
153          case PER_CPU_STATE_READY_TO_START_MULTITASKING:
154          case PER_CPU_STATE_REQUEST_START_MULTITASKING:
155            _CPU_SMP_Processor_event_broadcast();
156            /* Fall through */
157          case PER_CPU_STATE_UP:
158            /*
159             * Calling this function with the current processor is intentional.
160             * We have to perform our own jobs here in case inter-processor
161             * interrupts are not working.
162             */
163            _Per_CPU_Try_perform_jobs( _Per_CPU_Get() );
164            break;
165          default:
166            _SMP_Fatal( SMP_FATAL_WRONG_CPU_STATE_TO_PERFORM_JOBS );
167            break;
168        }
169      }
170    }
171  }
172}
173
174void _SMP_Multicast_action(
175  const Processor_mask *targets,
176  SMP_Action_handler    handler,
177  void                 *arg
178)
179{
180  SMP_Multicast_jobs jobs;
181  uint32_t           cpu_max;
182
183  cpu_max = _SMP_Get_processor_maximum();
184  _Assert( cpu_max <= RTEMS_ARRAY_SIZE( jobs.Jobs ) );
185
186  jobs.Context.handler = handler;
187  jobs.Context.arg = arg;
188
189  _SMP_Issue_action_jobs( targets, &jobs, cpu_max );
190  _SMP_Wait_for_action_jobs( targets, &jobs, cpu_max );
191}
192
193void _SMP_Broadcast_action(
194  SMP_Action_handler  handler,
195  void               *arg
196)
197{
198  _SMP_Multicast_action( _SMP_Get_online_processors(), handler, arg );
199}
200
201void _SMP_Othercast_action(
202  SMP_Action_handler  handler,
203  void               *arg
204)
205{
206  Processor_mask targets;
207
208  _Processor_mask_Assign( &targets, _SMP_Get_online_processors() );
209  _Processor_mask_Clear( &targets, _SMP_Get_current_processor() );
210  _SMP_Multicast_action( &targets, handler, arg );
211}
Note: See TracBrowser for help on using the repository browser.