RTEMS
irq-generic.c
Go to the documentation of this file.
1 
9 /*
10  * Based on concepts of Pavel Pisa, Till Straumann and Eric Valette.
11  *
12  * Copyright (c) 2008, 2018 embedded brains GmbH.
13  *
14  * embedded brains GmbH
15  * Dornierstr. 4
16  * 82178 Puchheim
17  * Germany
18  * <rtems@embedded-brains.de>
19  *
20  * The license and distribution terms for this file may be
21  * found in the file LICENSE in this distribution or at
22  * http://www.rtems.org/license/LICENSE.
23  */
24 
25 #include <bsp/irq-generic.h>
26 #include <bsp/fatal.h>
27 
28 #include <stdlib.h>
29 
31 #include <rtems/malloc.h>
32 
33 #ifdef BSP_INTERRUPT_USE_INDEX_TABLE
34  bsp_interrupt_handler_index_type bsp_interrupt_handler_index_table
35  [BSP_INTERRUPT_VECTOR_NUMBER];
36 #endif
37 
38 bsp_interrupt_handler_entry bsp_interrupt_handler_table
39  [BSP_INTERRUPT_HANDLER_TABLE_SIZE];
40 
41 /* The last entry indicates if everything is initialized */
42 static uint8_t bsp_interrupt_handler_unique_table
43  [(BSP_INTERRUPT_HANDLER_TABLE_SIZE + 7 + 1) / 8];
44 
45 static void bsp_interrupt_handler_empty(void *arg)
46 {
47  rtems_vector_number vector = (rtems_vector_number) (uintptr_t) arg;
48 
50 }
51 
52 #ifdef RTEMS_SMP
53  static void bsp_interrupt_handler_do_nothing(void *arg)
54  {
55  (void) arg;
56  }
57 #endif
58 
59 static inline bool bsp_interrupt_is_handler_unique(rtems_vector_number index)
60 {
61  rtems_vector_number i = index / 8;
62  rtems_vector_number s = index % 8;
63  return (bsp_interrupt_handler_unique_table [i] >> s) & 0x1;
64 }
65 
66 static inline void bsp_interrupt_set_handler_unique(
67  rtems_vector_number index,
68  bool unique
69 )
70 {
71  rtems_vector_number i = index / 8;
72  rtems_vector_number s = index % 8;
73  if (unique) {
74  bsp_interrupt_handler_unique_table [i] |= (uint8_t) (0x1U << s);
75  } else {
76  bsp_interrupt_handler_unique_table [i] &= (uint8_t) ~(0x1U << s);
77  }
78 }
79 
80 static inline bool bsp_interrupt_is_initialized(void)
81 {
82  return bsp_interrupt_is_handler_unique(BSP_INTERRUPT_HANDLER_TABLE_SIZE);
83 }
84 
85 static inline void bsp_interrupt_set_initialized(void)
86 {
87  bsp_interrupt_set_handler_unique(BSP_INTERRUPT_HANDLER_TABLE_SIZE, true);
88 }
89 
90 static inline bool bsp_interrupt_is_empty_handler_entry(
92 )
93 {
94  return e->handler == bsp_interrupt_handler_empty;
95 }
96 
97 static inline void bsp_interrupt_clear_handler_entry(
99  rtems_vector_number vector
100 )
101 {
102  e->handler = bsp_interrupt_handler_empty;
103  bsp_interrupt_fence(ATOMIC_ORDER_RELEASE);
104  e->arg = (void *) (uintptr_t) vector;
105  e->info = NULL;
106  e->next = NULL;
107 }
108 
109 static inline bool bsp_interrupt_allocate_handler_index(
110  rtems_vector_number vector,
111  rtems_vector_number *index
112 )
113 {
114  #ifdef BSP_INTERRUPT_USE_INDEX_TABLE
115  rtems_vector_number i = 0;
116 
117  /* The first entry will remain empty */
118  for (i = 1; i < BSP_INTERRUPT_HANDLER_TABLE_SIZE; ++i) {
119  const bsp_interrupt_handler_entry *e = &bsp_interrupt_handler_table [i];
120  if (bsp_interrupt_is_empty_handler_entry(e)) {
121  *index = i;
122  return true;
123  }
124  }
125 
126  return false;
127  #else
128  *index = bsp_interrupt_handler_index(vector);
129  return true;
130  #endif
131 }
132 
133 static bsp_interrupt_handler_entry *bsp_interrupt_allocate_handler_entry(void)
134 {
136 
137  #ifdef BSP_INTERRUPT_NO_HEAP_USAGE
138  rtems_vector_number index = 0;
139 
140  if (bsp_interrupt_allocate_handler_index(0, &index)) {
141  e = &bsp_interrupt_handler_table [index];
142  } else {
143  e = NULL;
144  }
145  #else
146  e = rtems_malloc(sizeof(*e));
147  #endif
148 
149  return e;
150 }
151 
152 static void bsp_interrupt_free_handler_entry(bsp_interrupt_handler_entry *e)
153 {
154  #ifdef BSP_INTERRUPT_NO_HEAP_USAGE
155  bsp_interrupt_clear_handler_entry(e, 0);
156  #else
157  free(e);
158  #endif
159 }
160 
162 {
164  size_t i = 0;
165 
166  /* Initialize handler table */
167  for (i = 0; i < BSP_INTERRUPT_HANDLER_TABLE_SIZE; ++i) {
168  bsp_interrupt_handler_table [i].handler = bsp_interrupt_handler_empty;
169  bsp_interrupt_handler_table [i].arg = (void *) i;
170  }
171 
173  if (sc != RTEMS_SUCCESSFUL) {
174  bsp_fatal(BSP_FATAL_INTERRUPT_INITIALIZATION);
175  }
176 
177  bsp_interrupt_set_initialized();
178 }
179 
194  rtems_vector_number vector,
195  const char *info,
196  rtems_option options,
197  rtems_interrupt_handler handler,
198  void *arg
199 )
200 {
201  rtems_interrupt_level level;
202  rtems_vector_number index = 0;
203  bsp_interrupt_handler_entry *head = NULL;
204  bool enable_vector = false;
205  bool replace = RTEMS_INTERRUPT_IS_REPLACE(options);
206 
207  /* Check parameters and system state */
208  if (!bsp_interrupt_is_initialized()) {
209  return RTEMS_INTERNAL_ERROR;
210  } else if (!bsp_interrupt_is_valid_vector(vector)) {
211  return RTEMS_INVALID_ID;
212  } else if (handler == NULL) {
213  return RTEMS_INVALID_ADDRESS;
214  } else if (rtems_interrupt_is_in_progress()) {
215  return RTEMS_CALLED_FROM_ISR;
216  }
217 
218  /* Lock */
219  bsp_interrupt_lock();
220 
221  /* Get handler table index */
222  index = bsp_interrupt_handler_index(vector);
223 
224  /* Get head entry of the handler list for current vector */
225  head = &bsp_interrupt_handler_table [index];
226 
227  if (bsp_interrupt_is_empty_handler_entry(head)) {
228  if (replace) {
229  /* No handler to replace exists */
230  bsp_interrupt_unlock();
231  return RTEMS_UNSATISFIED;
232  }
233 
234  /*
235  * No real handler installed yet. So allocate a new index in
236  * the handler table and fill the entry with life.
237  */
238  if (bsp_interrupt_allocate_handler_index(vector, &index)) {
239  bsp_interrupt_disable(level);
240  bsp_interrupt_handler_table [index].arg = arg;
241  bsp_interrupt_fence(ATOMIC_ORDER_RELEASE);
242  bsp_interrupt_handler_table [index].handler = handler;
243  #ifdef BSP_INTERRUPT_USE_INDEX_TABLE
244  bsp_interrupt_handler_index_table [vector] = index;
245  #endif
246  bsp_interrupt_enable(level);
247  bsp_interrupt_handler_table [index].info = info;
248  } else {
249  /* Handler table is full */
250  bsp_interrupt_unlock();
251  return RTEMS_NO_MEMORY;
252  }
253 
254  /* This is the first handler so enable the vector later */
255  enable_vector = true;
256  } else {
257  bsp_interrupt_handler_entry *current = head;
258  bsp_interrupt_handler_entry *tail = NULL;
259  bsp_interrupt_handler_entry *match = NULL;
260 
261  /* Ensure that a unique handler remains unique */
262  if (
263  !replace
264  && (RTEMS_INTERRUPT_IS_UNIQUE(options)
265  || bsp_interrupt_is_handler_unique(index))
266  ) {
267  /*
268  * Tried to install a unique handler on a not empty
269  * list or there is already a unique handler installed.
270  */
271  bsp_interrupt_unlock();
272  return RTEMS_RESOURCE_IN_USE;
273  }
274 
275  /*
276  * Search for the list tail and check if the handler is already
277  * installed.
278  */
279  do {
280  if (
281  match == NULL
282  && (current->handler == handler || replace)
283  && current->arg == arg
284  ) {
285  match = current;
286  }
287  tail = current;
288  current = current->next;
289  } while (current != NULL);
290 
291  if (replace) {
292  /* Ensure that a handler to replace exists */
293  if (match == NULL) {
294  bsp_interrupt_unlock();
295  return RTEMS_UNSATISFIED;
296  }
297 
298  /* Use existing entry */
299  current = match;
300  } else {
301  /* Ensure the handler is not already installed */
302  if (match != NULL) {
303  /* The handler is already installed */
304  bsp_interrupt_unlock();
305  return RTEMS_TOO_MANY;
306  }
307 
308  /* Allocate a new entry */
309  current = bsp_interrupt_allocate_handler_entry();
310  if (current == NULL) {
311  /* Not enough memory */
312  bsp_interrupt_unlock();
313  return RTEMS_NO_MEMORY;
314  }
315  }
316 
317  /* Update existing entry or set new entry */
318  current->handler = handler;
319  current->info = info;
320 
321  if (!replace) {
322  /* Set new entry */
323  current->arg = arg;
324  current->next = NULL;
325 
326  /* Link to list tail */
327  bsp_interrupt_disable(level);
328  bsp_interrupt_fence(ATOMIC_ORDER_RELEASE);
329  tail->next = current;
330  bsp_interrupt_enable(level);
331  }
332  }
333 
334  /* Make the handler unique if necessary */
335  bsp_interrupt_set_handler_unique(index, RTEMS_INTERRUPT_IS_UNIQUE(options));
336 
337  /* Enable the vector if necessary */
338  if (enable_vector) {
340  }
341 
342  /* Unlock */
343  bsp_interrupt_unlock();
344 
345  return RTEMS_SUCCESSFUL;
346 }
347 
359  rtems_vector_number vector,
360  rtems_interrupt_handler handler,
361  void *arg
362 )
363 {
364  rtems_interrupt_level level;
365  rtems_vector_number index = 0;
366  bsp_interrupt_handler_entry *head = NULL;
367  bsp_interrupt_handler_entry *current = NULL;
368  bsp_interrupt_handler_entry *previous = NULL;
369  bsp_interrupt_handler_entry *match = NULL;
370 
371  /* Check parameters and system state */
372  if (!bsp_interrupt_is_initialized()) {
373  return RTEMS_INTERNAL_ERROR;
374  } else if (!bsp_interrupt_is_valid_vector(vector)) {
375  return RTEMS_INVALID_ID;
376  } else if (handler == NULL) {
377  return RTEMS_INVALID_ADDRESS;
378  } else if (rtems_interrupt_is_in_progress()) {
379  return RTEMS_CALLED_FROM_ISR;
380  }
381 
382  /* Lock */
383  bsp_interrupt_lock();
384 
385  /* Get handler table index */
386  index = bsp_interrupt_handler_index(vector);
387 
388  /* Get head entry of the handler list for current vector */
389  head = &bsp_interrupt_handler_table [index];
390 
391  /* Search for a matching entry */
392  current = head;
393  do {
394  if (current->handler == handler && current->arg == arg) {
395  match = current;
396  break;
397  }
398  previous = current;
399  current = current->next;
400  } while (current != NULL);
401 
402  /* Remove the matching entry */
403  if (match != NULL) {
404  if (match->next != NULL) {
405  /*
406  * The match has a successor. A successor is always
407  * allocated. So replace the match with its successor
408  * and free the successor entry.
409  */
410  current = match->next;
411 
412  bsp_interrupt_disable(level);
413  #ifdef RTEMS_SMP
414  match->handler = bsp_interrupt_handler_do_nothing;
415  bsp_interrupt_fence(ATOMIC_ORDER_RELEASE);
416  #endif
417  match->arg = current->arg;
418  bsp_interrupt_fence(ATOMIC_ORDER_RELEASE);
419  match->handler = current->handler;
420  match->info = current->info;
421  match->next = current->next;
422  bsp_interrupt_enable(level);
423 
424  bsp_interrupt_free_handler_entry(current);
425  } else if (match == head) {
426  /*
427  * The match is the list head and has no successor.
428  * The list head is stored in a static table so clear
429  * this entry. Since now the list is empty disable the
430  * vector.
431  */
432 
433  /* Disable the vector */
435 
436  /* Clear entry */
437  bsp_interrupt_disable(level);
438  bsp_interrupt_clear_handler_entry(head, vector);
439  #ifdef BSP_INTERRUPT_USE_INDEX_TABLE
440  bsp_interrupt_handler_index_table [vector] = 0;
441  #endif
442  bsp_interrupt_enable(level);
443 
444  /* Allow shared handlers */
445  bsp_interrupt_set_handler_unique(index, false);
446  } else {
447  /*
448  * The match is the list tail and has a predecessor.
449  * So terminate the predecessor and free the match.
450  */
451  bsp_interrupt_disable(level);
452  previous->next = NULL;
453  bsp_interrupt_fence(ATOMIC_ORDER_RELEASE);
454  bsp_interrupt_enable(level);
455 
456  bsp_interrupt_free_handler_entry(match);
457  }
458  } else {
459  /* No matching entry found */
460  bsp_interrupt_unlock();
461  return RTEMS_UNSATISFIED;
462  }
463 
464  /* Unlock */
465  bsp_interrupt_unlock();
466 
467  return RTEMS_SUCCESSFUL;
468 }
469 
481  rtems_vector_number vector,
483  void *arg
484 )
485 {
486  bsp_interrupt_handler_entry *current = NULL;
487  rtems_option options = 0;
488  rtems_vector_number index = 0;
489 
490  /* Check parameters and system state */
491  if (!bsp_interrupt_is_initialized()) {
492  return RTEMS_INTERNAL_ERROR;
493  } else if (!bsp_interrupt_is_valid_vector(vector)) {
494  return RTEMS_INVALID_ID;
495  } else if (rtems_interrupt_is_in_progress()) {
496  return RTEMS_CALLED_FROM_ISR;
497  }
498 
499  /* Lock */
500  bsp_interrupt_lock();
501 
502  /* Interate */
503  index = bsp_interrupt_handler_index(vector);
504  current = &bsp_interrupt_handler_table [index];
505  if (!bsp_interrupt_is_empty_handler_entry(current)) {
506  do {
507  options = bsp_interrupt_is_handler_unique(index) ?
509  routine(arg, current->info, options, current->handler, current->arg);
510  current = current->next;
511  } while (current != NULL);
512  }
513 
514  /* Unlock */
515  bsp_interrupt_unlock();
516 
517  return RTEMS_SUCCESSFUL;
518 }
519 
521  rtems_vector_number vector,
522  const char *info,
523  rtems_option options,
524  rtems_interrupt_handler handler,
525  void *arg
526 )
527 {
528  return bsp_interrupt_handler_install(vector, info, options, handler, arg);
529 }
530 
532  rtems_vector_number vector,
533  rtems_interrupt_handler handler,
534  void *arg
535 )
536 {
537  return bsp_interrupt_handler_remove(vector, handler, arg);
538 }
539 
541  rtems_vector_number vector,
543  void *arg
544 )
545 {
546  return bsp_interrupt_handler_iterate(vector, routine, arg);
547 }
548 
550 {
551  rtems_vector_number index = 0;
552  bsp_interrupt_handler_entry *head = NULL;
553  bool empty;
554 
555  /* For use in interrupts so no lock. */
556 
557  /* Get handler table index */
558  index = bsp_interrupt_handler_index(vector);
559 
560  /* Get head entry of the handler list for the vector */
561  head = &bsp_interrupt_handler_table [index];
562 
563  empty = bsp_interrupt_is_empty_handler_entry(head);
564 
565  return empty;
566 }
567 
569  rtems_vector_number vector,
570  size_t affinity_size,
571  const cpu_set_t *affinity
572 )
573 {
574  Processor_mask set;
575  Processor_mask_Copy_status status;
576 
577  if (!bsp_interrupt_is_valid_vector(vector)) {
578  return RTEMS_INVALID_ID;
579  }
580 
581  status = _Processor_mask_From_cpu_set_t(&set, affinity_size, affinity);
582  if (status != PROCESSOR_MASK_COPY_LOSSLESS) {
583  return RTEMS_INVALID_SIZE;
584  }
585 
586 #if defined(RTEMS_SMP)
587  bsp_interrupt_set_affinity(vector, &set);
588 #endif
589  return RTEMS_SUCCESSFUL;
590 }
591 
593  rtems_vector_number vector,
594  size_t affinity_size,
595  cpu_set_t *affinity
596 )
597 {
598  Processor_mask set;
599  Processor_mask_Copy_status status;
600 
601  if (!bsp_interrupt_is_valid_vector(vector)) {
602  return RTEMS_INVALID_ID;
603  }
604 
605 #if defined(RTEMS_SMP)
606  bsp_interrupt_get_affinity(vector, &set);
607 #else
609 #endif
610 
611  status = _Processor_mask_To_cpu_set_t(&set, affinity_size, affinity);
612  if (status != PROCESSOR_MASK_COPY_LOSSLESS) {
613  return RTEMS_INVALID_SIZE;
614  }
615 
616  return RTEMS_SUCCESSFUL;
617 }
This status code indicates you have attempted to create too many instances of a particular object cla...
Definition: status.h:112
RTEMS_INLINE_ROUTINE Processor_mask_Copy_status _Processor_mask_From_cpu_set_t(Processor_mask *dst, size_t src_size, const cpu_set_t *src)
Copies one mask to another.
Generic BSP interrupt support API.
Definition: irq-generic.h:77
void * rtems_malloc(size_t size) RTEMS_MALLOCLIKE RTEMS_ALLOC_SIZE(1) RTEMS_WARN_UNUSED_RESULT
Allocates a memory area of the specified size from the heap.
uint32_t rtems_option
This type is used to represent an option set.
Definition: options.h:121
#define RTEMS_INTERRUPT_SHARED
Allows that this interrupt handler may share a common interrupt vector with other handler...
Definition: irq-extension.h:50
static rtems_status_code bsp_interrupt_handler_remove(rtems_vector_number vector, rtems_interrupt_handler handler, void *arg)
Removes an interrupt handler.
Definition: irq-generic.c:358
This status code indicates that the object still had resources in use.
Definition: status.h:149
This status code indicates that the request was not satisfied.
Definition: status.h:154
RTEMS_INLINE_ROUTINE Processor_mask_Copy_status _Processor_mask_To_cpu_set_t(const Processor_mask *src, size_t dst_size, cpu_set_t *dst)
Copies one mask to another.
rtems_status_code rtems_interrupt_handler_remove(rtems_vector_number vector, rtems_interrupt_handler handler, void *arg)
Removes the interrupt handler routine handler with argument arg for the interrupt vector with number ...
Definition: irq-generic.c:531
#define rtems_interrupt_is_in_progress()
%
Definition: intr.h:193
void bsp_interrupt_vector_disable(rtems_vector_number vector)
Disables the interrupt vector with number vector.
Definition: irq-shared.c:74
bool bsp_interrupt_handler_is_empty(rtems_vector_number vector)
Is interrupt handler empty.
Definition: irq-generic.c:549
rtems_status_code rtems_interrupt_handler_install(rtems_vector_number vector, const char *info, rtems_option options, rtems_interrupt_handler handler, void *arg)
Installs the interrupt handler routine handler for the interrupt vector with number vector...
Definition: irq-generic.c:520
static rtems_status_code bsp_interrupt_handler_install(rtems_vector_number vector, const char *info, rtems_option options, rtems_interrupt_handler handler, void *arg)
Installs an interrupt handler.
Definition: irq-generic.c:193
This status code indicates successful completion.
Definition: status.h:86
ISR_Level rtems_interrupt_level
%
Definition: intr.h:211
rtems_status_code rtems_interrupt_get_affinity(rtems_vector_number vector, size_t affinity_size, cpu_set_t *affinity)
Gets the processor affinity set of an interrupt vector.
Definition: irq-generic.c:592
rtems_status_code
This enumeration provides status codes for directives of the Classic API.
Definition: status.h:82
#define RTEMS_INTERRUPT_IS_REPLACE(options)
Returns true if the interrupt handler replace option is set.
Definition: irq-extension.h:73
#define RTEMS_INTERRUPT_UNIQUE
Makes the interrupt handler unique. Prevents other handler from using the same interrupt vector...
Definition: irq-extension.h:44
void bsp_interrupt_handler_default(rtems_vector_number vector)
Default interrupt handler.
RTEMS_INLINE_ROUTINE void _Processor_mask_From_index(Processor_mask *mask, uint32_t index)
Creates a processor set from the specified index.
This status code indicates that a specified address was invalid.
Definition: status.h:133
static bool bsp_interrupt_is_valid_vector(rtems_vector_number vector)
Returns true if the interrupt vector with number vector is valid.
Definition: irq-generic.h:167
void(* rtems_interrupt_per_handler_routine)(void *, const char *, rtems_option, rtems_interrupt_handler, void *)
Interrupt handler iteration routine type.
This status code indicates that the operation should not be called from this execution environment...
Definition: status.h:183
This status code indicates that an object identifier was invalid.
Definition: status.h:106
static rtems_status_code bsp_interrupt_handler_iterate(rtems_vector_number vector, rtems_interrupt_per_handler_routine routine, void *arg)
Iterates over all installed interrupt handler of a vector.
Definition: irq-generic.c:480
void(* rtems_interrupt_handler)(void *)
Interrupt handler routine type.
Definition: irq-extension.h:79
Processor Mask API.
This status code indicates that the directive attempted to allocate memory but was unable to do so...
Definition: status.h:232
void bsp_interrupt_initialize(void)
Initialize BSP interrupt support.
Definition: irq-generic.c:161
This status code indicates that an internal RTEMS inconsistency was detected.
Definition: status.h:226
rtems_status_code rtems_interrupt_set_affinity(rtems_vector_number vector, size_t affinity_size, const cpu_set_t *affinity)
Sets the processor affinity set of an interrupt vector.
Definition: irq-generic.c:568
ISR_Vector_number rtems_vector_number
%
Definition: intr.h:90
rtems_status_code bsp_interrupt_facility_initialize(void)
BSP specific initialization.
Definition: irq-shared.c:62
rtems_status_code rtems_interrupt_handler_iterate(rtems_vector_number vector, rtems_interrupt_per_handler_routine routine, void *arg)
Iterates over all installed interrupt handler of the interrupt vector with number vector...
Definition: irq-generic.c:540
void bsp_interrupt_vector_enable(rtems_vector_number vector)
Enables the interrupt vector with number vector.
Definition: irq-shared.c:67
#define RTEMS_INTERRUPT_IS_UNIQUE(options)
Returns true if the interrupt handler unique option is set.
Definition: irq-extension.h:61
This status code indicates that a specified size was invalid.
Definition: status.h:128