[PATCH 09/13][SRU][U/OEM-5.10] UBUNTU: SAUCE: thunderbolt: Add connection manager specific hooks for USB4 router operations
You-Sheng Yang
vicamo.yang at canonical.com
Thu Dec 3 08:18:48 UTC 2020
From: Mika Westerberg <mika.westerberg at linux.intel.com>
BugLink: https://bugs.launchpad.net/bugs/1906236
Intel USB4 host routers that run the firmware based connection manager
(ICM) may implement a proxy for USB4 router operations. This is to avoid
the firmware to race with the OS driver, as both may need to run these
operations.
This adds two new connection manager specific callbacks which, if
provided, get called instead of the native USB4 router operation.
Signed-off-by: Mika Westerberg <mika.westerberg at linux.intel.com>
(cherry picked from commit 9490f71167feba55349e33854f5e51a1a3af9e8c
git://git.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt.git)
Signed-off-by: You-Sheng Yang <vicamo.yang at canonical.com>
---
drivers/thunderbolt/tb.h | 13 ++++++++++
drivers/thunderbolt/usb4.c | 50 +++++++++++++++++++++++++++++++++-----
2 files changed, 57 insertions(+), 6 deletions(-)
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
index 3301ef9c62c5..0a88218cb2a4 100644
--- a/drivers/thunderbolt/tb.h
+++ b/drivers/thunderbolt/tb.h
@@ -367,6 +367,14 @@ struct tb_path {
* @disconnect_pcie_paths: Disconnects PCIe paths before NVM update
* @approve_xdomain_paths: Approve (establish) XDomain DMA paths
* @disconnect_xdomain_paths: Disconnect XDomain DMA paths
+ * @usb4_switch_op: Optional proxy for USB4 router operations. If set
+ * this will be called whenever USB4 router operation is
+ * performed. If this returns %-EOPNOTSUPP then the
+ * native USB4 router operation is called.
+ * @usb4_switch_nvm_authenticate_status: Optional callback that the CM
+ * implementation can be used to
+ * return status of USB4 NVM_AUTH
+ * router operation.
*/
struct tb_cm_ops {
int (*driver_ready)(struct tb *tb);
@@ -393,6 +401,11 @@ struct tb_cm_ops {
int (*disconnect_pcie_paths)(struct tb *tb);
int (*approve_xdomain_paths)(struct tb *tb, struct tb_xdomain *xd);
int (*disconnect_xdomain_paths)(struct tb *tb, struct tb_xdomain *xd);
+ int (*usb4_switch_op)(struct tb_switch *sw, u16 opcode, u32 *metadata,
+ u8 *status, const void *tx_data, size_t tx_data_len,
+ void *rx_data, size_t rx_data_len);
+ int (*usb4_switch_nvm_authenticate_status)(struct tb_switch *sw,
+ u32 *status);
};
static inline void *tb_priv(struct tb *tb)
diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c
index 4c8f2ffb4662..384f236aa40e 100644
--- a/drivers/thunderbolt/usb4.c
+++ b/drivers/thunderbolt/usb4.c
@@ -143,16 +143,14 @@ static int usb4_do_write_data(unsigned int address, const void *buf, size_t size
return 0;
}
-static int __usb4_switch_op(struct tb_switch *sw, u16 opcode, u32 *metadata,
- u8 *status, const void *tx_data, size_t tx_dwords,
- void *rx_data, size_t rx_dwords)
+static int usb4_native_switch_op(struct tb_switch *sw, u16 opcode,
+ u32 *metadata, u8 *status,
+ const void *tx_data, size_t tx_dwords,
+ void *rx_data, size_t rx_dwords)
{
u32 val;
int ret;
- if (tx_dwords > USB4_DATA_DWORDS || rx_dwords > USB4_DATA_DWORDS)
- return -EINVAL;
-
if (metadata) {
ret = tb_sw_write(sw, metadata, TB_CFG_SWITCH, ROUTER_CS_25, 1);
if (ret)
@@ -200,6 +198,39 @@ static int __usb4_switch_op(struct tb_switch *sw, u16 opcode, u32 *metadata,
return 0;
}
+static int __usb4_switch_op(struct tb_switch *sw, u16 opcode, u32 *metadata,
+ u8 *status, const void *tx_data, size_t tx_dwords,
+ void *rx_data, size_t rx_dwords)
+{
+ const struct tb_cm_ops *cm_ops = sw->tb->cm_ops;
+
+ if (tx_dwords > USB4_DATA_DWORDS || rx_dwords > USB4_DATA_DWORDS)
+ return -EINVAL;
+
+ /*
+ * If the connection manager implementation provides USB4 router
+ * operation proxy callback, call it here instead of running the
+ * operation natively.
+ */
+ if (cm_ops->usb4_switch_op) {
+ int ret;
+
+ ret = cm_ops->usb4_switch_op(sw, opcode, metadata, status,
+ tx_data, tx_dwords, rx_data,
+ rx_dwords);
+ if (ret != -EOPNOTSUPP)
+ return ret;
+
+ /*
+ * If the proxy was not supported then run the native
+ * router operation instead.
+ */
+ }
+
+ return usb4_native_switch_op(sw, opcode, metadata, status, tx_data,
+ tx_dwords, rx_data, rx_dwords);
+}
+
static inline int usb4_switch_op(struct tb_switch *sw, u16 opcode,
u32 *metadata, u8 *status)
{
@@ -678,10 +709,17 @@ int usb4_switch_nvm_authenticate(struct tb_switch *sw)
*/
int usb4_switch_nvm_authenticate_status(struct tb_switch *sw, u32 *status)
{
+ const struct tb_cm_ops *cm_ops = sw->tb->cm_ops;
u16 opcode;
u32 val;
int ret;
+ if (cm_ops->usb4_switch_nvm_authenticate_status) {
+ ret = cm_ops->usb4_switch_nvm_authenticate_status(sw, status);
+ if (ret != -EOPNOTSUPP)
+ return ret;
+ }
+
ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, ROUTER_CS_26, 1);
if (ret)
return ret;
--
2.29.2
More information about the kernel-team
mailing list