xref: /netbsd-src/sys/arch/ia64/ia64/interrupt.c (revision 6ec65fcfd4fc14dd006a1488ebb10c8b067ba270)
1 /* $NetBSD: interrupt.c,v 1.12 2023/10/06 11:45:16 skrll Exp $ */
2 
3 /*-
4  * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
5  * All rights reserved.
6  *
7  * Authors: Keith Bostic, Chris G. Demetriou
8  *
9  * Permission to use, copy, modify and distribute this software and
10  * its documentation is hereby granted, provided that both the copyright
11  * notice and this permission notice appear in all copies of the
12  * software, derivative works or modified versions, and any portions
13  * thereof, and that both notices appear in supporting documentation.
14  *
15  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
17  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18  *
19  * Carnegie Mellon requests users of this software to return to
20  *
21  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
22  *  School of Computer Science
23  *  Carnegie Mellon University
24  *  Pittsburgh PA 15213-3890
25  *
26  * any improvements or extensions that they make and grant Carnegie the
27  * rights to redistribute these changes.
28  */
29 /*-
30  * Additional Copyright (c) 1997 by Matthew Jacob for NASA/Ames Research Center.
31  * Redistribute and modify at will, leaving only this additional copyright
32  * notice.
33  */
34 
35 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
36 __KERNEL_RCSID(0, "$NetBSD: interrupt.c,v 1.12 2023/10/06 11:45:16 skrll Exp $");
37 
38 #include "opt_ddb.h"
39 
40 #include <sys/param.h>
41 #include <sys/evcnt.h>
42 #include <sys/lwp.h>
43 #include <sys/proc.h>
44 #include <sys/kmem.h>
45 #include <sys/sched.h>
46 
47 #include <machine/clock.h>
48 #include <machine/cpu.h>
49 #include <machine/cpufunc.h>
50 #include <machine/fpu.h>
51 #include <machine/frame.h>
52 #include <machine/intr.h>
53 #include <machine/md_var.h>
54 #include <machine/sapicvar.h>
55 #include <machine/smp.h>
56 #include <machine/userret.h>
57 
58 #ifdef DDB
59 #include <ddb/ddb.h>
60 #endif
61 
62 
63 static void ia64_intr_eoi(void *);
64 static void ia64_intr_mask(void *);
65 #if 0
66 static void ia64_intr_unmask(void *);
67 #endif
68 static int ia64_dispatch_intr(void *, u_int);
69 
70 #ifdef DDB
71 void db_print_vector(u_int, int);
72 #endif
73 
74 
75 int
interrupt(uint64_t vector,struct trapframe * tf)76 interrupt(uint64_t vector, struct trapframe *tf)
77 {
78 	struct cpu_info *ci = curcpu();
79 	volatile struct ia64_interrupt_block *ib = IA64_INTERRUPT_BLOCK;
80 	uint64_t adj, clk, itc;
81 	int64_t delta;
82 	uint8_t inta;
83 	int count, handled = 0;
84 
85 	ia64_set_fpsr(IA64_FPSR_DEFAULT);
86 
87 	ci->ci_intrdepth++;
88 	ci->ci_data.cpu_nintr++;
89 
90  next:
91 	/*
92 	 * Handle ExtINT interrupts by generating an INTA cycle to
93 	 * read the vector.
94 	 */
95 	if (vector == 0) {
96 		inta = ib->ib_inta;
97 		printf("ExtINT interrupt: vector=%u\n", (int)inta);
98 		if (inta == 15) {
99 			__asm __volatile("mov cr.eoi = r0;; srlz.d");
100 			goto stray;
101 		}
102 		vector = (int)inta;
103 	} else if (vector == 15)
104 		goto stray;
105 
106 	if (vector == CLOCK_VECTOR) {/* clock interrupt */
107 		itc = ia64_get_itc();
108 
109 		adj = ci->ci_clockadj;
110 		clk = ci->ci_clock;
111 		delta = itc - clk;
112 		count = 0;
113 		while (delta >= ia64_clock_reload) {
114 			/* Only the BSP runs the real clock */
115 			if (ci->ci_cpuid == 0)
116 				hardclock((struct clockframe *)tf);
117 			else
118 				panic("CLOCK_VECTOR occur on not cpu0");
119 			delta -= ia64_clock_reload;
120 			clk += ia64_clock_reload;
121 			count++;
122 			handled = 1;
123 		}
124 		ia64_set_itm(ia64_get_itc() + ia64_clock_reload - adj);
125 		if (count > 0) {
126 			if (delta > (ia64_clock_reload >> 3)) {
127 				adj = ia64_clock_reload >> 4;
128 			} else
129 				adj = 0;
130 		} else
131 			adj = 0;
132 		ci->ci_clock = clk;
133 		ci->ci_clockadj = adj;
134 		ia64_srlz_d();
135 
136 #ifdef MULTIPROCESSOR
137 	} else if (vector == ipi_vector[IPI_AST]) {
138 		asts[PCPU_GET(cpuid)]++;
139 		CTR1(KTR_SMP, "IPI_AST, cpuid=%d", PCPU_GET(cpuid));
140 	} else if (vector == ipi_vector[IPI_HIGH_FP]) {
141 		struct thread *thr = PCPU_GET(fpcurthread);
142 
143 		if (thr != NULL) {
144 			mtx_lock_spin(&thr->td_md.md_highfp_mtx);
145 			save_high_fp(&thr->td_pcb->pcb_high_fp);
146 			thr->td_pcb->pcb_fpcpu = NULL;
147 			PCPU_SET(fpcurthread, NULL);
148 			mtx_unlock_spin(&thr->td_md.md_highfp_mtx);
149 		}
150 	} else if (vector == ipi_vector[IPI_RENDEZVOUS]) {
151 		rdvs[PCPU_GET(cpuid)]++;
152 		CTR1(KTR_SMP, "IPI_RENDEZVOUS, cpuid=%d", PCPU_GET(cpuid));
153 		enable_intr();
154 		smp_rendezvous_action();
155 		disable_intr();
156 	} else if (vector == ipi_vector[IPI_STOP]) {
157 		cpumask_t mybit = PCPU_GET(cpumask);
158 
159 		savectx(PCPU_PTR(pcb));
160 		atomic_set_int(&stopped_cpus, mybit);
161 		while ((started_cpus & mybit) == 0)
162 			cpu_spinwait();
163 		atomic_clear_int(&started_cpus, mybit);
164 		atomic_clear_int(&stopped_cpus, mybit);
165 	} else if (vector == ipi_vector[IPI_PREEMPT]) {
166 		CTR1(KTR_SMP, "IPI_PREEMPT, cpuid=%d", PCPU_GET(cpuid));
167 		__asm __volatile("mov cr.eoi = r0;; srlz.d");
168 		enable_intr();
169 		sched_preempt(curthread);
170 		disable_intr();
171 		goto stray;
172 #endif
173 	} else {
174 		ci->ci_intrdepth++;
175 		handled = ia64_dispatch_intr(tf, vector);
176 		ci->ci_intrdepth--;
177 	}
178 
179 	__asm __volatile("mov cr.eoi = r0;; srlz.d");
180 	vector = ia64_get_ivr();
181 	if (vector != 15)
182 		goto next;
183 
184 stray:
185 	if (TRAPF_USERMODE(tf)) {
186 		enable_intr();
187 		userret(curlwp);
188 		do_ast(tf);
189 	}
190 	ci->ci_intrdepth--;
191 	return handled;
192 }
193 
194 
195 /*
196  * Hardware irqs have vectors starting at this offset.
197  */
198 #define IA64_HARDWARE_IRQ_BASE	0x20
199 
200 struct ia64_intrhand {
201 	int (*ih_func)(void *);
202 	void *ih_arg;
203 	LIST_ENTRY(ia64_intrhand) ih_q;
204 	int ih_level;
205 	int ih_irq;
206 };
207 struct ia64_intr {
208 	u_int irq;
209 	struct sapic *sapic;
210 	int type;
211 
212 	LIST_HEAD(, ia64_intrhand) intr_q;
213 
214 	char evname[32];
215 	struct evcnt evcnt;
216 };
217 
218 static struct ia64_intr *ia64_intrs[256];
219 
220 
221 static void
ia64_intr_eoi(void * arg)222 ia64_intr_eoi(void *arg)
223 {
224 	u_int vector = (uintptr_t)arg;
225 	struct ia64_intr *i;
226 
227 	i = ia64_intrs[vector];
228 	if (i != NULL)
229 		sapic_eoi(i->sapic, vector);
230 }
231 
232 static void
ia64_intr_mask(void * arg)233 ia64_intr_mask(void *arg)
234 {
235 	u_int vector = (uintptr_t)arg;
236 	struct ia64_intr *i;
237 
238 	i = ia64_intrs[vector];
239 	if (i != NULL) {
240 		sapic_mask(i->sapic, i->irq);
241 		sapic_eoi(i->sapic, vector);
242 	}
243 }
244 
245 #if 0
246 static void
247 ia64_intr_unmask(void *arg)
248 {
249 	u_int vector = (uintptr_t)arg;
250 	struct ia64_intr *i;
251 
252 	i = ia64_intrs[vector];
253 	if (i != NULL)
254 		sapic_unmask(i->sapic, i->irq);
255 }
256 #endif
257 
258 void *
intr_establish_xname(int irq,int type,int level,int (* func)(void *),void * arg,const char * xname)259 intr_establish_xname(int irq, int type, int level, int (*func)(void *),
260     void *arg, const char *xname)
261 {
262 	/* TODO: xname support */
263 	return intr_establish(irq, type, level, func, arg);
264 }
265 
266 void *
intr_establish(int irq,int type,int level,int (* func)(void *),void * arg)267 intr_establish(int irq, int type, int level, int (*func)(void *), void *arg)
268 {
269 	struct ia64_intr *i;
270 	struct ia64_intrhand *ih;
271 	struct sapic *sa;
272 	u_int vector;
273 
274 	/* Get the I/O SAPIC that corresponds to the IRQ. */
275 	sa = sapic_lookup(irq);
276 	if (sa == NULL)
277 		return NULL;
278 
279 	switch (type) {
280 	case IST_EDGE:
281 	case IST_LEVEL:
282 		break;
283 
284 	default:
285 		return NULL;
286 	}
287 
288 	/*
289 	 * XXX - There's a priority implied by the choice of vector.
290 	 * We should therefore relate the vector to the interrupt type.
291 	 */
292 	vector = irq + IA64_HARDWARE_IRQ_BASE;
293 
294 	i = ia64_intrs[vector];
295 	if (i == NULL) {
296 		i = kmem_alloc(sizeof(struct ia64_intr), KM_SLEEP);
297 		i->irq = irq;
298 		i->sapic = sa;
299 		i->type = type;
300 		LIST_INIT(&i->intr_q);
301 		snprintf(i->evname, sizeof(i->evname), "irq %d", irq);
302 		evcnt_attach_dynamic(&i->evcnt, EVCNT_TYPE_INTR, NULL,
303 		    "iosapic", i->evname);
304 		ia64_intrs[vector] = i;
305 
306 		sapic_config_intr(irq, type);
307 		sapic_enable(i->sapic, irq, vector);
308 	} else
309 		if (i->type != type)
310 			return NULL;
311 
312 	ih = kmem_alloc(sizeof(*ih), KM_SLEEP);
313 	ih->ih_func = func;
314 	ih->ih_arg = arg;
315 	ih->ih_level = level;
316 	ih->ih_irq = irq;
317 	LIST_INSERT_HEAD(&i->intr_q, ih, ih_q);
318 
319 	return ih;
320 }
321 
322 void
intr_disestablish(void * cookie)323 intr_disestablish(void *cookie)
324 {
325 	struct ia64_intr *i;
326 	struct ia64_intrhand *ih = cookie;
327 	u_int vector = ih->ih_irq + IA64_HARDWARE_IRQ_BASE;
328 
329 	i = ia64_intrs[vector];
330 
331 	LIST_REMOVE(ih, ih_q);
332 	if (LIST_FIRST(&i->intr_q) == NULL) {
333 		ia64_intr_mask((void *)(uintptr_t)vector);
334 
335 		ia64_intrs[vector] = NULL;
336 		evcnt_detach(&i->evcnt);
337 		kmem_free(i, sizeof(*i));
338 	}
339 
340 	kmem_free(ih, sizeof(*ih));
341 }
342 
343 static int
ia64_dispatch_intr(void * frame,u_int vector)344 ia64_dispatch_intr(void *frame, u_int vector)
345 {
346 	struct ia64_intr *i;
347 	struct ia64_intrhand *ih;
348 	int handled = 0;
349 
350 	/*
351 	 * Find the interrupt thread for this vector.
352 	 */
353 	i = ia64_intrs[vector];
354 	KASSERT(i != NULL);
355 
356 	i->evcnt.ev_count++;
357 
358 	LIST_FOREACH(ih, &i->intr_q, ih_q) {
359 		if (__predict_false(ih->ih_func == NULL))
360 			printf("%s: spurious interrupt (irq = %d)\n",
361 			    __func__, ih->ih_irq);
362 		else if (__predict_true((*ih->ih_func)(ih->ih_arg)))
363 			handled = 1;
364 	}
365 	ia64_intr_eoi((void *)(uintptr_t)vector);
366 
367 	return handled;
368 }
369 
370 void
ia64_handle_intr(void * tf)371 ia64_handle_intr(void *tf)
372 {
373 	panic("XXX %s not implemented", __func__);
374 }
375 
376 #ifdef DDB
377 void
db_print_vector(u_int vector,int always)378 db_print_vector(u_int vector, int always)
379 {
380 	struct ia64_intr *i;
381 
382 	i = ia64_intrs[vector];
383 	if (i != NULL) {
384 		db_printf("vector %u (%p): ", vector, i);
385 		sapic_print(i->sapic, i->irq);
386 	} else if (always)
387 		db_printf("vector %u: unassigned\n", vector);
388 }
389 
390 const char *
intr_string(intr_handle_t ih,char * buf,size_t len)391 intr_string(intr_handle_t ih, char *buf, size_t len)
392 {
393 	panic("XXX %s not implemented", __func__);
394 }
395 #endif
396