summaryrefslogtreecommitdiffstats
path: root/bsps
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2020-07-30 10:30:15 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2020-08-03 08:52:41 +0200
commitc60942ea5bd6c8973e1f81dd2674f753b2862839 (patch)
treed0fe59f53609f5f83dab84bca21ccbce17572bf9 /bsps
parentbsps/fdt: Make sure data is cache aligned (diff)
downloadrtems-c60942ea5bd6c8973e1f81dd2674f753b2862839.tar.bz2
rtems: Add rtems_interrupt_server_create()
Add rtems_interrupt_server_destroy(). Before this patch, the only way to create interrupt servers was rtems_interrupt_server_initialize(). This function creates the default interrupt server and in SMP configurations additional interrupt servers for the additional processors. The interrupt server is heavily used by libbsd. This includes the epoch based reclamation which performs time consuming resource and memory deallocation work. This does not work well with time critical services, for example an UART over SPI or I2C. One approach to address this problem is to allow the application to create custom interrupt servers with the right priority and task properties. The interrupt server API accounted for this, however, it was not implemented before this patch. Close #4034.
Diffstat (limited to 'bsps')
-rw-r--r--bsps/shared/irq/irq-server.c365
1 files changed, 249 insertions, 116 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);