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