LCOV - code coverage report
Current view: top level - zephyr - irq_multilevel.h Hit Total Coverage
Test: new.info Lines: 15 16 93.8 %
Date: 2024-12-22 00:14:23

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

Generated by: LCOV version 1.14