summaryrefslogtreecommitdiffstats
path: root/bsps/shared/irq/irq-generic.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2021-06-25 15:52:16 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2021-07-26 19:57:31 +0200
commite5183238723bb35f5f5d2f0624b821f75f8b424b (patch)
tree6c410c8ae06dfeb9abaee226d7fdf025095d9dac /bsps/shared/irq/irq-generic.c
parentbsps/irq: Move bsp_interrupt_handler_is_empty() (diff)
downloadrtems-e5183238723bb35f5f5d2f0624b821f75f8b424b.tar.bz2
bsps/irq: Add rtems_interrupt_entry_install()
Add rtems_interrupt_entry_remove(). Split up irq-generic.c into several files. In particular, place all functions which use dynamic memory into their own file. Add optional macros to let the BSP customize the vector installation after installing the first entry and the vector removal before removing the last entry: * bsp_interrupt_vector_install() * bsp_interrupt_vector_remove() Use these new customization options in the m68k/genmcf548x BSP so re-use the generic interrupt controller support. Update #3269.
Diffstat (limited to 'bsps/shared/irq/irq-generic.c')
-rw-r--r--bsps/shared/irq/irq-generic.c486
1 files changed, 156 insertions, 330 deletions
diff --git a/bsps/shared/irq/irq-generic.c b/bsps/shared/irq/irq-generic.c
index df57c99ae3..eddb887d15 100644
--- a/bsps/shared/irq/irq-generic.c
+++ b/bsps/shared/irq/irq-generic.c
@@ -10,7 +10,7 @@
*/
/*
- * Copyright (C) 2008, 2018 embedded brains GmbH (http://www.embedded-brains.de)
+ * Copyright (C) 2008, 2021 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
@@ -46,92 +46,75 @@
[BSP_INTERRUPT_VECTOR_COUNT];
#endif
-rtems_interrupt_entry bsp_interrupt_handler_table
- [BSP_INTERRUPT_HANDLER_TABLE_SIZE];
+rtems_interrupt_entry *
+bsp_interrupt_handler_table[ BSP_INTERRUPT_HANDLER_TABLE_SIZE ];
/* The last entry indicates if everything is initialized */
uint8_t bsp_interrupt_handler_unique_table
[ ( BSP_INTERRUPT_HANDLER_TABLE_SIZE + 7 + 1 ) / 8 ];
-void bsp_interrupt_handler_empty( void *arg )
-{
- rtems_vector_number vector = (rtems_vector_number) (uintptr_t) arg;
-
- bsp_interrupt_handler_default( vector );
-}
-
-#ifdef RTEMS_SMP
- static void bsp_interrupt_handler_do_nothing(void *arg)
- {
- (void) arg;
- }
-#endif
-
-static inline void bsp_interrupt_set_handler_unique(
- rtems_vector_number index,
- bool unique
-)
-{
- rtems_vector_number i = index / 8;
- rtems_vector_number s = index % 8;
- if (unique) {
- bsp_interrupt_handler_unique_table [i] |= (uint8_t) (0x1U << s);
- } else {
- bsp_interrupt_handler_unique_table [i] &= (uint8_t) ~(0x1U << s);
- }
-}
-
static inline void bsp_interrupt_set_initialized(void)
{
bsp_interrupt_set_handler_unique(BSP_INTERRUPT_HANDLER_TABLE_SIZE, true);
}
-static inline void bsp_interrupt_clear_handler_entry(
- rtems_interrupt_entry *e,
+#if defined(BSP_INTERRUPT_USE_INDEX_TABLE)
+static inline rtems_vector_number bsp_interrupt_allocate_handler_index(
rtems_vector_number vector
)
{
- e->handler = bsp_interrupt_handler_empty;
- bsp_interrupt_fence(ATOMIC_ORDER_RELEASE);
- e->arg = (void *) (uintptr_t) vector;
- e->info = NULL;
- e->next = NULL;
-}
+ rtems_vector_number i;
-static inline bool bsp_interrupt_allocate_handler_index(
- rtems_vector_number vector,
- rtems_vector_number *index
-)
-{
- #ifdef BSP_INTERRUPT_USE_INDEX_TABLE
- rtems_vector_number i = 0;
-
- /* The first entry will remain empty */
- for (i = 1; i < BSP_INTERRUPT_HANDLER_TABLE_SIZE; ++i) {
- const rtems_interrupt_entry *e = &bsp_interrupt_handler_table [i];
- if (bsp_interrupt_is_empty_handler_entry(e)) {
- *index = i;
- return true;
- }
+ /* The first entry will remain empty */
+ for ( i = 1; i < BSP_INTERRUPT_HANDLER_TABLE_SIZE; ++i ) {
+ if ( bsp_interrupt_handler_table[ i ] == NULL ) {
+ break;
}
+ }
+
+ return i;
+}
+#endif
+
+#if defined(RTEMS_SMP)
+RTEMS_STATIC_ASSERT(
+ sizeof( Atomic_Uintptr ) == sizeof( rtems_interrupt_entry * ),
+ rtems_interrupt_entry_pointer_size
+);
- return false;
- #else
- *index = bsp_interrupt_handler_index(vector);
- return true;
- #endif
+void bsp_interrupt_spurious( rtems_vector_number vector )
+{
+ Atomic_Uintptr *ptr;
+ rtems_interrupt_entry *first;
+
+ /*
+ * In order to get the last written pointer value to the first entry, we have
+ * to carry out an atomic read-modify-write operation.
+ */
+ ptr = (Atomic_Uintptr *) &bsp_interrupt_handler_table[
+ bsp_interrupt_handler_index( vector )
+ ];
+ first = (rtems_interrupt_entry *)
+ _Atomic_Fetch_add_uintptr( ptr, 0, ATOMIC_ORDER_ACQUIRE );
+
+ if ( first == NULL ) {
+ bsp_interrupt_handler_default( vector );
+ } else {
+ bsp_interrupt_dispatch_entries( first );
+ }
}
+#endif
rtems_status_code bsp_interrupt_check_and_lock(
rtems_vector_number vector,
- rtems_interrupt_handler handler
+ rtems_interrupt_handler routine
)
{
if ( !bsp_interrupt_is_initialized() ) {
return RTEMS_INCORRECT_STATE;
}
- if ( handler == NULL ) {
+ if ( routine == NULL ) {
return RTEMS_INVALID_ADDRESS;
}
@@ -148,317 +131,160 @@ rtems_status_code bsp_interrupt_check_and_lock(
return RTEMS_SUCCESSFUL;
}
-void bsp_interrupt_initialize(void)
+rtems_interrupt_entry *bsp_interrupt_entry_find(
+ rtems_vector_number vector,
+ rtems_interrupt_handler routine,
+ void *arg,
+ rtems_interrupt_entry ***previous_next
+)
{
- rtems_status_code sc = RTEMS_SUCCESSFUL;
- size_t i = 0;
+ rtems_vector_number index;
+ rtems_interrupt_entry *entry;
- /* Initialize handler table */
- for (i = 0; i < BSP_INTERRUPT_HANDLER_TABLE_SIZE; ++i) {
- bsp_interrupt_handler_table [i].handler = bsp_interrupt_handler_empty;
- bsp_interrupt_handler_table [i].arg = (void *) i;
+ bsp_interrupt_assert( bsp_interrupt_is_valid_vector( vector ) );
+ index = bsp_interrupt_handler_index( vector );
+ *previous_next = &bsp_interrupt_handler_table[ index ];
+ entry = bsp_interrupt_handler_table[ index ];
+
+ while ( entry != NULL ) {
+ if ( entry->handler == routine && entry->arg == arg ) {
+ return entry;
+ }
+
+ *previous_next = &entry->next;
+ entry = entry->next;
}
+ return NULL;
+}
+
+void bsp_interrupt_initialize( void )
+{
+ rtems_status_code sc;
+
sc = bsp_interrupt_facility_initialize();
- if (sc != RTEMS_SUCCESSFUL) {
- bsp_fatal(BSP_FATAL_INTERRUPT_INITIALIZATION);
+ if ( sc != RTEMS_SUCCESSFUL ) {
+ bsp_fatal( BSP_FATAL_INTERRUPT_INITIALIZATION );
}
bsp_interrupt_set_initialized();
}
-/**
- * @brief Installs an interrupt handler.
- *
- * @ingroup bsp_interrupt
- *
- * @return In addition to the standard status codes this function returns:
- * - If the BSP interrupt support is not initialized RTEMS_INTERNAL_ERROR will
- * be returned.
- * - If not enough memory for a new handler is available RTEMS_NO_MEMORY will
- * be returned
- *
- * @see rtems_interrupt_handler_install()
- */
-static rtems_status_code bsp_interrupt_handler_install(
- rtems_vector_number vector,
- const char *info,
- rtems_option options,
- rtems_interrupt_handler handler,
- void *arg
+static rtems_status_code bsp_interrupt_entry_install_first(
+ rtems_vector_number vector,
+ rtems_option options,
+ rtems_interrupt_entry *entry
)
{
- rtems_status_code sc;
- rtems_interrupt_level level;
- rtems_vector_number index = 0;
- rtems_interrupt_entry *head = NULL;
- bool enable_vector = false;
- bool replace = RTEMS_INTERRUPT_IS_REPLACE(options);
+ rtems_vector_number index;
- sc = bsp_interrupt_check_and_lock( vector, handler );
+#ifdef BSP_INTERRUPT_USE_INDEX_TABLE
+ index = bsp_interrupt_allocate_handler_index( vector );
- if ( sc != RTEMS_SUCCESSFUL ) {
- return sc;
+ if ( index == BSP_INTERRUPT_HANDLER_TABLE_SIZE ) {
+ /* Handler table is full */
+ return RTEMS_NO_MEMORY;
}
+#else
+ index = vector;
+#endif
- /* Get handler table index */
- index = bsp_interrupt_handler_index(vector);
+#ifdef BSP_INTERRUPT_USE_INDEX_TABLE
+ bsp_interrupt_handler_index_table[ vector ] = index;
+#endif
+ bsp_interrupt_entry_store_release(
+ &bsp_interrupt_handler_table[ index ],
+ entry
+ );
+
+ bsp_interrupt_set_handler_unique(
+ index,
+ RTEMS_INTERRUPT_IS_UNIQUE( options )
+ );
+#if defined(bsp_interrupt_vector_install)
+ bsp_interrupt_vector_install( vector );
+#else
+ bsp_interrupt_vector_enable( vector );
+#endif
- /* Get head entry of the handler list for current vector */
- head = &bsp_interrupt_handler_table [index];
+ return RTEMS_SUCCESSFUL;
+}
- if (bsp_interrupt_is_empty_handler_entry(head)) {
- if (replace) {
- /* No handler to replace exists */
- bsp_interrupt_unlock();
- return RTEMS_UNSATISFIED;
- }
+static rtems_status_code bsp_interrupt_entry_install(
+ rtems_vector_number vector,
+ rtems_option options,
+ rtems_interrupt_entry *entry
+)
+{
+ rtems_vector_number index;
+ rtems_interrupt_entry *first;
+ rtems_interrupt_entry *other;
+ rtems_interrupt_entry **previous_next;
- /*
- * No real handler installed yet. So allocate a new index in
- * the handler table and fill the entry with life.
- */
- if (bsp_interrupt_allocate_handler_index(vector, &index)) {
- bsp_interrupt_disable(level);
- bsp_interrupt_handler_table [index].arg = arg;
- bsp_interrupt_fence(ATOMIC_ORDER_RELEASE);
- bsp_interrupt_handler_table [index].handler = handler;
- #ifdef BSP_INTERRUPT_USE_INDEX_TABLE
- bsp_interrupt_handler_index_table [vector] = index;
- #endif
- bsp_interrupt_enable(level);
- bsp_interrupt_handler_table [index].info = info;
- } else {
- /* Handler table is full */
- bsp_interrupt_unlock();
- return RTEMS_NO_MEMORY;
- }
+ if ( RTEMS_INTERRUPT_IS_REPLACE( options ) ) {
+ return RTEMS_INVALID_NUMBER;
+ }
- /* This is the first handler so enable the vector later */
- enable_vector = true;
- } else {
- rtems_interrupt_entry *current = head;
- rtems_interrupt_entry *tail = NULL;
- rtems_interrupt_entry *match = NULL;
-
- /* Ensure that a unique handler remains unique */
- if (
- !replace
- && (RTEMS_INTERRUPT_IS_UNIQUE(options)
- || bsp_interrupt_is_handler_unique(index))
- ) {
- /*
- * Tried to install a unique handler on a not empty
- * list or there is already a unique handler installed.
- */
- bsp_interrupt_unlock();
- return RTEMS_RESOURCE_IN_USE;
- }
+ index = bsp_interrupt_handler_index( vector );
+ first = bsp_interrupt_handler_table[ index ];
+
+ if ( first == NULL ) {
+ return bsp_interrupt_entry_install_first( vector, options, entry );
+ }
+ if ( RTEMS_INTERRUPT_IS_UNIQUE( options ) ) {
+ /* Cannot install a unique entry if there is already an entry installed */
+ return RTEMS_RESOURCE_IN_USE;
+ }
+
+ if ( bsp_interrupt_is_handler_unique( index ) ) {
/*
- * Search for the list tail and check if the handler is already
+ * Cannot install another entry if there is already an unique entry
* installed.
*/
- do {
- if (
- match == NULL
- && (current->handler == handler || replace)
- && current->arg == arg
- ) {
- match = current;
- }
- tail = current;
- current = current->next;
- } while (current != NULL);
-
- if (replace) {
- /* Ensure that a handler to replace exists */
- if (match == NULL) {
- bsp_interrupt_unlock();
- return RTEMS_UNSATISFIED;
- }
-
- /* Use existing entry */
- current = match;
- } else {
- /* Ensure the handler is not already installed */
- if (match != NULL) {
- /* The handler is already installed */
- bsp_interrupt_unlock();
- return RTEMS_TOO_MANY;
- }
-
- /* Allocate a new entry */
- current = rtems_malloc(sizeof(*current));
- if (current == NULL) {
- /* Not enough memory */
- bsp_interrupt_unlock();
- return RTEMS_NO_MEMORY;
- }
- }
-
- /* Update existing entry or set new entry */
- current->handler = handler;
- current->info = info;
-
- if (!replace) {
- /* Set new entry */
- current->arg = arg;
- current->next = NULL;
-
- /* Link to list tail */
- bsp_interrupt_disable(level);
- bsp_interrupt_fence(ATOMIC_ORDER_RELEASE);
- tail->next = current;
- bsp_interrupt_enable(level);
- }
+ return RTEMS_RESOURCE_IN_USE;
}
- /* Make the handler unique if necessary */
- bsp_interrupt_set_handler_unique(index, RTEMS_INTERRUPT_IS_UNIQUE(options));
+ other = bsp_interrupt_entry_find(
+ vector,
+ entry->handler,
+ entry->arg,
+ &previous_next
+ );
- /* Enable the vector if necessary */
- if (enable_vector) {
- bsp_interrupt_vector_enable(vector);
+ if ( other != NULL ) {
+ /*
+ * Cannot install an entry which has the same routine and argument as an
+ * already installed entry.
+ */
+ return RTEMS_TOO_MANY;
}
- /* Unlock */
- bsp_interrupt_unlock();
+ bsp_interrupt_entry_store_release( previous_next, entry );
return RTEMS_SUCCESSFUL;
}
-/**
- * @brief Removes an interrupt handler.
- *
- * @ingroup bsp_interrupt
- *
- * @return In addition to the standard status codes this function returns
- * RTEMS_INTERNAL_ERROR if the BSP interrupt support is not initialized.
- *
- * @see rtems_interrupt_handler_remove().
- */
-static rtems_status_code bsp_interrupt_handler_remove(
- rtems_vector_number vector,
- rtems_interrupt_handler handler,
- void *arg
+rtems_status_code rtems_interrupt_entry_install(
+ rtems_vector_number vector,
+ rtems_option options,
+ rtems_interrupt_entry *entry
)
{
rtems_status_code sc;
- rtems_interrupt_level level;
- rtems_vector_number index = 0;
- rtems_interrupt_entry *head = NULL;
- rtems_interrupt_entry *current = NULL;
- rtems_interrupt_entry *previous = NULL;
- rtems_interrupt_entry *match = NULL;
-
- sc = bsp_interrupt_check_and_lock( vector, handler );
- if ( sc != RTEMS_SUCCESSFUL ) {
- return sc;
+ if ( entry == NULL ) {
+ return RTEMS_INVALID_ADDRESS;
}
- /* Get handler table index */
- index = bsp_interrupt_handler_index(vector);
-
- /* Get head entry of the handler list for current vector */
- head = &bsp_interrupt_handler_table [index];
+ sc = bsp_interrupt_check_and_lock( vector, entry->handler );
- /* Search for a matching entry */
- current = head;
- do {
- if (current->handler == handler && current->arg == arg) {
- match = current;
- break;
- }
- previous = current;
- current = current->next;
- } while (current != NULL);
-
- /* Remove the matching entry */
- if (match != NULL) {
- if (match->next != NULL) {
- /*
- * The match has a successor. A successor is always
- * allocated. So replace the match with its successor
- * and free the successor entry.
- */
- current = match->next;
-
- bsp_interrupt_disable(level);
- #ifdef RTEMS_SMP
- match->handler = bsp_interrupt_handler_do_nothing;
- bsp_interrupt_fence(ATOMIC_ORDER_RELEASE);
- #endif
- match->arg = current->arg;
- bsp_interrupt_fence(ATOMIC_ORDER_RELEASE);
- match->handler = current->handler;
- match->info = current->info;
- match->next = current->next;
- bsp_interrupt_enable(level);
-
- free(current);
- } else if (match == head) {
- /*
- * The match is the list head and has no successor.
- * The list head is stored in a static table so clear
- * this entry. Since now the list is empty disable the
- * vector.
- */
-
- /* Disable the vector */
- bsp_interrupt_vector_disable(vector);
-
- /* Clear entry */
- bsp_interrupt_disable(level);
- bsp_interrupt_clear_handler_entry(head, vector);
- #ifdef BSP_INTERRUPT_USE_INDEX_TABLE
- bsp_interrupt_handler_index_table [vector] = 0;
- #endif
- bsp_interrupt_enable(level);
-
- /* Allow shared handlers */
- bsp_interrupt_set_handler_unique(index, false);
- } else {
- /*
- * The match is the list tail and has a predecessor.
- * So terminate the predecessor and free the match.
- */
- bsp_interrupt_disable(level);
- previous->next = NULL;
- bsp_interrupt_fence(ATOMIC_ORDER_RELEASE);
- bsp_interrupt_enable(level);
-
- free(match);
- }
- } else {
- /* No matching entry found */
- bsp_interrupt_unlock();
- return RTEMS_UNSATISFIED;
+ if ( sc != RTEMS_SUCCESSFUL ) {
+ return sc;
}
- /* Unlock */
+ sc = bsp_interrupt_entry_install( vector, options, entry );
bsp_interrupt_unlock();
- return RTEMS_SUCCESSFUL;
-}
-
-rtems_status_code rtems_interrupt_handler_install(
- rtems_vector_number vector,
- const char *info,
- rtems_option options,
- rtems_interrupt_handler handler,
- void *arg
-)
-{
- return bsp_interrupt_handler_install(vector, info, options, handler, arg);
-}
-
-rtems_status_code rtems_interrupt_handler_remove(
- rtems_vector_number vector,
- rtems_interrupt_handler handler,
- void *arg
-)
-{
- return bsp_interrupt_handler_remove(vector, handler, arg);
+ return sc;
}