/* SPDX-License-Identifier: BSD-2-Clause */
/**
* @file
*
* @ingroup bsp_interrupt
*
* @brief This source file contains the interrupt server implementation.
*/
/*
* Copyright (C) 2009, 2020 embedded brains GmbH (http://www.embedded-brains.de)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <string.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)
static rtems_interrupt_server_control bsp_interrupt_server_default;
static rtems_chain_control bsp_interrupt_server_chain =
RTEMS_CHAIN_INITIALIZER_EMPTY(bsp_interrupt_server_chain);
static rtems_interrupt_server_control *bsp_interrupt_server_get_context(
uint32_t server_index,
rtems_status_code *sc
)
{
rtems_chain_node *node;
bsp_interrupt_lock();
node = rtems_chain_first(&bsp_interrupt_server_chain);
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);
}
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;
rtems_interrupt_server_control *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 {
rtems_interrupt_server_control *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(
rtems_interrupt_server_control *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(
rtems_interrupt_server_control *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)
{
rtems_interrupt_server_control *s = (rtems_interrupt_server_control *) 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;
rtems_interrupt_server_control *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;
rtems_interrupt_server_control *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;
rtems_interrupt_server_control *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
);
}
/*
* 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 cpu_index
)
{
rtems_status_code sc;
#if defined(RTEMS_SMP)
rtems_id scheduler;
cpu_set_t cpu;
#endif
sc = rtems_task_create(
rtems_build_name('I', 'R', 'Q', 'S'),
priority,
stack_size,
modes,
attributes,
&s->server
);
if (sc != RTEMS_SUCCESSFUL) {
(*s->destroy)(s);
return sc;
}
rtems_interrupt_lock_initialize(&s->lock, "Interrupt Server");
rtems_chain_initialize_empty(&s->entries);
#if defined(RTEMS_SMP)
sc = rtems_scheduler_ident_by_processor(cpu_index, &scheduler);
/*
* If a scheduler exists for the processor, then move it to this scheduler
* and try to set the affinity to the processor, otherwise keep the scheduler
* of the executing thread.
*/
if (sc == 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
(void) cpu_index;
#endif
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)
uint32_t cpu_count;
#endif
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));
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,
cpu_index
);
if (sc != RTEMS_SUCCESSFUL) {
goto done;
}
++cpu_index;
}
#endif
done:
bsp_interrupt_unlock();
if (server_count != NULL) {
*server_count = cpu_index;
}
return sc;
}
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_create(
config->name,
config->priority,
config->storage_size,
config->modes,
config->attributes,
&s->server
);
if (sc != RTEMS_SUCCESSFUL) {
return sc;
}
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();
rtems_interrupt_lock_destroy(&s->lock);
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,
rtems_interrupt_server_control *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;
rtems_interrupt_server_control *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);
}
rtems_status_code rtems_interrupt_server_entry_move(
rtems_interrupt_server_entry *entry,
uint32_t destination_server_index
)
{
rtems_status_code sc;
rtems_interrupt_server_control *s;
s = bsp_interrupt_server_get_context(destination_server_index, &sc);
if (s == NULL) {
return sc;
}
entry->server = s;
return RTEMS_SUCCESSFUL;
}
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
)
{
rtems_interrupt_server_control *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;
rtems_interrupt_server_control *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;
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 */
(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;
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);
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;
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_entry_suspend_helper
);
return RTEMS_SUCCESSFUL;
}
rtems_status_code rtems_interrupt_server_resume(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;
}
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;
rtems_interrupt_server_control *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);
}