summaryrefslogtreecommitdiff
path: root/sys/dev/acpi/acpiprt.c
diff options
context:
space:
mode:
authorJordan Hargrave <jordan@cvs.openbsd.org>2010-07-01 06:29:33 +0000
committerJordan Hargrave <jordan@cvs.openbsd.org>2010-07-01 06:29:33 +0000
commit89d383c71ad84f4d1ad9b9f747df8fd8d59d166d (patch)
tree1344a9dda8fee63f8506921e888b909349f88ffb /sys/dev/acpi/acpiprt.c
parentb0aaff34b3bc1295a0eab7c8c181dea565af2d3c (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.c96
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) {