Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/arm/rockchip rk3399_pci: support for PCI express sw...



details:   https://anonhg.NetBSD.org/src/rev/b48ffdc2802a
branches:  trunk
changeset: 940609:b48ffdc2802a
user:      tnn <tnn%NetBSD.org@localhost>
date:      Sun Oct 11 15:33:18 2020 +0000

description:
rk3399_pci: support for PCI express switches / bridges / multiple buses

There were two isses that prevented this from working:

1. We must use type 1 configuration cycles when accessing bus 2 and
beyond, but type 0 configuration cycles for bus 0 and 1.

2. The hardware address decoder cannot be used to decode the bus portion
of the ECAM address. Due to the physical SoC address of the remote device
region not having sufficient alignment the wrong bus address would go out
on the wire. Also the mapped region is too small to address busses
beyond bus31.

Fix: Reduce the number of ECAM translated bits to dev+func only.
For each configuration space access, acquire an exclusive lock
and reprogram the translator with the correct bus number and access type.
Config space is accessed sufficiently infrequent for this to not cause
any performance problems.

diffstat:

 sys/arch/arm/rockchip/rk3399_pcie.c |  105 +++++++++++++++++++++++------------
 1 files changed, 69 insertions(+), 36 deletions(-)

diffs (165 lines):

diff -r 1bca83c0c3c7 -r b48ffdc2802a sys/arch/arm/rockchip/rk3399_pcie.c
--- a/sys/arch/arm/rockchip/rk3399_pcie.c       Sun Oct 11 14:54:08 2020 +0000
+++ b/sys/arch/arm/rockchip/rk3399_pcie.c       Sun Oct 11 15:33:18 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: rk3399_pcie.c,v 1.11 2020/10/08 22:14:00 tnn Exp $ */
+/* $NetBSD: rk3399_pcie.c,v 1.12 2020/10/11 15:33:18 tnn Exp $ */
 /*
  * Copyright (c) 2018 Mark Kettenis <kettenis%openbsd.org@localhost>
  *
@@ -17,7 +17,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(1, "$NetBSD: rk3399_pcie.c,v 1.11 2020/10/08 22:14:00 tnn Exp $");
+__KERNEL_RCSID(1, "$NetBSD: rk3399_pcie.c,v 1.12 2020/10/11 15:33:18 tnn Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -134,6 +134,7 @@
        bus_addr_t              sc_apb_addr;
        bus_size_t              sc_axi_size;
        bus_size_t              sc_apb_size;
+       kmutex_t                sc_conf_lock;
 };
 
 static int rkpcie_match(device_t, cfdata_t, void *);
@@ -405,6 +406,8 @@
        sc->sc_phsc.sc_pc.pc_conf_read = rkpcie_conf_read;
        sc->sc_phsc.sc_pc.pc_conf_write = rkpcie_conf_write;
        sc->sc_phsc.sc_pc.pc_conf_hook = rkpcie_conf_hook;
+
+       mutex_init(&sc->sc_conf_lock, MUTEX_DEFAULT, IPL_HIGH);
        pcihost_init2(&sc->sc_phsc);
 }
 
@@ -419,7 +422,7 @@
        int region, i, ranges_len;
 
        /* Use region 0 to map PCI configuration space */
-       HWRITE4(sc, PCIE_ATR_OB_ADDR0(0), 25 - 1);
+       HWRITE4(sc, PCIE_ATR_OB_ADDR0(0), 20 - 1);
        HWRITE4(sc, PCIE_ATR_OB_ADDR1(0), 0);
        HWRITE4(sc, PCIE_ATR_OB_DESC0(0), PCIE_ATR_HDR_CFG_TYPE0 | PCIE_ATR_HDR_RID);
        HWRITE4(sc, PCIE_ATR_OB_DESC1(0), 0);
@@ -517,8 +520,13 @@
 
 /* Only one device on root port and the first subordinate port. */
 static bool
-rkpcie_conf_ok(int bus, int dev, int fn, int bus_min)
+rkpcie_conf_ok(int bus, int dev, int fn, int offset, struct rkpcie_softc *sc)
 {
+       int bus_min = sc->sc_phsc.sc_bus_min;
+
+       if ((unsigned int)offset >= (1<<12))
+               return false;
+       /* first two buses use type 0 cfg which doesn't use bus/device numbers */
        if (dev != 0 && (bus == bus_min || bus == bus_min + 1))
                return false;
        return true;
@@ -528,7 +536,45 @@
 rkpcie_conf_read(void *v, pcitag_t tag, int offset)
 {
        struct rkpcie_softc *sc = v;
-       struct pcihost_softc *phsc = &sc->sc_phsc;
+       int bus_min = sc->sc_phsc.sc_bus_min;
+       int bus, dev, fn;
+       u_int reg;
+       int32_t val;
+
+       KASSERT(offset >= 0);
+       KASSERT(offset < PCI_EXTCONF_SIZE);
+
+       rkpcie_decompose_tag(sc, tag, &bus, &dev, &fn);
+       if (!rkpcie_conf_ok(bus, dev, fn, offset, sc))
+               return 0xffffffff;
+       reg = (dev << 15) | (fn << 12) | offset;
+
+       if (bus == bus_min)
+               val = HREAD4(sc, PCIE_RC_NORMAL_BASE + reg);
+       else {
+               mutex_spin_enter(&sc->sc_conf_lock);
+               HWRITE4(sc, PCIE_ATR_OB_ADDR0(0),
+                   (bus << 20) | (20 - 1));
+               HWRITE4(sc, PCIE_ATR_OB_DESC0(0),
+                   PCIE_ATR_HDR_RID | ((bus == bus_min + 1)
+                   ? PCIE_ATR_HDR_CFG_TYPE0 : PCIE_ATR_HDR_CFG_TYPE1));
+               bus_space_barrier(sc->sc_iot, sc->sc_ioh, 0, sc->sc_apb_size,
+                     BUS_SPACE_BARRIER_READ);
+               if (AXIPEEK4(sc, reg, &val) != 0)
+                       val = 0xffffffff;
+               bus_space_barrier(sc->sc_iot, sc->sc_axi_ioh,
+                   0, sc->sc_axi_size,
+                   BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+               mutex_spin_exit(&sc->sc_conf_lock);
+       }
+       return val;
+}
+
+void
+rkpcie_conf_write(void *v, pcitag_t tag, int offset, pcireg_t data)
+{
+       struct rkpcie_softc *sc = v;
+       int bus_min = sc->sc_phsc.sc_bus_min;
        int bus, dev, fn;
        u_int reg;
 
@@ -536,40 +582,27 @@
        KASSERT(offset < PCI_EXTCONF_SIZE);
 
        rkpcie_decompose_tag(sc, tag, &bus, &dev, &fn);
-       if (!rkpcie_conf_ok(bus, dev, fn, phsc->sc_bus_min))
-               return 0xffffffff;
-       reg = (bus << 20) | (dev << 15) | (fn << 12) | offset;
-
-       if (bus == phsc->sc_bus_min)
-               return HREAD4(sc, PCIE_RC_NORMAL_BASE + reg);
-       else {
-               uint32_t val;
-               if (AXIPEEK4(sc, reg, &val) != 0)
-                       return 0xffffffff;
-               return val;
-       }
-}
+       if (!rkpcie_conf_ok(bus, dev, fn, offset, sc))
+               return;
+       reg = (dev << 15) | (fn << 12) | offset;
 
-void
-rkpcie_conf_write(void *v, pcitag_t tag, int offset, pcireg_t data)
-{
-       struct rkpcie_softc *sc = v;
-       struct pcihost_softc *phsc = &sc->sc_phsc;
-       int bus, dev, fn;
-       u_int reg;
-
-       KASSERT(offset >= 0);
-       KASSERT(offset < PCI_EXTCONF_SIZE);
-
-       rkpcie_decompose_tag(sc, tag, &bus, &dev, &fn);
-       if (!rkpcie_conf_ok(bus, dev, fn, phsc->sc_bus_min))
-               return;
-       reg = (bus << 20) | (dev << 15) | (fn << 12) | offset;
-
-       if (bus == phsc->sc_bus_min)
+       if (bus == bus_min)
                HWRITE4(sc, PCIE_RC_NORMAL_BASE + reg, data);
-       else
+       else {
+               mutex_spin_enter(&sc->sc_conf_lock);
+               HWRITE4(sc, PCIE_ATR_OB_ADDR0(0),
+                   (bus << 20) | (20 - 1));
+               HWRITE4(sc, PCIE_ATR_OB_DESC0(0),
+                   PCIE_ATR_HDR_RID | ((bus == bus_min + 1)
+                   ? PCIE_ATR_HDR_CFG_TYPE0 : PCIE_ATR_HDR_CFG_TYPE1));
+               bus_space_barrier(sc->sc_iot, sc->sc_ioh, 0, sc->sc_apb_size,
+                   BUS_SPACE_BARRIER_WRITE);
                AXIPOKE4(sc, reg, data);
+               bus_space_barrier(sc->sc_iot, sc->sc_axi_ioh,
+                   0, sc->sc_axi_size,
+                   BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+               mutex_spin_exit(&sc->sc_conf_lock);
+       }
 }
 
 static int



Home | Main Index | Thread Index | Old Index