thunderbolt: Fixes for v6.6-rc3

This includes following fixes for v6.6-rc3:
 
   - Add a workaround for IOMMU faults for certain systems with Intel
     Maple Ridge
   - Make sure lane 1 is in CL0 before bonding lanes
   - Correct TMU mode initialization from hardware
   - Restart XDomain discovery handshake after failure.
 
 All these have been in linux-next with no reported issues.
 -----BEGIN PGP SIGNATURE-----
 
 iQJUBAABCgA+FiEEVTdhRGBbNzLrSUBaAP2fSd+ZWKAFAmUJM+ggHG1pa2Eud2Vz
 dGVyYmVyZ0BsaW51eC5pbnRlbC5jb20ACgkQAP2fSd+ZWKDX2BAAmusck45ea8dB
 rd1GYV5nzzYfc3k6QHvS2U7PMTyZntzZ9RqsU+0LxQg7s3bByr2wVmZLwxghxjZf
 UteMg96xlV9sdJZG09/dADNBLvrTRRoT6zGnt25wJPAlYJie8Kka/F6AEmQQB2jm
 IlX9j2C4kSXxxW+0p4h4ZCL4md0oUwSyn42owx1t8Xg8KyFe+xBNcW4E8mn8AF4P
 +8i/r3fTSBTyI8UIZYanVRggBCsw0AM1HSSjRtczV1W+XpHMNyyTu9qPfN30SWm4
 1JjWZobjeKdVHdUMKlYrAn1wjP/WZBqwAQ4AWGTXEhCao0suT23mlZKwM7yEY8xh
 npYRv3o+Ns7aFVhDyzulEkkvrfFKNbnhik6Ru6FlPqbR3HTh3PQj4l6eYu3F9d6a
 TgOXNATy7//6Kcr+1Vk5Bp1iMq0SUrJKCjRCEg0HTAMM9+pRuhhg2s+Ld/hKDEB5
 Rt+1byyMZH6Qm3MquY/nNN7E6dzOdXzIF0+T0WC6ASm04Lw1pGqi9xb++ClDDqhm
 Hl3sMiR0MHj4BBCHW6wSYfuqEnJycmqXmC5nDVzpmdiJhPMAfJ9Ju6fwaWaNM05K
 nQmfscFPJ2m4dcEHFlhiiVnelE7BRbE6+AJpHGtuN7zBEyaEsDcrWTNK7fQbKqdP
 M/HLO2yqcx/0NMgm+bGyFGZUOwP42ic=
 =I/5N
 -----END PGP SIGNATURE-----

Merge tag 'thunderbolt-for-v6.6-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt into usb-linus

Mika writes:

thunderbolt: Fixes for v6.6-rc3

This includes following fixes for v6.6-rc3:

  - Add a workaround for IOMMU faults for certain systems with Intel
    Maple Ridge
  - Make sure lane 1 is in CL0 before bonding lanes
  - Correct TMU mode initialization from hardware
  - Restart XDomain discovery handshake after failure.

All these have been in linux-next with no reported issues.

* tag 'thunderbolt-for-v6.6-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt:
  thunderbolt: Restart XDomain discovery handshake after failure
  thunderbolt: Correct TMU mode initialization from hardware
  thunderbolt: Check that lane 1 is in CL0 before enabling lane bonding
  thunderbolt: Workaround an IOMMU fault on certain systems with Intel Maple Ridge
This commit is contained in:
Greg Kroah-Hartman 2023-10-02 13:16:11 +02:00
commit 57e50f4bad
4 changed files with 69 additions and 38 deletions

View File

@ -41,6 +41,7 @@
#define PHY_PORT_CS1_LINK_STATE_SHIFT 26
#define ICM_TIMEOUT 5000 /* ms */
#define ICM_RETRIES 3
#define ICM_APPROVE_TIMEOUT 10000 /* ms */
#define ICM_MAX_LINK 4
@ -296,10 +297,9 @@ static bool icm_copy(struct tb_cfg_request *req, const struct ctl_pkg *pkg)
static int icm_request(struct tb *tb, const void *request, size_t request_size,
void *response, size_t response_size, size_t npackets,
unsigned int timeout_msec)
int retries, unsigned int timeout_msec)
{
struct icm *icm = tb_priv(tb);
int retries = 3;
do {
struct tb_cfg_request *req;
@ -410,7 +410,7 @@ static int icm_fr_get_route(struct tb *tb, u8 link, u8 depth, u64 *route)
return -ENOMEM;
ret = icm_request(tb, &request, sizeof(request), switches,
sizeof(*switches), npackets, ICM_TIMEOUT);
sizeof(*switches), npackets, ICM_RETRIES, ICM_TIMEOUT);
if (ret)
goto err_free;
@ -463,7 +463,7 @@ icm_fr_driver_ready(struct tb *tb, enum tb_security_level *security_level,
memset(&reply, 0, sizeof(reply));
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
1, ICM_TIMEOUT);
1, ICM_RETRIES, ICM_TIMEOUT);
if (ret)
return ret;
@ -488,7 +488,7 @@ static int icm_fr_approve_switch(struct tb *tb, struct tb_switch *sw)
memset(&reply, 0, sizeof(reply));
/* Use larger timeout as establishing tunnels can take some time */
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
1, ICM_APPROVE_TIMEOUT);
1, ICM_RETRIES, ICM_APPROVE_TIMEOUT);
if (ret)
return ret;
@ -515,7 +515,7 @@ static int icm_fr_add_switch_key(struct tb *tb, struct tb_switch *sw)
memset(&reply, 0, sizeof(reply));
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
1, ICM_TIMEOUT);
1, ICM_RETRIES, ICM_TIMEOUT);
if (ret)
return ret;
@ -543,7 +543,7 @@ static int icm_fr_challenge_switch_key(struct tb *tb, struct tb_switch *sw,
memset(&reply, 0, sizeof(reply));
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
1, ICM_TIMEOUT);
1, ICM_RETRIES, ICM_TIMEOUT);
if (ret)
return ret;
@ -577,7 +577,7 @@ static int icm_fr_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd,
memset(&reply, 0, sizeof(reply));
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
1, ICM_TIMEOUT);
1, ICM_RETRIES, ICM_TIMEOUT);
if (ret)
return ret;
@ -1020,7 +1020,7 @@ icm_tr_driver_ready(struct tb *tb, enum tb_security_level *security_level,
memset(&reply, 0, sizeof(reply));
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
1, 20000);
1, 10, 2000);
if (ret)
return ret;
@ -1053,7 +1053,7 @@ static int icm_tr_approve_switch(struct tb *tb, struct tb_switch *sw)
memset(&reply, 0, sizeof(reply));
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
1, ICM_APPROVE_TIMEOUT);
1, ICM_RETRIES, ICM_APPROVE_TIMEOUT);
if (ret)
return ret;
@ -1081,7 +1081,7 @@ static int icm_tr_add_switch_key(struct tb *tb, struct tb_switch *sw)
memset(&reply, 0, sizeof(reply));
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
1, ICM_TIMEOUT);
1, ICM_RETRIES, ICM_TIMEOUT);
if (ret)
return ret;
@ -1110,7 +1110,7 @@ static int icm_tr_challenge_switch_key(struct tb *tb, struct tb_switch *sw,
memset(&reply, 0, sizeof(reply));
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
1, ICM_TIMEOUT);
1, ICM_RETRIES, ICM_TIMEOUT);
if (ret)
return ret;
@ -1144,7 +1144,7 @@ static int icm_tr_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd,
memset(&reply, 0, sizeof(reply));
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
1, ICM_TIMEOUT);
1, ICM_RETRIES, ICM_TIMEOUT);
if (ret)
return ret;
@ -1170,7 +1170,7 @@ static int icm_tr_xdomain_tear_down(struct tb *tb, struct tb_xdomain *xd,
memset(&reply, 0, sizeof(reply));
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
1, ICM_TIMEOUT);
1, ICM_RETRIES, ICM_TIMEOUT);
if (ret)
return ret;
@ -1496,7 +1496,7 @@ icm_ar_driver_ready(struct tb *tb, enum tb_security_level *security_level,
memset(&reply, 0, sizeof(reply));
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
1, ICM_TIMEOUT);
1, ICM_RETRIES, ICM_TIMEOUT);
if (ret)
return ret;
@ -1522,7 +1522,7 @@ static int icm_ar_get_route(struct tb *tb, u8 link, u8 depth, u64 *route)
memset(&reply, 0, sizeof(reply));
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
1, ICM_TIMEOUT);
1, ICM_RETRIES, ICM_TIMEOUT);
if (ret)
return ret;
@ -1543,7 +1543,7 @@ static int icm_ar_get_boot_acl(struct tb *tb, uuid_t *uuids, size_t nuuids)
memset(&reply, 0, sizeof(reply));
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
1, ICM_TIMEOUT);
1, ICM_RETRIES, ICM_TIMEOUT);
if (ret)
return ret;
@ -1604,7 +1604,7 @@ static int icm_ar_set_boot_acl(struct tb *tb, const uuid_t *uuids,
memset(&reply, 0, sizeof(reply));
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
1, ICM_TIMEOUT);
1, ICM_RETRIES, ICM_TIMEOUT);
if (ret)
return ret;
@ -1626,7 +1626,7 @@ icm_icl_driver_ready(struct tb *tb, enum tb_security_level *security_level,
memset(&reply, 0, sizeof(reply));
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
1, 20000);
1, ICM_RETRIES, 20000);
if (ret)
return ret;
@ -2298,7 +2298,7 @@ static int icm_usb4_switch_op(struct tb_switch *sw, u16 opcode, u32 *metadata,
memset(&reply, 0, sizeof(reply));
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
1, ICM_TIMEOUT);
1, ICM_RETRIES, ICM_TIMEOUT);
if (ret)
return ret;

View File

@ -2725,6 +2725,13 @@ int tb_switch_lane_bonding_enable(struct tb_switch *sw)
!tb_port_is_width_supported(down, TB_LINK_WIDTH_DUAL))
return 0;
/*
* Both lanes need to be in CL0. Here we assume lane 0 already be in
* CL0 and check just for lane 1.
*/
if (tb_wait_for_port(down->dual_link_port, false) <= 0)
return -ENOTCONN;
ret = tb_port_lane_bonding_enable(up);
if (ret) {
tb_port_warn(up, "failed to enable lane bonding\n");

View File

@ -382,7 +382,7 @@ static int tmu_mode_init(struct tb_switch *sw)
} else if (ucap && tb_port_tmu_is_unidirectional(up)) {
if (tmu_rates[TB_SWITCH_TMU_MODE_LOWRES] == rate)
sw->tmu.mode = TB_SWITCH_TMU_MODE_LOWRES;
else if (tmu_rates[TB_SWITCH_TMU_MODE_LOWRES] == rate)
else if (tmu_rates[TB_SWITCH_TMU_MODE_HIFI_UNI] == rate)
sw->tmu.mode = TB_SWITCH_TMU_MODE_HIFI_UNI;
} else if (rate) {
sw->tmu.mode = TB_SWITCH_TMU_MODE_HIFI_BI;

View File

@ -703,6 +703,27 @@ static void update_property_block(struct tb_xdomain *xd)
mutex_unlock(&xdomain_lock);
}
static void start_handshake(struct tb_xdomain *xd)
{
xd->state = XDOMAIN_STATE_INIT;
queue_delayed_work(xd->tb->wq, &xd->state_work,
msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
}
/* Can be called from state_work */
static void __stop_handshake(struct tb_xdomain *xd)
{
cancel_delayed_work_sync(&xd->properties_changed_work);
xd->properties_changed_retries = 0;
xd->state_retries = 0;
}
static void stop_handshake(struct tb_xdomain *xd)
{
cancel_delayed_work_sync(&xd->state_work);
__stop_handshake(xd);
}
static void tb_xdp_handle_request(struct work_struct *work)
{
struct xdomain_request_work *xw = container_of(work, typeof(*xw), work);
@ -765,6 +786,15 @@ static void tb_xdp_handle_request(struct work_struct *work)
case UUID_REQUEST:
tb_dbg(tb, "%llx: received XDomain UUID request\n", route);
ret = tb_xdp_uuid_response(ctl, route, sequence, uuid);
/*
* If we've stopped the discovery with an error such as
* timing out, we will restart the handshake now that we
* received UUID request from the remote host.
*/
if (!ret && xd && xd->state == XDOMAIN_STATE_ERROR) {
dev_dbg(&xd->dev, "restarting handshake\n");
start_handshake(xd);
}
break;
case LINK_STATE_STATUS_REQUEST:
@ -1521,6 +1551,13 @@ static void tb_xdomain_queue_properties_changed(struct tb_xdomain *xd)
msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
}
static void tb_xdomain_failed(struct tb_xdomain *xd)
{
xd->state = XDOMAIN_STATE_ERROR;
queue_delayed_work(xd->tb->wq, &xd->state_work,
msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT));
}
static void tb_xdomain_state_work(struct work_struct *work)
{
struct tb_xdomain *xd = container_of(work, typeof(*xd), state_work.work);
@ -1547,7 +1584,7 @@ static void tb_xdomain_state_work(struct work_struct *work)
if (ret) {
if (ret == -EAGAIN)
goto retry_state;
xd->state = XDOMAIN_STATE_ERROR;
tb_xdomain_failed(xd);
} else {
tb_xdomain_queue_properties_changed(xd);
if (xd->bonding_possible)
@ -1612,7 +1649,7 @@ static void tb_xdomain_state_work(struct work_struct *work)
if (ret) {
if (ret == -EAGAIN)
goto retry_state;
xd->state = XDOMAIN_STATE_ERROR;
tb_xdomain_failed(xd);
} else {
xd->state = XDOMAIN_STATE_ENUMERATED;
}
@ -1623,6 +1660,8 @@ static void tb_xdomain_state_work(struct work_struct *work)
break;
case XDOMAIN_STATE_ERROR:
dev_dbg(&xd->dev, "discovery failed, stopping handshake\n");
__stop_handshake(xd);
break;
default:
@ -1833,21 +1872,6 @@ static void tb_xdomain_release(struct device *dev)
kfree(xd);
}
static void start_handshake(struct tb_xdomain *xd)
{
xd->state = XDOMAIN_STATE_INIT;
queue_delayed_work(xd->tb->wq, &xd->state_work,
msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
}
static void stop_handshake(struct tb_xdomain *xd)
{
cancel_delayed_work_sync(&xd->properties_changed_work);
cancel_delayed_work_sync(&xd->state_work);
xd->properties_changed_retries = 0;
xd->state_retries = 0;
}
static int __maybe_unused tb_xdomain_suspend(struct device *dev)
{
stop_handshake(tb_to_xdomain(dev));