lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Tue, 9 Aug 2022 18:50:28 +0300
From:   Mika Westerberg <mika.westerberg@...ux.intel.com>
To:     Brad Campbell <lists2009@...rfbargle.com>
Cc:     linux-kernel@...r.kernel.org
Subject: Re: Apple Thunderbolt Display chaining

Hi,

On Tue, Aug 09, 2022 at 11:16:27PM +0800, Brad Campbell wrote:
> If I then reboot and load the driver it fails.
> 
> The only thing I could think of doing was an lspci -vvv after the boot and module load
> and an lspci -vvv after a warm reboot and diff them, because there are changes around the
> thunderbolt bridge devices. I've done a diff -u50 to try and keep as much context as possible.
> 
> On the first boot I can unload/reload the thunderbolt module repeatedly and there's no issue
> but loading it after a reboot locks up. There are no lspci changes on the first boot after the
> initial module load unless I rescan the PCI bus, but they're minor and it doesn't cause an issue
> with loading the thunderbolt module.
> 
> The firmware *must* be doing something on reboot I suppose or the PCIe configs wouldn't change.

Okay, let's try a bigger hammer and reset all the ports upon load. That
should hopefully clear out the "bad state" too. This is completely
untested but it should trigger reset and then re-initialize the TBT
links.

diff --git a/drivers/thunderbolt/lc.c b/drivers/thunderbolt/lc.c
index 633970fbe9b0..c419c2568de4 100644
--- a/drivers/thunderbolt/lc.c
+++ b/drivers/thunderbolt/lc.c
@@ -6,6 +6,8 @@
  * Author: Mika Westerberg <mika.westerberg@...ux.intel.com>
  */
 
+#include <linux/delay.h>
+
 #include "tb.h"
 
 /**
@@ -327,6 +329,34 @@ void tb_lc_xhci_disconnect(struct tb_port *port)
 	tb_port_dbg(port, "xHCI disconnected\n");
 }
 
+int tb_lc_reset_port(struct tb_port *port)
+{
+	struct tb_switch *sw = port->sw;
+	int cap, ret;
+	u32 val;
+
+	if (sw->generation != 3)
+		return -EINVAL;
+
+	cap = find_port_lc_cap(port);
+	if (cap < 0)
+		return cap;
+
+	ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, cap + TB_LC_PORT_MODE, 1);
+	if (ret)
+		return ret;
+
+	val |= TB_LC_PORT_MODE_DPR;
+	ret = tb_sw_write(sw, &val, TB_CFG_SWITCH, cap + TB_LC_PORT_MODE, 1);
+	if (ret)
+		return ret;
+
+	msleep(20);
+
+	val &= ~TB_LC_PORT_MODE_DPR;
+	return tb_sw_write(sw, &val, TB_CFG_SWITCH, cap + TB_LC_PORT_MODE, 1);
+}
+
 static int tb_lc_set_wake_one(struct tb_switch *sw, unsigned int offset,
 			      unsigned int flags)
 {
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index 0ae8a7ec7c9c..21ac3ccf1cf9 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -740,6 +740,11 @@ int tb_port_disable(struct tb_port *port)
 	return __tb_port_enable(port, false);
 }
 
+int tb_port_reset(struct tb_port *port)
+{
+	return tb_lc_reset_port(port);
+}
+
 /*
  * tb_init_port() - initialize a port
  *
diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
index 8030fc544c5e..48a7396994ef 100644
--- a/drivers/thunderbolt/tb.c
+++ b/drivers/thunderbolt/tb.c
@@ -1875,6 +1875,7 @@ static int tb_scan_finalize_switch(struct device *dev, void *data)
 static int tb_start(struct tb *tb)
 {
 	struct tb_cm *tcm = tb_priv(tb);
+	struct tb_port *p;
 	int ret;
 
 	tb->root_switch = tb_switch_alloc(tb, &tb->dev, 0);
@@ -1911,6 +1912,12 @@ static int tb_start(struct tb *tb)
 				false);
 	/* Enable TMU if it is off */
 	tb_switch_tmu_enable(tb->root_switch);
+
+	tb_switch_for_each_port(tb->root_switch, p) {
+		if (tb_port_is_null(p))
+			tb_port_reset(p);
+	}
+
 	/* Full scan to discover devices added before the driver was loaded. */
 	tb_scan_switch(tb->root_switch);
 	/* Find out tunnels created by the boot firmware */
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
index 28bb80d967d6..fe5edefec712 100644
--- a/drivers/thunderbolt/tb.h
+++ b/drivers/thunderbolt/tb.h
@@ -1028,6 +1028,7 @@ int tb_port_clear_counter(struct tb_port *port, int counter);
 int tb_port_unlock(struct tb_port *port);
 int tb_port_enable(struct tb_port *port);
 int tb_port_disable(struct tb_port *port);
+int tb_port_reset(struct tb_port *port);
 int tb_port_alloc_in_hopid(struct tb_port *port, int hopid, int max_hopid);
 void tb_port_release_in_hopid(struct tb_port *port, int hopid);
 int tb_port_alloc_out_hopid(struct tb_port *port, int hopid, int max_hopid);
@@ -1121,6 +1122,7 @@ bool tb_lc_is_usb_plugged(struct tb_port *port);
 bool tb_lc_is_xhci_connected(struct tb_port *port);
 int tb_lc_xhci_connect(struct tb_port *port);
 void tb_lc_xhci_disconnect(struct tb_port *port);
+int tb_lc_reset_port(struct tb_port *port);
 int tb_lc_set_wake(struct tb_switch *sw, unsigned int flags);
 int tb_lc_set_sleep(struct tb_switch *sw);
 bool tb_lc_lane_bonding_possible(struct tb_switch *sw);
diff --git a/drivers/thunderbolt/tb_regs.h b/drivers/thunderbolt/tb_regs.h
index f8c1ca3464d9..8fd12bc2d500 100644
--- a/drivers/thunderbolt/tb_regs.h
+++ b/drivers/thunderbolt/tb_regs.h
@@ -555,6 +555,9 @@ struct tb_regs_hop {
 #define TB_LC_POWER				0x740
 
 /* Link controller registers */
+#define TB_LC_PORT_MODE				0x26
+#define TB_LC_PORT_MODE_DPR			BIT(6)
+
 #define TB_LC_CS_42				0x2a
 #define TB_LC_CS_42_USB_PLUGGED			BIT(31)
 

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ