1 /*
2 * Copyright (C) 2015-2021 Alibaba Group Holding Limited
3 */
4
5 #include <errno.h>
6 #include <pthread.h>
7
8 #include "aos/list.h"
9
10 #include <drivers/bug.h>
11 #include <drivers/compat.h>
12 #include <drivers/char/u_device.h>
13 #include <drivers/u_interrupt.h>
14
15 //TODO: use rbtree instead
16 #if U_IRQ_DESC_LIST_RBTREE
17 #else
18 dlist_t g_u_irq_thread_head;
19 dlist_t g_u_irq_desc_head;
20
21 u_irq_lock_t g_u_irq_lock;
22
23 u_irq_desc_t g_dummy_irq = {.name = "dummy",
24 .irq_id = 0xFEDC,
25 .irq_handler = NULL,
26 .thread_handler = NULL,
27 .irq_cnt = 0,
28 .flags = 0,
29 .data = &g_dummy_irq,
30 .p_irq_th = NULL,
31 };
32 #endif
33
34 #if U_IRQ_LOCK_SPINLOCK
35
u_irq_lock_init(u_irq_lock_t * lock)36 static inline int u_irq_lock_init(u_irq_lock_t *lock) {
37 int ret = -1;
38
39 ret = pthread_spin_init(lock, PTHREAD_PROCESS_PRIVATE);
40
41 if (ret) {
42 ddkc_err("pthread_spin_init failed, ret:%d\r\n", ret);
43 } else {
44 ddkc_dbg("pthread_spin_init success\r\n");
45 }
46
47 return ret;
48 }
49
u_irq_lock_lock(u_irq_lock_t * lock)50 static inline int u_irq_lock_lock(u_irq_lock_t *lock) {
51 int ret = -1;
52
53 ret = pthread_spin_lock(lock);
54
55 if (ret) {
56 ddkc_err("pthread_spin_lock failed, ret:%d\r\n", ret);
57 } else {
58 ddkc_dbg("pthread_spin_lock success\r\n");
59 }
60
61 return ret;
62 }
63
u_irq_lock_unlock(u_irq_lock_t * lock)64 static inline int u_irq_lock_unlock(u_irq_lock_t *lock) {
65 int ret = -1;
66
67 ret = pthread_spin_unlock(lock);
68
69 if (ret) {
70 ddkc_err("pthread_spin_unlock failed, ret:%d\r\n", ret);
71 } else {
72 ddkc_dbg("pthread_spin_unlock success\r\n");
73 }
74
75 return ret;
76 }
77
78
u_irq_lock_destroy(u_irq_lock_t * lock)79 static inline int u_irq_lock_destroy(u_irq_lock_t *lock) {
80 int ret = -1;
81
82 ret = pthread_spin_destroy(lock);
83
84 if (ret) {
85 ddkc_err("pthread_spin_destroy failed, ret:%d\r\n", ret);
86 } else {
87 ddkc_dbg("pthread_spin_destroy success\r\n");
88 }
89
90 return ret;
91 }
92 #else
u_irq_lock_init(u_irq_lock_t * lock)93 static inline int u_irq_lock_init(u_irq_lock_t *lock) {
94 int ret = -1;
95
96 ret = pthread_mutex_init(lock, NULL);
97
98 if (ret) {
99 ddkc_err("pthread_mutex_init failed, ret:%d\r\n", ret);
100 } else {
101 ddkc_loud("pthread_mutex_init success\r\n");
102 }
103
104 return ret;
105 }
106
u_irq_lock_lock(u_irq_lock_t * lock)107 static inline int u_irq_lock_lock(u_irq_lock_t *lock) {
108 int ret = -1;
109
110 ret = pthread_mutex_lock(lock);
111
112 if (ret) {
113 ddkc_err("pthread_mutex_lock failed, ret:%d\r\n", ret);
114 } else {
115 ddkc_loud("pthread_mutex_lock success\r\n");
116 }
117
118 return ret;
119 }
120
u_irq_lock_unlock(u_irq_lock_t * lock)121 static inline int u_irq_lock_unlock(u_irq_lock_t *lock) {
122 int ret = -1;
123
124 ret = pthread_mutex_unlock(lock);
125
126 if (ret) {
127 ddkc_err("pthread_mutex_unlock failed, ret:%d\r\n", ret);
128 } else {
129 ddkc_loud("pthread_mutex_unlock success\r\n");
130 }
131
132 return ret;
133 }
134
135
u_irq_lock_destroy(u_irq_lock_t * lock)136 static inline int u_irq_lock_destroy(u_irq_lock_t *lock) {
137 int ret = -1;
138
139 ret = pthread_mutex_destroy(lock);
140
141 if (ret) {
142 ddkc_err("pthread_mutex_destroy failed, ret:%d\r\n", ret);
143 } else {
144 ddkc_loud("pthread_mutex_destroy success\r\n");
145 }
146
147 return ret;
148 }
149
150
151 #endif
152
u_irq_handler(int irq_id,void * data)153 u_irqreturn_t u_irq_handler(int irq_id, void *data) {
154
155 u_irq_desc_t *tmp = NULL;
156 u_irq_desc_t *desc = (u_irq_desc_t *)data;
157 u_irq_thread_t *p_irq_th = NULL;
158 u_irq_msg_t *p_irq_msg = NULL;
159
160 #if 0
161 p_irq_th = desc->p_irq_th;
162
163 p_irq_msg = (u_irq_msg_t *)malloc(sizeof(*p_irq_msg));
164 if (p_irq_msg) {
165 p_irq_msg->u_irq = desc;
166 u_irq_lock_lock(&p_irq_th->lock);
167 dlist_add_tail(&p_irq_msg->node, &p_irq_th->msg_head);
168 u_irq_lock_unlock(&p_irq_th->lock);
169
170 pthread_cond_signal(&p_irq_th->cond);
171 } else {
172 ddkc_err("malloc for irq_msg failed, %d missed\n", irq_id);
173 }
174 #else
175 // search irq_id's thread
176 dlist_for_each_entry_safe(&g_u_irq_desc_head, tmp, desc, u_irq_desc_t, irq_desc_node) {
177 if (desc->irq_id != irq_id)
178 continue;
179
180 p_irq_th = desc->p_irq_th;
181 // TODO: malloc is not allowed in IRQ context
182 // add irq_id into p_irq_th's message list
183 p_irq_msg = (u_irq_msg_t *)malloc(sizeof(*p_irq_msg));
184 if (p_irq_msg) {
185 p_irq_msg->u_irq = desc;
186 u_irq_lock_lock(&p_irq_th->lock);
187 dlist_add_tail(&p_irq_msg->node, &p_irq_th->msg_head);
188 u_irq_lock_unlock(&p_irq_th->lock);
189
190 pthread_cond_signal(&p_irq_th->cond);
191 } else {
192 ddkc_err("malloc for irq_msg failed, %d missed\r\n", irq_id);
193 }
194
195 }
196 #endif
197 return IRQ_HANDLED;
198 }
199
u_irq_thread_fn(void * arg)200 void* u_irq_thread_fn(void *arg) {
201 unsigned int r = -1;
202 u_irq_thread_t *p_irq_th = (u_irq_thread_t *)arg;
203 u_irq_msg_t *tmp = NULL;
204 u_irq_msg_t *p_irq_msg = NULL, *next = NULL;
205 u_irq_desc_t *desc = NULL;
206
207 BUG_ON(!p_irq_th);
208
209 do {
210 dlist_for_each_entry_safe(&p_irq_th->msg_head, tmp, p_irq_msg, u_irq_msg_t, node) {
211 u_irq_msg_t *m = p_irq_msg;
212
213 //TODO: NOTICE performance issue!!!
214 /** shall we add another lock to protect this critical section from operation on desc in u_free_irq?
215 */
216 u_irq_lock_lock(&p_irq_th->lock);
217 dlist_del(p_irq_msg);
218 desc = m->u_irq;
219 if (desc->thread_handler)
220 (desc->thread_handler)(desc->irq_id, desc->data);
221 else if (desc->irq_handler)
222 (desc->irq_handler)(desc->irq_id, desc->data);
223 desc->irq_cnt++;
224 u_irq_lock_unlock(&p_irq_th->lock);
225
226 free(p_irq_msg);
227 //TODO: shall add monitor on irq_cnt in <x> ms, disable the irq for flood irq case
228 }
229
230 r = pthread_cond_wait(&p_irq_th->cond, &p_irq_th->mutex);
231 if (r) {
232 ddkc_err("%s wait for cond failed, r:%d\r\n", p_irq_th->name, r);
233 }
234 } while (!p_irq_th->should_stop);
235
236 //TODO: clear IRQ related resources
237 p_irq_th->stopped = 1;
238 ddkc_info("thread %p stopped\r\n", p_irq_th);
239
240 return NULL;
241 }
242
u_irq_thread_create(u_irq_desc_t * u_irq,int prio)243 u_irq_thread_t *u_irq_thread_create(u_irq_desc_t *u_irq, int prio) {
244 int r = -1;
245 u_irq_thread_t *p_irq_th = NULL;
246 pthread_attr_t attr;
247
248 if (!u_irq) {
249 ddkc_err("invalid p_irq_th or u_irq\r\n");
250 return NULL;
251 }
252
253 p_irq_th = (u_irq_thread_t *)malloc(sizeof(*p_irq_th));
254 if (!p_irq_th) {
255 ddkc_err("malloc u_irq_thread_t for irq-%d failed\r\n", u_irq->irq_id);
256 return NULL;
257 }
258 p_irq_th->should_stop = 0;
259 p_irq_th->stopped = 0;
260
261 dlist_init(&p_irq_th->irq_desc_head);
262 dlist_init(&p_irq_th->irq_thread_node);
263 dlist_init(&p_irq_th->msg_head);
264
265 pthread_condattr_init(&p_irq_th->condattr);
266 pthread_condattr_setclock(&p_irq_th->condattr, CLOCK_MONOTONIC);
267 pthread_cond_init(&p_irq_th->cond, &p_irq_th->condattr);
268 pthread_mutex_init(&p_irq_th->mutex, NULL);
269 u_irq_lock_init(&p_irq_th->lock);
270
271 pthread_attr_init(&attr);
272
273 #if 0 //TODO: need to adjust thread's priority!!, change 0 and 120 to marco
274 struct sched_param sched;
275 if (prio <= 0 && prio > 120)
276 sched.sched_priority = 1;
277 else
278 sched.sched_priority = prio;
279
280 pthread_attr_setschedparam(&attr,&sched);
281 pthread_attr_setstacksize(&attr,4096);
282 #endif
283 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
284 r = pthread_create(&(p_irq_th->thread), &attr, u_irq_thread_fn, (void*)(p_irq_th));
285 pthread_attr_destroy(&attr);
286 if(!r) {
287 memset(p_irq_th->name, 0, sizeof(p_irq_th->name));
288
289 if (u_irq != &g_dummy_irq)
290 snprintf(p_irq_th->name, sizeof(p_irq_th->name), "irq-%d", u_irq->irq_id);
291 else
292 snprintf(p_irq_th->name, sizeof(p_irq_th->name), "irq-m-%d", getpid());
293
294 // assume this operation won't fail
295 pthread_setname_np(p_irq_th->thread, p_irq_th->name);
296 } else {
297 ddkc_err("pthread_create for irq-%d failed, r:%d\r\n", u_irq->irq_id, r);
298 free(p_irq_th);
299 return NULL;
300 }
301 ddkc_info("pthread create for irq-%d success, pid:%p, name:%s\r\n",
302 u_irq->irq_id, p_irq_th->thread, p_irq_th->name);
303 // add irq's thread_node into thread's irq_desc_head
304 u_irq_lock_lock(&p_irq_th->lock);
305 dlist_add_tail(&u_irq->thread_node, &p_irq_th->irq_desc_head);
306 u_irq_lock_unlock(&p_irq_th->lock);
307
308 u_irq_lock_lock(&g_u_irq_lock);
309 dlist_add_tail(&p_irq_th->irq_thread_node, &g_u_irq_thread_head);
310 u_irq_lock_unlock(&g_u_irq_lock);
311
312 return p_irq_th;
313 }
314
u_irq_thread_delete(u_irq_thread_t * t)315 int u_irq_thread_delete(u_irq_thread_t *t) {
316 t->should_stop = 1;
317 pthread_cond_signal(&t->cond);
318
319 /* wait for thread to quit and free the thread if necessary */
320 while(!t->stopped) {
321 // TODO: ethan - should add sychnronized mechanism
322 //msleep(50);
323 usleep(50 * 1000);
324 }
325
326 u_irq_lock_lock(&g_u_irq_lock);
327 dlist_del(&t->irq_thread_node);
328 u_irq_lock_unlock(&g_u_irq_lock);
329
330 WARN_ON(!dlist_empty(&t->irq_desc_head));
331
332 pthread_cond_destroy(&t->cond);
333 pthread_mutex_destroy(&t->mutex);
334 u_irq_lock_destroy(&t->lock);
335 pthread_condattr_destroy(&t->condattr);
336
337 free(t);
338
339 return 0;
340 }
341
342 //TODO:- must be called before any other IRQ system APIs called
u_irq_system_init(void)343 int u_irq_system_init(void) {
344 int r = 0;
345
346 u_irq_thread_t *g_u_irq_th = NULL;
347
348 dlist_init(&g_u_irq_thread_head);
349 dlist_init(&g_u_irq_desc_head);
350 u_irq_lock_init(&g_u_irq_lock);
351
352 g_u_irq_th = u_irq_thread_create(&g_dummy_irq, -1);
353
354 if (g_u_irq_th) {
355 ddkc_info("u_irq system init success\r\n");
356 r = 0;
357 } else {
358 ddkc_err("u_irq_thread_create for g_dummy_irq failed\r\n");
359 return -ENOMEM;
360 }
361
362 g_dummy_irq.p_irq_th = g_u_irq_th;
363
364 u_irq_lock_lock(&g_u_irq_lock);
365 dlist_add_tail(&g_dummy_irq.irq_desc_node, &g_u_irq_desc_head);
366 u_irq_lock_unlock(&g_u_irq_lock);
367
368 return r;
369 }
370
u_irq_system_deinit(void)371 int u_irq_system_deinit(void) {
372 u_irq_desc_t *desc = NULL;
373 u_irq_desc_t *n = NULL;
374
375 // search irq_id's thread
376 dlist_for_each_entry_safe(&g_u_irq_desc_head, n, desc, u_irq_desc_t, irq_desc_node) {
377
378 if (desc == &g_dummy_irq)
379 continue;
380
381 // deattch irq desc from g_u_irq_desc_head
382 u_irq_lock_lock(&g_u_irq_lock);
383 dlist_del(&desc->irq_desc_node);
384 u_irq_lock_unlock(&g_u_irq_lock);
385
386 // remove irq desc
387 u_irq_remove(desc);
388
389 free(desc);
390 }
391
392 // remove irq desc
393 u_irq_remove(desc);
394
395 return 0;
396 }
397
u_irq_setup(u_irq_desc_t * u_irq)398 int u_irq_setup(u_irq_desc_t *u_irq) {
399 if (!u_irq)
400 return -EINVAL;
401
402 BUG_ON_MSG((g_dummy_irq.irq_id == u_irq->irq_id),
403 "u_irq->irq_id equals with dummy irq_id, should NEVER happen\n");
404
405 if (u_irq->thread_handler) {
406 u_irq_thread_t *u_irq_th = u_irq_thread_create(u_irq, -1);
407 if (!u_irq_th)
408 return -ENOMEM;
409
410 u_irq->p_irq_th = u_irq_th;
411 } else if (u_irq->irq_handler) {
412 u_irq->p_irq_th = g_dummy_irq.p_irq_th;
413 } else {
414 ddkc_err("!!!!This should never happen\r\n");
415 return -EINVAL;
416 }
417 // add irq_desc_node to global u_irq_desc list
418 u_irq_lock_lock(&g_u_irq_lock);
419 dlist_add_tail(&u_irq->irq_desc_node, &g_u_irq_desc_head);
420 u_irq_lock_unlock(&g_u_irq_lock);
421 /** TODO: call system API to register IRQ
422 * Passthrough mode: register u_irq->irq_handler directly to low level system
423 * Agent mode: register agent irq handler (u_irq_handler) to system
424 */
425
426
427 return 0;
428 }
429
u_irq_remove(u_irq_desc_t * u_irq)430 int u_irq_remove(u_irq_desc_t *u_irq) {
431 int ret = 0;
432 u_irq_thread_t *p_irq_th = NULL;
433
434 if (!u_irq) {
435 ddkc_err("invalid u_irq:%p\r\n", u_irq);
436 return -EINVAL;
437 }
438
439 if (!u_irq->p_irq_th || !u_irq->thread_handler) {
440 ddkc_dbg("irq:%d pthread_irq_th:%p, thread_handler:%p, no need to stop irq thread\r\n",
441 u_irq->irq_id, u_irq->p_irq_th, u_irq->thread_handler);
442 return 0;
443 }
444 ddkc_dbg("start to clear resource for irq:%d\r\n", u_irq->irq_id);
445
446 p_irq_th = u_irq->p_irq_th;
447 if ((p_irq_th == g_dummy_irq.p_irq_th) &&
448 (u_irq->irq_id != g_dummy_irq.irq_id)) {
449 ddkc_info("irq[%d] shares common irq thread, ignore\r\n", u_irq->irq_id);
450 return 0;
451 }
452
453 ret = u_irq_thread_delete(p_irq_th);
454
455 ddkc_dbg("thread stopped for irq:%d\r\n", u_irq->irq_id);
456
457 return 0;
458 }
459
u_request_threaded_irq(unsigned int irq,u_irq_handler_t handler,u_irq_handler_t thread_fn,unsigned long flags,const char * name,void * data)460 int u_request_threaded_irq(
461 unsigned int irq, u_irq_handler_t handler, u_irq_handler_t thread_fn,
462 unsigned long flags, const char *name, void *data) {
463 int r = -1;
464 u_irq_desc_t *u_irq = NULL;
465
466 if (!handler && !thread_fn) {
467 ddkc_err("both handler and thread_fn is NULL\r\n", irq);
468 return -EINVAL;
469 }
470
471 u_irq = (u_irq_desc_t *)malloc (sizeof(u_irq_desc_t));
472 if (!u_irq) {
473 ddkc_err("malloc u_irq_desc_t failed for irq:%d\r\n", irq);
474 return -ENOMEM;
475 }
476 #if U_IRQ_DESC_LIST_RBTREE
477 #else
478 dlist_init(&u_irq->irq_desc_node);
479 #endif
480 dlist_init(&u_irq->thread_node);
481
482 u_irq->name = name;
483 u_irq->data = data;
484 u_irq->flags = flags;
485 u_irq->irq_cnt = 0;
486 u_irq->irq_id = irq;
487 u_irq->irq_handler = handler;
488 u_irq->thread_handler = thread_fn;
489 u_irq->p_irq_th = NULL;
490
491 /* setup new thread if needed */
492 r = u_irq_setup(u_irq);
493 if (r)
494 goto irq_setup_fail;
495
496 return 0;
497
498 irq_setup_fail:
499 u_irq_remove(u_irq);
500
501 free(u_irq);
502
503 return r;
504 }
505
free_u_irq(unsigned int irq_id)506 void free_u_irq(unsigned int irq_id) {
507 u_irq_desc_t *n = NULL;
508 u_irq_desc_t *u_irq = NULL;
509 u_irq_thread_t *p_irq_th = NULL;
510 u_irq_msg_t *p_irq_msg = NULL, *next = NULL;
511
512 // search irq_id's thread
513 dlist_for_each_entry_safe(&g_u_irq_desc_head, n, u_irq, u_irq_desc_t, irq_desc_node) {
514 if (u_irq->irq_id != irq_id)
515 continue;
516
517 p_irq_th = u_irq->p_irq_th;
518
519 dlist_for_each_entry_safe(&p_irq_th->msg_head, next, p_irq_msg, u_irq_msg_t, node) {
520
521 // clear all irq message of target irq
522 if (p_irq_msg->u_irq == u_irq) {
523 u_irq_lock_lock(&p_irq_th->lock);
524 dlist_del(p_irq_msg);
525 u_irq_lock_unlock(&p_irq_th->lock);
526 free(p_irq_msg);
527 }
528 }
529
530 // deattach u_irq from thread's irq list and global irq desc list
531 u_irq_lock_lock(&p_irq_th->lock);
532 dlist_del(&u_irq->thread_node);
533 u_irq_lock_unlock(&p_irq_th->lock);
534
535 u_irq_lock_lock(&g_u_irq_lock);
536 dlist_del(&u_irq->irq_desc_node);
537 u_irq_lock_unlock(&g_u_irq_lock);
538
539 // try to clean irq's thread resource
540 u_irq_remove(u_irq);
541 free(u_irq);
542 }
543
544 return 0;
545 }
disable_u_irq_nosync(unsigned int irq)546 void disable_u_irq_nosync(unsigned int irq) {
547 }
548
disable_u_irq(unsigned int irq)549 void disable_u_irq(unsigned int irq) {
550 }
551
enable_u_irq(unsigned int irq)552 void enable_u_irq(unsigned int irq) {
553 }
554
free_irq(unsigned int irq,void * dev_id)555 __weak void free_irq(unsigned int irq, void *dev_id) {
556 }
557
__wrap_free_irq(unsigned int irq,void * dev_id)558 void __wrap_free_irq(unsigned int irq, void *dev_id) {
559 __real_free_irq(irq, dev_id);
560 }
561
562