core: support shared irq

With some platforms would have multiplexed interrupts
and software implement difference interrupt handler.
Currently the interrupt mechanism only handle the first
matched handler, and can not support shared irq.

New change to keep find another matched handler if the
previous handler return none.

Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org>
Signed-off-by: davidwang <davidwang@realtek.com>
diff --git a/core/include/kernel/interrupt.h b/core/include/kernel/interrupt.h
index e85f7fc..849e987 100644
--- a/core/include/kernel/interrupt.h
+++ b/core/include/kernel/interrupt.h
@@ -7,8 +7,10 @@
 
 #include <types_ext.h>
 #include <sys/queue.h>
+#include <util.h>
 
-#define ITRF_TRIGGER_LEVEL	(1 << 0)
+#define ITRF_TRIGGER_LEVEL	BIT(0)
+#define ITRF_SHARED			BIT(1)
 
 struct itr_chip {
 	const struct itr_ops *ops;
diff --git a/core/kernel/interrupt.c b/core/kernel/interrupt.c
index d17662d..4409f73 100644
--- a/core/kernel/interrupt.c
+++ b/core/kernel/interrupt.c
@@ -6,6 +6,7 @@
 #include <kernel/interrupt.h>
 #include <kernel/panic.h>
 #include <trace.h>
+#include <assert.h>
 
 /*
  * NOTE!
@@ -23,34 +24,35 @@
 	itr_chip = chip;
 }
 
-static struct itr_handler *find_handler(size_t it)
-{
-	struct itr_handler *h;
-
-	SLIST_FOREACH(h, &handlers, link)
-		if (h->it == it)
-			return h;
-	return NULL;
-}
-
 void itr_handle(size_t it)
 {
-	struct itr_handler *h = find_handler(it);
+	struct itr_handler *h = NULL;
+	bool was_handled = false;
 
-	if (!h) {
-		EMSG("Disabling unhandled interrupt %zu", it);
-		itr_chip->ops->disable(itr_chip, it);
-		return;
+	SLIST_FOREACH(h, &handlers, link) {
+		if (h->it == it) {
+			if (h->handler(h) == ITRR_HANDLED)
+				was_handled = true;
+			else if (!(h->flags & ITRF_SHARED))
+				break;
+		}
 	}
 
-	if (h->handler(h) != ITRR_HANDLED) {
-		EMSG("Disabling interrupt %zu not handled by handler", it);
+	if (!was_handled) {
+		EMSG("Disabling unhandled interrupt %zu", it);
 		itr_chip->ops->disable(itr_chip, it);
 	}
 }
 
 void itr_add(struct itr_handler *h)
 {
+	struct itr_handler __maybe_unused *hdl = NULL;
+
+	SLIST_FOREACH(hdl, &handlers, link)
+		if (hdl->it == h->it)
+			assert((hdl->flags & ITRF_SHARED) &&
+			       (h->flags & ITRF_SHARED));
+
 	itr_chip->ops->add(itr_chip, h->it, h->flags);
 	SLIST_INSERT_HEAD(&handlers, h, link);
 }