]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - queue-6.6/thunderbolt-introduce-tb_port_reset.patch
6.6-stable patches
[thirdparty/kernel/stable-queue.git] / queue-6.6 / thunderbolt-introduce-tb_port_reset.patch
CommitLineData
7b79d708
GKH
1From 01da6b99d49f60b1edead44e33569b1a2e9f49b7 Mon Sep 17 00:00:00 2001
2From: Sanath S <Sanath.S@amd.com>
3Date: Sat, 13 Jan 2024 11:39:57 +0200
4Subject: thunderbolt: Introduce tb_port_reset()
5
6From: Sanath S <Sanath.S@amd.com>
7
8commit 01da6b99d49f60b1edead44e33569b1a2e9f49b7 upstream.
9
10Introduce a function that issues Downstream Port Reset to a USB4 port.
11This supports Thunderbolt 2, 3 and USB4 routers.
12
13Signed-off-by: Sanath S <Sanath.S@amd.com>
14Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
15Cc: Mario Limonciello <mario.limonciello@amd.com>
16Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
17---
18 drivers/thunderbolt/lc.c | 45 ++++++++++++++++++++++++++++++++++++++++++
19 drivers/thunderbolt/switch.c | 7 ++++++
20 drivers/thunderbolt/tb.h | 2 +
21 drivers/thunderbolt/tb_regs.h | 4 +++
22 drivers/thunderbolt/usb4.c | 39 ++++++++++++++++++++++++++++++++++++
23 5 files changed, 97 insertions(+)
24
25--- a/drivers/thunderbolt/lc.c
26+++ b/drivers/thunderbolt/lc.c
27@@ -6,6 +6,8 @@
28 * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
29 */
30
31+#include <linux/delay.h>
32+
33 #include "tb.h"
34
35 /**
36@@ -45,6 +47,49 @@ static int find_port_lc_cap(struct tb_po
37 return sw->cap_lc + start + phys * size;
38 }
39
40+/**
41+ * tb_lc_reset_port() - Trigger downstream port reset through LC
42+ * @port: Port that is reset
43+ *
44+ * Triggers downstream port reset through link controller registers.
45+ * Returns %0 in case of success negative errno otherwise. Only supports
46+ * non-USB4 routers with link controller (that's Thunderbolt 2 and
47+ * Thunderbolt 3).
48+ */
49+int tb_lc_reset_port(struct tb_port *port)
50+{
51+ struct tb_switch *sw = port->sw;
52+ int cap, ret;
53+ u32 mode;
54+
55+ if (sw->generation < 2)
56+ return -EINVAL;
57+
58+ cap = find_port_lc_cap(port);
59+ if (cap < 0)
60+ return cap;
61+
62+ ret = tb_sw_read(sw, &mode, TB_CFG_SWITCH, cap + TB_LC_PORT_MODE, 1);
63+ if (ret)
64+ return ret;
65+
66+ mode |= TB_LC_PORT_MODE_DPR;
67+
68+ ret = tb_sw_write(sw, &mode, TB_CFG_SWITCH, cap + TB_LC_PORT_MODE, 1);
69+ if (ret)
70+ return ret;
71+
72+ fsleep(10000);
73+
74+ ret = tb_sw_read(sw, &mode, TB_CFG_SWITCH, cap + TB_LC_PORT_MODE, 1);
75+ if (ret)
76+ return ret;
77+
78+ mode &= ~TB_LC_PORT_MODE_DPR;
79+
80+ return tb_sw_write(sw, &mode, TB_CFG_SWITCH, cap + TB_LC_PORT_MODE, 1);
81+}
82+
83 static int tb_lc_set_port_configured(struct tb_port *port, bool configured)
84 {
85 bool upstream = tb_is_upstream_port(port);
86--- a/drivers/thunderbolt/switch.c
87+++ b/drivers/thunderbolt/switch.c
88@@ -675,6 +675,13 @@ int tb_port_disable(struct tb_port *port
89 return __tb_port_enable(port, false);
90 }
91
92+static int tb_port_reset(struct tb_port *port)
93+{
94+ if (tb_switch_is_usb4(port->sw))
95+ return port->cap_usb4 ? usb4_port_reset(port) : 0;
96+ return tb_lc_reset_port(port);
97+}
98+
99 /*
100 * tb_init_port() - initialize a port
101 *
102--- a/drivers/thunderbolt/tb.h
103+++ b/drivers/thunderbolt/tb.h
104@@ -1119,6 +1119,7 @@ int tb_drom_read(struct tb_switch *sw);
105 int tb_drom_read_uid_only(struct tb_switch *sw, u64 *uid);
106
107 int tb_lc_read_uuid(struct tb_switch *sw, u32 *uuid);
108+int tb_lc_reset_port(struct tb_port *port);
109 int tb_lc_configure_port(struct tb_port *port);
110 void tb_lc_unconfigure_port(struct tb_port *port);
111 int tb_lc_configure_xdomain(struct tb_port *port);
112@@ -1251,6 +1252,7 @@ void usb4_switch_remove_ports(struct tb_
113
114 int usb4_port_unlock(struct tb_port *port);
115 int usb4_port_hotplug_enable(struct tb_port *port);
116+int usb4_port_reset(struct tb_port *port);
117 int usb4_port_configure(struct tb_port *port);
118 void usb4_port_unconfigure(struct tb_port *port);
119 int usb4_port_configure_xdomain(struct tb_port *port, struct tb_xdomain *xd);
120--- a/drivers/thunderbolt/tb_regs.h
121+++ b/drivers/thunderbolt/tb_regs.h
122@@ -383,6 +383,7 @@ struct tb_regs_port_header {
123 #define PORT_CS_18_WODS BIT(17)
124 #define PORT_CS_18_WOU4S BIT(18)
125 #define PORT_CS_19 0x13
126+#define PORT_CS_19_DPR BIT(0)
127 #define PORT_CS_19_PC BIT(3)
128 #define PORT_CS_19_PID BIT(4)
129 #define PORT_CS_19_WOC BIT(16)
130@@ -579,6 +580,9 @@ struct tb_regs_hop {
131 #define TB_LC_POWER 0x740
132
133 /* Link controller registers */
134+#define TB_LC_PORT_MODE 0x26
135+#define TB_LC_PORT_MODE_DPR BIT(0)
136+
137 #define TB_LC_CS_42 0x2a
138 #define TB_LC_CS_42_USB_PLUGGED BIT(31)
139
140--- a/drivers/thunderbolt/usb4.c
141+++ b/drivers/thunderbolt/usb4.c
142@@ -1113,6 +1113,45 @@ int usb4_port_hotplug_enable(struct tb_p
143 return tb_port_write(port, &val, TB_CFG_PORT, ADP_CS_5, 1);
144 }
145
146+/**
147+ * usb4_port_reset() - Issue downstream port reset
148+ * @port: USB4 port to reset
149+ *
150+ * Issues downstream port reset to @port.
151+ */
152+int usb4_port_reset(struct tb_port *port)
153+{
154+ int ret;
155+ u32 val;
156+
157+ if (!port->cap_usb4)
158+ return -EINVAL;
159+
160+ ret = tb_port_read(port, &val, TB_CFG_PORT,
161+ port->cap_usb4 + PORT_CS_19, 1);
162+ if (ret)
163+ return ret;
164+
165+ val |= PORT_CS_19_DPR;
166+
167+ ret = tb_port_write(port, &val, TB_CFG_PORT,
168+ port->cap_usb4 + PORT_CS_19, 1);
169+ if (ret)
170+ return ret;
171+
172+ fsleep(10000);
173+
174+ ret = tb_port_read(port, &val, TB_CFG_PORT,
175+ port->cap_usb4 + PORT_CS_19, 1);
176+ if (ret)
177+ return ret;
178+
179+ val &= ~PORT_CS_19_DPR;
180+
181+ return tb_port_write(port, &val, TB_CFG_PORT,
182+ port->cap_usb4 + PORT_CS_19, 1);
183+}
184+
185 static int usb4_port_set_configured(struct tb_port *port, bool configured)
186 {
187 int ret;