aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAymeric Wibo <obiwac@FreeBSD.org>2026-08-12 17:40:56 +0000
committerAymeric Wibo <obiwac@FreeBSD.org>2026-08-12 21:53:13 +0000
commitefdb82413963bea5f4bf2ae52006cceeb6944a3b (patch)
tree327397654ad53eabd1bf20fe72f213f7665c2254
parent529177b332dc4ba29d261ab7d2eec796d274b345 (diff)
thunderbolt: Reset controllers
Reset routine for both v1.0 and v2.0 routes, chosen depending on version reported in caps. Reviewed by: imp Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D49452
-rw-r--r--sys/dev/thunderbolt/nhi.c63
-rw-r--r--sys/dev/thunderbolt/router_var.h4
2 files changed, 67 insertions, 0 deletions
diff --git a/sys/dev/thunderbolt/nhi.c b/sys/dev/thunderbolt/nhi.c
index 4b45560923c3..75eb4fe6a5d9 100644
--- a/sys/dev/thunderbolt/nhi.c
+++ b/sys/dev/thunderbolt/nhi.c
@@ -235,6 +235,67 @@ nhi_outmail_cmd(struct nhi_softc *sc, uint32_t *val)
return (0);
}
+static int
+nhi_reset_v1(struct nhi_softc *sc)
+{
+
+ /* See section 2.4 of HCM guide v2. */
+ nhi_write_reg(sc, ROUTER_HIR, 1);
+ pause_sbt("nhi", ustosbt(10 * 1000), 0, C_HARDCLOCK);
+ return (0);
+}
+
+static int
+nhi_reset_v2(struct nhi_softc *sc)
+{
+ uint32_t reg;
+
+ /*
+ * TODO "The Connection Manager shall disable all Transmit Descriptor
+ * Rings and wait for at least 1 millisecond prior to setting the Host
+ * Router Reset bit to 1b. After the Connection Manager sets the Host
+ * Router Reset bit to 1b, it shall not access the Receive Descriptor
+ * Rings until the Host Router Reset bit is set to 0b."
+ */
+ /* See section 3.5 of HCM guide v2. */
+ nhi_write_reg(sc, ROUTER_HRR, 1);
+ /*
+ * "The Host Router is required to complete its reset within 500ms
+ * after the Host Router Reset bit is set to 1b."
+ */
+ for (size_t i = 0; i < 10 && reg; i++) {
+ /*
+ * Wait at least 50 ms after writing before reading this
+ * register. If this is 1, it means that we are still
+ * resetting.
+ */
+ pause_sbt("nhi", ustosbt(50 * 1000), 0, 0);
+ reg = nhi_read_reg(sc, ROUTER_HRR);
+ }
+ if (reg == 0) {
+ tb_debug(sc, DBG_INIT|DBG_EXTRA,
+ "Succeeded in resetting host router\n");
+ return (0);
+ }
+ tb_printf(sc, "Host router reset timed out\n");
+ return (ETIMEDOUT);
+}
+
+static int
+nhi_reset(struct nhi_softc *sc)
+{
+
+ tb_debug(sc, DBG_INIT, "Resetting host router\n");
+
+ switch (sc->ver) {
+ case NHI_VER_1_0:
+ return (nhi_reset_v1(sc));
+ case NHI_VER_2_0:
+ return (nhi_reset_v2(sc));
+ }
+ return (ENXIO);
+}
+
int
nhi_attach(struct nhi_softc *sc)
{
@@ -272,6 +333,8 @@ nhi_attach(struct nhi_softc *sc)
}
sc->path_count = val;
+ nhi_reset(sc);
+
SLIST_INIT(&sc->ring_list);
error = nhi_pci_configure_interrupts(sc);
diff --git a/sys/dev/thunderbolt/router_var.h b/sys/dev/thunderbolt/router_var.h
index 8366ede852e7..06c41e636121 100644
--- a/sys/dev/thunderbolt/router_var.h
+++ b/sys/dev/thunderbolt/router_var.h
@@ -87,6 +87,10 @@ struct router_cfg_cap {
uint16_t vsec_len;
};
+/* Router reset registers */
+#define ROUTER_HRR 0x39898
+#define ROUTER_HIR 0x39858
+
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 *);