diff options
author | Jordan Hargrave <jordan@cvs.openbsd.org> | 2010-07-01 06:29:33 +0000 |
---|---|---|
committer | Jordan Hargrave <jordan@cvs.openbsd.org> | 2010-07-01 06:29:33 +0000 |
commit | 89d383c71ad84f4d1ad9b9f747df8fd8d59d166d (patch) | |
tree | 1344a9dda8fee63f8506921e888b909349f88ffb /sys/dev/acpi/acpiprt.c | |
parent | b0aaff34b3bc1295a0eab7c8c181dea565af2d3c (diff) |
Backout recent AML changes, breaks on R210 and others
Diffstat (limited to 'sys/dev/acpi/acpiprt.c')
-rw-r--r-- | sys/dev/acpi/acpiprt.c | 96 |
1 files changed, 88 insertions, 8 deletions
diff --git a/sys/dev/acpi/acpiprt.c b/sys/dev/acpi/acpiprt.c index f1f7578e912..c677299e983 100644 --- a/sys/dev/acpi/acpiprt.c +++ b/sys/dev/acpi/acpiprt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpiprt.c,v 1.37 2010/07/01 01:39:39 jordan Exp $ */ +/* $OpenBSD: acpiprt.c,v 1.38 2010/07/01 06:29:32 jordan Exp $ */ /* * Copyright (c) 2006 Mark Kettenis <kettenis@openbsd.org> * @@ -56,6 +56,7 @@ SIMPLEQ_HEAD(, acpiprt_map) acpiprt_map_list = int acpiprt_match(struct device *, void *, void *); void acpiprt_attach(struct device *, struct device *, void *); int acpiprt_getirq(union acpi_resource *crs, void *arg); +int acpiprt_getminbus(union acpi_resource *, void *); int acpiprt_chooseirq(union acpi_resource *, void *); struct acpiprt_softc { @@ -278,20 +279,25 @@ acpiprt_prt_add(struct acpiprt_softc *sc, struct aml_value *v) aml_freevalue(&res); return; } - aml_parse_resource(&res, acpiprt_getirq, &irq); + aml_parse_resource(res.length, res.v_buffer, + acpiprt_getirq, &irq); aml_freevalue(&res); /* Pick a new IRQ if necessary. */ if ((irq == 0 || irq == 2 || irq == 13) && !aml_evalname(sc->sc_acpi, node, "_PRS", 0, NULL, &res)){ - aml_parse_resource(&res, acpiprt_chooseirq, &irq); + if (res.type == AML_OBJTYPE_BUFFER && + res.length >= 5) { + aml_parse_resource(res.length, res.v_buffer, + acpiprt_chooseirq, &irq); + } aml_freevalue(&res); } if ((p = malloc(sizeof(*p), M_ACPI, M_NOWAIT)) == NULL) return; p->bus = sc->sc_bus; - p->dev = ACPI_ADR_PCIDEV(addr); + p->dev = ACPI_PCI_DEV(addr << 16); p->pin = pin; p->irq = irq; p->sc = sc; @@ -359,11 +365,85 @@ acpiprt_prt_add(struct acpiprt_softc *sc, struct aml_value *v) } int +acpiprt_getminbus(union acpi_resource *crs, void *arg) +{ + int *bbn = arg; + int typ = AML_CRSTYPE(crs); + + /* Check for embedded bus number */ + if (typ == LR_WORD && crs->lr_word.type == 2) + *bbn = crs->lr_word._min; + return 0; +} + +int acpiprt_getpcibus(struct acpiprt_softc *sc, struct aml_node *node) { - /* Check if parent device has PCI mapping */ - return (node->parent && node->parent->pci) ? - node->parent->pci->sub : -1; + struct aml_node *parent = node->parent; + struct aml_value res; + pci_chipset_tag_t pc = NULL; + pcitag_t tag; + pcireg_t reg; + int bus, dev, func, rv; + int64_t ires; + + if (parent == NULL) + return 0; + + /* + * If our parent is a a bridge, it might have an address descriptor + * that tells us our bus number. + */ + if (aml_evalname(sc->sc_acpi, parent, "_CRS.", 0, NULL, &res) == 0) { + rv = -1; + if (res.type == AML_OBJTYPE_BUFFER) + aml_parse_resource(res.length, res.v_buffer, + acpiprt_getminbus, &rv); + aml_freevalue(&res); + if (rv != -1) + return rv; + } + + /* + * If our parent is the root of the bus, it should specify the + * base bus number. + */ + if (aml_evalinteger(sc->sc_acpi, parent, "_BBN.", 0, NULL, &ires) == 0) { + return (ires); + } + + /* + * If our parent is a PCI-PCI bridge, get our bus number from its + * PCI config space. + */ + if (aml_evalinteger(sc->sc_acpi, parent, "_ADR.", 0, NULL, &ires) == 0) { + bus = acpiprt_getpcibus(sc, parent); + dev = ACPI_PCI_DEV(ires << 16); + func = ACPI_PCI_FN(ires << 16); + + /* + * Some systems return 255 as the device number for + * devices that are not really there. + */ + if (dev >= pci_bus_maxdevs(pc, bus)) + return (-1); + + tag = pci_make_tag(pc, bus, dev, func); + + /* Check whether the device is really there. */ + reg = pci_conf_read(pc, tag, PCI_ID_REG); + if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID) + return (-1); + + /* Fetch bus number from PCI config space. */ + reg = pci_conf_read(pc, tag, PCI_CLASS_REG); + if (PCI_CLASS(reg) == PCI_CLASS_BRIDGE && + PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_PCI) { + reg = pci_conf_read(pc, tag, PPB_REG_BUSINFO); + return (PPB_BUSINFO_SECONDARY(reg)); + } + } + return (0); } void @@ -404,7 +484,7 @@ acpiprt_route_interrupt(int bus, int dev, int pin) aml_freevalue(&res); return; } - aml_parse_resource(&res, acpiprt_getirq, &irq); + aml_parse_resource(res.length, res.v_buffer, acpiprt_getirq, &irq); /* Only re-route interrupts when necessary. */ if ((sta & STA_ENABLED) && irq == newirq) { |