Home | History | Annotate | Line # | Download | only in x86
      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