Module Name:    src
Committed By:   jmcneill
Date:           Wed Oct 31 15:43:19 UTC 2018

Modified Files:
        src/sys/arch/arm/cortex: gic_v2m.c

Log Message:
Add MSI-X support.


To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/arm/cortex/gic_v2m.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/arm/cortex/gic_v2m.c
diff -u src/sys/arch/arm/cortex/gic_v2m.c:1.2 src/sys/arch/arm/cortex/gic_v2m.c:1.3
--- src/sys/arch/arm/cortex/gic_v2m.c:1.2	Tue Oct 30 23:59:47 2018
+++ src/sys/arch/arm/cortex/gic_v2m.c	Wed Oct 31 15:43:19 2018
@@ -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 @@ gic_v2m_msi_disable(struct gic_v2m_frame
 	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 @@ gic_v2m_msi_alloc(struct arm_pci_msi *ms
 	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 @@ gic_v2m_msi_intr_release(struct arm_pci_
 
 	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 @@ gic_v2m_init(struct gic_v2m_frame *frame
 	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;
 

Reply via email to