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

4.11
Last change on this file since dd8df59 was dd8df59, checked in by Sebastian Huber <sebastian.huber@…>, on Nov 14, 2012 at 12:59:27 PM

bsps: Interrupt initialization error is 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/bootcard.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    rtems_fatal(
174      RTEMS_FATAL_SOURCE_BSP_GENERIC,
175      BSP_GENERIC_FATAL_INTERRUPT_INITIALIZATION
176    );
177  }
178
179  bsp_interrupt_set_initialized();
180}
181
182/**
183 * @brief Installs an interrupt handler.
184 *
185 * @ingroup bsp_interrupt
186 *
187 * @return In addition to the standard status codes this function returns:
188 * - If the BSP interrupt support is not initialized RTEMS_INTERNAL_ERROR will
189 * be returned.
190 * - If not enough memory for a new handler is available RTEMS_NO_MEMORY will
191 * be returned
192 *
193 * @see rtems_interrupt_handler_install()
194 */
195static rtems_status_code bsp_interrupt_handler_install(
196  rtems_vector_number vector,
197  const char *info,
198  rtems_option options,
199  rtems_interrupt_handler handler,
200  void *arg
201)
202{
203  rtems_status_code sc = RTEMS_SUCCESSFUL;
204  rtems_interrupt_level level;
205  rtems_vector_number index = 0;
206  bsp_interrupt_handler_entry *head = NULL;
207  bsp_interrupt_handler_entry *tail = NULL;
208  bsp_interrupt_handler_entry *current = NULL;
209  bsp_interrupt_handler_entry *match = NULL;
210  bool enable_vector = false;
211
212  /* Check parameters and system state */
213  if (!bsp_interrupt_is_initialized()) {
214    return RTEMS_INTERNAL_ERROR;
215  } else if (!bsp_interrupt_is_valid_vector(vector)) {
216    return RTEMS_INVALID_ID;
217  } else if (handler == NULL) {
218    return RTEMS_INVALID_ADDRESS;
219  } else if (rtems_interrupt_is_in_progress()) {
220    return RTEMS_CALLED_FROM_ISR;
221  }
222
223  /* Lock */
224  bsp_interrupt_lock();
225
226  /* Get handler table index */
227  index = bsp_interrupt_handler_index(vector);
228
229  /* Get head entry of the handler list for current vector */
230  head = &bsp_interrupt_handler_table [index];
231
232  if (bsp_interrupt_is_empty_handler_entry(head)) {
233    /*
234     * No real handler installed yet.  So allocate a new index in
235     * the handler table and fill the entry with life.
236     */
237    if (bsp_interrupt_allocate_handler_index(vector, &index)) {
238      rtems_interrupt_disable(level);
239      bsp_interrupt_handler_table [index].handler = handler;
240      bsp_interrupt_handler_table [index].arg = arg;
241      #ifdef BSP_INTERRUPT_USE_INDEX_TABLE
242        bsp_interrupt_handler_index_table [vector] = index;
243      #endif
244      rtems_interrupt_enable(level);
245      bsp_interrupt_handler_table [index].info = info;
246    } else {
247      /* Handler table is full */
248      bsp_interrupt_unlock();
249      return RTEMS_NO_MEMORY;
250    }
251
252    /* This is the first handler so enable the vector later */
253    enable_vector = true;
254  } else {
255    /* Ensure that a unique handler remains unique */
256    if (
257      RTEMS_INTERRUPT_IS_UNIQUE(options)
258        || bsp_interrupt_is_handler_unique(index)
259    ) {
260      /*
261       * Tried to install a unique handler on a not empty
262       * list or there is already a unique handler installed.
263       */
264      bsp_interrupt_unlock();
265      return RTEMS_RESOURCE_IN_USE;
266    }
267
268    /*
269     * Search for the list tail and check if the handler is already
270     * installed.
271     */
272    current = head;
273    do {
274      if (current->handler == handler && current->arg == arg) {
275        match = current;
276      }
277      tail = current;
278      current = current->next;
279    } while (current != NULL);
280
281    /* Ensure the handler is not already installed */
282    if (match != NULL) {
283      /* The handler is already installed */
284      bsp_interrupt_unlock();
285      return RTEMS_TOO_MANY;
286    }
287
288    /* Allocate a new entry */
289    current = bsp_interrupt_allocate_handler_entry();
290    if (current == NULL) {
291      /* Not enough memory */
292      bsp_interrupt_unlock();
293      return RTEMS_NO_MEMORY;
294    }
295
296    /* Set entry */
297    current->handler = handler;
298    current->arg = arg;
299    current->info = info;
300    current->next = NULL;
301
302    /* Link to list tail */
303    rtems_interrupt_disable(level);
304    tail->next = current;
305    rtems_interrupt_enable(level);
306  }
307
308  /* Make the handler unique if necessary */
309  bsp_interrupt_set_handler_unique(index, RTEMS_INTERRUPT_IS_UNIQUE(options));
310
311  /* Enable the vector if necessary */
312  if (enable_vector) {
313    sc = bsp_interrupt_vector_enable(vector);
314    if (sc != RTEMS_SUCCESSFUL) {
315      bsp_interrupt_unlock();
316      return sc;
317    }
318  }
319
320  /* Unlock */
321  bsp_interrupt_unlock();
322
323  return RTEMS_SUCCESSFUL;
324}
325
326/**
327 * @brief Removes an interrupt handler.
328 *
329 * @ingroup bsp_interrupt
330 *
331 * @return In addition to the standard status codes this function returns
332 * RTEMS_INTERNAL_ERROR if the BSP interrupt support is not initialized.
333 *
334 * @see rtems_interrupt_handler_remove().
335 */
336static rtems_status_code bsp_interrupt_handler_remove(
337  rtems_vector_number vector,
338  rtems_interrupt_handler handler,
339  void *arg
340)
341{
342  rtems_status_code sc = RTEMS_SUCCESSFUL;
343  rtems_interrupt_level level;
344  rtems_vector_number index = 0;
345  bsp_interrupt_handler_entry *head = NULL;
346  bsp_interrupt_handler_entry *current = NULL;
347  bsp_interrupt_handler_entry *previous = NULL;
348  bsp_interrupt_handler_entry *match = NULL;
349
350  /* Check parameters and system state */
351  if (!bsp_interrupt_is_initialized()) {
352    return RTEMS_INTERNAL_ERROR;
353  } else if (!bsp_interrupt_is_valid_vector(vector)) {
354    return RTEMS_INVALID_ID;
355  } else if (handler == NULL) {
356    return RTEMS_INVALID_ADDRESS;
357  } else if (rtems_interrupt_is_in_progress()) {
358    return RTEMS_CALLED_FROM_ISR;
359  }
360
361  /* Lock */
362  bsp_interrupt_lock();
363
364  /* Get handler table index */
365  index = bsp_interrupt_handler_index(vector);
366
367  /* Get head entry of the handler list for current vector */
368  head = &bsp_interrupt_handler_table [index];
369
370  /* Search for a matching entry */
371  current = head;
372  do {
373    if (current->handler == handler && current->arg == arg) {
374      match = current;
375      break;
376    }
377    previous = current;
378    current = current->next;
379  } while (current != NULL);
380
381  /* Remove the matching entry */
382  if (match != NULL) {
383    if (match->next != NULL) {
384      /*
385       * The match has a successor.  A successor is always
386       * allocated.  So replace the match with its successor
387       * and free the successor entry.
388       */
389      current = match->next;
390
391      rtems_interrupt_disable(level);
392      *match = *current;
393      rtems_interrupt_enable(level);
394
395      bsp_interrupt_free_handler_entry(current);
396    } else if (match == head) {
397      /*
398       * The match is the list head and has no successor.
399       * The list head is stored in a static table so clear
400       * this entry.  Since now the list is empty disable the
401       * vector.
402       */
403
404      /* Disable the vector */
405      sc = bsp_interrupt_vector_disable(vector);
406
407      /* Clear entry */
408      rtems_interrupt_disable(level);
409      bsp_interrupt_clear_handler_entry(head);
410      #ifdef BSP_INTERRUPT_USE_INDEX_TABLE
411        bsp_interrupt_handler_index_table [vector] = 0;
412      #endif
413      rtems_interrupt_enable(level);
414
415      /* Allow shared handlers */
416      bsp_interrupt_set_handler_unique(index, false);
417
418      /* Check status code */
419      if (sc != RTEMS_SUCCESSFUL) {
420        bsp_interrupt_unlock();
421        return sc;
422      }
423    } else {
424      /*
425       * The match is the list tail and has a predecessor.
426       * So terminate the predecessor and free the match.
427       */
428      rtems_interrupt_disable(level);
429      previous->next = NULL;
430      rtems_interrupt_enable(level);
431
432      bsp_interrupt_free_handler_entry(match);
433    }
434  } else {
435    /* No matching entry found */
436    bsp_interrupt_unlock();
437    return RTEMS_UNSATISFIED;
438  }
439
440  /* Unlock */
441  bsp_interrupt_unlock();
442
443  return RTEMS_SUCCESSFUL;
444}
445
446/**
447 * @brief Iterates over all installed interrupt handler of a vector.
448 *
449 * @ingroup bsp_interrupt
450 *
451 * @return In addition to the standard status codes this function returns
452 * RTEMS_INTERNAL_ERROR if the BSP interrupt support is not initialized.
453 *
454 * @see rtems_interrupt_handler_iterate().
455 */
456static rtems_status_code bsp_interrupt_handler_iterate(
457  rtems_vector_number vector,
458  rtems_interrupt_per_handler_routine routine,
459  void *arg
460)
461{
462  bsp_interrupt_handler_entry *current = NULL;
463  rtems_option options = 0;
464  rtems_vector_number index = 0;
465
466  /* Check parameters and system state */
467  if (!bsp_interrupt_is_initialized()) {
468    return RTEMS_INTERNAL_ERROR;
469  } else if (!bsp_interrupt_is_valid_vector(vector)) {
470    return RTEMS_INVALID_ID;
471  } else if (rtems_interrupt_is_in_progress()) {
472    return RTEMS_CALLED_FROM_ISR;
473  }
474
475  /* Lock */
476  bsp_interrupt_lock();
477
478  /* Interate */
479  index = bsp_interrupt_handler_index(vector);
480  current = &bsp_interrupt_handler_table [index];
481  if (!bsp_interrupt_is_empty_handler_entry(current)) {
482    do {
483      options = bsp_interrupt_is_handler_unique(index) ?
484        RTEMS_INTERRUPT_UNIQUE : RTEMS_INTERRUPT_SHARED;
485      routine(arg, current->info, options, current->handler, current->arg);
486      current = current->next;
487    } while (current != NULL);
488  }
489
490  /* Unlock */
491  bsp_interrupt_unlock();
492
493  return RTEMS_SUCCESSFUL;
494}
495
496rtems_status_code rtems_interrupt_handler_install(
497  rtems_vector_number vector,
498  const char *info,
499  rtems_option options,
500  rtems_interrupt_handler handler,
501  void *arg
502)
503{
504  return bsp_interrupt_handler_install(vector, info, options, handler, arg);
505}
506
507rtems_status_code rtems_interrupt_handler_remove(
508  rtems_vector_number vector,
509  rtems_interrupt_handler handler,
510  void *arg
511)
512{
513  return bsp_interrupt_handler_remove(vector, handler, arg);
514}
515
516rtems_status_code rtems_interrupt_handler_iterate(
517  rtems_vector_number vector,
518  rtems_interrupt_per_handler_routine routine,
519  void *arg
520)
521{
522  return bsp_interrupt_handler_iterate(vector, routine, arg);
523}
Note: See TracBrowser for help on using the repository browser.