diff options
author | 2019-05-31 08:02:04 +0000 | |
---|---|---|
committer | 2019-05-31 08:02:04 +0000 | |
commit | a569ea7c7244091823e5fd7257c161eca1b67a5d (patch) | |
tree | 7a93e37c62bf46e9403e0d6ee807d8fc35a5d745 /sys | |
parent | Rename struct plimit field p_refcnt to pl_refcnt to avoid confusion (diff) | |
download | wireguard-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.arm64 | 3 | ||||
-rw-r--r-- | sys/arch/arm64/dev/acpipci.c | 71 | ||||
-rw-r--r-- | sys/arch/arm64/dev/pci_machdep.c | 85 | ||||
-rw-r--r-- | sys/arch/arm64/include/pci_machdep.h | 8 |
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, ®) == 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, ®) == 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, ®) == 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, ®) == 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); |