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