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

4.104.115
Last change on this file since 8634637 was 8634637, checked in by Joel Sherrill <joel.sherrill@…>, on 09/08/09 at 13:35:07

2009-09-08 Sebastian Huber <sebastian.huber@…>

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