summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkettenis <kettenis@openbsd.org>2011-01-04 21:17:49 +0000
committerkettenis <kettenis@openbsd.org>2011-01-04 21:17:49 +0000
commitfd1ffd5d0635e1f37a1a39acf2fb88cd18b9f81f (patch)
treeec894dc12e810b9fe32b8f75d2e32fdfa626df87
parentUse pmap_uncache_page() to alter cacheability of pages in bus_dmamem_map() (diff)
downloadwireguard-openbsd-fd1ffd5d0635e1f37a1a39acf2fb88cd18b9f81f.tar.xz
wireguard-openbsd-fd1ffd5d0635e1f37a1a39acf2fb88cd18b9f81f.zip
Add support for Memory Mapped Configuration space access. This gives us
access to PCIe extended configuration space access on modern i386 and amd64 machines.
-rw-r--r--sys/arch/amd64/conf/GENERIC3
-rw-r--r--sys/arch/amd64/include/pci_machdep.h5
-rw-r--r--sys/arch/amd64/pci/pci_machdep.c60
-rw-r--r--sys/arch/i386/conf/GENERIC3
-rw-r--r--sys/arch/i386/pci/pci_machdep.c60
-rw-r--r--sys/arch/i386/pci/pci_machdep.h5
-rw-r--r--sys/dev/acpi/acpimcfg.c73
-rw-r--r--sys/dev/acpi/acpireg.h13
-rw-r--r--sys/dev/acpi/files.acpi7
9 files changed, 221 insertions, 8 deletions
diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC
index 6d6388e1198..320c36ec6da 100644
--- a/sys/arch/amd64/conf/GENERIC
+++ b/sys/arch/amd64/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.310 2010/12/15 11:24:29 jsg Exp $
+# $OpenBSD: GENERIC,v 1.311 2011/01/04 21:17:49 kettenis Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
@@ -48,6 +48,7 @@ acpiec* at acpi?
acpiprt* at acpi?
acpitz* at acpi?
acpimadt0 at acpi?
+acpimcfg* at acpi?
acpiasus* at acpi?
acpisony* at acpi?
acpithinkpad* at acpi?
diff --git a/sys/arch/amd64/include/pci_machdep.h b/sys/arch/amd64/include/pci_machdep.h
index dc4522b387e..4b716578e93 100644
--- a/sys/arch/amd64/include/pci_machdep.h
+++ b/sys/arch/amd64/include/pci_machdep.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pci_machdep.h,v 1.16 2010/12/04 17:06:31 miod Exp $ */
+/* $OpenBSD: pci_machdep.h,v 1.17 2011/01/04 21:17:49 kettenis Exp $ */
/* $NetBSD: pci_machdep.h,v 1.1 2003/02/26 21:26:11 fvdl Exp $ */
/*
@@ -59,6 +59,9 @@ typedef struct {
* amd64-specific PCI variables and functions.
* NOT TO BE USED DIRECTLY BY MACHINE INDEPENDENT CODE.
*/
+extern bus_addr_t pci_mcfg_addr;
+extern int pci_mcfg_min_bus, pci_mcfg_max_bus;
+
struct pci_attach_args;
extern struct extent *pciio_ex;
diff --git a/sys/arch/amd64/pci/pci_machdep.c b/sys/arch/amd64/pci/pci_machdep.c
index db78807429d..10a5df20ae0 100644
--- a/sys/arch/amd64/pci/pci_machdep.c
+++ b/sys/arch/amd64/pci/pci_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pci_machdep.c,v 1.37 2010/12/04 17:06:31 miod Exp $ */
+/* $OpenBSD: pci_machdep.c,v 1.38 2011/01/04 21:17:49 kettenis Exp $ */
/* $NetBSD: pci_machdep.c,v 1.3 2003/05/07 21:33:58 fvdl Exp $ */
/*-
@@ -96,6 +96,19 @@
#include <machine/mpbiosvar.h>
#endif
+/*
+ * Memory Mapped Configuration space access.
+ *
+ * Since mapping the whole configuration space will cost us up to
+ * 256MB of kernel virtual memory, we use seperate mappings per bus.
+ * The mappings are created on-demand, such that we only use kernel
+ * virtual memory for busses that are actually present.
+ */
+bus_addr_t pci_mcfg_addr;
+int pci_mcfg_min_bus, pci_mcfg_max_bus;
+bus_space_tag_t pci_mcfgt = X86_BUS_SPACE_MEM;
+bus_space_handle_t pci_mcfgh[256];
+
struct mutex pci_conf_lock = MUTEX_INITIALIZER(IPL_HIGH);
#define PCI_CONF_LOCK() \
@@ -157,6 +170,14 @@ pci_make_tag(pci_chipset_tag_t pc, int bus, int device, int function)
if (bus >= 256 || device >= 32 || function >= 8)
panic("pci_make_tag: bad request");
+ if (pci_mcfg_addr) {
+ if (bus < pci_mcfg_min_bus || bus > pci_mcfg_max_bus ||
+ device >= 32 || function >= 8)
+ panic("pci_make_tag: bad request");
+
+ return (bus << 20) | (device << 15) | (function << 12);
+ }
+
return (PCI_MODE1_ENABLE |
(bus << 16) | (device << 11) | (function << 8));
}
@@ -164,6 +185,16 @@ pci_make_tag(pci_chipset_tag_t pc, int bus, int device, int function)
void
pci_decompose_tag(pci_chipset_tag_t pc, pcitag_t tag, int *bp, int *dp, int *fp)
{
+ if (pci_mcfg_addr) {
+ if (bp != NULL)
+ *bp = (tag >> 20) & 0xff;
+ if (dp != NULL)
+ *dp = (tag >> 15) & 0x1f;
+ if (fp != NULL)
+ *fp = (tag >> 12) & 0x7;
+ return;
+ }
+
if (bp != NULL)
*bp = (tag >> 16) & 0xff;
if (dp != NULL)
@@ -175,6 +206,9 @@ pci_decompose_tag(pci_chipset_tag_t pc, pcitag_t tag, int *bp, int *dp, int *fp)
int
pci_conf_size(pci_chipset_tag_t pc, pcitag_t tag)
{
+ if (pci_mcfg_addr)
+ return PCIE_CONFIG_SPACE_SIZE;
+
return PCI_CONFIG_SPACE_SIZE;
}
@@ -182,6 +216,17 @@ pcireg_t
pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg)
{
pcireg_t data;
+ int bus;
+
+ if (pci_mcfg_addr) {
+ pci_decompose_tag(pc, tag, &bus, NULL, NULL);
+ if (pci_mcfgh[bus] == 0 &&
+ bus_space_map(pci_mcfgt, pci_mcfg_addr + (bus << 20),
+ 1 << 20, 0, &pci_mcfgh[bus]))
+ panic("pci_conf_read: cannot map mcfg space");
+ return bus_space_read_4(pci_mcfgt, pci_mcfgh[bus],
+ (tag & 0x000ff000) | reg);
+ }
PCI_CONF_LOCK();
outl(PCI_MODE1_ADDRESS_REG, tag | reg);
@@ -195,6 +240,19 @@ pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg)
void
pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data)
{
+ int bus;
+
+ if (pci_mcfg_addr) {
+ pci_decompose_tag(pc, tag, &bus, NULL, NULL);
+ if (pci_mcfgh[bus] == 0 &&
+ bus_space_map(pci_mcfgt, pci_mcfg_addr + (bus << 20),
+ 1 << 20, 0, &pci_mcfgh[bus]))
+ panic("pci_conf_write: cannot map mcfg space");
+ bus_space_write_4(pci_mcfgt, pci_mcfgh[bus],
+ (tag & 0x000ff000) | reg, data);
+ return;
+ }
+
PCI_CONF_LOCK();
outl(PCI_MODE1_ADDRESS_REG, tag | reg);
outl(PCI_MODE1_DATA_REG, data);
diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC
index a59d3efb36e..4905624a876 100644
--- a/sys/arch/i386/conf/GENERIC
+++ b/sys/arch/i386/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.704 2010/12/15 11:24:29 jsg Exp $
+# $OpenBSD: GENERIC,v 1.705 2011/01/04 21:17:49 kettenis Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
@@ -57,6 +57,7 @@ acpicpu* at acpi?
acpidock* at acpi?
acpiec* at acpi?
acpimadt0 at acpi?
+acpimcfg* at acpi?
acpiprt* at acpi?
acpitz* at acpi?
acpiasus* at acpi?
diff --git a/sys/arch/i386/pci/pci_machdep.c b/sys/arch/i386/pci/pci_machdep.c
index 15a4e0cbfcd..e6404bf3f91 100644
--- a/sys/arch/i386/pci/pci_machdep.c
+++ b/sys/arch/i386/pci/pci_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pci_machdep.c,v 1.55 2010/12/04 17:06:31 miod Exp $ */
+/* $OpenBSD: pci_machdep.c,v 1.56 2011/01/04 21:17:49 kettenis Exp $ */
/* $NetBSD: pci_machdep.c,v 1.28 1997/06/06 23:29:17 thorpej Exp $ */
/*-
@@ -114,6 +114,19 @@ extern bios_pciinfo_t *bios_pciinfo;
int pci_mode = -1;
+/*
+ * Memory Mapped Configuration space access.
+ *
+ * Since mapping the whole configuration space will cost us up to
+ * 256MB of kernel virtual memory, we use seperate mappings per bus.
+ * The mappings are created on-demand, such that we only use kernel
+ * virtual memory for busses that are actually present.
+ */
+bus_addr_t pci_mcfg_addr;
+int pci_mcfg_min_bus, pci_mcfg_max_bus;
+bus_space_tag_t pci_mcfgt = I386_BUS_SPACE_MEM;
+bus_space_handle_t pci_mcfgh[256];
+
struct mutex pci_conf_lock = MUTEX_INITIALIZER(IPL_HIGH);
#define PCI_CONF_LOCK() \
@@ -211,6 +224,15 @@ pci_make_tag(pci_chipset_tag_t pc, int bus, int device, int function)
{
pcitag_t tag;
+ if (pci_mcfg_addr) {
+ if (bus < pci_mcfg_min_bus || bus > pci_mcfg_max_bus ||
+ device >= 32 || function >= 8)
+ panic("pci_make_tag: bad request");
+
+ tag.mode1 = (bus << 20) | (device << 15) | (function << 12);
+ return tag;
+ }
+
switch (pci_mode) {
case 1:
if (bus >= 256 || device >= 32 || function >= 8)
@@ -237,6 +259,15 @@ pci_make_tag(pci_chipset_tag_t pc, int bus, int device, int function)
void
pci_decompose_tag(pci_chipset_tag_t pc, pcitag_t tag, int *bp, int *dp, int *fp)
{
+ if (pci_mcfg_addr) {
+ if (bp != NULL)
+ *bp = (tag.mode1 >> 20) & 0xff;
+ if (dp != NULL)
+ *dp = (tag.mode1 >> 15) & 0x1f;
+ if (fp != NULL)
+ *fp = (tag.mode1 >> 12) & 0x7;
+ return;
+ }
switch (pci_mode) {
case 1:
@@ -263,6 +294,9 @@ pci_decompose_tag(pci_chipset_tag_t pc, pcitag_t tag, int *bp, int *dp, int *fp)
int
pci_conf_size(pci_chipset_tag_t pc, pcitag_t tag)
{
+ if (pci_mcfg_addr)
+ return PCIE_CONFIG_SPACE_SIZE;
+
return PCI_CONFIG_SPACE_SIZE;
}
@@ -270,6 +304,18 @@ pcireg_t
pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg)
{
pcireg_t data;
+ int bus;
+
+ if (pci_mcfg_addr) {
+ pci_decompose_tag(pc, tag, &bus, NULL, NULL);
+ if (pci_mcfgh[bus] == 0 &&
+ bus_space_map(pci_mcfgt, pci_mcfg_addr + (bus << 20),
+ 1 << 20, 0, &pci_mcfgh[bus]))
+ panic("pci_conf_read: cannot map mcfg space");
+ data = bus_space_read_4(pci_mcfgt, pci_mcfgh[bus],
+ (tag.mode1 & 0x000ff000) | reg);
+ return data;
+ }
PCI_CONF_LOCK();
switch (pci_mode) {
@@ -295,6 +341,18 @@ pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg)
void
pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data)
{
+ int bus;
+
+ if (pci_mcfg_addr) {
+ pci_decompose_tag(pc, tag, &bus, NULL, NULL);
+ if (pci_mcfgh[bus] == 0 &&
+ bus_space_map(pci_mcfgt, pci_mcfg_addr + (bus << 20),
+ 1 << 20, 0, &pci_mcfgh[bus]))
+ panic("pci_conf_write: cannot map mcfg space");
+ bus_space_write_4(pci_mcfgt, pci_mcfgh[bus],
+ (tag.mode1 & 0x000ff000) | reg, data);
+ return;
+ }
PCI_CONF_LOCK();
switch (pci_mode) {
diff --git a/sys/arch/i386/pci/pci_machdep.h b/sys/arch/i386/pci/pci_machdep.h
index dcc0f1fa42d..378c684bfb8 100644
--- a/sys/arch/i386/pci/pci_machdep.h
+++ b/sys/arch/i386/pci/pci_machdep.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pci_machdep.h,v 1.20 2010/12/04 17:06:31 miod Exp $ */
+/* $OpenBSD: pci_machdep.h,v 1.21 2011/01/04 21:17:49 kettenis Exp $ */
/* $NetBSD: pci_machdep.h,v 1.7 1997/06/06 23:29:18 thorpej Exp $ */
/*
@@ -75,6 +75,9 @@ struct {
* NOT TO BE USED DIRECTLY BY MACHINE INDEPENDENT CODE.
*/
extern int pci_mode;
+extern bus_addr_t pci_mcfg_addr;
+extern int pci_mcfg_min_bus, pci_mcfg_max_bus;
+
int pci_mode_detect(void);
extern struct extent *pciio_ex;
diff --git a/sys/dev/acpi/acpimcfg.c b/sys/dev/acpi/acpimcfg.c
new file mode 100644
index 00000000000..ee265db9918
--- /dev/null
+++ b/sys/dev/acpi/acpimcfg.c
@@ -0,0 +1,73 @@
+/* $OpenBSD: acpimcfg.c,v 1.1 2011/01/04 21:17:49 kettenis Exp $ */
+/*
+ * Copyright (c) 2010 Mark Kettenis <kettenis@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/apicvar.h>
+
+#include <dev/acpi/acpireg.h>
+#include <dev/acpi/acpivar.h>
+#include <dev/pci/pcivar.h>
+
+int acpimcfg_match(struct device *, void *, void *);
+void acpimcfg_attach(struct device *, struct device *, void *);
+
+struct cfattach acpimcfg_ca = {
+ sizeof(struct device), acpimcfg_match, acpimcfg_attach
+};
+
+struct cfdriver acpimcfg_cd = {
+ NULL, "acpimcfg", DV_DULL
+};
+
+int
+acpimcfg_match(struct device *parent, void *match, void *aux)
+{
+ struct acpi_attach_args *aaa = aux;
+ struct acpi_table_header *hdr;
+
+ /*
+ * If we do not have a table, it is not us
+ */
+ if (aaa->aaa_table == NULL)
+ return (0);
+
+ /*
+ * If it is an MCFG table, we can attach
+ */
+ hdr = (struct acpi_table_header *)aaa->aaa_table;
+ if (memcmp(hdr->signature, MCFG_SIG, sizeof(MCFG_SIG) - 1) != 0)
+ return (0);
+
+ return (1);
+}
+
+void
+acpimcfg_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct acpi_attach_args *aaa = aux;
+ struct acpi_mcfg *mcfg = (struct acpi_mcfg *)aaa->aaa_table;
+
+ printf(" addr 0x%llx, bus %d-%d\n", mcfg->base_address,
+ mcfg->min_bus_number, mcfg->max_bus_number);
+
+ pci_mcfg_addr = mcfg->base_address;
+ pci_mcfg_min_bus = mcfg->min_bus_number;
+ pci_mcfg_max_bus = mcfg->max_bus_number;
+}
diff --git a/sys/dev/acpi/acpireg.h b/sys/dev/acpi/acpireg.h
index 1669bec11bc..7bbb480485c 100644
--- a/sys/dev/acpi/acpireg.h
+++ b/sys/dev/acpi/acpireg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpireg.h,v 1.23 2010/07/21 19:35:15 deraadt Exp $ */
+/* $OpenBSD: acpireg.h,v 1.24 2011/01/04 21:17:49 kettenis Exp $ */
/*
* Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
* Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
@@ -380,6 +380,17 @@ struct acpi_hpet {
u_int8_t page_protection;
} __packed;
+struct acpi_mcfg {
+ struct acpi_table_header hdr;
+#define MCFG_SIG "MCFG"
+ u_int8_t reserved[8];
+ u_int64_t base_address;
+ u_int16_t segment;
+ u_int8_t min_bus_number;
+ u_int8_t max_bus_number;
+ u_int32_t reserved1;
+} __packed;
+
struct acpi_facs {
u_int8_t signature[4];
#define FACS_SIG "FACS"
diff --git a/sys/dev/acpi/files.acpi b/sys/dev/acpi/files.acpi
index 58885dfc2f9..f19855b6cd8 100644
--- a/sys/dev/acpi/files.acpi
+++ b/sys/dev/acpi/files.acpi
@@ -1,4 +1,4 @@
-# $OpenBSD: files.acpi,v 1.24 2010/07/26 11:29:23 pirofti Exp $
+# $OpenBSD: files.acpi,v 1.25 2011/01/04 21:17:49 kettenis Exp $
#
# Config file and device description for machine-independent ACPI code.
# Included by ports that need it.
@@ -56,6 +56,11 @@ device acpimadt
attach acpimadt at acpi
file dev/acpi/acpimadt.c acpimadt
+# Memory Mapped Configuration Space Address Description Table
+device acpimcfg
+attach acpimcfg at acpi
+file dev/acpi/acpimcfg.c acpimcfg
+
# PCI Routing Table
device acpiprt
attach acpiprt at acpi