Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:07

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSImplClassicIntr
0007  *
0008  * @brief This source file contains the generic interrupt controller support
0009  *   implementation.
0010  */
0011 
0012 /*
0013  * Copyright (C) 2008, 2021 embedded brains GmbH & Co. KG
0014  *
0015  * Redistribution and use in source and binary forms, with or without
0016  * modification, are permitted provided that the following conditions
0017  * are met:
0018  * 1. Redistributions of source code must retain the above copyright
0019  *    notice, this list of conditions and the following disclaimer.
0020  * 2. Redistributions in binary form must reproduce the above copyright
0021  *    notice, this list of conditions and the following disclaimer in the
0022  *    documentation and/or other materials provided with the distribution.
0023  *
0024  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0025  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0027  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0028  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0029  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0030  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0031  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0032  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0033  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0034  * POSSIBILITY OF SUCH DAMAGE.
0035  */
0036 
0037 #include <bsp/irq-generic.h>
0038 
0039 #include <rtems/malloc.h>
0040 
0041 #ifdef BSP_INTERRUPT_USE_INDEX_TABLE
0042   bsp_interrupt_dispatch_index_type bsp_interrupt_dispatch_index_table
0043     [BSP_INTERRUPT_VECTOR_COUNT];
0044 #endif
0045 
0046 rtems_interrupt_entry *
0047 bsp_interrupt_dispatch_table[ BSP_INTERRUPT_DISPATCH_TABLE_SIZE ];
0048 
0049 RTEMS_WEAK rtems_interrupt_entry **bsp_interrupt_get_dispatch_table_slot(
0050   rtems_vector_number index
0051 )
0052 {
0053   return &bsp_interrupt_dispatch_table[ index ];
0054 }
0055 
0056 /* The last entry indicates if everything is initialized */
0057 uint8_t bsp_interrupt_handler_unique_table
0058   [ ( BSP_INTERRUPT_DISPATCH_TABLE_SIZE + 7 + 1 ) / 8 ];
0059 
0060 static inline void bsp_interrupt_set_initialized(void)
0061 {
0062   bsp_interrupt_set_handler_unique(BSP_INTERRUPT_DISPATCH_TABLE_SIZE, true);
0063 }
0064 
0065 #if defined(BSP_INTERRUPT_USE_INDEX_TABLE)
0066 static inline rtems_vector_number bsp_interrupt_allocate_handler_index( void )
0067 {
0068   rtems_vector_number i;
0069 
0070   /* The first entry will remain empty */
0071   for ( i = 1; i < BSP_INTERRUPT_DISPATCH_TABLE_SIZE; ++i ) {
0072     if (  bsp_interrupt_dispatch_table[ i ] == NULL ) {
0073       break;
0074     }
0075   }
0076 
0077   return i;
0078 }
0079 #endif
0080 
0081 #if defined(RTEMS_SMP)
0082 RTEMS_STATIC_ASSERT(
0083   sizeof( Atomic_Uintptr ) == sizeof( rtems_interrupt_entry * ),
0084   rtems_interrupt_entry_pointer_size
0085 );
0086 
0087 void bsp_interrupt_spurious( rtems_vector_number vector )
0088 {
0089   Atomic_Uintptr        *ptr;
0090   rtems_interrupt_entry *first;
0091 
0092   /*
0093    * In order to get the last written pointer value to the first entry, we have
0094    * to carry out an atomic read-modify-write operation.
0095    */
0096   ptr = (Atomic_Uintptr *) bsp_interrupt_get_dispatch_table_slot(
0097     bsp_interrupt_dispatch_index( vector )
0098   );
0099   first = (rtems_interrupt_entry *)
0100     _Atomic_Fetch_add_uintptr( ptr, 0, ATOMIC_ORDER_ACQUIRE );
0101 
0102   if ( first == NULL ) {
0103     bsp_interrupt_handler_default( vector );
0104   } else {
0105     bsp_interrupt_dispatch_entries( first );
0106   }
0107 }
0108 #endif
0109 
0110 rtems_status_code bsp_interrupt_check_and_lock(
0111   rtems_vector_number     vector,
0112   rtems_interrupt_handler routine
0113 )
0114 {
0115   if ( !bsp_interrupt_is_initialized() ) {
0116     return RTEMS_INCORRECT_STATE;
0117   }
0118 
0119   if ( routine == NULL ) {
0120     return RTEMS_INVALID_ADDRESS;
0121   }
0122 
0123   if ( !bsp_interrupt_is_valid_vector( vector ) ) {
0124     return RTEMS_INVALID_ID;
0125   }
0126 
0127   if ( rtems_interrupt_is_in_progress() ) {
0128     return RTEMS_CALLED_FROM_ISR;
0129   }
0130 
0131   bsp_interrupt_lock();
0132 
0133   return RTEMS_SUCCESSFUL;
0134 }
0135 
0136 rtems_interrupt_entry *bsp_interrupt_entry_find(
0137   rtems_vector_number      vector,
0138   rtems_interrupt_handler  routine,
0139   void                    *arg,
0140   rtems_interrupt_entry ***previous_next
0141 )
0142 {
0143   rtems_vector_number    index;
0144   rtems_interrupt_entry *entry;
0145 
0146   bsp_interrupt_assert( bsp_interrupt_is_valid_vector( vector ) );
0147   index = bsp_interrupt_dispatch_index( vector );
0148   *previous_next = bsp_interrupt_get_dispatch_table_slot( index );
0149   entry = **previous_next;
0150 
0151   while ( entry != NULL ) {
0152     if ( entry->handler == routine && entry->arg == arg ) {
0153       return entry;
0154     }
0155 
0156     *previous_next = &entry->next;
0157     entry = entry->next;
0158   }
0159 
0160   return NULL;
0161 }
0162 
0163 void bsp_interrupt_initialize( void )
0164 {
0165   bsp_interrupt_facility_initialize();
0166   bsp_interrupt_set_initialized();
0167 }
0168 
0169 static rtems_status_code bsp_interrupt_entry_install_first(
0170   rtems_vector_number       vector,
0171   rtems_option              options,
0172   rtems_interrupt_entry    *entry
0173 )
0174 {
0175   rtems_vector_number index;
0176 
0177 #ifdef BSP_INTERRUPT_USE_INDEX_TABLE
0178   index = bsp_interrupt_allocate_handler_index();
0179 
0180   if ( index == BSP_INTERRUPT_DISPATCH_TABLE_SIZE ) {
0181     /* Handler table is full */
0182     return RTEMS_NO_MEMORY;
0183   }
0184 #else
0185   index = vector;
0186 #endif
0187 
0188 #ifdef BSP_INTERRUPT_USE_INDEX_TABLE
0189   bsp_interrupt_dispatch_index_table[ vector ] = index;
0190 #endif
0191   bsp_interrupt_entry_store_release(
0192     bsp_interrupt_get_dispatch_table_slot( index ),
0193     entry
0194   );
0195 
0196   bsp_interrupt_set_handler_unique(
0197     index,
0198     RTEMS_INTERRUPT_IS_UNIQUE( options )
0199   );
0200 #if defined(bsp_interrupt_vector_install)
0201   bsp_interrupt_vector_install( vector );
0202 #else
0203   bsp_interrupt_vector_enable( vector );
0204 #endif
0205 
0206   return RTEMS_SUCCESSFUL;
0207 }
0208 
0209 static rtems_status_code bsp_interrupt_entry_install(
0210   rtems_vector_number    vector,
0211   rtems_option           options,
0212   rtems_interrupt_entry *entry
0213 )
0214 {
0215   rtems_vector_number     index;
0216   rtems_interrupt_entry  *first;
0217   rtems_interrupt_entry  *other;
0218   rtems_interrupt_entry **previous_next;
0219 
0220   if ( RTEMS_INTERRUPT_IS_REPLACE( options ) ) {
0221     return RTEMS_INVALID_NUMBER;
0222   }
0223 
0224   index = bsp_interrupt_dispatch_index( vector );
0225   first = *bsp_interrupt_get_dispatch_table_slot( index );
0226 
0227   if ( first == NULL ) {
0228     return bsp_interrupt_entry_install_first( vector, options, entry );
0229   }
0230 
0231   if ( RTEMS_INTERRUPT_IS_UNIQUE( options ) ) {
0232     /* Cannot install a unique entry if there is already an entry installed */
0233     return RTEMS_RESOURCE_IN_USE;
0234   }
0235 
0236   if ( bsp_interrupt_is_handler_unique( index ) ) {
0237     /*
0238      * Cannot install another entry if there is already an unique entry
0239      * installed.
0240      */
0241     return RTEMS_RESOURCE_IN_USE;
0242   }
0243 
0244   other = bsp_interrupt_entry_find(
0245     vector,
0246     entry->handler,
0247     entry->arg,
0248     &previous_next
0249   );
0250 
0251   if ( other != NULL ) {
0252     /*
0253      * Cannot install an entry which has the same routine and argument as an
0254      * already installed entry.
0255      */
0256     return RTEMS_TOO_MANY;
0257   }
0258 
0259   bsp_interrupt_entry_store_release( previous_next, entry );
0260 
0261   return RTEMS_SUCCESSFUL;
0262 }
0263 
0264 rtems_status_code rtems_interrupt_entry_install(
0265   rtems_vector_number    vector,
0266   rtems_option           options,
0267   rtems_interrupt_entry *entry
0268 )
0269 {
0270   rtems_status_code sc;
0271 
0272   if ( entry == NULL ) {
0273     return RTEMS_INVALID_ADDRESS;
0274   }
0275 
0276   sc = bsp_interrupt_check_and_lock( vector, entry->handler );
0277 
0278   if ( sc != RTEMS_SUCCESSFUL ) {
0279     return sc;
0280   }
0281 
0282   sc = bsp_interrupt_entry_install( vector, options, entry );
0283   bsp_interrupt_unlock();
0284 
0285   return sc;
0286 }