svn commit: r304630 - projects/powernv/powerpc/powernv

Nathan Whitehorn nwhitehorn at FreeBSD.org
Mon Aug 22 19:35:14 UTC 2016


Author: nwhitehorn
Date: Mon Aug 22 19:35:12 2016
New Revision: 304630
URL: https://svnweb.freebsd.org/changeset/base/304630

Log:
  Add MSI support for OPAL-based PCI controllers. This supports only the POWER8
  version of MSI and above but the POWER7-based OPAL firmware was never publicly
  released, so I don't think we need to worry about that.

Modified:
  projects/powernv/powerpc/powernv/opal.h
  projects/powernv/powerpc/powernv/opal_pci.c

Modified: projects/powernv/powerpc/powernv/opal.h
==============================================================================
--- projects/powernv/powerpc/powernv/opal.h	Mon Aug 22 19:32:50 2016	(r304629)
+++ projects/powernv/powerpc/powernv/opal.h	Mon Aug 22 19:35:12 2016	(r304630)
@@ -63,6 +63,9 @@ int opal_call(uint64_t token, ...);
 #define	OPAL_SET_XIVE			19
 #define	OPAL_GET_XIVE			20
 #define	OPAL_PCI_SET_PE			31
+#define	OPAL_GET_MSI_32			39
+#define	OPAL_GET_MSI_64			40
+#define	OPAL_PCI_MSI_EOI		63
 #define	OPAL_START_CPU			41
 #define	OPAL_PCI_MAP_PE_DMA_WINDOW_REAL	45
 #define	OPAL_RETURN_CPU			69

Modified: projects/powernv/powerpc/powernv/opal_pci.c
==============================================================================
--- projects/powernv/powerpc/powernv/opal_pci.c	Mon Aug 22 19:32:50 2016	(r304629)
+++ projects/powernv/powerpc/powernv/opal_pci.c	Mon Aug 22 19:35:12 2016	(r304630)
@@ -48,7 +48,9 @@ __FBSDID("$FreeBSD$");
 #include <machine/resource.h>
 #include <machine/rtas.h>
 
+#include <sys/endian.h>
 #include <sys/rman.h>
+#include <sys/vmem.h>
 
 #include <vm/vm.h>
 #include <vm/pmap.h>
@@ -56,6 +58,7 @@ __FBSDID("$FreeBSD$");
 #include <dev/ofw/ofwpci.h>
 
 #include "pcib_if.h"
+#include "pic_if.h"
 #include "iommu_if.h"
 #include "opal.h"
 
@@ -68,18 +71,29 @@ static int		opalpci_attach(device_t);
 /*
  * pcib interface.
  */
-static u_int32_t	opalpci_read_config(device_t, u_int, u_int, u_int,
+static uint32_t		opalpci_read_config(device_t, u_int, u_int, u_int,
 			    u_int, int);
 static void		opalpci_write_config(device_t, u_int, u_int, u_int,
 			    u_int, u_int32_t, int);
+static int		opalpci_alloc_msi(device_t dev, device_t child,
+			    int count, int maxcount, int *irqs);
+static int		opalpci_release_msi(device_t dev, device_t child,
+			    int count, int *irqs);
+static int		opalpci_alloc_msix(device_t dev, device_t child,
+			    int *irq);
+static int		opalpci_release_msix(device_t dev, device_t child,
+			    int irq);
+static int		opalpci_map_msi(device_t dev, device_t child,
+			    int irq, uint64_t *addr, uint32_t *data);
+static int opalpci_route_interrupt(device_t bus, device_t dev, int pin);
 
 /*
- * bus interface.
+ * MSI PIC interface.
  */
-
-static int opalpci_setup_intr(device_t dev, device_t child, struct resource *r,
-    int flags, driver_filter_t *filter, driver_intr_t *ithread,
-    void *arg, void **cookiep);
+static void opalpic_pic_enable(device_t dev, u_int irq, u_int vector);
+static void opalpic_pic_eoi(device_t dev, u_int irq);
+static void opalpic_pic_mask(device_t dev, u_int irq);
+static void opalpic_pic_unmask(device_t dev, u_int irq);
 
 /*
  * Commands
@@ -116,8 +130,18 @@ static device_method_t	opalpci_methods[]
 	DEVMETHOD(pcib_read_config,	opalpci_read_config),
 	DEVMETHOD(pcib_write_config,	opalpci_write_config),
 
-	/* bus overrides */
-	DEVMETHOD(bus_setup_intr,	opalpci_setup_intr),
+	DEVMETHOD(pcib_alloc_msi,	opalpci_alloc_msi),
+	DEVMETHOD(pcib_release_msi,	opalpci_release_msi),
+	DEVMETHOD(pcib_alloc_msix,	opalpci_alloc_msix),
+	DEVMETHOD(pcib_release_msix,	opalpci_release_msix),
+	DEVMETHOD(pcib_map_msi,		opalpci_map_msi),
+	DEVMETHOD(pcib_route_interrupt,	opalpci_route_interrupt),
+
+	/* PIC interface for MSIs */
+	DEVMETHOD(pic_enable,		opalpic_pic_enable),
+	DEVMETHOD(pic_eoi,		opalpic_pic_eoi),
+	DEVMETHOD(pic_mask,		opalpic_pic_mask),
+	DEVMETHOD(pic_unmask,		opalpic_pic_unmask),
 
 	DEVMETHOD_END
 };
@@ -125,6 +149,9 @@ static device_method_t	opalpci_methods[]
 struct opalpci_softc {
 	struct ofw_pci_softc ofw_sc;
 	uint64_t phb_id;
+	vmem_t *msi_vmem;
+	int msi_base;		/* Base XIVE number */
+	int base_msi_irq;	/* Base IRQ assigned by FreeBSD to this PIC */
 };
 
 static devclass_t	opalpci_devclass;
@@ -286,6 +313,28 @@ opalpci_attach(device_t dev)
 	}
 
 	/*
+	 * Get MSI properties
+	 */
+	sc->msi_vmem = NULL;
+	if (OF_getproplen(ofw_bus_get_node(dev), "ibm,opal-msi-ranges") > 0) {
+		cell_t msi_ranges[2];
+		OF_getencprop(ofw_bus_get_node(dev), "ibm,opal-msi-ranges",
+		    msi_ranges, sizeof(msi_ranges));
+		sc->msi_base = msi_ranges[0];
+
+		sc->msi_vmem = vmem_create("OPAL MSI", msi_ranges[0],
+		    msi_ranges[1], 1, 16, M_BESTFIT | M_WAITOK);
+
+		sc->base_msi_irq = powerpc_register_pic(dev,
+		    OF_xref_from_node(ofw_bus_get_node(dev)),
+		    msi_ranges[0] + msi_ranges[1], 0, FALSE);
+
+		if (bootverbose)
+			device_printf(dev, "Supports %d MSIs starting at %d\n",
+			    msi_ranges[1], msi_ranges[0]);
+	}
+
+	/*
 	 * General OFW PCI attach
 	 */
 	err = ofw_pci_init(dev);
@@ -410,17 +459,110 @@ opalpci_write_config(device_t dev, u_int
 }
 
 static int
-opalpci_setup_intr(device_t dev, device_t child, struct resource *r,
-    int flags, driver_filter_t *filter, driver_intr_t *ithread,
-    void *arg, void **cookiep)
+opalpci_route_interrupt(device_t bus, device_t dev, int pin)
+{
+	return (pin);
+}
+
+static int
+opalpci_alloc_msi(device_t dev, device_t child, int count, int maxcount,
+    int *irqs)
 {
 	struct opalpci_softc *sc;
+	vmem_addr_t start;
+	phandle_t xref;
+	int err, i;
 
 	sc = device_get_softc(dev);
-	opal_call(OPAL_PCI_SET_XIVE_PE, sc->phb_id, OPAL_PCI_DEFAULT_PE,
-	    rman_get_start(r));
+	if (sc->msi_vmem == NULL)
+		return (ENODEV);
+
+	err = vmem_xalloc(sc->msi_vmem, count, powerof2(count), 0, 0,
+	    VMEM_ADDR_MIN, VMEM_ADDR_MAX, M_BESTFIT | M_WAITOK, &start);
+
+	if (err)
+		return (err);
+
+	xref = OF_xref_from_node(ofw_bus_get_node(dev));
+	for (i = 0; i < count; i++)
+		irqs[i] = MAP_IRQ(xref, start + i);
+
+	return (0);
+}
 
-	return BUS_SETUP_INTR(device_get_parent(dev), child, r, flags, filter,
-	    ithread, arg, cookiep);
+static int
+opalpci_release_msi(device_t dev, device_t child, int count, int *irqs)
+{
+	struct opalpci_softc *sc;
+
+	sc = device_get_softc(dev);
+	if (sc->msi_vmem == NULL)
+		return (ENODEV);
+
+	vmem_xfree(sc->msi_vmem, irqs[0] - sc->base_msi_irq, count);
+	return (0);
+}
+
+static int
+opalpci_alloc_msix(device_t dev, device_t child, int *irq)
+{
+	return (opalpci_alloc_msi(dev, child, 1, 1, irq));
+}
+
+static int
+opalpci_release_msix(device_t dev, device_t child, int irq)
+{
+	return (opalpci_release_msi(dev, child, 1, &irq));
 }
 
+static int
+opalpci_map_msi(device_t dev, device_t child, int irq, uint64_t *addr,
+    uint32_t *data)
+{
+	struct opalpci_softc *sc;
+	int err, xive;
+
+	sc = device_get_softc(dev);
+	if (sc->msi_vmem == NULL)
+		return (ENODEV);
+
+	xive = irq - sc->base_msi_irq - sc->msi_base;
+	opal_call(OPAL_PCI_SET_XIVE_PE, sc->phb_id, OPAL_PCI_DEFAULT_PE, xive);
+	err = opal_call(OPAL_GET_MSI_64, sc->phb_id, OPAL_PCI_DEFAULT_PE, xive,
+	    1, vtophys(addr), vtophys(data));
+	*addr = be64toh(*addr);
+	*data = be32toh(*data);
+
+	if (bootverbose && err != 0)
+		device_printf(child, "OPAL MSI mapping error: %d\n", err);
+
+	return ((err == 0) ? 0 : ENXIO);
+}
+
+static void
+opalpic_pic_enable(device_t dev, u_int irq, u_int vector)
+{
+	PIC_ENABLE(root_pic, irq, vector);
+}
+
+static void opalpic_pic_eoi(device_t dev, u_int irq)
+{
+	struct opalpci_softc *sc;
+
+	sc = device_get_softc(dev);
+	opal_call(OPAL_PCI_MSI_EOI, sc->phb_id, irq);
+
+	PIC_EOI(root_pic, irq);
+}
+
+static void opalpic_pic_mask(device_t dev, u_int irq)
+{
+	PIC_MASK(root_pic, irq);
+}
+
+static void opalpic_pic_unmask(device_t dev, u_int irq)
+{
+	PIC_UNMASK(root_pic, irq);
+}
+
+


More information about the svn-src-projects mailing list