Ignore:
Timestamp:
11/03/15 10:44:11 (8 years ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
5, master
Children:
811885cb
Parents:
ac84d42e
git-author:
Sebastian Huber <sebastian.huber@…> (11/03/15 10:44:11)
git-committer:
Sebastian Huber <sebastian.huber@…> (01/20/16 09:15:56)
Message:

bsp/irq-server: Support shared interrupts

File:
1 edited

Legend:

Unmodified
Added
Removed
  • c/src/lib/libbsp/shared/src/irq-server.c

    rac84d42e rd9bd59da  
    88
    99/*
    10  * Copyright (c) 2009, 2015 embedded brains GmbH.  All rights reserved.
     10 * Copyright (c) 2009, 2016 embedded brains GmbH.  All rights reserved.
    1111 *
    1212 *  embedded brains GmbH
     
    2525#include <rtems.h>
    2626#include <rtems/chain.h>
     27#include <rtems/score/assert.h>
    2728
    2829#include <bsp/irq-generic.h>
     
    3435)
    3536
    36 typedef struct bsp_interrupt_server_entry {
     37typedef struct bsp_interrupt_server_action {
     38  struct bsp_interrupt_server_action *next;
     39  rtems_interrupt_handler handler;
     40  void *arg;
     41} bsp_interrupt_server_action;
     42
     43typedef struct {
    3744  rtems_chain_node node;
    3845  rtems_vector_number vector;
    39   rtems_interrupt_handler handler;
    40   void *arg;
     46  bsp_interrupt_server_action *actions;
    4147} bsp_interrupt_server_entry;
    4248
     
    7480
    7581  rtems_event_system_send(bsp_interrupt_server_id, RTEMS_EVENT_SYSTEM_SERVER);
     82}
     83
     84typedef struct {
     85  bsp_interrupt_server_action *action;
     86  bsp_interrupt_server_action **link;
     87  rtems_id task;
     88} bsp_interrupt_server_helper_data;
     89
     90static void bsp_interrupt_server_helper(void *arg)
     91{
     92  bsp_interrupt_server_helper_data *hd = arg;
     93
     94  *hd->link = hd->action;
     95  rtems_event_transient_send(hd->task);
     96}
     97
     98static void bsp_interrupt_server_call_helper(
     99  bsp_interrupt_server_action *action,
     100  bsp_interrupt_server_action **link
     101)
     102{
     103  bsp_interrupt_server_helper_data hd = {
     104    .action = action,
     105    .link = link,
     106    .task = rtems_task_self()
     107  };
     108  bsp_interrupt_server_action a = {
     109    .handler = bsp_interrupt_server_helper,
     110    .arg = &hd
     111  };
     112  bsp_interrupt_server_entry e = {
     113    .vector = BSP_INTERRUPT_VECTOR_MAX + 1,
     114    .actions = &a
     115  };
     116
     117  bsp_interrupt_server_trigger(&e);
     118  rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
    76119}
    77120
     
    100143static void bsp_interrupt_server_task(rtems_task_argument arg)
    101144{
    102   rtems_status_code sc = RTEMS_SUCCESSFUL;
    103 
    104145  while (true) {
    105     rtems_event_set events = 0;
    106     bsp_interrupt_server_entry *e = NULL;
    107 
    108     sc = rtems_event_system_receive(
     146    rtems_event_set events;
     147    bsp_interrupt_server_entry *e;
     148
     149    rtems_event_system_receive(
    109150      RTEMS_EVENT_SYSTEM_SERVER,
    110151      RTEMS_EVENT_ALL | RTEMS_WAIT,
     
    112153      &events
    113154    );
    114     if (sc != RTEMS_SUCCESSFUL) {
    115       break;
    116     }
    117155
    118156    while ((e = bsp_interrupt_server_get_entry()) != NULL) {
    119       (*e->handler)(e->arg);
    120 
    121       bsp_interrupt_vector_enable(e->vector);
    122     }
    123   }
    124 
    125   rtems_task_delete(RTEMS_SELF);
     157      bsp_interrupt_server_action *action = e->actions;
     158      rtems_vector_number vector = e->vector;
     159
     160      do {
     161        bsp_interrupt_server_action *current = action;
     162        action = action->next;
     163        (*current->handler)(current->arg);
     164      } while (action != NULL);
     165
     166      bsp_interrupt_vector_enable(vector);
     167    }
     168  }
    126169}
    127170
    128171typedef struct {
    129   rtems_interrupt_handler handler;
    130   void *arg;
    131172  bsp_interrupt_server_entry *entry;
     173  rtems_option *options;
    132174} bsp_interrupt_server_iterate_entry;
    133175
     
    140182)
    141183{
    142   bsp_interrupt_server_iterate_entry *ie = iterate_arg;
    143   bsp_interrupt_server_entry *e = handler_arg;
    144 
    145184  if (handler == bsp_interrupt_server_trigger) {
    146     if (e->handler == ie->handler && e->arg == ie->arg) {
    147       ie->entry = e;
    148     }
    149   }
     185    bsp_interrupt_server_iterate_entry *ie = iterate_arg;
     186
     187    ie->entry = handler_arg;
     188    *ie->options = options;
     189  }
     190}
     191
     192static bsp_interrupt_server_entry *bsp_interrupt_server_query_entry(
     193  rtems_vector_number vector,
     194  rtems_option *trigger_options
     195)
     196{
     197  bsp_interrupt_server_iterate_entry ie = {
     198    .entry = NULL,
     199    .options = trigger_options
     200  };
     201
     202  rtems_interrupt_handler_iterate(
     203    vector,
     204    bsp_interrupt_server_per_handler_routine,
     205    &ie
     206  );
     207
     208  return ie.entry;
    150209}
    151210
     
    159218)
    160219{
    161   rtems_status_code sc = RTEMS_SUCCESSFUL;
    162   bsp_interrupt_server_entry *e = NULL;
     220  rtems_status_code sc;
     221  bsp_interrupt_server_entry *e;
     222  bsp_interrupt_server_action *a;
     223  rtems_option trigger_options;
    163224
    164225  sc = bsp_interrupt_server_is_initialized();
     
    171232  }
    172233
    173   if (RTEMS_INTERRUPT_IS_SHARED(options)) {
    174     return RTEMS_NOT_IMPLEMENTED;
    175   }
    176 
    177   e = calloc(1, sizeof(*e));
     234  a = calloc(1, sizeof(*a));
     235  if (a == NULL) {
     236    return RTEMS_NO_MEMORY;
     237  }
     238
     239  a->handler = handler;
     240  a->arg = arg;
     241
     242  bsp_interrupt_lock();
     243
     244  e = bsp_interrupt_server_query_entry(vector, &trigger_options);
    178245  if (e == NULL) {
    179     return RTEMS_NO_MEMORY;
    180   }
    181 
    182   e->vector = vector;
    183   e->handler = handler;
    184   e->arg = arg;
    185 
    186   sc = rtems_interrupt_handler_install(
    187     vector,
    188     info,
    189     options,
    190     bsp_interrupt_server_trigger,
    191     e
    192   );
     246    e = calloc(1, sizeof(*e));
     247    if (e != NULL) {
     248      e->vector = vector;
     249      e->actions = a;
     250
     251      sc = rtems_interrupt_handler_install(
     252        vector,
     253        "IRQS",
     254        options & RTEMS_INTERRUPT_UNIQUE,
     255        bsp_interrupt_server_trigger,
     256        e
     257      );
     258      if (sc != RTEMS_SUCCESSFUL) {
     259        free(e);
     260      }
     261    } else {
     262      sc = RTEMS_NO_MEMORY;
     263    }
     264  } else if (
     265    RTEMS_INTERRUPT_IS_UNIQUE(options)
     266      || RTEMS_INTERRUPT_IS_UNIQUE(trigger_options)
     267  ) {
     268    sc = RTEMS_RESOURCE_IN_USE;
     269  } else {
     270    bsp_interrupt_server_action **link = &e->actions;
     271    bsp_interrupt_server_action *c;
     272
     273    while ((c = *link) != NULL) {
     274      if (c->handler == handler && c->arg == arg) {
     275        sc = RTEMS_TOO_MANY;
     276        break;
     277      }
     278
     279      link = &c->next;
     280    }
     281
     282    if (sc == RTEMS_SUCCESSFUL) {
     283      bsp_interrupt_server_call_helper(a, link);
     284    }
     285  }
     286
     287  bsp_interrupt_unlock();
     288
    193289  if (sc != RTEMS_SUCCESSFUL) {
    194     free(e);
    195 
    196     return sc;
    197   }
    198 
    199   return RTEMS_SUCCESSFUL;
     290    free(a);
     291  }
     292
     293  return sc;
    200294}
    201295
     
    207301)
    208302{
    209   rtems_status_code sc = RTEMS_SUCCESSFUL;
    210   bsp_interrupt_server_iterate_entry ie = {
    211     .handler = handler,
    212     .arg = arg,
    213     .entry = NULL
    214   };
     303  rtems_status_code sc;
     304  bsp_interrupt_server_entry *e;
     305  rtems_option trigger_options;
    215306
    216307  sc = bsp_interrupt_server_is_initialized();
     
    223314  }
    224315
    225   /* Query corresponding interrupt server entry */
    226   sc = rtems_interrupt_handler_iterate(
    227     vector,
    228     bsp_interrupt_server_per_handler_routine,
    229     &ie
    230   );
    231   if (sc != RTEMS_SUCCESSFUL) {
    232     return sc;
    233   } else if (ie.entry == NULL) {
    234     return RTEMS_INVALID_ID;
    235   }
    236 
    237   sc = rtems_interrupt_handler_remove(
    238     vector,
    239     bsp_interrupt_server_trigger,
    240     ie.entry
    241   );
    242   if (sc != RTEMS_SUCCESSFUL) {
    243     return sc;
    244   }
    245 
    246   free(ie.entry);
    247 
    248   return RTEMS_SUCCESSFUL;
     316  bsp_interrupt_lock();
     317
     318  e = bsp_interrupt_server_query_entry(vector, &trigger_options);
     319  if (e != NULL) {
     320    bsp_interrupt_server_action **link = &e->actions;
     321    bsp_interrupt_server_action *c;
     322
     323    while ((c = *link) != NULL) {
     324      if (c->handler == handler && c->arg == arg) {
     325        break;
     326      }
     327
     328      link = &c->next;
     329    }
     330
     331    if (c != NULL) {
     332      bool remove_last = e->actions->next == NULL;
     333
     334      if (remove_last) {
     335        rtems_interrupt_handler_remove(
     336          vector,
     337          bsp_interrupt_server_trigger,
     338          e
     339        );
     340      }
     341
     342      bsp_interrupt_server_call_helper(c->next, link);
     343      free(c);
     344
     345      if (remove_last) {
     346        free(e);
     347      }
     348    } else {
     349      sc = RTEMS_UNSATISFIED;
     350    }
     351  } else {
     352    sc = RTEMS_INVALID_ID;
     353  }
     354
     355  bsp_interrupt_unlock();
     356
     357  return sc;
    249358}
    250359
     
    280389    0
    281390  );
    282   if (sc != RTEMS_SUCCESSFUL) {
    283     /* In this case we could also panic */
    284     rtems_task_delete(bsp_interrupt_server_id);
    285     bsp_interrupt_server_id = RTEMS_ID_NONE;
    286 
    287     return RTEMS_TOO_MANY;
    288   }
     391  _Assert(sc == RTEMS_SUCCESSFUL);
    289392
    290393  return RTEMS_SUCCESSFUL;
Note: See TracChangeset for help on using the changeset viewer.