Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F162982324
D49452.id154524.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D49452.id154524.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
@@ -261,11 +261,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);
@@ -275,18 +337,34 @@
nhi_configure_caps(sc);
/*
- * 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. Alpine Ridge appears to default to 12.
+ * 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. Alpine Ridge
+ * appears to default to 12.
*/
- 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) || ((NHI_IS_AR(sc) && val != 12))) {
+ 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) ||
+ ((NHI_IS_AR(sc) && caps.total_paths != 12))) {
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
@@ -256,7 +268,7 @@
#define ICL_VSCAP22_FORCEPWR (1 << 1)
/* * Data structures
- * Transmit buffer descriptor. Must be aligned on a 4byte boundary
+ * Transmit buffer descriptor, 12.3.1. Must be aligned on a 4byte boundary
*/
struct nhi_tx_buffer_desc {
uint32_t addr_lo;
@@ -275,7 +287,7 @@
} __packed;
/*
- * Receive buffer descriptor. 4 byte aligned. This goes into
+ * Receive buffer descriptor, 12.4.1. 4 byte aligned. This goes into
* the descriptor ring, but changes into the _post form when the
* controller uses it.
*/
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
@@ -201,6 +201,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
@@ -66,8 +66,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 *);
@@ -499,8 +503,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
@@ -585,6 +647,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 *);
@@ -121,7 +132,7 @@
}
/*
- * Read the Router config space for the router refered to in the softc.
+ * Read the Router config space for the router referred to in the softc.
* addr - The dword offset in the config space
* dwlen - The number of dwords
* buf - must be large enough to hold the number of dwords requested.
@@ -141,7 +152,7 @@
}
/*
- * Write the Router config space for the router refered to in the softc.
+ * Write the Router config space for the router referred to in the softc.
* addr - The dword offset in the config space
* dwlen - The number of dwords
* buf - must be large enough to hold the number of dwords requested.
@@ -154,7 +165,7 @@
}
/*
- * Read the Adapter config space for the router refered to in the softc.
+ * Read the Adapter config space for the router referred to in the softc.
* adap - Adapter number
* addr - The dword offset in the config space
* dwlen - The number of dwords
@@ -168,7 +179,7 @@
}
/*
- * Read the Adapter config space for the router refered to in the softc.
+ * Read the Adapter config space for the router referred to in the softc.
* adap - Adapter number
* addr - The dword offset in the config space
* dwlen - The number of dwords
@@ -182,7 +193,7 @@
}
/*
- * Read the Path config space for the router refered to in the softc.
+ * Read the Path config space for the router referred to in the softc.
* adap - Adapter number
* hopid - HopID of the path
* len - The number of adjacent paths
@@ -197,7 +208,7 @@
}
/*
- * Write the Path config space for the router refered to in the softc.
+ * Write the Path config space for the router referred to in the softc.
* adap - Adapter number
* hopid - HopID of the path
* len - The number of adjacent paths
@@ -212,7 +223,7 @@
}
/*
- * Read the Counters config space for the router refered to in the softc.
+ * Read the Counters config space for the router referred to in the softc.
* Counters come in sets of 3 dwords.
* adap - Adapter number
* set - The counter set index
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
Details
Attached
Mime Type
text/plain
Expires
Sun, Jul 19, 10:06 PM (6 h, 19 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35252072
Default Alt Text
D49452.id154524.diff (11 KB)
Attached To
Mode
D49452: USB4 host reset (& writing to router config space)
Attached
Detach File
Event Timeline
Log In to Comment