Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/1032830/?format=api
{ "id": 1032830, "url": "http://patchwork.ozlabs.org/api/patches/1032830/?format=api", "web_url": "http://patchwork.ozlabs.org/project/netdev/patch/20190129150143.12681-17-mika.westerberg@linux.intel.com/", "project": { "id": 7, "url": "http://patchwork.ozlabs.org/api/projects/7/?format=api", "name": "Linux network development", "link_name": "netdev", "list_id": "netdev.vger.kernel.org", "list_email": "netdev@vger.kernel.org", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20190129150143.12681-17-mika.westerberg@linux.intel.com>", "list_archive_url": null, "date": "2019-01-29T15:01:31", "name": "[16/28] thunderbolt: Discover preboot PCIe paths the boot firmware established", "commit_ref": null, "pull_url": null, "state": "not-applicable", "archived": false, "hash": "5e246042fbc3c84597c44240ebd3fcfa01721e91", "submitter": { "id": 14534, "url": "http://patchwork.ozlabs.org/api/people/14534/?format=api", "name": "Mika Westerberg", "email": "mika.westerberg@linux.intel.com" }, "delegate": { "id": 34, "url": "http://patchwork.ozlabs.org/api/users/34/?format=api", "username": "davem", "first_name": "David", "last_name": "Miller", "email": "davem@davemloft.net" }, "mbox": "http://patchwork.ozlabs.org/project/netdev/patch/20190129150143.12681-17-mika.westerberg@linux.intel.com/mbox/", "series": [ { "id": 88859, "url": "http://patchwork.ozlabs.org/api/series/88859/?format=api", "web_url": "http://patchwork.ozlabs.org/project/netdev/list/?series=88859", "date": "2019-01-29T15:01:18", "name": "thunderbolt: Software connection manager improvements", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/88859/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/1032830/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/1032830/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<netdev-owner@vger.kernel.org>", "X-Original-To": "patchwork-incoming-netdev@ozlabs.org", "Delivered-To": "patchwork-incoming-netdev@ozlabs.org", "Authentication-Results": [ "ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=vger.kernel.org\n\t(client-ip=209.132.180.67; helo=vger.kernel.org;\n\tenvelope-from=netdev-owner@vger.kernel.org;\n\treceiver=<UNKNOWN>)", "ozlabs.org; dmarc=none (p=none dis=none)\n\theader.from=linux.intel.com" ], "Received": [ "from vger.kernel.org (vger.kernel.org [209.132.180.67])\n\tby ozlabs.org (Postfix) with ESMTP id 43pqY01zLxz9sMM\n\tfor <patchwork-incoming-netdev@ozlabs.org>;\n\tWed, 30 Jan 2019 02:04:52 +1100 (AEDT)", "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1729107AbfA2PE1 (ORCPT\n\t<rfc822;patchwork-incoming-netdev@ozlabs.org>);\n\tTue, 29 Jan 2019 10:04:27 -0500", "from mga02.intel.com ([134.134.136.20]:34504 \"EHLO mga02.intel.com\"\n\trhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP\n\tid S1728344AbfA2PBx (ORCPT <rfc822;netdev@vger.kernel.org>);\n\tTue, 29 Jan 2019 10:01:53 -0500", "from fmsmga005.fm.intel.com ([10.253.24.32])\n\tby orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t29 Jan 2019 07:01:53 -0800", "from black.fi.intel.com ([10.237.72.28])\n\tby fmsmga005.fm.intel.com with ESMTP; 29 Jan 2019 07:01:50 -0800", "by black.fi.intel.com (Postfix, from userid 1001)\n\tid EED5983A; Tue, 29 Jan 2019 17:01:44 +0200 (EET)" ], "X-Amp-Result": "SKIPPED(no attachment in message)", "X-Amp-File-Uploaded": "False", "X-ExtLoop1": "1", "X-IronPort-AV": "E=Sophos;i=\"5.56,537,1539673200\"; d=\"scan'208\";a=\"315840533\"", "From": "Mika Westerberg <mika.westerberg@linux.intel.com>", "To": "linux-kernel@vger.kernel.org", "Cc": "Michael Jamet <michael.jamet@intel.com>,\n\tYehezkel Bernat <YehezkelShB@gmail.com>,\n\tAndreas Noever <andreas.noever@gmail.com>,\n\tLukas Wunner <lukas@wunner.de>, \"David S . Miller\" <davem@davemloft.net>,\n\tMika Westerberg <mika.westerberg@linux.intel.com>,\n\tAndy Shevchenko <andriy.shevchenko@linux.intel.com>,\n\tnetdev@vger.kernel.org", "Subject": "[PATCH 16/28] thunderbolt: Discover preboot PCIe paths the boot\n\tfirmware established", "Date": "Tue, 29 Jan 2019 18:01:31 +0300", "Message-Id": "<20190129150143.12681-17-mika.westerberg@linux.intel.com>", "X-Mailer": "git-send-email 2.20.1", "In-Reply-To": "<20190129150143.12681-1-mika.westerberg@linux.intel.com>", "References": "<20190129150143.12681-1-mika.westerberg@linux.intel.com>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "Sender": "netdev-owner@vger.kernel.org", "Precedence": "bulk", "List-ID": "<netdev.vger.kernel.org>", "X-Mailing-List": "netdev@vger.kernel.org" }, "content": "In Apple Macs the boot firmware (EFI) connects all devices automatically\nwhen the system is started, before it hands over to the OS. Instead of\nignoring we discover all those PCIe tunnels and record them using our\ninternal structures, just like we do when a device is connected after\nthe OS is already up.\n\nBy doing this we can properly tear down tunnels when devices are\ndisconnected. Also this allows us to resume the existing tunnels after\nsystem suspend/resume cycle.\n\nSigned-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>\n---\n drivers/thunderbolt/path.c | 144 +++++++++++++++++++++++++++++------\n drivers/thunderbolt/switch.c | 14 ++++\n drivers/thunderbolt/tb.c | 35 +++++++++\n drivers/thunderbolt/tb.h | 4 +\n drivers/thunderbolt/tunnel.c | 68 +++++++++++++++++\n drivers/thunderbolt/tunnel.h | 1 +\n 6 files changed, 244 insertions(+), 22 deletions(-)", "diff": "diff --git a/drivers/thunderbolt/path.c b/drivers/thunderbolt/path.c\nindex 122e6a1daf34..ada60d4aa99b 100644\n--- a/drivers/thunderbolt/path.c\n+++ b/drivers/thunderbolt/path.c\n@@ -1,8 +1,9 @@\n // SPDX-License-Identifier: GPL-2.0\n /*\n- * Thunderbolt Cactus Ridge driver - path/tunnel functionality\n+ * Thunderbolt driver - path/tunnel functionality\n *\n * Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com>\n+ * Copyright (C) 2019, Intel Corporation\n */\n \n #include <linux/slab.h>\n@@ -12,6 +13,7 @@\n \n #include \"tb.h\"\n \n+#define MAX_PATH_HOPS\t7\n \n static void tb_dump_hop(struct tb_port *port, struct tb_regs_hop *hop)\n {\n@@ -30,6 +32,124 @@ static void tb_dump_hop(struct tb_port *port, struct tb_regs_hop *hop)\n \t\t hop->unknown1, hop->unknown2, hop->unknown3);\n }\n \n+static struct tb_port *tb_port_remote(struct tb_port *port)\n+{\n+\tstruct tb_port *remote = port->remote;\n+\n+\t/*\n+\t * If we have a dual link, the remote is available through the\n+\t * primary link.\n+\t */\n+\tif (!remote && port->dual_link_port && port->dual_link_port->remote)\n+\t\treturn port->dual_link_port->remote->dual_link_port;\n+\treturn remote;\n+}\n+\n+/**\n+ * tb_path_discover() - Discover a path starting from given hopid\n+ * @port: First input port of a path\n+ * @start_hopid: Starting hop ID of a path\n+ * @last: Last port on a path will be filled here if not %NULL\n+ *\n+ * Follows a path starting from @port and @hopid to the last output port\n+ * of the path. Allocates hop IDs for the visited ports. Call\n+ * tb_path_free() to release the path and allocated hop IDs when the\n+ * path is not needed anymore.\n+ *\n+ * Return: Discovered path on success, %NULL in case of failure\n+ */\n+struct tb_path *tb_path_discover(struct tb_port *port, int start_hopid,\n+\t\t\t\t struct tb_port **last)\n+{\n+\tstruct tb_port *out_port;\n+\tstruct tb_regs_hop hop;\n+\tstruct tb_path *path;\n+\tstruct tb_switch *sw;\n+\tstruct tb_port *p;\n+\tsize_t num_hops;\n+\tint ret, i, h;\n+\n+\tp = port;\n+\th = start_hopid;\n+\n+\tfor (i = 0; p && i < MAX_PATH_HOPS; i++) {\n+\t\tsw = p->sw;\n+\n+\t\tret = tb_port_read(p, &hop, TB_CFG_HOPS, 2 * h, 2);\n+\t\tif (ret) {\n+\t\t\ttb_port_warn(p, \"failed to read path at %d\\n\", h);\n+\t\t\treturn NULL;\n+\t\t}\n+\n+\t\tif (!hop.enable)\n+\t\t\treturn NULL;\n+\n+\t\tout_port = &sw->ports[hop.out_port];\n+\t\tif (last)\n+\t\t\t*last = out_port;\n+\n+\t\th = hop.next_hop;\n+\t\tp = tb_port_remote(out_port);\n+\t}\n+\n+\tnum_hops = i;\n+\tpath = kzalloc(sizeof(*path), GFP_KERNEL);\n+\tif (!path)\n+\t\treturn NULL;\n+\n+\tpath->tb = port->sw->tb;\n+\tpath->path_length = num_hops;\n+\n+\tpath->hops = kcalloc(num_hops, sizeof(*path->hops), GFP_KERNEL);\n+\tif (!path->hops) {\n+\t\tkfree(path);\n+\t\treturn NULL;\n+\t}\n+\n+\tp = port;\n+\th = start_hopid;\n+\n+\tfor (i = 0; i < num_hops; i++) {\n+\t\tint next_hop;\n+\n+\t\tsw = p->sw;\n+\n+\t\tret = tb_port_read(p, &hop, TB_CFG_HOPS, 2 * h, 2);\n+\t\tif (ret) {\n+\t\t\ttb_port_warn(p, \"failed to read path at %d\\n\", h);\n+\t\t\tgoto err;\n+\t\t}\n+\n+\t\tif (tb_port_alloc_in_hopid(p, h, h) < 0)\n+\t\t\tgoto err;\n+\n+\t\tout_port = &sw->ports[hop.out_port];\n+\t\tnext_hop = hop.next_hop;\n+\n+\t\tif (tb_port_alloc_out_hopid(out_port, next_hop, next_hop) < 0) {\n+\t\t\ttb_port_release_in_hopid(p, h);\n+\t\t\tgoto err;\n+\t\t}\n+\n+\t\tpath->hops[i].in_port = p;\n+\t\tpath->hops[i].in_hop_index = h;\n+\t\tpath->hops[i].in_counter_index = -1;\n+\t\tpath->hops[i].out_port = out_port;\n+\t\tpath->hops[i].next_hop_index = next_hop;\n+\n+\t\th = next_hop;\n+\t\tp = tb_port_remote(out_port);\n+\t}\n+\n+\treturn path;\n+\n+err:\n+\ttb_port_warn(port, \"failed to discover path starting at hop %d\\n\",\n+\t\t start_hopid);\n+\ttb_path_free(path);\n+\treturn NULL;\n+}\n+\n /**\n * tb_path_alloc() - allocate a thunderbolt path between two ports\n * @tb: Domain pointer\n@@ -279,30 +399,10 @@ int tb_path_activate(struct tb_path *path)\n \tfor (i = path->path_length - 1; i >= 0; i--) {\n \t\tstruct tb_regs_hop hop = { 0 };\n \n-\t\t/*\n-\t\t * We do (currently) not tear down paths setup by the firmeware.\n-\t\t * If a firmware device is unplugged and plugged in again then\n-\t\t * it can happen that we reuse some of the hops from the (now\n-\t\t * defunct) firmeware path. This causes the hotplug operation to\n-\t\t * fail (the pci device does not show up). Clearing the hop\n-\t\t * before overwriting it fixes the problem.\n-\t\t *\n-\t\t * Should be removed once we discover and tear down firmeware\n-\t\t * paths.\n-\t\t */\n-\t\tres = tb_port_write(path->hops[i].in_port, &hop, TB_CFG_HOPS,\n-\t\t\t\t 2 * path->hops[i].in_hop_index, 2);\n-\t\tif (res) {\n-\t\t\t__tb_path_deactivate_hops(path, i);\n-\t\t\t__tb_path_deallocate_nfc(path, 0);\n-\t\t\tgoto err;\n-\t\t}\n-\n \t\t/* dword 0 */\n \t\thop.next_hop = path->hops[i].next_hop_index;\n \t\thop.out_port = path->hops[i].out_port->port;\n-\t\t/* TODO: figure out why these are good values */\n-\t\thop.initial_credits = (i == path->path_length - 1) ? 16 : 7;\n+\t\thop.initial_credits = path->hops[i].initial_credits;\n \t\thop.unknown1 = 0;\n \t\thop.enable = 1;\n \ndiff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c\nindex d0f9e3a01851..c1bab1bc7150 100644\n--- a/drivers/thunderbolt/switch.c\n+++ b/drivers/thunderbolt/switch.c\n@@ -743,6 +743,20 @@ struct tb_port *tb_port_get_next(struct tb_port *start, struct tb_port *end,\n \treturn next;\n }\n \n+/**\n+ * tb_pci_port_is_enabled() - Is the PCIe adapter port enabled\n+ * @port: PCIe port to check\n+ */\n+bool tb_pci_port_is_enabled(struct tb_port *port)\n+{\n+\tu32 data;\n+\n+\tif (tb_port_read(port, &data, TB_CFG_PORT, port->cap_adap, 1))\n+\t\treturn false;\n+\n+\treturn !!(data & TB_PCI_EN);\n+}\n+\n /**\n * tb_pci_port_enable() - Enable PCIe adapter port\n * @port: PCIe port to enable\ndiff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c\nindex 8986f4a179bd..8acd16c3ada6 100644\n--- a/drivers/thunderbolt/tb.c\n+++ b/drivers/thunderbolt/tb.c\n@@ -29,6 +29,39 @@ struct tb_cm {\n \n /* enumeration & hot plug handling */\n \n+static void tb_discover_tunnels(struct tb_switch *sw)\n+{\n+\tstruct tb *tb = sw->tb;\n+\tstruct tb_cm *tcm = tb_priv(tb);\n+\tstruct tb_port *port;\n+\tint i;\n+\n+\tfor (i = 1; i <= sw->config.max_port_number; i++) {\n+\t\tstruct tb_tunnel *tunnel = NULL;\n+\n+\t\tport = &sw->ports[i];\n+\t\tswitch (port->config.type) {\n+\t\tcase TB_TYPE_PCIE_DOWN:\n+\t\t\ttunnel = tb_tunnel_discover_pci(tb, port);\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\t/* Find and add existing tunnels */\n+\t\tif (tunnel)\n+\t\t\tlist_add_tail(&tunnel->list, &tcm->tunnel_list);\n+\t}\n+\n+\tfor (i = 1; i <= sw->config.max_port_number; i++) {\n+\t\tport = &sw->ports[i];\n+\t\tif (tb_is_upstream_port(port))\n+\t\t\tcontinue;\n+\t\tif (port->remote)\n+\t\t\ttb_discover_tunnels(port->remote->sw);\n+\t}\n+}\n \n static void tb_scan_port(struct tb_port *port);\n \n@@ -393,6 +426,8 @@ static int tb_start(struct tb *tb)\n \n \t/* Full scan to discover devices added before the driver was loaded. */\n \ttb_scan_switch(tb->root_switch);\n+\t/* Find out tunnels created by the boot firmware */\n+\ttb_discover_tunnels(tb->root_switch);\n \ttb_activate_pcie_devices(tb);\n \n \t/* Allow tb_handle_hotplug to progress events */\ndiff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h\nindex ceed33895105..f476c3f0cb9a 100644\n--- a/drivers/thunderbolt/tb.h\n+++ b/drivers/thunderbolt/tb.h\n@@ -166,6 +166,7 @@ struct tb_path_hop {\n \tint in_hop_index;\n \tint in_counter_index; /* write -1 to disable counters for this hop. */\n \tint next_hop_index;\n+\tunsigned int initial_credits;\n };\n \n /**\n@@ -458,8 +459,11 @@ struct tb_port *tb_port_get_next(struct tb_port *start, struct tb_port *end,\n int tb_switch_find_vse_cap(struct tb_switch *sw, enum tb_switch_vse_cap vsec);\n int tb_port_find_cap(struct tb_port *port, enum tb_port_cap cap);\n \n+bool tb_pci_port_is_enabled(struct tb_port *port);\n int tb_pci_port_enable(struct tb_port *port, bool enable);\n \n+struct tb_path *tb_path_discover(struct tb_port *port, int start_hopid,\n+\t\t\t\t struct tb_port **last);\n struct tb_path *tb_path_alloc(struct tb *tb, struct tb_port *src,\n \t\t\t struct tb_port *dst, int start_hopid,\n \t\t\t int end_hopid, int link_nr);\ndiff --git a/drivers/thunderbolt/tunnel.c b/drivers/thunderbolt/tunnel.c\nindex b48c66efe87a..1a5e2aa395c6 100644\n--- a/drivers/thunderbolt/tunnel.c\n+++ b/drivers/thunderbolt/tunnel.c\n@@ -78,6 +78,74 @@ static void tb_pci_init_path(struct tb_path *path)\n \tpath->weight = 1;\n \tpath->drop_packages = 0;\n \tpath->nfc_credits = 0;\n+\tpath->hops[0].initial_credits = 7;\n+\tpath->hops[1].initial_credits = 16;\n+}\n+\n+/**\n+ * tb_tunnel_discover_pci() - Discover existing PCIe tunnels\n+ * @tb: Pointer to the domain structure\n+ * @down: PCIe downstream adapter\n+ *\n+ * If @down adapter is active, follows the tunnel to the PCIe upstream\n+ * adapter and back. Returns the discovered tunnel or %NULL if there was\n+ * no tunnel.\n+ */\n+struct tb_tunnel *tb_tunnel_discover_pci(struct tb *tb, struct tb_port *down)\n+{\n+\tstruct tb_tunnel *tunnel;\n+\tstruct tb_path *path;\n+\n+\tif (!tb_pci_port_is_enabled(down))\n+\t\treturn NULL;\n+\n+\ttunnel = tb_tunnel_alloc(tb, 2);\n+\tif (!tunnel)\n+\t\treturn NULL;\n+\n+\ttunnel->activate = tb_pci_activate;\n+\ttunnel->src_port = down;\n+\n+\tpath = tb_path_discover(down, TB_PCI_HOPID, &tunnel->dst_port);\n+\tif (!path)\n+\t\tgoto err_free;\n+\n+\tif (tunnel->dst_port->config.type != TB_TYPE_PCIE_UP) {\n+\t\ttb_port_warn(tunnel->dst_port,\n+\t\t\t \"path does not end to a PCIe adapter\\n\");\n+\t\tgoto err_free;\n+\t}\n+\n+\ttunnel->paths[TB_PCI_PATH_UP] = path;\n+\n+\tpath = tb_path_discover(tunnel->dst_port, TB_PCI_HOPID, &down);\n+\tif (!path)\n+\t\tgoto err_free;\n+\ttunnel->paths[TB_PCI_PATH_DOWN] = path;\n+\n+\tif (down != tunnel->src_port) {\n+\t\ttb_tunnel_warn(tunnel, \"path is not complete, skipping\\n\");\n+\t\tgoto err_free;\n+\t}\n+\n+\tif (!tb_pci_port_is_enabled(tunnel->dst_port)) {\n+\t\ttb_tunnel_warn(tunnel,\n+\t\t\t \"tunnel is not fully activated, skipping\\n\");\n+\t\tgoto err_free;\n+\t}\n+\n+\t/* Activated by the boot firmware */\n+\ttunnel->paths[TB_PCI_PATH_UP]->activated = true;\n+\ttunnel->paths[TB_PCI_PATH_DOWN]->activated = true;\n+\n+\ttb_pci_init_path(tunnel->paths[TB_PCI_PATH_UP]);\n+\ttb_pci_init_path(tunnel->paths[TB_PCI_PATH_DOWN]);\n+\n+\treturn tunnel;\n+\n+err_free:\n+\ttb_tunnel_free(tunnel);\n+\treturn NULL;\n }\n \n /**\ndiff --git a/drivers/thunderbolt/tunnel.h b/drivers/thunderbolt/tunnel.h\nindex b4e992165e56..7e801a31f9d1 100644\n--- a/drivers/thunderbolt/tunnel.h\n+++ b/drivers/thunderbolt/tunnel.h\n@@ -31,6 +31,7 @@ struct tb_tunnel {\n \tstruct list_head list;\n };\n \n+struct tb_tunnel *tb_tunnel_discover_pci(struct tb *tb, struct tb_port *down);\n struct tb_tunnel *tb_tunnel_alloc_pci(struct tb *tb, struct tb_port *up,\n \t\t\t\t struct tb_port *down);\n void tb_tunnel_free(struct tb_tunnel *tunnel);\n", "prefixes": [ "16/28" ] }