diff options
Diffstat (limited to 'bsps/shared/irq/irq-server.c')
-rw-r--r-- | bsps/shared/irq/irq-server.c | 365 |
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); |