git: efdb82413963 - main - thunderbolt: Reset controllers
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 12 Aug 2026 21:53:29 UTC
The branch main has been updated by obiwac:
URL: https://cgit.FreeBSD.org/src/commit/?id=efdb82413963bea5f4bf2ae52006cceeb6944a3b
commit efdb82413963bea5f4bf2ae52006cceeb6944a3b
Author: Aymeric Wibo <obiwac@FreeBSD.org>
AuthorDate: 2026-08-12 17:40:56 +0000
Commit: Aymeric Wibo <obiwac@FreeBSD.org>
CommitDate: 2026-08-12 21:53:13 +0000
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
---
sys/dev/thunderbolt/nhi.c | 63 ++++++++++++++++++++++++++++++++++++++++
sys/dev/thunderbolt/router_var.h | 4 +++
2 files changed, 67 insertions(+)
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 *);