xref: /netbsd-src/sys/arch/x86/x86/mpacpi.c (revision cbefede3df4c9cb57ca41d1287e99931562f9c73)
1 /*	$NetBSD: mpacpi.c,v 1.111 2024/09/30 17:00:10 bouyer Exp $	*/
2 
3 /*
4  * Copyright (c) 2003 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 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: mpacpi.c,v 1.111 2024/09/30 17:00:10 bouyer Exp $");
40 
41 #include "acpica.h"
42 #include "opt_acpi.h"
43 #include "opt_ddb.h"
44 #include "opt_mpbios.h"
45 #include "opt_multiprocessor.h"
46 #include "pchb.h"
47 
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/kernel.h>
51 #include <sys/device.h>
52 #include <sys/kmem.h>
53 #include <sys/queue.h>
54 
55 #include <uvm/uvm_extern.h>
56 
57 #include <machine/specialreg.h>
58 #include <machine/cpuvar.h>
59 #include <sys/bus.h>
60 #include <machine/mpacpi.h>
61 #include <machine/mpbiosvar.h>
62 
63 #include <machine/i82093reg.h>
64 #include <machine/i82093var.h>
65 #include <machine/i82489reg.h>
66 #include <machine/i82489var.h>
67 #include <dev/isa/isareg.h>
68 #include <dev/pci/pcivar.h>
69 #include <dev/pci/pcidevs.h>
70 #include <dev/pci/ppbreg.h>
71 
72 #include <dev/acpi/acpica.h>
73 #include <dev/acpi/acpireg.h>
74 #include <dev/acpi/acpivar.h>
75 
76 #include <dev/cons.h>
77 
78 #define _COMPONENT     ACPI_RESOURCE_COMPONENT
79 ACPI_MODULE_NAME       ("mpacpi")
80 
81 #include "pci.h"
82 #include "ioapic.h"
83 #include "lapic.h"
84 
85 #include "locators.h"
86 
87 /* XXX room for PCI-to-PCI bus */
88 #define BUS_BUFFER (16)
89 
90 #if NPCI > 0
91 struct mpacpi_pcibus {
92 	TAILQ_ENTRY(mpacpi_pcibus) mpr_list;
93 	devhandle_t mpr_devhandle;
94 	ACPI_BUFFER mpr_buf;		/* preserve _PRT */
95 	int mpr_seg;			/* PCI segment number */
96 	int mpr_bus;			/* PCI bus number */
97 };
98 
99 static TAILQ_HEAD(, mpacpi_pcibus) mpacpi_pcibusses;
100 
101 #endif
102 
103 static int mpacpi_cpuprint(void *, const char *);
104 static int mpacpi_ioapicprint(void *, const char *);
105 
106 /* acpi_madt_walk callbacks */
107 static ACPI_STATUS mpacpi_count(ACPI_SUBTABLE_HEADER *, void *);
108 static ACPI_STATUS mpacpi_config_cpu(ACPI_SUBTABLE_HEADER *, void *);
109 static ACPI_STATUS mpacpi_config_ioapic(ACPI_SUBTABLE_HEADER *, void *);
110 static ACPI_STATUS mpacpi_nonpci_intr(ACPI_SUBTABLE_HEADER *, void *);
111 
112 #if NPCI > 0
113 static int mpacpi_pcircount(struct mpacpi_pcibus *);
114 static int mpacpi_pciroute(struct mpacpi_pcibus *);
115 static int mpacpi_find_pcibusses(struct acpi_softc *);
116 
117 static void mpacpi_print_pci_intr(int);
118 #endif
119 
120 static void mpacpi_config_irouting(struct acpi_softc *);
121 
122 static void mpacpi_print_intr(struct mp_intr_map *);
123 static void mpacpi_print_isa_intr(int);
124 
125 static void mpacpi_user_continue(const char *fmt, ...);
126 
127 #ifdef DDB
128 void mpacpi_dump(void);
129 #endif
130 
131 int mpacpi_nioapic;			/* number of ioapics */
132 int mpacpi_ncpu;			/* number of cpus */
133 int mpacpi_nintsrc;			/* number of non-device interrupts */
134 
135 #if NPCI > 0
136 static int mpacpi_npci;
137 static int mpacpi_maxpci;
138 static int mpacpi_npciroots;
139 #endif
140 
141 static int mpacpi_intr_index;
142 static paddr_t mpacpi_lapic_base = LAPIC_BASE;
143 
144 int mpacpi_step;
145 int mpacpi_force;
146 
147 static int
148 mpacpi_cpuprint(void *aux, const char *pnp)
149 {
150 	struct cpu_attach_args *caa = aux;
151 
152 	if (pnp)
153 		aprint_normal("cpu at %s", pnp);
154 	aprint_normal(" apid %d", caa->cpu_number);
155 	return UNCONF;
156 }
157 
158 static int
159 mpacpi_ioapicprint(void *aux, const char *pnp)
160 {
161 	struct apic_attach_args *aaa = aux;
162 
163 	if (pnp)
164 		aprint_normal("ioapic at %s", pnp);
165 	aprint_normal(" apid %d", aaa->apic_id);
166 	return UNCONF;
167 }
168 
169 /*
170  * Handle special interrupt sources and overrides from the MADT.
171  * This is a callback function for acpi_madt_walk() (see acpi.c).
172  */
173 static ACPI_STATUS
174 mpacpi_nonpci_intr(ACPI_SUBTABLE_HEADER *hdrp, void *aux)
175 {
176 	int *index = aux, pin, lindex;
177 	struct mp_intr_map *mpi;
178 	ACPI_MADT_NMI_SOURCE *ioapic_nmi;
179 	ACPI_MADT_LOCAL_APIC_NMI *lapic_nmi;
180 	ACPI_MADT_INTERRUPT_OVERRIDE *isa_ovr;
181 	ACPI_MADT_LOCAL_X2APIC_NMI *x2apic_nmi;
182 	struct pic *pic;
183 	extern struct acpi_softc *acpi_softc;	/* XXX */
184 
185 	switch (hdrp->Type) {
186 	case ACPI_MADT_TYPE_NMI_SOURCE:
187 		ioapic_nmi = (ACPI_MADT_NMI_SOURCE *)hdrp;
188 		pic = intr_findpic(ioapic_nmi->GlobalIrq);
189 		if (pic == NULL)
190 			break;
191 #if NIOAPIC == 0
192 		if (pic->pic_type == PIC_IOAPIC)
193 			break;
194 #endif
195 		mpi = &mp_intrs[*index];
196 		(*index)++;
197 		mpi->next = NULL;
198 		mpi->bus = NULL;
199 		mpi->type = MPS_INTTYPE_NMI;
200 		mpi->ioapic = pic;
201 		pin = ioapic_nmi->GlobalIrq - pic->pic_vecbase;
202 		mpi->ioapic_pin = pin;
203 		mpi->bus_pin = -1;
204 		mpi->redir = (IOAPIC_REDLO_DEL_NMI << IOAPIC_REDLO_DEL_SHIFT);
205 #if NIOAPIC > 0
206 		if (pic->pic_type == PIC_IOAPIC) {
207 			pic->pic_ioapic->sc_pins[pin].ip_map = mpi;
208 			mpi->ioapic_ih = APIC_INT_VIA_APIC |
209 			    (pic->pic_apicid << APIC_INT_APIC_SHIFT) |
210 			    (pin << APIC_INT_PIN_SHIFT);
211 		} else
212 #endif
213 			mpi->ioapic_ih = pin;
214 		mpi->flags = ioapic_nmi->IntiFlags;
215 		mpi->global_int = ioapic_nmi->GlobalIrq;
216 		break;
217 	case ACPI_MADT_TYPE_LOCAL_APIC_NMI:
218 		lapic_nmi = (ACPI_MADT_LOCAL_APIC_NMI *)hdrp;
219 		mpi = &mp_intrs[*index];
220 		(*index)++;
221 		mpi->next = NULL;
222 		mpi->bus = NULL;
223 		mpi->ioapic = NULL;
224 		mpi->type = MPS_INTTYPE_NMI;
225 		mpi->ioapic_pin = lapic_nmi->Lint;
226 		mpi->cpu_id = lapic_nmi->ProcessorId;
227 		mpi->redir = (IOAPIC_REDLO_DEL_NMI << IOAPIC_REDLO_DEL_SHIFT);
228 		mpi->global_int = -1;
229 		break;
230 	case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE:
231 		isa_ovr = (ACPI_MADT_INTERRUPT_OVERRIDE *)hdrp;
232 		if (mp_verbose) {
233 			printf("mpacpi: ISA interrupt override %d -> %d (%d/%d)\n",
234 			    isa_ovr->SourceIrq, isa_ovr->GlobalIrq,
235 			    isa_ovr->IntiFlags & ACPI_MADT_POLARITY_MASK,
236 			    (isa_ovr->IntiFlags & ACPI_MADT_TRIGGER_MASK) >>2);
237 		}
238 		if (isa_ovr->SourceIrq > 15 || isa_ovr->SourceIrq == 2 ||
239 		    (isa_ovr->SourceIrq == 0 && isa_ovr->GlobalIrq == 2 &&
240 			(acpi_softc->sc_quirks & ACPI_QUIRK_IRQ0)))
241 			break;
242 		pic = intr_findpic(isa_ovr->GlobalIrq);
243 		if (pic == NULL)
244 			break;
245 #if NIOAPIC == 0
246 		if (pic->pic_type == PIC_IOAPIC)
247 			break;
248 #endif
249 		pin = isa_ovr->GlobalIrq - pic->pic_vecbase;
250 		lindex = isa_ovr->SourceIrq;
251 		/*
252 		 * IRQ 2 was skipped in the default setup.
253 		 */
254 		if (lindex > 2)
255 			lindex--;
256 		mpi = &mp_intrs[lindex];
257 #if NIOAPIC > 0
258 		if (pic->pic_type == PIC_IOAPIC) {
259 			mpi->ioapic_ih = APIC_INT_VIA_APIC |
260 			    (pic->pic_apicid << APIC_INT_APIC_SHIFT) |
261 			    (pin << APIC_INT_PIN_SHIFT);
262 		} else
263 #endif
264 			mpi->ioapic_ih = pin;
265 		mpi->bus_pin = isa_ovr->SourceIrq;
266 		mpi->ioapic = (struct pic *)pic;
267 		mpi->ioapic_pin = pin;
268 		mpi->sflags |= MPI_OVR;
269 		mpi->redir = 0;
270 		mpi->global_int = isa_ovr->GlobalIrq;
271 		switch (isa_ovr->IntiFlags & ACPI_MADT_POLARITY_MASK) {
272 		case ACPI_MADT_POLARITY_ACTIVE_HIGH:
273 			mpi->redir &= ~IOAPIC_REDLO_ACTLO;
274 			break;
275 		case ACPI_MADT_POLARITY_ACTIVE_LOW:
276 			mpi->redir |= IOAPIC_REDLO_ACTLO;
277 			break;
278 		case ACPI_MADT_POLARITY_CONFORMS:
279 			if (isa_ovr->SourceIrq == AcpiGbl_FADT.SciInterrupt)
280 				mpi->redir |= IOAPIC_REDLO_ACTLO;
281 			else
282 				mpi->redir &= ~IOAPIC_REDLO_ACTLO;
283 			break;
284 		}
285 		mpi->redir |= (IOAPIC_REDLO_DEL_FIXED<<IOAPIC_REDLO_DEL_SHIFT);
286 		switch (isa_ovr->IntiFlags & ACPI_MADT_TRIGGER_MASK) {
287 		case ACPI_MADT_TRIGGER_LEVEL:
288 			mpi->redir |= IOAPIC_REDLO_LEVEL;
289 			break;
290 		case ACPI_MADT_TRIGGER_EDGE:
291 			mpi->redir &= ~IOAPIC_REDLO_LEVEL;
292 			break;
293 		case ACPI_MADT_TRIGGER_CONFORMS:
294 			if (isa_ovr->SourceIrq == AcpiGbl_FADT.SciInterrupt)
295 				mpi->redir |= IOAPIC_REDLO_LEVEL;
296 			else
297 				mpi->redir &= ~IOAPIC_REDLO_LEVEL;
298 			break;
299 		}
300 		mpi->flags = isa_ovr->IntiFlags;
301 #if NIOAPIC > 0
302 		if (pic->pic_type == PIC_IOAPIC)
303 			pic->pic_ioapic->sc_pins[pin].ip_map = mpi;
304 #endif
305 		break;
306 
307 	case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI:
308 		x2apic_nmi = (ACPI_MADT_LOCAL_X2APIC_NMI *)hdrp;
309 
310 		mpi = &mp_intrs[*index];
311 		(*index)++;
312 		mpi->next = NULL;
313 		mpi->bus = NULL;
314 		mpi->ioapic = NULL;
315 		mpi->type = MPS_INTTYPE_NMI;
316 		mpi->ioapic_pin = x2apic_nmi->Lint;
317 		mpi->cpu_id = x2apic_nmi->Uid;
318 		mpi->redir = (IOAPIC_REDLO_DEL_NMI << IOAPIC_REDLO_DEL_SHIFT);
319 		mpi->global_int = -1;
320 		break;
321 
322 	default:
323 		break;
324 	}
325 	return AE_OK;
326 }
327 
328 /*
329  * Count various MP resources present in the MADT.
330  * This is a callback function for acpi_madt_walk().
331  */
332 static ACPI_STATUS
333 mpacpi_count(ACPI_SUBTABLE_HEADER *hdrp, void *aux)
334 {
335 	ACPI_MADT_LOCAL_APIC_OVERRIDE *lop;
336 
337 	switch (hdrp->Type) {
338 	case ACPI_MADT_TYPE_LOCAL_APIC:
339 	case ACPI_MADT_TYPE_LOCAL_X2APIC:
340 		mpacpi_ncpu++;
341 		break;
342 	case ACPI_MADT_TYPE_IO_APIC:
343 		mpacpi_nioapic++;
344 		break;
345 	case ACPI_MADT_TYPE_NMI_SOURCE:
346 	case ACPI_MADT_TYPE_LOCAL_APIC_NMI:
347 	case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI:
348 		mpacpi_nintsrc++;
349 		break;
350 	case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE:
351 		lop = (ACPI_MADT_LOCAL_APIC_OVERRIDE *)hdrp;
352 		mpacpi_lapic_base = lop->Address;
353 	default:
354 		break;
355 	}
356 	return AE_OK;
357 }
358 
359 static ACPI_STATUS
360 mpacpi_config_cpu(ACPI_SUBTABLE_HEADER *hdrp, void *aux)
361 {
362 	device_t parent = aux;
363 	ACPI_MADT_LOCAL_APIC *lapic;
364 	ACPI_MADT_LOCAL_X2APIC *x2apic;
365 	struct cpu_attach_args caa;
366 	int cpunum = 0;
367 	int locs[CPUBUSCF_NLOCS];
368 
369 #if defined(MULTIPROCESSOR) || defined(IOAPIC)
370 	if (mpacpi_ncpu > 1)
371 		cpunum = lapic_cpu_number();
372 #endif
373 
374 	switch (hdrp->Type) {
375 	case ACPI_MADT_TYPE_LOCAL_APIC:
376 		lapic = (ACPI_MADT_LOCAL_APIC *)hdrp;
377 		if (lapic->LapicFlags & ACPI_MADT_ENABLED) {
378 			if (lapic->Id != cpunum)
379 				caa.cpu_role = CPU_ROLE_AP;
380 			else
381 				caa.cpu_role = CPU_ROLE_BP;
382 			caa.cpu_id = lapic->ProcessorId;
383 			caa.cpu_number = lapic->Id;
384 			caa.cpu_func = &mp_cpu_funcs;
385 			locs[CPUBUSCF_APID] = caa.cpu_number;
386 			config_found(parent, &caa, mpacpi_cpuprint,
387 			    CFARGS(.submatch = config_stdsubmatch,
388 				   .iattr = "cpubus",
389 				   .locators = locs));
390 		}
391 		break;
392 
393 	case ACPI_MADT_TYPE_LOCAL_X2APIC:
394 		x2apic = (ACPI_MADT_LOCAL_X2APIC *)hdrp;
395 
396 		if (x2apic->LapicFlags & ACPI_MADT_ENABLED) {
397 			if (x2apic->LocalApicId != cpunum)
398 				caa.cpu_role = CPU_ROLE_AP;
399 			else
400 				caa.cpu_role = CPU_ROLE_BP;
401 			caa.cpu_id = x2apic->Uid;
402 			caa.cpu_number = x2apic->LocalApicId;
403 			caa.cpu_func = &mp_cpu_funcs;
404 			locs[CPUBUSCF_APID] = caa.cpu_number;
405 			config_found(parent, &caa, mpacpi_cpuprint,
406 			    CFARGS(.submatch = config_stdsubmatch,
407 				   .iattr = "cpubus",
408 				   .locators = locs));
409 		}
410 		break;
411 
412 	}
413 	return AE_OK;
414 }
415 
416 static ACPI_STATUS
417 mpacpi_config_ioapic(ACPI_SUBTABLE_HEADER *hdrp, void *aux)
418 {
419 	device_t parent = aux;
420 	struct apic_attach_args aaa;
421 	ACPI_MADT_IO_APIC *p;
422 	int locs[IOAPICBUSCF_NLOCS];
423 
424 	if (hdrp->Type == ACPI_MADT_TYPE_IO_APIC) {
425 		p = (ACPI_MADT_IO_APIC *)hdrp;
426 		aaa.apic_id = p->Id;
427 		aaa.apic_address = p->Address;
428 		aaa.apic_version = -1;
429 		aaa.flags = IOAPIC_VWIRE;
430 		aaa.apic_vecbase = p->GlobalIrqBase;
431 		locs[IOAPICBUSCF_APID] = aaa.apic_id;
432 		config_found(parent, &aaa, mpacpi_ioapicprint,
433 		    CFARGS(.submatch = config_stdsubmatch,
434 			   .iattr = "ioapicbus",
435 			   .locators = locs));
436 	}
437 	return AE_OK;
438 }
439 
440 int
441 mpacpi_scan_apics(device_t self, int *ncpup)
442 {
443 	int rv = 0;
444 
445 	if (acpi_madt_map() != AE_OK)
446 		return 0;
447 
448 	mpacpi_ncpu = mpacpi_nintsrc = mpacpi_nioapic = 0;
449 	acpi_madt_walk(mpacpi_count, self);
450 
451 	acpi_madt_walk(mpacpi_config_ioapic, self);
452 
453 #if NLAPIC > 0
454 	lapic_boot_init(mpacpi_lapic_base);
455 #endif
456 
457 	acpi_madt_walk(mpacpi_config_cpu, self);
458 
459 	if (mpacpi_ncpu == 0)
460 		goto done;
461 
462 #if NPCI > 0
463 	/*
464 	 * If PCI routing tables can't be built we report failure
465 	 * and let MPBIOS do the work.
466 	 */
467 	if (!mpacpi_force &&
468 	    (acpi_find_quirks() & (ACPI_QUIRK_BADPCI)) != 0)
469 		goto done;
470 #endif
471 	rv = 1;
472 done:
473 	*ncpup = mpacpi_ncpu;
474 	acpi_madt_unmap();
475 	return rv;
476 }
477 
478 #if NPCI > 0
479 
480 static void
481 mpacpi_pci_foundbus(struct acpi_devnode *ad)
482 {
483 	struct mpacpi_pcibus *mpr;
484 	ACPI_BUFFER buf;
485 	int rv;
486 
487 	/*
488 	 * set mpr_buf from _PRT (if it exists).
489 	 * set mpr_seg and mpr_bus from previously cached info.
490 	 */
491 
492 	rv = acpi_get(ad->ad_handle, &buf, AcpiGetIrqRoutingTable);
493 	if (ACPI_FAILURE(rv)) {
494 		buf.Length = 0;
495 		buf.Pointer = NULL;
496 	}
497 
498 	mpr = kmem_zalloc(sizeof(struct mpacpi_pcibus), KM_SLEEP);
499 	mpr->mpr_devhandle =
500 	    devhandle_from_acpi(devhandle_invalid(), ad->ad_handle);
501 	mpr->mpr_buf = buf;
502 	mpr->mpr_seg = ad->ad_pciinfo->ap_segment;
503 	mpr->mpr_bus = ad->ad_pciinfo->ap_downbus;
504 	TAILQ_INSERT_TAIL(&mpacpi_pcibusses, mpr, mpr_list);
505 
506 	if ((ad->ad_devinfo->Flags & ACPI_PCI_ROOT_BRIDGE) != 0) {
507 		if (mp_verbose)
508 			printf("mpacpi: found root PCI bus %d\n",
509 			    mpr->mpr_bus);
510 		mpacpi_npciroots++;
511 	} else {
512 		if (mp_verbose)
513 			printf("mpacpi: found subordinate bus %d\n",
514 			    mpr->mpr_bus);
515 	}
516 
517 	/*
518 	 * XXX this wrongly assumes that bus numbers are unique
519 	 * even between segments.
520 	 */
521 	if (mpr->mpr_bus > mpacpi_maxpci)
522 		mpacpi_maxpci = mpr->mpr_bus;
523 
524 	mpacpi_npci++;
525 }
526 
527 
528 static void
529 mpacpi_pci_walk(struct acpi_devnode *ad)
530 {
531 	struct acpi_devnode *child;
532 
533 	if (ad->ad_pciinfo &&
534 	    (ad->ad_pciinfo->ap_flags & ACPI_PCI_INFO_BRIDGE) != 0) {
535 		mpacpi_pci_foundbus(ad);
536 	}
537 	SIMPLEQ_FOREACH(child, &ad->ad_child_head, ad_child_list) {
538 		mpacpi_pci_walk(child);
539 	}
540 }
541 
542 static int
543 mpacpi_find_pcibusses(struct acpi_softc *sc)
544 {
545 
546 	TAILQ_INIT(&mpacpi_pcibusses);
547 	mpacpi_pci_walk(sc->sc_root);
548 	return 0;
549 }
550 
551 /*
552  * Find all static PRT entries for a PCI bus.
553  */
554 static int
555 mpacpi_pciroute(struct mpacpi_pcibus *mpr)
556 {
557 	ACPI_PCI_ROUTING_TABLE *ptrp;
558 	ACPI_HANDLE linkdev;
559 	char *p;
560 	struct mp_intr_map *mpi, *iter;
561 	struct mp_bus *mpb;
562 	struct pic *pic;
563 	unsigned dev;
564 	int pin;
565 
566 	if (mp_verbose)
567 		printf("mpacpi: configuring PCI bus %d int routing\n",
568 		    mpr->mpr_bus);
569 
570 	mpb = &mp_busses[mpr->mpr_bus];
571 
572 	if (mpb->mb_name != NULL)
573 		printf("mpacpi: PCI bus %d int routing already done!\n",
574 		    mpr->mpr_bus);
575 
576 	mpb->mb_intrs = NULL;
577 	mpb->mb_name = "pci";
578 	mpb->mb_idx = mpr->mpr_bus;
579 	mpb->mb_intr_print = mpacpi_print_pci_intr;
580 	mpb->mb_intr_cfg = NULL;
581 	mpb->mb_data = 0;
582 
583 	if (mpr->mpr_buf.Length == 0) {
584 		goto out;
585 	}
586 
587 	for (p = mpr->mpr_buf.Pointer; ; p += ptrp->Length) {
588 		ptrp = (ACPI_PCI_ROUTING_TABLE *)p;
589 		if (ptrp->Length == 0)
590 			break;
591 		dev = ACPI_HIWORD(ptrp->Address);
592 
593 		if (ptrp->Source[0] == 0 &&
594 		    (ptrp->SourceIndex == 14 || ptrp->SourceIndex == 15)) {
595 			printf("Skipping PCI routing entry for PCI IDE compat IRQ");
596 			continue;
597 		}
598 
599 		mpi = &mp_intrs[mpacpi_intr_index];
600 		mpi->bus_pin = (dev << 2) | (ptrp->Pin & 3);
601 		mpi->bus = mpb;
602 		mpi->type = MPS_INTTYPE_INT;
603 
604 		/*
605 		 * First check if an entry for this device/pin combination
606 		 * was already found.  Some DSDTs have more than one entry
607 		 * and it seems that the first is generally the right one.
608 		 */
609 		for (iter = mpb->mb_intrs; iter != NULL; iter = iter->next) {
610 			if (iter->bus_pin == mpi->bus_pin)
611 				break;
612 		}
613 		if (iter != NULL)
614 			continue;
615 
616 		++mpacpi_intr_index;
617 
618 		if (ptrp->Source[0] != 0) {
619 			if (mp_verbose > 1)
620 				printf("pciroute: dev %d INT%c on lnkdev %s\n",
621 				    dev, 'A' + (ptrp->Pin & 3), ptrp->Source);
622 			mpi->global_int = -1;
623 			mpi->sourceindex = ptrp->SourceIndex;
624 			if (AcpiGetHandle(ACPI_ROOT_OBJECT, ptrp->Source,
625 			    &linkdev) != AE_OK) {
626 				printf("AcpiGetHandle failed for '%s'\n",
627 				    ptrp->Source);
628 				continue;
629 			}
630 			/* acpi_allocate_resources(linkdev); */
631 			mpi->ioapic_pin = -1;
632 			mpi->linkdev = acpi_pci_link_devbyhandle(linkdev);
633 			acpi_pci_link_add_reference(mpi->linkdev, NULL, 0,
634 			    mpr->mpr_bus, dev, ptrp->Pin & 3);
635 			mpi->ioapic = NULL;
636 			mpi->flags = MPS_INTPO_ACTLO | (MPS_INTTR_LEVEL << 2);
637 			if (mp_verbose > 1)
638 				printf("pciroute: done adding entry\n");
639 		} else {
640 			if (mp_verbose > 1)
641 				printf("pciroute: dev %d INT%c on globint %d\n",
642 				    dev, 'A' + (ptrp->Pin & 3),
643 				    ptrp->SourceIndex);
644 			mpi->sourceindex = 0;
645 			mpi->global_int = ptrp->SourceIndex;
646 			pic = intr_findpic(ptrp->SourceIndex);
647 			if (pic == NULL)
648 				continue;
649 			/* Defaults for PCI (active low, level triggered) */
650 			mpi->redir =
651 			    (IOAPIC_REDLO_DEL_FIXED <<IOAPIC_REDLO_DEL_SHIFT) |
652 			    IOAPIC_REDLO_LEVEL | IOAPIC_REDLO_ACTLO;
653 			mpi->ioapic = pic;
654 			pin = ptrp->SourceIndex - pic->pic_vecbase;
655 			if (pic->pic_type == PIC_I8259 && pin > 15)
656 				panic("bad pin %d for legacy IRQ", pin);
657 			mpi->ioapic_pin = pin;
658 #if NIOAPIC > 0
659 			if (pic->pic_type == PIC_IOAPIC) {
660 				pic->pic_ioapic->sc_pins[pin].ip_map = mpi;
661 				mpi->ioapic_ih = APIC_INT_VIA_APIC |
662 				    (pic->pic_apicid << APIC_INT_APIC_SHIFT) |
663 				    (pin << APIC_INT_PIN_SHIFT);
664 			} else
665 #endif
666 				mpi->ioapic_ih = pin;
667 			mpi->linkdev = NULL;
668 			mpi->flags = MPS_INTPO_ACTLO | (MPS_INTTR_LEVEL << 2);
669 			if (mp_verbose > 1)
670 				printf("pciroute: done adding entry\n");
671 		}
672 
673 		mpi->cpu_id = 0;
674 
675 		mpi->next = mpb->mb_intrs;
676 		mpb->mb_intrs = mpi;
677 	}
678 
679 	ACPI_FREE(mpr->mpr_buf.Pointer);
680 	mpr->mpr_buf.Pointer = NULL;	/* be preventive to bugs */
681 
682 out:
683 	if (mp_verbose > 1)
684 		printf("pciroute: done\n");
685 
686 	return 0;
687 }
688 
689 /*
690  * Count number of elements in _PRT
691  */
692 static int
693 mpacpi_pcircount(struct mpacpi_pcibus *mpr)
694 {
695 	int count = 0;
696 	ACPI_PCI_ROUTING_TABLE *PrtElement;
697 	uint8_t *Buffer;
698 
699 	if (mpr->mpr_buf.Length == 0) {
700 		return 0;
701 	}
702 
703 	for (Buffer = mpr->mpr_buf.Pointer;; Buffer += PrtElement->Length) {
704 		PrtElement = (ACPI_PCI_ROUTING_TABLE *)Buffer;
705 		if (PrtElement->Length == 0)
706 			break;
707 		count++;
708 	}
709 
710 	return count;
711 }
712 #endif
713 
714 /*
715  * Set up the interrupt config lists, in the same format as the mpbios does.
716  */
717 static void
718 mpacpi_config_irouting(struct acpi_softc *acpi)
719 {
720 #if NPCI > 0
721 	struct mpacpi_pcibus *mpr;
722 #endif
723 	int nintr;
724 	int i;
725 	struct mp_bus *mbp;
726 	struct mp_intr_map *mpi;
727 	struct pic *pic;
728 
729 	nintr = mpacpi_nintsrc + NUM_LEGACY_IRQS - 1;
730 #if NPCI > 0
731 	TAILQ_FOREACH(mpr, &mpacpi_pcibusses, mpr_list) {
732 		nintr += mpacpi_pcircount(mpr);
733 	}
734 
735 	mp_isa_bus = mpacpi_maxpci + BUS_BUFFER; /* XXX */
736 #else
737 	mp_isa_bus = 0;
738 #endif
739 	mp_nbus = mp_isa_bus + 1;
740 	mp_nintr = nintr;
741 
742 	mp_busses = kmem_zalloc(sizeof(struct mp_bus) * mp_nbus, KM_SLEEP);
743 	mp_intrs = kmem_zalloc(sizeof(struct mp_intr_map) * mp_nintr, KM_SLEEP);
744 	mbp = &mp_busses[mp_isa_bus];
745 	mbp->mb_name = "isa";
746 	mbp->mb_idx = 0;
747 	mbp->mb_intr_print = mpacpi_print_isa_intr;
748 	mbp->mb_intr_cfg = NULL;
749 	mbp->mb_intrs = &mp_intrs[0];
750 	mbp->mb_data = 0;
751 
752 	pic = intr_findpic(0);
753 	if (pic == NULL)
754 		panic("mpacpi: can't find first PIC");
755 #if NIOAPIC == 0
756 	if (pic->pic_type == PIC_IOAPIC)
757 		panic("mpacpi: ioapic but no i8259?");
758 #endif
759 
760 	/*
761 	 * Set up default identity mapping for ISA irqs to first ioapic.
762 	 */
763 	for (i = mpacpi_intr_index = 0; i < NUM_LEGACY_IRQS; i++) {
764 		if (i == 2)
765 			continue;
766 		mpi = &mp_intrs[mpacpi_intr_index];
767 		if (mpacpi_intr_index < (NUM_LEGACY_IRQS - 2))
768 			mpi->next = &mp_intrs[mpacpi_intr_index + 1];
769 		else
770 			mpi->next = NULL;
771 		mpi->bus = mbp;
772 		mpi->bus_pin = i;
773 		mpi->ioapic_pin = i;
774 		mpi->ioapic = pic;
775 		mpi->type = MPS_INTTYPE_INT;
776 		mpi->cpu_id = 0;
777 		mpi->redir = 0;
778 #if NIOAPIC > 0
779 		if (pic->pic_type == PIC_IOAPIC) {
780 			mpi->ioapic_ih = APIC_INT_VIA_APIC |
781 			    (pic->pic_apicid << APIC_INT_APIC_SHIFT) |
782 			    (i << APIC_INT_PIN_SHIFT);
783 			mpi->redir =
784 			    (IOAPIC_REDLO_DEL_FIXED << IOAPIC_REDLO_DEL_SHIFT);
785 			pic->pic_ioapic->sc_pins[i].ip_map = mpi;
786 		} else
787 #endif
788 			mpi->ioapic_ih = i;
789 
790 		mpi->flags = MPS_INTPO_DEF | (MPS_INTTR_DEF << 2);
791 		mpi->global_int = i;
792 		mpacpi_intr_index++;
793 	}
794 
795 	mpacpi_user_continue("done setting up mp_bus array and ISA maps");
796 
797 	if (acpi_madt_map() == AE_OK) {
798 		acpi_madt_walk(mpacpi_nonpci_intr, &mpacpi_intr_index);
799 		acpi_madt_unmap();
800 	}
801 
802 	mpacpi_user_continue("done with non-PCI interrupts");
803 
804 #if NPCI > 0
805 	TAILQ_FOREACH(mpr, &mpacpi_pcibusses, mpr_list) {
806 		mpacpi_pciroute(mpr);
807 	}
808 #endif
809 
810 	mpacpi_user_continue("done routing PCI interrupts");
811 
812 	mp_nintr = mpacpi_intr_index;
813 }
814 
815 /*
816  * XXX code duplication with mpbios.c
817  */
818 
819 #if NPCI > 0
820 static void
821 mpacpi_print_pci_intr(int intr)
822 {
823 	printf(" device %d INT_%c", (intr >> 2) & 0x1f, 'A' + (intr & 0x3));
824 }
825 #endif
826 
827 static void
828 mpacpi_print_isa_intr(int intr)
829 {
830 	printf(" irq %d", intr);
831 }
832 
833 static const char inttype_fmt[] = "\177\020"
834 		"f\0\2type\0" "=\1NMI\0" "=\2SMI\0" "=\3ExtINT\0";
835 
836 static const char flagtype_fmt[] = "\177\020"
837 		"f\0\2pol\0" "=\1Act Hi\0" "=\3Act Lo\0"
838 		"f\2\2trig\0" "=\1Edge\0" "=\3Level\0";
839 
840 static void
841 mpacpi_print_intr(struct mp_intr_map *mpi)
842 {
843 	char buf[256];
844 	int pin;
845 	struct pic *sc;
846 	const char *busname;
847 
848 	sc = mpi->ioapic;
849 	pin = mpi->ioapic_pin;
850 	if (mpi->bus != NULL)
851 		busname = mpi->bus->mb_name;
852 	else {
853 		switch (mpi->type) {
854 		case MPS_INTTYPE_NMI:
855 			busname = "NMI";
856 			break;
857 		case MPS_INTTYPE_SMI:
858 			busname = "SMI";
859 			break;
860 		case MPS_INTTYPE_ExtINT:
861 			busname = "ExtINT";
862 			break;
863 		default:
864 			busname = "<unknown>";
865 			break;
866 		}
867 	}
868 
869 	if (mpi->linkdev != NULL)
870 		printf("linkdev %s attached to %s",
871 		    acpi_pci_link_name(mpi->linkdev), busname);
872 	else
873 		printf("%s: pin %d attached to %s",
874 		    sc ? sc->pic_name : "local apic",
875 		    pin, busname);
876 
877 	if (mpi->bus != NULL) {
878 		if (mpi->bus->mb_idx != -1)
879 			printf("%d", mpi->bus->mb_idx);
880 		(*(mpi->bus->mb_intr_print))(mpi->bus_pin);
881 	}
882 	snprintb(buf, sizeof(buf), inttype_fmt, mpi->type);
883 	printf(" (type %s", buf);
884 
885 	snprintb(buf, sizeof(buf), flagtype_fmt, mpi->flags);
886 	printf(" flags %s)\n", buf);
887 
888 }
889 
890 
891 int
892 mpacpi_find_interrupts(void *self)
893 {
894 #if NIOAPIC > 0
895 	ACPI_STATUS rv;
896 #endif
897 	struct acpi_softc *acpi = self;
898 	int i;
899 
900 #ifdef MPBIOS
901 	/*
902 	 * If MPBIOS was enabled, and did the work (because the initial
903 	 * MADT scan failed for some reason), there's nothing left to
904 	 * do here. Same goes for the case where no I/O APICS were found.
905 	 */
906 	if (mpbios_scanned)
907 		return 0;
908 #endif
909 
910 #if NIOAPIC > 0
911 	if (mpacpi_nioapic != 0) {
912 		/*
913 		 * Switch us into APIC mode by evaluating _PIC(1).
914 		 * Needs to be done now, since it has an effect on
915 		 * the interrupt information we're about to retrieve.
916 		 *
917 		 * ACPI 3.0 (section 5.8.1):
918 		 *   0 = PIC mode, 1 = APIC mode, 2 = SAPIC mode.
919 		 */
920 		rv = acpi_eval_set_integer(NULL, "\\_PIC", 1);
921 		if (ACPI_FAILURE(rv) && rv != AE_NOT_FOUND) {
922 			if (mp_verbose)
923 				printf("mpacpi: switch to APIC mode failed\n");
924 			return 0;
925 		}
926 	}
927 #endif
928 
929 #if NPCI > 0
930 	mpacpi_user_continue("finding PCI busses ");
931 	mpacpi_find_pcibusses(acpi);
932 	if (mp_verbose)
933 		printf("mpacpi: %d PCI busses\n", mpacpi_npci);
934 #endif
935 	mpacpi_config_irouting(acpi);
936 	if (mp_verbose)
937 		for (i = 0; i < mp_nintr; i++)
938 			mpacpi_print_intr(&mp_intrs[i]);
939 	return 0;
940 }
941 
942 #if NPCI > 0
943 
944 static void
945 mpacpi_set_devhandle(device_t self, struct pcibus_attach_args *pba)
946 {
947 	devhandle_t devhandle = device_handle(self);
948 	struct mpacpi_pcibus *mpr;
949 
950 	/* If we already have a valid handle, eject now. */
951 	if (devhandle_type(devhandle) != DEVHANDLE_TYPE_INVALID) {
952 		return;
953 	}
954 
955 	TAILQ_FOREACH(mpr, &mpacpi_pcibusses, mpr_list) {
956 		/* XXX Assuming always segment 0 on x86. */
957 		if (mpr->mpr_seg != 0) {
958 			continue;
959 		}
960 		if (mpr->mpr_bus == pba->pba_bus) {
961 			device_set_handle(self, mpr->mpr_devhandle);
962 			return;
963 		}
964 	}
965 }
966 
967 int
968 mpacpi_pci_attach_hook(device_t parent, device_t self,
969 		       struct pcibus_attach_args *pba)
970 {
971 	struct mp_bus *mpb;
972 
973 #ifdef MPBIOS
974 	if (mpbios_scanned != 0)
975 		return ENOENT;
976 #endif
977 
978 	if (TAILQ_EMPTY(&mpacpi_pcibusses))
979 		return 0;
980 
981 	/*
982 	 * If this bus is not found in mpacpi_find_pcibusses
983 	 * (i.e. behind PCI-to-PCI bridge), register as an extra bus.
984 	 *
985 	 * at this point, mp_busses[] are as follows:
986 	 *  mp_busses[0 .. mpacpi_maxpci] : PCI
987 	 *  mp_busses[mpacpi_maxpci + BUS_BUFFER] : ISA
988 	 */
989 	if (pba->pba_bus >= mp_isa_bus) {
990 		intr_add_pcibus(pba);
991 		return 0;
992 	}
993 
994 	mpb = &mp_busses[pba->pba_bus];
995 	if (mpb->mb_name != NULL) {
996 		if (strcmp(mpb->mb_name, "pci"))
997 			return EINVAL;
998 	} else {
999 		/*
1000 		 * As we cannot find all PCI-to-PCI bridge in
1001 		 * mpacpi_find_pcibusses, some of the MP_busses may remain
1002 		 * uninitialized.
1003 		 */
1004 		mpb->mb_name = "pci";
1005 	}
1006 
1007 	mpacpi_set_devhandle(self, pba);
1008 
1009 	mpb->mb_dev = self;
1010 	mpb->mb_pci_bridge_tag = pba->pba_bridgetag;
1011 	mpb->mb_pci_chipset_tag = pba->pba_pc;
1012 
1013 	if (mp_verbose)
1014 		printf("\n%s: added to list as bus %d", device_xname(parent),
1015 		    pba->pba_bus);
1016 
1017 
1018 	if (pba->pba_bus > mpacpi_maxpci)
1019 		mpacpi_maxpci = pba->pba_bus;
1020 
1021 	return 0;
1022 }
1023 #endif
1024 
1025 int
1026 mpacpi_findintr_linkdev(struct mp_intr_map *mip)
1027 {
1028 	int irq, line, pol, trig;
1029 	struct pic *pic;
1030 	int pin;
1031 
1032 	if (mip->linkdev == NULL)
1033 		return ENOENT;
1034 
1035 	irq = acpi_pci_link_route_interrupt(mip->linkdev, NULL,
1036 	    mip->sourceindex, &line, &pol, &trig);
1037 	if (mp_verbose)
1038 		printf("linkdev %s returned ACPI global irq %d, line %d\n",
1039 		    acpi_pci_link_name(mip->linkdev), irq, line);
1040 	if (irq == X86_PCI_INTERRUPT_LINE_NO_CONNECTION)
1041 		return ENOENT;
1042 	if (irq != line) {
1043 		aprint_error("%s: mpacpi_findintr_linkdev:"
1044 		    " irq mismatch (%d vs %d)\n",
1045 		    acpi_pci_link_name(mip->linkdev), irq, line);
1046 		return ENOENT;
1047 	}
1048 
1049 	/*
1050 	 * Convert ACPICA values to MPS values
1051 	 */
1052 	if (pol == ACPI_ACTIVE_LOW)
1053 		pol = MPS_INTPO_ACTLO;
1054 	else
1055 		pol = MPS_INTPO_ACTHI;
1056 
1057 	if (trig == ACPI_EDGE_SENSITIVE)
1058 		trig = MPS_INTTR_EDGE;
1059 	else
1060 		trig = MPS_INTTR_LEVEL;
1061 
1062 	mip->flags = pol | (trig << 2);
1063 	mip->global_int = irq;
1064 	pic = intr_findpic(irq);
1065 	if (pic == NULL)
1066 		return ENOENT;
1067 	mip->ioapic = pic;
1068 	pin = irq - pic->pic_vecbase;
1069 
1070 	if (pic->pic_type == PIC_IOAPIC) {
1071 #if NIOAPIC > 0
1072 		mip->redir = (IOAPIC_REDLO_DEL_FIXED <<IOAPIC_REDLO_DEL_SHIFT);
1073 		if (pol ==  MPS_INTPO_ACTLO)
1074 			mip->redir |= IOAPIC_REDLO_ACTLO;
1075 		if (trig ==  MPS_INTTR_LEVEL)
1076 			mip->redir |= IOAPIC_REDLO_LEVEL;
1077 		mip->ioapic_ih = APIC_INT_VIA_APIC |
1078 		    (pic->pic_apicid << APIC_INT_APIC_SHIFT) |
1079 		    (pin << APIC_INT_PIN_SHIFT);
1080 		pic->pic_ioapic->sc_pins[pin].ip_map = mip;
1081 		mip->ioapic_pin = pin;
1082 #else
1083 		return ENOENT;
1084 #endif
1085 	} else
1086 		mip->ioapic_ih = pin;
1087 	return 0;
1088 }
1089 
1090 static void
1091 mpacpi_user_continue(const char *fmt, ...)
1092 {
1093 	va_list ap;
1094 
1095 	if (!mpacpi_step)
1096 		return;
1097 
1098 	printf("mpacpi: ");
1099 	va_start(ap, fmt);
1100 	vprintf(fmt, ap);
1101 	va_end(ap);
1102 	printf("<press any key to continue>\n>");
1103 	cngetc();
1104 }
1105 
1106 #ifdef DDB
1107 void
1108 mpacpi_dump(void)
1109 {
1110 	int i;
1111 	for (i = 0; i < mp_nintr; i++)
1112 		mpacpi_print_intr(&mp_intrs[i]);
1113 }
1114 #endif
1115