Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F157923609
D49453.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
4 KB
Referenced Files
None
Subscribers
None
D49453.diff
View Options
diff --git a/sys/dev/thunderbolt/nhi.c b/sys/dev/thunderbolt/nhi.c
--- a/sys/dev/thunderbolt/nhi.c
+++ b/sys/dev/thunderbolt/nhi.c
@@ -415,6 +415,20 @@
return (0);
}
+int
+nhi_suspend(struct nhi_softc *sc)
+{
+
+ return (tb_router_suspend(sc->root_rsc));
+}
+
+int
+nhi_resume(struct nhi_softc *sc)
+{
+
+ return (0);
+}
+
static void
nhi_memaddr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
{
diff --git a/sys/dev/thunderbolt/nhi_pci.c b/sys/dev/thunderbolt/nhi_pci.c
--- a/sys/dev/thunderbolt/nhi_pci.c
+++ b/sys/dev/thunderbolt/nhi_pci.c
@@ -242,15 +242,17 @@
static int
nhi_pci_suspend(device_t dev)
{
+ struct nhi_softc *sc = device_get_softc(dev);
- return (0);
+ return (nhi_suspend(sc));
}
static int
nhi_pci_resume(device_t dev)
{
+ struct nhi_softc *sc = device_get_softc(dev);
- return (0);
+ return (nhi_resume(sc));
}
static void
diff --git a/sys/dev/thunderbolt/nhi_var.h b/sys/dev/thunderbolt/nhi_var.h
--- a/sys/dev/thunderbolt/nhi_var.h
+++ b/sys/dev/thunderbolt/nhi_var.h
@@ -229,6 +229,8 @@
void nhi_get_tunables(struct nhi_softc *);
int nhi_attach(struct nhi_softc *);
int nhi_detach(struct nhi_softc *);
+int nhi_suspend(struct nhi_softc *);
+int nhi_resume(struct nhi_softc *);
struct nhi_cmd_frame * nhi_alloc_tx_frame(struct nhi_ring_pair *);
void nhi_free_tx_frame(struct nhi_ring_pair *, struct nhi_cmd_frame *);
diff --git a/sys/dev/thunderbolt/router.c b/sys/dev/thunderbolt/router.c
--- a/sys/dev/thunderbolt/router.c
+++ b/sys/dev/thunderbolt/router.c
@@ -255,6 +255,7 @@
sc->ring0 = nsc->ring0;
sc->route = route;
sc->nsc = nsc;
+ sc->suspended = false;
mtx_init(&sc->mtx, "tbcfg", "Thunderbolt Router Config", MTX_DEF);
TAILQ_INIT(&sc->cmd_queue);
@@ -346,6 +347,90 @@
return (0);
}
+int
+tb_router_suspend(struct router_softc *sc)
+{
+ int err;
+ uint32_t reg;
+
+ tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "%s called\n", __func__);
+ if (sc->suspended) {
+ tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "Already suspended\n");
+ return (0);
+ }
+
+ /*
+ * TODO Before we do anything, we've first got to make sure that the
+ * USB3 hub is in the U3 state, and the PCIe endpoint is in D3.
+ *
+ * Also check for "USB4 Port is Configured" to know if we support
+ * sleep state.
+ */
+
+ /* First, we've got to set ROUTER_CS_5.SLP (enter sleep). */
+ err = tb_config_router_read(sc, ROUTER_CS_5, 1, ®);
+ if (err != 0) {
+ tb_debug(sc, DBG_ROUTER, "Cannot read ROUTER_CS5\n");
+ return (err);
+ }
+ /*
+ * We want to set the enter sleep bit, as well as preventing wake
+ * events from:
+ * - Wake on PCIe (WoP).
+ * - Wake on USB3 (WoU).
+ * - Wake on DisplayPort (WoD).
+ */
+ reg |= ROUTER_SLP;
+ reg &= ~(ROUTER_WOP | ROUTER_WOU | ROUTER_WOD);
+ err = tb_config_router_write(sc, ROUTER_CS_5, 1, ®);
+ if (err != 0) {
+ tb_debug(sc, DBG_ROUTER, "Cannot write to ROUTER_CS5\n");
+ return (err);
+ }
+
+ /*
+ * The ROUTER_CS_6.SLPR (sleep ready) bit should be set tSetSR after
+ * we set the SLP bit. Poll for it to be set.
+ *
+ * TODO On a v2 router, we should wait for the ROP_CMPLT notification,
+ * but in the meantime just polling is also valid.
+ */
+ pause_sbt("tbrouter", ustosbt(NHI_SLPR_WAIT_US), 0, C_HARDCLOCK);
+ err = tb_config_router_read(sc, ROUTER_CS_6, 1, ®);
+ if (err != 0) {
+ tb_debug(sc, DBG_ROUTER, "Cannot read ROUTER_CS6\n");
+ return (err);
+ }
+ if ((reg & ROUTER_SLPR) != 0)
+ goto ready;
+ tb_printf(sc, "Sleep ready bit not set after 50 ms after "
+ "asking to enter sleep, waiting...\n");
+ for (size_t i = 0; i < NHI_SLPR_WAIT_MAX; i++) {
+ pause_sbt("tbrouter", ustosbt(NHI_SLPR_WAIT_US), 0,
+ C_HARDCLOCK);
+ err = tb_config_router_read(sc, ROUTER_CS_6, 1, ®);
+ if (err != 0) {
+ tb_debug(sc, DBG_ROUTER, "Cannot read ROUTER_CS6\n");
+ return (err);
+ }
+ if ((reg & ROUTER_SLPR) != 0)
+ goto ready;
+ }
+ tb_printf(sc, "Timed out waiting for the sleep ready bit to be"
+ "set\n");
+ return (ETIMEDOUT);
+
+ready:
+ tb_printf(sc, "Ready to enter sleep\n");
+ sc->suspended = true;
+ /*
+ * TODO We must tell the host router to send LT_LRoff on the sideband
+ * channel of each DFP. (I thought we weren't allowed to send anything
+ * on the sideband channel after setting the sleep entry bit?)
+ */
+ return (0);
+}
+
static void
router_get_config_cb(struct router_softc *sc, struct router_command *cmd,
void *arg)
diff --git a/sys/dev/thunderbolt/router_var.h b/sys/dev/thunderbolt/router_var.h
--- a/sys/dev/thunderbolt/router_var.h
+++ b/sys/dev/thunderbolt/router_var.h
@@ -61,6 +61,7 @@
tb_route_t route;
device_t dev;
struct nhi_softc *nsc;
+ bool suspended;
struct mtx mtx;
struct nhi_ring_pair *ring0;
@@ -101,6 +102,7 @@
int tb_router_attach(struct router_softc *, tb_route_t);
int tb_router_attach_root(struct nhi_softc *, tb_route_t);
int tb_router_detach(struct router_softc *);
+int tb_router_suspend(struct router_softc *);
int tb_config_read(struct router_softc *, u_int, u_int, u_int, u_int,
uint32_t *);
int tb_config_read_polled(struct router_softc *, u_int, u_int, u_int, u_int,
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, May 27, 1:06 PM (20 h, 36 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33557293
Default Alt Text
D49453.diff (4 KB)
Attached To
Mode
D49453: USB4 initial work on suspend routine
Attached
Detach File
Event Timeline
Log In to Comment