LCOV - code coverage report
Current view: top level - home/runner/zephyrproject/zephyr/boards/native/native_posix - irq_handler.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 20 72 27.8 %
Date: 2024-09-16 20:15:30 Functions: 6 14 42.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 1 20 5.0 %

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

Generated by: LCOV version 1.14