1/* NetBSD: intr.c,v 1.15 2004/04/10 14:49:55 kochi Exp */
2
3/*
4 * Copyright 2002 (c) Wasabi Systems, Inc.
5 * All rights reserved.
6 *
7 * Written by Frank van der Linden for Wasabi Systems, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38/*-
39 * Copyright (c) 1991 The Regents of the University of California.
40 * All rights reserved.
41 *
42 * This code is derived from software contributed to Berkeley by
43 * William Jolitz.
44 *
45 * Redistribution and use in source and binary forms, with or without
46 * modification, are permitted provided that the following conditions
47 * are met:
48 * 1. Redistributions of source code must retain the above copyright
49 * notice, this list of conditions and the following disclaimer.
50 * 2. Redistributions in binary form must reproduce the above copyright
51 * notice, this list of conditions and the following disclaimer in the
52 * documentation and/or other materials provided with the distribution.
53 * 3. Neither the name of the University nor the names of its contributors
54 * may be used to endorse or promote products derived from this software
55 * without specific prior written permission.
56 *
57 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
58 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
59 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
60 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
61 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
63 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
64 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67 * SUCH DAMAGE.
68 *
69 * @(#)isa.c 7.2 (Berkeley) 5/13/91
70 */
71/*-
72 * Copyright (c) 1993, 1994 Charles Hannum.
73 *
74 * Redistribution and use in source and binary forms, with or without
75 * modification, are permitted provided that the following conditions
76 * are met:
77 * 1. Redistributions of source code must retain the above copyright
78 * notice, this list of conditions and the following disclaimer.
79 * 2. Redistributions in binary form must reproduce the above copyright
80 * notice, this list of conditions and the following disclaimer in the
81 * documentation and/or other materials provided with the distribution.
82 * 3. All advertising materials mentioning features or use of this software
83 * must display the following acknowledgement:
84 * This product includes software developed by the University of
85 * California, Berkeley and its contributors.
86 * 4. Neither the name of the University nor the names of its contributors
87 * may be used to endorse or promote products derived from this software
88 * without specific prior written permission.
89 *
90 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
91 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
92 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
93 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
94 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
95 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
96 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
97 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
98 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
99 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
100 * SUCH DAMAGE.
101 *
102 * @(#)isa.c 7.2 (Berkeley) 5/13/91
103 */
104
105#include <sys/cdefs.h>
106__KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.30 2016/10/17 18:23:50 jdolecek Exp $");
107
108#include "opt_multiprocessor.h"
109#include "opt_xen.h"
110#include "isa.h"
111#include "pci.h"
112
113#include <sys/param.h>
114#include <sys/systm.h>
115#include <sys/kernel.h>
116#include <sys/syslog.h>
117#include <sys/device.h>
118#include <sys/malloc.h>
119#include <sys/proc.h>
120#include <sys/errno.h>
121#include <sys/cpu.h>
122
123#include <uvm/uvm_extern.h>
124
125#include <machine/i8259.h>
126#include <machine/pio.h>
127#include <xen/evtchn.h>
128
129#include "acpica.h"
130#include "ioapic.h"
131#include "opt_mpbios.h"
132/* for x86/i8259.c */
133struct intrstub i8259_stubs[NUM_LEGACY_IRQS] = {{0,0}};
134#if NIOAPIC > 0
135/* for x86/ioapic.c */
136struct intrstub ioapic_edge_stubs[MAX_INTR_SOURCES] = {{0,0}};
137struct intrstub ioapic_level_stubs[MAX_INTR_SOURCES] = {{0,0}};
138
139#include <machine/i82093var.h>
140int irq2vect[256] = {0};
141int vect2irq[256] = {0};
142#endif /* NIOAPIC */
143#if NACPICA > 0
144#include <machine/mpconfig.h>
145#include <machine/mpacpi.h>
146#endif
147#ifdef MPBIOS
148#include <machine/mpbiosvar.h>
149#endif
150
151#if NPCI > 0
152#include <dev/pci/ppbreg.h>
153#endif
154
155/*
156 * Fake interrupt handler structures for the benefit of symmetry with
157 * other interrupt sources.
158 */
159struct intrhand fake_softclock_intrhand;
160struct intrhand fake_softnet_intrhand;
161struct intrhand fake_softserial_intrhand;
162struct intrhand fake_timer_intrhand;
163struct intrhand fake_ipi_intrhand;
164
165/*
166 * Initialize all handlers that aren't dynamically allocated, and exist
167 * for each CPU. Also init ci_iunmask[].
168 */
169void
170cpu_intr_init(struct cpu_info *ci)
171{
172 int i;
173#if defined(INTRSTACKSIZE)
174 char *cp;
175#endif
176
177 ci->ci_iunmask[0] = 0xfffffffe;
178 for (i = 1; i < NIPL; i++)
179 ci->ci_iunmask[i] = ci->ci_iunmask[i - 1] & ~(1 << i);
180
181#if defined(INTRSTACKSIZE)
182 cp = (char *)uvm_km_alloc(kernel_map, INTRSTACKSIZE, 0, UVM_KMF_WIRED);
183 ci->ci_intrstack = cp + INTRSTACKSIZE - sizeof(register_t);
184#endif
185 ci->ci_idepth = -1;
186}
187
188#if NPCI > 0 || NISA > 0
189void *
190intr_establish_xname(int legacy_irq, struct pic *pic, int pin,
191 int type, int level, int (*handler)(void *) , void *arg,
192 bool known_mpsafe, const char *xname)
193{
194 /* XXX xname registration not supported */
195 return intr_establish(legacy_irq, pic, pin, type, level, handler, arg,
196 known_mpsafe);
197}
198
199void *
200intr_establish(int legacy_irq, struct pic *pic, int pin,
201 int type, int level, int (*handler)(void *) , void *arg,
202 bool known_mpsafe)
203{
204 struct pintrhand *ih;
205 int evtchn;
206 char evname[16];
207#ifdef DIAGNOSTIC
208 if (legacy_irq != -1 && (legacy_irq < 0 || legacy_irq > 15))
209 panic("intr_establish: bad legacy IRQ value");
210 if (legacy_irq == -1 && pic == &i8259_pic)
211 panic("intr_establish: non-legacy IRQ on i8259");
212#endif /* DIAGNOSTIC */
213 if (legacy_irq == -1) {
214#if NIOAPIC > 0
215 /* will do interrupts via I/O APIC */
216 legacy_irq = APIC_INT_VIA_APIC;
217 legacy_irq |= pic->pic_apicid << APIC_INT_APIC_SHIFT;
218 legacy_irq |= pin << APIC_INT_PIN_SHIFT;
219 snprintf(evname, sizeof(evname), "%s pin %d",
220 pic->pic_name, pin);
221#else /* NIOAPIC */
222 return NULL;
223#endif /* NIOAPIC */
224 } else
225 snprintf(evname, sizeof(evname), "irq%d", legacy_irq);
226
227 evtchn = xen_intr_map(&legacy_irq, type);
228 ih = pirq_establish(legacy_irq & 0xff, evtchn, handler, arg, level,
229 evname);
230 return ih;
231}
232
233int
234xen_intr_map(int *pirq, int type)
235{
236 int irq = *pirq;
237#if NIOAPIC > 0
238 extern struct cpu_info phycpu_info_primary; /* XXX */
239 /*
240 * The hypervisor has already allocated vectors and IRQs for the
241 * devices. Reusing the same IRQ doesn't work because as we bind
242 * them for each devices, we can't then change the route entry
243 * of the next device if this one used this IRQ. The easiest is
244 * to allocate IRQs top-down, starting with a high number.
245 * 250 and 230 have been tried, but got rejected by Xen.
246 *
247 * Xen 3.5 also rejects 200. Try out all values until Xen accepts
248 * or none is available.
249 */
250 static int xen_next_irq = 200;
251 struct ioapic_softc *ioapic = ioapic_find(APIC_IRQ_APIC(*pirq));
252 struct pic *pic = &ioapic->sc_pic;
253 int pin = APIC_IRQ_PIN(*pirq);
254 physdev_op_t op;
255
256 if (*pirq & APIC_INT_VIA_APIC) {
257 irq = vect2irq[ioapic->sc_pins[pin].ip_vector];
258 if (ioapic->sc_pins[pin].ip_vector == 0 || irq == 0) {
259 /* allocate IRQ */
260 irq = APIC_IRQ_LEGACY_IRQ(*pirq);
261 if (irq <= 0 || irq > 15)
262 irq = xen_next_irq--;
263retry:
264 /* allocate vector and route interrupt */
265 op.cmd = PHYSDEVOP_ASSIGN_VECTOR;
266 op.u.irq_op.irq = irq;
267 if (HYPERVISOR_physdev_op(&op) < 0) {
268 irq = xen_next_irq--;
269 if (xen_next_irq == 15)
270 panic("PHYSDEVOP_ASSIGN_VECTOR irq %d", irq);
271 goto retry;
272 }
273 irq2vect[irq] = op.u.irq_op.vector;
274 vect2irq[op.u.irq_op.vector] = irq;
275 pic->pic_addroute(pic, &phycpu_info_primary, pin,
276 op.u.irq_op.vector, type);
277 }
278 *pirq &= ~0xff;
279 *pirq |= irq;
280 }
281#endif /* NIOAPIC */
282 return bind_pirq_to_evtch(irq);
283}
284
285void
286intr_disestablish(struct intrhand *ih)
287{
288 printf("intr_disestablish irq\n");
289}
290
291#if defined(MPBIOS) || NACPICA > 0
292struct pic *
293intr_findpic(int num)
294{
295#if NIOAPIC > 0
296 struct ioapic_softc *pic;
297
298 pic = ioapic_find_bybase(num);
299 if (pic != NULL)
300 return &pic->sc_pic;
301#endif
302 if (num < NUM_LEGACY_IRQS)
303 return &i8259_pic;
304
305 return NULL;
306}
307#endif
308
309#if NIOAPIC > 0 || NACPICA > 0
310struct intr_extra_bus {
311 int bus;
312 pcitag_t *pci_bridge_tag;
313 pci_chipset_tag_t pci_chipset_tag;
314 LIST_ENTRY(intr_extra_bus) list;
315};
316
317LIST_HEAD(, intr_extra_bus) intr_extra_buses =
318 LIST_HEAD_INITIALIZER(intr_extra_buses);
319
320static int intr_scan_bus(int, int, struct xen_intr_handle *);
321
322void
323intr_add_pcibus(struct pcibus_attach_args *pba)
324{
325 struct intr_extra_bus *iebp;
326
327 iebp = malloc(sizeof(struct intr_extra_bus), M_TEMP, M_WAITOK);
328 iebp->bus = pba->pba_bus;
329 iebp->pci_chipset_tag = pba->pba_pc;
330 iebp->pci_bridge_tag = pba->pba_bridgetag;
331 LIST_INSERT_HEAD(&intr_extra_buses, iebp, list);
332}
333
334static int
335intr_find_pcibridge(int bus, pcitag_t *pci_bridge_tag,
336 pci_chipset_tag_t *pc)
337{
338 struct intr_extra_bus *iebp;
339 struct mp_bus *mpb;
340
341 if (bus < 0)
342 return ENOENT;
343
344 if (bus < mp_nbus) {
345 mpb = &mp_busses[bus];
346 if (mpb->mb_pci_bridge_tag == NULL)
347 return ENOENT;
348 *pci_bridge_tag = *mpb->mb_pci_bridge_tag;
349 *pc = mpb->mb_pci_chipset_tag;
350 return 0;
351 }
352
353 LIST_FOREACH(iebp, &intr_extra_buses, list) {
354 if (iebp->bus == bus) {
355 if (iebp->pci_bridge_tag == NULL)
356 return ENOENT;
357 *pci_bridge_tag = *iebp->pci_bridge_tag;
358 *pc = iebp->pci_chipset_tag;
359 return 0;
360 }
361 }
362 return ENOENT;
363}
364
365int
366intr_find_mpmapping(int bus, int pin, struct xen_intr_handle *handle)
367{
368#if NPCI > 0
369 int dev, func;
370 pcitag_t pci_bridge_tag;
371 pci_chipset_tag_t pc;
372#endif
373
374#if NPCI > 0
375 while (intr_scan_bus(bus, pin, handle) != 0) {
376 if (intr_find_pcibridge(bus, &pci_bridge_tag,
377 &pc) != 0)
378 return ENOENT;
379 dev = pin >> 2;
380 pin = pin & 3;
381 pin = PPB_INTERRUPT_SWIZZLE(pin + 1, dev) - 1;
382 pci_decompose_tag(pc, pci_bridge_tag, &bus,
383 &dev, &func);
384 pin |= (dev << 2);
385 }
386 return 0;
387#else
388 return intr_scan_bus(bus, pin, handle);
389#endif
390}
391
392static int
393intr_scan_bus(int bus, int pin, struct xen_intr_handle *handle)
394{
395 struct mp_intr_map *mip, *intrs;
396
397 if (bus < 0 || bus >= mp_nbus)
398 return ENOENT;
399
400 intrs = mp_busses[bus].mb_intrs;
401 if (intrs == NULL)
402 return ENOENT;
403
404 for (mip = intrs; mip != NULL; mip = mip->next) {
405 if (mip->bus_pin == pin) {
406#if NACPICA > 0
407 if (mip->linkdev != NULL)
408 if (mpacpi_findintr_linkdev(mip) != 0)
409 continue;
410#endif
411 handle->pirq = mip->ioapic_ih;
412 return 0;
413 }
414 }
415 return ENOENT;
416}
417#endif /* NIOAPIC > 0 || NACPICA > 0 */
418#endif /* NPCI > 0 || NISA > 0 */
419
420
421#ifdef INTRDEBUG
422void
423intr_printconfig(void)
424{
425 int i;
426 struct intrhand *ih;
427 struct intrsource *isp;
428 struct cpu_info *ci;
429 CPU_INFO_ITERATOR cii;
430
431 for (CPU_INFO_FOREACH(cii, ci)) {
432 printf("%s: interrupt masks:\n", device_xname(ci->ci_dev));
433 for (i = 0; i < NIPL; i++)
434 printf("IPL %d mask %lx unmask %lx\n", i,
435 (u_long)ci->ci_imask[i], (u_long)ci->ci_iunmask[i]);
436 for (i = 0; i < MAX_INTR_SOURCES; i++) {
437 isp = ci->ci_isources[i];
438 if (isp == NULL)
439 continue;
440 printf("%s source %d is pin %d from pic %s maxlevel %d\n",
441 device_xname(ci->ci_dev), i, isp->is_pin,
442 isp->is_pic->pic_name, isp->is_maxlevel);
443 for (ih = isp->is_handlers; ih != NULL;
444 ih = ih->ih_next)
445 printf("\thandler %p level %d\n",
446 ih->ih_fun, ih->ih_level);
447
448 }
449 }
450}
451#endif
452
453void
454cpu_intr_redistribute(void)
455{
456
457 /* XXX nothing */
458}
459
460u_int
461cpu_intr_count(struct cpu_info *ci)
462{
463
464 KASSERT(ci->ci_nintrhand >= 0);
465
466 return ci->ci_nintrhand;
467}
468