summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bsps/shared/irq/irq-server.c365
-rw-r--r--cpukit/include/rtems/irq-extension.h143
2 files changed, 378 insertions, 130 deletions
diff --git a/bsps/shared/irq/irq-server.c b/bsps/shared/irq/irq-server.c
index 93e2d144d8..fe96b59cd4 100644
--- a/bsps/shared/irq/irq-server.c
+++ b/bsps/shared/irq/irq-server.c
@@ -7,13 +7,7 @@
*/
/*
- * Copyright (c) 2009, 2019 embedded brains GmbH. All rights reserved.
- *
- * embedded brains GmbH
- * Dornierstr. 4
- * 82178 Puchheim
- * Germany
- * <rtems@embedded-brains.de>
+ * Copyright (C) 2009, 2020 embedded brains GmbH (http://www.embedded-brains.de)
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
@@ -21,6 +15,7 @@
*/
#include <stdlib.h>
+#include <string.h>
#include <rtems.h>
#include <rtems/chain.h>
@@ -30,54 +25,43 @@
#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;
+static rtems_interrupt_server_control bsp_interrupt_server_default;
-#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 rtems_chain_control bsp_interrupt_server_chain =
+ RTEMS_CHAIN_INITIALIZER_EMPTY(bsp_interrupt_server_chain);
-static bsp_interrupt_server_context *bsp_interrupt_server_get_context(
+static rtems_interrupt_server_control *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
+ rtems_chain_node *node;
+
+ bsp_interrupt_lock();
+ node = rtems_chain_first(&bsp_interrupt_server_chain);
- if (server_index >= rtems_scheduler_get_processor_maximum()) {
- *sc = RTEMS_INVALID_ID;
- return NULL;
+ while (node != rtems_chain_tail(&bsp_interrupt_server_chain)) {
+ rtems_interrupt_server_control *s;
+
+ s = RTEMS_CONTAINER_OF(node, rtems_interrupt_server_control, node);
+ if (s->index == server_index) {
+ bsp_interrupt_unlock();
+ return s;
+ }
+
+ node = rtems_chain_next(node);
}
- *sc = RTEMS_SUCCESSFUL;
-#if defined(RTEMS_SMP)
- return &bsp_interrupt_server_instances[server_index];
-#else
- return &bsp_interrupt_server_instance;
-#endif
+ bsp_interrupt_unlock();
+ *sc = RTEMS_INVALID_ID;
+ return NULL;
}
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;
+ rtems_interrupt_server_control *s = e->server;
if (bsp_interrupt_is_valid_vector(e->vector)) {
bsp_interrupt_vector_disable(e->vector);
@@ -137,7 +121,7 @@ static rtems_interrupt_server_entry *bsp_interrupt_server_query_entry(
}
typedef struct {
- bsp_interrupt_server_context *server;
+ rtems_interrupt_server_control *server;
rtems_vector_number vector;
rtems_option options;
rtems_interrupt_handler handler;
@@ -281,7 +265,7 @@ static void bsp_interrupt_server_remove_helper(void *arg)
}
static rtems_status_code bsp_interrupt_server_call_helper(
- bsp_interrupt_server_context *s,
+ rtems_interrupt_server_control *s,
rtems_vector_number vector,
rtems_option options,
rtems_interrupt_handler handler,
@@ -314,7 +298,7 @@ static rtems_status_code bsp_interrupt_server_call_helper(
}
static rtems_interrupt_server_entry *bsp_interrupt_server_get_entry(
- bsp_interrupt_server_context *s
+ rtems_interrupt_server_control *s
)
{
rtems_interrupt_lock_context lock_context;
@@ -337,7 +321,7 @@ static rtems_interrupt_server_entry *bsp_interrupt_server_get_entry(
static void bsp_interrupt_server_task(rtems_task_argument arg)
{
- bsp_interrupt_server_context *s = (bsp_interrupt_server_context *) arg;
+ rtems_interrupt_server_control *s = (rtems_interrupt_server_control *) arg;
while (true) {
rtems_event_set events;
@@ -377,7 +361,7 @@ rtems_status_code rtems_interrupt_server_handler_install(
)
{
rtems_status_code sc;
- bsp_interrupt_server_context *s;
+ rtems_interrupt_server_control *s;
s = bsp_interrupt_server_get_context(server_index, &sc);
if (s == NULL) {
@@ -402,7 +386,7 @@ rtems_status_code rtems_interrupt_server_handler_remove(
)
{
rtems_status_code sc;
- bsp_interrupt_server_context *s;
+ rtems_interrupt_server_control *s;
s = bsp_interrupt_server_get_context(server_index, &sc);
if (s == NULL) {
@@ -464,7 +448,7 @@ rtems_status_code rtems_interrupt_server_handler_iterate(
{
rtems_status_code sc;
bsp_interrupt_server_handler_iterate_helper_data hihd;
- bsp_interrupt_server_context *s;
+ rtems_interrupt_server_control *s;
s = bsp_interrupt_server_get_context(server_index, &sc);
if (s == NULL) {
@@ -487,103 +471,252 @@ rtems_status_code rtems_interrupt_server_handler_iterate(
);
}
-rtems_status_code rtems_interrupt_server_initialize(
+/*
+ * The default server is statically allocated. Just clear the structure so
+ * that it can be re-initialized.
+ */
+static void bsp_interrupt_server_destroy_default(
+ rtems_interrupt_server_control *s
+)
+{
+ memset(s, 0, sizeof(*s));
+}
+
+#if defined(RTEMS_SMP)
+static void bsp_interrupt_server_destroy_secondary(
+ rtems_interrupt_server_control *s
+)
+{
+ free(s);
+}
+#endif
+
+static rtems_status_code bsp_interrupt_server_create(
+ rtems_interrupt_server_control *s,
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_index;
- uint32_t cpu_count;
- uint32_t dummy;
- bsp_interrupt_server_context *instances;
+ rtems_status_code sc;
+#if defined(RTEMS_SMP)
+ rtems_id scheduler;
+ cpu_set_t cpu;
+#endif
- if (server_count == NULL) {
- server_count = &dummy;
- }
+ rtems_interrupt_lock_initialize(&s->lock, "Interrupt Server");
+ rtems_chain_initialize_empty(&s->entries);
- cpu_count = rtems_scheduler_get_processor_maximum();
+ sc = rtems_task_create(
+ rtems_build_name('I', 'R', 'Q', 'S'),
+ priority,
+ stack_size,
+ modes,
+ attributes,
+ &s->server
+ );
+ if (sc != RTEMS_SUCCESSFUL) {
+ return sc;
+ }
#if defined(RTEMS_SMP)
- instances = calloc(cpu_count, sizeof(*instances));
- if (instances == NULL) {
- return RTEMS_NO_MEMORY;
+ sc = rtems_scheduler_ident_by_processor(cpu_index, &scheduler);
+ if (sc != RTEMS_SUCCESSFUL) {
+ /* Do not start an interrupt server on a processor without a scheduler */
+ return RTEMS_SUCCESSFUL;
}
+
+ sc = rtems_task_set_scheduler(s->server, scheduler, priority);
+ _Assert(sc == RTEMS_SUCCESSFUL);
+
+ /* Set the task to processor affinity on a best-effort basis */
+ CPU_ZERO(&cpu);
+ CPU_SET(cpu_index, &cpu);
+ (void) rtems_task_set_affinity(s->server, sizeof(cpu), &cpu);
#else
- instances = &bsp_interrupt_server_instance;
+ (void) cpu_index;
#endif
- for (cpu_index = 0; cpu_index < cpu_count; ++cpu_index) {
- bsp_interrupt_server_context *s = &instances[cpu_index];
- rtems_status_code sc;
+ rtems_chain_append_unprotected(&bsp_interrupt_server_chain, &s->node);
+
+ sc = rtems_task_start(
+ s->server,
+ bsp_interrupt_server_task,
+ (rtems_task_argument) s
+ );
+ _Assert(sc == RTEMS_SUCCESSFUL);
+
+ return sc;
+}
+
+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
+)
+{
+ rtems_status_code sc;
+ rtems_interrupt_server_control *s;
+ uint32_t cpu_index;
#if defined(RTEMS_SMP)
- rtems_id scheduler;
- cpu_set_t cpu;
+ uint32_t cpu_count;
#endif
- rtems_interrupt_lock_initialize(&s->lock, "Interrupt Server");
- rtems_chain_initialize_empty(&s->entries);
+ cpu_index = 0;
+ s = &bsp_interrupt_server_default;
+
+ bsp_interrupt_lock();
+
+ if (s->server != 0) {
+ sc = RTEMS_INCORRECT_STATE;
+ goto done;
+ }
+
+ s->destroy = bsp_interrupt_server_destroy_default;
+ sc = bsp_interrupt_server_create(
+ s,
+ priority,
+ stack_size,
+ modes,
+ attributes,
+ cpu_index
+ );
+ if (sc != RTEMS_SUCCESSFUL) {
+ goto done;
+ }
+
+ cpu_index = 1;
+
+#if defined(RTEMS_SMP)
+ cpu_count = rtems_scheduler_get_processor_maximum();
+
+ while (cpu_index < cpu_count) {
+ s = calloc(1, sizeof(*s));
- sc = rtems_task_create(
- rtems_build_name('I', 'R', 'Q', 'S'),
+ if (s == NULL) {
+ sc = RTEMS_NO_MEMORY;
+ goto done;
+ }
+
+ s->destroy = bsp_interrupt_server_destroy_secondary;
+ s->index = cpu_index;
+ sc = bsp_interrupt_server_create(
+ s,
priority,
stack_size,
modes,
attributes,
- &s->server
+ cpu_index
);
if (sc != RTEMS_SUCCESSFUL) {
- *server_count = cpu_index;
-
-#if defined(RTEMS_SMP)
- if (cpu_index > 0) {
- bsp_interrupt_server_instances = instances;
- return RTEMS_SUCCESSFUL;
- }
+ goto done;
+ }
- free(instances);
+ ++cpu_index;
+ }
#endif
- return RTEMS_TOO_MANY;
- }
+done:
+ bsp_interrupt_unlock();
-#if defined(RTEMS_SMP)
- sc = rtems_scheduler_ident_by_processor(cpu_index, &scheduler);
- if (sc != RTEMS_SUCCESSFUL) {
- /* Do not start an interrupt server on a processor without a scheduler */
- continue;
- }
+ if (server_count != NULL) {
+ *server_count = cpu_index;
+ }
- sc = rtems_task_set_scheduler(s->server, scheduler, priority);
- _Assert(sc == RTEMS_SUCCESSFUL);
+ return sc;
+}
- /* Set the task to processor affinity on a best-effort basis */
- CPU_ZERO(&cpu);
- CPU_SET(cpu_index, &cpu);
- (void) rtems_task_set_affinity(s->server, sizeof(cpu), &cpu);
-#endif
+rtems_status_code rtems_interrupt_server_create(
+ rtems_interrupt_server_control *s,
+ const rtems_interrupt_server_config *config,
+ uint32_t *server_index
+)
+{
+ rtems_status_code sc;
- sc = rtems_task_start(
- s->server,
- bsp_interrupt_server_task,
- (rtems_task_argument) s
- );
- _Assert(sc == RTEMS_SUCCESSFUL);
+ sc = rtems_task_create(
+ config->name,
+ config->priority,
+ config->storage_size,
+ config->modes,
+ config->attributes,
+ &s->server
+ );
+ if (sc != RTEMS_SUCCESSFUL) {
+ return sc;
}
-#if defined(RTEMS_SMP)
- bsp_interrupt_server_instances = instances;
-#endif
- *server_count = cpu_index;
+ rtems_interrupt_lock_initialize(&s->lock, "Interrupt Server");
+ rtems_chain_initialize_empty(&s->entries);
+ s->destroy = config->destroy;
+ s->index = rtems_object_id_get_index(s->server)
+ + rtems_scheduler_get_processor_maximum();
+ *server_index = s->index;
+ bsp_interrupt_lock();
+ rtems_chain_initialize_node(&s->node);
+ rtems_chain_append_unprotected(&bsp_interrupt_server_chain, &s->node);
+ bsp_interrupt_unlock();
+
+ sc = rtems_task_start(
+ s->server,
+ bsp_interrupt_server_task,
+ (rtems_task_argument) s
+ );
+ _Assert(sc == RTEMS_SUCCESSFUL);
+
+ return sc;
+}
+
+static void bsp_interrupt_server_destroy_helper(void *arg)
+{
+ bsp_interrupt_server_helper_data *hd = arg;
+ rtems_interrupt_server_control *s = hd->server;
+ rtems_status_code sc;
+
+ bsp_interrupt_lock();
+ rtems_chain_extract_unprotected(&s->node);
+ bsp_interrupt_unlock();
+
+ if (s->destroy != NULL) {
+ (*s->destroy)(s);
+ }
+
+ sc = rtems_event_transient_send(hd->task);
+ _Assert(sc == RTEMS_SUCCESSFUL);
+ (void) sc;
+
+ rtems_task_exit();
+}
+
+rtems_status_code rtems_interrupt_server_delete(uint32_t server_index)
+{
+ rtems_status_code sc;
+ rtems_interrupt_server_control *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_destroy_helper
+ );
return RTEMS_SUCCESSFUL;
}
static void bsp_interrupt_server_entry_initialize(
rtems_interrupt_server_entry *entry,
- bsp_interrupt_server_context *s
+ rtems_interrupt_server_control *s
)
{
rtems_chain_set_off_chain(&entry->node);
@@ -611,7 +744,7 @@ rtems_status_code rtems_interrupt_server_entry_initialize(
)
{
rtems_status_code sc;
- bsp_interrupt_server_context *s;
+ rtems_interrupt_server_control *s;
s = bsp_interrupt_server_get_context(server_index, &sc);
if (s == NULL) {
@@ -645,7 +778,7 @@ rtems_status_code rtems_interrupt_server_entry_move(
)
{
rtems_status_code sc;
- bsp_interrupt_server_context *s;
+ rtems_interrupt_server_control *s;
s = bsp_interrupt_server_get_context(destination_server_index, &sc);
if (s == NULL) {
@@ -667,7 +800,7 @@ void rtems_interrupt_server_entry_destroy(
rtems_interrupt_server_entry *entry
)
{
- bsp_interrupt_server_context *s;
+ rtems_interrupt_server_control *s;
rtems_interrupt_lock_context lock_context;
s = entry->server;
@@ -698,7 +831,7 @@ rtems_status_code rtems_interrupt_server_request_initialize(
)
{
rtems_status_code sc;
- bsp_interrupt_server_context *s;
+ rtems_interrupt_server_control *s;
s = bsp_interrupt_server_get_context(server_index, &sc);
if (s == NULL) {
@@ -727,8 +860,8 @@ static void bsp_interrupt_server_handler_move_helper(void *arg)
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;
+ rtems_interrupt_server_control *src = e->server;
+ rtems_interrupt_server_control *dst = hihd->arg;
bool pending;
/* The source server is only used in SMP configurations for the lock */
@@ -763,8 +896,8 @@ rtems_status_code rtems_interrupt_server_move(
)
{
rtems_status_code sc;
- bsp_interrupt_server_context *src;
- bsp_interrupt_server_context *dst;
+ rtems_interrupt_server_control *src;
+ rtems_interrupt_server_control *dst;
bsp_interrupt_server_handler_iterate_helper_data hihd;
src = bsp_interrupt_server_get_context(source_server_index, &sc);
@@ -810,7 +943,7 @@ static void bsp_interrupt_server_entry_suspend_helper(void *arg)
rtems_status_code rtems_interrupt_server_suspend(uint32_t server_index)
{
rtems_status_code sc;
- bsp_interrupt_server_context *s;
+ rtems_interrupt_server_control *s;
s = bsp_interrupt_server_get_context(server_index, &sc);
if (s == NULL) {
@@ -831,7 +964,7 @@ rtems_status_code rtems_interrupt_server_suspend(uint32_t server_index)
rtems_status_code rtems_interrupt_server_resume(uint32_t server_index)
{
rtems_status_code sc;
- bsp_interrupt_server_context *s;
+ rtems_interrupt_server_control *s;
s = bsp_interrupt_server_get_context(server_index, &sc);
if (s == NULL) {
@@ -858,7 +991,7 @@ rtems_status_code rtems_interrupt_server_set_affinity(
)
{
rtems_status_code sc;
- bsp_interrupt_server_context *s;
+ rtems_interrupt_server_control *s;
rtems_id scheduler;
s = bsp_interrupt_server_get_context(server_index, &sc);
diff --git a/cpukit/include/rtems/irq-extension.h b/cpukit/include/rtems/irq-extension.h
index 0d77b320bc..2105194c00 100644
--- a/cpukit/include/rtems/irq-extension.h
+++ b/cpukit/include/rtems/irq-extension.h
@@ -9,13 +9,7 @@
/*
* Based on concepts of Pavel Pisa, Till Straumann and Eric Valette.
*
- * Copyright (C) 2008, 2019 embedded brains GmbH
- *
- * embedded brains GmbH
- * Dornierstr. 4
- * 82178 Puchheim
- * Germany
- * <rtems@embedded-brains.de>
+ * Copyright (C) 2008, 2020 embedded brains GmbH (http://www.embedded-brains.de)
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
@@ -260,6 +254,76 @@ typedef struct rtems_interrupt_server_action {
#define RTEMS_INTERRUPT_SERVER_DEFAULT 0
/**
+ * @brief An interrupt server control.
+ *
+ * This structure must be treated as an opaque data type. Members must not be
+ * accessed directly.
+ *
+ * @see rtems_interrupt_server_create()
+ */
+typedef struct rtems_interrupt_server_control {
+ RTEMS_INTERRUPT_LOCK_MEMBER( lock )
+ rtems_chain_control entries;
+ rtems_id server;
+ unsigned long errors;
+ uint32_t index;
+ rtems_chain_node node;
+ void ( *destroy )( struct rtems_interrupt_server_control * );
+} rtems_interrupt_server_control;
+
+/**
+ * @brief An interrupt server configuration.
+ *
+ * @see rtems_interrupt_server_create()
+ */
+typedef struct {
+ /**
+ * @brief The task name of the interrupt server.
+ */
+ rtems_name name;
+
+ /**
+ * @brief The initial task priority of the interrupt server.
+ */
+ rtems_task_priority priority;
+
+ /**
+ * @brief The task storage area of the interrupt server.
+ *
+ * It shall be NULL for interrupt servers created by
+ * rtems_interrupt_server_create().
+ */
+ void *storage_area;
+
+ /**
+ * @brief The task storage size of the interrupt server.
+ *
+ * For interrupt servers created by rtems_interrupt_server_create() this is
+ * the task stack size.
+ */
+ size_t storage_size;
+
+ /**
+ * @brief The initial task modes of the interrupt server.
+ */
+ rtems_mode modes;
+
+ /**
+ * @brief The task attributes of the interrupt server.
+ */
+ rtems_attribute attributes;
+
+ /**
+ * @brief An optional handler to destroy the interrupt server control handed
+ * over to rtems_interrupt_server_create().
+ *
+ * This handler is called in the context of the interrupt server to be
+ * deleted, see also rtems_interrupt_server_delete().
+ */
+ void ( *destroy )( rtems_interrupt_server_control * );
+} rtems_interrupt_server_config;
+
+/**
* @brief An interrupt server entry.
*
* This structure must be treated as an opaque data type. Members must not be
@@ -309,16 +373,19 @@ typedef struct {
*
* The server count pointer @a server_count may be @a NULL.
*
+ * The task name of interrupt servers created by this function is
+ * rtems_build_name( 'I', 'R', 'Q', 'S' ).
+ *
* This function may block.
*
- * @see rtems_task_create().
+ * @retval RTEMS_SUCCESSFUL The operation was successful.
*
- * @retval RTEMS_SUCCESSFUL Successful operation.
- * @retval RTEMS_INCORRECT_STATE The interrupt servers are not initialized.
- * @retval RTEMS_NO_MEMORY Not enough memory.
- * @retval RTEMS_TOO_MANY No free task available to create at least one server task.
- * @retval RTEMS_UNSATISFIED Task stack size too large.
- * @retval RTEMS_INVALID_PRIORITY Invalid task priority.
+ * @retval RTEMS_INCORRECT_STATE The interrupt servers were already initialized.
+ *
+ * @return The function uses rtems_task_create(). If this operation is not
+ * successful, then its status code is returned.
+ *
+ * @see rtems_interrupt_server_create() and rtems_interrupt_server_delete().
*/
rtems_status_code rtems_interrupt_server_initialize(
rtems_task_priority priority,
@@ -329,6 +396,54 @@ rtems_status_code rtems_interrupt_server_initialize(
);
/**
+ * @brief Creates an interrupt server.
+ *
+ * This function may block.
+ *
+ * @param[out] control is the interrupt server control. The ownership of this
+ * structure is transferred from the caller of this function to the interrupt
+ * server management.
+ *
+ * @param config is the interrupt server configuration.
+ *
+ * @param[out] server_index is the pointer to a server index variable. The
+ * index of the built interrupt server will be stored in the referenced
+ * variable if the operation was successful.
+ *
+ * @retval RTEMS_SUCCESSFUL The operation was successful.
+ *
+ * @return The function uses rtems_task_create(). If this operation is not
+ * successful, then its status code is returned.
+ *
+ * @see rtems_interrupt_server_initialize() and
+ * rtems_interrupt_server_delete().
+ */
+rtems_status_code rtems_interrupt_server_create(
+ rtems_interrupt_server_control *control,
+ const rtems_interrupt_server_config *config,
+ uint32_t *server_index
+);
+
+/**
+ * @brief Destroys the interrupt server.
+ *
+ * This function may block.
+ *
+ * The interrupt server deletes itself, so after the return of the function the
+ * interrupt server may be still in the termination process depending on the
+ * task priorities of the system.
+ *
+ * @param server_index is the index of the interrupt server to destroy. Use
+ * ::RTEMS_INTERRUPT_SERVER_DEFAULT to specify the default server.
+ *
+ * @retval RTEMS_SUCCESSFUL The operation was successful.
+ * @retval RTEMS_INVALID_ID The interrupt server index was invalid.
+ *
+ * @see rtems_interrupt_server_create()
+ */
+rtems_status_code rtems_interrupt_server_delete( uint32_t server_index );
+
+/**
* @brief Installs the interrupt handler routine @a handler for the interrupt
* vector with number @a vector on the server @a server.
*