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

4.115
Last change on this file since e278f8b7 was 956531b, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on 03/25/10 at 20:29:22

fix warning

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