1  /*
2  * Copyright (C) 2017-2024 Alibaba Group Holding Limited
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #include <stdint.h>
20 #include <soc.h>
21 #include <csi_core.h>
22 #include <csi_config.h>
23 #include <drv/common.h>
24 #if CONFIG_AOS_OSAL
25 #include <aos/kernel.h>
26 #endif
27 
28 extern void Default_Handler(void);
29 extern uint32_t soc_irq_get_irq_num(void);
30 extern void soc_irq_end(uint32_t irq_num);
31 
32 #if CONFIG_AOS_OSAL
33 #define CSI_INTRPT_ENTER() aos_kernel_intrpt_enter()
34 #define CSI_INTRPT_EXIT()  aos_kernel_intrpt_exit()
35 #else
36 #ifdef CONFIG_KERNEL_FREERTOS
37 extern int freertos_intrpt_enter(void);
38 extern int freertos_intrpt_exit(void);
39 #define CSI_INTRPT_ENTER() freertos_intrpt_enter()
40 #define CSI_INTRPT_EXIT()  freertos_intrpt_exit()
41 #elif defined(CONFIG_KERNEL_RTTHREAD)
42 extern void rt_interrupt_enter(void);
43 extern void rt_interrupt_leave(void);
44 #define CSI_INTRPT_ENTER() rt_interrupt_enter()
45 #define CSI_INTRPT_EXIT()  rt_interrupt_leave()
46 #else
47 #define CSI_INTRPT_ENTER()
48 #define CSI_INTRPT_EXIT()
49 #endif
50 #endif /* end CONFIG_AOS_OSAL */
51 
52 #if defined(CONFIG_SMP) && CONFIG_SMP
53 volatile uint32_t  g_irq_nested_level[CONFIG_NR_CPUS];
54 #else
55 volatile uint32_t  g_irq_nested_level;
56 #endif
57 csi_dev_t *g_irq_table[CONFIG_IRQ_NUM];
58 
59 /**
60   \brief       register irq handler(deprecated).
61   \param[in]   irq_num Number of IRQ.
62   \return      None.
63 */
csi_irq_attach(uint32_t irq_num,void * irq_handler,csi_dev_t * dev)64 void csi_irq_attach(uint32_t irq_num, void *irq_handler, csi_dev_t *dev)
65 {
66     dev->irq_handler = irq_handler;
67     g_irq_table[irq_num] = dev;
68 }
69 
70 /**
71   \brief       Attach irq handler2 for compatible(Recommended).
72   \param[in]   irq_num      Number of IRQ.
73   \param[in]   irq_handler2 IRQ Handler.
74   \param[in]   dev          The dev to operate
75   \param[in]   arg          user data of irq_handler2
76   \return      None.
77 */
csi_irq_attach2(uint32_t irq_num,void * irq_handler2,csi_dev_t * dev,void * arg)78 void csi_irq_attach2(uint32_t irq_num, void *irq_handler2, csi_dev_t *dev, void *arg)
79 {
80     dev->arg             = arg;
81     dev->irq_handler2    = irq_handler2;
82     g_irq_table[irq_num] = dev;
83 }
84 
85 /**
86   \brief       unregister irq handler.
87   \param[in]   irq_num Number of IRQ.
88   \param[in]   irq_handler IRQ Handler.
89   \return      None.
90 */
csi_irq_detach(uint32_t irq_num)91 void csi_irq_detach(uint32_t irq_num)
92 {
93     g_irq_table[irq_num] = NULL;
94 }
95 
96 /**
97   \brief       gets whether in irq context
98   \return      true or false.
99 */
csi_irq_context(void)100 bool csi_irq_context(void)
101 {
102 #if defined(CONFIG_SMP) && CONFIG_SMP
103     return ((g_irq_nested_level[csi_get_cpu_id()] > 0U) ? true : false);
104 #else
105     return ((g_irq_nested_level > 0U) ? true : false);
106 #endif
107 }
108 
109 #if CONFIG_CPU_XUANTIE_E9XX
110 static volatile int g_nmi_cnt;
handle_nmi_exception(void)111 __attribute__((weak)) void handle_nmi_exception(void)
112 {
113     g_nmi_cnt++;
114 #if CONFIG_SUPPORT_NMI_DEMO
115     extern void timer_clear_irq();
116     timer_clear_irq();
117 #endif
118 }
119 #else
120 //FIXME:
121 extern void tick_irq_handler(void *arg);
CORET_IRQHandler(void)122 void CORET_IRQHandler(void)
123 {
124 #if defined(CONFIG_SMP) && CONFIG_SMP
125     g_irq_nested_level[csi_get_cpu_id()]++;
126 #else
127     g_irq_nested_level++;
128 #endif
129     CSI_INTRPT_ENTER();
130     tick_irq_handler(NULL);
131     CSI_INTRPT_EXIT();
132 #if defined(CONFIG_SMP) && CONFIG_SMP
133     g_irq_nested_level[csi_get_cpu_id()]--;
134 #else
135     g_irq_nested_level--;
136 #endif
137 }
138 #endif /* CONFIG_CPU_XUANTIE_E9XX */
139 
140 #if CONFIG_ECC_L1_ENABLE || CONFIG_ECC_L2_ENABLE
141 static struct {
142     int err_cnt_l1;
143     int err_cnt_l2;
144 } g_ecc_stat;
145 
ecc_l1_irqhandler(void * arg)146 void __attribute__((weak)) ecc_l1_irqhandler(void *arg)
147 {
148     g_ecc_stat.err_cnt_l1++;
149 
150     if (!(__get_MCER() >> 31) || (__get_MCER() & (0x1 << 30))) {
151         /* may be ecc fatal error happens */
152         while (1);
153     } else {
154         /* clear MCER EE_VLD */
155 #if __riscv_xlen == 32
156         __set_MCER(0);
157         __set_MCERH(0);
158 #else
159         __set_MCER(0);
160 #endif
161     }
162 }
163 
ecc_l2_irqhandler(void * arg)164 void __attribute__((weak)) ecc_l2_irqhandler(void *arg)
165 {
166     g_ecc_stat.err_cnt_l2++;
167 
168 #if __riscv_xlen == 32
169     if((__get_MCER2H() >> 30) == 0x2) {
170         /* clear MCER EE_VLD */
171         __set_MCER2(0);
172         __set_MCER2H(0);
173     } else {
174         /* may be ecc fatal error happens */
175         while (1);
176     }
177 #else
178     if((__get_MCER2() >> 62) == 0x2) {
179         /* clear MCER EE_VLD */
180         __set_MCER2(0);
181     } else {
182         /* may be ecc fatal error happens */
183         while (1);
184     }
185 #endif
186 }
187 
ECC_L1_IRQHandler(void)188 void ECC_L1_IRQHandler(void)
189 {
190 #if defined(CONFIG_SMP) && CONFIG_SMP
191     g_irq_nested_level[csi_get_cpu_id()]++;
192 #else
193     g_irq_nested_level++;
194 #endif
195     CSI_INTRPT_ENTER();
196     ecc_l1_irqhandler(NULL);
197     CSI_INTRPT_EXIT();
198 #if defined(CONFIG_SMP) && CONFIG_SMP
199     g_irq_nested_level[csi_get_cpu_id()]--;
200 #else
201     g_irq_nested_level--;
202 #endif
203 }
204 
205 #endif
206 /**
207   \brief       dispatching irq handlers(only handle external irq)
208   \return      None.
209 */
do_irq(void)210 void do_irq(void)
211 {
212     uint32_t irqn;
213 
214 #if defined(CONFIG_SMP) && CONFIG_SMP
215     g_irq_nested_level[csi_get_cpu_id()]++;
216 #else
217     g_irq_nested_level++;
218 #endif
219     CSI_INTRPT_ENTER();
220     irqn = soc_irq_get_irq_num();
221     if (g_irq_table[irqn]) {
222         if (g_irq_table[irqn]->irq_handler)
223             /* for compatibility */
224             g_irq_table[irqn]->irq_handler(g_irq_table[irqn]);
225         else if (g_irq_table[irqn]->irq_handler2)
226             g_irq_table[irqn]->irq_handler2(irqn, g_irq_table[irqn]->arg);
227         else
228             Default_Handler();
229     } else {
230         Default_Handler();
231     }
232     /* clear irq for cxx */
233     soc_irq_end(irqn);
234     CSI_INTRPT_EXIT();
235 #if defined(CONFIG_SMP) && CONFIG_SMP
236     g_irq_nested_level[csi_get_cpu_id()]--;
237 #else
238     g_irq_nested_level--;
239 #endif
240 }
241