summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorkettenis <kettenis@openbsd.org>2019-05-31 08:02:04 +0000
committerkettenis <kettenis@openbsd.org>2019-05-31 08:02:04 +0000
commita569ea7c7244091823e5fd7257c161eca1b67a5d (patch)
tree7a93e37c62bf46e9403e0d6ee807d8fc35a5d745 /sys
parentRename struct plimit field p_refcnt to pl_refcnt to avoid confusion (diff)
downloadwireguard-openbsd-a569ea7c7244091823e5fd7257c161eca1b67a5d.tar.xz
wireguard-openbsd-a569ea7c7244091823e5fd7257c161eca1b67a5d.zip
Add MSI-X support for acpipci(4). This splits out some generic code into
a new pci_machdep.c file such that it can be re-used by other arm64 PCI host bridge drivers in the future. ok patrick@
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/arm64/conf/files.arm643
-rw-r--r--sys/arch/arm64/dev/acpipci.c71
-rw-r--r--sys/arch/arm64/dev/pci_machdep.c85
-rw-r--r--sys/arch/arm64/include/pci_machdep.h8
4 files changed, 134 insertions, 33 deletions
diff --git a/sys/arch/arm64/conf/files.arm64 b/sys/arch/arm64/conf/files.arm64
index 72b13758721..5a3df8ac167 100644
--- a/sys/arch/arm64/conf/files.arm64
+++ b/sys/arch/arm64/conf/files.arm64
@@ -1,4 +1,4 @@
-# $OpenBSD: files.arm64,v 1.27 2019/01/23 09:57:36 phessler Exp $
+# $OpenBSD: files.arm64,v 1.28 2019/05/31 08:02:04 kettenis Exp $
maxpartitions 16
maxusers 2 8 64
@@ -38,6 +38,7 @@ file arch/arm64/arm64/support.S
file arch/arm64/arm64/bus_dma.c
file arch/arm64/dev/arm64_bus_space.c
+file arch/arm64/dev/pci_machdep.c
file arch/arm64/arm64/db_disasm.c ddb
file arch/arm64/arm64/db_interface.c ddb
diff --git a/sys/arch/arm64/dev/acpipci.c b/sys/arch/arm64/dev/acpipci.c
index 88a140a5f8d..22cc3200f5c 100644
--- a/sys/arch/arm64/dev/acpipci.c
+++ b/sys/arch/arm64/dev/acpipci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpipci.c,v 1.8 2019/05/24 08:24:01 kettenis Exp $ */
+/* $OpenBSD: acpipci.c,v 1.9 2019/05/31 08:02:04 kettenis Exp $ */
/*
* Copyright (c) 2018 Mark Kettenis
*
@@ -334,11 +334,15 @@ acpipci_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data)
bus_space_write_4(am->am_iot, am->am_ioh, tag | reg, data);
}
+#define PCI_INTX 0
+#define PCI_MSI 1
+#define PCI_MSIX 2
+
struct acpipci_intr_handle {
pci_chipset_tag_t ih_pc;
pcitag_t ih_tag;
int ih_intrpin;
- int ih_msi;
+ int ih_type;
};
int
@@ -418,7 +422,7 @@ acpipci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
ih->ih_pc = pa->pa_pc;
ih->ih_tag = pa->pa_tag;
ih->ih_intrpin = index;
- ih->ih_msi = 0;
+ ih->ih_type = PCI_INTX;
*ihp = (pci_intr_handle_t)ih;
return 0;
@@ -441,8 +445,7 @@ acpipci_intr_map_msi(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
ih = malloc(sizeof(struct acpipci_intr_handle), M_DEVBUF, M_WAITOK);
ih->ih_pc = pa->pa_pc;
ih->ih_tag = pa->pa_tag;
- ih->ih_intrpin = pa->pa_intrpin;
- ih->ih_msi = 1;
+ ih->ih_type = PCI_MSI;
*ihp = (pci_intr_handle_t)ih;
return 0;
@@ -452,7 +455,26 @@ int
acpipci_intr_map_msix(struct pci_attach_args *pa, int vec,
pci_intr_handle_t *ihp)
{
- return -1;
+ pci_chipset_tag_t pc = pa->pa_pc;
+ pcitag_t tag = pa->pa_tag;
+ struct acpipci_intr_handle *ih;
+ pcireg_t reg;
+
+ if ((pa->pa_flags & PCI_FLAGS_MSI_ENABLED) == 0 ||
+ pci_get_capability(pc, tag, PCI_CAP_MSIX, NULL, &reg) == 0)
+ return -1;
+
+ if (vec > PCI_MSIX_MC_TBLSZ(reg))
+ return -1;
+
+ ih = malloc(sizeof(struct acpipci_intr_handle), M_DEVBUF, M_WAITOK);
+ ih->ih_pc = pa->pa_pc;
+ ih->ih_tag = pa->pa_tag;
+ ih->ih_intrpin = vec;
+ ih->ih_type = PCI_MSIX;
+ *ihp = (pci_intr_handle_t)ih;
+
+ return 0;
}
const char *
@@ -461,8 +483,12 @@ acpipci_intr_string(void *v, pci_intr_handle_t ihp)
struct acpipci_intr_handle *ih = (struct acpipci_intr_handle *)ihp;
static char irqstr[32];
- if (ih->ih_msi)
+ switch (ih->ih_type) {
+ case PCI_MSI:
return "msi";
+ case PCI_MSIX:
+ return "msix";
+ }
snprintf(irqstr, sizeof(irqstr), "irq %d", ih->ih_intrpin);
return irqstr;
@@ -472,6 +498,7 @@ void *
acpipci_intr_establish(void *v, pci_intr_handle_t ihp, int level,
int (*func)(void *), void *arg, char *name)
{
+ struct acpipci_softc *sc = v;
struct acpipci_intr_handle *ih = (struct acpipci_intr_handle *)ihp;
struct interrupt_controller *ic;
void *cookie;
@@ -483,11 +510,9 @@ acpipci_intr_establish(void *v, pci_intr_handle_t ihp, int level,
}
if (ic == NULL)
return NULL;
-
- if (ih->ih_msi) {
+
+ if (ih->ih_type != PCI_INTX) {
uint64_t addr, data;
- pcireg_t reg;
- int off;
/* Map Requester ID through IORT to get sideband data. */
data = acpipci_iort_map_msi(ih->ih_pc, ih->ih_tag);
@@ -498,25 +523,11 @@ acpipci_intr_establish(void *v, pci_intr_handle_t ihp, int level,
/* TODO: translate address to the PCI device's view */
- if (pci_get_capability(ih->ih_pc, ih->ih_tag, PCI_CAP_MSI,
- &off, &reg) == 0)
- panic("%s: no msi capability", __func__);
-
- if (reg & PCI_MSI_MC_C64) {
- pci_conf_write(ih->ih_pc, ih->ih_tag,
- off + PCI_MSI_MA, addr);
- pci_conf_write(ih->ih_pc, ih->ih_tag,
- off + PCI_MSI_MAU32, addr >> 32);
- pci_conf_write(ih->ih_pc, ih->ih_tag,
- off + PCI_MSI_MD64, data);
- } else {
- pci_conf_write(ih->ih_pc, ih->ih_tag,
- off + PCI_MSI_MA, addr);
- pci_conf_write(ih->ih_pc, ih->ih_tag,
- off + PCI_MSI_MD32, data);
- }
- pci_conf_write(ih->ih_pc, ih->ih_tag,
- off, reg | PCI_MSI_MC_MSIE);
+ if (ih->ih_type == PCI_MSIX) {
+ pci_msix_enable(ih->ih_pc, ih->ih_tag,
+ &sc->sc_bus_memt, ih->ih_intrpin, addr, data);
+ } else
+ pci_msi_enable(ih->ih_pc, ih->ih_tag, addr, data);
} else {
cookie = acpi_intr_establish(ih->ih_intrpin, 0, level,
func, arg, name);
diff --git a/sys/arch/arm64/dev/pci_machdep.c b/sys/arch/arm64/dev/pci_machdep.c
new file mode 100644
index 00000000000..476de2e10f2
--- /dev/null
+++ b/sys/arch/arm64/dev/pci_machdep.c
@@ -0,0 +1,85 @@
+/* $OpenBSD: pci_machdep.c,v 1.1 2019/05/31 08:02:04 kettenis Exp $ */
+
+/*
+ * Copyright (c) 2019 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 <machine/bus.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+
+void
+pci_msi_enable(pci_chipset_tag_t pc, pcitag_t tag,
+ bus_addr_t addr, uint32_t data)
+{
+ pcireg_t reg;
+ int off;
+
+ if (pci_get_capability(pc, tag, PCI_CAP_MSI, &off, &reg) == 0)
+ panic("%s: no msi capability", __func__);
+
+ if (reg & PCI_MSI_MC_C64) {
+ pci_conf_write(pc, tag, off + PCI_MSI_MA, addr);
+ pci_conf_write(pc, tag, off + PCI_MSI_MAU32, addr >> 32);
+ pci_conf_write(pc, tag, off + PCI_MSI_MD64, data);
+ } else {
+ pci_conf_write(pc, tag, off + PCI_MSI_MA, addr);
+ pci_conf_write(pc, tag, off + PCI_MSI_MD32, data);
+ }
+ pci_conf_write(pc, tag, off, reg | PCI_MSI_MC_MSIE);
+}
+
+void
+pci_msix_enable(pci_chipset_tag_t pc, pcitag_t tag, bus_space_tag_t memt,
+ int vec, bus_addr_t addr, uint32_t data)
+{
+ bus_space_handle_t memh;
+ bus_addr_t base;
+ pcireg_t reg, table, type;
+ uint32_t ctrl;
+ int bir, offset;
+ int off, tblsz;
+
+ if (pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, &reg) == 0)
+ panic("%s: no msix capability", __func__);
+
+ table = pci_conf_read(pc, tag, off + PCI_MSIX_TABLE);
+ bir = (table & PCI_MSIX_TABLE_BIR);
+ offset = (table & PCI_MSIX_TABLE_OFF);
+ tblsz = PCI_MSIX_MC_TBLSZ(reg) + 1;
+
+ bir = PCI_MAPREG_START + bir * 4;
+ type = pci_mapreg_type(pc, tag, bir);
+ if (pci_mapreg_info(pc, tag, bir, type, &base, NULL, NULL) ||
+ bus_space_map(memt, base + offset, tblsz * 16, 0, &memh))
+ panic("%s: cannot map registers", __func__);
+
+ bus_space_write_4(memt, memh, PCI_MSIX_MA(vec), addr);
+ bus_space_write_4(memt, memh, PCI_MSIX_MAU32(vec), addr >> 32);
+ bus_space_write_4(memt, memh, PCI_MSIX_MD(vec), data);
+ bus_space_barrier(memt, memh, PCI_MSIX_MA(vec), 16,
+ BUS_SPACE_BARRIER_WRITE);
+ ctrl = bus_space_read_4(memt, memh, PCI_MSIX_VC(vec));
+ bus_space_write_4(memt, memh, PCI_MSIX_VC(vec),
+ ctrl & ~PCI_MSIX_VC_MASK);
+
+ bus_space_unmap(memt, memh, tblsz * 16);
+
+ pci_conf_write(pc, tag, off, reg | PCI_MSIX_MC_MSIXE);
+}
diff --git a/sys/arch/arm64/include/pci_machdep.h b/sys/arch/arm64/include/pci_machdep.h
index 64739c2e755..884e91889d6 100644
--- a/sys/arch/arm64/include/pci_machdep.h
+++ b/sys/arch/arm64/include/pci_machdep.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pci_machdep.h,v 1.3 2018/08/19 08:23:47 kettenis Exp $ */
+/* $OpenBSD: pci_machdep.h,v 1.4 2019/05/31 08:02:04 kettenis Exp $ */
/*
* Copyright (c) 2003-2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -97,5 +97,9 @@ struct arm64_pci_chipset {
#define pci_dev_postattach(a, b)
-void pci_mcfg_init(bus_space_tag_t, bus_addr_t, int, int, int);
+void pci_mcfg_init(bus_space_tag_t, bus_addr_t, int, int, int);
pci_chipset_tag_t pci_lookup_segment(int);
+
+void pci_msi_enable(pci_chipset_tag_t, pcitag_t, bus_addr_t, uint32_t);
+void pci_msix_enable(pci_chipset_tag_t, pcitag_t, bus_space_tag_t,
+ int, bus_addr_t, uint32_t);