mirror of
https://github.com/torvalds/linux.git
synced 2026-05-24 07:03:03 +02:00
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:
commit
57e50f4bad
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user