Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:07

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSImplClassicIntr
0007  *
0008  * @brief This source file contains the interrupt server implementation.
0009  */
0010 
0011 /*
0012  * Copyright (C) 2009, 2020 embedded brains GmbH & Co. KG
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #include <stdlib.h>
0037 #include <string.h>
0038 
0039 #include <rtems.h>
0040 #include <rtems/chain.h>
0041 #include <rtems/score/assert.h>
0042 
0043 #include <bsp/irq-generic.h>
0044 
0045 #define BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR BSP_INTERRUPT_VECTOR_COUNT
0046 
0047 static rtems_interrupt_server_control bsp_interrupt_server_default;
0048 
0049 static rtems_chain_control bsp_interrupt_server_chain =
0050   RTEMS_CHAIN_INITIALIZER_EMPTY(bsp_interrupt_server_chain);
0051 
0052 static rtems_interrupt_server_control *bsp_interrupt_server_get_context(
0053   uint32_t server_index,
0054   rtems_status_code *sc
0055 )
0056 {
0057   rtems_chain_node *node;
0058 
0059   bsp_interrupt_lock();
0060   node = rtems_chain_first(&bsp_interrupt_server_chain);
0061 
0062   while (node != rtems_chain_tail(&bsp_interrupt_server_chain)) {
0063     rtems_interrupt_server_control *s;
0064 
0065     s = RTEMS_CONTAINER_OF(node, rtems_interrupt_server_control, node);
0066     if (s->index == server_index) {
0067       bsp_interrupt_unlock();
0068       return s;
0069     }
0070 
0071     node = rtems_chain_next(node);
0072   }
0073 
0074   bsp_interrupt_unlock();
0075   *sc = RTEMS_INVALID_ID;
0076   return NULL;
0077 }
0078 
0079 static void bsp_interrupt_server_trigger(void *arg)
0080 {
0081   rtems_interrupt_lock_context lock_context;
0082   rtems_interrupt_server_entry *e = arg;
0083   rtems_interrupt_server_control *s = e->server;
0084 
0085   if (bsp_interrupt_is_valid_vector(e->vector)) {
0086     bsp_interrupt_vector_disable(e->vector);
0087   }
0088 
0089   rtems_interrupt_lock_acquire(&s->lock, &lock_context);
0090 
0091   if (rtems_chain_is_node_off_chain(&e->node)) {
0092     rtems_chain_append_unprotected(&s->entries, &e->node);
0093   } else {
0094     ++s->errors;
0095   }
0096 
0097   rtems_interrupt_lock_release(&s->lock, &lock_context);
0098 
0099   rtems_event_system_send(s->server, RTEMS_EVENT_SYSTEM_SERVER);
0100 }
0101 
0102 typedef struct {
0103   rtems_interrupt_server_entry *entry;
0104   rtems_option *options;
0105 } bsp_interrupt_server_iterate_entry;
0106 
0107 static void bsp_interrupt_server_per_handler_routine(
0108   void *iterate_arg,
0109   const char *info,
0110   rtems_option options,
0111   rtems_interrupt_handler handler,
0112   void *handler_arg
0113 )
0114 {
0115   if (handler == bsp_interrupt_server_trigger) {
0116     bsp_interrupt_server_iterate_entry *ie = iterate_arg;
0117 
0118     ie->entry = handler_arg;
0119     *ie->options = options;
0120   }
0121 }
0122 
0123 static rtems_interrupt_server_entry *bsp_interrupt_server_query_entry(
0124   rtems_vector_number vector,
0125   rtems_option *trigger_options
0126 )
0127 {
0128   bsp_interrupt_server_iterate_entry ie = {
0129     .entry = NULL,
0130     .options = trigger_options
0131   };
0132 
0133   rtems_interrupt_handler_iterate(
0134     vector,
0135     bsp_interrupt_server_per_handler_routine,
0136     &ie
0137   );
0138 
0139   return ie.entry;
0140 }
0141 
0142 typedef struct {
0143   rtems_interrupt_server_control *server;
0144   rtems_vector_number vector;
0145   rtems_option options;
0146   rtems_interrupt_handler handler;
0147   void *arg;
0148   rtems_id task;
0149   rtems_status_code sc;
0150 } bsp_interrupt_server_helper_data;
0151 
0152 static void bsp_interrupt_server_install_helper(void *arg)
0153 {
0154   bsp_interrupt_server_helper_data *hd = arg;
0155   rtems_status_code sc;
0156   rtems_interrupt_server_entry *e;
0157   rtems_interrupt_server_action *a;
0158   rtems_option trigger_options;
0159 
0160   a = calloc(1, sizeof(*a));
0161   if (a == NULL) {
0162     hd->sc = RTEMS_NO_MEMORY;
0163     rtems_event_transient_send(hd->task);
0164     return;
0165   }
0166 
0167   a->handler = hd->handler;
0168   a->arg = hd->arg;
0169 
0170   bsp_interrupt_lock();
0171 
0172   e = bsp_interrupt_server_query_entry(hd->vector, &trigger_options);
0173   if (e == NULL) {
0174     e = calloc(1, sizeof(*e));
0175     if (e != NULL) {
0176       e->server = hd->server;
0177       e->vector = hd->vector;
0178       e->actions = a;
0179 
0180       sc = rtems_interrupt_handler_install(
0181         hd->vector,
0182         "IRQS",
0183         hd->options & RTEMS_INTERRUPT_UNIQUE,
0184         bsp_interrupt_server_trigger,
0185         e
0186       );
0187       if (sc != RTEMS_SUCCESSFUL) {
0188         free(e);
0189       }
0190     } else {
0191       sc = RTEMS_NO_MEMORY;
0192     }
0193 #if defined(RTEMS_SMP)
0194   } else if (e->server != hd->server) {
0195     sc = RTEMS_RESOURCE_IN_USE;
0196 #endif
0197   } else if (
0198     RTEMS_INTERRUPT_IS_UNIQUE(hd->options)
0199       || RTEMS_INTERRUPT_IS_UNIQUE(trigger_options)
0200   ) {
0201     sc = RTEMS_RESOURCE_IN_USE;
0202   } else {
0203     rtems_interrupt_server_action **link = &e->actions;
0204     rtems_interrupt_server_action *c;
0205 
0206     sc = RTEMS_SUCCESSFUL;
0207 
0208     while ((c = *link) != NULL) {
0209       if (c->handler == hd->handler && c->arg == hd->arg) {
0210         sc = RTEMS_TOO_MANY;
0211         break;
0212       }
0213 
0214       link = &c->next;
0215     }
0216 
0217     if (sc == RTEMS_SUCCESSFUL) {
0218       *link = a;
0219     }
0220   }
0221 
0222   bsp_interrupt_unlock();
0223 
0224   if (sc != RTEMS_SUCCESSFUL) {
0225     free(a);
0226   }
0227 
0228   hd->sc = sc;
0229   rtems_event_transient_send(hd->task);
0230 }
0231 
0232 static void bsp_interrupt_server_remove_helper(void *arg)
0233 {
0234   bsp_interrupt_server_helper_data *hd = arg;
0235   rtems_status_code sc;
0236   rtems_interrupt_server_entry *e;
0237   rtems_option trigger_options;
0238 
0239   bsp_interrupt_lock();
0240 
0241   e = bsp_interrupt_server_query_entry(hd->vector, &trigger_options);
0242   if (e != NULL) {
0243     rtems_interrupt_server_action **link = &e->actions;
0244     rtems_interrupt_server_action *c;
0245 
0246     while ((c = *link) != NULL) {
0247       if (c->handler == hd->handler && c->arg == hd->arg) {
0248         break;
0249       }
0250 
0251       link = &c->next;
0252     }
0253 
0254     if (c != NULL) {
0255       bool remove_last = e->actions->next == NULL;
0256 
0257       if (remove_last) {
0258         rtems_interrupt_handler_remove(
0259           hd->vector,
0260           bsp_interrupt_server_trigger,
0261           e
0262         );
0263       }
0264 
0265       *link = c->next;
0266       free(c);
0267 
0268       if (remove_last) {
0269         free(e);
0270       }
0271 
0272       sc = RTEMS_SUCCESSFUL;
0273     } else {
0274       sc = RTEMS_UNSATISFIED;
0275     }
0276   } else {
0277     sc = RTEMS_INVALID_ID;
0278   }
0279 
0280   bsp_interrupt_unlock();
0281 
0282   hd->sc = sc;
0283   rtems_event_transient_send(hd->task);
0284 }
0285 
0286 static rtems_status_code bsp_interrupt_server_call_helper(
0287   rtems_interrupt_server_control *s,
0288   rtems_vector_number vector,
0289   rtems_option options,
0290   rtems_interrupt_handler handler,
0291   void *arg,
0292   void (*helper)(void *)
0293 )
0294 {
0295   bsp_interrupt_server_helper_data hd = {
0296     .server = s,
0297     .vector = vector,
0298     .options = options,
0299     .handler = handler,
0300     .arg = arg,
0301     .task = rtems_task_self()
0302   };
0303   rtems_interrupt_server_action a = {
0304     .handler = helper,
0305     .arg = &hd
0306   };
0307   rtems_interrupt_server_entry e = {
0308     .server = s,
0309     .vector = BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR,
0310     .actions = &a
0311   };
0312 
0313   bsp_interrupt_server_trigger(&e);
0314   rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
0315 
0316   return hd.sc;
0317 }
0318 
0319 static rtems_interrupt_server_entry *bsp_interrupt_server_get_entry(
0320   rtems_interrupt_server_control *s
0321 )
0322 {
0323   rtems_interrupt_lock_context lock_context;
0324   rtems_interrupt_server_entry *e;
0325 
0326   rtems_interrupt_lock_acquire(&s->lock, &lock_context);
0327 
0328   if (!rtems_chain_is_empty(&s->entries)) {
0329     e = (rtems_interrupt_server_entry *)
0330       rtems_chain_get_first_unprotected(&s->entries);
0331     rtems_chain_set_off_chain(&e->node);
0332   } else {
0333     e = NULL;
0334   }
0335 
0336   rtems_interrupt_lock_release(&s->lock, &lock_context);
0337 
0338   return e;
0339 }
0340 
0341 static void bsp_interrupt_server_task(rtems_task_argument arg)
0342 {
0343   rtems_interrupt_server_control *s = (rtems_interrupt_server_control *) arg;
0344 
0345   while (true) {
0346     rtems_event_set events;
0347     rtems_interrupt_server_entry *e;
0348 
0349     rtems_event_system_receive(
0350       RTEMS_EVENT_SYSTEM_SERVER,
0351       RTEMS_EVENT_ALL | RTEMS_WAIT,
0352       RTEMS_NO_TIMEOUT,
0353       &events
0354     );
0355 
0356     while ((e = bsp_interrupt_server_get_entry(s)) != NULL) {
0357       rtems_interrupt_server_action *action = e->actions;
0358       rtems_vector_number vector = e->vector;
0359 
0360       do {
0361         rtems_interrupt_server_action *current = action;
0362         action = action->next;
0363         (*current->handler)(current->arg);
0364       } while (action != NULL);
0365 
0366       if (bsp_interrupt_is_valid_vector(vector)) {
0367         bsp_interrupt_vector_enable(vector);
0368       }
0369     }
0370   }
0371 }
0372 
0373 rtems_status_code rtems_interrupt_server_handler_install(
0374   uint32_t server_index,
0375   rtems_vector_number vector,
0376   const char *info,
0377   rtems_option options,
0378   rtems_interrupt_handler handler,
0379   void *arg
0380 )
0381 {
0382   rtems_status_code sc;
0383   rtems_interrupt_server_control *s;
0384 
0385   s = bsp_interrupt_server_get_context(server_index, &sc);
0386   if (s == NULL) {
0387     return sc;
0388   }
0389 
0390   return bsp_interrupt_server_call_helper(
0391     s,
0392     vector,
0393     options,
0394     handler,
0395     arg,
0396     bsp_interrupt_server_install_helper
0397   );
0398 }
0399 
0400 rtems_status_code rtems_interrupt_server_handler_remove(
0401   uint32_t server_index,
0402   rtems_vector_number vector,
0403   rtems_interrupt_handler handler,
0404   void *arg
0405 )
0406 {
0407   rtems_status_code sc;
0408   rtems_interrupt_server_control *s;
0409 
0410   s = bsp_interrupt_server_get_context(server_index, &sc);
0411   if (s == NULL) {
0412     return sc;
0413   }
0414 
0415   return bsp_interrupt_server_call_helper(
0416     s,
0417     vector,
0418     0,
0419     handler,
0420     arg,
0421     bsp_interrupt_server_remove_helper
0422   );
0423 }
0424 
0425 typedef struct {
0426   rtems_interrupt_per_handler_routine routine;
0427   void *arg;
0428 } bsp_interrupt_server_handler_iterate_helper_data;
0429 
0430 static void bsp_interrupt_server_handler_iterate_helper(void *arg)
0431 {
0432   bsp_interrupt_server_helper_data *hd = arg;
0433   bsp_interrupt_server_handler_iterate_helper_data *hihd = hd->arg;
0434   rtems_status_code sc;
0435   rtems_interrupt_server_entry *e;
0436   rtems_option trigger_options;
0437 
0438   bsp_interrupt_lock();
0439 
0440   e = bsp_interrupt_server_query_entry(hd->vector, &trigger_options);
0441   if (e != NULL) {
0442     rtems_interrupt_server_action **link = &e->actions;
0443     rtems_interrupt_server_action *c;
0444 
0445     while ((c = *link) != NULL) {
0446       (*hihd->routine)(hihd->arg, NULL, trigger_options, c->handler, c->arg);
0447       link = &c->next;
0448     }
0449 
0450     sc = RTEMS_SUCCESSFUL;
0451   } else {
0452     sc = RTEMS_UNSATISFIED;
0453   }
0454 
0455   bsp_interrupt_unlock();
0456 
0457   hd->sc = sc;
0458   rtems_event_transient_send(hd->task);
0459 }
0460 
0461 rtems_status_code rtems_interrupt_server_handler_iterate(
0462   uint32_t server_index,
0463   rtems_vector_number vector,
0464   rtems_interrupt_per_handler_routine routine,
0465   void *arg
0466 )
0467 {
0468   rtems_status_code sc;
0469   bsp_interrupt_server_handler_iterate_helper_data hihd;
0470   rtems_interrupt_server_control *s;
0471 
0472   s = bsp_interrupt_server_get_context(server_index, &sc);
0473   if (s == NULL) {
0474     return sc;
0475   }
0476 
0477   if (!bsp_interrupt_is_valid_vector(vector)) {
0478     return RTEMS_INVALID_ID;
0479   }
0480 
0481   hihd.routine = routine;
0482   hihd.arg = arg;
0483   return bsp_interrupt_server_call_helper(
0484     s,
0485     vector,
0486     0,
0487     NULL,
0488     &hihd,
0489     bsp_interrupt_server_handler_iterate_helper
0490   );
0491 }
0492 
0493 /*
0494  * The default server is statically allocated.  Just clear the structure so
0495  * that it can be re-initialized.
0496  */
0497 static void bsp_interrupt_server_destroy_default(
0498   rtems_interrupt_server_control *s
0499 )
0500 {
0501   memset(s, 0, sizeof(*s));
0502 }
0503 
0504 #if defined(RTEMS_SMP)
0505 static void bsp_interrupt_server_destroy_secondary(
0506   rtems_interrupt_server_control *s
0507 )
0508 {
0509   free(s);
0510 }
0511 #endif
0512 
0513 static rtems_status_code bsp_interrupt_server_create(
0514   rtems_interrupt_server_control *s,
0515   rtems_task_priority priority,
0516   size_t stack_size,
0517   rtems_mode modes,
0518   rtems_attribute attributes,
0519   uint32_t cpu_index
0520 )
0521 {
0522   rtems_status_code sc;
0523 #if defined(RTEMS_SMP)
0524   rtems_id scheduler;
0525   cpu_set_t cpu;
0526 #endif
0527 
0528   sc = rtems_task_create(
0529     rtems_build_name('I', 'R', 'Q', 'S'),
0530     priority,
0531     stack_size,
0532     modes,
0533     attributes,
0534     &s->server
0535   );
0536   if (sc != RTEMS_SUCCESSFUL) {
0537     (*s->destroy)(s);
0538     return sc;
0539   }
0540 
0541   rtems_interrupt_lock_initialize(&s->lock, "Interrupt Server");
0542   rtems_chain_initialize_empty(&s->entries);
0543 
0544 #if defined(RTEMS_SMP)
0545   sc = rtems_scheduler_ident_by_processor(cpu_index, &scheduler);
0546 
0547   /*
0548    * If a scheduler exists for the processor, then move it to this scheduler
0549    * and try to set the affinity to the processor, otherwise keep the scheduler
0550    * of the executing thread.
0551    */
0552   if (sc == RTEMS_SUCCESSFUL) {
0553     sc = rtems_task_set_scheduler(s->server, scheduler, priority);
0554     _Assert(sc == RTEMS_SUCCESSFUL);
0555 
0556     /* Set the task to processor affinity on a best-effort basis */
0557     CPU_ZERO(&cpu);
0558     CPU_SET(cpu_index, &cpu);
0559     (void) rtems_task_set_affinity(s->server, sizeof(cpu), &cpu);
0560   }
0561 #else
0562   (void) cpu_index;
0563 #endif
0564 
0565   rtems_chain_append_unprotected(&bsp_interrupt_server_chain, &s->node);
0566 
0567   sc = rtems_task_start(
0568     s->server,
0569     bsp_interrupt_server_task,
0570     (rtems_task_argument) s
0571   );
0572   _Assert(sc == RTEMS_SUCCESSFUL);
0573 
0574   return sc;
0575 }
0576 
0577 rtems_status_code rtems_interrupt_server_initialize(
0578   rtems_task_priority priority,
0579   size_t stack_size,
0580   rtems_mode modes,
0581   rtems_attribute attributes,
0582   uint32_t *server_count
0583 )
0584 {
0585   rtems_status_code sc;
0586   rtems_interrupt_server_control *s;
0587   uint32_t cpu_index;
0588 #if defined(RTEMS_SMP)
0589   uint32_t cpu_count;
0590 #endif
0591 
0592   cpu_index = 0;
0593   s = &bsp_interrupt_server_default;
0594 
0595   bsp_interrupt_lock();
0596 
0597   if (s->server != 0) {
0598     sc = RTEMS_INCORRECT_STATE;
0599     goto done;
0600   }
0601 
0602   s->destroy = bsp_interrupt_server_destroy_default;
0603   sc = bsp_interrupt_server_create(
0604     s,
0605     priority,
0606     stack_size,
0607     modes,
0608     attributes,
0609     cpu_index
0610   );
0611   if (sc != RTEMS_SUCCESSFUL) {
0612     goto done;
0613   }
0614 
0615   cpu_index = 1;
0616 
0617 #if defined(RTEMS_SMP)
0618   cpu_count = rtems_scheduler_get_processor_maximum();
0619 
0620   while (cpu_index < cpu_count) {
0621     s = calloc(1, sizeof(*s));
0622 
0623     if (s == NULL) {
0624       sc = RTEMS_NO_MEMORY;
0625       goto done;
0626     }
0627 
0628     s->destroy = bsp_interrupt_server_destroy_secondary;
0629     s->index = cpu_index;
0630     sc = bsp_interrupt_server_create(
0631       s,
0632       priority,
0633       stack_size,
0634       modes,
0635       attributes,
0636       cpu_index
0637     );
0638     if (sc != RTEMS_SUCCESSFUL) {
0639       goto done;
0640     }
0641 
0642     ++cpu_index;
0643   }
0644 #endif
0645 
0646 done:
0647   bsp_interrupt_unlock();
0648 
0649   if (server_count != NULL) {
0650     *server_count = cpu_index;
0651   }
0652 
0653   return sc;
0654 }
0655 
0656 rtems_status_code rtems_interrupt_server_create(
0657   rtems_interrupt_server_control      *s,
0658   const rtems_interrupt_server_config *config,
0659   uint32_t                            *server_index
0660 )
0661 {
0662   rtems_status_code sc;
0663 
0664   sc = rtems_task_create(
0665     config->name,
0666     config->priority,
0667     config->storage_size,
0668     config->modes,
0669     config->attributes,
0670     &s->server
0671   );
0672   if (sc != RTEMS_SUCCESSFUL) {
0673     return sc;
0674   }
0675 
0676   rtems_interrupt_lock_initialize(&s->lock, "Interrupt Server");
0677   rtems_chain_initialize_empty(&s->entries);
0678   s->destroy = config->destroy;
0679   s->index = rtems_object_id_get_index(s->server)
0680     + rtems_scheduler_get_processor_maximum();
0681   *server_index = s->index;
0682 
0683   bsp_interrupt_lock();
0684   rtems_chain_initialize_node(&s->node);
0685   rtems_chain_append_unprotected(&bsp_interrupt_server_chain, &s->node);
0686   bsp_interrupt_unlock();
0687 
0688   sc = rtems_task_start(
0689     s->server,
0690     bsp_interrupt_server_task,
0691     (rtems_task_argument) s
0692   );
0693   _Assert(sc == RTEMS_SUCCESSFUL);
0694 
0695   return sc;
0696 }
0697 
0698 static void bsp_interrupt_server_destroy_helper(void *arg)
0699 {
0700   bsp_interrupt_server_helper_data *hd = arg;
0701   rtems_interrupt_server_control *s = hd->server;
0702   rtems_status_code sc;
0703 
0704   bsp_interrupt_lock();
0705   rtems_chain_extract_unprotected(&s->node);
0706   bsp_interrupt_unlock();
0707 
0708   rtems_interrupt_lock_destroy(&s->lock);
0709 
0710   if (s->destroy != NULL) {
0711     (*s->destroy)(s);
0712   }
0713 
0714   sc = rtems_event_transient_send(hd->task);
0715   _Assert(sc == RTEMS_SUCCESSFUL);
0716   (void) sc;
0717 
0718   rtems_task_exit();
0719 }
0720 
0721 rtems_status_code rtems_interrupt_server_delete(uint32_t server_index)
0722 {
0723   rtems_status_code sc;
0724   rtems_interrupt_server_control *s;
0725 
0726   s = bsp_interrupt_server_get_context(server_index, &sc);
0727   if (s == NULL) {
0728     return sc;
0729   }
0730 
0731   bsp_interrupt_server_call_helper(
0732     s,
0733     BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR,
0734     0,
0735     NULL,
0736     NULL,
0737     bsp_interrupt_server_destroy_helper
0738   );
0739   return RTEMS_SUCCESSFUL;
0740 }
0741 
0742 static void bsp_interrupt_server_entry_initialize(
0743   rtems_interrupt_server_entry *entry,
0744   rtems_interrupt_server_control *s
0745 )
0746 {
0747   rtems_chain_set_off_chain(&entry->node);
0748   entry->server = s;
0749   entry->vector = BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR;
0750   entry->actions = NULL;
0751 }
0752 
0753 static void bsp_interrupt_server_action_prepend(
0754   rtems_interrupt_server_entry  *entry,
0755   rtems_interrupt_server_action *action,
0756   rtems_interrupt_handler        handler,
0757   void                          *arg
0758 )
0759 {
0760   action->handler = handler;
0761   action->arg = arg;
0762   action->next = entry->actions;
0763   entry->actions = action;
0764 }
0765 
0766 rtems_status_code rtems_interrupt_server_entry_initialize(
0767   uint32_t                      server_index,
0768   rtems_interrupt_server_entry *entry
0769 )
0770 {
0771   rtems_status_code sc;
0772   rtems_interrupt_server_control *s;
0773 
0774   s = bsp_interrupt_server_get_context(server_index, &sc);
0775   if (s == NULL) {
0776     return sc;
0777   }
0778 
0779   bsp_interrupt_server_entry_initialize(entry, s);
0780   return RTEMS_SUCCESSFUL;
0781 }
0782 
0783 void rtems_interrupt_server_action_prepend(
0784   rtems_interrupt_server_entry  *entry,
0785   rtems_interrupt_server_action *action,
0786   rtems_interrupt_handler        handler,
0787   void                          *arg
0788 )
0789 {
0790   bsp_interrupt_server_action_prepend(entry, action, handler, arg);
0791 }
0792 
0793 void rtems_interrupt_server_entry_submit(
0794   rtems_interrupt_server_entry *entry
0795 )
0796 {
0797   bsp_interrupt_server_trigger(entry);
0798 }
0799 
0800 rtems_status_code rtems_interrupt_server_entry_move(
0801   rtems_interrupt_server_entry *entry,
0802   uint32_t                      destination_server_index
0803 )
0804 {
0805   rtems_status_code sc;
0806   rtems_interrupt_server_control *s;
0807 
0808   s = bsp_interrupt_server_get_context(destination_server_index, &sc);
0809   if (s == NULL) {
0810     return sc;
0811   }
0812 
0813   entry->server = s;
0814   return RTEMS_SUCCESSFUL;
0815 }
0816 
0817 static void bsp_interrupt_server_entry_synchronize_helper(void *arg)
0818 {
0819   bsp_interrupt_server_helper_data *hd = arg;
0820 
0821   rtems_event_transient_send(hd->task);
0822 }
0823 
0824 void rtems_interrupt_server_entry_destroy(
0825   rtems_interrupt_server_entry *entry
0826 )
0827 {
0828   rtems_interrupt_server_control *s;
0829   rtems_interrupt_lock_context lock_context;
0830 
0831   s = entry->server;
0832   rtems_interrupt_lock_acquire(&s->lock, &lock_context);
0833 
0834   if (!rtems_chain_is_node_off_chain(&entry->node)) {
0835     rtems_chain_extract_unprotected(&entry->node);
0836     rtems_chain_set_off_chain(&entry->node);
0837   }
0838 
0839   rtems_interrupt_lock_release(&s->lock, &lock_context);
0840 
0841   bsp_interrupt_server_call_helper(
0842     s,
0843     BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR,
0844     0,
0845     NULL,
0846     NULL,
0847     bsp_interrupt_server_entry_synchronize_helper
0848   );
0849 }
0850 
0851 rtems_status_code rtems_interrupt_server_request_initialize(
0852   uint32_t                        server_index,
0853   rtems_interrupt_server_request *request,
0854   rtems_interrupt_handler         handler,
0855   void                           *arg
0856 )
0857 {
0858   rtems_status_code sc;
0859   rtems_interrupt_server_control *s;
0860 
0861   s = bsp_interrupt_server_get_context(server_index, &sc);
0862   if (s == NULL) {
0863     return sc;
0864   }
0865 
0866   bsp_interrupt_server_entry_initialize(&request->entry, s);
0867   bsp_interrupt_server_action_prepend(
0868     &request->entry,
0869     &request->action,
0870     handler,
0871     arg
0872   );
0873   return RTEMS_SUCCESSFUL;
0874 }
0875 
0876 static void bsp_interrupt_server_handler_move_helper(void *arg)
0877 {
0878   bsp_interrupt_server_helper_data *hd = arg;
0879   bsp_interrupt_server_handler_iterate_helper_data *hihd = hd->arg;
0880   rtems_interrupt_server_entry *e;
0881   rtems_option trigger_options;
0882 
0883   bsp_interrupt_lock();
0884 
0885   e = bsp_interrupt_server_query_entry(hd->vector, &trigger_options);
0886   if (e != NULL) {
0887     rtems_interrupt_lock_context lock_context;
0888     rtems_interrupt_server_control *src = e->server;
0889     rtems_interrupt_server_control *dst = hihd->arg;
0890     bool pending;
0891 
0892     /* The source server is only used in SMP configurations for the lock */
0893     (void) src;
0894 
0895     rtems_interrupt_lock_acquire(&src->lock, &lock_context);
0896 
0897     pending = !rtems_chain_is_node_off_chain(&e->node);
0898     if (pending) {
0899       rtems_chain_extract_unprotected(&e->node);
0900       rtems_chain_set_off_chain(&e->node);
0901     }
0902 
0903     rtems_interrupt_lock_release(&src->lock, &lock_context);
0904 
0905     e->server = dst;
0906 
0907     if (pending) {
0908       bsp_interrupt_server_trigger(e);
0909     }
0910   }
0911 
0912   bsp_interrupt_unlock();
0913 
0914   rtems_event_transient_send(hd->task);
0915 }
0916 
0917 rtems_status_code rtems_interrupt_server_move(
0918   uint32_t source_server_index,
0919   rtems_vector_number vector,
0920   uint32_t destination_server_index
0921 )
0922 {
0923   rtems_status_code sc;
0924   rtems_interrupt_server_control *src;
0925   rtems_interrupt_server_control *dst;
0926   bsp_interrupt_server_handler_iterate_helper_data hihd;
0927 
0928   src = bsp_interrupt_server_get_context(source_server_index, &sc);
0929   if (src == NULL) {
0930     return sc;
0931   }
0932 
0933   dst = bsp_interrupt_server_get_context(destination_server_index, &sc);
0934   if (dst == NULL) {
0935     return sc;
0936   }
0937 
0938   if (!bsp_interrupt_is_valid_vector(vector)) {
0939     return RTEMS_INVALID_ID;
0940   }
0941 
0942   hihd.arg = dst;
0943   bsp_interrupt_server_call_helper(
0944     src,
0945     vector,
0946     0,
0947     NULL,
0948     &hihd,
0949     bsp_interrupt_server_handler_move_helper
0950   );
0951   return RTEMS_SUCCESSFUL;
0952 }
0953 
0954 static void bsp_interrupt_server_entry_suspend_helper(void *arg)
0955 {
0956   bsp_interrupt_server_helper_data *hd = arg;
0957   rtems_event_set events;
0958 
0959   rtems_event_transient_send(hd->task);
0960   rtems_event_system_receive(
0961     RTEMS_EVENT_SYSTEM_SERVER_RESUME,
0962     RTEMS_WAIT,
0963     RTEMS_NO_TIMEOUT,
0964     &events
0965   );
0966 }
0967 
0968 rtems_status_code rtems_interrupt_server_suspend(uint32_t server_index)
0969 {
0970   rtems_status_code sc;
0971   rtems_interrupt_server_control *s;
0972 
0973   s = bsp_interrupt_server_get_context(server_index, &sc);
0974   if (s == NULL) {
0975     return sc;
0976   }
0977 
0978   bsp_interrupt_server_call_helper(
0979     s,
0980     BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR,
0981     0,
0982     NULL,
0983     NULL,
0984     bsp_interrupt_server_entry_suspend_helper
0985   );
0986   return RTEMS_SUCCESSFUL;
0987 }
0988 
0989 rtems_status_code rtems_interrupt_server_resume(uint32_t server_index)
0990 {
0991   rtems_status_code sc;
0992   rtems_interrupt_server_control *s;
0993 
0994   s = bsp_interrupt_server_get_context(server_index, &sc);
0995   if (s == NULL) {
0996     return sc;
0997   }
0998 
0999   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 
1011 rtems_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 }