diff options
| author | Aymeric Wibo <obiwac@FreeBSD.org> | 2026-08-12 17:40:56 +0000 |
|---|---|---|
| committer | Aymeric Wibo <obiwac@FreeBSD.org> | 2026-08-12 21:53:13 +0000 |
| commit | efdb82413963bea5f4bf2ae52006cceeb6944a3b (patch) | |
| tree | 327397654ad53eabd1bf20fe72f213f7665c2254 | |
| parent | 529177b332dc4ba29d261ab7d2eec796d274b345 (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.c | 63 | ||||
| -rw-r--r-- | sys/dev/thunderbolt/router_var.h | 4 |
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 *); |
