diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-04-05 06:40:02 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-04-09 07:09:47 +0200 |
commit | 9b7c45673231ce5ddcebf2a88ba36783deb5a349 (patch) | |
tree | 0172e429e3466281853c1c2dca9e0ed398073deb /bsps/shared | |
parent | bsps: Remove librtemsbsp.a wrapup (diff) | |
download | rtems-9b7c45673231ce5ddcebf2a88ba36783deb5a349.tar.bz2 |
bsps: Move generic IRQ support to bsps
This patch is a part of the BSP source reorganization.
Update #3285.
Diffstat (limited to 'bsps/shared')
-rw-r--r-- | bsps/shared/irq-sources.am | 5 | ||||
-rw-r--r-- | bsps/shared/irq/irq-default-handler.c | 24 | ||||
-rw-r--r-- | bsps/shared/irq/irq-generic.c | 627 | ||||
-rw-r--r-- | bsps/shared/irq/irq-info.c | 95 | ||||
-rw-r--r-- | bsps/shared/irq/irq-legacy.c | 125 | ||||
-rw-r--r-- | bsps/shared/irq/irq-server.c | 863 | ||||
-rw-r--r-- | bsps/shared/irq/irq-shell.c | 45 |
7 files changed, 1784 insertions, 0 deletions
diff --git a/bsps/shared/irq-sources.am b/bsps/shared/irq-sources.am new file mode 100644 index 0000000000..b37591851e --- /dev/null +++ b/bsps/shared/irq-sources.am @@ -0,0 +1,5 @@ +librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/irq/irq-generic.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/irq/irq-info.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/irq/irq-legacy.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/irq/irq-server.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/irq/irq-shell.c diff --git a/bsps/shared/irq/irq-default-handler.c b/bsps/shared/irq/irq-default-handler.c new file mode 100644 index 0000000000..4f4b4be673 --- /dev/null +++ b/bsps/shared/irq/irq-default-handler.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2008-2012 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <inttypes.h> + +#include <rtems/bspIo.h> + +#include <bsp/irq-generic.h> + +void bsp_interrupt_handler_default(rtems_vector_number vector) +{ + printk("spurious interrupt: %" PRIu32 "\n", vector); +} diff --git a/bsps/shared/irq/irq-generic.c b/bsps/shared/irq/irq-generic.c new file mode 100644 index 0000000000..99033dc46a --- /dev/null +++ b/bsps/shared/irq/irq-generic.c @@ -0,0 +1,627 @@ +/** + * @file + * + * @ingroup bsp_interrupt + * + * @brief Generic BSP interrupt support implementation. + */ + +/* + * Based on concepts of Pavel Pisa, Till Straumann and Eric Valette. + * + * Copyright (c) 2008, 2017 embedded brains GmbH. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <bsp/irq-generic.h> +#include <bsp/fatal.h> + +#include <stdlib.h> + +#include <rtems/score/apimutex.h> +#include <rtems/score/processormask.h> +#include <rtems/score/sysstate.h> + +#ifdef BSP_INTERRUPT_USE_INDEX_TABLE + bsp_interrupt_handler_index_type bsp_interrupt_handler_index_table + [BSP_INTERRUPT_VECTOR_NUMBER]; +#endif + +bsp_interrupt_handler_entry bsp_interrupt_handler_table + [BSP_INTERRUPT_HANDLER_TABLE_SIZE]; + +/* The last entry indicates if everything is initialized */ +static uint8_t bsp_interrupt_handler_unique_table + [(BSP_INTERRUPT_HANDLER_TABLE_SIZE + 7 + 1) / 8]; + +static void bsp_interrupt_handler_empty(void *arg) +{ + rtems_vector_number vector = (rtems_vector_number) (uintptr_t) arg; + + bsp_interrupt_handler_default(vector); +} + +#ifdef RTEMS_SMP + static void bsp_interrupt_handler_do_nothing(void *arg) + { + (void) arg; + } +#endif + +static inline bool bsp_interrupt_is_handler_unique(rtems_vector_number index) +{ + rtems_vector_number i = index / 8; + rtems_vector_number s = index % 8; + return (bsp_interrupt_handler_unique_table [i] >> s) & 0x1; +} + +static inline void bsp_interrupt_set_handler_unique( + rtems_vector_number index, + bool unique +) +{ + rtems_vector_number i = index / 8; + rtems_vector_number s = index % 8; + if (unique) { + bsp_interrupt_handler_unique_table [i] |= (uint8_t) (0x1U << s); + } else { + bsp_interrupt_handler_unique_table [i] &= (uint8_t) ~(0x1U << s); + } +} + +static inline bool bsp_interrupt_is_initialized(void) +{ + return bsp_interrupt_is_handler_unique(BSP_INTERRUPT_HANDLER_TABLE_SIZE); +} + +static inline void bsp_interrupt_set_initialized(void) +{ + bsp_interrupt_set_handler_unique(BSP_INTERRUPT_HANDLER_TABLE_SIZE, true); +} + +static inline bool bsp_interrupt_is_empty_handler_entry( + const bsp_interrupt_handler_entry *e +) +{ + return e->handler == bsp_interrupt_handler_empty; +} + +static inline void bsp_interrupt_clear_handler_entry( + bsp_interrupt_handler_entry *e, + rtems_vector_number vector +) +{ + e->handler = bsp_interrupt_handler_empty; + bsp_interrupt_fence(ATOMIC_ORDER_RELEASE); + e->arg = (void *) (uintptr_t) vector; + e->info = NULL; + e->next = NULL; +} + +static inline bool bsp_interrupt_allocate_handler_index( + rtems_vector_number vector, + rtems_vector_number *index +) +{ + #ifdef BSP_INTERRUPT_USE_INDEX_TABLE + rtems_vector_number i = 0; + + /* The first entry will remain empty */ + for (i = 1; i < BSP_INTERRUPT_HANDLER_TABLE_SIZE; ++i) { + const bsp_interrupt_handler_entry *e = &bsp_interrupt_handler_table [i]; + if (bsp_interrupt_is_empty_handler_entry(e)) { + *index = i; + return true; + } + } + + return false; + #else + *index = bsp_interrupt_handler_index(vector); + return true; + #endif +} + +static bsp_interrupt_handler_entry *bsp_interrupt_allocate_handler_entry(void) +{ + #ifdef BSP_INTERRUPT_NO_HEAP_USAGE + rtems_vector_number index = 0; + if (bsp_interrupt_allocate_handler_index(0, &index)) { + return &bsp_interrupt_handler_table [index]; + } else { + return NULL; + } + #else + return malloc(sizeof(bsp_interrupt_handler_entry)); + #endif +} + +static void bsp_interrupt_free_handler_entry(bsp_interrupt_handler_entry *e) +{ + #ifdef BSP_INTERRUPT_NO_HEAP_USAGE + bsp_interrupt_clear_handler_entry(e, 0); + #else + free(e); + #endif +} + +void bsp_interrupt_lock(void) +{ + if (_System_state_Is_up(_System_state_Get())) { + _RTEMS_Lock_allocator(); + } +} + +void bsp_interrupt_unlock(void) +{ + if (_System_state_Is_up(_System_state_Get())) { + _RTEMS_Unlock_allocator(); + } +} + +void bsp_interrupt_initialize(void) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + size_t i = 0; + + /* Initialize handler table */ + for (i = 0; i < BSP_INTERRUPT_HANDLER_TABLE_SIZE; ++i) { + bsp_interrupt_handler_table [i].handler = bsp_interrupt_handler_empty; + bsp_interrupt_handler_table [i].arg = (void *) i; + } + + sc = bsp_interrupt_facility_initialize(); + if (sc != RTEMS_SUCCESSFUL) { + bsp_fatal(BSP_FATAL_INTERRUPT_INITIALIZATION); + } + + bsp_interrupt_set_initialized(); +} + +/** + * @brief Installs an interrupt handler. + * + * @ingroup bsp_interrupt + * + * @return In addition to the standard status codes this function returns: + * - If the BSP interrupt support is not initialized RTEMS_INTERNAL_ERROR will + * be returned. + * - If not enough memory for a new handler is available RTEMS_NO_MEMORY will + * be returned + * + * @see rtems_interrupt_handler_install() + */ +static rtems_status_code bsp_interrupt_handler_install( + rtems_vector_number vector, + const char *info, + rtems_option options, + rtems_interrupt_handler handler, + void *arg +) +{ + rtems_interrupt_level level; + rtems_vector_number index = 0; + bsp_interrupt_handler_entry *head = NULL; + bool enable_vector = false; + bool replace = RTEMS_INTERRUPT_IS_REPLACE(options); + + /* Check parameters and system state */ + if (!bsp_interrupt_is_initialized()) { + return RTEMS_INTERNAL_ERROR; + } else if (!bsp_interrupt_is_valid_vector(vector)) { + return RTEMS_INVALID_ID; + } else if (handler == NULL) { + return RTEMS_INVALID_ADDRESS; + } else if (rtems_interrupt_is_in_progress()) { + return RTEMS_CALLED_FROM_ISR; + } + + /* Lock */ + bsp_interrupt_lock(); + + /* Get handler table index */ + index = bsp_interrupt_handler_index(vector); + + /* Get head entry of the handler list for current vector */ + head = &bsp_interrupt_handler_table [index]; + + if (bsp_interrupt_is_empty_handler_entry(head)) { + if (replace) { + /* No handler to replace exists */ + bsp_interrupt_unlock(); + return RTEMS_UNSATISFIED; + } + + /* + * No real handler installed yet. So allocate a new index in + * the handler table and fill the entry with life. + */ + if (bsp_interrupt_allocate_handler_index(vector, &index)) { + bsp_interrupt_disable(level); + bsp_interrupt_handler_table [index].arg = arg; + bsp_interrupt_fence(ATOMIC_ORDER_RELEASE); + bsp_interrupt_handler_table [index].handler = handler; + #ifdef BSP_INTERRUPT_USE_INDEX_TABLE + bsp_interrupt_handler_index_table [vector] = index; + #endif + bsp_interrupt_enable(level); + bsp_interrupt_handler_table [index].info = info; + } else { + /* Handler table is full */ + bsp_interrupt_unlock(); + return RTEMS_NO_MEMORY; + } + + /* This is the first handler so enable the vector later */ + enable_vector = true; + } else { + bsp_interrupt_handler_entry *current = head; + bsp_interrupt_handler_entry *tail = NULL; + bsp_interrupt_handler_entry *match = NULL; + + /* Ensure that a unique handler remains unique */ + if ( + !replace + && (RTEMS_INTERRUPT_IS_UNIQUE(options) + || bsp_interrupt_is_handler_unique(index)) + ) { + /* + * Tried to install a unique handler on a not empty + * list or there is already a unique handler installed. + */ + bsp_interrupt_unlock(); + return RTEMS_RESOURCE_IN_USE; + } + + /* + * Search for the list tail and check if the handler is already + * installed. + */ + do { + if ( + match == NULL + && (current->handler == handler || replace) + && current->arg == arg + ) { + match = current; + } + tail = current; + current = current->next; + } while (current != NULL); + + if (replace) { + /* Ensure that a handler to replace exists */ + if (match == NULL) { + bsp_interrupt_unlock(); + return RTEMS_UNSATISFIED; + } + + /* Use existing entry */ + current = match; + } else { + /* Ensure the handler is not already installed */ + if (match != NULL) { + /* The handler is already installed */ + bsp_interrupt_unlock(); + return RTEMS_TOO_MANY; + } + + /* Allocate a new entry */ + current = bsp_interrupt_allocate_handler_entry(); + if (current == NULL) { + /* Not enough memory */ + bsp_interrupt_unlock(); + return RTEMS_NO_MEMORY; + } + } + + /* Update existing entry or set new entry */ + current->handler = handler; + current->info = info; + + if (!replace) { + /* Set new entry */ + current->arg = arg; + current->next = NULL; + + /* Link to list tail */ + bsp_interrupt_disable(level); + bsp_interrupt_fence(ATOMIC_ORDER_RELEASE); + tail->next = current; + bsp_interrupt_enable(level); + } + } + + /* Make the handler unique if necessary */ + bsp_interrupt_set_handler_unique(index, RTEMS_INTERRUPT_IS_UNIQUE(options)); + + /* Enable the vector if necessary */ + if (enable_vector) { + bsp_interrupt_vector_enable(vector); + } + + /* Unlock */ + bsp_interrupt_unlock(); + + return RTEMS_SUCCESSFUL; +} + +/** + * @brief Removes an interrupt handler. + * + * @ingroup bsp_interrupt + * + * @return In addition to the standard status codes this function returns + * RTEMS_INTERNAL_ERROR if the BSP interrupt support is not initialized. + * + * @see rtems_interrupt_handler_remove(). + */ +static rtems_status_code bsp_interrupt_handler_remove( + rtems_vector_number vector, + rtems_interrupt_handler handler, + void *arg +) +{ + rtems_interrupt_level level; + rtems_vector_number index = 0; + bsp_interrupt_handler_entry *head = NULL; + bsp_interrupt_handler_entry *current = NULL; + bsp_interrupt_handler_entry *previous = NULL; + bsp_interrupt_handler_entry *match = NULL; + + /* Check parameters and system state */ + if (!bsp_interrupt_is_initialized()) { + return RTEMS_INTERNAL_ERROR; + } else if (!bsp_interrupt_is_valid_vector(vector)) { + return RTEMS_INVALID_ID; + } else if (handler == NULL) { + return RTEMS_INVALID_ADDRESS; + } else if (rtems_interrupt_is_in_progress()) { + return RTEMS_CALLED_FROM_ISR; + } + + /* Lock */ + bsp_interrupt_lock(); + + /* Get handler table index */ + index = bsp_interrupt_handler_index(vector); + + /* Get head entry of the handler list for current vector */ + head = &bsp_interrupt_handler_table [index]; + + /* Search for a matching entry */ + current = head; + do { + if (current->handler == handler && current->arg == arg) { + match = current; + break; + } + previous = current; + current = current->next; + } while (current != NULL); + + /* Remove the matching entry */ + if (match != NULL) { + if (match->next != NULL) { + /* + * The match has a successor. A successor is always + * allocated. So replace the match with its successor + * and free the successor entry. + */ + current = match->next; + + bsp_interrupt_disable(level); + #ifdef RTEMS_SMP + match->handler = bsp_interrupt_handler_do_nothing; + bsp_interrupt_fence(ATOMIC_ORDER_RELEASE); + #endif + match->arg = current->arg; + bsp_interrupt_fence(ATOMIC_ORDER_RELEASE); + match->handler = current->handler; + match->info = current->info; + match->next = current->next; + bsp_interrupt_enable(level); + + bsp_interrupt_free_handler_entry(current); + } else if (match == head) { + /* + * The match is the list head and has no successor. + * The list head is stored in a static table so clear + * this entry. Since now the list is empty disable the + * vector. + */ + + /* Disable the vector */ + bsp_interrupt_vector_disable(vector); + + /* Clear entry */ + bsp_interrupt_disable(level); + bsp_interrupt_clear_handler_entry(head, vector); + #ifdef BSP_INTERRUPT_USE_INDEX_TABLE + bsp_interrupt_handler_index_table [vector] = 0; + #endif + bsp_interrupt_enable(level); + + /* Allow shared handlers */ + bsp_interrupt_set_handler_unique(index, false); + } else { + /* + * The match is the list tail and has a predecessor. + * So terminate the predecessor and free the match. + */ + bsp_interrupt_disable(level); + previous->next = NULL; + bsp_interrupt_fence(ATOMIC_ORDER_RELEASE); + bsp_interrupt_enable(level); + + bsp_interrupt_free_handler_entry(match); + } + } else { + /* No matching entry found */ + bsp_interrupt_unlock(); + return RTEMS_UNSATISFIED; + } + + /* Unlock */ + bsp_interrupt_unlock(); + + return RTEMS_SUCCESSFUL; +} + +/** + * @brief Iterates over all installed interrupt handler of a vector. + * + * @ingroup bsp_interrupt + * + * @return In addition to the standard status codes this function returns + * RTEMS_INTERNAL_ERROR if the BSP interrupt support is not initialized. + * + * @see rtems_interrupt_handler_iterate(). + */ +static rtems_status_code bsp_interrupt_handler_iterate( + rtems_vector_number vector, + rtems_interrupt_per_handler_routine routine, + void *arg +) +{ + bsp_interrupt_handler_entry *current = NULL; + rtems_option options = 0; + rtems_vector_number index = 0; + + /* Check parameters and system state */ + if (!bsp_interrupt_is_initialized()) { + return RTEMS_INTERNAL_ERROR; + } else if (!bsp_interrupt_is_valid_vector(vector)) { + return RTEMS_INVALID_ID; + } else if (rtems_interrupt_is_in_progress()) { + return RTEMS_CALLED_FROM_ISR; + } + + /* Lock */ + bsp_interrupt_lock(); + + /* Interate */ + index = bsp_interrupt_handler_index(vector); + current = &bsp_interrupt_handler_table [index]; + if (!bsp_interrupt_is_empty_handler_entry(current)) { + do { + options = bsp_interrupt_is_handler_unique(index) ? + RTEMS_INTERRUPT_UNIQUE : RTEMS_INTERRUPT_SHARED; + routine(arg, current->info, options, current->handler, current->arg); + current = current->next; + } while (current != NULL); + } + + /* Unlock */ + bsp_interrupt_unlock(); + + return RTEMS_SUCCESSFUL; +} + +rtems_status_code rtems_interrupt_handler_install( + rtems_vector_number vector, + const char *info, + rtems_option options, + rtems_interrupt_handler handler, + void *arg +) +{ + return bsp_interrupt_handler_install(vector, info, options, handler, arg); +} + +rtems_status_code rtems_interrupt_handler_remove( + rtems_vector_number vector, + rtems_interrupt_handler handler, + void *arg +) +{ + return bsp_interrupt_handler_remove(vector, handler, arg); +} + +rtems_status_code rtems_interrupt_handler_iterate( + rtems_vector_number vector, + rtems_interrupt_per_handler_routine routine, + void *arg +) +{ + return bsp_interrupt_handler_iterate(vector, routine, arg); +} + +bool bsp_interrupt_handler_is_empty(rtems_vector_number vector) +{ + rtems_vector_number index = 0; + bsp_interrupt_handler_entry *head = NULL; + bool empty; + + /* For use in interrupts so no lock. */ + + /* Get handler table index */ + index = bsp_interrupt_handler_index(vector); + + /* Get head entry of the handler list for the vector */ + head = &bsp_interrupt_handler_table [index]; + + empty = bsp_interrupt_is_empty_handler_entry(head); + + return empty; +} + +rtems_status_code rtems_interrupt_set_affinity( + rtems_vector_number vector, + size_t affinity_size, + const cpu_set_t *affinity +) +{ + Processor_mask set; + Processor_mask_Copy_status status; + + if (!bsp_interrupt_is_valid_vector(vector)) { + return RTEMS_INVALID_ID; + } + + status = _Processor_mask_From_cpu_set_t(&set, affinity_size, affinity); + if (status != PROCESSOR_MASK_COPY_LOSSLESS) { + return RTEMS_INVALID_SIZE; + } + +#if defined(RTEMS_SMP) + bsp_interrupt_set_affinity(vector, &set); +#endif + return RTEMS_SUCCESSFUL; +} + +rtems_status_code rtems_interrupt_get_affinity( + rtems_vector_number vector, + size_t affinity_size, + cpu_set_t *affinity +) +{ + Processor_mask set; + Processor_mask_Copy_status status; + + if (!bsp_interrupt_is_valid_vector(vector)) { + return RTEMS_INVALID_ID; + } + +#if defined(RTEMS_SMP) + bsp_interrupt_get_affinity(vector, &set); +#else + _Processor_mask_From_index(&set, 0); +#endif + + status = _Processor_mask_To_cpu_set_t(&set, affinity_size, affinity); + if (status != PROCESSOR_MASK_COPY_LOSSLESS) { + return RTEMS_INVALID_SIZE; + } + + return RTEMS_SUCCESSFUL; +} diff --git a/bsps/shared/irq/irq-info.c b/bsps/shared/irq/irq-info.c new file mode 100644 index 0000000000..ef965d3d07 --- /dev/null +++ b/bsps/shared/irq/irq-info.c @@ -0,0 +1,95 @@ +/** + * @file + * + * @ingroup bsp_interrupt + * + * @brief Generic BSP interrupt information implementation. + */ + +/* + * Copyright (c) 2008, 2009, 2010 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <inttypes.h> + +#include <rtems/printer.h> + +#include <bsp/irq-generic.h> +#include <bsp/irq-info.h> + +typedef struct { + const rtems_printer *printer; + rtems_vector_number vector; +} bsp_interrupt_report_entry; + +static void bsp_interrupt_report_per_handler_routine( + void *arg, + const char *info, + rtems_option options, + rtems_interrupt_handler handler, + void *handler_arg +) +{ + bsp_interrupt_report_entry *e = (bsp_interrupt_report_entry *) arg; + const char *opt = options == RTEMS_INTERRUPT_UNIQUE ? "UNIQUE" : "SHARED"; + + rtems_printf( + e->printer, + "%7" PRIu32 " | %-32s | %7s | %p | %p\n", + e->vector, + info, + opt, + handler, + handler_arg + ); +} + +void bsp_interrupt_report_with_plugin( + const rtems_printer *printer +) +{ + rtems_vector_number v = 0; + bsp_interrupt_report_entry e = { + .printer = printer, + .vector = 0 + }; + + rtems_printf( + printer, + "-------------------------------------------------------------------------------\n" + " INTERRUPT INFORMATION\n" + "--------+----------------------------------+---------+------------+------------\n" + " VECTOR | INFO | OPTIONS | HANDLER | ARGUMENT \n" + "--------+----------------------------------+---------+------------+------------\n" + ); + + for (v = BSP_INTERRUPT_VECTOR_MIN; v <= BSP_INTERRUPT_VECTOR_MAX; ++v) { + e.vector = v; + rtems_interrupt_handler_iterate( + v, + bsp_interrupt_report_per_handler_routine, + &e + ); + } + + rtems_printf( + printer, + "--------+----------------------------------+---------+------------+------------\n" + ); +} + +void bsp_interrupt_report(void) +{ + rtems_printer printer; + rtems_print_printer_printk(&printer); + bsp_interrupt_report_with_plugin(&printer); +} diff --git a/bsps/shared/irq/irq-legacy.c b/bsps/shared/irq/irq-legacy.c new file mode 100644 index 0000000000..64c324b472 --- /dev/null +++ b/bsps/shared/irq/irq-legacy.c @@ -0,0 +1,125 @@ +/** + * @file + * + * @ingroup bsp_interrupt + * + * @brief Generic BSP interrupt support legacy implementation. + */ + +/* + * Copyright (c) 2008, 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <string.h> + +#define BSP_SHARED_HANDLER_SUPPORT + +#include <rtems.h> +#include <rtems/irq.h> + +#include <bsp/irq-generic.h> + +/** + * @deprecated Obsolete. + */ +int BSP_get_current_rtems_irq_handler(rtems_irq_connect_data *cd) +{ + memset(cd, 0, sizeof(*cd)); + + return 1; +} + +/** + * @deprecated Use rtems_interrupt_handler_install() instead. + */ +int BSP_install_rtems_irq_handler(const rtems_irq_connect_data *cd) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + + sc = rtems_interrupt_handler_install( + cd->name, + "LEGACY INSTALLED", + RTEMS_INTERRUPT_UNIQUE, + cd->hdl, + cd->handle + ); + if (sc != RTEMS_SUCCESSFUL) { + return 0; + } + + if (cd->on != NULL) { + cd->on(cd); + } + + return 1; +} + +/** + * @deprecated Use rtems_interrupt_handler_install() instead. + */ +int BSP_install_rtems_shared_irq_handler(const rtems_irq_connect_data *cd) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + + sc = rtems_interrupt_handler_install( + cd->name, + "LEGACY INSTALLED", + RTEMS_INTERRUPT_SHARED, + cd->hdl, + cd->handle + ); + if (sc != RTEMS_SUCCESSFUL) { + return 0; + } + + if (cd->on != NULL) { + (*cd->on)(cd); + } + + return 1; +} + +/** + * @deprecated Use rtems_interrupt_handler_remove() instead. + */ +int BSP_remove_rtems_irq_handler(const rtems_irq_connect_data *cd) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + + if (cd->off != NULL) { + (*cd->off)(cd); + } + + sc = rtems_interrupt_handler_remove(cd->name, cd->hdl, cd->handle); + if (sc != RTEMS_SUCCESSFUL) { + return 0; + } + + return 1; +} + +/** + * @deprecated Use bsp_interrupt_initialize() instead. + */ +int BSP_rtems_irq_mngt_set(rtems_irq_global_settings *config) +{ + return 0; +} + +/** + * @deprecated Obsolete. + */ +int BSP_rtems_irq_mngt_get(rtems_irq_global_settings **config) +{ + *config = NULL; + return 0; +} diff --git a/bsps/shared/irq/irq-server.c b/bsps/shared/irq/irq-server.c new file mode 100644 index 0000000000..f94f0dc71c --- /dev/null +++ b/bsps/shared/irq/irq-server.c @@ -0,0 +1,863 @@ +/** + * @file + * + * @ingroup bsp_interrupt + * + * @brief Generic BSP interrupt server implementation. + */ + +/* + * Copyright (c) 2009, 2017 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <stdlib.h> + +#include <rtems.h> +#include <rtems/chain.h> +#include <rtems/score/assert.h> + +#include <bsp/irq-generic.h> + +#define BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR (BSP_INTERRUPT_VECTOR_MAX + 1) + +typedef struct { + RTEMS_INTERRUPT_LOCK_MEMBER(lock); + rtems_chain_control entries; + rtems_id server; + unsigned errors; +} bsp_interrupt_server_context; + +#if defined(RTEMS_SMP) +static bsp_interrupt_server_context *bsp_interrupt_server_instances; +#else +static bsp_interrupt_server_context bsp_interrupt_server_instance; +#endif + +static bsp_interrupt_server_context *bsp_interrupt_server_get_context( + uint32_t server_index, + rtems_status_code *sc +) +{ +#if defined(RTEMS_SMP) + if (bsp_interrupt_server_instances == NULL) { + *sc = RTEMS_INCORRECT_STATE; + return NULL; + } +#else + if (bsp_interrupt_server_instance.server == RTEMS_ID_NONE) { + *sc = RTEMS_INCORRECT_STATE; + return NULL; + } +#endif + + if (server_index >= rtems_get_processor_count()) { + *sc = RTEMS_INVALID_ID; + return NULL; + } + + *sc = RTEMS_SUCCESSFUL; +#if defined(RTEMS_SMP) + return &bsp_interrupt_server_instances[server_index]; +#else + return &bsp_interrupt_server_instance; +#endif +} + +static void bsp_interrupt_server_trigger(void *arg) +{ + rtems_interrupt_lock_context lock_context; + rtems_interrupt_server_entry *e = arg; + bsp_interrupt_server_context *s = e->server; + + if (bsp_interrupt_is_valid_vector(e->vector)) { + bsp_interrupt_vector_disable(e->vector); + } + + rtems_interrupt_lock_acquire(&s->lock, &lock_context); + + if (rtems_chain_is_node_off_chain(&e->node)) { + rtems_chain_append_unprotected(&s->entries, &e->node); + } else { + ++s->errors; + } + + rtems_interrupt_lock_release(&s->lock, &lock_context); + + rtems_event_system_send(s->server, RTEMS_EVENT_SYSTEM_SERVER); +} + +typedef struct { + rtems_interrupt_server_entry *entry; + rtems_option *options; +} bsp_interrupt_server_iterate_entry; + +static void bsp_interrupt_server_per_handler_routine( + void *iterate_arg, + const char *info, + rtems_option options, + rtems_interrupt_handler handler, + void *handler_arg +) +{ + if (handler == bsp_interrupt_server_trigger) { + bsp_interrupt_server_iterate_entry *ie = iterate_arg; + + ie->entry = handler_arg; + *ie->options = options; + } +} + +static rtems_interrupt_server_entry *bsp_interrupt_server_query_entry( + rtems_vector_number vector, + rtems_option *trigger_options +) +{ + bsp_interrupt_server_iterate_entry ie = { + .entry = NULL, + .options = trigger_options + }; + + rtems_interrupt_handler_iterate( + vector, + bsp_interrupt_server_per_handler_routine, + &ie + ); + + return ie.entry; +} + +typedef struct { + bsp_interrupt_server_context *server; + rtems_vector_number vector; + rtems_option options; + rtems_interrupt_handler handler; + void *arg; + rtems_id task; + rtems_status_code sc; +} bsp_interrupt_server_helper_data; + +static void bsp_interrupt_server_install_helper(void *arg) +{ + bsp_interrupt_server_helper_data *hd = arg; + rtems_status_code sc; + rtems_interrupt_server_entry *e; + rtems_interrupt_server_action *a; + rtems_option trigger_options; + + a = calloc(1, sizeof(*a)); + if (a == NULL) { + hd->sc = RTEMS_NO_MEMORY; + rtems_event_transient_send(hd->task); + return; + } + + a->handler = hd->handler; + a->arg = hd->arg; + + bsp_interrupt_lock(); + + e = bsp_interrupt_server_query_entry(hd->vector, &trigger_options); + if (e == NULL) { + e = calloc(1, sizeof(*e)); + if (e != NULL) { + e->server = hd->server; + e->vector = hd->vector; + e->actions = a; + + sc = rtems_interrupt_handler_install( + hd->vector, + "IRQS", + hd->options & RTEMS_INTERRUPT_UNIQUE, + bsp_interrupt_server_trigger, + e + ); + if (sc != RTEMS_SUCCESSFUL) { + free(e); + } + } else { + sc = RTEMS_NO_MEMORY; + } +#if defined(RTEMS_SMP) + } else if (e->server != hd->server) { + sc = RTEMS_RESOURCE_IN_USE; +#endif + } else if ( + RTEMS_INTERRUPT_IS_UNIQUE(hd->options) + || RTEMS_INTERRUPT_IS_UNIQUE(trigger_options) + ) { + sc = RTEMS_RESOURCE_IN_USE; + } else { + rtems_interrupt_server_action **link = &e->actions; + rtems_interrupt_server_action *c; + + sc = RTEMS_SUCCESSFUL; + + while ((c = *link) != NULL) { + if (c->handler == hd->handler && c->arg == hd->arg) { + sc = RTEMS_TOO_MANY; + break; + } + + link = &c->next; + } + + if (sc == RTEMS_SUCCESSFUL) { + *link = a; + } + } + + bsp_interrupt_unlock(); + + if (sc != RTEMS_SUCCESSFUL) { + free(a); + } + + hd->sc = sc; + rtems_event_transient_send(hd->task); +} + +static void bsp_interrupt_server_remove_helper(void *arg) +{ + bsp_interrupt_server_helper_data *hd = arg; + rtems_status_code sc; + rtems_interrupt_server_entry *e; + rtems_option trigger_options; + + bsp_interrupt_lock(); + + e = bsp_interrupt_server_query_entry(hd->vector, &trigger_options); + if (e != NULL) { + rtems_interrupt_server_action **link = &e->actions; + rtems_interrupt_server_action *c; + + while ((c = *link) != NULL) { + if (c->handler == hd->handler && c->arg == hd->arg) { + break; + } + + link = &c->next; + } + + if (c != NULL) { + bool remove_last = e->actions->next == NULL; + + if (remove_last) { + rtems_interrupt_handler_remove( + hd->vector, + bsp_interrupt_server_trigger, + e + ); + } + + *link = c->next; + free(c); + + if (remove_last) { + free(e); + } + + sc = RTEMS_SUCCESSFUL; + } else { + sc = RTEMS_UNSATISFIED; + } + } else { + sc = RTEMS_INVALID_ID; + } + + bsp_interrupt_unlock(); + + hd->sc = sc; + rtems_event_transient_send(hd->task); +} + +static rtems_status_code bsp_interrupt_server_call_helper( + bsp_interrupt_server_context *s, + rtems_vector_number vector, + rtems_option options, + rtems_interrupt_handler handler, + void *arg, + void (*helper)(void *) +) +{ + bsp_interrupt_server_helper_data hd = { + .server = s, + .vector = vector, + .options = options, + .handler = handler, + .arg = arg, + .task = rtems_task_self() + }; + rtems_interrupt_server_action a = { + .handler = helper, + .arg = &hd + }; + rtems_interrupt_server_entry e = { + .server = s, + .vector = BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR, + .actions = &a + }; + + bsp_interrupt_server_trigger(&e); + rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT); + + return hd.sc; +} + +static rtems_interrupt_server_entry *bsp_interrupt_server_get_entry( + bsp_interrupt_server_context *s +) +{ + rtems_interrupt_lock_context lock_context; + rtems_interrupt_server_entry *e; + + rtems_interrupt_lock_acquire(&s->lock, &lock_context); + + if (!rtems_chain_is_empty(&s->entries)) { + e = (rtems_interrupt_server_entry *) + rtems_chain_get_first_unprotected(&s->entries); + rtems_chain_set_off_chain(&e->node); + } else { + e = NULL; + } + + rtems_interrupt_lock_release(&s->lock, &lock_context); + + return e; +} + +static void bsp_interrupt_server_task(rtems_task_argument arg) +{ + bsp_interrupt_server_context *s = (bsp_interrupt_server_context *) arg; + + while (true) { + rtems_event_set events; + rtems_interrupt_server_entry *e; + + rtems_event_system_receive( + RTEMS_EVENT_SYSTEM_SERVER, + RTEMS_EVENT_ALL | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, + &events + ); + + while ((e = bsp_interrupt_server_get_entry(s)) != NULL) { + rtems_interrupt_server_action *action = e->actions; + rtems_vector_number vector = e->vector; + + do { + rtems_interrupt_server_action *current = action; + action = action->next; + (*current->handler)(current->arg); + } while (action != NULL); + + if (bsp_interrupt_is_valid_vector(vector)) { + bsp_interrupt_vector_enable(vector); + } + } + } +} + +rtems_status_code rtems_interrupt_server_handler_install( + uint32_t server_index, + rtems_vector_number vector, + const char *info, + rtems_option options, + rtems_interrupt_handler handler, + void *arg +) +{ + rtems_status_code sc; + bsp_interrupt_server_context *s; + + s = bsp_interrupt_server_get_context(server_index, &sc); + if (s == NULL) { + return sc; + } + + return bsp_interrupt_server_call_helper( + s, + vector, + options, + handler, + arg, + bsp_interrupt_server_install_helper + ); +} + +rtems_status_code rtems_interrupt_server_handler_remove( + uint32_t server_index, + rtems_vector_number vector, + rtems_interrupt_handler handler, + void *arg +) +{ + rtems_status_code sc; + bsp_interrupt_server_context *s; + + s = bsp_interrupt_server_get_context(server_index, &sc); + if (s == NULL) { + return sc; + } + + return bsp_interrupt_server_call_helper( + s, + vector, + 0, + handler, + arg, + bsp_interrupt_server_remove_helper + ); +} + +typedef struct { + rtems_interrupt_per_handler_routine routine; + void *arg; +} bsp_interrupt_server_handler_iterate_helper_data; + +static void bsp_interrupt_server_handler_iterate_helper(void *arg) +{ + bsp_interrupt_server_helper_data *hd = arg; + bsp_interrupt_server_handler_iterate_helper_data *hihd = hd->arg; + rtems_status_code sc; + rtems_interrupt_server_entry *e; + rtems_option trigger_options; + + bsp_interrupt_lock(); + + e = bsp_interrupt_server_query_entry(hd->vector, &trigger_options); + if (e != NULL) { + rtems_interrupt_server_action **link = &e->actions; + rtems_interrupt_server_action *c; + + while ((c = *link) != NULL) { + (*hihd->routine)(hihd->arg, NULL, trigger_options, c->handler, c->arg); + link = &c->next; + } + + sc = RTEMS_SUCCESSFUL; + } else { + sc = RTEMS_UNSATISFIED; + } + + bsp_interrupt_unlock(); + + hd->sc = sc; + rtems_event_transient_send(hd->task); +} + +rtems_status_code rtems_interrupt_server_handler_iterate( + uint32_t server_index, + rtems_vector_number vector, + rtems_interrupt_per_handler_routine routine, + void *arg +) +{ + rtems_status_code sc; + bsp_interrupt_server_handler_iterate_helper_data hihd; + bsp_interrupt_server_context *s; + + s = bsp_interrupt_server_get_context(server_index, &sc); + if (s == NULL) { + return sc; + } + + if (!bsp_interrupt_is_valid_vector(vector)) { + return RTEMS_INVALID_ID; + } + + hihd.routine = routine; + hihd.arg = arg; + return bsp_interrupt_server_call_helper( + s, + vector, + 0, + NULL, + &hihd, + bsp_interrupt_server_handler_iterate_helper + ); +} + +rtems_status_code rtems_interrupt_server_initialize( + rtems_task_priority priority, + size_t stack_size, + rtems_mode modes, + rtems_attribute attributes, + uint32_t *server_count +) +{ + uint32_t cpu_index; + uint32_t cpu_count; + uint32_t dummy; + bsp_interrupt_server_context *instances; + + if (server_count == NULL) { + server_count = &dummy; + } + + cpu_count = rtems_get_processor_count(); + +#if defined(RTEMS_SMP) + instances = calloc(cpu_count, sizeof(*instances)); + if (instances == NULL) { + return RTEMS_NO_MEMORY; + } +#else + instances = &bsp_interrupt_server_instance; +#endif + + for (cpu_index = 0; cpu_index < cpu_count; ++cpu_index) { + bsp_interrupt_server_context *s = &instances[cpu_index]; + rtems_status_code sc; +#if defined(RTEMS_SMP) + rtems_id scheduler; + cpu_set_t cpu; +#endif + + rtems_interrupt_lock_initialize(&s->lock, "Interrupt Server"); + rtems_chain_initialize_empty(&s->entries); + + sc = rtems_task_create( + rtems_build_name('I', 'R', 'Q', 'S'), + priority, + stack_size, + modes, + attributes, + &s->server + ); + if (sc != RTEMS_SUCCESSFUL) { + *server_count = cpu_index; + +#if defined(RTEMS_SMP) + if (cpu_index > 0) { + return RTEMS_SUCCESSFUL; + } + + free(instances); +#endif + + return RTEMS_TOO_MANY; + } + +#if defined(RTEMS_SMP) + sc = rtems_scheduler_ident_by_processor(cpu_index, &scheduler); + _Assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_set_scheduler(s->server, scheduler, priority); + _Assert(sc == RTEMS_SUCCESSFUL); + + CPU_ZERO(&cpu); + CPU_SET(cpu_index, &cpu); + sc = rtems_task_set_affinity(s->server, sizeof(cpu), &cpu); + _Assert(sc == RTEMS_SUCCESSFUL); +#endif + + sc = rtems_task_start( + s->server, + bsp_interrupt_server_task, + (rtems_task_argument) s + ); + _Assert(sc == RTEMS_SUCCESSFUL); + } + +#if defined(RTEMS_SMP) + bsp_interrupt_server_instances = instances; +#endif + *server_count = cpu_index; + + return RTEMS_SUCCESSFUL; +} + +static void bsp_interrupt_server_entry_initialize( + rtems_interrupt_server_entry *entry, + bsp_interrupt_server_context *s +) +{ + rtems_chain_set_off_chain(&entry->node); + entry->server = s; + entry->vector = BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR; + entry->actions = NULL; +} + +static void bsp_interrupt_server_action_prepend( + rtems_interrupt_server_entry *entry, + rtems_interrupt_server_action *action, + rtems_interrupt_handler handler, + void *arg +) +{ + action->handler = handler; + action->arg = arg; + action->next = entry->actions; + entry->actions = action; +} + +rtems_status_code rtems_interrupt_server_entry_initialize( + uint32_t server_index, + rtems_interrupt_server_entry *entry +) +{ + rtems_status_code sc; + bsp_interrupt_server_context *s; + + s = bsp_interrupt_server_get_context(server_index, &sc); + if (s == NULL) { + return sc; + } + + bsp_interrupt_server_entry_initialize(entry, s); + return RTEMS_SUCCESSFUL; +} + +void rtems_interrupt_server_action_prepend( + rtems_interrupt_server_entry *entry, + rtems_interrupt_server_action *action, + rtems_interrupt_handler handler, + void *arg +) +{ + bsp_interrupt_server_action_prepend(entry, action, handler, arg); +} + +void rtems_interrupt_server_entry_submit( + rtems_interrupt_server_entry *entry +) +{ + bsp_interrupt_server_trigger(entry); +} + +static void bsp_interrupt_server_entry_synchronize_helper(void *arg) +{ + bsp_interrupt_server_helper_data *hd = arg; + + rtems_event_transient_send(hd->task); +} + +void rtems_interrupt_server_entry_destroy( + rtems_interrupt_server_entry *entry +) +{ + bsp_interrupt_server_context *s; + rtems_interrupt_lock_context lock_context; + + s = entry->server; + rtems_interrupt_lock_acquire(&s->lock, &lock_context); + + if (!rtems_chain_is_node_off_chain(&entry->node)) { + rtems_chain_extract_unprotected(&entry->node); + rtems_chain_set_off_chain(&entry->node); + } + + rtems_interrupt_lock_release(&s->lock, &lock_context); + + bsp_interrupt_server_call_helper( + s, + BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR, + 0, + NULL, + NULL, + bsp_interrupt_server_entry_synchronize_helper + ); +} + +rtems_status_code rtems_interrupt_server_request_initialize( + uint32_t server_index, + rtems_interrupt_server_request *request, + rtems_interrupt_handler handler, + void *arg +) +{ + rtems_status_code sc; + bsp_interrupt_server_context *s; + + s = bsp_interrupt_server_get_context(server_index, &sc); + if (s == NULL) { + return sc; + } + + bsp_interrupt_server_entry_initialize(&request->entry, s); + bsp_interrupt_server_action_prepend( + &request->entry, + &request->action, + handler, + arg + ); + return RTEMS_SUCCESSFUL; +} + +static void bsp_interrupt_server_handler_move_helper(void *arg) +{ + bsp_interrupt_server_helper_data *hd = arg; + bsp_interrupt_server_handler_iterate_helper_data *hihd = hd->arg; + rtems_interrupt_server_entry *e; + rtems_option trigger_options; + + bsp_interrupt_lock(); + + e = bsp_interrupt_server_query_entry(hd->vector, &trigger_options); + if (e != NULL) { + rtems_interrupt_lock_context lock_context; + bsp_interrupt_server_context *src = e->server; + bsp_interrupt_server_context *dst = hihd->arg; + bool pending; + + /* The source server is only used in SMP configurations for the lock */ + (void) src; + + rtems_interrupt_lock_acquire(&src->lock, &lock_context); + + pending = !rtems_chain_is_node_off_chain(&e->node); + if (pending) { + rtems_chain_extract_unprotected(&e->node); + rtems_chain_set_off_chain(&e->node); + } + + rtems_interrupt_lock_release(&src->lock, &lock_context); + + e->server = dst; + + if (pending) { + bsp_interrupt_server_trigger(e); + } + } + + bsp_interrupt_unlock(); + + rtems_event_transient_send(hd->task); +} + +rtems_status_code rtems_interrupt_server_move( + uint32_t source_server_index, + rtems_vector_number vector, + uint32_t destination_server_index +) +{ + rtems_status_code sc; + bsp_interrupt_server_context *src; + bsp_interrupt_server_context *dst; + bsp_interrupt_server_handler_iterate_helper_data hihd; + + src = bsp_interrupt_server_get_context(source_server_index, &sc); + if (src == NULL) { + return sc; + } + + dst = bsp_interrupt_server_get_context(destination_server_index, &sc); + if (dst == NULL) { + return sc; + } + + if (!bsp_interrupt_is_valid_vector(vector)) { + return RTEMS_INVALID_ID; + } + + hihd.arg = dst; + bsp_interrupt_server_call_helper( + src, + vector, + 0, + NULL, + &hihd, + bsp_interrupt_server_handler_move_helper + ); + return RTEMS_SUCCESSFUL; +} + +static void bsp_interrupt_server_entry_suspend_helper(void *arg) +{ + bsp_interrupt_server_helper_data *hd = arg; + rtems_event_set events; + + rtems_event_transient_send(hd->task); + rtems_event_system_receive( + RTEMS_EVENT_SYSTEM_SERVER_RESUME, + RTEMS_WAIT, + RTEMS_NO_TIMEOUT, + &events + ); +} + +rtems_status_code rtems_interrupt_server_suspend(uint32_t server_index) +{ + rtems_status_code sc; + bsp_interrupt_server_context *s; + + s = bsp_interrupt_server_get_context(server_index, &sc); + if (s == NULL) { + return sc; + } + + bsp_interrupt_server_call_helper( + s, + BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR, + 0, + NULL, + NULL, + bsp_interrupt_server_entry_suspend_helper + ); + return RTEMS_SUCCESSFUL; +} + +rtems_status_code rtems_interrupt_server_resume(uint32_t server_index) +{ + rtems_status_code sc; + bsp_interrupt_server_context *s; + + s = bsp_interrupt_server_get_context(server_index, &sc); + if (s == NULL) { + return sc; + } + + rtems_event_system_send(s->server, RTEMS_EVENT_SYSTEM_SERVER_RESUME); + bsp_interrupt_server_call_helper( + s, + BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR, + 0, + NULL, + NULL, + bsp_interrupt_server_entry_synchronize_helper + ); + return RTEMS_SUCCESSFUL; +} + +rtems_status_code rtems_interrupt_server_set_affinity( + uint32_t server_index, + size_t affinity_size, + const cpu_set_t *affinity, + rtems_task_priority priority +) +{ + rtems_status_code sc; + bsp_interrupt_server_context *s; + rtems_id scheduler; + + s = bsp_interrupt_server_get_context(server_index, &sc); + if (s == NULL) { + return sc; + } + + sc = rtems_scheduler_ident_by_processor_set( + affinity_size, + affinity, + &scheduler + ); + if (sc != RTEMS_SUCCESSFUL) { + return sc; + } + + sc = rtems_task_set_scheduler(s->server, scheduler, priority); + if (sc != RTEMS_SUCCESSFUL) { + return sc; + } + + return rtems_task_set_affinity(s->server, affinity_size, affinity); +} diff --git a/bsps/shared/irq/irq-shell.c b/bsps/shared/irq/irq-shell.c new file mode 100644 index 0000000000..ca936f8038 --- /dev/null +++ b/bsps/shared/irq/irq-shell.c @@ -0,0 +1,45 @@ +/** + * @file + * + * @ingroup bsp_interrupt + * + * @brief Generic BSP interrupt shell implementation. + */ + +/* + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <stdio.h> + +#include <rtems/printer.h> +#include <rtems/shell.h> + +#include <bsp/irq-info.h> + +static int bsp_interrupt_shell_main(int argc, char **argv) +{ + rtems_printer printer; + rtems_print_printer_printf(&printer); + bsp_interrupt_report_with_plugin(&printer); + + return 0; +} + +struct rtems_shell_cmd_tt bsp_interrupt_shell_command = { + .name = "irq", + .usage = "Prints interrupt information", + .topic = "rtems", + .command = bsp_interrupt_shell_main, + .alias = NULL, + .next = NULL +}; |