Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/arm/cortex Add MSI-X support.
details: https://anonhg.NetBSD.org/src/rev/3095c81dff91
branches: trunk
changeset: 445522:3095c81dff91
user: jmcneill <jmcneill%NetBSD.org@localhost>
date: Wed Oct 31 15:43:19 2018 +0000
description:
Add MSI-X support.
diffstat:
sys/arch/arm/cortex/gic_v2m.c | 115 ++++++++++++++++++++++++++++++++++++++++-
1 files changed, 112 insertions(+), 3 deletions(-)
diffs (157 lines):
diff -r a69f189d5d3c -r 3095c81dff91 sys/arch/arm/cortex/gic_v2m.c
--- a/sys/arch/arm/cortex/gic_v2m.c Wed Oct 31 15:42:36 2018 +0000
+++ b/sys/arch/arm/cortex/gic_v2m.c Wed Oct 31 15:43:19 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: gic_v2m.c,v 1.2 2018/10/30 23:59:47 jmcneill Exp $ */
+/* $NetBSD: gic_v2m.c,v 1.3 2018/10/31 15:43:19 jmcneill Exp $ */
/*-
* Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -32,7 +32,7 @@
#define _INTR_PRIVATE
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: gic_v2m.c,v 1.2 2018/10/30 23:59:47 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: gic_v2m.c,v 1.3 2018/10/31 15:43:19 jmcneill Exp $");
#include <sys/param.h>
#include <sys/kmem.h>
@@ -135,6 +135,48 @@
pci_conf_write(pc, tag, off + PCI_MSI_CTL, ctl);
}
+static void
+gic_v2m_msix_enable(struct gic_v2m_frame *frame, int spi, int msix_vec,
+ bus_space_tag_t bst, bus_space_handle_t bsh)
+{
+ const struct pci_attach_args *pa = frame->frame_pa[spi];
+ pci_chipset_tag_t pc = pa->pa_pc;
+ pcitag_t tag = pa->pa_tag;
+ pcireg_t ctl;
+ int off;
+
+ if (!pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, NULL))
+ panic("gic_v2m_msix_enable: device is not MSI-X-capable");
+
+ const uint64_t addr = frame->frame_reg + GIC_MSI_SETSPI;
+ const uint64_t entry_base = PCI_MSIX_TABLE_ENTRY_SIZE * msix_vec;
+ bus_space_write_4(bst, bsh, entry_base + PCI_MSIX_TABLE_ENTRY_ADDR_LO, (uint32_t)addr);
+ bus_space_write_4(bst, bsh, entry_base + PCI_MSIX_TABLE_ENTRY_ADDR_HI, (uint32_t)(addr >> 32));
+ bus_space_write_4(bst, bsh, entry_base + PCI_MSIX_TABLE_ENTRY_DATA, spi);
+ bus_space_write_4(bst, bsh, entry_base + PCI_MSIX_TABLE_ENTRY_VECTCTL, 0);
+
+ ctl = pci_conf_read(pc, tag, off + PCI_MSIX_CTL);
+ ctl |= PCI_MSIX_CTL_ENABLE;
+ pci_conf_write(pc, tag, off + PCI_MSIX_CTL, ctl);
+}
+
+static void
+gic_v2m_msix_disable(struct gic_v2m_frame *frame, int spi)
+{
+ const struct pci_attach_args *pa = frame->frame_pa[spi];
+ pci_chipset_tag_t pc = pa->pa_pc;
+ pcitag_t tag = pa->pa_tag;
+ pcireg_t ctl;
+ int off;
+
+ if (!pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, NULL))
+ panic("gic_v2m_msix_disable: device is not MSI-X-capable");
+
+ ctl = pci_conf_read(pc, tag, off + PCI_MSIX_CTL);
+ ctl &= ~PCI_MSIX_CTL_ENABLE;
+ pci_conf_write(pc, tag, off + PCI_MSIX_CTL, ctl);
+}
+
static pci_intr_handle_t *
gic_v2m_msi_alloc(struct arm_pci_msi *msi, int *count,
const struct pci_attach_args *pa, bool exact)
@@ -175,6 +217,69 @@
return vectors;
}
+static pci_intr_handle_t *
+gic_v2m_msix_alloc(struct arm_pci_msi *msi, u_int *table_indexes, int *count,
+ const struct pci_attach_args *pa, bool exact)
+{
+ struct gic_v2m_frame * const frame = msi->msi_priv;
+ pci_intr_handle_t *vectors;
+ bus_space_tag_t bst;
+ bus_space_handle_t bsh;
+ bus_size_t bsz;
+ uint32_t table_offset, table_size;
+ int n, off, bar, error;
+ pcireg_t tbl;
+
+ if (!pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_MSIX, &off, NULL))
+ return NULL;
+
+ const int avail = gic_v2m_msi_available_spi(frame);
+ if (exact && *count > avail)
+ return NULL;
+
+ while (*count > avail) {
+ if (avail < *count)
+ (*count) >>= 1;
+ }
+ if (*count == 0)
+ return NULL;
+
+ tbl = pci_conf_read(pa->pa_pc, pa->pa_tag, off + PCI_MSIX_TBLOFFSET);
+ bar = PCI_BAR0 + (4 * (tbl & PCI_MSIX_PBABIR_MASK));
+ table_offset = tbl & PCI_MSIX_TBLOFFSET_MASK;
+ table_size = pci_msix_count(pa->pa_pc, pa->pa_tag) * PCI_MSIX_TABLE_ENTRY_SIZE;
+ if (table_size == 0)
+ return NULL;
+
+ error = pci_mapreg_submap(pa, bar, pci_mapreg_type(pa->pa_pc, pa->pa_tag, bar),
+ BUS_SPACE_MAP_LINEAR, roundup(table_size, PAGE_SIZE), table_offset,
+ &bst, &bsh, NULL, &bsz);
+ if (error)
+ return NULL;
+
+ const int spi_base = gic_v2m_msi_alloc_spi(frame, *count, pa);
+ if (spi_base == -1) {
+ bus_space_unmap(bst, bsh, bsz);
+ return NULL;
+ }
+
+ vectors = kmem_alloc(sizeof(*vectors) * *count, KM_SLEEP);
+ for (n = 0; n < *count; n++) {
+ const int spi = spi_base + n;
+ const int msix_vec = table_indexes ? table_indexes[n] : n;
+ vectors[msix_vec] = ARM_PCI_INTR_MSIX |
+ __SHIFTIN(spi, ARM_PCI_INTR_IRQ) |
+ __SHIFTIN(msix_vec, ARM_PCI_INTR_MSI_VEC) |
+ __SHIFTIN(msi->msi_id, ARM_PCI_INTR_FRAME);
+
+ gic_v2m_msix_enable(frame, spi, msix_vec, bst, bsh);
+ }
+
+ bus_space_unmap(bst, bsh, bsz);
+
+ return vectors;
+}
+
static void *
gic_v2m_msi_intr_establish(struct arm_pci_msi *msi,
pci_intr_handle_t ih, int ipl, int (*func)(void *), void *arg)
@@ -197,7 +302,10 @@
for (n = 0; n < count; n++) {
const int spi = __SHIFTOUT(pih[n], ARM_PCI_INTR_IRQ);
- gic_v2m_msi_disable(frame, spi);
+ if (pih[n] & ARM_PCI_INTR_MSIX)
+ gic_v2m_msix_disable(frame, spi);
+ if (pih[n] & ARM_PCI_INTR_MSI)
+ gic_v2m_msi_disable(frame, spi);
gic_v2m_msi_free_spi(frame, spi);
struct intrsource * const is =
frame->frame_pic->pic_sources[spi];
@@ -214,6 +322,7 @@
msi->msi_dev = dev;
msi->msi_priv = frame;
msi->msi_alloc = gic_v2m_msi_alloc;
+ msi->msix_alloc = gic_v2m_msix_alloc;
msi->msi_intr_establish = gic_v2m_msi_intr_establish;
msi->msi_intr_release = gic_v2m_msi_intr_release;
Home |
Main Index |
Thread Index |
Old Index