summaryrefslogtreecommitdiffstats
path: root/bsps/shared
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-05 06:40:02 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-09 07:09:47 +0200
commit9b7c45673231ce5ddcebf2a88ba36783deb5a349 (patch)
tree0172e429e3466281853c1c2dca9e0ed398073deb /bsps/shared
parentbsps: Remove librtemsbsp.a wrapup (diff)
downloadrtems-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.am5
-rw-r--r--bsps/shared/irq/irq-default-handler.c24
-rw-r--r--bsps/shared/irq/irq-generic.c627
-rw-r--r--bsps/shared/irq/irq-info.c95
-rw-r--r--bsps/shared/irq/irq-legacy.c125
-rw-r--r--bsps/shared/irq/irq-server.c863
-rw-r--r--bsps/shared/irq/irq-shell.c45
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
+};