source: rtems/c/src/lib/libbsp/shared/src/irq-generic.c @ ade27c6

4.115
Last change on this file since ade27c6 was ade27c6, checked in by Sebastian Huber <sebastian.huber@…>, on Jun 20, 2013 at 9:44:04 AM

bsps: Move bsp_generic_fatal_code to new file

Add bsp_generic_fatal().

  • Property mode set to 100644
File size: 13.3 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-2012 embedded brains GmbH.
13 *
14 *  embedded brains GmbH
15 *  Obere Lagerstr. 30
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.com/license/LICENSE.
23 */
24
25#include <bsp/irq-generic.h>
26#include <bsp/generic-fatal.h>
27
28#include <stdlib.h>
29
30#include <rtems/score/apimutex.h>
31
32#ifdef BSP_INTERRUPT_USE_INDEX_TABLE
33  bsp_interrupt_handler_index_type bsp_interrupt_handler_index_table
34    [BSP_INTERRUPT_VECTOR_NUMBER];
35#endif
36
37bsp_interrupt_handler_entry bsp_interrupt_handler_table
38  [BSP_INTERRUPT_HANDLER_TABLE_SIZE];
39
40/* The last entry indicates if everything is initialized */
41static uint8_t bsp_interrupt_handler_unique_table
42  [(BSP_INTERRUPT_HANDLER_TABLE_SIZE + 7 + 1) / 8];
43
44static void bsp_interrupt_handler_empty(void *arg)
45{
46  rtems_vector_number vector = (rtems_vector_number) arg;
47
48  bsp_interrupt_handler_default(vector);
49}
50
51static inline bool bsp_interrupt_is_handler_unique(rtems_vector_number index)
52{
53  rtems_vector_number i = index / 8;
54  rtems_vector_number s = index % 8;
55  return (bsp_interrupt_handler_unique_table [i] >> s) & 0x1;
56}
57
58static inline void bsp_interrupt_set_handler_unique(
59  rtems_vector_number index,
60  bool unique
61)
62{
63  rtems_vector_number i = index / 8;
64  rtems_vector_number s = index % 8;
65  if (unique) {
66    bsp_interrupt_handler_unique_table [i] |= (uint8_t) (0x1U << s);
67  } else {
68    bsp_interrupt_handler_unique_table [i] &= (uint8_t) ~(0x1U << s);
69  }
70}
71
72static inline bool bsp_interrupt_is_initialized(void)
73{
74  return bsp_interrupt_is_handler_unique(BSP_INTERRUPT_HANDLER_TABLE_SIZE);
75}
76
77static inline void bsp_interrupt_set_initialized(void)
78{
79  bsp_interrupt_set_handler_unique(BSP_INTERRUPT_HANDLER_TABLE_SIZE, true);
80}
81
82static inline bool bsp_interrupt_is_empty_handler_entry(
83  const bsp_interrupt_handler_entry *e
84)
85{
86  return e->handler == bsp_interrupt_handler_empty;
87}
88
89static inline void bsp_interrupt_clear_handler_entry(
90  bsp_interrupt_handler_entry *e
91)
92{
93  e->handler = bsp_interrupt_handler_empty;
94  e->arg = NULL;
95  e->info = NULL;
96  e->next = NULL;
97}
98
99static inline bool bsp_interrupt_allocate_handler_index(
100  rtems_vector_number vector,
101  rtems_vector_number *index
102)
103{
104  #ifdef BSP_INTERRUPT_USE_INDEX_TABLE
105    rtems_vector_number i = 0;
106
107    /* The first entry will remain empty */
108    for (i = 1; i < BSP_INTERRUPT_HANDLER_TABLE_SIZE; ++i) {
109      const bsp_interrupt_handler_entry *e = &bsp_interrupt_handler_table [i];
110      if (bsp_interrupt_is_empty_handler_entry(e)) {
111        *index = i;
112        return true;
113      }
114    }
115
116    return false;
117  #else
118    *index = vector;
119    return true;
120  #endif
121}
122
123static bsp_interrupt_handler_entry *bsp_interrupt_allocate_handler_entry(void)
124{
125  #ifdef BSP_INTERRUPT_NO_HEAP_USAGE
126    rtems_vector_number index = 0;
127    if (bsp_interrupt_allocate_handler_index(0, &index)) {
128      return &bsp_interrupt_handler_table [index];
129    } else {
130      return NULL;
131    }
132  #else
133    return malloc(sizeof(bsp_interrupt_handler_entry));
134  #endif
135}
136
137static void bsp_interrupt_free_handler_entry(bsp_interrupt_handler_entry *e)
138{
139  #ifdef BSP_INTERRUPT_NO_HEAP_USAGE
140    bsp_interrupt_clear_handler_entry(e);
141  #else
142    free(e);
143  #endif
144}
145
146static void bsp_interrupt_lock(void)
147{
148  if (_System_state_Is_up(_System_state_Get())) {
149    _RTEMS_Lock_allocator();
150  }
151}
152
153static void bsp_interrupt_unlock(void)
154{
155  if (_System_state_Is_up(_System_state_Get())) {
156    _RTEMS_Unlock_allocator();
157  }
158}
159
160void bsp_interrupt_initialize(void)
161{
162  rtems_status_code sc = RTEMS_SUCCESSFUL;
163  size_t i = 0;
164
165  /* Initialize handler table */
166  for (i = 0; i < BSP_INTERRUPT_HANDLER_TABLE_SIZE; ++i) {
167    bsp_interrupt_handler_table [i].handler = bsp_interrupt_handler_empty;
168    bsp_interrupt_handler_table [i].arg = (void *) i;
169  }
170
171  sc = bsp_interrupt_facility_initialize();
172  if (sc != RTEMS_SUCCESSFUL) {
173    bsp_generic_fatal(BSP_GENERIC_FATAL_INTERRUPT_INITIALIZATION);
174  }
175
176  bsp_interrupt_set_initialized();
177}
178
179/**
180 * @brief Installs an interrupt handler.
181 *
182 * @ingroup bsp_interrupt
183 *
184 * @return In addition to the standard status codes this function returns:
185 * - If the BSP interrupt support is not initialized RTEMS_INTERNAL_ERROR will
186 * be returned.
187 * - If not enough memory for a new handler is available RTEMS_NO_MEMORY will
188 * be returned
189 *
190 * @see rtems_interrupt_handler_install()
191 */
192static rtems_status_code bsp_interrupt_handler_install(
193  rtems_vector_number vector,
194  const char *info,
195  rtems_option options,
196  rtems_interrupt_handler handler,
197  void *arg
198)
199{
200  rtems_status_code sc = RTEMS_SUCCESSFUL;
201  rtems_interrupt_level level;
202  rtems_vector_number index = 0;
203  bsp_interrupt_handler_entry *head = NULL;
204  bsp_interrupt_handler_entry *tail = NULL;
205  bsp_interrupt_handler_entry *current = NULL;
206  bsp_interrupt_handler_entry *match = NULL;
207  bool enable_vector = false;
208
209  /* Check parameters and system state */
210  if (!bsp_interrupt_is_initialized()) {
211    return RTEMS_INTERNAL_ERROR;
212  } else if (!bsp_interrupt_is_valid_vector(vector)) {
213    return RTEMS_INVALID_ID;
214  } else if (handler == NULL) {
215    return RTEMS_INVALID_ADDRESS;
216  } else if (rtems_interrupt_is_in_progress()) {
217    return RTEMS_CALLED_FROM_ISR;
218  }
219
220  /* Lock */
221  bsp_interrupt_lock();
222
223  /* Get handler table index */
224  index = bsp_interrupt_handler_index(vector);
225
226  /* Get head entry of the handler list for current vector */
227  head = &bsp_interrupt_handler_table [index];
228
229  if (bsp_interrupt_is_empty_handler_entry(head)) {
230    /*
231     * No real handler installed yet.  So allocate a new index in
232     * the handler table and fill the entry with life.
233     */
234    if (bsp_interrupt_allocate_handler_index(vector, &index)) {
235      rtems_interrupt_disable(level);
236      bsp_interrupt_handler_table [index].handler = handler;
237      bsp_interrupt_handler_table [index].arg = arg;
238      #ifdef BSP_INTERRUPT_USE_INDEX_TABLE
239        bsp_interrupt_handler_index_table [vector] = index;
240      #endif
241      rtems_interrupt_enable(level);
242      bsp_interrupt_handler_table [index].info = info;
243    } else {
244      /* Handler table is full */
245      bsp_interrupt_unlock();
246      return RTEMS_NO_MEMORY;
247    }
248
249    /* This is the first handler so enable the vector later */
250    enable_vector = true;
251  } else {
252    /* Ensure that a unique handler remains unique */
253    if (
254      RTEMS_INTERRUPT_IS_UNIQUE(options)
255        || bsp_interrupt_is_handler_unique(index)
256    ) {
257      /*
258       * Tried to install a unique handler on a not empty
259       * list or there is already a unique handler installed.
260       */
261      bsp_interrupt_unlock();
262      return RTEMS_RESOURCE_IN_USE;
263    }
264
265    /*
266     * Search for the list tail and check if the handler is already
267     * installed.
268     */
269    current = head;
270    do {
271      if (current->handler == handler && current->arg == arg) {
272        match = current;
273      }
274      tail = current;
275      current = current->next;
276    } while (current != NULL);
277
278    /* Ensure the handler is not already installed */
279    if (match != NULL) {
280      /* The handler is already installed */
281      bsp_interrupt_unlock();
282      return RTEMS_TOO_MANY;
283    }
284
285    /* Allocate a new entry */
286    current = bsp_interrupt_allocate_handler_entry();
287    if (current == NULL) {
288      /* Not enough memory */
289      bsp_interrupt_unlock();
290      return RTEMS_NO_MEMORY;
291    }
292
293    /* Set entry */
294    current->handler = handler;
295    current->arg = arg;
296    current->info = info;
297    current->next = NULL;
298
299    /* Link to list tail */
300    rtems_interrupt_disable(level);
301    tail->next = current;
302    rtems_interrupt_enable(level);
303  }
304
305  /* Make the handler unique if necessary */
306  bsp_interrupt_set_handler_unique(index, RTEMS_INTERRUPT_IS_UNIQUE(options));
307
308  /* Enable the vector if necessary */
309  if (enable_vector) {
310    sc = bsp_interrupt_vector_enable(vector);
311    if (sc != RTEMS_SUCCESSFUL) {
312      bsp_interrupt_unlock();
313      return sc;
314    }
315  }
316
317  /* Unlock */
318  bsp_interrupt_unlock();
319
320  return RTEMS_SUCCESSFUL;
321}
322
323/**
324 * @brief Removes an interrupt handler.
325 *
326 * @ingroup bsp_interrupt
327 *
328 * @return In addition to the standard status codes this function returns
329 * RTEMS_INTERNAL_ERROR if the BSP interrupt support is not initialized.
330 *
331 * @see rtems_interrupt_handler_remove().
332 */
333static rtems_status_code bsp_interrupt_handler_remove(
334  rtems_vector_number vector,
335  rtems_interrupt_handler handler,
336  void *arg
337)
338{
339  rtems_status_code sc = RTEMS_SUCCESSFUL;
340  rtems_interrupt_level level;
341  rtems_vector_number index = 0;
342  bsp_interrupt_handler_entry *head = NULL;
343  bsp_interrupt_handler_entry *current = NULL;
344  bsp_interrupt_handler_entry *previous = NULL;
345  bsp_interrupt_handler_entry *match = NULL;
346
347  /* Check parameters and system state */
348  if (!bsp_interrupt_is_initialized()) {
349    return RTEMS_INTERNAL_ERROR;
350  } else if (!bsp_interrupt_is_valid_vector(vector)) {
351    return RTEMS_INVALID_ID;
352  } else if (handler == NULL) {
353    return RTEMS_INVALID_ADDRESS;
354  } else if (rtems_interrupt_is_in_progress()) {
355    return RTEMS_CALLED_FROM_ISR;
356  }
357
358  /* Lock */
359  bsp_interrupt_lock();
360
361  /* Get handler table index */
362  index = bsp_interrupt_handler_index(vector);
363
364  /* Get head entry of the handler list for current vector */
365  head = &bsp_interrupt_handler_table [index];
366
367  /* Search for a matching entry */
368  current = head;
369  do {
370    if (current->handler == handler && current->arg == arg) {
371      match = current;
372      break;
373    }
374    previous = current;
375    current = current->next;
376  } while (current != NULL);
377
378  /* Remove the matching entry */
379  if (match != NULL) {
380    if (match->next != NULL) {
381      /*
382       * The match has a successor.  A successor is always
383       * allocated.  So replace the match with its successor
384       * and free the successor entry.
385       */
386      current = match->next;
387
388      rtems_interrupt_disable(level);
389      *match = *current;
390      rtems_interrupt_enable(level);
391
392      bsp_interrupt_free_handler_entry(current);
393    } else if (match == head) {
394      /*
395       * The match is the list head and has no successor.
396       * The list head is stored in a static table so clear
397       * this entry.  Since now the list is empty disable the
398       * vector.
399       */
400
401      /* Disable the vector */
402      sc = bsp_interrupt_vector_disable(vector);
403
404      /* Clear entry */
405      rtems_interrupt_disable(level);
406      bsp_interrupt_clear_handler_entry(head);
407      #ifdef BSP_INTERRUPT_USE_INDEX_TABLE
408        bsp_interrupt_handler_index_table [vector] = 0;
409      #endif
410      rtems_interrupt_enable(level);
411
412      /* Allow shared handlers */
413      bsp_interrupt_set_handler_unique(index, false);
414
415      /* Check status code */
416      if (sc != RTEMS_SUCCESSFUL) {
417        bsp_interrupt_unlock();
418        return sc;
419      }
420    } else {
421      /*
422       * The match is the list tail and has a predecessor.
423       * So terminate the predecessor and free the match.
424       */
425      rtems_interrupt_disable(level);
426      previous->next = NULL;
427      rtems_interrupt_enable(level);
428
429      bsp_interrupt_free_handler_entry(match);
430    }
431  } else {
432    /* No matching entry found */
433    bsp_interrupt_unlock();
434    return RTEMS_UNSATISFIED;
435  }
436
437  /* Unlock */
438  bsp_interrupt_unlock();
439
440  return RTEMS_SUCCESSFUL;
441}
442
443/**
444 * @brief Iterates over all installed interrupt handler of a vector.
445 *
446 * @ingroup bsp_interrupt
447 *
448 * @return In addition to the standard status codes this function returns
449 * RTEMS_INTERNAL_ERROR if the BSP interrupt support is not initialized.
450 *
451 * @see rtems_interrupt_handler_iterate().
452 */
453static rtems_status_code bsp_interrupt_handler_iterate(
454  rtems_vector_number vector,
455  rtems_interrupt_per_handler_routine routine,
456  void *arg
457)
458{
459  bsp_interrupt_handler_entry *current = NULL;
460  rtems_option options = 0;
461  rtems_vector_number index = 0;
462
463  /* Check parameters and system state */
464  if (!bsp_interrupt_is_initialized()) {
465    return RTEMS_INTERNAL_ERROR;
466  } else if (!bsp_interrupt_is_valid_vector(vector)) {
467    return RTEMS_INVALID_ID;
468  } else if (rtems_interrupt_is_in_progress()) {
469    return RTEMS_CALLED_FROM_ISR;
470  }
471
472  /* Lock */
473  bsp_interrupt_lock();
474
475  /* Interate */
476  index = bsp_interrupt_handler_index(vector);
477  current = &bsp_interrupt_handler_table [index];
478  if (!bsp_interrupt_is_empty_handler_entry(current)) {
479    do {
480      options = bsp_interrupt_is_handler_unique(index) ?
481        RTEMS_INTERRUPT_UNIQUE : RTEMS_INTERRUPT_SHARED;
482      routine(arg, current->info, options, current->handler, current->arg);
483      current = current->next;
484    } while (current != NULL);
485  }
486
487  /* Unlock */
488  bsp_interrupt_unlock();
489
490  return RTEMS_SUCCESSFUL;
491}
492
493rtems_status_code rtems_interrupt_handler_install(
494  rtems_vector_number vector,
495  const char *info,
496  rtems_option options,
497  rtems_interrupt_handler handler,
498  void *arg
499)
500{
501  return bsp_interrupt_handler_install(vector, info, options, handler, arg);
502}
503
504rtems_status_code rtems_interrupt_handler_remove(
505  rtems_vector_number vector,
506  rtems_interrupt_handler handler,
507  void *arg
508)
509{
510  return bsp_interrupt_handler_remove(vector, handler, arg);
511}
512
513rtems_status_code rtems_interrupt_handler_iterate(
514  rtems_vector_number vector,
515  rtems_interrupt_per_handler_routine routine,
516  void *arg
517)
518{
519  return bsp_interrupt_handler_iterate(vector, routine, arg);
520}
Note: See TracBrowser for help on using the repository browser.