source: rtems/bsps/shared/irq/irq-server.c @ 3ee19b7a

Last change on this file since 3ee19b7a was 3ee19b7a, checked in by Sebastian Huber <sebastian.huber@…>, on Jun 17, 2021 at 2:01:48 PM

bsps/irq: Change license to BSD-2-Clause

Change license to BSD-2-Clause according to file history and
re-licensing agreement.

Update #3053.

  • Property mode set to 100644
File size: 23.4 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/**
4 * @file
5 *
6 * @ingroup bsp_interrupt
7 *
8 * @brief This source file contains the interrupt server implementation.
9 */
10
11/*
12 * Copyright (C) 2009, 2020 embedded brains GmbH (http://www.embedded-brains.de)
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 *    notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 *    notice, this list of conditions and the following disclaimer in the
21 *    documentation and/or other materials provided with the distribution.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 */
35
36#include <stdlib.h>
37#include <string.h>
38
39#include <rtems.h>
40#include <rtems/chain.h>
41#include <rtems/score/assert.h>
42
43#include <bsp/irq-generic.h>
44
45#define BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR (BSP_INTERRUPT_VECTOR_MAX + 1)
46
47static rtems_interrupt_server_control bsp_interrupt_server_default;
48
49static rtems_chain_control bsp_interrupt_server_chain =
50  RTEMS_CHAIN_INITIALIZER_EMPTY(bsp_interrupt_server_chain);
51
52static rtems_interrupt_server_control *bsp_interrupt_server_get_context(
53  uint32_t server_index,
54  rtems_status_code *sc
55)
56{
57  rtems_chain_node *node;
58
59  bsp_interrupt_lock();
60  node = rtems_chain_first(&bsp_interrupt_server_chain);
61
62  while (node != rtems_chain_tail(&bsp_interrupt_server_chain)) {
63    rtems_interrupt_server_control *s;
64
65    s = RTEMS_CONTAINER_OF(node, rtems_interrupt_server_control, node);
66    if (s->index == server_index) {
67      bsp_interrupt_unlock();
68      return s;
69    }
70
71    node = rtems_chain_next(node);
72  }
73
74  bsp_interrupt_unlock();
75  *sc = RTEMS_INVALID_ID;
76  return NULL;
77}
78
79static void bsp_interrupt_server_trigger(void *arg)
80{
81  rtems_interrupt_lock_context lock_context;
82  rtems_interrupt_server_entry *e = arg;
83  rtems_interrupt_server_control *s = e->server;
84
85  if (bsp_interrupt_is_valid_vector(e->vector)) {
86    bsp_interrupt_vector_disable(e->vector);
87  }
88
89  rtems_interrupt_lock_acquire(&s->lock, &lock_context);
90
91  if (rtems_chain_is_node_off_chain(&e->node)) {
92    rtems_chain_append_unprotected(&s->entries, &e->node);
93  } else {
94    ++s->errors;
95  }
96
97  rtems_interrupt_lock_release(&s->lock, &lock_context);
98
99  rtems_event_system_send(s->server, RTEMS_EVENT_SYSTEM_SERVER);
100}
101
102typedef struct {
103  rtems_interrupt_server_entry *entry;
104  rtems_option *options;
105} bsp_interrupt_server_iterate_entry;
106
107static void bsp_interrupt_server_per_handler_routine(
108  void *iterate_arg,
109  const char *info,
110  rtems_option options,
111  rtems_interrupt_handler handler,
112  void *handler_arg
113)
114{
115  if (handler == bsp_interrupt_server_trigger) {
116    bsp_interrupt_server_iterate_entry *ie = iterate_arg;
117
118    ie->entry = handler_arg;
119    *ie->options = options;
120  }
121}
122
123static rtems_interrupt_server_entry *bsp_interrupt_server_query_entry(
124  rtems_vector_number vector,
125  rtems_option *trigger_options
126)
127{
128  bsp_interrupt_server_iterate_entry ie = {
129    .entry = NULL,
130    .options = trigger_options
131  };
132
133  rtems_interrupt_handler_iterate(
134    vector,
135    bsp_interrupt_server_per_handler_routine,
136    &ie
137  );
138
139  return ie.entry;
140}
141
142typedef struct {
143  rtems_interrupt_server_control *server;
144  rtems_vector_number vector;
145  rtems_option options;
146  rtems_interrupt_handler handler;
147  void *arg;
148  rtems_id task;
149  rtems_status_code sc;
150} bsp_interrupt_server_helper_data;
151
152static void bsp_interrupt_server_install_helper(void *arg)
153{
154  bsp_interrupt_server_helper_data *hd = arg;
155  rtems_status_code sc;
156  rtems_interrupt_server_entry *e;
157  rtems_interrupt_server_action *a;
158  rtems_option trigger_options;
159
160  a = calloc(1, sizeof(*a));
161  if (a == NULL) {
162    hd->sc = RTEMS_NO_MEMORY;
163    rtems_event_transient_send(hd->task);
164    return;
165  }
166
167  a->handler = hd->handler;
168  a->arg = hd->arg;
169
170  bsp_interrupt_lock();
171
172  e = bsp_interrupt_server_query_entry(hd->vector, &trigger_options);
173  if (e == NULL) {
174    e = calloc(1, sizeof(*e));
175    if (e != NULL) {
176      e->server = hd->server;
177      e->vector = hd->vector;
178      e->actions = a;
179
180      sc = rtems_interrupt_handler_install(
181        hd->vector,
182        "IRQS",
183        hd->options & RTEMS_INTERRUPT_UNIQUE,
184        bsp_interrupt_server_trigger,
185        e
186      );
187      if (sc != RTEMS_SUCCESSFUL) {
188        free(e);
189      }
190    } else {
191      sc = RTEMS_NO_MEMORY;
192    }
193#if defined(RTEMS_SMP)
194  } else if (e->server != hd->server) {
195    sc = RTEMS_RESOURCE_IN_USE;
196#endif
197  } else if (
198    RTEMS_INTERRUPT_IS_UNIQUE(hd->options)
199      || RTEMS_INTERRUPT_IS_UNIQUE(trigger_options)
200  ) {
201    sc = RTEMS_RESOURCE_IN_USE;
202  } else {
203    rtems_interrupt_server_action **link = &e->actions;
204    rtems_interrupt_server_action *c;
205
206    sc = RTEMS_SUCCESSFUL;
207
208    while ((c = *link) != NULL) {
209      if (c->handler == hd->handler && c->arg == hd->arg) {
210        sc = RTEMS_TOO_MANY;
211        break;
212      }
213
214      link = &c->next;
215    }
216
217    if (sc == RTEMS_SUCCESSFUL) {
218      *link = a;
219    }
220  }
221
222  bsp_interrupt_unlock();
223
224  if (sc != RTEMS_SUCCESSFUL) {
225    free(a);
226  }
227
228  hd->sc = sc;
229  rtems_event_transient_send(hd->task);
230}
231
232static void bsp_interrupt_server_remove_helper(void *arg)
233{
234  bsp_interrupt_server_helper_data *hd = arg;
235  rtems_status_code sc;
236  rtems_interrupt_server_entry *e;
237  rtems_option trigger_options;
238
239  bsp_interrupt_lock();
240
241  e = bsp_interrupt_server_query_entry(hd->vector, &trigger_options);
242  if (e != NULL) {
243    rtems_interrupt_server_action **link = &e->actions;
244    rtems_interrupt_server_action *c;
245
246    while ((c = *link) != NULL) {
247      if (c->handler == hd->handler && c->arg == hd->arg) {
248        break;
249      }
250
251      link = &c->next;
252    }
253
254    if (c != NULL) {
255      bool remove_last = e->actions->next == NULL;
256
257      if (remove_last) {
258        rtems_interrupt_handler_remove(
259          hd->vector,
260          bsp_interrupt_server_trigger,
261          e
262        );
263      }
264
265      *link = c->next;
266      free(c);
267
268      if (remove_last) {
269        free(e);
270      }
271
272      sc = RTEMS_SUCCESSFUL;
273    } else {
274      sc = RTEMS_UNSATISFIED;
275    }
276  } else {
277    sc = RTEMS_INVALID_ID;
278  }
279
280  bsp_interrupt_unlock();
281
282  hd->sc = sc;
283  rtems_event_transient_send(hd->task);
284}
285
286static rtems_status_code bsp_interrupt_server_call_helper(
287  rtems_interrupt_server_control *s,
288  rtems_vector_number vector,
289  rtems_option options,
290  rtems_interrupt_handler handler,
291  void *arg,
292  void (*helper)(void *)
293)
294{
295  bsp_interrupt_server_helper_data hd = {
296    .server = s,
297    .vector = vector,
298    .options = options,
299    .handler = handler,
300    .arg = arg,
301    .task = rtems_task_self()
302  };
303  rtems_interrupt_server_action a = {
304    .handler = helper,
305    .arg = &hd
306  };
307  rtems_interrupt_server_entry e = {
308    .server = s,
309    .vector = BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR,
310    .actions = &a
311  };
312
313  bsp_interrupt_server_trigger(&e);
314  rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
315
316  return hd.sc;
317}
318
319static rtems_interrupt_server_entry *bsp_interrupt_server_get_entry(
320  rtems_interrupt_server_control *s
321)
322{
323  rtems_interrupt_lock_context lock_context;
324  rtems_interrupt_server_entry *e;
325
326  rtems_interrupt_lock_acquire(&s->lock, &lock_context);
327
328  if (!rtems_chain_is_empty(&s->entries)) {
329    e = (rtems_interrupt_server_entry *)
330      rtems_chain_get_first_unprotected(&s->entries);
331    rtems_chain_set_off_chain(&e->node);
332  } else {
333    e = NULL;
334  }
335
336  rtems_interrupt_lock_release(&s->lock, &lock_context);
337
338  return e;
339}
340
341static void bsp_interrupt_server_task(rtems_task_argument arg)
342{
343  rtems_interrupt_server_control *s = (rtems_interrupt_server_control *) arg;
344
345  while (true) {
346    rtems_event_set events;
347    rtems_interrupt_server_entry *e;
348
349    rtems_event_system_receive(
350      RTEMS_EVENT_SYSTEM_SERVER,
351      RTEMS_EVENT_ALL | RTEMS_WAIT,
352      RTEMS_NO_TIMEOUT,
353      &events
354    );
355
356    while ((e = bsp_interrupt_server_get_entry(s)) != NULL) {
357      rtems_interrupt_server_action *action = e->actions;
358      rtems_vector_number vector = e->vector;
359
360      do {
361        rtems_interrupt_server_action *current = action;
362        action = action->next;
363        (*current->handler)(current->arg);
364      } while (action != NULL);
365
366      if (bsp_interrupt_is_valid_vector(vector)) {
367        bsp_interrupt_vector_enable(vector);
368      }
369    }
370  }
371}
372
373rtems_status_code rtems_interrupt_server_handler_install(
374  uint32_t server_index,
375  rtems_vector_number vector,
376  const char *info,
377  rtems_option options,
378  rtems_interrupt_handler handler,
379  void *arg
380)
381{
382  rtems_status_code sc;
383  rtems_interrupt_server_control *s;
384
385  s = bsp_interrupt_server_get_context(server_index, &sc);
386  if (s == NULL) {
387    return sc;
388  }
389
390  return bsp_interrupt_server_call_helper(
391    s,
392    vector,
393    options,
394    handler,
395    arg,
396    bsp_interrupt_server_install_helper
397  );
398}
399
400rtems_status_code rtems_interrupt_server_handler_remove(
401  uint32_t server_index,
402  rtems_vector_number vector,
403  rtems_interrupt_handler handler,
404  void *arg
405)
406{
407  rtems_status_code sc;
408  rtems_interrupt_server_control *s;
409
410  s = bsp_interrupt_server_get_context(server_index, &sc);
411  if (s == NULL) {
412    return sc;
413  }
414
415  return bsp_interrupt_server_call_helper(
416    s,
417    vector,
418    0,
419    handler,
420    arg,
421    bsp_interrupt_server_remove_helper
422  );
423}
424
425typedef struct {
426  rtems_interrupt_per_handler_routine routine;
427  void *arg;
428} bsp_interrupt_server_handler_iterate_helper_data;
429
430static void bsp_interrupt_server_handler_iterate_helper(void *arg)
431{
432  bsp_interrupt_server_helper_data *hd = arg;
433  bsp_interrupt_server_handler_iterate_helper_data *hihd = hd->arg;
434  rtems_status_code sc;
435  rtems_interrupt_server_entry *e;
436  rtems_option trigger_options;
437
438  bsp_interrupt_lock();
439
440  e = bsp_interrupt_server_query_entry(hd->vector, &trigger_options);
441  if (e != NULL) {
442    rtems_interrupt_server_action **link = &e->actions;
443    rtems_interrupt_server_action *c;
444
445    while ((c = *link) != NULL) {
446      (*hihd->routine)(hihd->arg, NULL, trigger_options, c->handler, c->arg);
447      link = &c->next;
448    }
449
450    sc = RTEMS_SUCCESSFUL;
451  } else {
452    sc = RTEMS_UNSATISFIED;
453  }
454
455  bsp_interrupt_unlock();
456
457  hd->sc = sc;
458  rtems_event_transient_send(hd->task);
459}
460
461rtems_status_code rtems_interrupt_server_handler_iterate(
462  uint32_t server_index,
463  rtems_vector_number vector,
464  rtems_interrupt_per_handler_routine routine,
465  void *arg
466)
467{
468  rtems_status_code sc;
469  bsp_interrupt_server_handler_iterate_helper_data hihd;
470  rtems_interrupt_server_control *s;
471
472  s = bsp_interrupt_server_get_context(server_index, &sc);
473  if (s == NULL) {
474    return sc;
475  }
476
477  if (!bsp_interrupt_is_valid_vector(vector)) {
478    return RTEMS_INVALID_ID;
479  }
480
481  hihd.routine = routine;
482  hihd.arg = arg;
483  return bsp_interrupt_server_call_helper(
484    s,
485    vector,
486    0,
487    NULL,
488    &hihd,
489    bsp_interrupt_server_handler_iterate_helper
490  );
491}
492
493/*
494 * The default server is statically allocated.  Just clear the structure so
495 * that it can be re-initialized.
496 */
497static void bsp_interrupt_server_destroy_default(
498  rtems_interrupt_server_control *s
499)
500{
501  memset(s, 0, sizeof(*s));
502}
503
504#if defined(RTEMS_SMP)
505static void bsp_interrupt_server_destroy_secondary(
506  rtems_interrupt_server_control *s
507)
508{
509  free(s);
510}
511#endif
512
513static rtems_status_code bsp_interrupt_server_create(
514  rtems_interrupt_server_control *s,
515  rtems_task_priority priority,
516  size_t stack_size,
517  rtems_mode modes,
518  rtems_attribute attributes,
519  uint32_t cpu_index
520)
521{
522  rtems_status_code sc;
523#if defined(RTEMS_SMP)
524  rtems_id scheduler;
525  cpu_set_t cpu;
526#endif
527
528  sc = rtems_task_create(
529    rtems_build_name('I', 'R', 'Q', 'S'),
530    priority,
531    stack_size,
532    modes,
533    attributes,
534    &s->server
535  );
536  if (sc != RTEMS_SUCCESSFUL) {
537    (*s->destroy)(s);
538    return sc;
539  }
540
541  rtems_interrupt_lock_initialize(&s->lock, "Interrupt Server");
542  rtems_chain_initialize_empty(&s->entries);
543
544#if defined(RTEMS_SMP)
545  sc = rtems_scheduler_ident_by_processor(cpu_index, &scheduler);
546
547  /*
548   * If a scheduler exists for the processor, then move it to this scheduler
549   * and try to set the affinity to the processor, otherwise keep the scheduler
550   * of the executing thread.
551   */
552  if (sc == RTEMS_SUCCESSFUL) {
553    sc = rtems_task_set_scheduler(s->server, scheduler, priority);
554    _Assert(sc == RTEMS_SUCCESSFUL);
555
556    /* Set the task to processor affinity on a best-effort basis */
557    CPU_ZERO(&cpu);
558    CPU_SET(cpu_index, &cpu);
559    (void) rtems_task_set_affinity(s->server, sizeof(cpu), &cpu);
560  }
561#else
562  (void) cpu_index;
563#endif
564
565  rtems_chain_append_unprotected(&bsp_interrupt_server_chain, &s->node);
566
567  sc = rtems_task_start(
568    s->server,
569    bsp_interrupt_server_task,
570    (rtems_task_argument) s
571  );
572  _Assert(sc == RTEMS_SUCCESSFUL);
573
574  return sc;
575}
576
577rtems_status_code rtems_interrupt_server_initialize(
578  rtems_task_priority priority,
579  size_t stack_size,
580  rtems_mode modes,
581  rtems_attribute attributes,
582  uint32_t *server_count
583)
584{
585  rtems_status_code sc;
586  rtems_interrupt_server_control *s;
587  uint32_t cpu_index;
588#if defined(RTEMS_SMP)
589  uint32_t cpu_count;
590#endif
591
592  cpu_index = 0;
593  s = &bsp_interrupt_server_default;
594
595  bsp_interrupt_lock();
596
597  if (s->server != 0) {
598    sc = RTEMS_INCORRECT_STATE;
599    goto done;
600  }
601
602  s->destroy = bsp_interrupt_server_destroy_default;
603  sc = bsp_interrupt_server_create(
604    s,
605    priority,
606    stack_size,
607    modes,
608    attributes,
609    cpu_index
610  );
611  if (sc != RTEMS_SUCCESSFUL) {
612    goto done;
613  }
614
615  cpu_index = 1;
616
617#if defined(RTEMS_SMP)
618  cpu_count = rtems_scheduler_get_processor_maximum();
619
620  while (cpu_index < cpu_count) {
621    s = calloc(1, sizeof(*s));
622
623    if (s == NULL) {
624      sc = RTEMS_NO_MEMORY;
625      goto done;
626    }
627
628    s->destroy = bsp_interrupt_server_destroy_secondary;
629    s->index = cpu_index;
630    sc = bsp_interrupt_server_create(
631      s,
632      priority,
633      stack_size,
634      modes,
635      attributes,
636      cpu_index
637    );
638    if (sc != RTEMS_SUCCESSFUL) {
639      goto done;
640    }
641
642    ++cpu_index;
643  }
644#endif
645
646done:
647  bsp_interrupt_unlock();
648
649  if (server_count != NULL) {
650    *server_count = cpu_index;
651  }
652
653  return sc;
654}
655
656rtems_status_code rtems_interrupt_server_create(
657  rtems_interrupt_server_control      *s,
658  const rtems_interrupt_server_config *config,
659  uint32_t                            *server_index
660)
661{
662  rtems_status_code sc;
663
664  sc = rtems_task_create(
665    config->name,
666    config->priority,
667    config->storage_size,
668    config->modes,
669    config->attributes,
670    &s->server
671  );
672  if (sc != RTEMS_SUCCESSFUL) {
673    return sc;
674  }
675
676  rtems_interrupt_lock_initialize(&s->lock, "Interrupt Server");
677  rtems_chain_initialize_empty(&s->entries);
678  s->destroy = config->destroy;
679  s->index = rtems_object_id_get_index(s->server)
680    + rtems_scheduler_get_processor_maximum();
681  *server_index = s->index;
682
683  bsp_interrupt_lock();
684  rtems_chain_initialize_node(&s->node);
685  rtems_chain_append_unprotected(&bsp_interrupt_server_chain, &s->node);
686  bsp_interrupt_unlock();
687
688  sc = rtems_task_start(
689    s->server,
690    bsp_interrupt_server_task,
691    (rtems_task_argument) s
692  );
693  _Assert(sc == RTEMS_SUCCESSFUL);
694
695  return sc;
696}
697
698static void bsp_interrupt_server_destroy_helper(void *arg)
699{
700  bsp_interrupt_server_helper_data *hd = arg;
701  rtems_interrupt_server_control *s = hd->server;
702  rtems_status_code sc;
703
704  bsp_interrupt_lock();
705  rtems_chain_extract_unprotected(&s->node);
706  bsp_interrupt_unlock();
707
708  rtems_interrupt_lock_destroy(&s->lock);
709
710  if (s->destroy != NULL) {
711    (*s->destroy)(s);
712  }
713
714  sc = rtems_event_transient_send(hd->task);
715  _Assert(sc == RTEMS_SUCCESSFUL);
716  (void) sc;
717
718  rtems_task_exit();
719}
720
721rtems_status_code rtems_interrupt_server_delete(uint32_t server_index)
722{
723  rtems_status_code sc;
724  rtems_interrupt_server_control *s;
725
726  s = bsp_interrupt_server_get_context(server_index, &sc);
727  if (s == NULL) {
728    return sc;
729  }
730
731  bsp_interrupt_server_call_helper(
732    s,
733    BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR,
734    0,
735    NULL,
736    NULL,
737    bsp_interrupt_server_destroy_helper
738  );
739  return RTEMS_SUCCESSFUL;
740}
741
742static void bsp_interrupt_server_entry_initialize(
743  rtems_interrupt_server_entry *entry,
744  rtems_interrupt_server_control *s
745)
746{
747  rtems_chain_set_off_chain(&entry->node);
748  entry->server = s;
749  entry->vector = BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR;
750  entry->actions = NULL;
751}
752
753static void bsp_interrupt_server_action_prepend(
754  rtems_interrupt_server_entry  *entry,
755  rtems_interrupt_server_action *action,
756  rtems_interrupt_handler        handler,
757  void                          *arg
758)
759{
760  action->handler = handler;
761  action->arg = arg;
762  action->next = entry->actions;
763  entry->actions = action;
764}
765
766rtems_status_code rtems_interrupt_server_entry_initialize(
767  uint32_t                      server_index,
768  rtems_interrupt_server_entry *entry
769)
770{
771  rtems_status_code sc;
772  rtems_interrupt_server_control *s;
773
774  s = bsp_interrupt_server_get_context(server_index, &sc);
775  if (s == NULL) {
776    return sc;
777  }
778
779  bsp_interrupt_server_entry_initialize(entry, s);
780  return RTEMS_SUCCESSFUL;
781}
782
783void rtems_interrupt_server_action_prepend(
784  rtems_interrupt_server_entry  *entry,
785  rtems_interrupt_server_action *action,
786  rtems_interrupt_handler        handler,
787  void                          *arg
788)
789{
790  bsp_interrupt_server_action_prepend(entry, action, handler, arg);
791}
792
793void rtems_interrupt_server_entry_submit(
794  rtems_interrupt_server_entry *entry
795)
796{
797  bsp_interrupt_server_trigger(entry);
798}
799
800rtems_status_code rtems_interrupt_server_entry_move(
801  rtems_interrupt_server_entry *entry,
802  uint32_t                      destination_server_index
803)
804{
805  rtems_status_code sc;
806  rtems_interrupt_server_control *s;
807
808  s = bsp_interrupt_server_get_context(destination_server_index, &sc);
809  if (s == NULL) {
810    return sc;
811  }
812
813  entry->server = s;
814  return RTEMS_SUCCESSFUL;
815}
816
817static void bsp_interrupt_server_entry_synchronize_helper(void *arg)
818{
819  bsp_interrupt_server_helper_data *hd = arg;
820
821  rtems_event_transient_send(hd->task);
822}
823
824void rtems_interrupt_server_entry_destroy(
825  rtems_interrupt_server_entry *entry
826)
827{
828  rtems_interrupt_server_control *s;
829  rtems_interrupt_lock_context lock_context;
830
831  s = entry->server;
832  rtems_interrupt_lock_acquire(&s->lock, &lock_context);
833
834  if (!rtems_chain_is_node_off_chain(&entry->node)) {
835    rtems_chain_extract_unprotected(&entry->node);
836    rtems_chain_set_off_chain(&entry->node);
837  }
838
839  rtems_interrupt_lock_release(&s->lock, &lock_context);
840
841  bsp_interrupt_server_call_helper(
842    s,
843    BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR,
844    0,
845    NULL,
846    NULL,
847    bsp_interrupt_server_entry_synchronize_helper
848  );
849}
850
851rtems_status_code rtems_interrupt_server_request_initialize(
852  uint32_t                        server_index,
853  rtems_interrupt_server_request *request,
854  rtems_interrupt_handler         handler,
855  void                           *arg
856)
857{
858  rtems_status_code sc;
859  rtems_interrupt_server_control *s;
860
861  s = bsp_interrupt_server_get_context(server_index, &sc);
862  if (s == NULL) {
863    return sc;
864  }
865
866  bsp_interrupt_server_entry_initialize(&request->entry, s);
867  bsp_interrupt_server_action_prepend(
868    &request->entry,
869    &request->action,
870    handler,
871    arg
872  );
873  return RTEMS_SUCCESSFUL;
874}
875
876static void bsp_interrupt_server_handler_move_helper(void *arg)
877{
878  bsp_interrupt_server_helper_data *hd = arg;
879  bsp_interrupt_server_handler_iterate_helper_data *hihd = hd->arg;
880  rtems_interrupt_server_entry *e;
881  rtems_option trigger_options;
882
883  bsp_interrupt_lock();
884
885  e = bsp_interrupt_server_query_entry(hd->vector, &trigger_options);
886  if (e != NULL) {
887    rtems_interrupt_lock_context lock_context;
888    rtems_interrupt_server_control *src = e->server;
889    rtems_interrupt_server_control *dst = hihd->arg;
890    bool pending;
891
892    /* The source server is only used in SMP configurations for the lock */
893    (void) src;
894
895    rtems_interrupt_lock_acquire(&src->lock, &lock_context);
896
897    pending = !rtems_chain_is_node_off_chain(&e->node);
898    if (pending) {
899      rtems_chain_extract_unprotected(&e->node);
900      rtems_chain_set_off_chain(&e->node);
901    }
902
903    rtems_interrupt_lock_release(&src->lock, &lock_context);
904
905    e->server = dst;
906
907    if (pending) {
908      bsp_interrupt_server_trigger(e);
909    }
910  }
911
912  bsp_interrupt_unlock();
913
914  rtems_event_transient_send(hd->task);
915}
916
917rtems_status_code rtems_interrupt_server_move(
918  uint32_t source_server_index,
919  rtems_vector_number vector,
920  uint32_t destination_server_index
921)
922{
923  rtems_status_code sc;
924  rtems_interrupt_server_control *src;
925  rtems_interrupt_server_control *dst;
926  bsp_interrupt_server_handler_iterate_helper_data hihd;
927
928  src = bsp_interrupt_server_get_context(source_server_index, &sc);
929  if (src == NULL) {
930    return sc;
931  }
932
933  dst = bsp_interrupt_server_get_context(destination_server_index, &sc);
934  if (dst == NULL) {
935    return sc;
936  }
937
938  if (!bsp_interrupt_is_valid_vector(vector)) {
939    return RTEMS_INVALID_ID;
940  }
941
942  hihd.arg = dst;
943  bsp_interrupt_server_call_helper(
944    src,
945    vector,
946    0,
947    NULL,
948    &hihd,
949    bsp_interrupt_server_handler_move_helper
950  );
951  return RTEMS_SUCCESSFUL;
952}
953
954static void bsp_interrupt_server_entry_suspend_helper(void *arg)
955{
956  bsp_interrupt_server_helper_data *hd = arg;
957  rtems_event_set events;
958
959  rtems_event_transient_send(hd->task);
960  rtems_event_system_receive(
961    RTEMS_EVENT_SYSTEM_SERVER_RESUME,
962    RTEMS_WAIT,
963    RTEMS_NO_TIMEOUT,
964    &events
965  );
966}
967
968rtems_status_code rtems_interrupt_server_suspend(uint32_t server_index)
969{
970  rtems_status_code sc;
971  rtems_interrupt_server_control *s;
972
973  s = bsp_interrupt_server_get_context(server_index, &sc);
974  if (s == NULL) {
975    return sc;
976  }
977
978  bsp_interrupt_server_call_helper(
979    s,
980    BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR,
981    0,
982    NULL,
983    NULL,
984    bsp_interrupt_server_entry_suspend_helper
985  );
986  return RTEMS_SUCCESSFUL;
987}
988
989rtems_status_code rtems_interrupt_server_resume(uint32_t server_index)
990{
991  rtems_status_code sc;
992  rtems_interrupt_server_control *s;
993
994  s = bsp_interrupt_server_get_context(server_index, &sc);
995  if (s == NULL) {
996    return sc;
997  }
998
999  rtems_event_system_send(s->server, RTEMS_EVENT_SYSTEM_SERVER_RESUME);
1000  bsp_interrupt_server_call_helper(
1001    s,
1002    BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR,
1003    0,
1004    NULL,
1005    NULL,
1006    bsp_interrupt_server_entry_synchronize_helper
1007  );
1008  return RTEMS_SUCCESSFUL;
1009}
1010
1011rtems_status_code rtems_interrupt_server_set_affinity(
1012  uint32_t            server_index,
1013  size_t              affinity_size,
1014  const cpu_set_t    *affinity,
1015  rtems_task_priority priority
1016)
1017{
1018  rtems_status_code sc;
1019  rtems_interrupt_server_control *s;
1020  rtems_id scheduler;
1021
1022  s = bsp_interrupt_server_get_context(server_index, &sc);
1023  if (s == NULL) {
1024    return sc;
1025  }
1026
1027  sc = rtems_scheduler_ident_by_processor_set(
1028    affinity_size,
1029    affinity,
1030    &scheduler
1031  );
1032  if (sc != RTEMS_SUCCESSFUL) {
1033    return sc;
1034  }
1035
1036  sc = rtems_task_set_scheduler(s->server, scheduler, priority);
1037  if (sc != RTEMS_SUCCESSFUL) {
1038    return sc;
1039  }
1040
1041  return rtems_task_set_affinity(s->server, affinity_size, affinity);
1042}
Note: See TracBrowser for help on using the repository browser.