1 /*
2 * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
3 * Copyright (c) 2018,2020, The Linux Foundation. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7 #include <assert.h>
8 #include <stdint.h>
9
10 #include <arch_helpers.h>
11 #include <bl31/interrupt_mgmt.h>
12 #include <common/debug.h>
13 #include <drivers/arm/gic_common.h>
14 #include <lib/el3_runtime/context_mgmt.h>
15 #include <lib/spinlock.h>
16 #include <lib/utils_def.h>
17
18 #include <platform.h>
19 #include <qti_interrupt_svc.h>
20 #include <qtiseclib_interface.h>
21
22 #define QTI_INTR_INVALID_INT_NUM 0xFFFFFFFFU
23 #define ISR_TABLE_LEN 20
24
25 static struct qti_isr_table {
26 struct qti_isr {
27 qti_int_svc_isr_t func;
28 uint32_t id;
29 void *ctx;
30 } entry[ISR_TABLE_LEN];
31
32 spinlock_t lock;
33 uint8_t cnt;
34 } isr_table = {
35 .entry[0 ... ISR_TABLE_LEN - 1] = { .id = QTI_INTR_INVALID_INT_NUM },
36 };
37
qti_interrupt_svc_register(uint32_t id,qti_int_svc_isr_t func,void * ctx)38 int qti_interrupt_svc_register(uint32_t id, qti_int_svc_isr_t func, void *ctx)
39 {
40 struct qti_isr *p = isr_table.entry;
41
42 spin_lock(&isr_table.lock);
43 if (isr_table.cnt >= ISR_TABLE_LEN)
44 goto error;
45
46 for (size_t i = 0; i < ISR_TABLE_LEN; i++, p++) {
47 if (p->id != QTI_INTR_INVALID_INT_NUM) {
48 continue;
49 }
50
51 p->func = func;
52 p->ctx = ctx;
53 p->id = id;
54 isr_table.cnt++;
55 spin_unlock(&isr_table.lock);
56
57 return 0;
58 }
59 error:
60 spin_unlock(&isr_table.lock);
61
62 return -ENOTCAPABLE;
63 }
64
qti_interrupt_svc_unregister(uint32_t id)65 int qti_interrupt_svc_unregister(uint32_t id)
66 {
67 struct qti_isr *p = isr_table.entry;
68
69 spin_lock(&isr_table.lock);
70 if (!isr_table.cnt)
71 goto error;
72
73 for (size_t i = 0; i < ISR_TABLE_LEN; i++, p++) {
74 if (p->id != id) {
75 continue;
76 }
77
78 memset(p, 0, sizeof(*p));
79 p->id = QTI_INTR_INVALID_INT_NUM;
80 isr_table.cnt--;
81 spin_unlock(&isr_table.lock);
82
83 return 0;
84 }
85 error:
86 spin_unlock(&isr_table.lock);
87
88 return -ENOENT;
89 }
90
interrupt_svc_invoke_isr(uint32_t id,void * handle)91 static void interrupt_svc_invoke_isr(uint32_t id, void *handle)
92 {
93 struct qti_isr *p = isr_table.entry;
94 qti_int_svc_isr_t invoke_isr = NULL;
95
96 spin_lock(&isr_table.lock);
97 if (!isr_table.cnt)
98 goto qtiseclib_dispatch;
99
100 for (size_t i = 0; i < ISR_TABLE_LEN; i++, p++) {
101 if (p->id != id) {
102 continue;
103 }
104
105 invoke_isr = p->func;
106 spin_unlock(&isr_table.lock);
107 p->ctx = invoke_isr(id, p->ctx);
108
109 return;
110 }
111
112 qtiseclib_dispatch:
113 spin_unlock(&isr_table.lock);
114 qtiseclib_invoke_isr(id, handle);
115 }
116
117 /*
118 * Top-level EL3 interrupt handler.
119 */
qti_el3_interrupt_handler(uint32_t id,uint32_t flags,void * handle,void * cookie)120 static uint64_t qti_el3_interrupt_handler(uint32_t id, uint32_t flags,
121 void *handle, void *cookie)
122 {
123 uint32_t irq = QTI_INTR_INVALID_INT_NUM;
124
125 /*
126 * EL3 non-interruptible. Interrupt shouldn't occur when we are at
127 * EL3 / Secure.
128 */
129 assert(handle != cm_get_context(SECURE));
130
131 irq = plat_ic_acknowledge_interrupt();
132
133 interrupt_svc_invoke_isr(irq, handle);
134
135 /* End of Interrupt. */
136 if (irq < 1022U) {
137 plat_ic_end_of_interrupt(irq);
138 }
139
140 return (uint64_t) handle;
141 }
142
qti_interrupt_svc_init(bool have_sel1)143 int qti_interrupt_svc_init(bool have_sel1)
144 {
145 int ret;
146 uint64_t flags = 0U;
147
148 /*
149 * Route EL3 interrupts to EL3 when in Non-secure.
150 * Note: EL3 won't have interrupts enabled.
151 * When we have a Secure EL1 interrupt handler, allow it
152 * to handle Secure interrupts.
153 */
154 set_interrupt_rm_flag(flags, NON_SECURE);
155 if (!have_sel1)
156 set_interrupt_rm_flag(flags, SECURE);
157
158 /* Register handler for EL3 interrupts */
159 ret = register_interrupt_type_handler(INTR_TYPE_EL3,
160 qti_el3_interrupt_handler, flags);
161 assert(ret == 0);
162
163 return ret;
164 }
165