summaryrefslogtreecommitdiffstats
path: root/bsps/include/bsp/irq-generic.h
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/include/bsp/irq-generic.h
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/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