From: Greg Kroah-Hartman Date: Fri, 11 Nov 2022 08:53:10 +0000 (+0100) Subject: 5.15-stable patches X-Git-Tag: v5.10.155~58 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e6b789cebab8a657f8e7d411624b5e74e0ef21a4;p=thirdparty%2Fkernel%2Fstable-queue.git 5.15-stable patches added patches: thunderbolt-add-dp-out-resource-when-dp-tunnel-is-discovered.patch thunderbolt-tear-down-existing-tunnels-when-resuming-from-hibernate.patch --- diff --git a/queue-5.15/thunderbolt-add-dp-out-resource-when-dp-tunnel-is-discovered.patch b/queue-5.15/thunderbolt-add-dp-out-resource-when-dp-tunnel-is-discovered.patch new file mode 100644 index 00000000000..3d2d6a044b4 --- /dev/null +++ b/queue-5.15/thunderbolt-add-dp-out-resource-when-dp-tunnel-is-discovered.patch @@ -0,0 +1,70 @@ +From b60e31bf18a7064032dbcb73dcb5b58f8a00a110 Mon Sep 17 00:00:00 2001 +From: Sanjay R Mehta +Date: Thu, 4 Aug 2022 05:48:38 -0500 +Subject: thunderbolt: Add DP OUT resource when DP tunnel is discovered + +From: Sanjay R Mehta + +commit b60e31bf18a7064032dbcb73dcb5b58f8a00a110 upstream. + +If the boot firmware implements a connection manager of its own it may +create a DisplayPort tunnel and will be handed off to Linux connection +manager, but the DP OUT resource is not saved in the dp_resource list. + +This patch adds tunnelled DP OUT port to the dp_resource list once the +DP tunnel is discovered. + +Signed-off-by: Sanjay R Mehta +Signed-off-by: Basavaraj Natikar +Tested-by: Renjith Pananchikkal +Signed-off-by: Mika Westerberg +Cc: "Limonciello, Mario" +Signed-off-by: Greg Kroah-Hartman +--- + drivers/thunderbolt/tb.c | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +--- a/drivers/thunderbolt/tb.c ++++ b/drivers/thunderbolt/tb.c +@@ -105,6 +105,32 @@ static void tb_remove_dp_resources(struc + } + } + ++static void tb_discover_dp_resource(struct tb *tb, struct tb_port *port) ++{ ++ struct tb_cm *tcm = tb_priv(tb); ++ struct tb_port *p; ++ ++ list_for_each_entry(p, &tcm->dp_resources, list) { ++ if (p == port) ++ return; ++ } ++ ++ tb_port_dbg(port, "DP %s resource available discovered\n", ++ tb_port_is_dpin(port) ? "IN" : "OUT"); ++ list_add_tail(&port->list, &tcm->dp_resources); ++} ++ ++static void tb_discover_dp_resources(struct tb *tb) ++{ ++ struct tb_cm *tcm = tb_priv(tb); ++ struct tb_tunnel *tunnel; ++ ++ list_for_each_entry(tunnel, &tcm->tunnel_list, list) { ++ if (tb_tunnel_is_dp(tunnel)) ++ tb_discover_dp_resource(tb, tunnel->dst_port); ++ } ++} ++ + static void tb_switch_discover_tunnels(struct tb_switch *sw, + struct list_head *list, + bool alloc_hopids) +@@ -1396,6 +1422,8 @@ static int tb_start(struct tb *tb) + 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. diff --git a/queue-5.15/thunderbolt-tear-down-existing-tunnels-when-resuming-from-hibernate.patch b/queue-5.15/thunderbolt-tear-down-existing-tunnels-when-resuming-from-hibernate.patch new file mode 100644 index 00000000000..e5f871b433e --- /dev/null +++ b/queue-5.15/thunderbolt-tear-down-existing-tunnels-when-resuming-from-hibernate.patch @@ -0,0 +1,418 @@ +From 43bddb26e20af916249b5318200cfe1734c1700c Mon Sep 17 00:00:00 2001 +From: Mika Westerberg +Date: Sun, 14 Nov 2021 17:20:59 +0200 +Subject: thunderbolt: Tear down existing tunnels when resuming from hibernate + +From: Mika Westerberg + +commit 43bddb26e20af916249b5318200cfe1734c1700c upstream. + +If the boot firmware implements connection manager of its own it may not +create the paths in the same way or order we do. For example it may +create first PCIe tunnel and then USB3 tunnel. When we restore our +tunnels (first de-activating them) we may be doing that over completely +different tunnels and that leaves them possibly non-functional. For this +reason we re-use the tunnel discovery functionality and find out all the +existing tunnels, and tear them down. Once that is done we can restore +our tunnels. + +Signed-off-by: Mika Westerberg +Cc: "Limonciello, Mario" +Signed-off-by: Greg Kroah-Hartman +--- + drivers/thunderbolt/path.c | 38 ++++++++++++++---------- + drivers/thunderbolt/tb.c | 68 ++++++++++++++++++++++++++++++++----------- + drivers/thunderbolt/tb.h | 5 ++- + drivers/thunderbolt/tunnel.c | 27 ++++++++++------- + drivers/thunderbolt/tunnel.h | 9 +++-- + 5 files changed, 102 insertions(+), 45 deletions(-) + +--- a/drivers/thunderbolt/path.c ++++ b/drivers/thunderbolt/path.c +@@ -85,11 +85,12 @@ static int tb_path_find_src_hopid(struct + * @dst_hopid: HopID to the @dst (%-1 if don't care) + * @last: Last port is filled here if not %NULL + * @name: Name of the path ++ * @alloc_hopid: Allocate HopIDs for the ports + * + * Follows a path starting from @src and @src_hopid to the last output +- * port of the path. Allocates HopIDs for the visited ports. Call +- * tb_path_free() to release the path and allocated HopIDs when the path +- * is not needed anymore. ++ * port of the path. Allocates HopIDs for the visited ports (if ++ * @alloc_hopid is true). Call tb_path_free() to release the path and ++ * allocated HopIDs when the path is not needed anymore. + * + * Note function discovers also incomplete paths so caller should check + * that the @dst port is the expected one. If it is not, the path can be +@@ -99,7 +100,8 @@ static int tb_path_find_src_hopid(struct + */ + struct tb_path *tb_path_discover(struct tb_port *src, int src_hopid, + struct tb_port *dst, int dst_hopid, +- struct tb_port **last, const char *name) ++ struct tb_port **last, const char *name, ++ bool alloc_hopid) + { + struct tb_port *out_port; + struct tb_regs_hop hop; +@@ -156,6 +158,7 @@ struct tb_path *tb_path_discover(struct + path->tb = src->sw->tb; + path->path_length = num_hops; + path->activated = true; ++ path->alloc_hopid = alloc_hopid; + + path->hops = kcalloc(num_hops, sizeof(*path->hops), GFP_KERNEL); + if (!path->hops) { +@@ -177,13 +180,14 @@ struct tb_path *tb_path_discover(struct + goto err; + } + +- if (tb_port_alloc_in_hopid(p, h, h) < 0) ++ if (alloc_hopid && tb_port_alloc_in_hopid(p, h, h) < 0) + goto err; + + out_port = &sw->ports[hop.out_port]; + next_hop = hop.next_hop; + +- if (tb_port_alloc_out_hopid(out_port, next_hop, next_hop) < 0) { ++ if (alloc_hopid && ++ tb_port_alloc_out_hopid(out_port, next_hop, next_hop) < 0) { + tb_port_release_in_hopid(p, h); + goto err; + } +@@ -263,6 +267,8 @@ struct tb_path *tb_path_alloc(struct tb + return NULL; + } + ++ path->alloc_hopid = true; ++ + in_hopid = src_hopid; + out_port = NULL; + +@@ -345,17 +351,19 @@ err: + */ + void tb_path_free(struct tb_path *path) + { +- int i; ++ if (path->alloc_hopid) { ++ int i; + +- for (i = 0; i < path->path_length; i++) { +- const struct tb_path_hop *hop = &path->hops[i]; ++ for (i = 0; i < path->path_length; i++) { ++ const struct tb_path_hop *hop = &path->hops[i]; + +- if (hop->in_port) +- tb_port_release_in_hopid(hop->in_port, +- hop->in_hop_index); +- if (hop->out_port) +- tb_port_release_out_hopid(hop->out_port, +- hop->next_hop_index); ++ if (hop->in_port) ++ tb_port_release_in_hopid(hop->in_port, ++ hop->in_hop_index); ++ if (hop->out_port) ++ tb_port_release_out_hopid(hop->out_port, ++ hop->next_hop_index); ++ } + } + + kfree(path->hops); +--- a/drivers/thunderbolt/tb.c ++++ b/drivers/thunderbolt/tb.c +@@ -105,10 +105,11 @@ static void tb_remove_dp_resources(struc + } + } + +-static void tb_discover_tunnels(struct tb_switch *sw) ++static void tb_switch_discover_tunnels(struct tb_switch *sw, ++ struct list_head *list, ++ bool alloc_hopids) + { + struct tb *tb = sw->tb; +- struct tb_cm *tcm = tb_priv(tb); + struct tb_port *port; + + tb_switch_for_each_port(sw, port) { +@@ -116,24 +117,41 @@ static void tb_discover_tunnels(struct t + + switch (port->config.type) { + case TB_TYPE_DP_HDMI_IN: +- tunnel = tb_tunnel_discover_dp(tb, port); ++ tunnel = tb_tunnel_discover_dp(tb, port, alloc_hopids); + break; + + case TB_TYPE_PCIE_DOWN: +- tunnel = tb_tunnel_discover_pci(tb, port); ++ tunnel = tb_tunnel_discover_pci(tb, port, alloc_hopids); + break; + + case TB_TYPE_USB3_DOWN: +- tunnel = tb_tunnel_discover_usb3(tb, port); ++ tunnel = tb_tunnel_discover_usb3(tb, port, alloc_hopids); + break; + + default: + break; + } + +- if (!tunnel) +- continue; ++ if (tunnel) ++ list_add_tail(&tunnel->list, list); ++ } ++ ++ tb_switch_for_each_port(sw, port) { ++ if (tb_port_has_remote(port)) { ++ tb_switch_discover_tunnels(port->remote->sw, list, ++ alloc_hopids); ++ } ++ } ++} ++ ++static void tb_discover_tunnels(struct tb *tb) ++{ ++ struct tb_cm *tcm = tb_priv(tb); ++ struct tb_tunnel *tunnel; ++ ++ tb_switch_discover_tunnels(tb->root_switch, &tcm->tunnel_list, true); + ++ list_for_each_entry(tunnel, &tcm->tunnel_list, list) { + if (tb_tunnel_is_pci(tunnel)) { + struct tb_switch *parent = tunnel->dst_port->sw; + +@@ -146,13 +164,6 @@ static void tb_discover_tunnels(struct t + pm_runtime_get_sync(&tunnel->src_port->sw->dev); + pm_runtime_get_sync(&tunnel->dst_port->sw->dev); + } +- +- list_add_tail(&tunnel->list, &tcm->tunnel_list); +- } +- +- tb_switch_for_each_port(sw, port) { +- if (tb_port_has_remote(port)) +- tb_discover_tunnels(port->remote->sw); + } + } + +@@ -1384,7 +1395,7 @@ static int tb_start(struct tb *tb) + /* 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->root_switch); ++ tb_discover_tunnels(tb); + /* + * If the boot firmware did not create USB 3.x tunnels create them + * now for the whole topology. +@@ -1444,6 +1455,8 @@ static int tb_resume_noirq(struct tb *tb + { + struct tb_cm *tcm = tb_priv(tb); + struct tb_tunnel *tunnel, *n; ++ unsigned int usb3_delay = 0; ++ LIST_HEAD(tunnels); + + tb_dbg(tb, "resuming...\n"); + +@@ -1454,8 +1467,31 @@ static int tb_resume_noirq(struct tb *tb + tb_free_invalid_tunnels(tb); + tb_free_unplugged_children(tb->root_switch); + tb_restore_children(tb->root_switch); +- list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list) ++ ++ /* ++ * If we get here from suspend to disk the boot firmware or the ++ * restore kernel might have created tunnels of its own. Since ++ * we cannot be sure they are usable for us we find and tear ++ * them down. ++ */ ++ tb_switch_discover_tunnels(tb->root_switch, &tunnels, false); ++ list_for_each_entry_safe_reverse(tunnel, n, &tunnels, list) { ++ if (tb_tunnel_is_usb3(tunnel)) ++ usb3_delay = 500; ++ tb_tunnel_deactivate(tunnel); ++ tb_tunnel_free(tunnel); ++ } ++ ++ /* Re-create our tunnels now */ ++ list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list) { ++ /* USB3 requires delay before it can be re-activated */ ++ if (tb_tunnel_is_usb3(tunnel)) { ++ msleep(usb3_delay); ++ /* Only need to do it once */ ++ usb3_delay = 0; ++ } + tb_tunnel_restart(tunnel); ++ } + if (!list_empty(&tcm->tunnel_list)) { + /* + * the pcie links need some time to get going. +--- a/drivers/thunderbolt/tb.h ++++ b/drivers/thunderbolt/tb.h +@@ -354,6 +354,7 @@ enum tb_path_port { + * when deactivating this path + * @hops: Path hops + * @path_length: How many hops the path uses ++ * @alloc_hopid: Does this path consume port HopID + * + * A path consists of a number of hops (see &struct tb_path_hop). To + * establish a PCIe tunnel two paths have to be created between the two +@@ -374,6 +375,7 @@ struct tb_path { + bool clear_fc; + struct tb_path_hop *hops; + int path_length; ++ bool alloc_hopid; + }; + + /* HopIDs 0-7 are reserved by the Thunderbolt protocol */ +@@ -957,7 +959,8 @@ int tb_dp_port_enable(struct tb_port *po + + struct tb_path *tb_path_discover(struct tb_port *src, int src_hopid, + struct tb_port *dst, int dst_hopid, +- struct tb_port **last, const char *name); ++ struct tb_port **last, const char *name, ++ bool alloc_hopid); + struct tb_path *tb_path_alloc(struct tb *tb, struct tb_port *src, int src_hopid, + struct tb_port *dst, int dst_hopid, int link_nr, + const char *name); +--- a/drivers/thunderbolt/tunnel.c ++++ b/drivers/thunderbolt/tunnel.c +@@ -207,12 +207,14 @@ static int tb_pci_init_path(struct tb_pa + * tb_tunnel_discover_pci() - Discover existing PCIe tunnels + * @tb: Pointer to the domain structure + * @down: PCIe downstream adapter ++ * @alloc_hopid: Allocate HopIDs from visited ports + * + * If @down adapter is active, follows the tunnel to the PCIe upstream + * adapter and back. Returns the discovered tunnel or %NULL if there was + * no tunnel. + */ +-struct tb_tunnel *tb_tunnel_discover_pci(struct tb *tb, struct tb_port *down) ++struct tb_tunnel *tb_tunnel_discover_pci(struct tb *tb, struct tb_port *down, ++ bool alloc_hopid) + { + struct tb_tunnel *tunnel; + struct tb_path *path; +@@ -233,7 +235,7 @@ struct tb_tunnel *tb_tunnel_discover_pci + * case. + */ + path = tb_path_discover(down, TB_PCI_HOPID, NULL, -1, +- &tunnel->dst_port, "PCIe Up"); ++ &tunnel->dst_port, "PCIe Up", alloc_hopid); + if (!path) { + /* Just disable the downstream port */ + tb_pci_port_enable(down, false); +@@ -244,7 +246,7 @@ struct tb_tunnel *tb_tunnel_discover_pci + goto err_free; + + path = tb_path_discover(tunnel->dst_port, -1, down, TB_PCI_HOPID, NULL, +- "PCIe Down"); ++ "PCIe Down", alloc_hopid); + if (!path) + goto err_deactivate; + tunnel->paths[TB_PCI_PATH_DOWN] = path; +@@ -761,6 +763,7 @@ static int tb_dp_init_video_path(struct + * tb_tunnel_discover_dp() - Discover existing Display Port tunnels + * @tb: Pointer to the domain structure + * @in: DP in adapter ++ * @alloc_hopid: Allocate HopIDs from visited ports + * + * If @in adapter is active, follows the tunnel to the DP out adapter + * and back. Returns the discovered tunnel or %NULL if there was no +@@ -768,7 +771,8 @@ static int tb_dp_init_video_path(struct + * + * Return: DP tunnel or %NULL if no tunnel found. + */ +-struct tb_tunnel *tb_tunnel_discover_dp(struct tb *tb, struct tb_port *in) ++struct tb_tunnel *tb_tunnel_discover_dp(struct tb *tb, struct tb_port *in, ++ bool alloc_hopid) + { + struct tb_tunnel *tunnel; + struct tb_port *port; +@@ -787,7 +791,7 @@ struct tb_tunnel *tb_tunnel_discover_dp( + tunnel->src_port = in; + + path = tb_path_discover(in, TB_DP_VIDEO_HOPID, NULL, -1, +- &tunnel->dst_port, "Video"); ++ &tunnel->dst_port, "Video", alloc_hopid); + if (!path) { + /* Just disable the DP IN port */ + tb_dp_port_enable(in, false); +@@ -797,14 +801,15 @@ struct tb_tunnel *tb_tunnel_discover_dp( + if (tb_dp_init_video_path(tunnel->paths[TB_DP_VIDEO_PATH_OUT])) + goto err_free; + +- path = tb_path_discover(in, TB_DP_AUX_TX_HOPID, NULL, -1, NULL, "AUX TX"); ++ path = tb_path_discover(in, TB_DP_AUX_TX_HOPID, NULL, -1, NULL, "AUX TX", ++ alloc_hopid); + if (!path) + goto err_deactivate; + tunnel->paths[TB_DP_AUX_PATH_OUT] = path; + tb_dp_init_aux_path(tunnel->paths[TB_DP_AUX_PATH_OUT]); + + path = tb_path_discover(tunnel->dst_port, -1, in, TB_DP_AUX_RX_HOPID, +- &port, "AUX RX"); ++ &port, "AUX RX", alloc_hopid); + if (!path) + goto err_deactivate; + tunnel->paths[TB_DP_AUX_PATH_IN] = path; +@@ -1344,12 +1349,14 @@ static void tb_usb3_init_path(struct tb_ + * tb_tunnel_discover_usb3() - Discover existing USB3 tunnels + * @tb: Pointer to the domain structure + * @down: USB3 downstream adapter ++ * @alloc_hopid: Allocate HopIDs from visited ports + * + * If @down adapter is active, follows the tunnel to the USB3 upstream + * adapter and back. Returns the discovered tunnel or %NULL if there was + * no tunnel. + */ +-struct tb_tunnel *tb_tunnel_discover_usb3(struct tb *tb, struct tb_port *down) ++struct tb_tunnel *tb_tunnel_discover_usb3(struct tb *tb, struct tb_port *down, ++ bool alloc_hopid) + { + struct tb_tunnel *tunnel; + struct tb_path *path; +@@ -1370,7 +1377,7 @@ struct tb_tunnel *tb_tunnel_discover_usb + * case. + */ + path = tb_path_discover(down, TB_USB3_HOPID, NULL, -1, +- &tunnel->dst_port, "USB3 Down"); ++ &tunnel->dst_port, "USB3 Down", alloc_hopid); + if (!path) { + /* Just disable the downstream port */ + tb_usb3_port_enable(down, false); +@@ -1380,7 +1387,7 @@ struct tb_tunnel *tb_tunnel_discover_usb + tb_usb3_init_path(tunnel->paths[TB_USB3_PATH_DOWN]); + + path = tb_path_discover(tunnel->dst_port, -1, down, TB_USB3_HOPID, NULL, +- "USB3 Up"); ++ "USB3 Up", alloc_hopid); + if (!path) + goto err_deactivate; + tunnel->paths[TB_USB3_PATH_UP] = path; +--- a/drivers/thunderbolt/tunnel.h ++++ b/drivers/thunderbolt/tunnel.h +@@ -64,10 +64,12 @@ struct tb_tunnel { + int allocated_down; + }; + +-struct tb_tunnel *tb_tunnel_discover_pci(struct tb *tb, struct tb_port *down); ++struct tb_tunnel *tb_tunnel_discover_pci(struct tb *tb, struct tb_port *down, ++ bool alloc_hopid); + struct tb_tunnel *tb_tunnel_alloc_pci(struct tb *tb, struct tb_port *up, + struct tb_port *down); +-struct tb_tunnel *tb_tunnel_discover_dp(struct tb *tb, struct tb_port *in); ++struct tb_tunnel *tb_tunnel_discover_dp(struct tb *tb, struct tb_port *in, ++ bool alloc_hopid); + struct tb_tunnel *tb_tunnel_alloc_dp(struct tb *tb, struct tb_port *in, + struct tb_port *out, int link_nr, + int max_up, int max_down); +@@ -77,7 +79,8 @@ struct tb_tunnel *tb_tunnel_alloc_dma(st + int receive_ring); + bool tb_tunnel_match_dma(const struct tb_tunnel *tunnel, int transmit_path, + int transmit_ring, int receive_path, int receive_ring); +-struct tb_tunnel *tb_tunnel_discover_usb3(struct tb *tb, struct tb_port *down); ++struct tb_tunnel *tb_tunnel_discover_usb3(struct tb *tb, struct tb_port *down, ++ bool alloc_hopid); + struct tb_tunnel *tb_tunnel_alloc_usb3(struct tb *tb, struct tb_port *up, + struct tb_port *down, int max_up, + int max_down);