• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 HiSilicon (Shanghai) Technologies CO., LIMITED.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  */
18 
19 #include "hi_osal.h"
20 #include <linux/module.h>
21 #include <linux/kernel.h>
22 #include <linux/printk.h>
23 #include <linux/interrupt.h>
24 #include <linux/version.h>
25 #include <linux/slab.h>
26 #include "securec.h"
27 
28 static OSAL_LIST_HEAD(g_irq_list);
29 
30 typedef struct irq_info_ {
31     int irq;
32     int __irq;
33     struct osal_list_head node;
34 }irq_info;
35 
osal_irq_find_node(int irq,struct osal_list_head * list)36 irq_info *osal_irq_find_node(int irq, struct osal_list_head *list)
37 {
38     irq_info *irq_node = NULL;
39 
40     osal_list_for_each_entry(irq_node, list, node) {
41         if (irq_node->irq == irq) {
42             return irq_node;
43         }
44     }
45 
46     return NULL;
47 }
48 
49 extern int hi_get_irq_byname(char *name);
osal_irq_request(unsigned int irq,osal_irq_handler handler,osal_irq_handler thread_fn,const char * name,void * dev)50 int osal_irq_request(unsigned int irq, osal_irq_handler handler, osal_irq_handler thread_fn, const char *name,
51                      void *dev)
52 {
53     int __irq = irq;
54     unsigned long flags = IRQF_SHARED;
55 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
56     irq_info *irq_node = NULL;
57 #endif
58 
59     if (name == NULL) {
60         printk("name is NULL ! \n");
61         return 0;
62     }
63 
64     if (dev == NULL) {
65         flags = 0;
66     }
67 
68 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
69     irq_node = osal_irq_find_node(irq, &g_irq_list);
70     if (irq_node != NULL) {
71         printk("irq %s, irq_num =%dr repeat!!!\n", name, irq);
72         return -1;
73     }
74 
75     irq_node = kmalloc(sizeof(irq_info), GFP_KERNEL);
76     if (irq_node == NULL) {
77         printk("kmalloc irq_node:%s failed.\n", name);
78         return -1;
79     }
80 
81     __irq = hi_get_irq_byname((char *)name);
82     if (__irq == -1) {
83         printk("hi_get_irq_byname:%s failed.\n", name);
84         kfree(irq_node);
85         return -1;
86     }
87     irq_node->__irq = __irq;
88     irq_node->irq = irq;
89 #endif
90 
91     osal_list_add_tail(&irq_node->node, &g_irq_list);
92 
93     return request_threaded_irq(__irq, (irq_handler_t)handler, (irq_handler_t)thread_fn, flags, name, dev);
94 }
95 EXPORT_SYMBOL(osal_irq_request);
96 
osal_irq_free(unsigned int irq,void * dev)97 void osal_irq_free(unsigned int irq, void *dev)
98 {
99     int __irq = irq;
100 
101 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
102     irq_info *irq_node = NULL;
103 
104     irq_node = osal_irq_find_node(irq, &g_irq_list);
105     if (irq_node != NULL) {
106         __irq = irq_node->__irq;
107         osal_list_del(&irq_node->node);
108         kfree(irq_node);
109     } else {
110         printk("osal_irq_free irq=%u, is not exist\n", irq);
111         osal_dump_stack();
112         return;
113     }
114 #endif
115 
116     free_irq(__irq, dev);
117 }
118 EXPORT_SYMBOL(osal_irq_free);
119 
osal_irq_set_affinity(unsigned int irq,const char * name,int cpu_mask)120 int osal_irq_set_affinity(unsigned int irq, const char *name, int cpu_mask)
121 {
122     int __irq = irq;
123     struct cpumask cpumask_set = {0};
124 
125     cpumask_clear(&cpumask_set);
126 
127     ((OSAL_CPU_0 & (unsigned int)cpu_mask) == 0) ?
128         0 : cpumask_set_cpu(0, &cpumask_set); // cpu0
129 
130     ((OSAL_CPU_1 & (unsigned int)cpu_mask) == 0) ?
131         0 : cpumask_set_cpu(1, &cpumask_set); // cpu1
132 
133     ((OSAL_CPU_2 & (unsigned int)cpu_mask) == 0) ?
134         0 : cpumask_set_cpu(2, &cpumask_set); // cpu2
135 
136     ((OSAL_CPU_3 & (unsigned int)cpu_mask) == 0) ?
137         0 : cpumask_set_cpu(3, &cpumask_set); // cpu 3
138 
139 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
140     __irq = hi_get_irq_byname((char *)name);
141 #endif
142 
143     return irq_set_affinity_hint(__irq, &cpumask_set);
144 }
145 EXPORT_SYMBOL(osal_irq_set_affinity);
146 
osal_in_interrupt(void)147 int osal_in_interrupt(void)
148 {
149     return in_interrupt();
150 }
151 EXPORT_SYMBOL(osal_in_interrupt);
152 
153 /*
154  * enable_irq - enable handling of an irq
155  * @irq: Interrupt to enable
156  *
157  * Undoes the effect of one call to disable_irq().  If this
158  * matches the last disable, processing of interrupts on this
159  * IRQ line is re-enabled.
160  * This function may be called from IRQ context only when
161  * desc->irq_data.chip->bus_lock and desc->chip->bus_sync_unlock
162  * are NULL !
163  */
osal_irq_enable(unsigned int irq)164 void osal_irq_enable(unsigned int irq)
165 {
166     int __irq = irq;
167 
168 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
169     irq_info *irq_node = NULL;
170 
171     irq_node = osal_irq_find_node(irq, &g_irq_list);
172     if (irq_node != NULL) {
173         __irq = irq_node->__irq;
174     } else {
175         printk("osal_irq_enable irq=%u, is not exist\n", irq);
176         return;
177     }
178 #endif
179 
180     enable_irq(__irq);
181 
182     return;
183 }
184 EXPORT_SYMBOL(osal_irq_enable);
185 
186 /*
187  * disable_irq - disable an irq and wait for completion
188  * irq: Interrupt to disable
189  *
190  * Disable the selected interrupt line.  Enables and Disables are
191  * nested.
192  * This function waits for any pending IRQ handlers for this interrupt
193  * to complete before returning. If you use this function while
194  * holding a resource the IRQ handler may need you will deadlock.
195  * This function may be called - with care - from IRQ context.
196  **/
osal_irq_disable(unsigned int irq)197 void osal_irq_disable(unsigned int irq)
198 {
199     int __irq = irq;
200 
201 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
202     irq_info *irq_node = NULL;
203 
204     irq_node = osal_irq_find_node(irq, &g_irq_list);
205     if (irq_node != NULL) {
206         __irq = irq_node->__irq;
207     } else {
208         printk("osal_irq_disable irq=%d, is not exist\n", irq);
209         return;
210     }
211 #endif
212 
213     disable_irq(__irq);
214 
215     return;
216 }
217 EXPORT_SYMBOL(osal_irq_disable);
218 
219 /* tasklet is running only on one CPU simultaneously */
osal_tasklet_init(osal_tasklet * tasklet)220 int osal_tasklet_init(osal_tasklet *tasklet)
221 {
222     int ret = 0;
223     struct tasklet_struct *tasklet_local = NULL;
224     atomic_t i = ATOMIC_INIT(0);
225 
226     if (!tasklet) {
227         printk("init tasklet is NULL ! \n");
228         return -1;
229     }
230 
231     tasklet_local = (struct tasklet_struct *)kmalloc(sizeof(struct tasklet_struct), GFP_KERNEL);
232     if (!tasklet_local) {
233         printk("Tasklet initialize when malloc memory failed\n");
234         return -1;
235     }
236 
237     ret = memset_s(tasklet_local, sizeof(struct tasklet_struct), 0, sizeof(struct tasklet_struct));
238     if (ret != 0) {
239         return -1;
240     }
241 
242     tasklet_local->next  = NULL;
243     tasklet_local->state = 0;
244     tasklet_local->count = i;
245     tasklet_local->func  = tasklet->handler;
246     tasklet_local->data  = tasklet->data;
247 
248     tasklet->tasklet = (void*)tasklet_local;
249 
250     return 0;
251 }
252 EXPORT_SYMBOL(osal_tasklet_init);
253 
254 /*
255  * tasklet update should be called after tasklet init
256  **/
osal_tasklet_update(osal_tasklet * tasklet)257 int osal_tasklet_update(osal_tasklet *tasklet)
258 {
259     struct tasklet_struct *tasklet_local = NULL;
260 
261     if (!tasklet) {
262         printk("tasklet setdata input is NULL\n");
263         return -1;
264     }
265 
266     tasklet_local = (struct tasklet_struct *) tasklet->tasklet;
267     tasklet_local->data = tasklet->data;
268     tasklet_local->func = tasklet->handler;
269 
270     return 0;
271 }
272 EXPORT_SYMBOL(osal_tasklet_update);
273 
274 /*
275  * add tasklet to tasklet_hi_vec and start tasklet
276  **/
osal_tasklet_schedule(osal_tasklet * tasklet)277 int osal_tasklet_schedule(osal_tasklet *tasklet)
278 {
279     if (!tasklet) {
280         printk("schedule tasklet is NULL ! \n");
281         return -1;
282     }
283 
284     tasklet_schedule((struct tasklet_struct *)tasklet->tasklet);
285 
286     return 0;
287 }
288 EXPORT_SYMBOL(osal_tasklet_schedule);
289 
290 /* kill tasklet */
osal_tasklet_kill(osal_tasklet * tasklet)291 int osal_tasklet_kill(osal_tasklet *tasklet)
292 {
293     if (!tasklet) {
294         printk("kill tasklet is NULL \n");
295         return -1;
296     }
297 
298     tasklet_kill((struct tasklet_struct *)tasklet->tasklet);
299     kfree(tasklet->tasklet);
300     tasklet->tasklet = NULL;
301 
302     return 0;
303 }
304 EXPORT_SYMBOL(osal_tasklet_kill);
305