1 /*
2 * Copyright (c) 2023 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
3 * Licensed under the Mulan PSL v2.
4 * You can use this software according to the terms and conditions of the Mulan PSL v2.
5 * You may obtain a copy of Mulan PSL v2 at:
6 * http://license.coscl.org.cn/MulanPSL2
7 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
8 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
9 * PURPOSE.
10 * See the Mulan PSL v2 for more details.
11 */
12 #include <ipc/notification.h>
13 #include <irq/irq.h>
14 #include <object/irq.h>
15 #include <common/errno.h>
16 #include <sched/context.h>
17
18
19
20 struct irq_notification *irq_notifcs[MAX_IRQ_NUM];
user_handle_irq(int irq)21 int user_handle_irq(int irq)
22 {
23 struct irq_notification *irq_notic;
24
25 irq_notic = irq_notifcs[irq];
26
27 /*
28 * If the interrupt handler thread is not ready for handling a new
29 * interrupt, we ignore a nested interrupt.
30 */
31 if (!irq_notic || !irq_notic->user_handler_ready) {
32 kdebug("One interrupt (irq: %d) is ingored since the handler "
33 "thread is not ready.\n",
34 irq);
35 return 0;
36 }
37
38 /*
39 * Disable the irq before passing the current irq to the
40 * user-level handler thread.
41 */
42 arch_disable_irqno(irq_notic->intr_vector);
43
44 signal_irq_notific(irq_notic);
45 sched();
46 eret_to_thread(switch_context());
47 /* Never returns. */
48
49 BUG_ON(1);
50 return 0;
51 }
52
irq_deinit(void * irq_ptr)53 void irq_deinit(void *irq_ptr)
54 {
55 struct irq_notification *irq_notifc;
56 int irq;
57
58 irq_notifc = (struct irq_notification *)irq_ptr;
59 irq = irq_notifc->intr_vector;
60 irq_handle_type[irq] = HANDLE_KERNEL;
61 smp_mb();
62 irq_notifcs[irq] = NULL;
63 }
64
sys_irq_register(int irq)65 cap_t sys_irq_register(int irq)
66 {
67 struct irq_notification *irq_notifc = NULL;
68 cap_t irq_notifc_cap = 0;
69 int ret = 0;
70
71 if (irq < 0 || irq >= MAX_IRQ_NUM)
72 return -EINVAL;
73
74 irq_notifc = obj_alloc(TYPE_IRQ, sizeof(*irq_notifc));
75 if (!irq_notifc) {
76 ret = -ENOMEM;
77 goto out_fail;
78 }
79 irq_notifc->intr_vector = irq;
80 init_notific(&irq_notifc->notifc);
81 irq_notifc->user_handler_ready = 0;
82
83 irq_notifc_cap = cap_alloc(current_cap_group, irq_notifc);
84 if (irq_notifc_cap < 0) {
85 ret = irq_notifc_cap;
86 goto out_free_obj;
87 }
88
89 irq_notifcs[irq] = irq_notifc;
90 smp_mb();
91 irq_handle_type[irq] = HANDLE_USER;
92
93 return irq_notifc_cap;
94 out_free_obj:
95 obj_free(irq_notifc);
96 out_fail:
97 return ret;
98 }
99
sys_irq_stop(cap_t irq_cap)100 int sys_irq_stop(cap_t irq_cap)
101 {
102 struct irq_notification *irq_notifc = NULL;
103 int ret = 0;
104 irq_notifc = obj_get(current_thread->cap_group, irq_cap, TYPE_IRQ);
105 if (!irq_notifc) {
106 ret = -ECAPBILITY;
107 goto out;
108 }
109
110 ret = stop_irq_notific(irq_notifc);
111
112 out:
113 return ret;
114 }
115
sys_irq_wait(cap_t irq_cap,bool is_block)116 int sys_irq_wait(cap_t irq_cap, bool is_block)
117 {
118 struct irq_notification *irq_notifc = NULL;
119 int ret = 0;
120 irq_notifc = obj_get(current_thread->cap_group, irq_cap, TYPE_IRQ);
121 if (!irq_notifc) {
122 ret = -ECAPBILITY;
123 goto out;
124 }
125
126 /*
127 * When the interrupt handler thread calls this function,
128 * we enable the corresponding irq.
129 */
130 arch_enable_irqno(irq_notifc->intr_vector);
131 ret = wait_irq_notific(irq_notifc);
132 if (ret) {
133 goto out;
134 }
135
136 /* Never returns */
137 BUG_ON(1);
138
139 out:
140 return ret;
141 }
142
sys_irq_ack(cap_t irq_cap)143 int sys_irq_ack(cap_t irq_cap)
144 {
145 struct irq_notification *irq_notifc = NULL;
146 int ret = 0;
147 irq_notifc = obj_get(current_thread->cap_group, irq_cap, TYPE_IRQ);
148 if (!irq_notifc) {
149 ret = -ECAPBILITY;
150 goto out;
151 }
152 plat_ack_irq(irq_notifc->intr_vector);
153 obj_put(irq_notifc);
154 out:
155 return ret;
156 }
157
sys_disable_irqno(int irq)158 int sys_disable_irqno(int irq)
159 {
160 plat_disable_irqno(irq);
161 return 0;
162 }
163
sys_enable_irqno(int irq)164 int sys_enable_irqno(int irq)
165 {
166 plat_enable_irqno(irq);
167 return 0;
168 }
169
sys_irq_op(int irq,int op,long val)170 int sys_irq_op(int irq, int op, long val)
171 {
172 extern int gicv3_op(int irq, int op, long val);
173 return gicv3_op(irq, op, val);
174 }