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

4.115
Last change on this file since 39046f7 was 39046f7, checked in by Sebastian Huber <sebastian.huber@…>, on 07/24/13 at 09:09:23

score: Merge sysstate API into one file

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