summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorJordan Hargrave <jordan@cvs.openbsd.org>2010-06-29 22:08:30 +0000
committerJordan Hargrave <jordan@cvs.openbsd.org>2010-06-29 22:08:30 +0000
commit239f93eac26516451d8fe99c92ce8e530e1f6e96 (patch)
tree85345019cadae6936addfbeafb4062bd5eab8398 /sys/dev
parentd0c7e69d7f21d2c6df66db72892887d848952ef2 (diff)
Add support for mapping ACPI to PCI devices
ok kettenis, deraadt
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/acpi/acpi.c132
-rw-r--r--sys/dev/acpi/acpireg.h4
-rw-r--r--sys/dev/acpi/amltypes.h20
-rw-r--r--sys/dev/acpi/dsdt.c5
-rw-r--r--sys/dev/pci/pci.c4
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)