]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.15-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 11 Nov 2022 08:53:10 +0000 (09:53 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 11 Nov 2022 08:53:10 +0000 (09:53 +0100)
added patches:
thunderbolt-add-dp-out-resource-when-dp-tunnel-is-discovered.patch
thunderbolt-tear-down-existing-tunnels-when-resuming-from-hibernate.patch

queue-5.15/thunderbolt-add-dp-out-resource-when-dp-tunnel-is-discovered.patch [new file with mode: 0644]
queue-5.15/thunderbolt-tear-down-existing-tunnels-when-resuming-from-hibernate.patch [new file with mode: 0644]

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 (file)
index 0000000..3d2d6a0
--- /dev/null
@@ -0,0 +1,70 @@
+From b60e31bf18a7064032dbcb73dcb5b58f8a00a110 Mon Sep 17 00:00:00 2001
+From: Sanjay R Mehta <sanju.mehta@amd.com>
+Date: Thu, 4 Aug 2022 05:48:38 -0500
+Subject: thunderbolt: Add DP OUT resource when DP tunnel is discovered
+
+From: Sanjay R Mehta <sanju.mehta@amd.com>
+
+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 <sanju.mehta@amd.com>
+Signed-off-by: Basavaraj Natikar <Basavaraj.Natikar@amd.com>
+Tested-by: Renjith Pananchikkal <Renjith.Pananchikkal@amd.com>
+Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Cc: "Limonciello, Mario" <Mario.Limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..e5f871b
--- /dev/null
@@ -0,0 +1,418 @@
+From 43bddb26e20af916249b5318200cfe1734c1700c Mon Sep 17 00:00:00 2001
+From: Mika Westerberg <mika.westerberg@linux.intel.com>
+Date: Sun, 14 Nov 2021 17:20:59 +0200
+Subject: thunderbolt: Tear down existing tunnels when resuming from hibernate
+
+From: Mika Westerberg <mika.westerberg@linux.intel.com>
+
+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 <mika.westerberg@linux.intel.com>
+Cc: "Limonciello, Mario" <Mario.Limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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);