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