1  /*******************************************************************************
2  Copyright (c) 2006-2019 Cadence Design Systems Inc.
3  
4  Permission is hereby granted, free of charge, to any person obtaining
5  a copy of this software and associated documentation files (the
6  "Software"), to deal in the Software without restriction, including
7  without limitation the rights to use, copy, modify, merge, publish,
8  distribute, sublicense, and/or sell copies of the Software, and to
9  permit persons to whom the Software is furnished to do so, subject to
10  the following conditions:
11  
12  The above copyright notice and this permission notice shall be included
13  in all copies or substantial portions of the Software.
14  
15  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  ******************************************************************************/
23  
24  /******************************************************************************
25    Xtensa-specific interrupt and exception functions for RTOS ports.
26    Also see xtensa_intr_asm.S.
27  ******************************************************************************/
28  
29  #include <stdlib.h>
30  
31  #include <xtensa/config/core.h>
32  #include <xtensa/core-macros.h>
33  
34  #include "xtensa_api.h"
35  
36  
37  #if XCHAL_HAVE_EXCEPTIONS
38  
39  /* Handler table is in xtensa_intr_asm.S */
40  
41  extern xt_exc_handler _xt_exception_table[XCHAL_EXCCAUSE_NUM];
42  
43  
44  /*
45    Default handler for unhandled exceptions.
46  */
xt_unhandled_exception(XtExcFrame * frame)47  void xt_unhandled_exception(XtExcFrame *frame)
48  {
49      (void) frame; /* Keep compiler happy */
50      exit(-1);
51  }
52  
53  
54  /*
55    This function registers a handler for the specified exception.
56    The function returns the address of the previous handler.
57    On error, it returns 0.
58  */
xt_set_exception_handler(uint32_t n,xt_exc_handler f)59  xt_exc_handler xt_set_exception_handler(uint32_t n, xt_exc_handler f)
60  {
61      xt_exc_handler old;
62  
63      if (n >= XCHAL_EXCCAUSE_NUM) {
64          return 0;       /* invalid exception number */
65      }
66  
67      old = _xt_exception_table[n];
68  
69      if (f != NULL) {
70          _xt_exception_table[n] = f;
71      }
72      else {
73          _xt_exception_table[n] = &xt_unhandled_exception;
74      }
75  
76      return old;
77  }
78  
79  #endif
80  
81  #if XCHAL_HAVE_INTERRUPTS
82  
83  #if XCHAL_HAVE_XEA2
84  /* Defined in xtensa_intr_asm.S */
85  extern uint32_t _xt_intenable;
86  extern uint32_t _xt_vpri_mask;
87  #endif
88  
89  /* Handler table is in xtensa_intr_asm.S */
90  
91  typedef struct xt_handler_table_entry {
92      void * handler;
93      void * arg;
94  } xt_handler_table_entry;
95  
96  #if (XT_USE_INT_WRAPPER || XCHAL_HAVE_XEA3)
97  extern xt_handler_table_entry _xt_interrupt_table[XCHAL_NUM_INTERRUPTS + 1];
98  #else
99  extern xt_handler_table_entry _xt_interrupt_table[XCHAL_NUM_INTERRUPTS];
100  #endif
101  
102  
103  /*
104    Default handler for unhandled interrupts.
105  */
xt_unhandled_interrupt(void * arg)106  void xt_unhandled_interrupt(void * arg)
107  {
108      (void) arg; /* Keep compiler happy */
109      exit(-1);
110  }
111  
112  
113  /*
114    This function registers a handler for the specified interrupt. The "arg"
115    parameter specifies the argument to be passed to the handler when it is
116    invoked. The function returns the address of the previous handler.
117    On error, it returns 0.
118  */
xt_set_interrupt_handler(uint32_t n,xt_handler f,void * arg)119  xt_handler xt_set_interrupt_handler(uint32_t n, xt_handler f, void * arg)
120  {
121      xt_handler_table_entry * entry;
122      xt_handler               old;
123  
124      if (n >= XCHAL_NUM_INTERRUPTS) {
125          return 0;       /* invalid interrupt number */
126      }
127  
128  #if XCHAL_HAVE_XEA2
129      if (Xthal_intlevel[n] > XCHAL_EXCM_LEVEL) {
130          return 0;       /* priority level too high to safely handle in C */
131      }
132  #endif
133  
134  #if (XT_USE_INT_WRAPPER || XCHAL_HAVE_XEA3)
135      entry = _xt_interrupt_table + n + 1;
136  #else
137      entry = _xt_interrupt_table + n;
138  #endif
139      old   = entry->handler;
140  
141      if (f != NULL) {
142          entry->handler = f;
143          entry->arg     = arg;
144      }
145      else {
146          entry->handler = &xt_unhandled_interrupt;
147          entry->arg     = (void*)n;
148      }
149  
150      return old;
151  }
152  
153  
154  /*
155    This function enables the interrupt whose number is specified as
156    the argument.
157  */
xt_interrupt_enable(uint32_t intnum)158  void xt_interrupt_enable(uint32_t intnum)
159  {
160  #if XCHAL_HAVE_XEA2
161      uint32_t ps = XT_RSIL(15);
162  
163      // New INTENABLE = (_xt_intenable | mask) & _xt_vpri_mask.
164      _xt_intenable |= (1 << intnum);
165      XT_WSR_INTENABLE(_xt_intenable & _xt_vpri_mask);
166      XT_WSR_PS(ps);
167      XT_RSYNC();
168  #else
169      xthal_interrupt_enable(intnum);
170  #endif
171  }
172  
173  
174  /*
175    This function disables the interrupt whose number is specified as
176    the argument.
177  */
xt_interrupt_disable(uint32_t intnum)178  void xt_interrupt_disable(uint32_t intnum)
179  {
180  #if XCHAL_HAVE_XEA2
181      uint32_t ps = XT_RSIL(15);
182  
183      // New INTENABLE = (_xt_intenable & ~mask) & _xt_vpri_mask.
184      _xt_intenable &= ~(1 << intnum);
185      XT_WSR_INTENABLE(_xt_intenable & _xt_vpri_mask);
186      XT_WSR_PS(ps);
187      XT_RSYNC();
188  #else
189      xthal_interrupt_disable(intnum);
190  #endif
191  }
192  
193  
194  /*
195    This function triggers the specified interrupt.
196  */
xt_interrupt_trigger(uint32_t intnum)197  void xt_interrupt_trigger(uint32_t intnum)
198  {
199      xthal_interrupt_trigger(intnum);
200  }
201  
202  
203  /*
204    This function clears the specified interrupt.
205  */
xt_interrupt_clear(uint32_t intnum)206  void xt_interrupt_clear(uint32_t intnum)
207  {
208      xthal_interrupt_clear(intnum);
209  }
210  
211  
212  #endif /* XCHAL_HAVE_INTERRUPTS */
213  
214