Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 21 Jul 2021 04:51:54 GMT
From:      Jessica Clarke <jrtc27@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 4707bb0430e6 - main - pci_dw: Detect number of outbound regions automatically
Message-ID:  <202107210451.16L4psri065957@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by jrtc27:

URL: https://cgit.FreeBSD.org/src/commit/?id=4707bb0430e6ca3935ef8196e30830b3cdaf3514

commit 4707bb0430e6ca3935ef8196e30830b3cdaf3514
Author:     Jessica Clarke <jrtc27@FreeBSD.org>
AuthorDate: 2021-07-21 04:51:20 +0000
Commit:     Jessica Clarke <jrtc27@FreeBSD.org>
CommitDate: 2021-07-21 04:51:20 +0000

    pci_dw: Detect number of outbound regions automatically
    
    Currently we use the num-viewports property to decide how many outbound
    regions there are we can use, defaulting to 2. However, Linux has
    stopped using that and so it no longer appears in new device trees, such
    as for the SiFive FU740. Instead, it's possible to just probe the
    hardware directly.
    
    Reviewed by:    mmel
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D31030
---
 sys/dev/pci/pci_dw.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++------
 sys/dev/pci/pci_dw.h |  2 +-
 2 files changed, 78 insertions(+), 10 deletions(-)

diff --git a/sys/dev/pci/pci_dw.c b/sys/dev/pci/pci_dw.c
index 90f992e83fce..9eb7b04dfd28 100644
--- a/sys/dev/pci/pci_dw.c
+++ b/sys/dev/pci/pci_dw.c
@@ -179,6 +179,71 @@ pci_dw_detect_atu_unroll(struct pci_dw_softc *sc)
 	return (DBI_RD4(sc, DW_IATU_VIEWPORT) == 0xFFFFFFFFU);
 }
 
+static int
+pci_dw_detect_out_atu_regions_unroll(struct pci_dw_softc *sc)
+{
+	int num_regions, i;
+	uint32_t reg;
+
+	num_regions = sc->iatu_ur_size / DW_IATU_UR_STEP;
+
+	for (i = 0; i < num_regions; ++i) {
+		IATU_UR_WR4(sc, DW_IATU_UR_REG(i, LWR_TARGET_ADDR),
+		    0x12340000);
+		reg = IATU_UR_RD4(sc, DW_IATU_UR_REG(i, LWR_TARGET_ADDR));
+		if (reg != 0x12340000)
+			break;
+	}
+
+	sc->num_out_regions = i;
+
+	return (0);
+}
+
+static int
+pci_dw_detect_out_atu_regions_legacy(struct pci_dw_softc *sc)
+{
+	int num_viewports, i;
+	uint32_t reg;
+
+	/* Find out how many viewports there are in total */
+	DBI_WR4(sc, DW_IATU_VIEWPORT, IATU_REGION_INDEX(~0U));
+	reg = DBI_RD4(sc, DW_IATU_VIEWPORT);
+	if (reg > IATU_REGION_INDEX(~0U)) {
+		device_printf(sc->dev,
+		    "Cannot detect number of output iATU regions; read %#x\n",
+		    reg);
+		return (ENXIO);
+	}
+
+	num_viewports = reg + 1;
+
+	/*
+	 * Find out how many of them are outbound by seeing whether a dummy
+	 * page-aligned address sticks.
+	 */
+	for (i = 0; i < num_viewports; ++i) {
+		DBI_WR4(sc, DW_IATU_VIEWPORT, IATU_REGION_INDEX(i));
+		DBI_WR4(sc, DW_IATU_LWR_TARGET_ADDR, 0x12340000);
+		reg = DBI_RD4(sc, DW_IATU_LWR_TARGET_ADDR);
+		if (reg != 0x12340000)
+			break;
+	}
+
+	sc->num_out_regions = i;
+
+	return (0);
+}
+
+static int
+pci_dw_detect_out_atu_regions(struct pci_dw_softc *sc)
+{
+	if (sc->iatu_ur_res)
+		return (pci_dw_detect_out_atu_regions_unroll(sc));
+	else
+		return (pci_dw_detect_out_atu_regions_legacy(sc));
+}
+
 static int
 pci_dw_map_out_atu_unroll(struct pci_dw_softc *sc, int idx, int type,
     uint64_t pa, uint64_t pci_addr, uint32_t size)
@@ -285,7 +350,7 @@ pci_dw_setup_hw(struct pci_dw_softc *sc)
 	pci_dw_dbi_protect(sc, true);
 
 	/* Setup outbound memory windows */
-	for (i = 0; i < min(sc->num_mem_ranges, sc->num_viewport - 1); ++i) {
+	for (i = 0; i < min(sc->num_mem_ranges, sc->num_out_regions - 1); ++i) {
 		rv = pci_dw_map_out_atu(sc, i + 1, IATU_CTRL1_TYPE_MEM,
 		    sc->mem_ranges[i].host, sc->mem_ranges[i].pci,
 		    sc->mem_ranges[i].size);
@@ -293,8 +358,8 @@ pci_dw_setup_hw(struct pci_dw_softc *sc)
 			return (rv);
 	}
 
-	/* If we have enough viewports ..*/
-	if (sc->num_mem_ranges + 1 < sc->num_viewport &&
+	/* If we have enough regions ... */
+	if (sc->num_mem_ranges + 1 < sc->num_out_regions &&
 	    sc->io_range.size != 0) {
 		/* Setup outbound I/O window */
 		rv = pci_dw_map_out_atu(sc, sc->num_mem_ranges + 1,
@@ -660,13 +725,8 @@ pci_dw_init(device_t dev)
 	if (!sc->coherent)
 		sc->coherent = OF_hasprop(sc->node, "dma-coherent");
 
-	rv = OF_getencprop(sc->node, "num-viewport", &sc->num_viewport,
-	    sizeof(sc->num_viewport));
-	if (rv != sizeof(sc->num_viewport))
-		sc->num_viewport = 2;
-
 	rv = OF_getencprop(sc->node, "num-lanes", &sc->num_lanes,
-	    sizeof(sc->num_viewport));
+	    sizeof(sc->num_lanes));
 	if (rv != sizeof(sc->num_lanes))
 		sc->num_lanes = 1;
 	if (sc->num_lanes != 1 && sc->num_lanes != 2 &&
@@ -753,6 +813,14 @@ pci_dw_init(device_t dev)
 		}
 	}
 
+	rv = pci_dw_detect_out_atu_regions(sc);
+	if (rv != 0)
+		goto out;
+
+	if (bootverbose)
+		device_printf(sc->dev, "Detected outbound iATU regions: %d\n",
+		    sc->num_out_regions);
+
 	rv = pci_dw_setup_hw(sc);
 	if (rv != 0)
 		goto out;
diff --git a/sys/dev/pci/pci_dw.h b/sys/dev/pci/pci_dw.h
index 51c4169f74d2..6f2248344f44 100644
--- a/sys/dev/pci/pci_dw.h
+++ b/sys/dev/pci/pci_dw.h
@@ -115,7 +115,7 @@ struct pci_dw_softc {
 	bus_dma_tag_t		dmat;
 
 	int			num_lanes;
-	int			num_viewport;
+	int			num_out_regions;
 	struct resource		*iatu_ur_res;	/* NB: May be dbi_res */
 	bus_addr_t		iatu_ur_offset;
 	bus_size_t		iatu_ur_size;



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