source: rtems/bsps/shared/irq/irq-generic.c @ 9a029ce

5
Last change on this file since 9a029ce was 9a029ce, checked in by Sebastian Huber <sebastian.huber@…>, on 11/09/18 at 12:06:52

bsps/irq: Use rtems_malloc()

  • Property mode set to 100644
File size: 15.7 KB
RevLine 
[780428f]1/**
2 * @file
3 *
4 * @ingroup bsp_interrupt
5 *
[8634637]6 * @brief Generic BSP interrupt support implementation.
[780428f]7 */
8
9/*
[359e537]10 * Based on concepts of Pavel Pisa, Till Straumann and Eric Valette.
[780428f]11 *
[dea4bbe3]12 * Copyright (c) 2008, 2018 embedded brains GmbH.
[dd8df59]13 *
14 *  embedded brains GmbH
[e0609ac]15 *  Dornierstr. 4
[dd8df59]16 *  82178 Puchheim
17 *  Germany
18 *  <rtems@embedded-brains.de>
[780428f]19 *
[8634637]20 * The license and distribution terms for this file may be
21 * found in the file LICENSE in this distribution or at
[c499856]22 * http://www.rtems.org/license/LICENSE.
[780428f]23 */
24
[a9e5e74]25#include <bsp/irq-generic.h>
[33cb8bf]26#include <bsp/fatal.h>
[a9e5e74]27
[8634637]28#include <stdlib.h>
[b3eeac38]29
[e19da87a]30#include <rtems/score/processormask.h>
[dea4bbe3]31#include <rtems/malloc.h>
[780428f]32
33#ifdef BSP_INTERRUPT_USE_INDEX_TABLE
[8634637]34  bsp_interrupt_handler_index_type bsp_interrupt_handler_index_table
35    [BSP_INTERRUPT_VECTOR_NUMBER];
36#endif
[780428f]37
[8634637]38bsp_interrupt_handler_entry bsp_interrupt_handler_table
39  [BSP_INTERRUPT_HANDLER_TABLE_SIZE];
[780428f]40
41/* The last entry indicates if everything is initialized */
[8634637]42static uint8_t bsp_interrupt_handler_unique_table
43  [(BSP_INTERRUPT_HANDLER_TABLE_SIZE + 7 + 1) / 8];
[780428f]44
[60e5832]45static void bsp_interrupt_handler_empty(void *arg)
[780428f]46{
[ec25c6ef]47  rtems_vector_number vector = (rtems_vector_number) (uintptr_t) arg;
[60e5832]48
[8634637]49  bsp_interrupt_handler_default(vector);
[780428f]50}
51
[e0609ac]52#ifdef RTEMS_SMP
53  static void bsp_interrupt_handler_do_nothing(void *arg)
54  {
55    (void) arg;
56  }
57#endif
58
[8634637]59static inline bool bsp_interrupt_is_handler_unique(rtems_vector_number index)
[780428f]60{
[8634637]61  rtems_vector_number i = index / 8;
62  rtems_vector_number s = index % 8;
63  return (bsp_interrupt_handler_unique_table [i] >> s) & 0x1;
64}
65
66static inline void bsp_interrupt_set_handler_unique(
67  rtems_vector_number index,
68  bool unique
69)
70{
71  rtems_vector_number i = index / 8;
72  rtems_vector_number s = index % 8;
73  if (unique) {
74    bsp_interrupt_handler_unique_table [i] |= (uint8_t) (0x1U << s);
75  } else {
76    bsp_interrupt_handler_unique_table [i] &= (uint8_t) ~(0x1U << s);
77  }
[780428f]78}
79
[f3eaba9a]80static inline bool bsp_interrupt_is_initialized(void)
[780428f]81{
[8634637]82  return bsp_interrupt_is_handler_unique(BSP_INTERRUPT_HANDLER_TABLE_SIZE);
[780428f]83}
84
[f3eaba9a]85static inline void bsp_interrupt_set_initialized(void)
[780428f]86{
[8634637]87  bsp_interrupt_set_handler_unique(BSP_INTERRUPT_HANDLER_TABLE_SIZE, true);
[780428f]88}
89
[8634637]90static inline bool bsp_interrupt_is_empty_handler_entry(
[956531b]91  const bsp_interrupt_handler_entry *e
[8634637]92)
[780428f]93{
[8634637]94  return e->handler == bsp_interrupt_handler_empty;
[780428f]95}
96
[8634637]97static inline void bsp_interrupt_clear_handler_entry(
[6faf789]98  bsp_interrupt_handler_entry *e,
99  rtems_vector_number vector
[8634637]100)
[780428f]101{
[8634637]102  e->handler = bsp_interrupt_handler_empty;
[e0609ac]103  bsp_interrupt_fence(ATOMIC_ORDER_RELEASE);
[ec25c6ef]104  e->arg = (void *) (uintptr_t) vector;
[8634637]105  e->info = NULL;
106  e->next = NULL;
[780428f]107}
108
[8634637]109static inline bool bsp_interrupt_allocate_handler_index(
110  rtems_vector_number vector,
111  rtems_vector_number *index
112)
[780428f]113{
[8634637]114  #ifdef BSP_INTERRUPT_USE_INDEX_TABLE
115    rtems_vector_number i = 0;
116
117    /* The first entry will remain empty */
118    for (i = 1; i < BSP_INTERRUPT_HANDLER_TABLE_SIZE; ++i) {
119      const bsp_interrupt_handler_entry *e = &bsp_interrupt_handler_table [i];
120      if (bsp_interrupt_is_empty_handler_entry(e)) {
121        *index = i;
122        return true;
123      }
124    }
125
126    return false;
127  #else
[a9859d1]128    *index = bsp_interrupt_handler_index(vector);
[8634637]129    return true;
130  #endif
[780428f]131}
132
[8634637]133static bsp_interrupt_handler_entry *bsp_interrupt_allocate_handler_entry(void)
[780428f]134{
[9a029ce]135  bsp_interrupt_handler_entry *e;
136
[8634637]137  #ifdef BSP_INTERRUPT_NO_HEAP_USAGE
138    rtems_vector_number index = 0;
[9a029ce]139
[8634637]140    if (bsp_interrupt_allocate_handler_index(0, &index)) {
[9a029ce]141      e = &bsp_interrupt_handler_table [index];
[8634637]142    } else {
[9a029ce]143      e = NULL;
[8634637]144    }
145  #else
[9a029ce]146    e = rtems_malloc(sizeof(*e));
[8634637]147  #endif
[9a029ce]148
149  return e;
[780428f]150}
151
[8634637]152static void bsp_interrupt_free_handler_entry(bsp_interrupt_handler_entry *e)
[780428f]153{
[8634637]154  #ifdef BSP_INTERRUPT_NO_HEAP_USAGE
[6faf789]155    bsp_interrupt_clear_handler_entry(e, 0);
[8634637]156  #else
157    free(e);
158  #endif
[780428f]159}
160
[dd8df59]161void bsp_interrupt_initialize(void)
[780428f]162{
[8634637]163  rtems_status_code sc = RTEMS_SUCCESSFUL;
164  size_t i = 0;
165
166  /* Initialize handler table */
167  for (i = 0; i < BSP_INTERRUPT_HANDLER_TABLE_SIZE; ++i) {
168    bsp_interrupt_handler_table [i].handler = bsp_interrupt_handler_empty;
[60e5832]169    bsp_interrupt_handler_table [i].arg = (void *) i;
[8634637]170  }
171
172  sc = bsp_interrupt_facility_initialize();
173  if (sc != RTEMS_SUCCESSFUL) {
[33cb8bf]174    bsp_fatal(BSP_FATAL_INTERRUPT_INITIALIZATION);
[8634637]175  }
176
177  bsp_interrupt_set_initialized();
[780428f]178}
179
180/**
181 * @brief Installs an interrupt handler.
182 *
183 * @ingroup bsp_interrupt
184 *
185 * @return In addition to the standard status codes this function returns:
186 * - If the BSP interrupt support is not initialized RTEMS_INTERNAL_ERROR will
187 * be returned.
188 * - If not enough memory for a new handler is available RTEMS_NO_MEMORY will
189 * be returned
190 *
191 * @see rtems_interrupt_handler_install()
192 */
[8634637]193static rtems_status_code bsp_interrupt_handler_install(
194  rtems_vector_number vector,
195  const char *info,
196  rtems_option options,
197  rtems_interrupt_handler handler,
198  void *arg
199)
[780428f]200{
[8634637]201  rtems_interrupt_level level;
202  rtems_vector_number index = 0;
203  bsp_interrupt_handler_entry *head = NULL;
204  bool enable_vector = false;
[718124e]205  bool replace = RTEMS_INTERRUPT_IS_REPLACE(options);
[8634637]206
207  /* Check parameters and system state */
208  if (!bsp_interrupt_is_initialized()) {
209    return RTEMS_INTERNAL_ERROR;
210  } else if (!bsp_interrupt_is_valid_vector(vector)) {
211    return RTEMS_INVALID_ID;
212  } else if (handler == NULL) {
213    return RTEMS_INVALID_ADDRESS;
214  } else if (rtems_interrupt_is_in_progress()) {
215    return RTEMS_CALLED_FROM_ISR;
216  }
217
218  /* Lock */
[a9e5e74]219  bsp_interrupt_lock();
[8634637]220
221  /* Get handler table index */
222  index = bsp_interrupt_handler_index(vector);
223
224  /* Get head entry of the handler list for current vector */
225  head = &bsp_interrupt_handler_table [index];
226
227  if (bsp_interrupt_is_empty_handler_entry(head)) {
[718124e]228    if (replace) {
229      /* No handler to replace exists */
230      bsp_interrupt_unlock();
231      return RTEMS_UNSATISFIED;
232    }
233
[8634637]234    /*
235     * No real handler installed yet.  So allocate a new index in
236     * the handler table and fill the entry with life.
237     */
238    if (bsp_interrupt_allocate_handler_index(vector, &index)) {
[e0609ac]239      bsp_interrupt_disable(level);
[8634637]240      bsp_interrupt_handler_table [index].arg = arg;
[e0609ac]241      bsp_interrupt_fence(ATOMIC_ORDER_RELEASE);
242      bsp_interrupt_handler_table [index].handler = handler;
[8634637]243      #ifdef BSP_INTERRUPT_USE_INDEX_TABLE
244        bsp_interrupt_handler_index_table [vector] = index;
245      #endif
[e0609ac]246      bsp_interrupt_enable(level);
[8634637]247      bsp_interrupt_handler_table [index].info = info;
248    } else {
249      /* Handler table is full */
250      bsp_interrupt_unlock();
251      return RTEMS_NO_MEMORY;
252    }
253
254    /* This is the first handler so enable the vector later */
255    enable_vector = true;
256  } else {
[718124e]257    bsp_interrupt_handler_entry *current = head;
258    bsp_interrupt_handler_entry *tail = NULL;
259    bsp_interrupt_handler_entry *match = NULL;
260
[8634637]261    /* Ensure that a unique handler remains unique */
262    if (
[718124e]263      !replace
264        && (RTEMS_INTERRUPT_IS_UNIQUE(options)
265          || bsp_interrupt_is_handler_unique(index))
[8634637]266    ) {
267      /*
268       * Tried to install a unique handler on a not empty
269       * list or there is already a unique handler installed.
270       */
271      bsp_interrupt_unlock();
272      return RTEMS_RESOURCE_IN_USE;
273    }
274
275    /*
276     * Search for the list tail and check if the handler is already
277     * installed.
278     */
279    do {
[718124e]280      if (
281        match == NULL
282          && (current->handler == handler || replace)
283          && current->arg == arg
284      ) {
[8634637]285        match = current;
286      }
287      tail = current;
288      current = current->next;
289    } while (current != NULL);
290
[718124e]291    if (replace) {
292      /* Ensure that a handler to replace exists */
293      if (match == NULL) {
294        bsp_interrupt_unlock();
295        return RTEMS_UNSATISFIED;
296      }
[8634637]297
[718124e]298      /* Use existing entry */
299      current = match;
300    } else {
301      /* Ensure the handler is not already installed */
302      if (match != NULL) {
303        /* The handler is already installed */
304        bsp_interrupt_unlock();
305        return RTEMS_TOO_MANY;
306      }
307
308      /* Allocate a new entry */
309      current = bsp_interrupt_allocate_handler_entry();
310      if (current == NULL) {
311        /* Not enough memory */
312        bsp_interrupt_unlock();
313        return RTEMS_NO_MEMORY;
314      }
[8634637]315    }
316
[718124e]317    /* Update existing entry or set new entry */
[8634637]318    current->handler = handler;
319    current->info = info;
320
[718124e]321    if (!replace) {
322      /* Set new entry */
323      current->arg = arg;
324      current->next = NULL;
325
326      /* Link to list tail */
327      bsp_interrupt_disable(level);
328      bsp_interrupt_fence(ATOMIC_ORDER_RELEASE);
329      tail->next = current;
330      bsp_interrupt_enable(level);
331    }
[8634637]332  }
333
334  /* Make the handler unique if necessary */
335  bsp_interrupt_set_handler_unique(index, RTEMS_INTERRUPT_IS_UNIQUE(options));
336
337  /* Enable the vector if necessary */
338  if (enable_vector) {
[c6810c8]339    bsp_interrupt_vector_enable(vector);
[8634637]340  }
341
342  /* Unlock */
[a9e5e74]343  bsp_interrupt_unlock();
[8634637]344
345  return RTEMS_SUCCESSFUL;
[780428f]346}
347
348/**
349 * @brief Removes an interrupt handler.
350 *
351 * @ingroup bsp_interrupt
352 *
353 * @return In addition to the standard status codes this function returns
354 * RTEMS_INTERNAL_ERROR if the BSP interrupt support is not initialized.
355 *
356 * @see rtems_interrupt_handler_remove().
357 */
[8634637]358static rtems_status_code bsp_interrupt_handler_remove(
359  rtems_vector_number vector,
360  rtems_interrupt_handler handler,
361  void *arg
362)
[780428f]363{
[8634637]364  rtems_interrupt_level level;
365  rtems_vector_number index = 0;
366  bsp_interrupt_handler_entry *head = NULL;
367  bsp_interrupt_handler_entry *current = NULL;
368  bsp_interrupt_handler_entry *previous = NULL;
369  bsp_interrupt_handler_entry *match = NULL;
370
371  /* Check parameters and system state */
372  if (!bsp_interrupt_is_initialized()) {
373    return RTEMS_INTERNAL_ERROR;
374  } else if (!bsp_interrupt_is_valid_vector(vector)) {
375    return RTEMS_INVALID_ID;
376  } else if (handler == NULL) {
377    return RTEMS_INVALID_ADDRESS;
378  } else if (rtems_interrupt_is_in_progress()) {
379    return RTEMS_CALLED_FROM_ISR;
380  }
381
382  /* Lock */
[a9e5e74]383  bsp_interrupt_lock();
[8634637]384
385  /* Get handler table index */
386  index = bsp_interrupt_handler_index(vector);
387
388  /* Get head entry of the handler list for current vector */
389  head = &bsp_interrupt_handler_table [index];
390
391  /* Search for a matching entry */
392  current = head;
393  do {
394    if (current->handler == handler && current->arg == arg) {
395      match = current;
396      break;
397    }
398    previous = current;
399    current = current->next;
400  } while (current != NULL);
401
402  /* Remove the matching entry */
403  if (match != NULL) {
404    if (match->next != NULL) {
405      /*
406       * The match has a successor.  A successor is always
407       * allocated.  So replace the match with its successor
408       * and free the successor entry.
409       */
410      current = match->next;
411
[e0609ac]412      bsp_interrupt_disable(level);
413      #ifdef RTEMS_SMP
414        match->handler = bsp_interrupt_handler_do_nothing;
415        bsp_interrupt_fence(ATOMIC_ORDER_RELEASE);
416      #endif
417      match->arg = current->arg;
418      bsp_interrupt_fence(ATOMIC_ORDER_RELEASE);
419      match->handler = current->handler;
420      match->info = current->info;
421      match->next = current->next;
422      bsp_interrupt_enable(level);
[8634637]423
424      bsp_interrupt_free_handler_entry(current);
425    } else if (match == head) {
426      /*
427       * The match is the list head and has no successor.
428       * The list head is stored in a static table so clear
429       * this entry.  Since now the list is empty disable the
430       * vector.
431       */
432
433      /* Disable the vector */
[c6810c8]434      bsp_interrupt_vector_disable(vector);
[8634637]435
436      /* Clear entry */
[e0609ac]437      bsp_interrupt_disable(level);
[6faf789]438      bsp_interrupt_clear_handler_entry(head, vector);
[8634637]439      #ifdef BSP_INTERRUPT_USE_INDEX_TABLE
440        bsp_interrupt_handler_index_table [vector] = 0;
441      #endif
[e0609ac]442      bsp_interrupt_enable(level);
[8634637]443
444      /* Allow shared handlers */
445      bsp_interrupt_set_handler_unique(index, false);
446    } else {
447      /*
448       * The match is the list tail and has a predecessor.
449       * So terminate the predecessor and free the match.
450       */
[e0609ac]451      bsp_interrupt_disable(level);
[8634637]452      previous->next = NULL;
[e0609ac]453      bsp_interrupt_fence(ATOMIC_ORDER_RELEASE);
454      bsp_interrupt_enable(level);
[8634637]455
456      bsp_interrupt_free_handler_entry(match);
457    }
458  } else {
459    /* No matching entry found */
460    bsp_interrupt_unlock();
461    return RTEMS_UNSATISFIED;
462  }
463
464  /* Unlock */
[a9e5e74]465  bsp_interrupt_unlock();
[8634637]466
467  return RTEMS_SUCCESSFUL;
[780428f]468}
469
[2e2c640e]470/**
471 * @brief Iterates over all installed interrupt handler of a vector.
472 *
473 * @ingroup bsp_interrupt
474 *
475 * @return In addition to the standard status codes this function returns
476 * RTEMS_INTERNAL_ERROR if the BSP interrupt support is not initialized.
477 *
478 * @see rtems_interrupt_handler_iterate().
479 */
[8634637]480static rtems_status_code bsp_interrupt_handler_iterate(
481  rtems_vector_number vector,
482  rtems_interrupt_per_handler_routine routine,
483  void *arg
484)
[780428f]485{
[8634637]486  bsp_interrupt_handler_entry *current = NULL;
487  rtems_option options = 0;
488  rtems_vector_number index = 0;
489
490  /* Check parameters and system state */
491  if (!bsp_interrupt_is_initialized()) {
492    return RTEMS_INTERNAL_ERROR;
493  } else if (!bsp_interrupt_is_valid_vector(vector)) {
494    return RTEMS_INVALID_ID;
495  } else if (rtems_interrupt_is_in_progress()) {
496    return RTEMS_CALLED_FROM_ISR;
497  }
498
499  /* Lock */
[a9e5e74]500  bsp_interrupt_lock();
[8634637]501
502  /* Interate */
503  index = bsp_interrupt_handler_index(vector);
504  current = &bsp_interrupt_handler_table [index];
505  if (!bsp_interrupt_is_empty_handler_entry(current)) {
506    do {
507      options = bsp_interrupt_is_handler_unique(index) ?
508        RTEMS_INTERRUPT_UNIQUE : RTEMS_INTERRUPT_SHARED;
509      routine(arg, current->info, options, current->handler, current->arg);
510      current = current->next;
511    } while (current != NULL);
512  }
513
514  /* Unlock */
[a9e5e74]515  bsp_interrupt_unlock();
[8634637]516
517  return RTEMS_SUCCESSFUL;
[780428f]518}
519
[8634637]520rtems_status_code rtems_interrupt_handler_install(
521  rtems_vector_number vector,
522  const char *info,
523  rtems_option options,
524  rtems_interrupt_handler handler,
525  void *arg
526)
[780428f]527{
[8634637]528  return bsp_interrupt_handler_install(vector, info, options, handler, arg);
[2e2c640e]529}
[780428f]530
[8634637]531rtems_status_code rtems_interrupt_handler_remove(
532  rtems_vector_number vector,
533  rtems_interrupt_handler handler,
534  void *arg
535)
[2e2c640e]536{
[8634637]537  return bsp_interrupt_handler_remove(vector, handler, arg);
[2e2c640e]538}
[780428f]539
[8634637]540rtems_status_code rtems_interrupt_handler_iterate(
541  rtems_vector_number vector,
542  rtems_interrupt_per_handler_routine routine,
543  void *arg
544)
[2e2c640e]545{
[8634637]546  return bsp_interrupt_handler_iterate(vector, routine, arg);
[780428f]547}
[43f18a1]548
549bool bsp_interrupt_handler_is_empty(rtems_vector_number vector)
550{
551  rtems_vector_number index = 0;
552  bsp_interrupt_handler_entry *head = NULL;
553  bool empty;
554
555  /* For use in interrupts so no lock. */
556
557  /* Get handler table index */
558  index = bsp_interrupt_handler_index(vector);
559
560  /* Get head entry of the handler list for the vector */
561  head = &bsp_interrupt_handler_table [index];
562
563  empty = bsp_interrupt_is_empty_handler_entry(head);
564
565  return empty;
566}
[af207fa9]567
568rtems_status_code rtems_interrupt_set_affinity(
569  rtems_vector_number  vector,
570  size_t               affinity_size,
571  const cpu_set_t     *affinity
572)
573{
574  Processor_mask             set;
575  Processor_mask_Copy_status status;
576
577  if (!bsp_interrupt_is_valid_vector(vector)) {
578    return RTEMS_INVALID_ID;
579  }
580
581  status = _Processor_mask_From_cpu_set_t(&set, affinity_size, affinity);
582  if (status != PROCESSOR_MASK_COPY_LOSSLESS) {
583    return RTEMS_INVALID_SIZE;
584  }
585
586#if defined(RTEMS_SMP)
587  bsp_interrupt_set_affinity(vector, &set);
588#endif
589  return RTEMS_SUCCESSFUL;
590}
591
592rtems_status_code rtems_interrupt_get_affinity(
593  rtems_vector_number  vector,
594  size_t               affinity_size,
595  cpu_set_t           *affinity
596)
597{
598  Processor_mask             set;
599  Processor_mask_Copy_status status;
600
601  if (!bsp_interrupt_is_valid_vector(vector)) {
602    return RTEMS_INVALID_ID;
603  }
604
605#if defined(RTEMS_SMP)
606  bsp_interrupt_get_affinity(vector, &set);
607#else
608  _Processor_mask_From_index(&set, 0);
609#endif
610
611  status = _Processor_mask_To_cpu_set_t(&set, affinity_size, affinity);
612  if (status != PROCESSOR_MASK_COPY_LOSSLESS) {
613    return RTEMS_INVALID_SIZE;
614  }
615
616  return RTEMS_SUCCESSFUL;
617}
Note: See TracBrowser for help on using the repository browser.