Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 7 Sep 2021 12:09:42 GMT
From:      Jessica Clarke <jrtc27@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 15a5871387ca - stable/13 - pci_dw: Support modern "unroll" iATU mode
Message-ID:  <202109071209.187C9g8s087251@gitrepo.freebsd.org>

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

URL: https://cgit.FreeBSD.org/src/commit/?id=15a5871387caeaba7303c47a899b984ac49d4a90

commit 15a5871387caeaba7303c47a899b984ac49d4a90
Author:     Jessica Clarke <jrtc27@FreeBSD.org>
AuthorDate: 2021-07-21 04:50:50 +0000
Commit:     Jessica Clarke <jrtc27@FreeBSD.org>
CommitDate: 2021-09-07 12:06:48 +0000

    pci_dw: Support modern "unroll" iATU mode
    
    This supersedes the old legacy mode where a viewport register was used
    to mux multiple regions behind a single set of registers, and is used on
    the SiFive FU740.
    
    Reviewed by:    mmel
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D31029
    
    (cherry picked from commit f240dfff229d1f1ff502f59901ef2b9364ca55d9)
---
 sys/dev/pci/pci_dw.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 sys/dev/pci/pci_dw.h | 18 ++++++++++
 2 files changed, 114 insertions(+), 3 deletions(-)

diff --git a/sys/dev/pci/pci_dw.c b/sys/dev/pci/pci_dw.c
index e4211a70a80b..525c5fcf9cd5 100644
--- a/sys/dev/pci/pci_dw.c
+++ b/sys/dev/pci/pci_dw.c
@@ -73,6 +73,11 @@ __FBSDID("$FreeBSD$");
 #define	DBI_RD2(sc, reg)	pci_dw_dbi_rd2((sc)->dev, reg)
 #define	DBI_RD4(sc, reg)	pci_dw_dbi_rd4((sc)->dev, reg)
 
+#define	IATU_UR_WR4(sc, reg, val)	\
+    bus_write_4((sc)->iatu_ur_res, (sc)->iatu_ur_offset + (reg), (val))
+#define	IATU_UR_RD4(sc, reg)		\
+    bus_read_4((sc)->iatu_ur_res, (sc)->iatu_ur_offset + (reg))
+
 #define	PCI_BUS_SHIFT		20
 #define	PCI_SLOT_SHIFT		15
 #define	PCI_FUNC_SHIFT		12
@@ -168,9 +173,52 @@ pci_dw_check_dev(struct pci_dw_softc *sc, u_int bus, u_int slot, u_int func,
 	return (true);
 }
 
-/* Map one uoutbound ATU region */
+static bool
+pci_dw_detect_atu_unroll(struct pci_dw_softc *sc)
+{
+	return (DBI_RD4(sc, DW_IATU_VIEWPORT) == 0xFFFFFFFFU);
+}
+
 static int
-pci_dw_map_out_atu(struct pci_dw_softc *sc, int idx, int type,
+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)
+{
+	uint32_t reg;
+	int i;
+
+	if (size == 0)
+		return (0);
+
+	IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, LWR_BASE_ADDR),
+	    pa & 0xFFFFFFFF);
+	IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, UPPER_BASE_ADDR),
+	    (pa >> 32) & 0xFFFFFFFF);
+	IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, LIMIT_ADDR),
+	    (pa + size - 1) & 0xFFFFFFFF);
+	IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, LWR_TARGET_ADDR),
+	    pci_addr & 0xFFFFFFFF);
+	IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, UPPER_TARGET_ADDR),
+	    (pci_addr  >> 32) & 0xFFFFFFFF);
+	IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, CTRL1),
+	    IATU_CTRL1_TYPE(type));
+	IATU_UR_WR4(sc, DW_IATU_UR_REG(idx, CTRL2),
+	    IATU_CTRL2_REGION_EN);
+
+	/* Wait until setup becomes valid */
+	for (i = 10; i > 0; i--) {
+		reg = IATU_UR_RD4(sc, DW_IATU_UR_REG(idx, CTRL2));
+		if (reg & IATU_CTRL2_REGION_EN)
+			return (0);
+		DELAY(5);
+	}
+
+	device_printf(sc->dev,
+	    "Cannot map outbound region %d in unroll mode iATU\n", idx);
+	return (ETIMEDOUT);
+}
+
+static int
+pci_dw_map_out_atu_legacy(struct pci_dw_softc *sc, int idx, int type,
     uint64_t pa, uint64_t pci_addr, uint32_t size)
 {
 	uint32_t reg;
@@ -195,11 +243,25 @@ pci_dw_map_out_atu(struct pci_dw_softc *sc, int idx, int type,
 			return (0);
 		DELAY(5);
 	}
+
 	device_printf(sc->dev,
-	    "Cannot map outbound region(%d) in iATU\n", idx);
+	    "Cannot map outbound region %d in legacy mode iATU\n", idx);
 	return (ETIMEDOUT);
 }
 
+/* Map one outbound ATU region */
+static int
+pci_dw_map_out_atu(struct pci_dw_softc *sc, int idx, int type,
+    uint64_t pa, uint64_t pci_addr, uint32_t size)
+{
+	if (sc->iatu_ur_res)
+		return (pci_dw_map_out_atu_unroll(sc, idx, type, pa,
+		    pci_addr, size));
+	else
+		return (pci_dw_map_out_atu_legacy(sc, idx, type, pa,
+		    pci_addr, size));
+}
+
 static int
 pci_dw_setup_hw(struct pci_dw_softc *sc)
 {
@@ -580,6 +642,7 @@ pci_dw_init(device_t dev)
 {
 	struct pci_dw_softc *sc;
 	int rv, rid;
+	bool unroll_mode;
 
 	sc = device_get_softc(dev);
 	sc->dev = dev;
@@ -660,6 +723,36 @@ pci_dw_init(device_t dev)
 	if (rv != 0)
 		goto out;
 
+	unroll_mode = pci_dw_detect_atu_unroll(sc);
+	if (bootverbose)
+		device_printf(dev, "Using iATU %s mode\n",
+		    unroll_mode ? "unroll" : "legacy");
+	if (unroll_mode) {
+		rid = 0;
+		rv = ofw_bus_find_string_index(sc->node, "reg-names", "atu", &rid);
+		if (rv == 0) {
+			sc->iatu_ur_res = bus_alloc_resource_any(dev,
+			    SYS_RES_MEMORY, &rid, RF_ACTIVE);
+			if (sc->iatu_ur_res == NULL) {
+				device_printf(dev,
+				    "Cannot allocate iATU space (rid: %d)\n",
+				    rid);
+				rv = ENXIO;
+				goto out;
+			}
+			sc->iatu_ur_offset = 0;
+			sc->iatu_ur_size = rman_get_size(sc->iatu_ur_res);
+		} else if (rv == ENOENT) {
+			sc->iatu_ur_res = sc->dbi_res;
+			sc->iatu_ur_offset = DW_DEFAULT_IATU_UR_DBI_OFFSET;
+			sc->iatu_ur_size = DW_DEFAULT_IATU_UR_DBI_SIZE;
+		} else {
+			device_printf(dev, "Cannot get iATU space memory\n");
+			rv = ENXIO;
+			goto out;
+		}
+	}
+
 	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 c2c9249449bb..51c4169f74d2 100644
--- a/sys/dev/pci/pci_dw.h
+++ b/sys/dev/pci/pci_dw.h
@@ -63,6 +63,7 @@
 #define	DW_MISC_CONTROL_1		0x8BC
 #define	 DBI_RO_WR_EN				(1 << 0)
 
+/* Legacy (pre-4.80) iATU mode */
 #define	DW_IATU_VIEWPORT			0x900
 #define	 IATU_REGION_INBOUND			(1U << 31)
 #define	 IATU_REGION_INDEX(x)			((x) & 0x7)
@@ -80,6 +81,20 @@
 #define	DW_IATU_LWR_TARGET_ADDR		0x918
 #define	DW_IATU_UPPER_TARGET_ADDR	0x91C
 
+/* Modern (4.80+) "unroll" iATU mode */
+#define	DW_IATU_UR_STEP			0x200
+#define	DW_IATU_UR_REG(r, n)		(r) * DW_IATU_UR_STEP + IATU_UR_##n
+#define	 IATU_UR_CTRL1				0x00
+#define	 IATU_UR_CTRL2				0x04
+#define	 IATU_UR_LWR_BASE_ADDR			0x08
+#define	 IATU_UR_UPPER_BASE_ADDR		0x0C
+#define	 IATU_UR_LIMIT_ADDR			0x10
+#define	 IATU_UR_LWR_TARGET_ADDR		0x14
+#define	 IATU_UR_UPPER_TARGET_ADDR		0x18
+
+#define	DW_DEFAULT_IATU_UR_DBI_OFFSET	0x300000
+#define	DW_DEFAULT_IATU_UR_DBI_SIZE	0x1000
+
 struct pci_dw_softc {
 	struct ofw_pci_softc	ofw_pci;	/* Must be first */
 
@@ -101,6 +116,9 @@ struct pci_dw_softc {
 
 	int			num_lanes;
 	int			num_viewport;
+	struct resource		*iatu_ur_res;	/* NB: May be dbi_res */
+	bus_addr_t		iatu_ur_offset;
+	bus_size_t		iatu_ur_size;
 	bus_addr_t		cfg_pa;   	/* PA of config memoty */
 	bus_size_t		cfg_size; 	/* size of config  region */
 



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