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

4.104.115
Last change on this file since 51a6fd5 was 51a6fd5, checked in by Joel Sherrill <joel.sherrill@…>, on 12/19/08 at 15:00:09

2008-12-19 Sebastian Huber <sebastian.huber@…>

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