Try a little harder to find PCI buses in the MPACPI code, in a (probably

futile) attempt to get quirky ACPI implementations going.

Work around a problem with quirky MP tables for ioapic interrupt routing.
This commit is contained in:
fvdl 2003-05-15 13:30:31 +00:00
parent 6454d66c69
commit 74793a8cdd
3 changed files with 107 additions and 55 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: ioapic.c,v 1.5 2003/05/11 13:49:02 fvdl Exp $ */
/* $NetBSD: ioapic.c,v 1.6 2003/05/15 13:30:31 fvdl Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@ -119,6 +119,7 @@ int ioapic_cold = 1;
struct ioapic_softc *ioapics; /* head of linked list */
int nioapics = 0; /* number attached */
static int ioapic_vecbase;
static __inline u_long
ioapic_lock(struct ioapic_softc *sc)
@ -218,10 +219,6 @@ ioapic_find_bybase(int vec)
struct ioapic_softc *sc;
for (sc = ioapics; sc != NULL; sc = sc->sc_next) {
#ifdef DIAGNOSTIC
if (sc->sc_apic_vecbase == -1)
panic("finding ioapic by vector in non-ACPI case");
#endif
if (vec >= sc->sc_apic_vecbase &&
vec < (sc->sc_apic_vecbase + sc->sc_apic_sz))
return sc;
@ -312,6 +309,17 @@ ioapic_attach(struct device *parent, struct device *self, void *aux)
sc->sc_apic_sz = (ver_sz & IOAPIC_MAX_MASK) >> IOAPIC_MAX_SHIFT;
sc->sc_apic_sz++;
if (aaa->apic_vecbase != -1)
sc->sc_apic_vecbase = aaa->apic_vecbase;
else {
/*
* XXX this assumes ordering of ioapics in the table.
* Only needed for broken BIOS workaround (see mpbios.c)
*/
sc->sc_apic_vecbase = ioapic_vecbase;
ioapic_vecbase += sc->sc_apic_sz;
}
if (mp_verbose) {
printf(", %s mode",
aaa->flags & IOAPIC_PICMODE ? "PIC" : "virtual wire");

View File

@ -1,4 +1,4 @@
/* $NetBSD: mpacpi.c,v 1.2 2003/05/11 21:51:32 fvdl Exp $ */
/* $NetBSD: mpacpi.c,v 1.3 2003/05/15 13:30:31 fvdl Exp $ */
/*
* Copyright (c) 2003 Wasabi Systems, Inc.
@ -73,11 +73,14 @@
#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;
};
struct mpacpi_walk_status {
struct mpacpi_pcibus *mpw_mpr;
struct acpi_softc *mpw_acpi;
};
TAILQ_HEAD(, mpacpi_pcibus) mpacpi_pcibusses;
@ -102,8 +105,7 @@ static ACPI_STATUS mpacpi_nonpci_intr(APIC_HEADER *, void *);
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 ACPI_STATUS mpacpi_pcihier_cb(ACPI_HANDLE, UINT32, void *, void **);
static int mpacpi_find_pcibusses(struct acpi_softc *);
static void mpacpi_print_pci_intr(int);
@ -123,6 +125,7 @@ int mpacpi_npci;
int mpacpi_maxpci;
static int mpacpi_maxbuslevel;
static int mpacpi_npciroots;
static int mpacpi_npciknown;
#endif
static int mpacpi_intr_index;
@ -347,18 +350,6 @@ mpacpi_scan_apics(struct device *self)
#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)
{
@ -406,7 +397,6 @@ mpacpi_pcibus_cb(ACPI_HANDLE handle, UINT32 level, void *ct, void **status)
} 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);
@ -418,7 +408,6 @@ mpacpi_pcibus_cb(ACPI_HANDLE handle, UINT32 level, void *ct, void **status)
}
mpr->mpr_handle = handle;
mpr->mpr_node = node;
mpr->mpr_level = (int)level;
TAILQ_INSERT_TAIL(&mpacpi_pcibusses, mpr, mpr_list);
mpacpi_npci++;
@ -427,40 +416,58 @@ mpacpi_pcibus_cb(ACPI_HANDLE handle, UINT32 level, void *ct, void **status)
return AE_OK;
}
static void
mpacpi_pcihier(struct acpi_softc *acpi, struct mpacpi_pcibus *mpr)
static ACPI_STATUS
mpacpi_pcihier_cb(ACPI_HANDLE handle, UINT32 level, void *ct, void **status)
{
ACPI_NAMESPACE_NODE *parentnode;
ACPI_STATUS ret;
ACPI_INTEGER val;
struct mpacpi_pcibus *parentmpr;
pcireg_t binf;
pcireg_t binf, class;
pcitag_t tag;
struct acpi_softc *acpi;
struct mpacpi_pcibus *mpr, *mparent;
struct mpacpi_walk_status *mpw = ct;
int bus;
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;
mparent = mpw->mpw_mpr;
acpi = mpw->mpw_acpi;
ret = AcpiUtEvaluateNumericObject(METHOD_NAME__ADR, handle, &val);
if (ACPI_FAILURE(ret))
return AE_OK;
tag = pci_make_tag(acpi->sc_pc, mparent->mpr_bus,
ACPI_HIWORD(val), ACPI_LOWORD(val));
class = pci_conf_read(acpi->sc_pc, tag, PCI_CLASS_REG);
if (PCI_CLASS(class) != PCI_CLASS_BRIDGE ||
PCI_SUBCLASS(class) != PCI_SUBCLASS_BRIDGE_PCI)
return AE_OK;
TAILQ_FOREACH(mpr, &mpacpi_pcibusses, mpr_list)
if (mpr->mpr_handle == handle)
break;
if (mpr != NULL && mpr->mpr_bus != -1)
return AE_OK;
binf = pci_conf_read(acpi->sc_pc, tag, PPB_REG_BUSINFO);
bus = PPB_BUSINFO_SECONDARY(binf);
if (mpr == NULL) {
if (mp_verbose)
printf("mpacpi: found subordinate PCI bus %d\n",
mpr->mpr_bus);
printf("mpacpi: PCI bus %d has no ACPI handle; "
"ignoring.\n", bus);
return AE_OK;
}
mpr->mpr_bus = bus;
mpacpi_npciknown++;
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;
return AE_OK;
}
/*
@ -565,24 +572,44 @@ mpacpi_config_irouting(struct acpi_softc *acpi)
#if NPCI > 0
struct mpacpi_pcibus *mpr;
#endif
int nintr;
int nintr, known;
int i, index;
struct mp_bus *mbp;
struct mp_intr_map *mpi;
struct ioapic_softc *ioapic;
struct mpacpi_walk_status mpw;
nintr = mpacpi_nintsrc + NUM_LEGACY_IRQS - 1;
mpacpi_npciknown = mpacpi_npciroots;
#if NPCI > 0
TAILQ_FOREACH(mpr, &mpacpi_pcibusses, mpr_list) {
nintr += mpacpi_pcircount(mpr);
}
for (i = 0; i <= mpacpi_maxbuslevel; i++) {
for (;;) {
known = mpacpi_npciknown;
TAILQ_FOREACH(mpr, &mpacpi_pcibusses, mpr_list) {
if (mpr->mpr_level == i)
mpacpi_pcihier(acpi, mpr);
if (mpr->mpr_bus != -1) {
mpw.mpw_acpi = acpi;
mpw.mpw_mpr = mpr;
AcpiWalkNamespace(ACPI_TYPE_DEVICE,
mpr->mpr_handle, 1, mpacpi_pcihier_cb,
&mpw, NULL);
}
}
if (mpacpi_npciknown == mpacpi_npci) {
if (mp_verbose)
printf("mpacpi: resolved all PCI buses\n");
break;
}
if (mpacpi_npciknown == known) {
if (mp_verbose)
printf("mpacpi: couldn't find all PCI bus "
"numbers\n");
break;
}
}
mp_isa_bus = mpacpi_maxpci + 1;
#else
mp_isa_bus = 0;

View File

@ -1,4 +1,4 @@
/* $NetBSD: mpbios.c,v 1.5 2003/05/11 00:06:31 fvdl Exp $ */
/* $NetBSD: mpbios.c,v 1.6 2003/05/15 13:30:31 fvdl Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@ -996,7 +996,7 @@ mpbios_int(ent, enttype, mpi)
struct mp_intr_map *mpi;
{
const struct mpbios_int *entry = (const struct mpbios_int *)ent;
struct ioapic_softc *sc = NULL;
struct ioapic_softc *sc = NULL, *sc2;
struct mp_intr_map *altmpi;
struct mp_bus *mpb;
@ -1049,6 +1049,23 @@ mpbios_int(ent, enttype, mpi)
return;
}
/*
* XXX workaround for broken BIOSs that put the ACPI
* global interrupt number in the entry, not the pin
* number.
*/
if (pin >= sc->sc_apic_sz) {
sc2 = ioapic_find_bybase(pin);
if (sc2 != sc) {
printf("mpbios: bad pin %d for apic %d\n",
pin, id);
return;
}
printf("mpbios: WARNING: pin %d for apic %d too high; "
"assuming ACPI global int value\n", pin, id);
pin -= sc->sc_apic_vecbase;
}
mpi->ioapic = sc;
mpi->ioapic_pin = pin;