source: rtems/bsps/shared/irq/irq-generic.c @ 67c033d3

Last change on this file since 67c033d3 was e518323, checked in by Sebastian Huber <sebastian.huber@…>, on 06/25/21 at 13:52:16

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.

  • Property mode set to 100644
File size: 7.3 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/**
4 * @file
5 *
6 * @ingroup bsp_interrupt
7 *
8 * @brief This source file contains the generic interrupt controller support
9 *   implementation.
10 */
11
12/*
13 * Copyright (C) 2008, 2021 embedded brains GmbH (http://www.embedded-brains.de)
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 *    notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 *    notice, this list of conditions and the following disclaimer in the
22 *    documentation and/or other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37#include <bsp/irq-generic.h>
38#include <bsp/fatal.h>
39
40#include <stdlib.h>
41
42#include <rtems/malloc.h>
43
44#ifdef BSP_INTERRUPT_USE_INDEX_TABLE
45  bsp_interrupt_handler_index_type bsp_interrupt_handler_index_table
46    [BSP_INTERRUPT_VECTOR_COUNT];
47#endif
48
49rtems_interrupt_entry *
50bsp_interrupt_handler_table[ BSP_INTERRUPT_HANDLER_TABLE_SIZE ];
51
52/* The last entry indicates if everything is initialized */
53uint8_t bsp_interrupt_handler_unique_table
54  [ ( BSP_INTERRUPT_HANDLER_TABLE_SIZE + 7 + 1 ) / 8 ];
55
56static inline void bsp_interrupt_set_initialized(void)
57{
58  bsp_interrupt_set_handler_unique(BSP_INTERRUPT_HANDLER_TABLE_SIZE, true);
59}
60
61#if defined(BSP_INTERRUPT_USE_INDEX_TABLE)
62static inline rtems_vector_number bsp_interrupt_allocate_handler_index(
63  rtems_vector_number vector
64)
65{
66  rtems_vector_number i;
67
68  /* The first entry will remain empty */
69  for ( i = 1; i < BSP_INTERRUPT_HANDLER_TABLE_SIZE; ++i ) {
70    if (  bsp_interrupt_handler_table[ i ] == NULL ) {
71      break;
72    }
73  }
74
75  return i;
76}
77#endif
78
79#if defined(RTEMS_SMP)
80RTEMS_STATIC_ASSERT(
81  sizeof( Atomic_Uintptr ) == sizeof( rtems_interrupt_entry * ),
82  rtems_interrupt_entry_pointer_size
83);
84
85void bsp_interrupt_spurious( rtems_vector_number vector )
86{
87  Atomic_Uintptr        *ptr;
88  rtems_interrupt_entry *first;
89
90  /*
91   * In order to get the last written pointer value to the first entry, we have
92   * to carry out an atomic read-modify-write operation.
93   */
94  ptr = (Atomic_Uintptr *) &bsp_interrupt_handler_table[
95    bsp_interrupt_handler_index( vector )
96  ];
97  first = (rtems_interrupt_entry *)
98    _Atomic_Fetch_add_uintptr( ptr, 0, ATOMIC_ORDER_ACQUIRE );
99
100  if ( first == NULL ) {
101    bsp_interrupt_handler_default( vector );
102  } else {
103    bsp_interrupt_dispatch_entries( first );
104  }
105}
106#endif
107
108rtems_status_code bsp_interrupt_check_and_lock(
109  rtems_vector_number     vector,
110  rtems_interrupt_handler routine
111)
112{
113  if ( !bsp_interrupt_is_initialized() ) {
114    return RTEMS_INCORRECT_STATE;
115  }
116
117  if ( routine == NULL ) {
118    return RTEMS_INVALID_ADDRESS;
119  }
120
121  if ( !bsp_interrupt_is_valid_vector( vector ) ) {
122    return RTEMS_INVALID_ID;
123  }
124
125  if ( rtems_interrupt_is_in_progress() ) {
126    return RTEMS_CALLED_FROM_ISR;
127  }
128
129  bsp_interrupt_lock();
130
131  return RTEMS_SUCCESSFUL;
132}
133
134rtems_interrupt_entry *bsp_interrupt_entry_find(
135  rtems_vector_number      vector,
136  rtems_interrupt_handler  routine,
137  void                    *arg,
138  rtems_interrupt_entry ***previous_next
139)
140{
141  rtems_vector_number    index;
142  rtems_interrupt_entry *entry;
143
144  bsp_interrupt_assert( bsp_interrupt_is_valid_vector( vector ) );
145  index = bsp_interrupt_handler_index( vector );
146  *previous_next = &bsp_interrupt_handler_table[ index ];
147  entry = bsp_interrupt_handler_table[ index ];
148
149  while ( entry != NULL ) {
150    if ( entry->handler == routine && entry->arg == arg ) {
151      return entry;
152    }
153
154    *previous_next = &entry->next;
155    entry = entry->next;
156  }
157
158  return NULL;
159}
160
161void bsp_interrupt_initialize( void )
162{
163  rtems_status_code sc;
164
165  sc = bsp_interrupt_facility_initialize();
166  if ( sc != RTEMS_SUCCESSFUL ) {
167    bsp_fatal( BSP_FATAL_INTERRUPT_INITIALIZATION );
168  }
169
170  bsp_interrupt_set_initialized();
171}
172
173static rtems_status_code bsp_interrupt_entry_install_first(
174  rtems_vector_number       vector,
175  rtems_option              options,
176  rtems_interrupt_entry    *entry
177)
178{
179  rtems_vector_number index;
180
181#ifdef BSP_INTERRUPT_USE_INDEX_TABLE
182  index = bsp_interrupt_allocate_handler_index( vector );
183
184  if ( index == BSP_INTERRUPT_HANDLER_TABLE_SIZE ) {
185    /* Handler table is full */
186    return RTEMS_NO_MEMORY;
187  }
188#else
189  index = vector;
190#endif
191
192#ifdef BSP_INTERRUPT_USE_INDEX_TABLE
193  bsp_interrupt_handler_index_table[ vector ] = index;
194#endif
195  bsp_interrupt_entry_store_release(
196    &bsp_interrupt_handler_table[ index ],
197    entry
198  );
199
200  bsp_interrupt_set_handler_unique(
201    index,
202    RTEMS_INTERRUPT_IS_UNIQUE( options )
203  );
204#if defined(bsp_interrupt_vector_install)
205  bsp_interrupt_vector_install( vector );
206#else
207  bsp_interrupt_vector_enable( vector );
208#endif
209
210  return RTEMS_SUCCESSFUL;
211}
212
213static rtems_status_code bsp_interrupt_entry_install(
214  rtems_vector_number    vector,
215  rtems_option           options,
216  rtems_interrupt_entry *entry
217)
218{
219  rtems_vector_number     index;
220  rtems_interrupt_entry  *first;
221  rtems_interrupt_entry  *other;
222  rtems_interrupt_entry **previous_next;
223
224  if ( RTEMS_INTERRUPT_IS_REPLACE( options ) ) {
225    return RTEMS_INVALID_NUMBER;
226  }
227
228  index = bsp_interrupt_handler_index( vector );
229  first = bsp_interrupt_handler_table[ index ];
230
231  if ( first == NULL ) {
232    return bsp_interrupt_entry_install_first( vector, options, entry );
233  }
234
235  if ( RTEMS_INTERRUPT_IS_UNIQUE( options ) ) {
236    /* Cannot install a unique entry if there is already an entry installed */
237    return RTEMS_RESOURCE_IN_USE;
238  }
239
240  if ( bsp_interrupt_is_handler_unique( index ) ) {
241    /*
242     * Cannot install another entry if there is already an unique entry
243     * installed.
244     */
245    return RTEMS_RESOURCE_IN_USE;
246  }
247
248  other = bsp_interrupt_entry_find(
249    vector,
250    entry->handler,
251    entry->arg,
252    &previous_next
253  );
254
255  if ( other != NULL ) {
256    /*
257     * Cannot install an entry which has the same routine and argument as an
258     * already installed entry.
259     */
260    return RTEMS_TOO_MANY;
261  }
262
263  bsp_interrupt_entry_store_release( previous_next, entry );
264
265  return RTEMS_SUCCESSFUL;
266}
267
268rtems_status_code rtems_interrupt_entry_install(
269  rtems_vector_number    vector,
270  rtems_option           options,
271  rtems_interrupt_entry *entry
272)
273{
274  rtems_status_code sc;
275
276  if ( entry == NULL ) {
277    return RTEMS_INVALID_ADDRESS;
278  }
279
280  sc = bsp_interrupt_check_and_lock( vector, entry->handler );
281
282  if ( sc != RTEMS_SUCCESSFUL ) {
283    return sc;
284  }
285
286  sc = bsp_interrupt_entry_install( vector, options, entry );
287  bsp_interrupt_unlock();
288
289  return sc;
290}
Note: See TracBrowser for help on using the repository browser.