Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 5 Nov 2016 10:48:44 +0000 (UTC)
From:      Michal Meloun <mmel@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org
Subject:   svn commit: r308334 - stable/11/sys/arm/nvidia
Message-ID:  <201611051048.uA5Amimd041637@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mmel
Date: Sat Nov  5 10:48:44 2016
New Revision: 308334
URL: https://svnweb.freebsd.org/changeset/base/308334

Log:
  MFC r302961,r304460,r304461:
  
    r302961:
      TEGRA: Subclass Tegra PCIE driver from ofw_pci base driver.  Remove now
      redundant code.
    r304460:
      TEGRA: Implement MSI/MSIX interrupts for pcie controller.
    r304461:
      TEGRA: Remove forgotten debug printf.

Modified:
  stable/11/sys/arm/nvidia/tegra_pcie.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/arm/nvidia/tegra_pcie.c
==============================================================================
--- stable/11/sys/arm/nvidia/tegra_pcie.c	Sat Nov  5 10:23:02 2016	(r308333)
+++ stable/11/sys/arm/nvidia/tegra_pcie.c	Sat Nov  5 10:48:44 2016	(r308334)
@@ -33,20 +33,20 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/devmap.h>
+#include <sys/proc.h>
 #include <sys/kernel.h>
-#include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
 #include <sys/mutex.h>
-#include <sys/queue.h>
-#include <sys/bus.h>
 #include <sys/rman.h>
-#include <sys/endian.h>
-#include <sys/devmap.h>
 
 #include <machine/intr.h>
 
 #include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
 #include <vm/pmap.h>
 
 #include <dev/extres/clk/clk.h>
@@ -57,6 +57,7 @@ __FBSDID("$FreeBSD$");
 #include <dev/ofw/ofw_bus.h>
 #include <dev/ofw/ofw_bus_subr.h>
 #include <dev/ofw/ofw_pci.h>
+#include <dev/ofw/ofwpci.h>
 #include <dev/pci/pcivar.h>
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcib_private.h>
@@ -64,100 +65,14 @@ __FBSDID("$FreeBSD$");
 #include <machine/resource.h>
 #include <machine/bus.h>
 
-#include "ofw_bus_if.h"
-#include "pcib_if.h"
-
 #include <arm/nvidia/tegra_pmc.h>
 
-/* --- Move to ofw_pci.c/.h ----------------------- */
-
-struct tegra_pci_range {
-	/* parsed phys.hi */
-	int 		nonrelocatable;
-	int		prefetchable;
-	int		aliased;
-	int		space_code;	/* In native format (not shifted)*/
-	int		bus;
-	int		device;
-	int		function;
-	int		reg;
-	pci_addr_t	pci_addr;	/* PCI Address */
-	bus_addr_t	host_addr;	/* Host bus address*/
-	bus_size_t	size;		/* Range size */
-};
-
-static int
-tegra_pci_get_ranges(phandle_t node,  struct tegra_pci_range **ranges)
-{
-	int host_address_cells, pci_address_cells, size_cells;
-	cell_t *base_ranges;
-	ssize_t nbase_ranges;
-	int nranges;
-	int i, j, k;
-	uint32_t flags;
-	uint64_t tmp;
-
-	host_address_cells = 1;
-	pci_address_cells = 3;
-	size_cells = 2;
-	OF_getencprop(OF_parent(node), "#address-cells", &host_address_cells,
-	    sizeof(host_address_cells));
-	OF_getencprop(node, "#address-cells", &pci_address_cells,
-	    sizeof(pci_address_cells));
-	OF_getencprop(node, "#size-cells", &size_cells, sizeof(size_cells));
-
-	nbase_ranges = OF_getproplen(node, "ranges");
-	if (nbase_ranges <= 0)
-		return (-1);
-	nranges = nbase_ranges / sizeof(cell_t) /
-	    (pci_address_cells + host_address_cells + size_cells);
-
-	*ranges = malloc(nranges * sizeof(struct tegra_pci_range),
-	    M_DEVBUF, M_WAITOK);
-	base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK);
-	OF_getencprop(node, "ranges", base_ranges, nbase_ranges);
-
-	for (i = 0, j = 0; i < nranges; i++) {
-		flags =  base_ranges[j++];
-		(*ranges)[i].nonrelocatable =
-		   flags & OFW_PCI_PHYS_HI_NONRELOCATABLE ? 1 : 0;
-		(*ranges)[i].prefetchable =
-		   flags & OFW_PCI_PHYS_HI_PREFETCHABLE ? 1 : 0;
-		(*ranges)[i].aliased =
-		   flags & OFW_PCI_PHYS_HI_ALIASED ? 1 : 0;
-		(*ranges)[i].space_code = flags & OFW_PCI_PHYS_HI_SPACEMASK;
-		(*ranges)[i].bus = OFW_PCI_PHYS_HI_BUS(flags);
-		(*ranges)[i].device = OFW_PCI_PHYS_HI_DEVICE(flags);
-		(*ranges)[i].function = OFW_PCI_PHYS_HI_FUNCTION(flags);
-		(*ranges)[i].reg = flags & OFW_PCI_PHYS_HI_REGISTERMASK;
-
-		tmp = 0;
-		for (k = 0; k < pci_address_cells - 1; k++) {
-			tmp <<= 32;
-			tmp |= base_ranges[j++];
-		}
-		(*ranges)[i].pci_addr = (pci_addr_t)tmp;
-
-		tmp = 0;
-		for (k = 0; k < host_address_cells; k++) {
-			tmp <<= 32;
-			tmp |= base_ranges[j++];
-		}
-		(*ranges)[i].host_addr = (bus_addr_t)tmp;
-		tmp = 0;
-
-		for (k = 0; k < size_cells; k++) {
-			tmp <<= 32;
-			tmp |= base_ranges[j++];
-		}
-		(*ranges)[i].size = (bus_size_t)tmp;
-	}
+#include "ofw_bus_if.h"
+#include "msi_if.h"
+#include "pcib_if.h"
+#include "pic_if.h"
 
-	free(base_ranges, M_DEVBUF);
-	return (nranges);
-}
 
-/* -------------------------------------------------------------------------- */
 #define	AFI_AXI_BAR0_SZ				0x000
 #define	AFI_AXI_BAR1_SZ				0x004
 #define	AFI_AXI_BAR2_SZ				0x008
@@ -179,17 +94,10 @@ tegra_pci_get_ranges(phandle_t node,  st
 #define	AFI_MSI_BAR_SZ				0x060
 #define	AFI_MSI_FPCI_BAR_ST			0x064
 #define	AFI_MSI_AXI_BAR_ST			0x068
-
-
-#define	AFI_AXI_BAR6_SZ				0x134
-#define	AFI_AXI_BAR7_SZ				0x138
-#define	AFI_AXI_BAR8_SZ				0x13c
-#define	AFI_AXI_BAR6_START			0x140
-#define	AFI_AXI_BAR7_START			0x144
-#define	AFI_AXI_BAR8_START			0x148
-#define	AFI_FPCI_BAR6				0x14c
-#define	AFI_FPCI_BAR7				0x150
-#define	AFI_FPCI_BAR8				0x154
+#define AFI_MSI_VEC(x)				(0x06c + 4 * (x))
+#define AFI_MSI_EN_VEC(x)			(0x08c + 4 * (x))
+#define	 AFI_MSI_INTR_IN_REG				32
+#define	 AFI_MSI_REGS					8
 
 #define	AFI_CONFIGURATION			0x0ac
 #define	 AFI_CONFIGURATION_EN_FPCI			(1 << 0)
@@ -296,6 +204,8 @@ tegra_pci_get_ranges(phandle_t node,  st
 /* Wait 50 ms (per port) for link. */
 #define	TEGRA_PCIE_LINKUP_TIMEOUT	50000
 
+#define TEGRA_PCIB_MSI_ENABLE
+
 #define	DEBUG
 #ifdef DEBUG
 #define	debugf(fmt, args...) do { printf(fmt,##args); } while (0)
@@ -345,6 +255,13 @@ static struct ofw_compat_data compat_dat
 	{NULL,		 		0},
 };
 
+#define	TEGRA_FLAG_MSI_USED	0x0001
+struct tegra_pcib_irqsrc {
+	struct intr_irqsrc	isrc;
+	u_int			irq;
+	u_int			flags;
+};
+
 struct tegra_pcib_port {
 	int		enabled;
 	int 		port_idx;		/* chip port index */
@@ -358,13 +275,11 @@ struct tegra_pcib_port {
 };
 
 #define	TEGRA_PCIB_MAX_PORTS	3
+#define	TEGRA_PCIB_MAX_MSI	AFI_MSI_INTR_IN_REG * AFI_MSI_REGS
 struct tegra_pcib_softc {
+	struct ofw_pci_softc	ofw_pci;
 	device_t		dev;
 	struct mtx		mtx;
-	struct ofw_bus_iinfo	pci_iinfo;
-	struct rman		pref_mem_rman;
-	struct rman		mem_rman;
-	struct rman		io_rman;
 	struct resource		*pads_mem_res;
 	struct resource		*afi_mem_res;
 	struct resource		*cfg_mem_res;
@@ -373,18 +288,18 @@ struct tegra_pcib_softc {
 	void			*intr_cookie;
 	void			*msi_intr_cookie;
 
-	struct tegra_pci_range	mem_range;
-	struct tegra_pci_range	pref_mem_range;
-	struct tegra_pci_range	io_range;
+	struct ofw_pci_range	mem_range;
+	struct ofw_pci_range	pref_mem_range;
+	struct ofw_pci_range	io_range;
 
 	phy_t			phy;
 	clk_t			clk_pex;
 	clk_t			clk_afi;
 	clk_t			clk_pll_e;
 	clk_t			clk_cml;
-	hwreset_t			hwreset_pex;
-	hwreset_t			hwreset_afi;
-	hwreset_t			hwreset_pcie_x;
+	hwreset_t		hwreset_pex;
+	hwreset_t		hwreset_afi;
+	hwreset_t		hwreset_pcie_x;
 	regulator_t		supply_avddio_pex;
 	regulator_t		supply_dvddio_pex;
 	regulator_t		supply_avdd_pex_pll;
@@ -393,8 +308,7 @@ struct tegra_pcib_softc {
 	regulator_t		supply_vddio_pex_ctl;
 	regulator_t		supply_avdd_pll_erefe;
 
-	int			busnr;		/* host bridge bus number */
-	uint32_t		msi_bitmap;
+	vm_offset_t		msi_page;	/* VA of MSI page */
 	bus_addr_t		cfg_base_addr;	/* base address of config */
 	bus_size_t		cfg_cur_offs; 	/* currently mapped window */
 	bus_space_handle_t 	cfg_handle;	/* handle of config window */
@@ -402,276 +316,28 @@ struct tegra_pcib_softc {
 	int			lanes_cfg;
 	int			num_ports;
 	struct tegra_pcib_port *ports[TEGRA_PCIB_MAX_PORTS];
+	struct tegra_pcib_irqsrc *isrcs;
 };
 
-/* ------------------------------------------------------------------------- */
-/*
- * Resource manager
- */
-static int
-tegra_pcib_rman_init(struct tegra_pcib_softc *sc)
-{
-	int err;
-	char buf[64];
-
-	/* Memory management. */
-	sc->pref_mem_rman.rm_type = RMAN_ARRAY;
-	snprintf(buf, sizeof(buf), "%s prefetchable memory space",
-	    device_get_nameunit(sc->dev));
-	sc->pref_mem_rman.rm_descr = strdup(buf, M_DEVBUF);
-	err = rman_init(&sc->pref_mem_rman);
-	if (err)
-		return (err);
-
-	sc->mem_rman.rm_type = RMAN_ARRAY;
-	snprintf(buf, sizeof(buf), "%s non prefetchable memory space",
-	    device_get_nameunit(sc->dev));
-	sc->mem_rman.rm_descr = strdup(buf, M_DEVBUF);
-	err = rman_init(&sc->mem_rman);
-	if (err)
-		return (err);
-
-	sc->io_rman.rm_type = RMAN_ARRAY;
-	snprintf(buf, sizeof(buf), "%s I/O space",
-	    device_get_nameunit(sc->dev));
-	sc->io_rman.rm_descr = strdup(buf, M_DEVBUF);
-	err = rman_init(&sc->io_rman);
-	if (err) {
-		rman_fini(&sc->mem_rman);
-		return (err);
-	}
-
-	err = rman_manage_region(&sc->pref_mem_rman,
-	    sc->pref_mem_range.host_addr,
-	    sc->pref_mem_range.host_addr + sc->pref_mem_range.size - 1);
-	if (err)
-		goto error;
-	err = rman_manage_region(&sc->mem_rman,
-	    sc->mem_range.host_addr,
-	    sc->mem_range.host_addr + sc->mem_range.size - 1);
-	if (err)
-		goto error;
-	err = rman_manage_region(&sc->io_rman,
-	    sc->io_range.pci_addr,
-	    sc->io_range.pci_addr + sc->io_range.size - 1);
-	if (err)
-		goto error;
-	return (0);
-
-error:
-	rman_fini(&sc->pref_mem_rman);
-	rman_fini(&sc->mem_rman);
-	rman_fini(&sc->io_rman);
-	return (err);
-}
-
-static struct rman *
-tegra_pcib_rman(struct tegra_pcib_softc *sc, int type, u_int flags)
-{
-
-	switch (type) {
-	case SYS_RES_IOPORT:
-		return (&sc->io_rman);
-	case SYS_RES_MEMORY:
-		if (flags & RF_PREFETCHABLE)
-			return (&sc->pref_mem_rman);
-		else
-			return (&sc->mem_rman);
-	default:
-		break;
-	}
-
-	return (NULL);
-}
-
-static struct resource *
-tegra_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
-    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
-{
-	struct tegra_pcib_softc *sc;
-	struct rman *rm;
-	struct resource *res;
-
-	debugf("%s: enter %d start %#jx end %#jx count %#jx\n", __func__,
-	    type, start, end, count);
-	sc = device_get_softc(dev);
-
-#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
-	if (type ==  PCI_RES_BUS) {
-		  return (pci_domain_alloc_bus(0, child, rid, start, end, count,
-					       flags));
-	}
-#endif
-
-	rm = tegra_pcib_rman(sc, type, flags);
-
-	if (rm == NULL) {
-		res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
-		    type, rid, start, end, count, flags);
-
-		return (res);
-	}
-
-	if (bootverbose) {
-		device_printf(dev,
-		    "rman_reserve_resource: start=%#jx, end=%#jx, count=%#jx\n",
-		    start, end, count);
-	}
-
-	res = rman_reserve_resource(rm, start, end, count, flags, child);
-	if (res == NULL)
-		goto fail;
-	rman_set_rid(res, *rid);
-	if (flags & RF_ACTIVE) {
-		if (bus_activate_resource(child, type, *rid, res)) {
-			rman_release_resource(res);
-			goto fail;
-		}
-	}
-	return (res);
-
-fail:
-	if (bootverbose) {
-		device_printf(dev, "%s FAIL: type=%d, rid=%d, "
-		    "start=%016jx, end=%016jx, count=%016jx, flags=%x\n",
-		    __func__, type, *rid, start, end, count, flags);
-	}
-
-	return (NULL);
-}
-
-static int
-tegra_pcib_release_resource(device_t dev, device_t child, int type, int rid,
-    struct resource *res)
-{
-	struct tegra_pcib_softc *sc;
-	struct rman *rm;
-
-	sc = device_get_softc(dev);
-	debugf("%s: %d rid %x\n",  __func__, type, rid);
-
-#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
-	if (type == PCI_RES_BUS)
-		return (pci_domain_release_bus(0, child, rid, res));
-#endif
-
-	rm = tegra_pcib_rman(sc, type, rman_get_flags(res));
-	if (rm != NULL) {
-		KASSERT(rman_is_region_manager(res, rm), ("rman mismatch"));
-		rman_release_resource(res);
-	}
-
-	return (bus_generic_release_resource(dev, child, type, rid, res));
-}
-
-static int
-tegra_pcib_adjust_resource(device_t dev, device_t child, int type,
-			    struct resource *res, rman_res_t start, rman_res_t end)
-{
-	struct tegra_pcib_softc *sc;
-	struct rman *rm;
-
-	sc = device_get_softc(dev);
-	debugf("%s: %d start %jx end %jx \n", __func__, type, start, end);
-
-#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
-	if (type == PCI_RES_BUS)
-		return (pci_domain_adjust_bus(0, child, res, start, end));
-#endif
-
-	rm = tegra_pcib_rman(sc, type, rman_get_flags(res));
-	if (rm != NULL)
-		return (rman_adjust_resource(res, start, end));
-	return (bus_generic_adjust_resource(dev, child, type, res, start, end));
-}
-extern bus_space_tag_t fdtbus_bs_tag;
-static int
-tegra_pcib_pcie_activate_resource(device_t dev, device_t child, int type,
-    int rid, struct resource *r)
-{
-	struct tegra_pcib_softc *sc;
-	vm_offset_t start;
-	void *p;
-	int rv;
-
-	sc = device_get_softc(dev);
-	rv = rman_activate_resource(r);
-	if (rv != 0)
-		return (rv);
-	switch(type) {
-	case SYS_RES_IOPORT:
-		start = rman_get_start(r) + sc->io_range.host_addr;
-		break;
-	default:
-		start = rman_get_start(r);
-		rman_get_start(r);
-		break;
-	}
-
-	if (bootverbose)
-		printf("%s: start %zx, len %jd\n", __func__, start,
-			rman_get_size(r));
-
-	p = pmap_mapdev(start, (vm_size_t)rman_get_size(r));
-	rman_set_virtual(r, p);
-	rman_set_bustag(r, fdtbus_bs_tag);
-	rman_set_bushandle(r, (u_long)p);
-	return (0);
-}
-
-/* ------------------------------------------------------------------------- */
-/*
- * IVARs
- */
-static int
-tegra_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
-{
-	struct tegra_pcib_softc *sc = device_get_softc(dev);
-
-	switch (which) {
-	case PCIB_IVAR_BUS:
-		*result = sc->busnr;
-		return (0);
-	case PCIB_IVAR_DOMAIN:
-		*result = device_get_unit(dev);
-		return (0);
-	}
-
-	return (ENOENT);
-}
-
-static int
-tegra_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
-{
-	struct tegra_pcib_softc *sc = device_get_softc(dev);
-
-	switch (which) {
-	case PCIB_IVAR_BUS:
-		sc->busnr = value;
-		return (0);
-	}
-
-	return (ENOENT);
-}
-
 static int
 tegra_pcib_maxslots(device_t dev)
 {
 	return (16);
 }
 
-
 static int
 tegra_pcib_route_interrupt(device_t bus, device_t dev, int pin)
 {
 	struct tegra_pcib_softc *sc;
+	u_int irq;
 
 	sc = device_get_softc(bus);
-	device_printf(bus, "route pin %d for device %d.%d to %ju\n",
+	irq = intr_map_clone_irq(rman_get_start(sc->irq_res));
+	device_printf(bus, "route pin %d for device %d.%d to %u\n",
 		      pin, pci_get_slot(dev), pci_get_function(dev),
-		      rman_get_start(sc->irq_res));
+		      irq);
 
-	return (rman_get_start(sc->irq_res));
+	return (irq);
 }
 
 static int
@@ -812,84 +478,319 @@ static int tegra_pci_intr(void *arg)
 	return (FILTER_HANDLED);
 }
 
-#if defined(TEGRA_PCI_MSI)
+/* -----------------------------------------------------------------------
+ *
+ * 	PCI MSI interface
+ */
+static int
+tegra_pcib_alloc_msi(device_t pci, device_t child, int count, int maxcount,
+    int *irqs)
+{
+	phandle_t msi_parent;
+
+	/* XXXX ofw_bus_msimap() don't works for Tegra DT.
+	ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent,
+	    NULL);
+	*/
+	msi_parent = OF_xref_from_node(ofw_bus_get_node(pci));
+	return (intr_alloc_msi(pci, child, msi_parent, count, maxcount,
+	    irqs));
+}
+
+static int
+tegra_pcib_release_msi(device_t pci, device_t child, int count, int *irqs)
+{
+	phandle_t msi_parent;
+
+	/* XXXX ofw_bus_msimap() don't works for Tegra DT.
+	ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent,
+	    NULL);
+	*/
+	msi_parent = OF_xref_from_node(ofw_bus_get_node(pci));
+	return (intr_release_msi(pci, child, msi_parent, count, irqs));
+}
+
 static int
-tegra_pcib_map_msi(device_t dev, device_t child, int irq, uint64_t *addr,
+tegra_pcib_map_msi(device_t pci, device_t child, int irq, uint64_t *addr,
     uint32_t *data)
 {
+	phandle_t msi_parent;
+
+	/* XXXX ofw_bus_msimap() don't works for Tegra DT.
+	ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent,
+	    NULL);
+	*/
+	msi_parent = OF_xref_from_node(ofw_bus_get_node(pci));
+	return (intr_map_msi(pci, child, msi_parent, irq, addr, data));
+}
+
+#ifdef TEGRA_PCIB_MSI_ENABLE
+
+/* --------------------------------------------------------------------------
+ *
+ * Interrupts
+ *
+ */
+
+static inline void
+tegra_pcib_isrc_mask(struct tegra_pcib_softc *sc,
+     struct tegra_pcib_irqsrc *tgi, uint32_t val)
+{
+	uint32_t reg;
+	int offs, bit;
+
+	offs = tgi->irq / AFI_MSI_INTR_IN_REG;
+	bit = 1 << (tgi->irq % AFI_MSI_INTR_IN_REG);
+
+	if (val != 0)
+		AFI_WR4(sc, AFI_MSI_VEC(offs), bit);
+	reg = AFI_RD4(sc, AFI_MSI_EN_VEC(offs));
+	if (val !=  0)
+		reg |= bit;
+	else
+		reg &= ~bit;
+	AFI_WR4(sc, AFI_MSI_EN_VEC(offs), reg);
+}
+
+static int
+tegra_pcib_msi_intr(void *arg)
+{
+	u_int irq, i, bit, reg;
 	struct tegra_pcib_softc *sc;
+	struct trapframe *tf;
+	struct tegra_pcib_irqsrc *tgi;
 
-	sc = device_get_softc(dev);
-	irq = irq - MSI_IRQ;
+	sc = (struct tegra_pcib_softc *)arg;
+	tf = curthread->td_intr_frame;
 
-	/* validate parameters */
-	if (isclr(&sc->msi_bitmap, irq)) {
-		device_printf(dev, "invalid MSI 0x%x\n", irq);
-		return (EINVAL);
+	for (i = 0; i < AFI_MSI_REGS; i++) {
+		reg = AFI_RD4(sc, AFI_MSI_VEC(i));
+		/* Handle one vector. */
+		while (reg != 0) {
+			bit = ffs(reg) - 1;
+			/* Send EOI */
+			AFI_WR4(sc, AFI_MSI_VEC(i), 1 << bit);
+			irq = i * AFI_MSI_INTR_IN_REG + bit;
+			tgi = &sc->isrcs[irq];
+			if (intr_isrc_dispatch(&tgi->isrc, tf) != 0) {
+				/* Disable stray. */
+				tegra_pcib_isrc_mask(sc, tgi, 0);
+				device_printf(sc->dev,
+				    "Stray irq %u disabled\n", irq);
+			}
+			reg = AFI_RD4(sc, AFI_MSI_VEC(i));
+		}
 	}
+	return (FILTER_HANDLED);
+}
+
+static int
+tegra_pcib_msi_attach(struct tegra_pcib_softc *sc)
+{
+	int error;
+	uint32_t irq;
+	const char *name;
+
+	sc->isrcs = malloc(sizeof(*sc->isrcs) * TEGRA_PCIB_MAX_MSI, M_DEVBUF,
+	    M_WAITOK | M_ZERO);
+
+	name = device_get_nameunit(sc->dev);
+	for (irq = 0; irq < TEGRA_PCIB_MAX_MSI; irq++) {
+		sc->isrcs[irq].irq = irq;
+		error = intr_isrc_register(&sc->isrcs[irq].isrc,
+		    sc->dev, 0, "%s,%u", name, irq);
+		if (error != 0)
+			return (error); /* XXX deregister ISRCs */
+	}
+	if (intr_msi_register(sc->dev,
+	    OF_xref_from_node(ofw_bus_get_node(sc->dev))) != 0)
+		return (ENXIO);
+
+	return (0);
+}
+
+static int
+tegra_pcib_msi_detach(struct tegra_pcib_softc *sc)
+{
+
+	/*
+	 *  There has not been established any procedure yet
+	 *  how to detach PIC from living system correctly.
+	 */
+	device_printf(sc->dev, "%s: not implemented yet\n", __func__);
+	return (EBUSY);
+}
+
+
+static void
+tegra_pcib_msi_disable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+	struct tegra_pcib_softc *sc;
+	struct tegra_pcib_irqsrc *tgi;
+
+	sc = device_get_softc(dev);
+	tgi = (struct tegra_pcib_irqsrc *)isrc;
+	tegra_pcib_isrc_mask(sc, tgi, 0);
+}
+
+static void
+tegra_pcib_msi_enable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+	struct tegra_pcib_softc *sc;
+	struct tegra_pcib_irqsrc *tgi;
 
-	tegra_msi_data(irq, addr, data);
+	sc = device_get_softc(dev);
+	tgi = (struct tegra_pcib_irqsrc *)isrc;
+	tegra_pcib_isrc_mask(sc, tgi, 1);
+}
 
-	debugf("%s: irq: %d addr: %jx data: %x\n",
-	    __func__, irq, *addr, *data);
+/* MSI interrupts are edge trigered -> do nothing */
+static void
+tegra_pcib_msi_post_filter(device_t dev, struct intr_irqsrc *isrc)
+{
+}
 
+static void
+tegra_pcib_msi_post_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+}
+
+static void
+tegra_pcib_msi_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+}
+
+static int
+tegra_pcib_msi_setup_intr(device_t dev, struct intr_irqsrc *isrc,
+    struct resource *res, struct intr_map_data *data)
+{
+	struct tegra_pcib_softc *sc;
+	struct tegra_pcib_irqsrc *tgi;
+
+	sc = device_get_softc(dev);
+	tgi = (struct tegra_pcib_irqsrc *)isrc;
+
+	if (data == NULL || data->type != INTR_MAP_DATA_MSI)
+		return (ENOTSUP);
+
+	if (isrc->isrc_handlers == 0)
+		tegra_pcib_msi_enable_intr(dev, isrc);
+
+	return (0);
+}
+
+static int
+tegra_pcib_msi_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
+    struct resource *res, struct intr_map_data *data)
+{
+	struct tegra_pcib_softc *sc;
+	struct tegra_pcib_irqsrc *tgi;
+
+	sc = device_get_softc(dev);
+	tgi = (struct tegra_pcib_irqsrc *)isrc;
+
+	if (isrc->isrc_handlers == 0)
+		tegra_pcib_isrc_mask(sc, tgi, 0);
 	return (0);
 }
 
+
 static int
-tegra_pcib_alloc_msi(device_t dev, device_t child, int count,
-    int maxcount __unused, int *irqs)
+tegra_pcib_msi_alloc_msi(device_t dev, device_t child, int count, int maxcount,
+    device_t *pic, struct intr_irqsrc **srcs)
 {
 	struct tegra_pcib_softc *sc;
-	u_int start = 0, i;
+	int i, irq, end_irq;
+	bool found;
 
-	if (powerof2(count) == 0 || count > MSI_IRQ_NUM)
-		return (EINVAL);
+	KASSERT(powerof2(count), ("%s: bad count", __func__));
+	KASSERT(powerof2(maxcount), ("%s: bad maxcount", __func__));
 
 	sc = device_get_softc(dev);
 	mtx_lock(&sc->mtx);
 
-	for (start = 0; (start + count) < MSI_IRQ_NUM; start++) {
-		for (i = start; i < start + count; i++) {
-			if (isset(&sc->msi_bitmap, i))
+	found = false;
+	for (irq = 0; irq < TEGRA_PCIB_MAX_MSI && !found; irq++) {
+		/* Start on an aligned interrupt */
+		if ((irq & (maxcount - 1)) != 0)
+			continue;
+
+		/* Assume we found a valid range until shown otherwise */
+		found = true;
+
+		/* Check this range is valid */
+		for (end_irq = irq; end_irq != irq + count - 1; end_irq++) {
+			/* No free interrupts */
+			if (end_irq == (TEGRA_PCIB_MAX_MSI - 1)) {
+				found = false;
 				break;
+			}
+
+			/* This is already used */
+			if ((sc->isrcs[irq].flags & TEGRA_FLAG_MSI_USED) ==
+			    TEGRA_FLAG_MSI_USED) {
+				found = false;
+				break;
+			}
 		}
-		if (i == start + count)
-			break;
 	}
 
-	if ((start + count) == MSI_IRQ_NUM) {
+	/* Not enough interrupts were found */
+	if (!found || irq == (TEGRA_PCIB_MAX_MSI - 1)) {
 		mtx_unlock(&sc->mtx);
 		return (ENXIO);
 	}
 
-	for (i = start; i < start + count; i++) {
-		setbit(&sc->msi_bitmap, i);
-		irqs[i] = MSI_IRQ + i;
-	}
-	debugf("%s: start: %x count: %x\n", __func__, start, count);
+	for (i = 0; i < count; i++) {
+		/* Mark the interrupt as used */
+		sc->isrcs[irq + i].flags |= TEGRA_FLAG_MSI_USED;
 
+	}
 	mtx_unlock(&sc->mtx);
+
+	for (i = 0; i < count; i++)
+		srcs[i] = (struct intr_irqsrc *)&sc->isrcs[irq + i];
+	*pic = device_get_parent(dev);
 	return (0);
 }
 
 static int
-tegra_pcib_release_msi(device_t dev, device_t child, int count, int *irqs)
+tegra_pcib_msi_release_msi(device_t dev, device_t child, int count,
+    struct intr_irqsrc **isrc)
 {
 	struct tegra_pcib_softc *sc;
-	u_int i;
+	struct tegra_pcib_irqsrc *ti;
+	int i;
 
 	sc = device_get_softc(dev);
 	mtx_lock(&sc->mtx);
+	for (i = 0; i < count; i++) {
+		ti = (struct tegra_pcib_irqsrc *)isrc;
 
-	for (i = 0; i < count; i++)
-		clrbit(&sc->msi_bitmap, irqs[i] - MSI_IRQ);
+		KASSERT((ti->flags & TEGRA_FLAG_MSI_USED) == TEGRA_FLAG_MSI_USED,
+		    ("%s: Trying to release an unused MSI-X interrupt",
+		    __func__));
 
-	mtx_unlock(&sc->mtx);
+		ti->flags &= ~TEGRA_FLAG_MSI_USED;
+		mtx_unlock(&sc->mtx);
+	}
+	return (0);
+}
+
+static int
+tegra_pcib_msi_map_msi(device_t dev, device_t child, struct intr_irqsrc *isrc,
+    uint64_t *addr, uint32_t *data)
+{
+	struct tegra_pcib_softc *sc = device_get_softc(dev);
+	struct tegra_pcib_irqsrc *ti = (struct tegra_pcib_irqsrc *)isrc;
+
+	*addr = vtophys(sc->msi_page);
+	*data = ti->irq;
 	return (0);
 }
 #endif
 
+/* ------------------------------------------------------------------- */
 static bus_size_t
 tegra_pcib_pex_ctrl(struct tegra_pcib_softc *sc, int port)
 {
@@ -948,7 +849,6 @@ tegra_pcib_enable_fdt_resources(struct t
 		    "Cannot enable 'avdd-pex-pll' regulator\n");
 		return (rv);
 	}
-
 	rv = regulator_enable(sc->supply_hvdd_pex);
 	if (rv != 0) {
 		device_printf(sc->dev,
@@ -992,13 +892,11 @@ tegra_pcib_enable_fdt_resources(struct t
 		device_printf(sc->dev, "Cannot enable 'afi' clock\n");
 		return (rv);
 	}
-
 	rv = clk_enable(sc->clk_cml);
 	if (rv != 0) {
 		device_printf(sc->dev, "Cannot enable 'cml' clock\n");
 		return (rv);
 	}
-
 	rv = clk_enable(sc->clk_pll_e);
 	if (rv != 0) {
 		device_printf(sc->dev, "Cannot enable 'pll_e' clock\n");
@@ -1193,12 +1091,13 @@ tegra_pcib_parse_fdt_resources(struct te
 
 static int
 tegra_pcib_decode_ranges(struct tegra_pcib_softc *sc,
-    struct tegra_pci_range *ranges, int nranges)
+    struct ofw_pci_range *ranges, int nranges)
 {
 	int i;
 
 	for (i = 2; i < nranges; i++) {
-		if (ranges[i].space_code == OFW_PCI_PHYS_HI_SPACE_IO) {
+		if ((ranges[i].pci_hi & OFW_PCI_PHYS_HI_SPACEMASK)  ==
+		    OFW_PCI_PHYS_HI_SPACE_IO) {
 			if (sc->io_range.size != 0) {
 				device_printf(sc->dev,
 				    "Duplicated IO range found in DT\n");
@@ -1206,23 +1105,25 @@ tegra_pcib_decode_ranges(struct tegra_pc
 			}
 			sc->io_range = ranges[i];
 		}
-		if ((ranges[i].space_code == OFW_PCI_PHYS_HI_SPACE_MEM32) &&
-		    !ranges[i].prefetchable) {
-			if (sc->mem_range.size != 0) {
-				device_printf(sc->dev,
-				    "Duplicated memory range found in DT\n");
-				return (ENXIO);
-			}
-			sc->mem_range = ranges[i];
-		}
-		if ((ranges[i].space_code == OFW_PCI_PHYS_HI_SPACE_MEM32) &&
-		    ranges[i].prefetchable) {
-			if (sc->pref_mem_range.size != 0) {
-				device_printf(sc->dev,
-				    "Duplicated memory range found in DT\n");
-				return (ENXIO);
+		if (((ranges[i].pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) ==
+		    OFW_PCI_PHYS_HI_SPACE_MEM32))  {
+			if (ranges[i].pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) {
+				if (sc->pref_mem_range.size != 0) {
+					device_printf(sc->dev,
+					    "Duplicated memory range found "
+					    "in DT\n");
+					return (ENXIO);
+				}
+				sc->pref_mem_range = ranges[i];
+			} else {
+				if (sc->mem_range.size != 0) {
+					device_printf(sc->dev,
+					    "Duplicated memory range found "
+					    "in DT\n");
+					return (ENXIO);
+				}
+				sc->mem_range = ranges[i];
 			}
-			sc->pref_mem_range = ranges[i];
 		}
 	}
 	if ((sc->io_range.size == 0) || (sc->mem_range.size == 0)
@@ -1457,16 +1358,16 @@ tegra_pcib_enable(struct tegra_pcib_soft
 	   FPCI_MAP_EXT_TYPE1_CONFIG, rman_get_size(sc->cfg_mem_res), 0);
 
 	/* BAR 1 - downstream I/O. */
-	tegra_pcib_set_bar(sc, 1, sc->io_range.host_addr, FPCI_MAP_IO,
+	tegra_pcib_set_bar(sc, 1, sc->io_range.host, FPCI_MAP_IO,
 	    sc->io_range.size, 0);
 
 	/* BAR 2 - downstream prefetchable memory 1:1. */
-	tegra_pcib_set_bar(sc, 2, sc->pref_mem_range.host_addr,
-	    sc->pref_mem_range.host_addr, sc->pref_mem_range.size, 1);
+	tegra_pcib_set_bar(sc, 2, sc->pref_mem_range.host,
+	    sc->pref_mem_range.host, sc->pref_mem_range.size, 1);
 
 	/* BAR 3 - downstream not prefetchable memory 1:1 .*/
-	tegra_pcib_set_bar(sc, 3, sc->mem_range.host_addr,
-	    sc->mem_range.host_addr, sc->mem_range.size, 1);
+	tegra_pcib_set_bar(sc, 3, sc->mem_range.host,
+	    sc->mem_range.host, sc->mem_range.size, 1);
 
 	/* BAR 3-8 clear. */
 	tegra_pcib_set_bar(sc, 4, 0, 0, 0, 0);
@@ -1480,6 +1381,52 @@ tegra_pcib_enable(struct tegra_pcib_soft
 	return(0);
 }
 
+#ifdef TEGRA_PCIB_MSI_ENABLE
+static int
+tegra_pcib_attach_msi(device_t dev)
+{
+	struct tegra_pcib_softc *sc;
+	uint32_t reg;
+	int i, rv;
+
+	sc = device_get_softc(dev);
+
+	sc->msi_page = kmem_alloc_contig(kernel_arena, PAGE_SIZE, M_WAITOK,
+	    0, BUS_SPACE_MAXADDR, PAGE_SIZE, 0, VM_MEMATTR_DEFAULT);
+
+	/* MSI BAR */
+	tegra_pcib_set_bar(sc, 9, vtophys(sc->msi_page), vtophys(sc->msi_page),
+	    PAGE_SIZE, 0);
+
+	/* Disble and clear all interrupts. */
+	for (i = 0; i < AFI_MSI_REGS; i++) {
+		AFI_WR4(sc, AFI_MSI_EN_VEC(i), 0);
+		AFI_WR4(sc, AFI_MSI_VEC(i), 0xFFFFFFFF);
+	}

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201611051048.uA5Amimd041637>