summaryrefslogtreecommitdiffstats
path: root/bsps/include/bsp/irq-generic.h
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/include/bsp/irq-generic.h')
-rw-r--r--bsps/include/bsp/irq-generic.h214
1 files changed, 169 insertions, 45 deletions
diff --git a/bsps/include/bsp/irq-generic.h b/bsps/include/bsp/irq-generic.h
index 12e8f9155b..e27c1b230c 100644
--- a/bsps/include/bsp/irq-generic.h
+++ b/bsps/include/bsp/irq-generic.h
@@ -12,7 +12,7 @@
/*
* Copyright (C) 2016 Chris Johns <chrisj@rtems.org>
*
- * Copyright (C) 2008, 2017 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
@@ -70,20 +70,13 @@ extern "C" {
#define BSP_INTERRUPT_HANDLER_TABLE_SIZE BSP_INTERRUPT_VECTOR_COUNT
#endif
-/* Internal macros for SMP support, do not use externally */
-#ifdef RTEMS_SMP
- #define bsp_interrupt_disable(level) do { (void) level; } while (0)
- #define bsp_interrupt_enable(level) do { } while (0)
- #define bsp_interrupt_fence(order) _Atomic_Fence(order)
-#else
- #define bsp_interrupt_disable(level) rtems_interrupt_disable(level)
- #define bsp_interrupt_enable(level) rtems_interrupt_enable(level)
- #define bsp_interrupt_fence(order) do { } while (0)
-#endif
-
#define bsp_interrupt_assert(e) _Assert(e)
-extern rtems_interrupt_entry bsp_interrupt_handler_table [];
+/**
+ * @brief Each member of this table references the first installed entry at the
+ * corresponding interrupt vector or is NULL.
+ */
+extern rtems_interrupt_entry *bsp_interrupt_handler_table[];
#ifdef BSP_INTERRUPT_USE_INDEX_TABLE
#if BSP_INTERRUPT_HANDLER_TABLE_SIZE < 0x100
@@ -141,6 +134,12 @@ static inline rtems_vector_number bsp_interrupt_handler_index(
* - bsp_interrupt_vector_disable()
* - bsp_interrupt_handler_default()
*
+ * Optionally, the BSP may define the following macros to 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()
+ *
* The following now deprecated functions are provided for backward
* compatibility:
* - BSP_get_current_rtems_irq_handler()
@@ -362,14 +361,114 @@ rtems_status_code bsp_interrupt_raise_on(
*/
rtems_status_code bsp_interrupt_clear( rtems_vector_number vector );
+#if defined(RTEMS_SMP)
+/**
+ * @brief Handles a spurious interrupt.
+ *
+ * @param vector is the vector number.
+ */
+void bsp_interrupt_spurious( rtems_vector_number vector );
+#endif
+
+/**
+ * @brief Loads the interrupt entry with atomic acquire semantic.
+ *
+ * @param ptr is the pointer to an ::rtems_interrupt_entry pointer.
+ *
+ * @return Returns the pointer value.
+ */
+static inline rtems_interrupt_entry *bsp_interrupt_entry_load_acquire(
+ rtems_interrupt_entry * const *ptr
+)
+{
+#if defined(RTEMS_SMP)
+ return (rtems_interrupt_entry *) _Atomic_Load_uintptr(
+ (const Atomic_Uintptr *) ptr,
+ ATOMIC_ORDER_ACQUIRE
+ );
+#else
+ return *ptr;
+#endif
+}
+
+/**
+ * @brief Stores the interrupt entry with atomic release semantic.
+ *
+ * @param[out] ptr is the pointer to an ::rtems_interrupt_entry pointer.
+ *
+ * @param value is the pointer value.
+ */
+static inline void bsp_interrupt_entry_store_release(
+ rtems_interrupt_entry **ptr,
+ rtems_interrupt_entry *value
+)
+{
+#if defined(RTEMS_SMP)
+ _Atomic_Store_uintptr(
+ (Atomic_Uintptr *) ptr,
+ (Atomic_Uintptr) value,
+ ATOMIC_ORDER_RELEASE
+ );
+#else
+ rtems_interrupt_level level;
+
+ rtems_interrupt_local_disable( level );
+ *ptr = value;
+ rtems_interrupt_local_enable( level );
+#endif
+}
+
+/**
+ * @brief Loads the first interrupt entry installed at the interrupt vector.
+ *
+ * @param vector is the vector number.
+ *
+ * @return Returns the first entry or NULL.
+ */
+static inline rtems_interrupt_entry *bsp_interrupt_entry_load_first(
+ rtems_vector_number vector
+)
+{
+ rtems_vector_number index;
+
+ index = bsp_interrupt_handler_index( vector );
+
+ return bsp_interrupt_entry_load_acquire(
+ &bsp_interrupt_handler_table[ index ]
+ );
+}
+
+/**
+ * @brief Sequentially calls all interrupt handlers of the entry its
+ * successors.
+ *
+ * In uniprocessor configurations, you can call this function within every
+ * context which can be disabled via rtems_interrupt_local_disable().
+ *
+ * In SMP configurations, you can call this function in every context.
+ *
+ * @param entry is the first entry.
+ */
+static inline void bsp_interrupt_dispatch_entries(
+ const rtems_interrupt_entry *entry
+)
+{
+ do {
+ ( *entry->handler )( entry->arg );
+ entry = bsp_interrupt_entry_load_acquire( &entry->next );
+ } while ( RTEMS_PREDICT_FALSE( entry != NULL ) );
+}
+
/**
* @brief Sequentially calls all interrupt handlers installed at the vector.
*
* This function does not validate the vector number. If the vector number is
* out of range, then the behaviour is undefined.
*
- * You can call this function within every context which can be disabled via
- * rtems_interrupt_local_disable().
+ * In uniprocessor configurations, you can call this function within every
+ * context which can be disabled via rtems_interrupt_local_disable().
+ *
+ * In SMP configurations, you can call this function in every context.
*
* @param vector is the vector number.
*/
@@ -377,21 +476,19 @@ static inline void bsp_interrupt_handler_dispatch_unchecked(
rtems_vector_number vector
)
{
- const rtems_interrupt_entry *e;
-
- e = &bsp_interrupt_handler_table[ bsp_interrupt_handler_index( vector ) ];
-
- do {
- rtems_interrupt_handler handler;
- void *arg;
+ const rtems_interrupt_entry *entry;
- arg = e->arg;
- bsp_interrupt_fence( ATOMIC_ORDER_ACQUIRE );
- handler = e->handler;
- ( *handler )( arg );
+ entry = bsp_interrupt_entry_load_first( vector );
- e = e->next;
- } while ( e != NULL );
+ if ( RTEMS_PREDICT_TRUE( entry != NULL ) ) {
+ bsp_interrupt_dispatch_entries( entry );
+ } else {
+#if defined(RTEMS_SMP)
+ bsp_interrupt_spurious( vector );
+#else
+ bsp_interrupt_handler_default( vector );
+#endif
+ }
}
/**
@@ -401,8 +498,10 @@ static inline void bsp_interrupt_handler_dispatch_unchecked(
* bsp_interrupt_handler_default() will be called with the vector number as
* argument.
*
- * You can call this function within every context which can be disabled via
- * rtems_interrupt_local_disable().
+ * In uniprocessor configurations, you can call this function within every
+ * context which can be disabled via rtems_interrupt_local_disable().
+ *
+ * In SMP configurations, you can call this function in every context.
*
* @param vector is the vector number.
*/
@@ -457,6 +556,21 @@ rtems_status_code bsp_interrupt_check_and_lock(
rtems_interrupt_handler handler
);
+/* For internal use only */
+rtems_interrupt_entry *bsp_interrupt_entry_find(
+ rtems_vector_number vector,
+ rtems_interrupt_handler routine,
+ void *arg,
+ rtems_interrupt_entry ***previous_next
+);
+
+/* For internal use only */
+void bsp_interrupt_entry_remove(
+ rtems_vector_number vector,
+ rtems_interrupt_entry *entry,
+ rtems_interrupt_entry **previous_next
+);
+
/**
* @brief This table contains a bit map which indicates if an entry is unique
* or shared.
@@ -489,29 +603,39 @@ static inline bool bsp_interrupt_is_handler_unique( rtems_vector_number index )
}
/**
- * @brief Checks if the interrupt support is initialized.
+ * @brief Sets the unique status of the handler entry.
*
- * @return Returns true, if the interrupt support is initialized, otherwise
- * false.
+ * @param index is the handler index.
+ *
+ * @param unique is the unique status to set.
*/
-static inline bool bsp_interrupt_is_initialized( void )
+static inline void bsp_interrupt_set_handler_unique(
+ rtems_vector_number index,
+ bool unique
+)
{
- return bsp_interrupt_is_handler_unique( BSP_INTERRUPT_HANDLER_TABLE_SIZE );
-}
+ rtems_vector_number table_index;
+ uint8_t bit;
-/**
- * @brief This handler routine is used for empty entries.
- */
-void bsp_interrupt_handler_empty( void *arg );
+ table_index = index / 8;
+ bit = (uint8_t) ( 1U << ( index % 8 ) );
+
+ if (unique) {
+ bsp_interrupt_handler_unique_table[ table_index ] |= bit;
+ } else {
+ bsp_interrupt_handler_unique_table[ table_index ] &= ~bit;
+ }
+}
/**
- * @brief Checks if a handler entry is empty.
+ * @brief Checks if the interrupt support is initialized.
+ *
+ * @return Returns true, if the interrupt support is initialized, otherwise
+ * false.
*/
-static inline bool bsp_interrupt_is_empty_handler_entry(
- const rtems_interrupt_entry *entry
-)
+static inline bool bsp_interrupt_is_initialized( void )
{
- return entry->handler == bsp_interrupt_handler_empty;
+ return bsp_interrupt_is_handler_unique( BSP_INTERRUPT_HANDLER_TABLE_SIZE );
}
#ifdef __cplusplus