]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/sun4v/sun4v/intr_machdep.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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 static char *pil_names[] = {
105         "stray",
106         "low",          /* PIL_LOW */
107         "ithrd",        /* PIL_ITHREAD */
108         "rndzvs",       /* PIL_RENDEZVOUS */
109         "ast",          /* PIL_AST */
110         "stop",         /* PIL_STOP */
111         "preempt",      /* PIL_PREEMPT */
112         "stray", "stray", "stray", "stray", "stray", "stray",
113         "fast",         /* PIL_FAST */
114         "tick",         /* PIL_TICK */
115 };
116         
117  
118 /*
119  * XXX SUN4V_FIXME - the queue size values should
120  * really be calculated based on the size of the partition
121  *
122  */
123
124 int cpu_q_entries = 128;
125 int dev_q_entries = 128;
126
127 static vm_offset_t *mondo_data_array;
128 static vm_offset_t *cpu_list_array;
129 static vm_offset_t *cpu_q_array;
130 static vm_offset_t *dev_q_array;
131 static vm_offset_t *rq_array;
132 static vm_offset_t *nrq_array;
133 static int cpu_list_size;
134
135
136
137 /* protect the intr_vectors table */
138 static struct mtx intr_table_lock;
139
140 static void intr_execute_handlers(void *);
141 static void intr_stray_level(struct trapframe *);
142 static void  intr_stray_vector(void *);
143 static int  intrcnt_setname(const char *, int);
144 static void intrcnt_updatename(int, const char *, int);
145 static void cpu_intrq_alloc(void);
146
147 /*
148  * not MPSAFE
149  */
150 static void
151 intrcnt_updatename(int vec, const char *name, int ispil)
152 {
153         static int intrcnt_index, stray_pil_index, stray_vec_index;
154         int name_index;
155
156         if (intrnames[0] == '\0') {
157                 /* for bitbucket */
158                 if (bootverbose)
159                         printf("initalizing intr_countp\n");
160                 intrcnt_setname("???", intrcnt_index++);
161
162                 stray_vec_index = intrcnt_index++;
163                 intrcnt_setname("stray", stray_vec_index);
164                 for (name_index = 0; name_index < IV_MAX; name_index++)
165                         intr_countp[name_index] = stray_vec_index;
166
167                 stray_pil_index = intrcnt_index++;
168                 intrcnt_setname("pil", stray_pil_index);
169                 for (name_index = 0; name_index < PIL_MAX; name_index++)
170                         pil_countp[name_index] = stray_pil_index;
171         }
172
173         if (name == NULL)
174                 name = "???";
175
176         if (!ispil && intr_countp[vec] != stray_vec_index)
177                 name_index = intr_countp[vec];
178         else if (ispil && pil_countp[vec] != stray_pil_index)
179                 name_index = pil_countp[vec];
180         else
181                 name_index = intrcnt_index++;
182
183         if (intrcnt_setname(name, name_index))
184                 name_index = 0;
185
186         if (!ispil)
187                 intr_countp[vec] = name_index;
188         else
189                 pil_countp[vec] = name_index;
190 }
191
192 static int
193 intrcnt_setname(const char *name, int index)
194 {
195
196         if (intrnames + (MAXCOMLEN + 1) * index >= eintrnames)
197                 return (E2BIG);
198         snprintf(intrnames + (MAXCOMLEN + 1) * index, MAXCOMLEN + 1, "%-*s",
199             MAXCOMLEN, name);
200         return (0);
201 }
202
203 void
204 intr_setup(int pri, ih_func_t *ihf, int vec, iv_func_t *ivf, void *iva)
205 {
206         char pilname[MAXCOMLEN + 1];
207         u_long ps;
208
209         ps = intr_disable_all();
210         if (vec != -1) {
211                 intr_vectors[vec].iv_func = ivf;
212                 intr_vectors[vec].iv_arg = iva;
213                 intr_vectors[vec].iv_pri = pri;
214                 intr_vectors[vec].iv_vec = vec;
215         }
216         snprintf(pilname, MAXCOMLEN + 1, "pil%d: %s", pri, pil_names[pri]);
217         intrcnt_updatename(pri, pilname, 1);
218         intr_handlers[pri] = ihf;
219         intr_restore_all(ps);
220 }
221
222 static void
223 intr_stray_level(struct trapframe *tf)
224 {
225
226         printf("stray level interrupt - pil=%ld\n", tf->tf_pil);
227 }
228
229 static void
230 intr_stray_vector(void *cookie)
231 {
232         struct intr_vector *iv;
233
234         iv = cookie;
235         if (intr_stray_count[iv->iv_vec] < MAX_STRAY_LOG) {
236                 printf("stray vector interrupt %d\n", iv->iv_vec);
237                 intr_stray_count[iv->iv_vec]++;
238                 if (intr_stray_count[iv->iv_vec] >= MAX_STRAY_LOG)
239                         printf("got %d stray interrupt %d's: not logging "
240                             "anymore\n", MAX_STRAY_LOG, iv->iv_vec);
241         }
242 }
243
244 static void
245 intr_init(void)
246 {
247         int i;
248
249         /* Mark all interrupts as being stray. */
250         for (i = 0; i < PIL_MAX; i++)
251                 intr_handlers[i] = intr_stray_level;
252         for (i = 0; i < IV_MAX; i++) {
253                 intr_vectors[i].iv_func = intr_stray_vector;
254                 intr_vectors[i].iv_arg = &intr_vectors[i];
255                 intr_vectors[i].iv_pri = PIL_LOW;
256                 intr_vectors[i].iv_vec = i;
257         }
258         intr_handlers[PIL_LOW] = intr_fast;
259         
260 #ifdef SMP
261         intr_handlers[PIL_AST] = cpu_ipi_ast;
262         intr_handlers[PIL_RENDEZVOUS] = (ih_func_t *)smp_rendezvous_action;
263         intr_handlers[PIL_STOP]= cpu_ipi_stop;
264         intr_handlers[PIL_PREEMPT]= cpu_ipi_preempt;
265 #endif
266         mtx_init(&intr_table_lock, "intr table", NULL, MTX_SPIN);
267         cpu_intrq_alloc();
268         cpu_intrq_init();
269
270 }
271 SYSINIT(intr_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_init, NULL);
272
273 static void
274 intr_enable(void *cookie)
275 {
276         int vec;
277
278         vec = (uintptr_t)cookie;
279         hv_intr_setstate(vec, HV_INTR_IDLE_STATE);
280 }
281
282 static void
283 intr_execute_handlers(void *cookie)
284 {
285         struct intr_vector *iv;
286
287         iv = cookie;
288         if (intr_event_handle(iv->iv_event, NULL) != 0)
289                 intr_stray_vector(iv);
290 }
291
292 int
293 inthand_add(const char *name, int vec, driver_filter_t *filt, 
294     void (*handler)(void *), void *arg, int flags, void **cookiep)    
295 {
296         struct intr_vector *iv;
297         struct intr_event *ie;          /* descriptor for the IRQ */
298         struct intr_event *orphan;
299         int errcode, pil;
300
301         /*
302          * Work around a race where more than one CPU may be registering
303          * handlers on the same IRQ at the same time.
304          */
305         iv = &intr_vectors[vec];
306         mtx_lock_spin(&intr_table_lock);
307         ie = iv->iv_event;
308         mtx_unlock_spin(&intr_table_lock);
309         if (ie == NULL) {
310                 errcode = intr_event_create(&ie, (void *)(intptr_t)vec, 0, vec,
311                     NULL, intr_enable, intr_enable, NULL, "vec%d:", vec);
312                 if (errcode)
313                         return (errcode);
314                 mtx_lock_spin(&intr_table_lock);
315                 if (iv->iv_event == NULL) {
316                         iv->iv_event = ie;
317                         mtx_unlock_spin(&intr_table_lock);
318                 } else {
319                         orphan = ie;
320                         ie = iv->iv_event;
321                         mtx_unlock_spin(&intr_table_lock);
322                         intr_event_destroy(orphan);
323                 }
324         }
325
326         errcode = intr_event_add_handler(ie, name, filt, handler, arg,
327             intr_priority(flags), flags, cookiep);
328
329         if (errcode)
330                 return (errcode);
331
332         pil = (filt != NULL) ? PIL_FAST : PIL_ITHREAD;
333
334         intr_setup(pil, intr_fast, vec, intr_execute_handlers, iv);
335
336         intr_stray_count[vec] = 0;
337
338         intrcnt_updatename(vec, ie->ie_fullname, 0);
339
340         return (0);
341 }
342
343 int
344 inthand_remove(int vec, void *cookie)
345 {
346         struct intr_vector *iv;
347         int error;
348         
349         error = intr_event_remove_handler(cookie);
350         if (error == 0) {
351                 /*
352                  * XXX: maybe this should be done regardless of whether
353                  * intr_event_remove_handler() succeeded?
354                  * XXX: aren't the PIL's backwards below?
355                  */
356                 iv = &intr_vectors[vec];
357                 mtx_lock_spin(&intr_table_lock);
358                 if (iv->iv_event == NULL)
359                         intr_setup(PIL_ITHREAD, intr_fast, vec,
360                             intr_stray_vector, iv);
361                 else
362                         intr_setup(PIL_LOW, intr_fast, vec,
363                             intr_execute_handlers, iv);
364                 mtx_unlock_spin(&intr_table_lock);
365         }
366         return (error);
367 }
368
369 /* 
370  * Allocate and register intrq fields
371  */
372 static void 
373 cpu_intrq_alloc(void)
374 {
375         
376         mondo_data_array = malloc(INTR_REPORT_SIZE*MAXCPU, M_DEVBUF, M_WAITOK | M_ZERO);
377         PANIC_IF(mondo_data_array == NULL);
378
379         cpu_list_size = CPU_LIST_SIZE > INTR_REPORT_SIZE ? CPU_LIST_SIZE : INTR_REPORT_SIZE;
380         cpu_list_array = malloc(cpu_list_size*MAXCPU, M_DEVBUF, M_WAITOK | M_ZERO);
381         PANIC_IF(cpu_list_array == NULL);
382         
383         cpu_q_array = malloc(INTR_CPU_Q_SIZE*MAXCPU, M_DEVBUF, M_WAITOK | M_ZERO);
384         PANIC_IF(cpu_q_array == NULL);
385         
386         dev_q_array = malloc(INTR_DEV_Q_SIZE*MAXCPU, M_DEVBUF, M_WAITOK | M_ZERO);
387         PANIC_IF(dev_q_array == NULL);
388
389         rq_array = malloc(2*CPU_RQ_SIZE*MAXCPU, M_DEVBUF, M_WAITOK | M_ZERO);
390         PANIC_IF(rq_array == NULL);
391         
392         nrq_array = malloc(2*CPU_NRQ_SIZE*MAXCPU, M_DEVBUF, M_WAITOK | M_ZERO);
393         PANIC_IF(nrq_array == NULL);
394
395 }
396
397 void 
398 cpu_intrq_init()
399 {
400
401         uint64_t error;
402
403         pcpup->pc_mondo_data = (vm_offset_t *) ((char *)mondo_data_array + curcpu*INTR_REPORT_SIZE);
404         pcpup->pc_mondo_data_ra = vtophys(pcpup->pc_mondo_data);
405
406         pcpup->pc_cpu_q = (vm_offset_t *)((char *)cpu_q_array + curcpu*INTR_CPU_Q_SIZE);
407
408         pcpup->pc_cpu_q_ra = vtophys(pcpup->pc_cpu_q);
409         pcpup->pc_cpu_q_size = INTR_CPU_Q_SIZE;
410
411         pcpup->pc_dev_q = (vm_offset_t *)((char *)dev_q_array + curcpu*INTR_DEV_Q_SIZE);
412         pcpup->pc_dev_q_ra = vtophys(pcpup->pc_dev_q);
413         pcpup->pc_dev_q_size = INTR_DEV_Q_SIZE;
414
415         pcpup->pc_rq = (vm_offset_t *)((char *)rq_array + curcpu*2*CPU_RQ_SIZE);
416         pcpup->pc_rq_ra = vtophys(pcpup->pc_rq);
417         pcpup->pc_rq_size = CPU_RQ_SIZE;
418
419         pcpup->pc_nrq = (vm_offset_t *)((char *)nrq_array + curcpu*2*CPU_NRQ_SIZE);
420         pcpup->pc_nrq_ra = vtophys(pcpup->pc_nrq);
421         pcpup->pc_nrq_size = CPU_NRQ_SIZE;
422
423
424         error = hv_cpu_qconf(Q(CPU_MONDO_QUEUE_HEAD), pcpup->pc_cpu_q_ra, cpu_q_entries);
425         if (error != H_EOK)
426                 panic("cpu_mondo queue configuration failed: %lu va=%p ra=0x%lx", error,
427                       pcpup->pc_cpu_q, pcpup->pc_cpu_q_ra);
428
429         error = hv_cpu_qconf(Q(DEV_MONDO_QUEUE_HEAD), pcpup->pc_dev_q_ra, dev_q_entries);
430         if (error != H_EOK)
431                 panic("dev_mondo queue configuration failed: %lu", error);
432
433         error = hv_cpu_qconf(Q(RESUMABLE_ERROR_QUEUE_HEAD), pcpup->pc_rq_ra, CPU_RQ_ENTRIES);
434         if (error != H_EOK)
435                 panic("resumable error queue configuration failed: %lu", error);
436
437         error = hv_cpu_qconf(Q(NONRESUMABLE_ERROR_QUEUE_HEAD), pcpup->pc_nrq_ra, CPU_NRQ_ENTRIES);
438         if (error != H_EOK)
439                 panic("non-resumable error queue configuration failed: %lu", error);
440
441 }