aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2024-04-23 12:51:20 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2024-04-23 12:51:20 -0700
commit7b79d7083d3733bc1100c1c5fa8b9fd272046bda (patch)
tree7af768c2437adebe6f24ad96a4de7fe1693969d0
parent3652e88a874b32932a0fd1395320051d2ca23cc5 (diff)
downloadstable-queue-7b79d7083d3733bc1100c1c5fa8b9fd272046bda.tar.gz
6.6-stable patches
added patches: thunderbolt-introduce-tb_path_deactivate_hop.patch thunderbolt-introduce-tb_port_reset.patch thunderbolt-make-tb_switch_reset-support-thunderbolt-2-3-and-usb4-routers.patch thunderbolt-reset-topology-created-by-the-boot-firmware.patch
-rw-r--r--queue-6.6/series4
-rw-r--r--queue-6.6/thunderbolt-introduce-tb_path_deactivate_hop.patch53
-rw-r--r--queue-6.6/thunderbolt-introduce-tb_port_reset.patch187
-rw-r--r--queue-6.6/thunderbolt-make-tb_switch_reset-support-thunderbolt-2-3-and-usb4-routers.patch174
-rw-r--r--queue-6.6/thunderbolt-reset-topology-created-by-the-boot-firmware.patch207
5 files changed, 625 insertions, 0 deletions
diff --git a/queue-6.6/series b/queue-6.6/series
index 065f123bf4..ceac98733c 100644
--- a/queue-6.6/series
+++ b/queue-6.6/series
@@ -72,6 +72,10 @@ asoc-ti-convert-pandora-asoc-to-gpio-descriptors.patch
usb-pci-quirks-group-amd-specific-quirk-code-togethe.patch
usb-pci-quirks-handle-has_ioport-dependency-for-amd-.patch
usb-pci-quirks-handle-has_ioport-dependency-for-uhci.patch
+thunderbolt-introduce-tb_port_reset.patch
+thunderbolt-introduce-tb_path_deactivate_hop.patch
+thunderbolt-make-tb_switch_reset-support-thunderbolt-2-3-and-usb4-routers.patch
+thunderbolt-reset-topology-created-by-the-boot-firmware.patch
alsa-scarlett2-default-mixer-driver-to-enabled.patch
alsa-scarlett2-add-correct-product-series-name-to-me.patch
alsa-scarlett2-add-focusrite-clarett-2pre-and-4pre-s.patch
diff --git a/queue-6.6/thunderbolt-introduce-tb_path_deactivate_hop.patch b/queue-6.6/thunderbolt-introduce-tb_path_deactivate_hop.patch
new file mode 100644
index 0000000000..a6d04d40dc
--- /dev/null
+++ b/queue-6.6/thunderbolt-introduce-tb_path_deactivate_hop.patch
@@ -0,0 +1,53 @@
+From b35c1d7b11da8c08b14147bbe87c2c92f7a83f8b Mon Sep 17 00:00:00 2001
+From: Sanath S <Sanath.S@amd.com>
+Date: Sat, 13 Jan 2024 11:42:23 +0200
+Subject: thunderbolt: Introduce tb_path_deactivate_hop()
+
+From: Sanath S <Sanath.S@amd.com>
+
+commit b35c1d7b11da8c08b14147bbe87c2c92f7a83f8b upstream.
+
+This function can be used to clear path config space of an adapter. Make
+it available for other files in this driver.
+
+Signed-off-by: Sanath S <Sanath.S@amd.com>
+Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Cc: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/thunderbolt/path.c | 13 +++++++++++++
+ drivers/thunderbolt/tb.h | 1 +
+ 2 files changed, 14 insertions(+)
+
+--- a/drivers/thunderbolt/path.c
++++ b/drivers/thunderbolt/path.c
+@@ -446,6 +446,19 @@ static int __tb_path_deactivate_hop(stru
+ return -ETIMEDOUT;
+ }
+
++/**
++ * tb_path_deactivate_hop() - Deactivate one path in path config space
++ * @port: Lane or protocol adapter
++ * @hop_index: HopID of the path to be cleared
++ *
++ * This deactivates or clears a single path config space entry at
++ * @hop_index. Returns %0 in success and negative errno otherwise.
++ */
++int tb_path_deactivate_hop(struct tb_port *port, int hop_index)
++{
++ return __tb_path_deactivate_hop(port, hop_index, true);
++}
++
+ static void __tb_path_deactivate_hops(struct tb_path *path, int first_hop)
+ {
+ int i, res;
+--- a/drivers/thunderbolt/tb.h
++++ b/drivers/thunderbolt/tb.h
+@@ -1100,6 +1100,7 @@ struct tb_path *tb_path_alloc(struct tb
+ void tb_path_free(struct tb_path *path);
+ int tb_path_activate(struct tb_path *path);
+ void tb_path_deactivate(struct tb_path *path);
++int tb_path_deactivate_hop(struct tb_port *port, int hop_index);
+ bool tb_path_is_invalid(struct tb_path *path);
+ bool tb_path_port_on_path(const struct tb_path *path,
+ const struct tb_port *port);
diff --git a/queue-6.6/thunderbolt-introduce-tb_port_reset.patch b/queue-6.6/thunderbolt-introduce-tb_port_reset.patch
new file mode 100644
index 0000000000..28ab95c03c
--- /dev/null
+++ b/queue-6.6/thunderbolt-introduce-tb_port_reset.patch
@@ -0,0 +1,187 @@
+From 01da6b99d49f60b1edead44e33569b1a2e9f49b7 Mon Sep 17 00:00:00 2001
+From: Sanath S <Sanath.S@amd.com>
+Date: Sat, 13 Jan 2024 11:39:57 +0200
+Subject: thunderbolt: Introduce tb_port_reset()
+
+From: Sanath S <Sanath.S@amd.com>
+
+commit 01da6b99d49f60b1edead44e33569b1a2e9f49b7 upstream.
+
+Introduce a function that issues Downstream Port Reset to a USB4 port.
+This supports Thunderbolt 2, 3 and USB4 routers.
+
+Signed-off-by: Sanath S <Sanath.S@amd.com>
+Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Cc: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/thunderbolt/lc.c | 45 ++++++++++++++++++++++++++++++++++++++++++
+ drivers/thunderbolt/switch.c | 7 ++++++
+ drivers/thunderbolt/tb.h | 2 +
+ drivers/thunderbolt/tb_regs.h | 4 +++
+ drivers/thunderbolt/usb4.c | 39 ++++++++++++++++++++++++++++++++++++
+ 5 files changed, 97 insertions(+)
+
+--- a/drivers/thunderbolt/lc.c
++++ b/drivers/thunderbolt/lc.c
+@@ -6,6 +6,8 @@
+ * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
+ */
+
++#include <linux/delay.h>
++
+ #include "tb.h"
+
+ /**
+@@ -45,6 +47,49 @@ static int find_port_lc_cap(struct tb_po
+ return sw->cap_lc + start + phys * size;
+ }
+
++/**
++ * tb_lc_reset_port() - Trigger downstream port reset through LC
++ * @port: Port that is reset
++ *
++ * Triggers downstream port reset through link controller registers.
++ * Returns %0 in case of success negative errno otherwise. Only supports
++ * non-USB4 routers with link controller (that's Thunderbolt 2 and
++ * Thunderbolt 3).
++ */
++int tb_lc_reset_port(struct tb_port *port)
++{
++ struct tb_switch *sw = port->sw;
++ int cap, ret;
++ u32 mode;
++
++ if (sw->generation < 2)
++ return -EINVAL;
++
++ cap = find_port_lc_cap(port);
++ if (cap < 0)
++ return cap;
++
++ ret = tb_sw_read(sw, &mode, TB_CFG_SWITCH, cap + TB_LC_PORT_MODE, 1);
++ if (ret)
++ return ret;
++
++ mode |= TB_LC_PORT_MODE_DPR;
++
++ ret = tb_sw_write(sw, &mode, TB_CFG_SWITCH, cap + TB_LC_PORT_MODE, 1);
++ if (ret)
++ return ret;
++
++ fsleep(10000);
++
++ ret = tb_sw_read(sw, &mode, TB_CFG_SWITCH, cap + TB_LC_PORT_MODE, 1);
++ if (ret)
++ return ret;
++
++ mode &= ~TB_LC_PORT_MODE_DPR;
++
++ return tb_sw_write(sw, &mode, TB_CFG_SWITCH, cap + TB_LC_PORT_MODE, 1);
++}
++
+ static int tb_lc_set_port_configured(struct tb_port *port, bool configured)
+ {
+ bool upstream = tb_is_upstream_port(port);
+--- a/drivers/thunderbolt/switch.c
++++ b/drivers/thunderbolt/switch.c
+@@ -675,6 +675,13 @@ int tb_port_disable(struct tb_port *port
+ return __tb_port_enable(port, false);
+ }
+
++static int tb_port_reset(struct tb_port *port)
++{
++ if (tb_switch_is_usb4(port->sw))
++ return port->cap_usb4 ? usb4_port_reset(port) : 0;
++ return tb_lc_reset_port(port);
++}
++
+ /*
+ * tb_init_port() - initialize a port
+ *
+--- a/drivers/thunderbolt/tb.h
++++ b/drivers/thunderbolt/tb.h
+@@ -1119,6 +1119,7 @@ int tb_drom_read(struct tb_switch *sw);
+ int tb_drom_read_uid_only(struct tb_switch *sw, u64 *uid);
+
+ int tb_lc_read_uuid(struct tb_switch *sw, u32 *uuid);
++int tb_lc_reset_port(struct tb_port *port);
+ int tb_lc_configure_port(struct tb_port *port);
+ void tb_lc_unconfigure_port(struct tb_port *port);
+ int tb_lc_configure_xdomain(struct tb_port *port);
+@@ -1251,6 +1252,7 @@ void usb4_switch_remove_ports(struct tb_
+
+ int usb4_port_unlock(struct tb_port *port);
+ int usb4_port_hotplug_enable(struct tb_port *port);
++int usb4_port_reset(struct tb_port *port);
+ int usb4_port_configure(struct tb_port *port);
+ void usb4_port_unconfigure(struct tb_port *port);
+ int usb4_port_configure_xdomain(struct tb_port *port, struct tb_xdomain *xd);
+--- a/drivers/thunderbolt/tb_regs.h
++++ b/drivers/thunderbolt/tb_regs.h
+@@ -383,6 +383,7 @@ struct tb_regs_port_header {
+ #define PORT_CS_18_WODS BIT(17)
+ #define PORT_CS_18_WOU4S BIT(18)
+ #define PORT_CS_19 0x13
++#define PORT_CS_19_DPR BIT(0)
+ #define PORT_CS_19_PC BIT(3)
+ #define PORT_CS_19_PID BIT(4)
+ #define PORT_CS_19_WOC BIT(16)
+@@ -579,6 +580,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(0)
++
+ #define TB_LC_CS_42 0x2a
+ #define TB_LC_CS_42_USB_PLUGGED BIT(31)
+
+--- a/drivers/thunderbolt/usb4.c
++++ b/drivers/thunderbolt/usb4.c
+@@ -1113,6 +1113,45 @@ int usb4_port_hotplug_enable(struct tb_p
+ return tb_port_write(port, &val, TB_CFG_PORT, ADP_CS_5, 1);
+ }
+
++/**
++ * usb4_port_reset() - Issue downstream port reset
++ * @port: USB4 port to reset
++ *
++ * Issues downstream port reset to @port.
++ */
++int usb4_port_reset(struct tb_port *port)
++{
++ int ret;
++ u32 val;
++
++ if (!port->cap_usb4)
++ return -EINVAL;
++
++ ret = tb_port_read(port, &val, TB_CFG_PORT,
++ port->cap_usb4 + PORT_CS_19, 1);
++ if (ret)
++ return ret;
++
++ val |= PORT_CS_19_DPR;
++
++ ret = tb_port_write(port, &val, TB_CFG_PORT,
++ port->cap_usb4 + PORT_CS_19, 1);
++ if (ret)
++ return ret;
++
++ fsleep(10000);
++
++ ret = tb_port_read(port, &val, TB_CFG_PORT,
++ port->cap_usb4 + PORT_CS_19, 1);
++ if (ret)
++ return ret;
++
++ val &= ~PORT_CS_19_DPR;
++
++ return tb_port_write(port, &val, TB_CFG_PORT,
++ port->cap_usb4 + PORT_CS_19, 1);
++}
++
+ static int usb4_port_set_configured(struct tb_port *port, bool configured)
+ {
+ int ret;
diff --git a/queue-6.6/thunderbolt-make-tb_switch_reset-support-thunderbolt-2-3-and-usb4-routers.patch b/queue-6.6/thunderbolt-make-tb_switch_reset-support-thunderbolt-2-3-and-usb4-routers.patch
new file mode 100644
index 0000000000..89bab8397f
--- /dev/null
+++ b/queue-6.6/thunderbolt-make-tb_switch_reset-support-thunderbolt-2-3-and-usb4-routers.patch
@@ -0,0 +1,174 @@
+From ec8162b3f0683ae08a21f20517cf49272b07ee0b Mon Sep 17 00:00:00 2001
+From: Sanath S <Sanath.S@amd.com>
+Date: Sat, 13 Jan 2024 11:47:26 +0200
+Subject: thunderbolt: Make tb_switch_reset() support Thunderbolt 2, 3 and USB4 routers
+
+From: Sanath S <Sanath.S@amd.com>
+
+commit ec8162b3f0683ae08a21f20517cf49272b07ee0b upstream.
+
+Currently tb_switch_reset() only did something for Thunderbolt 1
+devices. Expand this to support all generations, including USB4, and
+both host and device routers.
+
+Signed-off-by: Sanath S <Sanath.S@amd.com>
+Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Cc: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/thunderbolt/switch.c | 123 +++++++++++++++++++++++++++++++++++++-----
+ drivers/thunderbolt/tb_regs.h | 2
+ 2 files changed, 111 insertions(+), 14 deletions(-)
+
+--- a/drivers/thunderbolt/switch.c
++++ b/drivers/thunderbolt/switch.c
+@@ -1492,29 +1492,124 @@ static void tb_dump_switch(const struct
+ regs->__unknown1, regs->__unknown4);
+ }
+
++static int tb_switch_reset_host(struct tb_switch *sw)
++{
++ if (sw->generation > 1) {
++ struct tb_port *port;
++
++ tb_switch_for_each_port(sw, port) {
++ int i, ret;
++
++ /*
++ * For lane adapters we issue downstream port
++ * reset and clear up path config spaces.
++ *
++ * For protocol adapters we disable the path and
++ * clear path config space one by one (from 8 to
++ * Max Input HopID of the adapter).
++ */
++ if (tb_port_is_null(port) && !tb_is_upstream_port(port)) {
++ ret = tb_port_reset(port);
++ if (ret)
++ return ret;
++ } else if (tb_port_is_usb3_down(port) ||
++ tb_port_is_usb3_up(port)) {
++ tb_usb3_port_enable(port, false);
++ } else if (tb_port_is_dpin(port) ||
++ tb_port_is_dpout(port)) {
++ tb_dp_port_enable(port, false);
++ } else if (tb_port_is_pcie_down(port) ||
++ tb_port_is_pcie_up(port)) {
++ tb_pci_port_enable(port, false);
++ } else {
++ continue;
++ }
++
++ /* Cleanup path config space of protocol adapter */
++ for (i = TB_PATH_MIN_HOPID;
++ i <= port->config.max_in_hop_id; i++) {
++ ret = tb_path_deactivate_hop(port, i);
++ if (ret)
++ return ret;
++ }
++ }
++ } else {
++ struct tb_cfg_result res;
++
++ /* Thunderbolt 1 uses the "reset" config space packet */
++ res.err = tb_sw_write(sw, ((u32 *) &sw->config) + 2,
++ TB_CFG_SWITCH, 2, 2);
++ if (res.err)
++ return res.err;
++ res = tb_cfg_reset(sw->tb->ctl, tb_route(sw));
++ if (res.err > 0)
++ return -EIO;
++ else if (res.err < 0)
++ return res.err;
++ }
++
++ return 0;
++}
++
++static int tb_switch_reset_device(struct tb_switch *sw)
++{
++ return tb_port_reset(tb_switch_downstream_port(sw));
++}
++
++static bool tb_switch_enumerated(struct tb_switch *sw)
++{
++ u32 val;
++ int ret;
++
++ /*
++ * Read directly from the hardware because we use this also
++ * during system sleep where sw->config.enabled is already set
++ * by us.
++ */
++ ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, ROUTER_CS_3, 1);
++ if (ret)
++ return false;
++
++ return !!(val & ROUTER_CS_3_V);
++}
++
+ /**
+- * tb_switch_reset() - reconfigure route, enable and send TB_CFG_PKG_RESET
+- * @sw: Switch to reset
++ * tb_switch_reset() - Perform reset to the router
++ * @sw: Router to reset
++ *
++ * Issues reset to the router @sw. Can be used for any router. For host
++ * routers, resets all the downstream ports and cleans up path config
++ * spaces accordingly. For device routers issues downstream port reset
++ * through the parent router, so as side effect there will be unplug
++ * soon after this is finished.
++ *
++ * If the router is not enumerated does nothing.
+ *
+- * Return: Returns 0 on success or an error code on failure.
++ * Returns %0 on success or negative errno in case of failure.
+ */
+ int tb_switch_reset(struct tb_switch *sw)
+ {
+- struct tb_cfg_result res;
++ int ret;
+
+- if (sw->generation > 1)
++ /*
++ * We cannot access the port config spaces unless the router is
++ * already enumerated. If the router is not enumerated it is
++ * equal to being reset so we can skip that here.
++ */
++ if (!tb_switch_enumerated(sw))
+ return 0;
+
+- tb_sw_dbg(sw, "resetting switch\n");
++ tb_sw_dbg(sw, "resetting\n");
++
++ if (tb_route(sw))
++ ret = tb_switch_reset_device(sw);
++ else
++ ret = tb_switch_reset_host(sw);
++
++ if (ret)
++ tb_sw_warn(sw, "failed to reset\n");
+
+- res.err = tb_sw_write(sw, ((u32 *) &sw->config) + 2,
+- TB_CFG_SWITCH, 2, 2);
+- if (res.err)
+- return res.err;
+- res = tb_cfg_reset(sw->tb->ctl, tb_route(sw));
+- if (res.err > 0)
+- return -EIO;
+- return res.err;
++ return ret;
+ }
+
+ /**
+--- a/drivers/thunderbolt/tb_regs.h
++++ b/drivers/thunderbolt/tb_regs.h
+@@ -194,6 +194,8 @@ struct tb_regs_switch_header {
+ #define USB4_VERSION_MAJOR_MASK GENMASK(7, 5)
+
+ #define ROUTER_CS_1 0x01
++#define ROUTER_CS_3 0x03
++#define ROUTER_CS_3_V BIT(31)
+ #define ROUTER_CS_4 0x04
+ /* Used with the router cmuv field */
+ #define ROUTER_CS_4_CMUV_V1 0x10
diff --git a/queue-6.6/thunderbolt-reset-topology-created-by-the-boot-firmware.patch b/queue-6.6/thunderbolt-reset-topology-created-by-the-boot-firmware.patch
new file mode 100644
index 0000000000..02dcac118f
--- /dev/null
+++ b/queue-6.6/thunderbolt-reset-topology-created-by-the-boot-firmware.patch
@@ -0,0 +1,207 @@
+From 59a54c5f3dbde00b8ad30aef27fe35b1fe07bf5c Mon Sep 17 00:00:00 2001
+From: Sanath S <Sanath.S@amd.com>
+Date: Sat, 13 Jan 2024 11:52:48 +0200
+Subject: thunderbolt: Reset topology created by the boot firmware
+
+From: Sanath S <Sanath.S@amd.com>
+
+commit 59a54c5f3dbde00b8ad30aef27fe35b1fe07bf5c upstream.
+
+Boot firmware (typically BIOS) might have created tunnels of its own.
+The tunnel configuration that it does might be sub-optimal. For instance
+it may only support HBR2 monitors so the DisplayPort tunnels it created
+may limit Linux graphics drivers. In addition there is an issue on some
+AMD based systems where the BIOS does not allocate enough PCIe resources
+for future topology extension. By resetting the USB4 topology the PCIe
+links will be reset as well allowing Linux to re-allocate.
+
+This aligns the behavior with Windows Connection Manager.
+
+We already issued host router reset for USB4 v2 routers, now extend it
+to USB4 v1 routers as well. For pre-USB4 (that's Apple systems) we leave
+it as is and continue to discover the existing tunnels.
+
+Suggested-by: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Sanath S <Sanath.S@amd.com>
+Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/thunderbolt/domain.c | 5 +++--
+ drivers/thunderbolt/icm.c | 2 +-
+ drivers/thunderbolt/nhi.c | 19 +++++++++++++------
+ drivers/thunderbolt/tb.c | 26 +++++++++++++++++++-------
+ drivers/thunderbolt/tb.h | 4 ++--
+ 5 files changed, 38 insertions(+), 18 deletions(-)
+
+--- a/drivers/thunderbolt/domain.c
++++ b/drivers/thunderbolt/domain.c
+@@ -423,6 +423,7 @@ err_free:
+ /**
+ * tb_domain_add() - Add domain to the system
+ * @tb: Domain to add
++ * @reset: Issue reset to the host router
+ *
+ * Starts the domain and adds it to the system. Hotplugging devices will
+ * work after this has been returned successfully. In order to remove
+@@ -431,7 +432,7 @@ err_free:
+ *
+ * Return: %0 in case of success and negative errno in case of error
+ */
+-int tb_domain_add(struct tb *tb)
++int tb_domain_add(struct tb *tb, bool reset)
+ {
+ int ret;
+
+@@ -460,7 +461,7 @@ int tb_domain_add(struct tb *tb)
+
+ /* Start the domain */
+ if (tb->cm_ops->start) {
+- ret = tb->cm_ops->start(tb);
++ ret = tb->cm_ops->start(tb, reset);
+ if (ret)
+ goto err_domain_del;
+ }
+--- a/drivers/thunderbolt/icm.c
++++ b/drivers/thunderbolt/icm.c
+@@ -2144,7 +2144,7 @@ static int icm_runtime_resume(struct tb
+ return 0;
+ }
+
+-static int icm_start(struct tb *tb)
++static int icm_start(struct tb *tb, bool not_used)
+ {
+ struct icm *icm = tb_priv(tb);
+ int ret;
+--- a/drivers/thunderbolt/nhi.c
++++ b/drivers/thunderbolt/nhi.c
+@@ -1221,7 +1221,7 @@ static void nhi_check_iommu(struct tb_nh
+ str_enabled_disabled(port_ok));
+ }
+
+-static void nhi_reset(struct tb_nhi *nhi)
++static bool nhi_reset(struct tb_nhi *nhi)
+ {
+ ktime_t timeout;
+ u32 val;
+@@ -1229,11 +1229,11 @@ static void nhi_reset(struct tb_nhi *nhi
+ val = ioread32(nhi->iobase + REG_CAPS);
+ /* Reset only v2 and later routers */
+ if (FIELD_GET(REG_CAPS_VERSION_MASK, val) < REG_CAPS_VERSION_2)
+- return;
++ return false;
+
+ if (!host_reset) {
+ dev_dbg(&nhi->pdev->dev, "skipping host router reset\n");
+- return;
++ return false;
+ }
+
+ iowrite32(REG_RESET_HRR, nhi->iobase + REG_RESET);
+@@ -1244,12 +1244,14 @@ static void nhi_reset(struct tb_nhi *nhi
+ val = ioread32(nhi->iobase + REG_RESET);
+ if (!(val & REG_RESET_HRR)) {
+ dev_warn(&nhi->pdev->dev, "host router reset successful\n");
+- return;
++ return true;
+ }
+ usleep_range(10, 20);
+ } while (ktime_before(ktime_get(), timeout));
+
+ dev_warn(&nhi->pdev->dev, "timeout resetting host router\n");
++
++ return false;
+ }
+
+ static int nhi_init_msi(struct tb_nhi *nhi)
+@@ -1331,6 +1333,7 @@ static int nhi_probe(struct pci_dev *pde
+ struct device *dev = &pdev->dev;
+ struct tb_nhi *nhi;
+ struct tb *tb;
++ bool reset;
+ int res;
+
+ if (!nhi_imr_valid(pdev))
+@@ -1365,7 +1368,11 @@ static int nhi_probe(struct pci_dev *pde
+ nhi_check_quirks(nhi);
+ nhi_check_iommu(nhi);
+
+- nhi_reset(nhi);
++ /*
++ * Only USB4 v2 hosts support host reset so if we already did
++ * that then don't do it again when the domain is initialized.
++ */
++ reset = nhi_reset(nhi) ? false : host_reset;
+
+ res = nhi_init_msi(nhi);
+ if (res)
+@@ -1392,7 +1399,7 @@ static int nhi_probe(struct pci_dev *pde
+
+ dev_dbg(dev, "NHI initialized, starting thunderbolt\n");
+
+- res = tb_domain_add(tb);
++ res = tb_domain_add(tb, reset);
+ if (res) {
+ /*
+ * At this point the RX/TX rings might already have been
+--- a/drivers/thunderbolt/tb.c
++++ b/drivers/thunderbolt/tb.c
+@@ -2131,7 +2131,7 @@ static int tb_scan_finalize_switch(struc
+ return 0;
+ }
+
+-static int tb_start(struct tb *tb)
++static int tb_start(struct tb *tb, bool reset)
+ {
+ struct tb_cm *tcm = tb_priv(tb);
+ int ret;
+@@ -2172,12 +2172,24 @@ static int tb_start(struct tb *tb)
+ tb_switch_tmu_configure(tb->root_switch, TB_SWITCH_TMU_MODE_LOWRES);
+ /* Enable TMU if it is off */
+ tb_switch_tmu_enable(tb->root_switch);
+- /* 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 */
+- tb_discover_tunnels(tb);
+- /* Add DP resources from the DP tunnels created by the boot firmware */
+- tb_discover_dp_resources(tb);
++
++ /*
++ * Boot firmware might have created tunnels of its own. Since we
++ * cannot be sure they are usable for us, tear them down and
++ * reset the ports to handle it as new hotplug for USB4 v1
++ * routers (for USB4 v2 and beyond we already do host reset).
++ */
++ if (reset && usb4_switch_version(tb->root_switch) == 1) {
++ tb_switch_reset(tb->root_switch);
++ } else {
++ /* 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 */
++ tb_discover_tunnels(tb);
++ /* Add DP resources from the DP tunnels created by the boot firmware */
++ tb_discover_dp_resources(tb);
++ }
++
+ /*
+ * If the boot firmware did not create USB 3.x tunnels create them
+ * now for the whole topology.
+--- a/drivers/thunderbolt/tb.h
++++ b/drivers/thunderbolt/tb.h
+@@ -488,7 +488,7 @@ struct tb_path {
+ */
+ struct tb_cm_ops {
+ int (*driver_ready)(struct tb *tb);
+- int (*start)(struct tb *tb);
++ int (*start)(struct tb *tb, bool reset);
+ void (*stop)(struct tb *tb);
+ int (*suspend_noirq)(struct tb *tb);
+ int (*resume_noirq)(struct tb *tb);
+@@ -735,7 +735,7 @@ int tb_xdomain_init(void);
+ void tb_xdomain_exit(void);
+
+ struct tb *tb_domain_alloc(struct tb_nhi *nhi, int timeout_msec, size_t privsize);
+-int tb_domain_add(struct tb *tb);
++int tb_domain_add(struct tb *tb, bool reset);
+ void tb_domain_remove(struct tb *tb);
+ int tb_domain_suspend_noirq(struct tb *tb);
+ int tb_domain_resume_noirq(struct tb *tb);