diff options
author | Jordan Hargrave <jordan@cvs.openbsd.org> | 2010-06-29 22:08:30 +0000 |
---|---|---|
committer | Jordan Hargrave <jordan@cvs.openbsd.org> | 2010-06-29 22:08:30 +0000 |
commit | 239f93eac26516451d8fe99c92ce8e530e1f6e96 (patch) | |
tree | 85345019cadae6936addfbeafb4062bd5eab8398 /sys/dev | |
parent | d0c7e69d7f21d2c6df66db72892887d848952ef2 (diff) |
Add support for mapping ACPI to PCI devices
ok kettenis, deraadt
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/acpi/acpi.c | 132 | ||||
-rw-r--r-- | sys/dev/acpi/acpireg.h | 4 | ||||
-rw-r--r-- | sys/dev/acpi/amltypes.h | 20 | ||||
-rw-r--r-- | sys/dev/acpi/dsdt.c | 5 | ||||
-rw-r--r-- | sys/dev/pci/pci.c | 4 |
5 files changed, 155 insertions, 10 deletions
diff --git a/sys/dev/acpi/acpi.c b/sys/dev/acpi/acpi.c index 2073ec98762..624a3645fbc 100644 --- a/sys/dev/acpi/acpi.c +++ b/sys/dev/acpi/acpi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpi.c,v 1.162 2010/06/29 18:54:35 kettenis Exp $ */ +/* $OpenBSD: acpi.c,v 1.163 2010/06/29 22:08:29 jordan Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> * Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org> @@ -42,6 +42,10 @@ #include <dev/acpi/dsdt.h> #include <dev/wscons/wsdisplayvar.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcidevs.h> +#include <dev/pci/ppbreg.h> + #include <dev/pci/pciidereg.h> #include <dev/pci/pciidevar.h> @@ -67,6 +71,8 @@ int acpi_saved_spl; void acpi_isr_thread(void *); void acpi_create_thread(void *); +void acpi_pci_match(struct device *, struct pci_attach_args *); + int acpi_match(struct device *, void *, void *); void acpi_attach(struct device *, struct device *, void *); int acpi_submatch(struct device *, void *, void *); @@ -493,6 +499,127 @@ acpi_match(struct device *parent, void *match, void *aux) return (1); } +TAILQ_HEAD(, acpi_pci) acpi_pcidevs = + TAILQ_HEAD_INITIALIZER(acpi_pcidevs); + +int acpi_getpci(struct aml_node *node, void *arg); +int acpi_getminbus(union acpi_resource *crs, void *arg); + +int +acpi_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; +} + +/* Map ACPI device node to PCI */ +int +acpi_getpci(struct aml_node *node, void *arg) +{ + const char *pcihid[] = { ACPI_DEV_PCIB, ACPI_DEV_PCIEB, "HWP0002", 0 }; + struct acpi_pci *pci, *ppci; + struct aml_value res; + struct acpi_softc *sc = arg; + pci_chipset_tag_t pc = NULL; + pcitag_t tag; + uint64_t val; + uint32_t reg; + + if (!node->value || node->value->type != AML_OBJTYPE_DEVICE) + return 0; + if (!aml_evalhid(node, &res)) { + /* Check if this is a PCI Root node */ + if (_acpi_matchhids(res.v_string, pcihid)) { + aml_freevalue(&res); + + pci = malloc(sizeof(*pci), M_DEVBUF, M_WAITOK|M_ZERO); + + if (!aml_evalinteger(sc, node, "_SEG", 0, NULL, &val)) + pci->seg = val; + if (!aml_evalinteger(sc, node, "_BBN", 0, NULL, &val)) + pci->bus = val; + else if (!aml_evalname(sc, node, "_CRS", 0, NULL, &res)) { + if (res.type == AML_OBJTYPE_BUFFER && + res.length > 5) + aml_parse_resource(res.length, + res.v_buffer, acpi_getminbus, + &pci->bus); + } + node->pci = pci; + dnprintf(10, "found PCI root: %s %d\n", + aml_nodename(node), pci->bus); + } + aml_freevalue(&res); + return 0; + } + + /* If parent is not PCI, or device does not have _ADR, return */ + if (!node->parent || (ppci = node->parent->pci) == NULL) + return 0; + if (aml_evalinteger(sc, node, "_ADR", 0, NULL, &val)) + return 0; + + pci = malloc(sizeof(*pci), M_DEVBUF, M_WAITOK|M_ZERO); + pci->bus = ppci->sub; + pci->dev = ACPI_ADR_PCIDEV(val); + pci->fun = ACPI_ADR_PCIFUN(val); + pci->node = node; + pci->sub = -1; + + dnprintf(10, "%.2x:%.2x.%x -> %s\n", + pci->bus, pci->dev, pci->fun, + aml_nodename(node)); + + /* Check if PCI device exists */ + tag = pci_make_tag(pc, pci->bus, pci->dev, pci->fun); + reg = pci_conf_read(pc, tag, PCI_ID_REG); + if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID) { + free(pci, M_DEVBUF); + return (1); + } + node->pci = pci; + + TAILQ_INSERT_TAIL(&acpi_pcidevs, pci, next); + + /* Check if this is a PCI bridge */ + 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); + pci->sub = PPB_BUSINFO_SECONDARY(reg); + + dnprintf(10, "found PCI bridge: %s %d\n", + aml_nodename(node), pci->sub); + + /* Continue scanning */ + return (0); + } + + /* Device does not have children, stop scanning */ + return (1); +} + +void +acpi_pci_match(struct device *dev, struct pci_attach_args *pa) +{ + struct acpi_pci *pdev; + + TAILQ_FOREACH(pdev, &acpi_pcidevs, next) { + if (pdev->bus == pa->pa_bus && + pdev->dev == pa->pa_device && + pdev->fun == pa->pa_function) { + dnprintf(10,"%s at acpi0 %s\n", + dev->dv_xname, aml_nodename(pdev->node)); + pdev->device = dev; + } + } +} + void acpi_attach(struct device *parent, struct device *self, void *aux) { @@ -710,6 +837,9 @@ acpi_attach(struct device *parent, struct device *self, void *aux) /* initialize runtime environment */ aml_find_node(&aml_root, "_INI", acpi_inidev, sc); + /* Get PCI mapping */ + aml_walknodes(&aml_root, AML_WALK_PRE, acpi_getpci, sc); + /* attach pci interrupt routing tables */ aml_find_node(&aml_root, "_PRT", acpi_foundprt, sc); diff --git a/sys/dev/acpi/acpireg.h b/sys/dev/acpi/acpireg.h index f1dba86c782..44560e01f1f 100644 --- a/sys/dev/acpi/acpireg.h +++ b/sys/dev/acpi/acpireg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: acpireg.h,v 1.21 2010/06/28 06:46:32 jordan Exp $ */ +/* $OpenBSD: acpireg.h,v 1.22 2010/06/29 22:08:29 jordan Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org> @@ -603,6 +603,8 @@ struct acpi_ivrs { /* * PCI Configuration space */ +#define ACPI_ADR_PCIDEV(addr) (u_int16_t)(addr >> 16) +#define ACPI_ADR_PCIFUN(addr) (u_int16_t)(addr & 0xFFFF) #define ACPI_PCI_BUS(addr) (u_int16_t)((addr) >> 48) #define ACPI_PCI_DEV(addr) (u_int16_t)((addr) >> 32) #define ACPI_PCI_FN(addr) (u_int16_t)((addr) >> 16) diff --git a/sys/dev/acpi/amltypes.h b/sys/dev/acpi/amltypes.h index 5bea7d0c9e9..335a2399f0f 100644 --- a/sys/dev/acpi/amltypes.h +++ b/sys/dev/acpi/amltypes.h @@ -1,4 +1,4 @@ -/* $OpenBSD: amltypes.h,v 1.34 2010/06/27 21:04:22 jordan Exp $ */ +/* $OpenBSD: amltypes.h,v 1.35 2010/06/29 22:08:29 jordan Exp $ */ /* * Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org> * @@ -347,6 +347,19 @@ struct aml_value { #define aml_pkglen(v) ((v)->length) #define aml_pkgval(v,i) (&(v)->v_package[(i)]) +struct acpi_pci { + TAILQ_ENTRY(acpi_pci) next; + + struct aml_node *node; + struct device *device; + + int sub; + int seg; + int bus; + int dev; + int fun; +}; + struct aml_node { struct aml_node *parent; @@ -357,12 +370,9 @@ struct aml_node { u_int16_t opcode; u_int8_t *start; u_int8_t *end; - // const char *name; - // const char *mnem; struct aml_value *value; - - int depth; + struct acpi_pci *pci; }; #define aml_bitmask(n) (1L << ((n) & 0x7)) diff --git a/sys/dev/acpi/dsdt.c b/sys/dev/acpi/dsdt.c index b26fb31875f..0fa0a6bc4ac 100644 --- a/sys/dev/acpi/dsdt.c +++ b/sys/dev/acpi/dsdt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dsdt.c,v 1.160 2010/06/27 21:04:22 jordan Exp $ */ +/* $OpenBSD: dsdt.c,v 1.161 2010/06/29 22:08:29 jordan Exp $ */ /* * Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org> * @@ -1234,7 +1234,8 @@ aml_walknodes(struct aml_node *node, int mode, if (node == NULL) return; if (mode == AML_WALK_PRE) - nodecb(node, arg); + if (nodecb(node, arg)) + return; SIMPLEQ_FOREACH(child, &node->son, sib) aml_walknodes(child, mode, nodecb, arg); if (mode == AML_WALK_POST) diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index 7a18d0f0746..7e21eeacf1f 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pci.c,v 1.76 2010/04/21 23:12:24 deraadt Exp $ */ +/* $OpenBSD: pci.c,v 1.77 2010/06/29 22:08:29 jordan Exp $ */ /* $NetBSD: pci.c,v 1.31 1997/06/06 23:48:04 thorpej Exp $ */ /* @@ -364,6 +364,8 @@ pci_probe_device(struct pci_softc *sc, pcitag_t tag, pcisubmatch))) { pcireg_t reg; + pci_dev_postattach(dev, &pa); + /* skip header type != 0 */ reg = pci_conf_read(pc, tag, PCI_BHLC_REG); if (PCI_HDRTYPE_TYPE(reg) != 0) |