Moved here from sys/arch/i386/i386

This commit is contained in:
fvdl 2003-05-11 18:21:16 +00:00
parent def0e7acaa
commit a03460e886
2 changed files with 1112 additions and 0 deletions

View File

@ -0,0 +1,333 @@
/* $NetBSD: acpi_machdep.c,v 1.1 2003/05/11 18:21:16 fvdl Exp $ */
/*
* Copyright 2001 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Jason R. Thorpe for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Machine-dependent routines for ACPICA.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: acpi_machdep.c,v 1.1 2003/05/11 18:21:16 fvdl Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <uvm/uvm_extern.h>
#include <machine/bus.h>
#include <machine/cpufunc.h>
#include <dev/acpi/acpica.h>
#include <dev/acpi/acpivar.h>
#include <machine/acpi_machdep.h>
#include <machine/mpbiosvar.h>
#include <machine/mpacpi.h>
#include <machine/i82093var.h>
#include <machine/pic.h>
#include <dev/pci/pcivar.h>
#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
#include "ioapic.h"
#include "opt_mpacpi.h"
#include "opt_mpbios.h"
static int acpi_intrcold = 1;
struct acpi_intr_defer {
UINT32 number;
OSD_HANDLER function;
void *context;
void *ih;
LIST_ENTRY(acpi_intr_defer) list;
};
LIST_HEAD(, acpi_intr_defer) acpi_intr_deferq =
LIST_HEAD_INITIALIZER(acpi_intr_deferq);
ACPI_STATUS
acpi_md_OsInitialize(void)
{
/* Nothing to do, yet. */
return (AE_OK);
}
ACPI_STATUS
acpi_md_OsTerminate(void)
{
/* Nothing to do, yet. */
return (AE_OK);
}
ACPI_STATUS
acpi_md_OsGetRootPointer(UINT32 Flags, ACPI_POINTER *PhysicalAddress)
{
return (AcpiFindRootPointer(Flags, PhysicalAddress));
}
ACPI_STATUS
acpi_md_OsInstallInterruptHandler(UINT32 InterruptNumber,
OSD_HANDLER ServiceRoutine, void *Context, void **cookiep)
{
void *ih;
struct pic *pic;
int irq, pin, trigger;
struct acpi_intr_defer *aip;
#ifdef MPACPI
int i, h;
struct mp_intr_map *mip;
#endif
#if NIOAPIC > 0
struct ioapic_softc *sc;
#endif
if (acpi_intrcold) {
aip = malloc(sizeof(struct acpi_intr_defer), M_TEMP, M_WAITOK);
aip->number = InterruptNumber;
aip->function = ServiceRoutine;
aip->context = Context;
aip->ih = NULL;
LIST_INSERT_HEAD(&acpi_intr_deferq, aip, list);
*cookiep = (void *)aip;
return AE_OK;
}
trigger = IST_LEVEL;
#ifdef MPACPI
/*
* Can only match on ACPI global interrupt numbers if the ACPI
* interrupt info was extracted, which is in the MPACPI case.
*/
if (mp_busses == NULL)
goto nomap;
for (i = 0; i < mp_nbus; i++) {
for (mip = mp_busses[i].mb_intrs; mip != NULL;
mip = mip->next) {
if (mip->global_int == (int)InterruptNumber) {
h = mip->ioapic_ih;
if (APIC_IRQ_ISLEGACY(h)) {
irq = APIC_IRQ_LEGACY_IRQ(h);
pin = irq;
pic = &i8259_pic;
trigger = IST_EDGE;
} else {
sc = ioapic_find(APIC_IRQ_APIC(h));
if (sc == NULL)
goto nomap;
pic = (struct pic *)sc;
pin = APIC_IRQ_PIN(h);
irq = -1;
trigger =
((mip->flags >> 2) & 3) ==
MPS_INTTR_EDGE ?
IST_EDGE : IST_LEVEL;
}
goto found;
}
}
}
nomap:
#endif
#if NIOAPIC > 0
pin = (int)InterruptNumber;
for (sc = ioapics ; sc != NULL && pin > sc->sc_apic_sz;
sc = sc->sc_next)
pin -= sc->sc_apic_sz;
if (sc != NULL) {
if (nioapics > 1)
printf("acpi: WARNING: no matching "
"I/O apic for SCI, assuming %s\n",
sc->sc_pic.pic_dev.dv_xname);
pic = (struct pic *)sc;
irq = -1;
} else
#endif
{
pic = &i8259_pic;
irq = pin = (int)InterruptNumber;
}
#ifdef MPACPI
found:
#endif
/*
* XXX probably, IPL_BIO is enough.
*/
ih = intr_establish(irq, pic, pin, trigger, IPL_VM,
(int (*)(void *)) ServiceRoutine, Context);
if (ih == NULL)
return (AE_NO_MEMORY);
*cookiep = ih;
return (AE_OK);
}
void
acpi_md_OsRemoveInterruptHandler(void *cookie)
{
struct acpi_intr_defer *aip;
LIST_FOREACH(aip, &acpi_intr_deferq, list) {
if (aip == cookie) {
if (aip->ih != NULL)
intr_disestablish(aip->ih);
return;
}
}
intr_disestablish(cookie);
}
ACPI_STATUS
acpi_md_OsMapMemory(ACPI_PHYSICAL_ADDRESS PhysicalAddress,
UINT32 Length, void **LogicalAddress)
{
if (_x86_memio_map(X86_BUS_SPACE_MEM, PhysicalAddress, Length,
0, (bus_space_handle_t *) LogicalAddress) == 0)
return (AE_OK);
return (AE_NO_MEMORY);
}
void
acpi_md_OsUnmapMemory(void *LogicalAddress, UINT32 Length)
{
(void) _x86_memio_unmap(X86_BUS_SPACE_MEM,
(bus_space_handle_t) LogicalAddress, Length, NULL);
}
ACPI_STATUS
acpi_md_OsGetPhysicalAddress(void *LogicalAddress,
ACPI_PHYSICAL_ADDRESS *PhysicalAddress)
{
paddr_t pa;
if (pmap_extract(pmap_kernel(), (vaddr_t) LogicalAddress, &pa)) {
*PhysicalAddress = pa;
return (AE_OK);
}
return (AE_ERROR);
}
BOOLEAN
acpi_md_OsReadable(void *Pointer, UINT32 Length)
{
BOOLEAN rv = TRUE;
vaddr_t sva, eva;
pt_entry_t *pte;
sva = trunc_page((vaddr_t) Pointer);
eva = round_page((vaddr_t) Pointer + Length);
if (sva < VM_MIN_KERNEL_ADDRESS)
return (FALSE);
for (; sva < eva; sva += PAGE_SIZE) {
pte = kvtopte(sva);
if ((*pte & PG_V) == 0) {
rv = FALSE;
break;
}
}
return (rv);
}
BOOLEAN
acpi_md_OsWritable(void *Pointer, UINT32 Length)
{
BOOLEAN rv = FALSE;
vaddr_t sva, eva;
pt_entry_t *pte;
sva = trunc_page((vaddr_t) Pointer);
eva = round_page((vaddr_t) Pointer + Length);
if (sva < VM_MIN_KERNEL_ADDRESS)
return (FALSE);
for (; sva < eva; sva += PAGE_SIZE) {
pte = kvtopte(sva);
if ((*pte & (PG_V|PG_W)) != (PG_V|PG_W)) {
rv = FALSE;
break;
}
}
return (rv);
}
void
acpi_md_OsDisableInterrupt(void)
{
disable_intr();
}
void
acpi_md_callback(struct device *acpi)
{
struct acpi_intr_defer *aip;
#ifdef MPACPI
#ifdef MPBIOS
if (!mpbios_scanned)
#endif
mpacpi_find_interrupts(acpi);
#endif
acpi_intrcold = 0;
/* Proces deferred interrupt handler establish calls. */
LIST_FOREACH(aip, &acpi_intr_deferq, list) {
acpi_md_OsInstallInterruptHandler(aip->number, aip->function,
aip->context, &aip->ih);
}
}

779
sys/arch/x86/x86/mpacpi.c Normal file
View File

@ -0,0 +1,779 @@
/* $NetBSD: mpacpi.c,v 1.1 2003/05/11 18:21:50 fvdl Exp $ */
/*
* Copyright (c) 2003 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Frank van der Linden for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "opt_acpi.h"
#include "opt_mpbios.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/queue.h>
#include <uvm/uvm_extern.h>
#include <machine/specialreg.h>
#include <machine/cputypes.h>
#include <machine/cpuvar.h>
#include <machine/bus.h>
#include <machine/mpacpi.h>
#include <machine/mpbiosvar.h>
#include <machine/i82093reg.h>
#include <machine/i82093var.h>
#include <machine/i82489reg.h>
#include <machine/i82489var.h>
#include <dev/isa/isareg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/ppbreg.h>
#include <dev/acpi/acpivar.h>
#include <dev/acpi/acpi_madt.h>
/* XXX */
#include <dev/acpi/acpica/Subsystem/actables.h>
#include <dev/acpi/acpica/Subsystem/acnamesp.h>
#include "pci.h"
#if NPCI > 0
struct mpacpi_pcibus {
TAILQ_ENTRY(mpacpi_pcibus) mpr_list;
ACPI_NAMESPACE_NODE *mpr_node;
ACPI_HANDLE *mpr_handle; /* Same thing really, but.. */
int mpr_bus;
int mpr_level;
struct mpacpi_pcibus *mpr_parent;
};
TAILQ_HEAD(, mpacpi_pcibus) mpacpi_pcibusses;
#endif
int mpacpi_print(void *, const char *);
int mpacpi_match(struct device *, struct cfdata *, void *);
/*
* acpi_madt_walk callbacks
*/
static ACPI_STATUS mpacpi_count(APIC_HEADER *, void *);
static ACPI_STATUS mpacpi_config_cpu(APIC_HEADER *, void *);
static ACPI_STATUS mpacpi_config_ioapic(APIC_HEADER *, void *);
static ACPI_STATUS mpacpi_nonpci_intr(APIC_HEADER *, void *);
#if NPCI > 0
/*
* Callbacks for the device namespace walk.
*/
static ACPI_STATUS mpacpi_pcibus_cb(ACPI_HANDLE, UINT32, void *, void **);
static int mpacpi_pcircount(struct mpacpi_pcibus *);
static int mpacpi_pciroute(struct mpacpi_pcibus *);
static void mpacpi_pcihier(struct acpi_softc *, struct mpacpi_pcibus *);
static struct mpacpi_pcibus *mpacpi_find_pcibus(ACPI_NAMESPACE_NODE *);
static int mpacpi_find_pcibusses(struct acpi_softc *);
static void mpacpi_print_pci_intr(int);
#endif
static void mpacpi_config_irouting(struct acpi_softc *);
static void mpacpi_print_intr(struct mp_intr_map *);
static void mpacpi_print_isa_intr(int);
int mpacpi_nioapic;
int mpacpi_ncpu;
int mpacpi_nintsrc;
#if NPCI > 0
int mpacpi_npci;
int mpacpi_maxpci;
static int mpacpi_maxbuslevel;
static int mpacpi_npciroots;
#endif
static int mpacpi_intr_index;
static paddr_t mpacpi_lapic_base = LAPIC_BASE;
int
mpacpi_print(void *aux, const char *pnp)
{
struct cpu_attach_args * caa = (struct cpu_attach_args *) aux;
if (pnp)
printf("%s at %s:",caa->caa_name, pnp);
return (UNCONF);
}
int
mpacpi_match(struct device *parent, struct cfdata *cf, void *aux)
{
struct cpu_attach_args * caa = (struct cpu_attach_args *) aux;
if (strcmp(caa->caa_name, cf->cf_name))
return 0;
return (config_match(parent, cf, aux));
}
/*
* Handle special interrupt sources and overrides from the MADT.
* This is a callback function for acpi_madt_walk().
*/
static ACPI_STATUS
mpacpi_nonpci_intr(APIC_HEADER *hdrp, void *aux)
{
int *index = aux, pin, lindex;
struct mp_intr_map *mpi;
INT_IOAPIC_SOURCE_NMI *ioapic_nmi;
INT_LAPIC_SOURCE_NMI *lapic_nmi;
INT_SOURCE_OVERRIDE *isa_ovr;
struct ioapic_softc *ioapic;
switch (hdrp->Type) {
case APIC_INTSRC_NMI:
ioapic_nmi = (INT_IOAPIC_SOURCE_NMI *)hdrp;
ioapic = ioapic_find_bybase(ioapic_nmi->GlobalInt);
if (ioapic == NULL)
break;
mpi = &mp_intrs[*index];
(*index)++;
mpi->next = NULL;
mpi->bus = NULL;
mpi->type = MPS_INTTYPE_NMI;
mpi->ioapic = ioapic;
pin = ioapic_nmi->GlobalInt - ioapic->sc_apic_vecbase;
mpi->ioapic_pin = pin;
mpi->bus_pin = -1;
mpi->redir = (IOAPIC_REDLO_DEL_NMI<<IOAPIC_REDLO_DEL_SHIFT);
ioapic->sc_pins[pin].ip_map = mpi;
mpi->ioapic_ih = APIC_INT_VIA_APIC |
(ioapic->sc_apicid << APIC_INT_APIC_SHIFT) |
(pin << APIC_INT_PIN_SHIFT);
mpi->flags = ioapic_nmi->Polarity | (ioapic_nmi->Trigger << 2);
mpi->global_int = ioapic_nmi->GlobalInt;
break;
case APIC_LAPIC_NMI:
lapic_nmi = (INT_LAPIC_SOURCE_NMI *)hdrp;
mpi = &mp_intrs[*index];
(*index)++;
mpi->next = NULL;
mpi->bus = NULL;
mpi->ioapic = NULL;
mpi->type = MPS_INTTYPE_NMI;
mpi->ioapic_pin = lapic_nmi->Lint;
mpi->cpu_id = lapic_nmi->ApicId;
mpi->redir = (IOAPIC_REDLO_DEL_NMI<<IOAPIC_REDLO_DEL_SHIFT);
mpi->global_int = -1;
break;
case APIC_INTSRC_OVR:
isa_ovr = (INT_SOURCE_OVERRIDE *)hdrp;
if (isa_ovr->Source > 15 || isa_ovr->Source == 2)
break;
ioapic = ioapic_find_bybase(isa_ovr->GlobalInt);
if (ioapic == NULL)
break;
pin = isa_ovr->GlobalInt - ioapic->sc_apic_vecbase;
lindex = isa_ovr->Source;
/*
* IRQ 2 was skipped in the default setup.
*/
if (lindex > 2)
lindex--;
mpi = &mp_intrs[lindex];
mpi->ioapic_ih = APIC_INT_VIA_APIC |
(ioapic->sc_apicid << APIC_INT_APIC_SHIFT) |
(pin << APIC_INT_PIN_SHIFT);
mpi->bus_pin = isa_ovr->Source;
mpi->ioapic_pin = pin;
mpi->redir = 0;
switch (isa_ovr->Polarity) {
case MPS_INTPO_ACTHI:
mpi->redir &= ~IOAPIC_REDLO_ACTLO;
break;
case MPS_INTPO_DEF:
case MPS_INTPO_ACTLO:
mpi->redir |= IOAPIC_REDLO_ACTLO;
break;
}
mpi->redir |= (IOAPIC_REDLO_DEL_LOPRI<<IOAPIC_REDLO_DEL_SHIFT);
switch (isa_ovr->Trigger) {
case MPS_INTTR_DEF:
case MPS_INTTR_LEVEL:
mpi->redir |= IOAPIC_REDLO_LEVEL;
break;
case MPS_INTTR_EDGE:
mpi->redir &= ~IOAPIC_REDLO_LEVEL;
break;
}
mpi->flags = isa_ovr->Polarity | (isa_ovr->Trigger << 2);
ioapic->sc_pins[pin].ip_map = mpi;
default:
break;
}
return AE_OK;
}
/*
* Count various MP resources present in the MADT.
* This is a callback function for acpi_madt_walk().
*/
static ACPI_STATUS
mpacpi_count(APIC_HEADER *hdrp, void *aux)
{
LAPIC_ADDR_OVR *lop;
switch (hdrp->Type) {
case APIC_PROC:
mpacpi_ncpu++;
break;
case APIC_IO:
mpacpi_nioapic++;
break;
case APIC_INTSRC_NMI:
case APIC_LAPIC_NMI:
mpacpi_nintsrc++;
break;
case APIC_ADDR_OVR:
lop = (LAPIC_ADDR_OVR *)hdrp;
mpacpi_lapic_base = lop->LocalApicAddress;
default:
break;
}
return AE_OK;
}
static ACPI_STATUS
mpacpi_config_cpu(APIC_HEADER *hdrp, void *aux)
{
struct device *parent = aux;
PROCESSOR_APIC *p;
struct cpu_attach_args caa;
if (hdrp->Type == APIC_PROC) {
p = (PROCESSOR_APIC *)hdrp;
if (p->ProcessorEnabled) {
/*
* Assume ACPI Id 0 == BSP.
* XXX check if that's correct.
* XXX field name in structure is wrong.
*/
if (p->ProcessorApicId == 0)
caa.cpu_role = CPU_ROLE_BP;
else
caa.cpu_role = CPU_ROLE_AP;
caa.caa_name = "cpu";
caa.cpu_number = p->LocalApicId;
caa.cpu_func = &mp_cpu_funcs;
config_found_sm(parent, &caa, mpacpi_print,
mpacpi_match);
}
}
return AE_OK;
}
static ACPI_STATUS
mpacpi_config_ioapic(APIC_HEADER *hdrp, void *aux)
{
struct device *parent = aux;
struct apic_attach_args aaa;
IO_APIC *p;
if (hdrp->Type == APIC_IO) {
p = (IO_APIC *)hdrp;
aaa.aaa_name = "ioapic";
aaa.apic_id = p->IoApicId;
aaa.apic_address = p->IoApicAddress;
aaa.apic_version = -1;
aaa.flags = IOAPIC_VWIRE;
aaa.apic_vecbase = p->Vector;
config_found_sm(parent, &aaa, mpacpi_print, mpacpi_match);
}
return AE_OK;
}
int
mpacpi_scan_apics(struct device *self)
{
if (acpi_madt_map() != AE_OK)
return 0;
mpacpi_ncpu = mpacpi_nintsrc = mpacpi_nioapic = 0;
acpi_madt_walk(mpacpi_count, self);
lapic_boot_init(mpacpi_lapic_base);
if (mpacpi_ncpu == 0)
return 0;
acpi_madt_walk(mpacpi_config_cpu, self);
acpi_madt_walk(mpacpi_config_ioapic, self);
acpi_madt_unmap();
return 1;
}
#if NPCI > 0
static struct mpacpi_pcibus *
mpacpi_find_pcibus(ACPI_NAMESPACE_NODE *node)
{
struct mpacpi_pcibus *mpr;
TAILQ_FOREACH(mpr, &mpacpi_pcibusses, mpr_list) {
if (mpr->mpr_node == node)
return mpr;
}
return NULL;
}
static int
mpacpi_find_pcibusses(struct acpi_softc *acpi)
{
ACPI_HANDLE sbhandle;
if (AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &sbhandle) != AE_OK)
return ENOENT;
TAILQ_INIT(&mpacpi_pcibusses);
AcpiWalkNamespace(ACPI_TYPE_DEVICE, sbhandle, 100,
mpacpi_pcibus_cb, acpi, NULL);
return 0;
}
/*
* Callback function for a namespace walk through ACPI space, finding all
* PCI root busses.
*/
static ACPI_STATUS
mpacpi_pcibus_cb(ACPI_HANDLE handle, UINT32 level, void *ct, void **status)
{
ACPI_STATUS ret;
ACPI_NAMESPACE_NODE *node;
ACPI_BUFFER buf;
ACPI_INTEGER val;
struct mpacpi_pcibus *mpr;
ret = acpi_get(handle, &buf, AcpiGetIrqRoutingTable);
if (ACPI_FAILURE(ret))
return AE_OK;
AcpiOsFree(buf.Pointer);
mpr = malloc(sizeof (struct mpacpi_pcibus), M_TEMP, M_WAITOK|M_ZERO);
if (mpr == NULL)
return AE_NO_MEMORY;
node = AcpiNsMapHandleToNode(handle);
if (level == 1) {
ret = AcpiUtEvaluateNumericObject(METHOD_NAME__BBN,
node, &val);
if (ACPI_FAILURE(ret)) {
mpr->mpr_bus = mpacpi_npciroots;
if (mp_verbose)
printf("mpacpi: could not get bus number for "
"PCI root bus, assuming %d\n",
mpr->mpr_bus);
} else
mpr->mpr_bus = ACPI_LOWORD(val);
mpacpi_npciroots++;
mpr->mpr_parent = NULL;
if (mp_verbose)
printf("mpacpi: found root PCI bus %d at level %u\n",
mpr->mpr_bus, level);
} else {
mpr->mpr_bus = -1;
if (mp_verbose)
printf("mpacpi: found subordinate bus at level %u\n",
level);
}
mpr->mpr_handle = handle;
mpr->mpr_node = node;
mpr->mpr_level = (int)level;
TAILQ_INSERT_TAIL(&mpacpi_pcibusses, mpr, mpr_list);
mpacpi_npci++;
if ((int)level > mpacpi_maxbuslevel)
mpacpi_maxbuslevel = level;
return AE_OK;
}
static void
mpacpi_pcihier(struct acpi_softc *acpi, struct mpacpi_pcibus *mpr)
{
ACPI_NAMESPACE_NODE *parentnode;
ACPI_STATUS ret;
ACPI_INTEGER val;
struct mpacpi_pcibus *parentmpr;
pcireg_t binf;
pcitag_t tag;
if (mpr->mpr_bus == -1) {
parentnode = AcpiNsGetParentNode(mpr->mpr_node);
parentmpr = mpacpi_find_pcibus(parentnode);
if (parentmpr == NULL) {
if (mp_verbose)
printf("mpacpi: no parent bus at level %d\n",
mpr->mpr_level);
return;
}
ret = AcpiUtEvaluateNumericObject(METHOD_NAME__ADR,
mpr->mpr_node, &val);
if (ACPI_FAILURE(ret))
return;
tag = pci_make_tag(acpi->sc_pc, parentmpr->mpr_bus,
ACPI_HIWORD(val), ACPI_LOWORD(val));
binf = pci_conf_read(acpi->sc_pc, tag, PPB_REG_BUSINFO);
mpr->mpr_bus = PPB_BUSINFO_SECONDARY(binf);
mpr->mpr_parent = parentmpr;
if (mp_verbose)
printf("mpacpi: found subordinate PCI bus %d\n",
mpr->mpr_bus);
}
if (mpr->mpr_bus > mpacpi_maxpci)
mpacpi_maxpci = mpr->mpr_bus;
}
/*
* Find all static PRT entries for a PCI bus.
*/
static int
mpacpi_pciroute(struct mpacpi_pcibus *mpr)
{
ACPI_STATUS ret;
ACPI_BUFFER buf;
ACPI_PCI_ROUTING_TABLE *ptrp;
char *p;
struct mp_intr_map *mpi;
struct mp_bus *mpb;
struct ioapic_softc *ioapic;
unsigned dev;
int pin;
ret = acpi_get(mpr->mpr_handle, &buf, AcpiGetIrqRoutingTable);
if (ACPI_FAILURE(ret))
return -1;
if (mp_verbose)
printf("mpacpi: configuring PCI bus %d int routing\n",
mpr->mpr_bus);
mpb = &mp_busses[mpr->mpr_bus];
mpb->mb_intrs = NULL;
mpb->mb_name = "pci";
mpb->mb_idx = mpr->mpr_bus;
mpb->mb_intr_print = mpacpi_print_pci_intr;
mpb->mb_intr_cfg = NULL;
mpb->mb_data = 0;
for (p = buf.Pointer; ; p += ptrp->Length) {
ptrp = (ACPI_PCI_ROUTING_TABLE *)p;
if (ptrp->Length == 0)
break;
dev = ACPI_HIWORD(ptrp->Address);
if (ptrp->Source[0] != 0)
continue;
ioapic = ioapic_find_bybase(ptrp->SourceIndex);
if (ioapic == NULL)
continue;
mpi = &mp_intrs[mpacpi_intr_index++];
mpi->bus = mpb;
mpi->bus_pin = (dev << 2) | ptrp->Pin;
mpi->type = MPS_INTTYPE_INT;
/* Defaults for PCI (active low, level triggered) */
mpi->redir = (IOAPIC_REDLO_DEL_LOPRI<<IOAPIC_REDLO_DEL_SHIFT) |
IOAPIC_REDLO_LEVEL | IOAPIC_REDLO_ACTLO;
mpi->flags = MPS_INTPO_ACTLO | (MPS_INTTR_LEVEL << 2);
mpi->cpu_id = 0;
pin = ptrp->SourceIndex - ioapic->sc_apic_vecbase;
mpi->ioapic = ioapic;
mpi->ioapic_pin = pin;
mpi->ioapic_ih = APIC_INT_VIA_APIC |
(ioapic->sc_apicid << APIC_INT_APIC_SHIFT) |
(pin << APIC_INT_PIN_SHIFT);
ioapic->sc_pins[pin].ip_map = mpi;
mpi->next = mpb->mb_intrs;
mpi->global_int = ptrp->SourceIndex;
mpb->mb_intrs = mpi;
}
AcpiOsFree(buf.Pointer);
return 0;
}
static int
mpacpi_pcircount(struct mpacpi_pcibus *mpr)
{
int count = 0;
ACPI_STATUS ret;
ACPI_BUFFER buf;
ACPI_PCI_ROUTING_TABLE *PrtElement;
UINT8 *Buffer;
ret = acpi_get(mpr->mpr_handle, &buf, AcpiGetIrqRoutingTable);
if (!ACPI_FAILURE(ret)) {
for (Buffer = buf.Pointer; ; Buffer += PrtElement->Length) {
PrtElement = (ACPI_PCI_ROUTING_TABLE *)Buffer;
if (PrtElement->Length == 0)
break;
count++;
}
AcpiOsFree(buf.Pointer);
}
return count;
}
#endif
/*
* Set up the interrupt config lists, in the same format as the mpbios
* does.
*/
static void
mpacpi_config_irouting(struct acpi_softc *acpi)
{
#if NPCI > 0
struct mpacpi_pcibus *mpr;
#endif
int nintr;
int i, index;
struct mp_bus *mbp;
struct mp_intr_map *mpi;
struct ioapic_softc *ioapic;
nintr = mpacpi_nintsrc + NUM_LEGACY_IRQS - 1;
#if NPCI > 0
TAILQ_FOREACH(mpr, &mpacpi_pcibusses, mpr_list) {
nintr += mpacpi_pcircount(mpr);
}
for (i = 0; i <= mpacpi_maxbuslevel; i++) {
TAILQ_FOREACH(mpr, &mpacpi_pcibusses, mpr_list) {
if (mpr->mpr_level == i)
mpacpi_pcihier(acpi, mpr);
}
}
mp_isa_bus = mpacpi_maxpci + 1;
#else
mp_isa_bus = 0;
#endif
mp_nbus = mp_isa_bus + 1;
mp_nintr = nintr + mpacpi_nintsrc + NUM_LEGACY_IRQS - 1;
mp_busses = malloc(sizeof(struct mp_bus) * mp_nbus, M_DEVBUF,
M_NOWAIT|M_ZERO);
if (mp_busses == NULL)
panic("can't allocate mp_busses");
mp_intrs = malloc(sizeof(struct mp_intr_map) * mp_nintr, M_DEVBUF,
M_NOWAIT|M_ZERO);
if (mp_intrs == NULL)
panic("can't allocate mp_intrs");
mbp = &mp_busses[mp_isa_bus];
mbp->mb_name = "isa";
mbp->mb_idx = 0;
mbp->mb_intr_print = mpacpi_print_isa_intr;
mbp->mb_intr_cfg = NULL;
mbp->mb_intrs = &mp_intrs[0];
mbp->mb_data = 0;
ioapic = ioapic_find_bybase(0);
if (ioapic == NULL)
panic("can't find first ioapic");
/*
* Set up default identity mapping for ISA irqs to first ioapic.
*/
for (i = index = 0; i < NUM_LEGACY_IRQS; i++) {
if (i == 2)
continue;
mpi = &mp_intrs[index];
if (index < (NUM_LEGACY_IRQS - 2))
mpi->next = &mp_intrs[index + 1];
else
mpi->next = NULL;
mpi->bus = mbp;
mpi->bus_pin = i;
mpi->ioapic_pin = i;
mpi->ioapic = ioapic;
mpi->type = MPS_INTTYPE_INT;
mpi->cpu_id = 0;
mpi->ioapic_ih = APIC_INT_VIA_APIC |
(ioapic->sc_apicid << APIC_INT_APIC_SHIFT) |
(i << APIC_INT_PIN_SHIFT);
mpi->redir = (IOAPIC_REDLO_DEL_LOPRI<<IOAPIC_REDLO_DEL_SHIFT);
mpi->flags = MPS_INTPO_DEF | (MPS_INTTR_DEF << 2);
mpi->global_int = i;
ioapic->sc_pins[i].ip_map = mpi;
index++;
}
mpacpi_intr_index = index;
if (acpi_madt_map() != AE_OK)
panic("failed to map the MADT a second time");
acpi_madt_walk(mpacpi_nonpci_intr, &mpacpi_intr_index);
acpi_madt_unmap();
#if NPCI > 0
TAILQ_FOREACH(mpr, &mpacpi_pcibusses, mpr_list) {
mpacpi_pciroute(mpr);
}
#endif
mp_nintr = mpacpi_intr_index;
}
/*
* XXX code duplication with mpbios.c
*/
#if NPCI > 0
static void
mpacpi_print_pci_intr(int intr)
{
printf(" device %d INT_%c", (intr>>2)&0x1f, 'A' + (intr & 0x3));
}
#endif
static void
mpacpi_print_isa_intr(int intr)
{
printf(" irq %d", intr);
}
static const char inttype_fmt[] = "\177\020"
"f\0\2type\0" "=\1NMI\0" "=\2SMI\0" "=\3ExtINT\0";
static const char flagtype_fmt[] = "\177\020"
"f\0\2pol\0" "=\1Act Hi\0" "=\3Act Lo\0"
"f\2\2trig\0" "=\1Edge\0" "=\3Level\0";
static void
mpacpi_print_intr(struct mp_intr_map *mpi)
{
char buf[256];
int pin;
struct ioapic_softc *sc;
char *busname;
sc = mpi->ioapic;
pin = mpi->ioapic_pin;
if (mpi->bus != NULL)
busname = mpi->bus->mb_name;
else {
switch (mpi->type) {
case MPS_INTTYPE_NMI:
busname = "NMI";
break;
case MPS_INTTYPE_SMI:
busname = "SMI";
break;
case MPS_INTTYPE_ExtINT:
busname = "ExtINT";
break;
default:
busname = "<unknown>";
break;
}
}
printf("%s: int%d attached to %s",
sc ? sc->sc_pic.pic_dev.dv_xname : "local apic",
pin, busname);
if (mpi->bus != NULL) {
if (mpi->bus->mb_idx != -1)
printf("%d", mpi->bus->mb_idx);
(*(mpi->bus->mb_intr_print))(mpi->bus_pin);
}
printf(" (type %s",
bitmask_snprintf(mpi->type, inttype_fmt, buf, sizeof(buf)));
printf(" flags %s)\n",
bitmask_snprintf(mpi->flags, flagtype_fmt, buf, sizeof(buf)));
}
int
mpacpi_find_interrupts(void *self)
{
ACPI_OBJECT_LIST arglist;
ACPI_OBJECT arg;
ACPI_STATUS ret;
struct acpi_softc *acpi = self;
int i;
#ifdef MPBIOS
/*
* If MPBIOS was enabled, and did the work (because the initial
* MADT scan failed for some reason), there's nothing left to
* do here. Same goes for the case where no I/O APICS were found.
*/
if (mpbios_scanned)
return 0;
#endif
if (mpacpi_nioapic == 0)
return 0;
/*
* Switch us into APIC mode by evaluating the _PIC(1).
* Needs to be done now, since it has an effect on
* the interrupt information we're about to retrieve.
*/
arglist.Count = 1;
arglist.Pointer = &arg;
arg.Type = ACPI_TYPE_INTEGER;
arg.Integer.Value = 1; /* I/O APIC mode (0 = PIC, 2 = IOSAPIC) */
ret = AcpiEvaluateObject(NULL, "\\_PIC", &arglist, NULL);
if (ACPI_FAILURE(ret)) {
if (mp_verbose)
printf("mpacpi: switch to APIC mode failed\n");
return 0;
}
#if NPCI > 0
mpacpi_find_pcibusses(acpi);
if (mp_verbose)
printf("mpacpi: %d PCI busses\n", mpacpi_npci);
#endif
mpacpi_config_irouting(acpi);
if (mp_verbose)
for (i = 0; i < mp_nintr; i++)
mpacpi_print_intr(&mp_intrs[i]);
return 0;
}