]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/sun4v/sun4v/intr_machdep.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / sun4v / sun4v / intr_machdep.c
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * William Jolitz.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 4. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 /*-
33  * Copyright (c) 2001 Jake Burkholder.
34  * All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  *
45  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
46  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
49  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55  * SUCH DAMAGE.
56  *
57  *      from: @(#)isa.c 7.2 (Berkeley) 5/13/91
58  *      form: src/sys/i386/isa/intr_machdep.c,v 1.57 2001/07/20
59  */
60
61 #include <sys/cdefs.h>
62 __FBSDID("$FreeBSD$");
63
64 #include <sys/param.h>
65 #include <sys/systm.h>
66 #include <sys/types.h>
67 #include <sys/malloc.h>
68 #include <sys/bus.h>
69 #include <sys/errno.h>
70 #include <sys/interrupt.h>
71 #include <sys/kernel.h>
72 #include <sys/ktr.h>
73 #include <sys/lock.h>
74 #include <sys/mutex.h>
75 #include <sys/pcpu.h>
76 #include <sys/proc.h>
77 #include <sys/smp.h>
78 #include <sys/vmmeter.h>
79
80 #include <machine/frame.h>
81 #include <machine/intr_machdep.h>
82 #include <machine/cpu.h>
83 #include <machine/smp.h>
84
85 #include <machine/hypervisorvar.h>
86 #include <machine/hv_api.h>
87
88 #include <vm/vm.h>
89 #include <vm/pmap.h>
90
91 #define PANIC_IF(exp) if (unlikely(exp)) {panic("%s: %s:%d", #exp, __FILE__, __LINE__);}
92
93 #define MAX_STRAY_LOG   5
94
95 CTASSERT((1 << IV_SHIFT) == sizeof(struct intr_vector));
96
97 ih_func_t *intr_handlers[PIL_MAX];
98 uint16_t pil_countp[PIL_MAX];
99
100 struct intr_vector intr_vectors[IV_MAX];
101 uint16_t intr_countp[IV_MAX];
102 static u_long intr_stray_count[IV_MAX];
103
104 struct ithread_vector_handler {
105         iv_func_t *ivh_handler;
106         void *ivh_arg;
107         u_int ivh_vec;
108 };
109
110 static char *pil_names[] = {
111         "stray",
112         "low",          /* PIL_LOW */
113         "ithrd",        /* PIL_ITHREAD */
114         "rndzvs",       /* PIL_RENDEZVOUS */
115         "ast",          /* PIL_AST */
116         "stop",         /* PIL_STOP */
117         "preempt",      /* PIL_PREEMPT */
118         "stray", "stray", "stray", "stray", "stray", "stray",
119         "fast",         /* PIL_FAST */
120         "tick",         /* PIL_TICK */
121 };
122         
123  
124 /*
125  * XXX SUN4V_FIXME - the queue size values should
126  * really be calculated based on the size of the partition
127  *
128  */
129
130 int cpu_q_entries = 128;
131 int dev_q_entries = 128;
132
133 static vm_offset_t *mondo_data_array;
134 static vm_offset_t *cpu_list_array;
135 static vm_offset_t *cpu_q_array;
136 static vm_offset_t *dev_q_array;
137 static vm_offset_t *rq_array;
138 static vm_offset_t *nrq_array;
139 static int cpu_list_size;
140
141
142
143 /* protect the intr_vectors table */
144 static struct mtx intr_table_lock;
145
146 static void intr_execute_handlers(void *);
147 static void intr_stray_level(struct trapframe *);
148 static void  intr_stray_vector(void *);
149 static int  intrcnt_setname(const char *, int);
150 static void intrcnt_updatename(int, const char *, int);
151 static void cpu_intrq_alloc(void);
152
153 /*
154  * not MPSAFE
155  */
156 static void
157 intrcnt_updatename(int vec, const char *name, int ispil)
158 {
159         static int intrcnt_index, stray_pil_index, stray_vec_index;
160         int name_index;
161
162         if (intrnames[0] == '\0') {
163                 /* for bitbucket */
164                 if (bootverbose)
165                         printf("initalizing intr_countp\n");
166                 intrcnt_setname("???", intrcnt_index++);
167
168                 stray_vec_index = intrcnt_index++;
169                 intrcnt_setname("stray", stray_vec_index);
170                 for (name_index = 0; name_index < IV_MAX; name_index++)
171                         intr_countp[name_index] = stray_vec_index;
172
173                 stray_pil_index = intrcnt_index++;
174                 intrcnt_setname("pil", stray_pil_index);
175                 for (name_index = 0; name_index < PIL_MAX; name_index++)
176                         pil_countp[name_index] = stray_pil_index;
177         }
178
179         if (name == NULL)
180                 name = "???";
181
182         if (!ispil && intr_countp[vec] != stray_vec_index)
183                 name_index = intr_countp[vec];
184         else if (ispil && pil_countp[vec] != stray_pil_index)
185                 name_index = pil_countp[vec];
186         else
187                 name_index = intrcnt_index++;
188
189         if (intrcnt_setname(name, name_index))
190                 name_index = 0;
191
192         if (!ispil)
193                 intr_countp[vec] = name_index;
194         else
195                 pil_countp[vec] = name_index;
196 }
197
198 static int
199 intrcnt_setname(const char *name, int index)
200 {
201
202         if (intrnames + (MAXCOMLEN + 1) * index >= eintrnames)
203                 return (E2BIG);
204         snprintf(intrnames + (MAXCOMLEN + 1) * index, MAXCOMLEN + 1, "%-*s",
205             MAXCOMLEN, name);
206         return (0);
207 }
208
209 void
210 intr_setup(int pri, ih_func_t *ihf, int vec, iv_func_t *ivf, void *iva)
211 {
212         char pilname[MAXCOMLEN + 1];
213         u_long ps;
214
215         ps = intr_disable_all();
216         if (vec != -1) {
217                 intr_vectors[vec].iv_func = ivf;
218                 intr_vectors[vec].iv_arg = iva;
219                 intr_vectors[vec].iv_pri = pri;
220                 intr_vectors[vec].iv_vec = vec;
221         }
222         snprintf(pilname, MAXCOMLEN + 1, "pil%d: %s", pri, pil_names[pri]);
223         intrcnt_updatename(pri, pilname, 1);
224         intr_handlers[pri] = ihf;
225         intr_restore_all(ps);
226 }
227
228 static void
229 intr_stray_level(struct trapframe *tf)
230 {
231
232         printf("stray level interrupt - pil=%ld\n", tf->tf_pil);
233 }
234
235 static void
236 intr_stray_vector(void *cookie)
237 {
238         struct intr_vector *iv;
239
240         iv = cookie;
241         if (intr_stray_count[iv->iv_vec] < MAX_STRAY_LOG) {
242                 printf("stray vector interrupt %d\n", iv->iv_vec);
243                 intr_stray_count[iv->iv_vec]++;
244                 if (intr_stray_count[iv->iv_vec] >= MAX_STRAY_LOG)
245                         printf("got %d stray interrupt %d's: not logging "
246                             "anymore\n", MAX_STRAY_LOG, iv->iv_vec);
247         }
248 }
249
250 static void
251 intr_init(void)
252 {
253         int i;
254
255         /* Mark all interrupts as being stray. */
256         for (i = 0; i < PIL_MAX; i++)
257                 intr_handlers[i] = intr_stray_level;
258         for (i = 0; i < IV_MAX; i++) {
259                 intr_vectors[i].iv_func = intr_stray_vector;
260                 intr_vectors[i].iv_arg = &intr_vectors[i];
261                 intr_vectors[i].iv_pri = PIL_LOW;
262                 intr_vectors[i].iv_vec = i;
263         }
264         intr_handlers[PIL_LOW] = intr_fast;
265         
266 #ifdef SMP
267         intr_handlers[PIL_AST] = cpu_ipi_ast;
268         intr_handlers[PIL_RENDEZVOUS] = (ih_func_t *)smp_rendezvous_action;
269         intr_handlers[PIL_STOP]= cpu_ipi_stop;
270         intr_handlers[PIL_PREEMPT]= cpu_ipi_preempt;
271 #endif
272         mtx_init(&intr_table_lock, "intr table", NULL, MTX_SPIN);
273         cpu_intrq_alloc();
274         cpu_intrq_init();
275
276 }
277 SYSINIT(intr_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_init, NULL);
278
279
280 static void
281 intr_execute_handlers(void *cookie)
282 {
283         struct intr_vector *iv;
284         struct intr_event *ie;
285         struct intr_handler *ih;
286         int fast, thread, ret;
287
288         iv = cookie;
289         ie = iv->iv_event;
290         if (ie == NULL) {
291                 intr_stray_vector(iv);
292                 return;
293         }
294         
295         ret = 0;
296         fast = thread = 0;
297         TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) {
298                 if (ih->ih_filter == NULL) {
299                         thread = 1;
300                         continue;
301                 }
302                 MPASS(ih->ih_filter != NULL && ih->ih_argument != NULL);
303                 CTR3(KTR_INTR, "%s: executing handler %p(%p)", __func__,
304                     ih->ih_filter, ih->ih_argument);
305                 ret = ih->ih_filter(ih->ih_argument);
306                 fast = 1;
307                 /*
308                  * Wrapper handler special case: see
309                  * i386/intr_machdep.c::intr_execute_handlers()
310                  */
311                 if (!thread) {
312                         if (ret == FILTER_SCHEDULE_THREAD)
313                                 thread = 1;
314                 }
315         }
316
317         /* Schedule a heavyweight interrupt process. */
318         if (thread) 
319                 intr_event_schedule_thread(ie);
320         else if (TAILQ_EMPTY(&ie->ie_handlers))
321                 intr_stray_vector(iv);
322
323         if (fast)
324                 hv_intr_setstate(iv->iv_vec, HV_INTR_IDLE_STATE);
325
326 }
327
328 static void
329 ithread_wrapper(void *arg)
330 {
331         struct ithread_vector_handler *ivh = (struct ithread_vector_handler *)arg;
332         
333         ivh->ivh_handler(ivh->ivh_arg);
334         /* re-enable interrupt */
335         hv_intr_setstate(ivh->ivh_vec, HV_INTR_IDLE_STATE);
336 }
337
338 int
339 inthand_add(const char *name, int vec, driver_filter_t *filt, 
340     void (*handler)(void *), void *arg, int flags, void **cookiep)    
341 {
342         struct intr_vector *iv;
343         struct intr_event *ie;          /* descriptor for the IRQ */
344         struct intr_event *orphan;
345         struct ithread_vector_handler *ivh;
346         int errcode, pil;
347
348         if (filt != NULL && handler != NULL) {
349                 printf("both filt and handler set is not valid\n");
350                 return (EINVAL);
351         }
352         /*
353          * Work around a race where more than one CPU may be registering
354          * handlers on the same IRQ at the same time.
355          */
356         iv = &intr_vectors[vec];
357         mtx_lock_spin(&intr_table_lock);
358         ie = iv->iv_event;
359         mtx_unlock_spin(&intr_table_lock);
360         if (ie == NULL) {
361                 errcode = intr_event_create(&ie, (void *)(intptr_t)vec, 0, NULL,
362                     NULL, "vec%d:", vec);
363                 if (errcode)
364                         return (errcode);
365                 mtx_lock_spin(&intr_table_lock);
366                 if (iv->iv_event == NULL) {
367                         iv->iv_event = ie;
368                         mtx_unlock_spin(&intr_table_lock);
369                 } else {
370                         orphan = ie;
371                         ie = iv->iv_event;
372                         mtx_unlock_spin(&intr_table_lock);
373                         intr_event_destroy(orphan);
374                 }
375         }
376
377         if (filt == NULL) {
378                 ivh = (struct ithread_vector_handler *)
379                         malloc(sizeof(struct ithread_vector_handler), M_DEVBUF, M_WAITOK);
380                 ivh->ivh_handler = (driver_intr_t *)handler;
381                 ivh->ivh_arg = arg;
382                 ivh->ivh_vec = vec;
383                 errcode = intr_event_add_handler(ie, name, NULL, ithread_wrapper, ivh,
384                                                  intr_priority(flags), flags, cookiep);
385         } else {
386                 ivh = NULL;
387                 errcode = intr_event_add_handler(ie, name, filt, NULL, arg,
388                                                  intr_priority(flags), flags, 
389                                                  cookiep);
390         }
391
392         if (errcode) {
393                 if (ivh)
394                         free(ivh, M_DEVBUF);
395                 return (errcode);
396         }
397         pil = (filt != NULL) ? PIL_FAST : PIL_ITHREAD;
398
399         intr_setup(pil, intr_fast, vec, intr_execute_handlers, iv);
400
401         intr_stray_count[vec] = 0;
402
403         intrcnt_updatename(vec, ie->ie_fullname, 0);
404
405         return (0);
406 }
407
408 int
409 inthand_remove(int vec, void *cookie)
410 {
411         struct intr_vector *iv;
412         int error;
413         
414         error = intr_event_remove_handler(cookie);
415         if (error == 0) {
416                 /*
417                  * XXX: maybe this should be done regardless of whether
418                  * intr_event_remove_handler() succeeded?
419                  * XXX: aren't the PIL's backwards below?
420                  */
421                 iv = &intr_vectors[vec];
422                 mtx_lock_spin(&intr_table_lock);
423                 if (iv->iv_event == NULL)
424                         intr_setup(PIL_ITHREAD, intr_fast, vec,
425                             intr_stray_vector, iv);
426                 else
427                         intr_setup(PIL_LOW, intr_fast, vec,
428                             intr_execute_handlers, iv);
429                 mtx_unlock_spin(&intr_table_lock);
430         }
431         return (error);
432 }
433
434 /* 
435  * Allocate and register intrq fields
436  */
437 static void 
438 cpu_intrq_alloc(void)
439 {
440         
441         mondo_data_array = malloc(INTR_REPORT_SIZE*MAXCPU, M_DEVBUF, M_WAITOK | M_ZERO);
442         PANIC_IF(mondo_data_array == NULL);
443
444         cpu_list_size = CPU_LIST_SIZE > INTR_REPORT_SIZE ? CPU_LIST_SIZE : INTR_REPORT_SIZE;
445         cpu_list_array = malloc(cpu_list_size*MAXCPU, M_DEVBUF, M_WAITOK | M_ZERO);
446         PANIC_IF(cpu_list_array == NULL);
447         
448         cpu_q_array = malloc(INTR_CPU_Q_SIZE*MAXCPU, M_DEVBUF, M_WAITOK | M_ZERO);
449         PANIC_IF(cpu_q_array == NULL);
450         
451         dev_q_array = malloc(INTR_DEV_Q_SIZE*MAXCPU, M_DEVBUF, M_WAITOK | M_ZERO);
452         PANIC_IF(dev_q_array == NULL);
453
454         rq_array = malloc(2*CPU_RQ_SIZE*MAXCPU, M_DEVBUF, M_WAITOK | M_ZERO);
455         PANIC_IF(rq_array == NULL);
456         
457         nrq_array = malloc(2*CPU_NRQ_SIZE*MAXCPU, M_DEVBUF, M_WAITOK | M_ZERO);
458         PANIC_IF(nrq_array == NULL);
459
460 }
461
462 void 
463 cpu_intrq_init()
464 {
465
466         uint64_t error;
467
468         pcpup->pc_mondo_data = (vm_offset_t *) ((char *)mondo_data_array + curcpu*INTR_REPORT_SIZE);
469         pcpup->pc_mondo_data_ra = vtophys(pcpup->pc_mondo_data);
470
471         pcpup->pc_cpu_q = (vm_offset_t *)((char *)cpu_q_array + curcpu*INTR_CPU_Q_SIZE);
472
473         pcpup->pc_cpu_q_ra = vtophys(pcpup->pc_cpu_q);
474         pcpup->pc_cpu_q_size = INTR_CPU_Q_SIZE;
475
476         pcpup->pc_dev_q = (vm_offset_t *)((char *)dev_q_array + curcpu*INTR_DEV_Q_SIZE);
477         pcpup->pc_dev_q_ra = vtophys(pcpup->pc_dev_q);
478         pcpup->pc_dev_q_size = INTR_DEV_Q_SIZE;
479
480         pcpup->pc_rq = (vm_offset_t *)((char *)rq_array + curcpu*2*CPU_RQ_SIZE);
481         pcpup->pc_rq_ra = vtophys(pcpup->pc_rq);
482         pcpup->pc_rq_size = CPU_RQ_SIZE;
483
484         pcpup->pc_nrq = (vm_offset_t *)((char *)nrq_array + curcpu*2*CPU_NRQ_SIZE);
485         pcpup->pc_nrq_ra = vtophys(pcpup->pc_nrq);
486         pcpup->pc_nrq_size = CPU_NRQ_SIZE;
487
488
489         error = hv_cpu_qconf(Q(CPU_MONDO_QUEUE_HEAD), pcpup->pc_cpu_q_ra, cpu_q_entries);
490         if (error != H_EOK)
491                 panic("cpu_mondo queue configuration failed: %lu va=%p ra=0x%lx", error,
492                       pcpup->pc_cpu_q, pcpup->pc_cpu_q_ra);
493
494         error = hv_cpu_qconf(Q(DEV_MONDO_QUEUE_HEAD), pcpup->pc_dev_q_ra, dev_q_entries);
495         if (error != H_EOK)
496                 panic("dev_mondo queue configuration failed: %lu", error);
497
498         error = hv_cpu_qconf(Q(RESUMABLE_ERROR_QUEUE_HEAD), pcpup->pc_rq_ra, CPU_RQ_ENTRIES);
499         if (error != H_EOK)
500                 panic("resumable error queue configuration failed: %lu", error);
501
502         error = hv_cpu_qconf(Q(NONRESUMABLE_ERROR_QUEUE_HEAD), pcpup->pc_nrq_ra, CPU_NRQ_ENTRIES);
503         if (error != H_EOK)
504                 panic("non-resumable error queue configuration failed: %lu", error);
505
506 }