Module Name:    src
Committed By:   jmcneill
Date:           Sun Nov 11 21:24:38 UTC 2018

Modified Files:
        src/sys/arch/arm/fdt: pcihost_fdt.c

Log Message:
Add MSI/MSI-X support.


To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/arm/fdt/pcihost_fdt.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/fdt/pcihost_fdt.c
diff -u src/sys/arch/arm/fdt/pcihost_fdt.c:1.2 src/sys/arch/arm/fdt/pcihost_fdt.c:1.3
--- src/sys/arch/arm/fdt/pcihost_fdt.c:1.2	Sun Sep  9 13:40:28 2018
+++ src/sys/arch/arm/fdt/pcihost_fdt.c	Sun Nov 11 21:24:38 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: pcihost_fdt.c,v 1.2 2018/09/09 13:40:28 jmcneill Exp $ */
+/* $NetBSD: pcihost_fdt.c,v 1.3 2018/11/11 21:24:38 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2018 Jared D. McNeill <[email protected]>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pcihost_fdt.c,v 1.2 2018/09/09 13:40:28 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pcihost_fdt.c,v 1.3 2018/11/11 21:24:38 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -50,6 +50,8 @@ __KERNEL_RCSID(0, "$NetBSD: pcihost_fdt.
 
 #include <dev/fdt/fdtvar.h>
 
+#include <arm/pci/pci_msi_machdep.h>
+
 #define	IH_INDEX_MASK			0x0000ffff
 #define	IH_MPSAFE			0x80000000
 
@@ -72,6 +74,8 @@ __KERNEL_RCSID(0, "$NetBSD: pcihost_fdt.
 #define	PHYS_HI_FUNCTION		__BITS(10,8)
 #define	PHYS_HI_REGISTER		__BITS(7,0)
 
+static int pcihost_segment = 0;
+
 enum pcihost_type {
 	PCIHOST_CAM = 1,
 	PCIHOST_ECAM,
@@ -86,6 +90,7 @@ struct pcihost_softc {
 
 	enum pcihost_type	sc_type;
 
+	u_int			sc_seg;
 	u_int			sc_bus_min;
 	u_int			sc_bus_max;
 
@@ -103,6 +108,7 @@ static void	pcihost_attach_hook(device_t
 static int	pcihost_bus_maxdevs(void *, int);
 static pcitag_t	pcihost_make_tag(void *, int, int, int);
 static void	pcihost_decompose_tag(void *, pcitag_t, int *, int *, int *);
+static u_int	pcihost_get_segment(void *);
 static pcireg_t	pcihost_conf_read(void *, pcitag_t, int);
 static void	pcihost_conf_write(void *, pcitag_t, int, pcireg_t);
 static int	pcihost_conf_hook(void *, int, int, int, pcireg_t);
@@ -178,6 +184,15 @@ pcihost_attach(device_t parent, device_t
 		sc->sc_bus_max = PCIHOST_DEFAULT_BUS_MAX;
 	}
 
+	/*
+	 * Assign a fixed PCI segment ("domain") number. If the property is not
+	 * present, assign one. The binding spec says if this property is used to
+	 * assign static segment numbers, all host bridges should have segments
+	 * astatic assigned to prevent overlaps.
+	 */
+	if (of_getprop_uint32(sc->sc_phandle, "linux,pci-domain", &sc->sc_seg))
+		sc->sc_seg = pcihost_segment++;
+
 	pcihost_init(&sc->sc_pc, sc);
 
 	if (pcihost_config(sc) != 0)
@@ -189,6 +204,12 @@ pcihost_attach(device_t parent, device_t
 			PCI_FLAGS_MWI_OKAY |
 			PCI_FLAGS_MEM_OKAY |
 			PCI_FLAGS_IO_OKAY;
+#ifdef __HAVE_PCI_MSI_MSIX
+	if (sc->sc_type == PCIHOST_ECAM) {
+		pba.pba_flags |= PCI_FLAGS_MSI_OKAY |
+				 PCI_FLAGS_MSIX_OKAY;
+	}
+#endif
 	pba.pba_iot = sc->sc_bst;
 	pba.pba_memt = sc->sc_bst;
 	pba.pba_dmat = sc->sc_dmat;
@@ -196,7 +217,7 @@ pcihost_attach(device_t parent, device_t
 	pba.pba_dmat64 = sc->sc_dmat;
 #endif
 	pba.pba_pc = &sc->sc_pc;
-	pba.pba_bus = 0;
+	pba.pba_bus = sc->sc_bus_min;
 
 	config_found_ia(self, "pcibus", &pba, pcibusprint);
 }
@@ -209,6 +230,7 @@ pcihost_init(pci_chipset_tag_t pc, void 
 	pc->pc_bus_maxdevs = pcihost_bus_maxdevs;
 	pc->pc_make_tag = pcihost_make_tag;
 	pc->pc_decompose_tag = pcihost_decompose_tag;
+	pc->pc_get_segment = pcihost_get_segment;
 	pc->pc_conf_read = pcihost_conf_read;
 	pc->pc_conf_write = pcihost_conf_write;
 	pc->pc_conf_hook = pcihost_conf_hook;
@@ -228,8 +250,17 @@ pcihost_config(struct pcihost_softc *sc)
 {
 	struct extent *ioext = NULL, *memext = NULL, *pmemext = NULL;
 	const u_int *ranges;
+	u_int probe_only;
 	int error, len;
 
+	/*
+	 * If this flag is set, skip configuration of the PCI bus and use existing config.
+	 */
+	if (of_getprop_uint32(sc->sc_phandle, "linux,pci-probe-only", &probe_only))
+		probe_only = 0;
+	if (probe_only)
+		return 0;
+
 	ranges = fdtbus_get_prop(sc->sc_phandle, "ranges", &len);
 	if (ranges == NULL) {
 		aprint_error_dev(sc->sc_dev, "missing 'ranges' property\n");
@@ -334,6 +365,14 @@ pcihost_decompose_tag(void *v, pcitag_t 
 		*fp = (tag >> 8) & 0x7;
 }
 
+static u_int
+pcihost_get_segment(void *v)
+{
+	struct pcihost_softc *sc = v;
+
+	return sc->sc_seg;
+}
+
 static pcireg_t
 pcihost_conf_read(void *v, pcitag_t tag, int offset)
 {
@@ -489,16 +528,24 @@ pcihost_find_intr(struct pcihost_softc *
 static const char *
 pcihost_intr_string(void *v, pci_intr_handle_t ih, char *buf, size_t len)
 {
+	const int irq = __SHIFTOUT(ih, ARM_PCI_INTR_IRQ);
+	const int vec = __SHIFTOUT(ih, ARM_PCI_INTR_MSI_VEC);
 	struct pcihost_softc *sc = v;
 	const u_int *specifier;
 	int ihandle;
 
-	specifier = pcihost_find_intr(sc, ih & IH_INDEX_MASK, &ihandle);
-	if (specifier == NULL)
-		return NULL;
+	if (ih & ARM_PCI_INTR_MSIX) {
+		snprintf(buf, len, "irq %d (MSI-X vec %d)", irq, vec);
+	} else if (ih & ARM_PCI_INTR_MSI) {
+		snprintf(buf, len, "irq %d (MSI vec %d)", irq, vec);
+	} else {
+		specifier = pcihost_find_intr(sc, ih & IH_INDEX_MASK, &ihandle);
+		if (specifier == NULL)
+			return NULL;
 
-	if (!fdtbus_intr_str_raw(ihandle, specifier, buf, len))
-		return NULL;
+		if (!fdtbus_intr_str_raw(ihandle, specifier, buf, len))
+			return NULL;
+	}
 
 	return buf;
 }
@@ -533,6 +580,9 @@ pcihost_intr_establish(void *v, pci_intr
 	const u_int *specifier;
 	int ihandle;
 
+	if ((ih & (ARM_PCI_INTR_MSI | ARM_PCI_INTR_MSIX)) != 0)
+		return arm_pci_msi_intr_establish(&sc->sc_pc, ih, ipl, callback, arg);
+
 	specifier = pcihost_find_intr(sc, ih & IH_INDEX_MASK, &ihandle);
 	if (specifier == NULL)
 		return NULL;

Reply via email to