Page MenuHomeFreeBSD

D49452.id175859.diff
No OneTemporary

D49452.id175859.diff

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
@@ -235,11 +235,73 @@
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, C_HARDCLOCK);
+ 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)
{
- uint32_t val;
- int error = 0;
+ uint32_t val;
+ struct nhi_host_caps caps;
+ int error = 0;
if ((error = nhi_setup_sysctl(sc)) != 0)
return (error);
@@ -247,18 +309,32 @@
mtx_init(&sc->nhi_mtx, "nhimtx", "NHI Control Mutex", MTX_DEF);
/*
- * Get the number of TX/RX paths. This sizes some of the register
- * arrays during allocation and initialization. USB4 spec says that
- * the max is 21.
+ * Get the host interface version and number of TX/RX paths. This
+ * sizes some of the register arrays during allocation and
+ * initialization. USB4 spec says that the max is 21.
*/
- val = GET_HOST_CAPS_PATHS(nhi_read_reg(sc, NHI_HOST_CAPS));
- tb_debug(sc, DBG_INIT|DBG_NOISY, "Total Paths= %d\n", val);
- if (val == 0 || val > 21) {
+ val = nhi_read_reg(sc, NHI_HOST_CAPS);
+ caps = *(struct nhi_host_caps *)&val;
+ if (caps.version_major == 0 && caps.version_minor == 0) {
+ tb_printf(sc, "Host interface is version 1.0\n");
+ sc->ver = NHI_VER_1_0;
+ } else if (caps.version_major == 2 && caps.version_minor == 0) {
+ tb_printf(sc, "Host interface is version 2.0\n");
+ sc->ver = NHI_VER_2_0;
+ } else {
+ tb_printf(sc, "WARN: unexpected host interface version %d.%d -"
+ " assuming 1.0\n", caps.version_major, caps.version_minor);
+ sc->ver = NHI_VER_1_0;
+ }
+ tb_debug(sc, DBG_INIT|DBG_NOISY, "Total Paths= %d\n", caps.total_paths);
+ if (caps.total_paths == 0 || caps.total_paths > 21) {
tb_printf(sc, "WARN: unexpected number of paths: %d\n", val);
/* return (ENXIO); */
}
sc->path_count = val;
+ nhi_reset(sc);
+
SLIST_INIT(&sc->ring_list);
error = nhi_pci_configure_interrupts(sc);
diff --git a/sys/dev/thunderbolt/nhi_reg.h b/sys/dev/thunderbolt/nhi_reg.h
--- a/sys/dev/thunderbolt/nhi_reg.h
+++ b/sys/dev/thunderbolt/nhi_reg.h
@@ -54,6 +54,10 @@
#define DEVICE_PINK_SARDINE_0 0x1668
#define DEVICE_PINK_SARDINE_1 0x1669
+/* Timings */
+#define NHI_SLPR_WAIT_US 50000 /* 50 ms, tSetSR */
+#define NHI_SLPR_WAIT_MAX 100
+
/* * * MMIO Registers
* * Ring buffer registers
*
@@ -176,7 +180,15 @@
/* Native Host Interface Control registers */
#define NHI_HOST_CAPS 0x39640
-#define GET_HOST_CAPS_PATHS(val) ((val) & 0x3f)
+
+/* Host Interface Capabilities, 12.6.3.1.1 */
+struct nhi_host_caps {
+ uint32_t total_paths:11;
+ uint8_t reserved1:5;
+ uint8_t version_major:3;
+ uint8_t version_minor:5;
+ uint8_t reserved0:8;
+} __packed;
/*
* This definition comes from the Linux driver. In the USB4 spec, this
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
@@ -186,6 +186,11 @@
uint8_t uuid[16];
uint8_t lc_uuid[16];
+
+ enum {
+ NHI_VER_1_0,
+ NHI_VER_2_0,
+ } ver;
};
struct nhi_dispatch {
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
@@ -63,8 +63,12 @@
static int _tb_router_attach(struct router_softc *);
static void router_prepare_read(struct router_softc *, struct router_command *,
int);
+static void router_prepare_write(struct router_softc *, struct router_command *,
+ int);
static int _tb_config_read(struct router_softc *, u_int, u_int, u_int, u_int,
uint32_t *, void *, struct router_command **);
+static int _tb_config_write(struct router_softc *, u_int, u_int, u_int, u_int,
+ uint32_t *, void *, struct router_command **);
static int router_schedule(struct router_softc *, struct router_command *);
static int router_schedule_locked(struct router_softc *,
struct router_command *);
@@ -494,8 +498,66 @@
tb_config_write(struct router_softc *sc, u_int space, u_int adapter,
u_int offset, u_int dwlen, uint32_t *buf)
{
+ struct router_command *cmd;
+ int error, retries;
- return(0);
+ if ((error = _tb_config_write(sc, space, adapter, offset, dwlen, buf,
+ router_get_config_cb, &cmd)) != 0)
+ return (error);
+
+ retries = cmd->retries;
+ mtx_lock(&sc->mtx);
+ while (retries-- >= 0) {
+ error = router_schedule_locked(sc, cmd);
+ if (error)
+ break;
+
+ error = msleep(cmd, &sc->mtx, 0, "tbtcfg", cmd->timeout * hz);
+ if (error != EWOULDBLOCK)
+ break;
+ sc->inflight_cmd = NULL;
+ tb_debug(sc, DBG_ROUTER, "Config command timed out, "
+ "retries=%d\n", retries);
+ }
+
+ if (cmd->ev != 0)
+ error = EINVAL;
+ router_free_cmd(sc, cmd);
+ mtx_unlock(&sc->mtx);
+ return (error);
+}
+
+static int
+_tb_config_write(struct router_softc *sc, u_int space, u_int adapter,
+ u_int offset, u_int dwlen, uint32_t *buf, void *cb,
+ struct router_command **rcmd) /* TODO Check that all these args are being used. */
+{
+ struct router_command *cmd;
+ struct tb_cfg_write *msg;
+ size_t msglen = sizeof(*msg) + dwlen * 4;
+ int error;
+
+ if ((error = router_alloc_cmd(sc, &cmd)) != 0)
+ return (error);
+
+ msg = router_get_frame_data(cmd);
+ bzero(msg, msglen);
+ msg->route.hi = sc->route.hi;
+ msg->route.lo = sc->route.lo;
+ printf("%s: space= %d, adapter= %d, dwlen= %d, offset= %d\n",
+ __func__, space, adapter, dwlen, offset);
+ msg->addr_attrs = TB_CONFIG_ADDR(0, space, adapter, dwlen, offset);
+ for (size_t i = 0; i < dwlen; i++)
+ msg->data[i] = buf[i];
+ cmd->callback = cb;
+ cmd->callback_arg = buf;
+ cmd->dwlen = dwlen;
+ router_prepare_write(sc, cmd, msglen);
+
+ if (rcmd != NULL)
+ *rcmd = cmd;
+
+ return (0);
}
static int
@@ -580,6 +642,41 @@
return;
}
+static void
+router_prepare_write(struct router_softc *sc, struct router_command *cmd,
+ int len)
+{
+ struct nhi_cmd_frame *nhicmd;
+ uint32_t *msg;
+ int msglen, i;
+
+ KASSERT(cmd != NULL, ("cmd cannot be NULL\n"));
+ KASSERT(len != 0, ("Invalid zero-length command\n"));
+ KASSERT(len % 4 == 0, ("Message must be 32bit padded\n"));
+
+ nhicmd = cmd->nhicmd;
+ msglen = (len - 4) / 4;
+ for (i = 0; i < msglen; i++)
+ nhicmd->data[i] = htobe32(nhicmd->data[i]);
+
+ msg = (uint32_t *)nhicmd->data;
+ msg[msglen] = htobe32(tb_calc_crc(nhicmd->data, len-4));
+
+ nhicmd->pdf = PDF_WRITE;
+ nhicmd->req_len = len;
+
+ nhicmd->timeout = NHI_CMD_TIMEOUT;
+ nhicmd->retries = 0;
+ nhicmd->resp_buffer = (uint32_t *)cmd->resp_buffer;
+ nhicmd->resp_len = (cmd->dwlen + 3) * 4;
+ nhicmd->context = cmd;
+
+ cmd->retries = CFG_DEFAULT_RETRIES;
+ cmd->timeout = CFG_DEFAULT_TIMEOUT;
+
+ return;
+}
+
static int
router_schedule(struct router_softc *sc, struct router_command *cmd)
{
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
@@ -87,6 +87,17 @@
uint16_t vsec_len;
};
+/* Router config space registers */
+#define ROUTER_HRR 0x39898
+#define ROUTER_HIR 0x39858
+#define ROUTER_CS_5 5
+#define ROUTER_SLP (1<<0) /* Enter sleep (CS5). */
+#define ROUTER_WOP (1<<1) /* Wake on PCIe (CS5). */
+#define ROUTER_WOU (1<<2) /* Wake on USB3 (CS5). */
+#define ROUTER_WOD (1<<3) /* Wake on DP (CS5). */
+#define ROUTER_CS_6 6
+#define ROUTER_SLPR (1<<0) /* Sleep ready (CS6). */
+
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 *);
diff --git a/sys/dev/thunderbolt/tbcfg_reg.h b/sys/dev/thunderbolt/tbcfg_reg.h
--- a/sys/dev/thunderbolt/tbcfg_reg.h
+++ b/sys/dev/thunderbolt/tbcfg_reg.h
@@ -64,8 +64,8 @@
struct tb_cfg_write {
tb_route_t route;
uint32_t addr_attrs;
- uint32_t data[0]; /* Up to 60 dwords */
- /* uint32_t crc is at the end */
+ uint32_t data[0];
+ uint32_t crc;
} __packed;
/* Config space write response, 6.4.2.6 */

File Metadata

Mime Type
text/plain
Expires
Thu, Aug 13, 5:35 PM (38 m, 7 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
36671205
Default Alt Text
D49452.id175859.diff (9 KB)

Event Timeline