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 Nov 9, 2018 at 12:06:52 PM

bsps/irq: Use rtems_malloc()

  • Property mode set to 100644
File size: 15.7 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup bsp_interrupt
5 *
6 * @brief Generic BSP interrupt support implementation.
7 */
8
9/*
10 * Based on concepts of Pavel Pisa, Till Straumann and Eric Valette.
11 *
12 * Copyright (c) 2008, 2018 embedded brains GmbH.
13 *
14 *  embedded brains GmbH
15 *  Dornierstr. 4
16 *  82178 Puchheim
17 *  Germany
18 *  <rtems@embedded-brains.de>
19 *
20 * The license and distribution terms for this file may be
21 * found in the file LICENSE in this distribution or at
22 * http://www.rtems.org/license/LICENSE.
23 */
24
25#include <bsp/irq-generic.h>
26#include <bsp/fatal.h>
27
28#include <stdlib.h>
29
30#include <rtems/score/processormask.h>
31#include <rtems/malloc.h>
32
33#ifdef BSP_INTERRUPT_USE_INDEX_TABLE
34  bsp_interrupt_handler_index_type bsp_interrupt_handler_index_table
35    [BSP_INTERRUPT_VECTOR_NUMBER];
36#endif
37
38bsp_interrupt_handler_entry bsp_interrupt_handler_table
39  [BSP_INTERRUPT_HANDLER_TABLE_SIZE];
40
41/* The last entry indicates if everything is initialized */
42static uint8_t bsp_interrupt_handler_unique_table
43  [(BSP_INTERRUPT_HANDLER_TABLE_SIZE + 7 + 1) / 8];
44
45static void bsp_interrupt_handler_empty(void *arg)
46{
47  rtems_vector_number vector = (rtems_vector_number) (uintptr_t) arg;
48
49  bsp_interrupt_handler_default(vector);
50}
51
52#ifdef RTEMS_SMP
53  static void bsp_interrupt_handler_do_nothing(void *arg)
54  {
55    (void) arg;
56  }
57#endif
58
59static inline bool bsp_interrupt_is_handler_unique(rtems_vector_number index)
60{
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  }
78}
79
80static inline bool bsp_interrupt_is_initialized(void)
81{
82  return bsp_interrupt_is_handler_unique(BSP_INTERRUPT_HANDLER_TABLE_SIZE);
83}
84
85static inline void bsp_interrupt_set_initialized(void)
86{
87  bsp_interrupt_set_handler_unique(BSP_INTERRUPT_HANDLER_TABLE_SIZE, true);
88}
89
90static inline bool bsp_interrupt_is_empty_handler_entry(
91  const bsp_interrupt_handler_entry *e
92)
93{
94  return e->handler == bsp_interrupt_handler_empty;
95}
96
97static inline void bsp_interrupt_clear_handler_entry(
98  bsp_interrupt_handler_entry *e,
99  rtems_vector_number vector
100)
101{
102  e->handler = bsp_interrupt_handler_empty;
103  bsp_interrupt_fence(ATOMIC_ORDER_RELEASE);
104  e->arg = (void *) (uintptr_t) vector;
105  e->info = NULL;
106  e->next = NULL;
107}
108
109static inline bool bsp_interrupt_allocate_handler_index(
110  rtems_vector_number vector,
111  rtems_vector_number *index
112)
113{
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
128    *index = bsp_interrupt_handler_index(vector);
129    return true;
130  #endif
131}
132
133static bsp_interrupt_handler_entry *bsp_interrupt_allocate_handler_entry(void)
134{
135  bsp_interrupt_handler_entry *e;
136
137  #ifdef BSP_INTERRUPT_NO_HEAP_USAGE
138    rtems_vector_number index = 0;
139
140    if (bsp_interrupt_allocate_handler_index(0, &index)) {
141      e = &bsp_interrupt_handler_table [index];
142    } else {
143      e = NULL;
144    }
145  #else
146    e = rtems_malloc(sizeof(*e));
147  #endif
148
149  return e;
150}
151
152static void bsp_interrupt_free_handler_entry(bsp_interrupt_handler_entry *e)
153{
154  #ifdef BSP_INTERRUPT_NO_HEAP_USAGE
155    bsp_interrupt_clear_handler_entry(e, 0);
156  #else
157    free(e);
158  #endif
159}
160
161void bsp_interrupt_initialize(void)
162{
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;
169    bsp_interrupt_handler_table [i].arg = (void *) i;
170  }
171
172  sc = bsp_interrupt_facility_initialize();
173  if (sc != RTEMS_SUCCESSFUL) {
174    bsp_fatal(BSP_FATAL_INTERRUPT_INITIALIZATION);
175  }
176
177  bsp_interrupt_set_initialized();
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 */
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)
200{
201  rtems_interrupt_level level;
202  rtems_vector_number index = 0;
203  bsp_interrupt_handler_entry *head = NULL;
204  bool enable_vector = false;
205  bool replace = RTEMS_INTERRUPT_IS_REPLACE(options);
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 */
219  bsp_interrupt_lock();
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)) {
228    if (replace) {
229      /* No handler to replace exists */
230      bsp_interrupt_unlock();
231      return RTEMS_UNSATISFIED;
232    }
233
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)) {
239      bsp_interrupt_disable(level);
240      bsp_interrupt_handler_table [index].arg = arg;
241      bsp_interrupt_fence(ATOMIC_ORDER_RELEASE);
242      bsp_interrupt_handler_table [index].handler = handler;
243      #ifdef BSP_INTERRUPT_USE_INDEX_TABLE
244        bsp_interrupt_handler_index_table [vector] = index;
245      #endif
246      bsp_interrupt_enable(level);
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 {
257    bsp_interrupt_handler_entry *current = head;
258    bsp_interrupt_handler_entry *tail = NULL;
259    bsp_interrupt_handler_entry *match = NULL;
260
261    /* Ensure that a unique handler remains unique */
262    if (
263      !replace
264        && (RTEMS_INTERRUPT_IS_UNIQUE(options)
265          || bsp_interrupt_is_handler_unique(index))
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 {
280      if (
281        match == NULL
282          && (current->handler == handler || replace)
283          && current->arg == arg
284      ) {
285        match = current;
286      }
287      tail = current;
288      current = current->next;
289    } while (current != NULL);
290
291    if (replace) {
292      /* Ensure that a handler to replace exists */
293      if (match == NULL) {
294        bsp_interrupt_unlock();
295        return RTEMS_UNSATISFIED;
296      }
297
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      }
315    }
316
317    /* Update existing entry or set new entry */
318    current->handler = handler;
319    current->info = info;
320
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    }
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) {
339    bsp_interrupt_vector_enable(vector);
340  }
341
342  /* Unlock */
343  bsp_interrupt_unlock();
344
345  return RTEMS_SUCCESSFUL;
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 */
358static rtems_status_code bsp_interrupt_handler_remove(
359  rtems_vector_number vector,
360  rtems_interrupt_handler handler,
361  void *arg
362)
363{
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 */
383  bsp_interrupt_lock();
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
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);
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 */
434      bsp_interrupt_vector_disable(vector);
435
436      /* Clear entry */
437      bsp_interrupt_disable(level);
438      bsp_interrupt_clear_handler_entry(head, vector);
439      #ifdef BSP_INTERRUPT_USE_INDEX_TABLE
440        bsp_interrupt_handler_index_table [vector] = 0;
441      #endif
442      bsp_interrupt_enable(level);
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       */
451      bsp_interrupt_disable(level);
452      previous->next = NULL;
453      bsp_interrupt_fence(ATOMIC_ORDER_RELEASE);
454      bsp_interrupt_enable(level);
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 */
465  bsp_interrupt_unlock();
466
467  return RTEMS_SUCCESSFUL;
468}
469
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 */
480static rtems_status_code bsp_interrupt_handler_iterate(
481  rtems_vector_number vector,
482  rtems_interrupt_per_handler_routine routine,
483  void *arg
484)
485{
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 */
500  bsp_interrupt_lock();
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 */
515  bsp_interrupt_unlock();
516
517  return RTEMS_SUCCESSFUL;
518}
519
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)
527{
528  return bsp_interrupt_handler_install(vector, info, options, handler, arg);
529}
530
531rtems_status_code rtems_interrupt_handler_remove(
532  rtems_vector_number vector,
533  rtems_interrupt_handler handler,
534  void *arg
535)
536{
537  return bsp_interrupt_handler_remove(vector, handler, arg);
538}
539
540rtems_status_code rtems_interrupt_handler_iterate(
541  rtems_vector_number vector,
542  rtems_interrupt_per_handler_routine routine,
543  void *arg
544)
545{
546  return bsp_interrupt_handler_iterate(vector, routine, arg);
547}
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}
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.