Skip to content

Commit 4ffdb08

Browse files
westerigregkh
authored andcommitted
thunderbolt: Read DP IN adapter first two dwords in one go
[ Upstream commit fd5c46b ] When we discover existing DP tunnels the code checks whether DP IN adapter port is enabled by calling tb_dp_port_is_enabled() before it continues the discovery process. On Light Ridge (gen 1) controller reading only the first dword of the DP IN config space causes subsequent access to the same DP IN port path config space to fail or return invalid data as can be seen in the below splat: thunderbolt 0000:07:00.0: CFG_ERROR(0:d): Invalid config space or offset Call Trace: tb_cfg_read+0xb9/0xd0 __tb_path_deactivate_hop+0x98/0x210 tb_path_activate+0x228/0x7d0 tb_tunnel_restart+0x95/0x200 tb_handle_hotplug+0x30e/0x630 process_one_work+0x1b4/0x340 worker_thread+0x44/0x3d0 kthread+0xeb/0x120 ? process_one_work+0x340/0x340 ? kthread_park+0xa0/0xa0 ret_from_fork+0x1f/0x30 If both DP In adapter config dwords are read in one go the issue does not reproduce. This is likely firmware bug but we can work it around by always reading the two dwords in one go. There should be no harm for other controllers either so can do it unconditionally. Link: https://lkml.org/lkml/2019/8/28/160 Reported-by: Brad Campbell <lists2009@fnarfbargle.com> Tested-by: Brad Campbell <lists2009@fnarfbargle.com> Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 57ba0c1 commit 4ffdb08

File tree

1 file changed

+11
-8
lines changed

1 file changed

+11
-8
lines changed

drivers/thunderbolt/switch.c

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -887,12 +887,13 @@ int tb_dp_port_set_hops(struct tb_port *port, unsigned int video,
887887
*/
888888
bool tb_dp_port_is_enabled(struct tb_port *port)
889889
{
890-
u32 data;
890+
u32 data[2];
891891

892-
if (tb_port_read(port, &data, TB_CFG_PORT, port->cap_adap, 1))
892+
if (tb_port_read(port, data, TB_CFG_PORT, port->cap_adap,
893+
ARRAY_SIZE(data)))
893894
return false;
894895

895-
return !!(data & (TB_DP_VIDEO_EN | TB_DP_AUX_EN));
896+
return !!(data[0] & (TB_DP_VIDEO_EN | TB_DP_AUX_EN));
896897
}
897898

898899
/**
@@ -905,19 +906,21 @@ bool tb_dp_port_is_enabled(struct tb_port *port)
905906
*/
906907
int tb_dp_port_enable(struct tb_port *port, bool enable)
907908
{
908-
u32 data;
909+
u32 data[2];
909910
int ret;
910911

911-
ret = tb_port_read(port, &data, TB_CFG_PORT, port->cap_adap, 1);
912+
ret = tb_port_read(port, data, TB_CFG_PORT, port->cap_adap,
913+
ARRAY_SIZE(data));
912914
if (ret)
913915
return ret;
914916

915917
if (enable)
916-
data |= TB_DP_VIDEO_EN | TB_DP_AUX_EN;
918+
data[0] |= TB_DP_VIDEO_EN | TB_DP_AUX_EN;
917919
else
918-
data &= ~(TB_DP_VIDEO_EN | TB_DP_AUX_EN);
920+
data[0] &= ~(TB_DP_VIDEO_EN | TB_DP_AUX_EN);
919921

920-
return tb_port_write(port, &data, TB_CFG_PORT, port->cap_adap, 1);
922+
return tb_port_write(port, data, TB_CFG_PORT, port->cap_adap,
923+
ARRAY_SIZE(data));
921924
}
922925

923926
/* switch utility functions */

0 commit comments

Comments
 (0)