LCOV - code coverage report
Current view: top level - zephyr - irq_multilevel.h Coverage Total Hit
Test: new.info Lines: 93.8 % 16 15
Test Date: 2025-09-05 16:43:28

            Line data    Source code
       1            1 : /*
       2              :  * Copyright (c) 2023 Meta
       3              :  *
       4              :  * SPDX-License-Identifier: Apache-2.0
       5              :  */
       6              : 
       7              : /**
       8              :  * @file
       9              :  * @brief Public interface for multi-level interrupts
      10              :  */
      11              : #ifndef ZEPHYR_INCLUDE_IRQ_MULTILEVEL_H_
      12              : #define ZEPHYR_INCLUDE_IRQ_MULTILEVEL_H_
      13              : 
      14              : #ifndef _ASMLANGUAGE
      15              : #include <zephyr/sys/__assert.h>
      16              : #include <zephyr/sys/util_macro.h>
      17              : #include <zephyr/types.h>
      18              : 
      19              : #ifdef __cplusplus
      20              : extern "C" {
      21              : #endif
      22              : 
      23              : #if defined(CONFIG_MULTI_LEVEL_INTERRUPTS) || defined(__DOXYGEN__)
      24              : 
      25              : typedef union _z_irq {
      26              :         /* Zephyr multilevel-encoded IRQ */
      27              :         uint32_t irq;
      28              : 
      29              :         /* Interrupt bits */
      30              :         struct {
      31              :                 /* First level interrupt bits */
      32              :                 uint32_t l1: CONFIG_1ST_LEVEL_INTERRUPT_BITS;
      33              :                 /* Second level interrupt bits */
      34              :                 uint32_t l2: CONFIG_2ND_LEVEL_INTERRUPT_BITS;
      35              : #if defined(CONFIG_3RD_LEVEL_INTERRUPTS) || defined(__DOXYGEN__)
      36              :                 /* Third level interrupt bits */
      37              :                 uint32_t l3: CONFIG_3RD_LEVEL_INTERRUPT_BITS;
      38              : #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
      39              :         } bits;
      40              : 
      41              : #if defined(CONFIG_3RD_LEVEL_INTERRUPTS) || defined(__DOXYGEN__)
      42              :         /* Third level IRQ's interrupt controller */
      43              :         struct {
      44              :                 /* IRQ of the third level interrupt aggregator */
      45              :                 uint32_t irq: CONFIG_1ST_LEVEL_INTERRUPT_BITS + CONFIG_2ND_LEVEL_INTERRUPT_BITS;
      46              :         } l3_intc;
      47              : #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
      48              : 
      49              :         /* Second level IRQ's interrupt controller */
      50              :         struct {
      51              :                 /* IRQ of the second level interrupt aggregator */
      52              :                 uint32_t irq: CONFIG_1ST_LEVEL_INTERRUPT_BITS;
      53              :         } l2_intc;
      54              : } _z_irq_t;
      55              : 
      56            0 : BUILD_ASSERT(sizeof(_z_irq_t) == sizeof(uint32_t), "Size of `_z_irq_t` must equal to `uint32_t`");
      57              : 
      58              : static inline uint32_t _z_l1_irq(_z_irq_t irq)
      59              : {
      60              :         return irq.bits.l1;
      61              : }
      62              : 
      63              : static inline uint32_t _z_l2_irq(_z_irq_t irq)
      64              : {
      65              :         return irq.bits.l2 - 1;
      66              : }
      67              : 
      68              : #ifdef CONFIG_3RD_LEVEL_INTERRUPTS
      69              : static inline uint32_t _z_l3_irq(_z_irq_t irq)
      70              : {
      71              :         return irq.bits.l3 - 1;
      72              : }
      73              : #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
      74              : 
      75              : static inline unsigned int _z_irq_get_level(_z_irq_t z_irq)
      76              : {
      77              : #ifdef CONFIG_3RD_LEVEL_INTERRUPTS
      78              :         if (z_irq.bits.l3 != 0) {
      79              :                 return 3;
      80              :         }
      81              : #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
      82              : 
      83              :         if (z_irq.bits.l2 != 0) {
      84              :                 return 2;
      85              :         }
      86              : 
      87              :         return 1;
      88              : }
      89              : 
      90              : /**
      91              :  * @brief Return IRQ level
      92              :  * This routine returns the interrupt level number of the provided interrupt.
      93              :  *
      94              :  * @param irq IRQ number in its zephyr format
      95              :  *
      96              :  * @return 1 if IRQ level 1, 2 if IRQ level 2, 3 if IRQ level 3
      97              :  */
      98            1 : static inline unsigned int irq_get_level(unsigned int irq)
      99              : {
     100              :         _z_irq_t z_irq = {
     101              :                 .irq = irq,
     102              :         };
     103              : 
     104              :         return _z_irq_get_level(z_irq);
     105              : }
     106              : 
     107              : /**
     108              :  * @brief Return the 2nd level interrupt number
     109              :  *
     110              :  * This routine returns the second level irq number of the zephyr irq
     111              :  * number passed in
     112              :  *
     113              :  * @param irq IRQ number in its zephyr format
     114              :  *
     115              :  * @return 2nd level IRQ number
     116              :  */
     117            1 : static inline unsigned int irq_from_level_2(unsigned int irq)
     118              : {
     119              :         _z_irq_t z_irq = {
     120              :                 .irq = irq,
     121              :         };
     122              : 
     123              :         return _z_l2_irq(z_irq);
     124              : }
     125              : 
     126              : /**
     127              :  * @brief Preprocessor macro to convert `irq` from level 1 to level 2 format
     128              :  *
     129              :  * @param irq IRQ number in its zephyr format
     130              :  *
     131              :  * @return 2nd level IRQ number
     132              :  */
     133            1 : #define IRQ_TO_L2(irq) ((irq + 1) << CONFIG_1ST_LEVEL_INTERRUPT_BITS)
     134              : 
     135              : /**
     136              :  * @brief Converts irq from level 1 to level 2 format
     137              :  *
     138              :  *
     139              :  * This routine converts the input into the level 2 irq number format
     140              :  *
     141              :  * @note Values >= 0xFF are invalid
     142              :  *
     143              :  * @param irq IRQ number in its zephyr format
     144              :  *
     145              :  * @return 2nd level IRQ number
     146              :  */
     147            1 : static inline unsigned int irq_to_level_2(unsigned int irq)
     148              : {
     149              :         _z_irq_t z_irq = {
     150              :                 .bits = {
     151              :                         .l1 = 0,
     152              :                         .l2 = irq + 1,
     153              : #ifdef CONFIG_3RD_LEVEL_INTERRUPTS
     154              :                         .l3 = 0,
     155              : #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
     156              :                 },
     157              :         };
     158              : 
     159              :         return z_irq.irq;
     160              : }
     161              : 
     162              : /**
     163              :  * @brief Returns the parent IRQ of the level 2 raw IRQ number
     164              :  *
     165              :  *
     166              :  * The parent of a 2nd level interrupt is in the 1st byte
     167              :  *
     168              :  * @param irq IRQ number in its zephyr format
     169              :  *
     170              :  * @return 2nd level IRQ parent
     171              :  */
     172            1 : static inline unsigned int irq_parent_level_2(unsigned int irq)
     173              : {
     174              :         _z_irq_t z_irq = {
     175              :                 .irq = irq,
     176              :         };
     177              : 
     178              :         return _z_l1_irq(z_irq);
     179              : }
     180              : 
     181              : #if defined(CONFIG_3RD_LEVEL_INTERRUPTS) || defined(__DOXYGEN__)
     182              : /**
     183              :  * @brief Return the 3rd level interrupt number
     184              :  *
     185              :  *
     186              :  * This routine returns the third level irq number of the zephyr irq
     187              :  * number passed in
     188              :  *
     189              :  * @param irq IRQ number in its zephyr format
     190              :  *
     191              :  * @return 3rd level IRQ number
     192              :  */
     193            1 : static inline unsigned int irq_from_level_3(unsigned int irq)
     194              : {
     195              :         _z_irq_t z_irq = {
     196              :                 .irq = irq,
     197              :         };
     198              : 
     199              :         return _z_l3_irq(z_irq);
     200              : }
     201              : 
     202              : /**
     203              :  * @brief Preprocessor macro to convert `irq` from level 1 to level 3 format
     204              :  *
     205              :  * @param irq IRQ number in its zephyr format
     206              :  *
     207              :  * @return 3rd level IRQ number
     208              :  */
     209            1 : #define IRQ_TO_L3(irq)                                                                             \
     210              :         ((irq + 1) << (CONFIG_1ST_LEVEL_INTERRUPT_BITS + CONFIG_2ND_LEVEL_INTERRUPT_BITS))
     211              : 
     212              : /**
     213              :  * @brief Converts irq from level 1 to level 3 format
     214              :  *
     215              :  *
     216              :  * This routine converts the input into the level 3 irq number format
     217              :  *
     218              :  * @note Values >= 0xFF are invalid
     219              :  *
     220              :  * @param irq IRQ number in its zephyr format
     221              :  *
     222              :  * @return 3rd level IRQ number
     223              :  */
     224            1 : static inline unsigned int irq_to_level_3(unsigned int irq)
     225              : {
     226              :         _z_irq_t z_irq = {
     227              :                 .bits = {
     228              :                         .l1 = 0,
     229              :                         .l2 = 0,
     230              :                         .l3 = irq + 1,
     231              :                 },
     232              :         };
     233              : 
     234              :         return z_irq.irq;
     235              : }
     236              : 
     237              : /**
     238              :  * @brief Returns the parent IRQ of the level 3 raw IRQ number
     239              :  *
     240              :  *
     241              :  * The parent of a 3rd level interrupt is in the 2nd byte
     242              :  *
     243              :  * @param irq IRQ number in its zephyr format
     244              :  *
     245              :  * @return 3rd level IRQ parent
     246              :  */
     247            1 : static inline unsigned int irq_parent_level_3(unsigned int irq)
     248              : {
     249              :         _z_irq_t z_irq = {
     250              :                 .irq = irq,
     251              :         };
     252              : 
     253              :         return _z_l2_irq(z_irq);
     254              : }
     255              : #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
     256              : 
     257              : /**
     258              :  * @brief Return the interrupt number for a given level
     259              :  *
     260              :  * @param irq IRQ number in its zephyr format
     261              :  * @param level IRQ level
     262              :  *
     263              :  * @return IRQ number in the level
     264              :  */
     265            1 : static inline unsigned int irq_from_level(unsigned int irq, unsigned int level)
     266              : {
     267              :         if (level == 1) {
     268              :                 return irq;
     269              :         } else if (level == 2) {
     270              :                 return irq_from_level_2(irq);
     271              :         }
     272              : #ifdef CONFIG_3RD_LEVEL_INTERRUPTS
     273              :         else if (level == 3) {
     274              :                 return irq_from_level_3(irq);
     275              :         }
     276              : #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
     277              : 
     278              :         /* level is higher than what's supported */
     279              :         __ASSERT_NO_MSG(false);
     280              :         return irq;
     281              : }
     282              : 
     283              : /**
     284              :  * @brief Converts irq from level 1 to a given level
     285              :  *
     286              :  * @param irq IRQ number in its zephyr format
     287              :  * @param level IRQ level
     288              :  *
     289              :  * @return Converted IRQ number in the level
     290              :  */
     291            1 : static inline unsigned int irq_to_level(unsigned int irq, unsigned int level)
     292              : {
     293              :         if (level == 1) {
     294              :                 return irq;
     295              :         } else if (level == 2) {
     296              :                 return irq_to_level_2(irq);
     297              :         }
     298              : #ifdef CONFIG_3RD_LEVEL_INTERRUPTS
     299              :         else if (level == 3) {
     300              :                 return irq_to_level_3(irq);
     301              :         }
     302              : #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
     303              : 
     304              :         /* level is higher than what's supported */
     305              :         __ASSERT_NO_MSG(false);
     306              :         return irq;
     307              : }
     308              : 
     309              : /**
     310              :  * @brief Returns the parent IRQ of the given level raw IRQ number
     311              :  *
     312              :  * @param irq IRQ number in its zephyr format
     313              :  * @param level IRQ level
     314              :  *
     315              :  * @return IRQ parent of the given level
     316              :  */
     317            1 : static inline unsigned int irq_parent_level(unsigned int irq, unsigned int level)
     318              : {
     319              :         if (level == 1) {
     320              :                 /* doesn't really make sense, but return anyway */
     321              :                 return irq;
     322              :         } else if (level == 2) {
     323              :                 return irq_parent_level_2(irq);
     324              :         }
     325              : #ifdef CONFIG_3RD_LEVEL_INTERRUPTS
     326              :         else if (level == 3) {
     327              :                 return irq_parent_level_3(irq);
     328              :         }
     329              : #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
     330              : 
     331              :         /* level is higher than what's supported */
     332              :         __ASSERT_NO_MSG(false);
     333              :         return irq;
     334              : }
     335              : 
     336              : /**
     337              :  * @brief Returns the parent interrupt controller IRQ of the given IRQ number
     338              :  *
     339              :  * @param irq IRQ number in its zephyr format
     340              :  *
     341              :  * @return IRQ of the interrupt controller
     342              :  */
     343            1 : static inline unsigned int irq_get_intc_irq(unsigned int irq)
     344              : {
     345              :         const unsigned int level = irq_get_level(irq);
     346              :         _z_irq_t z_irq = {
     347              :                 .irq = irq,
     348              :         };
     349              : 
     350              : #ifdef CONFIG_3RD_LEVEL_INTERRUPTS
     351              :         __ASSERT_NO_MSG(level <= 3);
     352              :         if (level == 3) {
     353              :                 return z_irq.l3_intc.irq;
     354              :         }
     355              : #else
     356              :         __ASSERT_NO_MSG(level <= 2);
     357              : #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
     358              : 
     359              :         if (level == 2) {
     360              :                 return z_irq.l2_intc.irq;
     361              :         }
     362              : 
     363              :         return irq;
     364              : }
     365              : 
     366              : /**
     367              :  * @brief Increments the multilevel-encoded @a irq by @a val
     368              :  *
     369              :  * @param irq IRQ number in its zephyr format
     370              :  * @param val Amount to increment
     371              :  *
     372              :  * @return @a irq incremented by @a val
     373              :  */
     374            1 : static inline unsigned int irq_increment(unsigned int irq, unsigned int val)
     375              : {
     376              :         _z_irq_t z_irq = {
     377              :                 .irq = irq,
     378              :         };
     379              : 
     380              :         if (false) {
     381              :                 /* so that it evaluates the next condition */
     382              : #ifdef CONFIG_3RD_LEVEL_INTERRUPTS
     383              :         } else if (z_irq.bits.l3 != 0) {
     384              :                 z_irq.bits.l3 += val;
     385              : #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
     386              :         } else if (z_irq.bits.l2 != 0) {
     387              :                 z_irq.bits.l2 += val;
     388              :         } else {
     389              :                 z_irq.bits.l1 += val;
     390              :         }
     391              : 
     392              :         return z_irq.irq;
     393              : }
     394              : 
     395              : #endif /* CONFIG_MULTI_LEVEL_INTERRUPTS */
     396              : #ifdef __cplusplus
     397              : }
     398              : #endif
     399              : 
     400              : #endif /* _ASMLANGUAGE */
     401              : #endif /* ZEPHYR_INCLUDE_IRQ_MULTILEVEL_H_ */
        

Generated by: LCOV version 2.0-1