Page MenuHomeFreeBSD

D31029.diff
No OneTemporary

D31029.diff

diff --git a/sys/dev/pci/pci_dw.h b/sys/dev/pci/pci_dw.h
--- 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 @@
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 */
diff --git a/sys/dev/pci/pci_dw.c b/sys/dev/pci/pci_dw.c
--- a/sys/dev/pci/pci_dw.c
+++ b/sys/dev/pci/pci_dw.c
@@ -73,6 +73,11 @@
#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 @@
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 @@
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 @@
{
struct pci_dw_softc *sc;
int rv, rid;
+ bool unroll_mode;
sc = device_get_softc(dev);
sc->dev = dev;
@@ -660,6 +723,36 @@
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;

File Metadata

Mime Type
text/plain
Expires
Sun, Apr 27, 12:53 PM (17 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17817831
Default Alt Text
D31029.diff (5 KB)

Event Timeline