LCOV - code coverage report
Current view: top level - /home/runner/zephyrproject/zephyr/boards/native/native_sim - irq_handler.c (source / functions) Coverage Total Hit
Test: lcov.info Lines: 26.0 % 77 20
Test Date: 2026-01-27 12:19:34 Functions: 42.9 % 14 6
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 8.3 % 24 2

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * Copyright (c) 2014 Wind River Systems, Inc.
       3                 :             :  * Copyright (c) 2017 Oticon A/S
       4                 :             :  * Copyright (c) 2023 Nordic Semiconductor ASA
       5                 :             :  *
       6                 :             :  * SPDX-License-Identifier: Apache-2.0
       7                 :             :  *
       8                 :             :  * SW side of the IRQ handling
       9                 :             :  */
      10                 :             : 
      11                 :             : #include <stdint.h>
      12                 :             : #include <zephyr/irq_offload.h>
      13                 :             : #include <zephyr/kernel_structs.h>
      14                 :             : #include "kernel_internal.h"
      15                 :             : #include "kswap.h"
      16                 :             : #include "irq_ctrl.h"
      17                 :             : #include "posix_core.h"
      18                 :             : #include <zephyr/sw_isr_table.h>
      19                 :             : #include "soc.h"
      20                 :             : #include <zephyr/tracing/tracing.h>
      21                 :             : #include "irq_handler.h"
      22                 :             : #include "board_soc.h"
      23                 :             : #include "nsi_cpu_if.h"
      24                 :             : 
      25                 :             : typedef void (*normal_irq_f_ptr)(const void *);
      26                 :             : typedef int (*direct_irq_f_ptr)(void);
      27                 :             : 
      28                 :             : static struct _isr_list irq_vector_table[N_IRQS] = { { 0 } };
      29                 :             : 
      30                 :             : static int currently_running_irq = -1;
      31                 :             : 
      32                 :           0 : static inline void vector_to_irq(int irq_nbr, int *may_swap)
      33                 :             : {
      34                 :           0 :         sys_trace_isr_enter();
      35                 :             : 
      36                 :           0 :         if (irq_vector_table[irq_nbr].func == NULL) { /* LCOV_EXCL_BR_LINE */
      37                 :             :                 /* LCOV_EXCL_START */
      38                 :             :                 posix_print_error_and_exit("Received irq %i without a "
      39                 :             :                                         "registered handler\n",
      40                 :             :                                         irq_nbr);
      41                 :             :                 /* LCOV_EXCL_STOP */
      42                 :             :         } else {
      43         [ #  # ]:           0 :                 if (irq_vector_table[irq_nbr].flags & ISR_FLAG_DIRECT) {
      44                 :           0 :                         *may_swap |= ((direct_irq_f_ptr)
      45                 :             :                                         irq_vector_table[irq_nbr].func)();
      46                 :             :                 } else {
      47                 :             : #ifdef CONFIG_PM
      48                 :             :                         posix_irq_check_idle_exit();
      49                 :             : #endif
      50                 :           0 :                         ((normal_irq_f_ptr)irq_vector_table[irq_nbr].func)
      51                 :             :                                         (irq_vector_table[irq_nbr].param);
      52                 :           0 :                         *may_swap = 1;
      53                 :             :                 }
      54                 :             :         }
      55                 :             : 
      56                 :           0 :         sys_trace_isr_exit();
      57                 :           0 : }
      58                 :             : 
      59                 :             : /**
      60                 :             :  * When an interrupt is raised, this function is called to handle it and, if
      61                 :             :  * needed, swap to a re-enabled thread
      62                 :             :  *
      63                 :             :  * Note that even that this function is executing in a Zephyr thread,  it is
      64                 :             :  * effectively the model of the interrupt controller passing context to the IRQ
      65                 :             :  * handler and therefore its priority handling
      66                 :             :  */
      67                 :           0 : void posix_irq_handler(void)
      68                 :             : {
      69                 :           0 :         uint64_t irq_lock;
      70                 :           0 :         int irq_nbr;
      71                 :           0 :         static int may_swap;
      72                 :             : 
      73                 :           0 :         irq_lock = hw_irq_ctrl_get_current_lock();
      74                 :             : 
      75         [ #  # ]:           0 :         if (irq_lock) {
      76                 :             :                 /* "spurious" wakes can happen with interrupts locked */
      77                 :             :                 return;
      78                 :             :         }
      79                 :             : 
      80                 :           0 :         irq_nbr = hw_irq_ctrl_get_highest_prio_irq();
      81                 :             : 
      82         [ #  # ]:           0 :         if (irq_nbr == -1) {
      83                 :             :                 /* This is a phony interrupt during a busy wait, no need for more */
      84                 :             :                 return;
      85                 :             :         }
      86                 :             : 
      87         [ #  # ]:           0 :         if (_kernel.cpus[0].nested == 0) {
      88                 :           0 :                 may_swap = 0;
      89                 :             :         }
      90                 :             : 
      91                 :           0 :         _kernel.cpus[0].nested++;
      92                 :             : 
      93                 :           0 :         do {
      94                 :           0 :                 int last_current_running_prio = hw_irq_ctrl_get_cur_prio();
      95                 :           0 :                 int last_running_irq = currently_running_irq;
      96                 :             : 
      97                 :           0 :                 hw_irq_ctrl_set_cur_prio(hw_irq_ctrl_get_prio(irq_nbr));
      98                 :           0 :                 hw_irq_ctrl_clear_irq(irq_nbr);
      99                 :             : 
     100                 :           0 :                 currently_running_irq = irq_nbr;
     101                 :           0 :                 vector_to_irq(irq_nbr, &may_swap);
     102                 :           0 :                 currently_running_irq = last_running_irq;
     103                 :             : 
     104                 :           0 :                 hw_irq_ctrl_set_cur_prio(last_current_running_prio);
     105         [ #  # ]:           0 :         } while ((irq_nbr = hw_irq_ctrl_get_highest_prio_irq()) != -1);
     106                 :             : 
     107                 :           0 :         _kernel.cpus[0].nested--;
     108                 :             : 
     109                 :             :         /* Call swap if all the following is true:
     110                 :             :          * 1) may_swap was enabled
     111                 :             :          * 2) We are not nesting irq_handler calls (interrupts)
     112                 :             :          * 3) Next thread to run in the ready queue is not this thread
     113                 :             :          */
     114         [ #  # ]:           0 :         if (may_swap
     115         [ #  # ]:           0 :                 && (hw_irq_ctrl_get_cur_prio() == 256)
     116   [ #  #  #  # ]:           0 :                 && (_kernel.ready_q.cache) && (_kernel.ready_q.cache != _current)) {
     117                 :             : 
     118                 :           0 :                 (void)z_swap_irqlock(irq_lock);
     119                 :             :         }
     120                 :             : }
     121                 :             : 
     122                 :             : /**
     123                 :             :  * Thru this function the IRQ controller can raise an immediate interrupt which
     124                 :             :  * will interrupt the SW itself
     125                 :             :  * (this function should only be called from the HW model code, from SW threads)
     126                 :             :  */
     127                 :           0 : void nsif_cpu0_irq_raised_from_sw(void)
     128                 :             : {
     129                 :             :         /*
     130                 :             :          * if a higher priority interrupt than the possibly currently running is
     131                 :             :          * pending we go immediately into irq_handler() to vector into its
     132                 :             :          * handler
     133                 :             :          */
     134         [ #  # ]:           0 :         if (hw_irq_ctrl_get_highest_prio_irq() != -1) {
     135                 :           0 :                 if (!posix_is_cpu_running()) { /* LCOV_EXCL_BR_LINE */
     136                 :             :                         /* LCOV_EXCL_START */
     137                 :             :                         posix_print_error_and_exit("programming error: %s "
     138                 :             :                                         "called from a HW model thread\n",
     139                 :             :                                         __func__);
     140                 :             :                         /* LCOV_EXCL_STOP */
     141                 :             :                 }
     142                 :           0 :                 posix_irq_handler();
     143                 :             :         }
     144                 :           0 : }
     145                 :             : 
     146                 :             : /**
     147                 :             :  * @brief Disable all interrupts on the CPU
     148                 :             :  *
     149                 :             :  * This routine disables interrupts.  It can be called from either interrupt,
     150                 :             :  * task or fiber level.  This routine returns an architecture-dependent
     151                 :             :  * lock-out key representing the "interrupt disable state" prior to the call;
     152                 :             :  * this key can be passed to irq_unlock() to re-enable interrupts.
     153                 :             :  *
     154                 :             :  * The lock-out key should only be used as the argument to the irq_unlock()
     155                 :             :  * API. It should never be used to manually re-enable interrupts or to inspect
     156                 :             :  * or manipulate the contents of the source register.
     157                 :             :  *
     158                 :             :  * This function can be called recursively: it will return a key to return the
     159                 :             :  * state of interrupt locking to the previous level.
     160                 :             :  *
     161                 :             :  * WARNINGS
     162                 :             :  * Invoking a kernel routine with interrupts locked may result in
     163                 :             :  * interrupts being re-enabled for an unspecified period of time.  If the
     164                 :             :  * called routine blocks, interrupts will be re-enabled while another
     165                 :             :  * thread executes, or while the system is idle.
     166                 :             :  *
     167                 :             :  * The "interrupt disable state" is an attribute of a thread.  Thus, if a
     168                 :             :  * fiber or task disables interrupts and subsequently invokes a kernel
     169                 :             :  * routine that causes the calling thread to block, the interrupt
     170                 :             :  * disable state will be restored when the thread is later rescheduled
     171                 :             :  * for execution.
     172                 :             :  *
     173                 :             :  * @return An architecture-dependent lock-out key representing the
     174                 :             :  * "interrupt disable state" prior to the call.
     175                 :             :  *
     176                 :             :  */
     177                 :         606 : unsigned int posix_irq_lock(void)
     178                 :             : {
     179                 :         606 :         return hw_irq_ctrl_change_lock(true);
     180                 :             : }
     181                 :             : 
     182                 :             : /**
     183                 :             :  * @brief Enable all interrupts on the CPU
     184                 :             :  *
     185                 :             :  * This routine re-enables interrupts on the CPU.  The @a key parameter is a
     186                 :             :  * board-dependent lock-out key that is returned by a previous invocation of
     187                 :             :  * board_irq_lock().
     188                 :             :  *
     189                 :             :  * This routine can be called from either interrupt, task or fiber level.
     190                 :             :  */
     191                 :         510 : void posix_irq_unlock(unsigned int key)
     192                 :             : {
     193                 :         510 :         hw_irq_ctrl_change_lock(key);
     194                 :         510 : }
     195                 :             : 
     196                 :          47 : void posix_irq_full_unlock(void)
     197                 :             : {
     198                 :          47 :         hw_irq_ctrl_change_lock(false);
     199                 :          47 : }
     200                 :             : 
     201                 :           1 : void posix_irq_enable(unsigned int irq)
     202                 :             : {
     203                 :           1 :         hw_irq_ctrl_enable_irq(irq);
     204                 :           1 : }
     205                 :             : 
     206                 :           0 : void posix_irq_disable(unsigned int irq)
     207                 :             : {
     208                 :           0 :         hw_irq_ctrl_disable_irq(irq);
     209                 :           0 : }
     210                 :             : 
     211                 :           0 : int posix_irq_is_enabled(unsigned int irq)
     212                 :             : {
     213                 :           0 :         return hw_irq_ctrl_is_irq_enabled(irq);
     214                 :             : }
     215                 :             : 
     216                 :           0 : int posix_get_current_irq(void)
     217                 :             : {
     218                 :           0 :         return currently_running_irq;
     219                 :             : }
     220                 :             : 
     221                 :             : /**
     222                 :             :  * Configure a static interrupt.
     223                 :             :  *
     224                 :             :  * posix_isr_declare will populate the interrupt table table with the
     225                 :             :  * interrupt's parameters, the vector table and the software ISR table.
     226                 :             :  *
     227                 :             :  * We additionally set the priority in the interrupt controller at
     228                 :             :  * runtime.
     229                 :             :  *
     230                 :             :  * @param irq_p IRQ line number
     231                 :             :  * @param flags [plug it directly (1), or as a SW managed interrupt (0)]
     232                 :             :  * @param isr_p Interrupt service routine
     233                 :             :  * @param isr_param_p ISR parameter
     234                 :             :  * @param flags_p IRQ options
     235                 :             :  */
     236                 :           1 : void posix_isr_declare(unsigned int irq_p, int flags, void isr_p(const void *),
     237                 :             :                        const void *isr_param_p)
     238                 :             : {
     239         [ -  + ]:           1 :         if (irq_p >= N_IRQS) {
     240                 :           0 :                 posix_print_error_and_exit("Attempted to configure not existent interrupt %u\n",
     241                 :             :                                            irq_p);
     242                 :           0 :                 return;
     243                 :             :         }
     244                 :           1 :         irq_vector_table[irq_p].irq   = irq_p;
     245                 :           1 :         irq_vector_table[irq_p].func  = isr_p;
     246                 :           1 :         irq_vector_table[irq_p].param = isr_param_p;
     247                 :           1 :         irq_vector_table[irq_p].flags = flags;
     248                 :             : }
     249                 :             : 
     250                 :             : /**
     251                 :             :  * @internal
     252                 :             :  *
     253                 :             :  * @brief Set an interrupt's priority
     254                 :             :  *
     255                 :             :  * Lower values take priority over higher values.
     256                 :             :  */
     257                 :           1 : void posix_irq_priority_set(unsigned int irq, unsigned int prio, uint32_t flags)
     258                 :             : {
     259         [ -  + ]:           1 :         if (irq >= N_IRQS) {
     260                 :           0 :                 posix_print_error_and_exit("Attempted to configure not existent interrupt %u\n",
     261                 :             :                                            irq);
     262                 :           0 :                 return;
     263                 :             :         }
     264                 :           1 :         hw_irq_ctrl_prio_set(irq, prio);
     265                 :             : }
     266                 :             : 
     267                 :             : /**
     268                 :             :  * Similar to ARM's NVIC_SetPendingIRQ
     269                 :             :  * set a pending IRQ from SW
     270                 :             :  *
     271                 :             :  * Note that this will interrupt immediately if the interrupt is not masked and
     272                 :             :  * IRQs are not locked, and this interrupt has higher priority than a possibly
     273                 :             :  * currently running interrupt
     274                 :             :  */
     275                 :           0 : void posix_sw_set_pending_IRQ(unsigned int IRQn)
     276                 :             : {
     277                 :           0 :         hw_irq_ctrl_raise_im_from_sw(IRQn);
     278                 :           0 : }
     279                 :             : 
     280                 :             : /**
     281                 :             :  * Similar to ARM's NVIC_ClearPendingIRQ
     282                 :             :  * clear a pending irq from SW
     283                 :             :  */
     284                 :           0 : void posix_sw_clear_pending_IRQ(unsigned int IRQn)
     285                 :             : {
     286                 :           0 :         hw_irq_ctrl_clear_irq(IRQn);
     287                 :           0 : }
     288                 :             : 
     289                 :             : #ifdef CONFIG_IRQ_OFFLOAD
     290                 :             : /**
     291                 :             :  * Storage for functions offloaded to IRQ
     292                 :             :  */
     293                 :             : static void (*off_routine)(const void *);
     294                 :             : static const void *off_parameter;
     295                 :             : 
     296                 :             : /**
     297                 :             :  * IRQ handler for the SW interrupt assigned to irq_offload()
     298                 :             :  */
     299                 :             : static void offload_sw_irq_handler(const void *a)
     300                 :             : {
     301                 :             :         ARG_UNUSED(a);
     302                 :             :         off_routine(off_parameter);
     303                 :             : }
     304                 :             : 
     305                 :             : /**
     306                 :             :  * @brief Run a function in interrupt context
     307                 :             :  *
     308                 :             :  * Raise the SW IRQ assigned to handled this
     309                 :             :  */
     310                 :             : void posix_irq_offload(void (*routine)(const void *), const void *parameter)
     311                 :             : {
     312                 :             :         off_routine = routine;
     313                 :             :         off_parameter = parameter;
     314                 :             :         posix_isr_declare(OFFLOAD_SW_IRQ, 0, offload_sw_irq_handler, NULL);
     315                 :             :         posix_irq_enable(OFFLOAD_SW_IRQ);
     316                 :             :         posix_sw_set_pending_IRQ(OFFLOAD_SW_IRQ);
     317                 :             :         posix_irq_disable(OFFLOAD_SW_IRQ);
     318                 :             : }
     319                 :             : #endif /* CONFIG_IRQ_OFFLOAD */
        

Generated by: LCOV version 2.0-1