Skip to content

Commit cd0c1e5

Browse files
Gil Finewesteri
authored andcommitted
thunderbolt: Add missing UNSET_INBOUND_SBTX for retimer access
According to USB4 retimer specification, the process of firmware update sequence requires issuing a SET_INBOUND_SBTX port operation that later shall be followed by UNSET_INBOUND_SBTX port operation. This last step is not currently issued by the driver but it is necessary to make sure the retimers are put back to passthrough mode even during enumeration. If this step is missing the link may not come up properly after soft-reboot for example. For this reason issue UNSET_INBOUND_SBTX after SET_INBOUND_SBTX for enumeration and also when the NVM upgrade is run. Reported-by: Christian Schaubschläger <[email protected]> Link: https://lore.kernel.org/linux-usb/[email protected]/ Cc: [email protected] Signed-off-by: Gil Fine <[email protected]> Signed-off-by: Mika Westerberg <[email protected]>
1 parent acec726 commit cd0c1e5

File tree

4 files changed

+37
-2
lines changed

4 files changed

+37
-2
lines changed

drivers/thunderbolt/retimer.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,22 @@ static ssize_t nvm_authenticate_show(struct device *dev,
187187
return ret;
188188
}
189189

190+
static void tb_retimer_set_inbound_sbtx(struct tb_port *port)
191+
{
192+
int i;
193+
194+
for (i = 1; i <= TB_MAX_RETIMER_INDEX; i++)
195+
usb4_port_retimer_set_inbound_sbtx(port, i);
196+
}
197+
198+
static void tb_retimer_unset_inbound_sbtx(struct tb_port *port)
199+
{
200+
int i;
201+
202+
for (i = TB_MAX_RETIMER_INDEX; i >= 1; i--)
203+
usb4_port_retimer_unset_inbound_sbtx(port, i);
204+
}
205+
190206
static ssize_t nvm_authenticate_store(struct device *dev,
191207
struct device_attribute *attr, const char *buf, size_t count)
192208
{
@@ -213,6 +229,7 @@ static ssize_t nvm_authenticate_store(struct device *dev,
213229
rt->auth_status = 0;
214230

215231
if (val) {
232+
tb_retimer_set_inbound_sbtx(rt->port);
216233
if (val == AUTHENTICATE_ONLY) {
217234
ret = tb_retimer_nvm_authenticate(rt, true);
218235
} else {
@@ -232,6 +249,7 @@ static ssize_t nvm_authenticate_store(struct device *dev,
232249
}
233250

234251
exit_unlock:
252+
tb_retimer_unset_inbound_sbtx(rt->port);
235253
mutex_unlock(&rt->tb->lock);
236254
exit_rpm:
237255
pm_runtime_mark_last_busy(&rt->dev);
@@ -440,8 +458,7 @@ int tb_retimer_scan(struct tb_port *port, bool add)
440458
* Enable sideband channel for each retimer. We can do this
441459
* regardless whether there is device connected or not.
442460
*/
443-
for (i = 1; i <= TB_MAX_RETIMER_INDEX; i++)
444-
usb4_port_retimer_set_inbound_sbtx(port, i);
461+
tb_retimer_set_inbound_sbtx(port);
445462

446463
/*
447464
* Before doing anything else, read the authentication status.
@@ -464,6 +481,8 @@ int tb_retimer_scan(struct tb_port *port, bool add)
464481
break;
465482
}
466483

484+
tb_retimer_unset_inbound_sbtx(port);
485+
467486
if (!last_idx)
468487
return 0;
469488

drivers/thunderbolt/sb_regs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ enum usb4_sb_opcode {
2020
USB4_SB_OPCODE_ROUTER_OFFLINE = 0x4e45534c, /* "LSEN" */
2121
USB4_SB_OPCODE_ENUMERATE_RETIMERS = 0x4d554e45, /* "ENUM" */
2222
USB4_SB_OPCODE_SET_INBOUND_SBTX = 0x5055534c, /* "LSUP" */
23+
USB4_SB_OPCODE_UNSET_INBOUND_SBTX = 0x50555355, /* "USUP" */
2324
USB4_SB_OPCODE_QUERY_LAST_RETIMER = 0x5453414c, /* "LAST" */
2425
USB4_SB_OPCODE_GET_NVM_SECTOR_SIZE = 0x53534e47, /* "GNSS" */
2526
USB4_SB_OPCODE_NVM_SET_OFFSET = 0x53504f42, /* "BOPS" */

drivers/thunderbolt/tb.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1242,6 +1242,7 @@ int usb4_port_sw_margin(struct tb_port *port, unsigned int lanes, bool timing,
12421242
int usb4_port_sw_margin_errors(struct tb_port *port, u32 *errors);
12431243

12441244
int usb4_port_retimer_set_inbound_sbtx(struct tb_port *port, u8 index);
1245+
int usb4_port_retimer_unset_inbound_sbtx(struct tb_port *port, u8 index);
12451246
int usb4_port_retimer_read(struct tb_port *port, u8 index, u8 reg, void *buf,
12461247
u8 size);
12471248
int usb4_port_retimer_write(struct tb_port *port, u8 index, u8 reg,

drivers/thunderbolt/usb4.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1578,6 +1578,20 @@ int usb4_port_retimer_set_inbound_sbtx(struct tb_port *port, u8 index)
15781578
500);
15791579
}
15801580

1581+
/**
1582+
* usb4_port_retimer_unset_inbound_sbtx() - Disable sideband channel transactions
1583+
* @port: USB4 port
1584+
* @index: Retimer index
1585+
*
1586+
* Disables sideband channel transations on SBTX. The reverse of
1587+
* usb4_port_retimer_set_inbound_sbtx().
1588+
*/
1589+
int usb4_port_retimer_unset_inbound_sbtx(struct tb_port *port, u8 index)
1590+
{
1591+
return usb4_port_retimer_op(port, index,
1592+
USB4_SB_OPCODE_UNSET_INBOUND_SBTX, 500);
1593+
}
1594+
15811595
/**
15821596
* usb4_port_retimer_read() - Read from retimer sideband registers
15831597
* @port: USB4 port

0 commit comments

Comments
 (0)