Page MenuHomeFreeBSD

D49452.id154524.diff
No OneTemporary

D49452.id154524.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
@@ -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

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)

Event Timeline