summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2017-02-21 15:25:03 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2017-02-23 07:27:39 +0100
commit33986022af8f5389370cb012ba0e73e032774cab (patch)
tree378acbd1600783b5ff8d8fb84c533c14c5015b91
parentbsp/xilinx-zynq: Add interrupt support to UART (diff)
downloadrtems-33986022af8f5389370cb012ba0e73e032774cab.tar.bz2
Add rtems_interrupt_server_request_submit()
This function may be used to do a two-step interrupt processing. The first step is done in interrupt context which calls this function. The second step is then done in the context of the interrupt server.
-rw-r--r--c/src/lib/libbsp/shared/src/irq-server.c148
-rw-r--r--cpukit/include/rtems/irq-extension.h182
2 files changed, 297 insertions, 33 deletions
diff --git a/c/src/lib/libbsp/shared/src/irq-server.c b/c/src/lib/libbsp/shared/src/irq-server.c
index 4f127af7ba..905c26198b 100644
--- a/c/src/lib/libbsp/shared/src/irq-server.c
+++ b/c/src/lib/libbsp/shared/src/irq-server.c
@@ -7,7 +7,7 @@
*/
/*
- * Copyright (c) 2009, 2016 embedded brains GmbH. All rights reserved.
+ * Copyright (c) 2009, 2017 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
@@ -28,24 +28,14 @@
#include <bsp/irq-generic.h>
+#define BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR (BSP_INTERRUPT_VECTOR_MAX + 1)
+
RTEMS_INTERRUPT_LOCK_DEFINE(
static,
bsp_interrupt_server_lock,
"Interrupt Server"
)
-typedef struct bsp_interrupt_server_action {
- struct bsp_interrupt_server_action *next;
- rtems_interrupt_handler handler;
- void *arg;
-} bsp_interrupt_server_action;
-
-typedef struct {
- rtems_chain_node node;
- rtems_vector_number vector;
- bsp_interrupt_server_action *actions;
-} bsp_interrupt_server_entry;
-
static rtems_id bsp_interrupt_server_id = RTEMS_ID_NONE;
static RTEMS_CHAIN_DEFINE_EMPTY(bsp_interrupt_server_chain);
@@ -64,7 +54,7 @@ static unsigned bsp_interrupt_server_errors;
static void bsp_interrupt_server_trigger(void *arg)
{
rtems_interrupt_lock_context lock_context;
- bsp_interrupt_server_entry *e = arg;
+ rtems_interrupt_server_entry *e = arg;
bsp_interrupt_vector_disable(e->vector);
@@ -82,7 +72,7 @@ static void bsp_interrupt_server_trigger(void *arg)
}
typedef struct {
- bsp_interrupt_server_entry *entry;
+ rtems_interrupt_server_entry *entry;
rtems_option *options;
} bsp_interrupt_server_iterate_entry;
@@ -102,7 +92,7 @@ static void bsp_interrupt_server_per_handler_routine(
}
}
-static bsp_interrupt_server_entry *bsp_interrupt_server_query_entry(
+static rtems_interrupt_server_entry *bsp_interrupt_server_query_entry(
rtems_vector_number vector,
rtems_option *trigger_options
)
@@ -134,8 +124,8 @@ static void bsp_interrupt_server_install_helper(void *arg)
{
bsp_interrupt_server_helper_data *hd = arg;
rtems_status_code sc;
- bsp_interrupt_server_entry *e;
- bsp_interrupt_server_action *a;
+ rtems_interrupt_server_entry *e;
+ rtems_interrupt_server_action *a;
rtems_option trigger_options;
a = calloc(1, sizeof(*a));
@@ -176,8 +166,8 @@ static void bsp_interrupt_server_install_helper(void *arg)
) {
sc = RTEMS_RESOURCE_IN_USE;
} else {
- bsp_interrupt_server_action **link = &e->actions;
- bsp_interrupt_server_action *c;
+ rtems_interrupt_server_action **link = &e->actions;
+ rtems_interrupt_server_action *c;
sc = RTEMS_SUCCESSFUL;
@@ -209,15 +199,15 @@ static void bsp_interrupt_server_remove_helper(void *arg)
{
bsp_interrupt_server_helper_data *hd = arg;
rtems_status_code sc;
- bsp_interrupt_server_entry *e;
+ 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) {
- bsp_interrupt_server_action **link = &e->actions;
- bsp_interrupt_server_action *c;
+ 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) {
@@ -274,12 +264,12 @@ static rtems_status_code bsp_interrupt_server_call_helper(
.arg = arg,
.task = rtems_task_self()
};
- bsp_interrupt_server_action a = {
+ rtems_interrupt_server_action a = {
.handler = helper,
.arg = &hd
};
- bsp_interrupt_server_entry e = {
- .vector = BSP_INTERRUPT_VECTOR_MAX + 1,
+ rtems_interrupt_server_entry e = {
+ .vector = BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR,
.actions = &a
};
@@ -289,17 +279,17 @@ static rtems_status_code bsp_interrupt_server_call_helper(
return hd.sc;
}
-static bsp_interrupt_server_entry *bsp_interrupt_server_get_entry(void)
+static rtems_interrupt_server_entry *bsp_interrupt_server_get_entry(void)
{
rtems_interrupt_lock_context lock_context;
- bsp_interrupt_server_entry *e;
+ rtems_interrupt_server_entry *e;
rtems_chain_control *chain;
rtems_interrupt_lock_acquire(&bsp_interrupt_server_lock, &lock_context);
chain = &bsp_interrupt_server_chain;
if (!rtems_chain_is_empty(chain)) {
- e = (bsp_interrupt_server_entry *)
+ e = (rtems_interrupt_server_entry *)
rtems_chain_get_first_unprotected(chain);
rtems_chain_set_off_chain(&e->node);
} else {
@@ -315,7 +305,7 @@ static void bsp_interrupt_server_task(rtems_task_argument arg)
{
while (true) {
rtems_event_set events;
- bsp_interrupt_server_entry *e;
+ rtems_interrupt_server_entry *e;
rtems_event_system_receive(
RTEMS_EVENT_SYSTEM_SERVER,
@@ -325,11 +315,11 @@ static void bsp_interrupt_server_task(rtems_task_argument arg)
);
while ((e = bsp_interrupt_server_get_entry()) != NULL) {
- bsp_interrupt_server_action *action = e->actions;
+ rtems_interrupt_server_action *action = e->actions;
rtems_vector_number vector = e->vector;
do {
- bsp_interrupt_server_action *current = action;
+ rtems_interrupt_server_action *current = action;
action = action->next;
(*current->handler)(current->arg);
} while (action != NULL);
@@ -430,3 +420,97 @@ rtems_status_code rtems_interrupt_server_initialize(
return RTEMS_SUCCESSFUL;
}
+
+static void bsp_interrupt_server_entry_initialize(
+ rtems_interrupt_server_entry *entry
+)
+{
+ rtems_chain_set_off_chain(&entry->node);
+ 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;
+}
+
+void rtems_interrupt_server_entry_initialize(
+ rtems_interrupt_server_entry *entry
+)
+{
+ bsp_interrupt_server_entry_initialize(entry);
+}
+
+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_id server,
+ rtems_interrupt_server_entry *entry
+)
+{
+ bsp_interrupt_server_trigger(entry);
+}
+
+static void bsp_interrupt_server_entry_destroy_helper(void *arg)
+{
+ bsp_interrupt_server_helper_data *hd = arg;
+
+ rtems_event_transient_send(hd->task);
+}
+
+void rtems_interrupt_server_entry_destroy(
+ rtems_id server,
+ rtems_interrupt_server_entry *entry
+)
+{
+ rtems_interrupt_lock_context lock_context;
+
+ rtems_interrupt_lock_acquire(&bsp_interrupt_server_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(&bsp_interrupt_server_lock, &lock_context);
+
+ bsp_interrupt_server_call_helper(
+ BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR,
+ 0,
+ NULL,
+ NULL,
+ bsp_interrupt_server_entry_destroy_helper
+ );
+}
+
+void rtems_interrupt_server_request_initialize(
+ rtems_interrupt_server_request *request,
+ rtems_interrupt_handler handler,
+ void *arg
+)
+{
+ bsp_interrupt_server_entry_initialize(&request->entry);
+ bsp_interrupt_server_action_prepend(
+ &request->entry,
+ &request->action,
+ handler,
+ arg
+ );
+}
diff --git a/cpukit/include/rtems/irq-extension.h b/cpukit/include/rtems/irq-extension.h
index fc8c125e1b..71ff800881 100644
--- a/cpukit/include/rtems/irq-extension.h
+++ b/cpukit/include/rtems/irq-extension.h
@@ -9,7 +9,7 @@
/*
* Based on concepts of Pavel Pisa, Till Straumann and Eric Valette.
*
- * Copyright (c) 2008, 2016 embedded brains GmbH.
+ * Copyright (c) 2008, 2017 embedded brains GmbH.
*
* embedded brains GmbH
* Dornierstr. 4
@@ -26,6 +26,7 @@
#define RTEMS_IRQ_EXTENSION_H
#include <rtems.h>
+#include <rtems/chain.h>
#ifdef __cplusplus
extern "C" {
@@ -203,6 +204,52 @@ rtems_status_code rtems_interrupt_handler_iterate(
);
/**
+ * @brief An interrupt server action.
+ *
+ * This structure must be treated as an opaque data type. Members must not be
+ * accessed directly.
+ *
+ * @see rtems_interrupt_server_action_prepend().
+ */
+typedef struct rtems_interrupt_server_action {
+ struct rtems_interrupt_server_action *next;
+ rtems_interrupt_handler handler;
+ void *arg;
+} rtems_interrupt_server_action;
+
+/**
+ * @brief An interrupt server entry.
+ *
+ * This structure must be treated as an opaque data type. Members must not be
+ * accessed directly.
+ *
+ * @see rtems_interrupt_server_entry_initialize(),
+ * rtems_interrupt_server_action_prepend(),
+ * rtems_interrupt_server_entry_submit(), and
+ * rtems_interrupt_server_entry_destroy().
+ */
+typedef struct {
+ rtems_chain_node node;
+ rtems_vector_number vector;
+ rtems_interrupt_server_action *actions;
+} rtems_interrupt_server_entry;
+
+/**
+ * @brief An interrupt server request.
+ *
+ * This structure must be treated as an opaque data type. Members must not be
+ * accessed directly.
+ *
+ * @see rtems_interrupt_server_request_initialize(),
+ * rtems_interrupt_server_request_submit(), and
+ * rtems_interrupt_server_request_destroy().
+ */
+typedef struct {
+ rtems_interrupt_server_entry entry;
+ rtems_interrupt_server_action action;
+} rtems_interrupt_server_request;
+
+/**
* @brief Initializes an interrupt server task.
*
* The task will have the priority @a priority, the stack size @a stack_size,
@@ -285,6 +332,139 @@ rtems_status_code rtems_interrupt_server_handler_remove(
void *arg
);
+/**
+ * @brief Initializes the specified interrupt server entry.
+ *
+ * @param[in] entry The interrupt server entry to initialize.
+ *
+ * @see rtems_interrupt_server_action_prepend().
+ */
+void rtems_interrupt_server_entry_initialize(
+ rtems_interrupt_server_entry *entry
+);
+
+/**
+ * @brief Prepends the specified interrupt server action to the list of actions
+ * of the specified interrupt server entry.
+ *
+ * No error checking is performed.
+ *
+ * @param[in] entry The interrupt server entry to prepend the interrupt server
+ * action. It must have been initialized via
+ * rtems_interrupt_server_entry_initialize().
+ * @param[in] action The interrupt server action to prepend the list of actions
+ * of the entry.
+ * @param[in] handler The interrupt handler for the action.
+ * @param[in] arg The interrupt handler argument for the action.
+ */
+void rtems_interrupt_server_action_prepend(
+ rtems_interrupt_server_entry *entry,
+ rtems_interrupt_server_action *action,
+ rtems_interrupt_handler handler,
+ void *arg
+);
+
+/**
+ * @brief Submits the specified interrupt server entry so that its interrupt
+ * server actions can be invoked by the specified interrupt server.
+ *
+ * This function may be used to do a two-step interrupt processing. The first
+ * step is done in interrupt context which calls this function. The second
+ * step is then done in the context of the interrupt server.
+ *
+ * This function may be called from thread or interrupt context. It does not
+ * block. No error checking is performed.
+ *
+ * @param[in] server The server identifier. Use @c RTEMS_ID_NONE to specify
+ * the default server.
+ * @param[in] entry The interrupt server entry must be initialized before the
+ * first call to this function via rtems_interrupt_server_entry_initialize()
+ * and rtems_interrupt_server_action_prepend(). The entry and its actions
+ * must not be modified between calls to this function. Use
+ * rtems_interrupt_server_entry_destroy() to destroy an entry in use.
+ */
+void rtems_interrupt_server_entry_submit(
+ rtems_id server,
+ rtems_interrupt_server_entry *entry
+);
+
+/**
+ * @brief Destroys the specified interrupt server entry.
+ *
+ * This function must be called from thread context. It may block. No error
+ * checking is performed.
+ *
+ * @param[in] server The server identifier. Use @c RTEMS_ID_NONE to specify
+ * the default server.
+ * @param[in] entry The interrupt server entry to destroy. It must have been
+ * initialized via rtems_interrupt_server_entry_initialize().
+ */
+void rtems_interrupt_server_entry_destroy(
+ rtems_id server,
+ rtems_interrupt_server_entry *entry
+);
+
+/**
+ * @brief Initializes the specified interrupt server request.
+ *
+ * No error checking is performed.
+ *
+ * @param[in] request The interrupt server request to initialize.
+ * @param[in] handler The interrupt handler for the request action.
+ * @param[in] arg The interrupt handler argument for the request action.
+ */
+void rtems_interrupt_server_request_initialize(
+ rtems_interrupt_server_request *request,
+ rtems_interrupt_handler handler,
+ void *arg
+);
+
+/**
+ * @brief Submits the specified interrupt server request so that its interrupt
+ * server action can be invoked by the specified interrupt server.
+ *
+ * This function may be used to do a two-step interrupt processing. The first
+ * step is done in interrupt context which calls this function. The second
+ * step is then done in the context of the interrupt server.
+ *
+ * This function may be called from thread or interrupt context. It does not
+ * block. No error checking is performed.
+ *
+ * @param[in] server The server identifier. Use @c RTEMS_ID_NONE to specify
+ * the default server.
+ * @param[in] request The interrupt server request must be initialized before the
+ * first call to this function via
+ * rtems_interrupt_server_request_initialize(). The request must not be
+ * modified between calls to this function. Use
+ * rtems_interrupt_server_request_destroy() to destroy a request in use.
+ */
+RTEMS_INLINE_ROUTINE void rtems_interrupt_server_request_submit(
+ rtems_id server,
+ rtems_interrupt_server_request *request
+)
+{
+ rtems_interrupt_server_entry_submit( server, &request->entry );
+}
+
+/**
+ * @brief Destroys the specified interrupt server request.
+ *
+ * This function must be called from thread context. It may block. No error
+ * checking is performed.
+ *
+ * @param[in] server The server identifier. Use @c RTEMS_ID_NONE to specify
+ * the default server.
+ * @param[in] request The interrupt server request to destroy. It must have
+ * been initialized via rtems_interrupt_server_request_initialize().
+ */
+RTEMS_INLINE_ROUTINE void rtems_interrupt_server_request_destroy(
+ rtems_id server,
+ rtems_interrupt_server_request *request
+)
+{
+ rtems_interrupt_server_entry_destroy( server, &request->entry );
+}
+
/** @} */
#ifdef __cplusplus