Received: by 2002:ac0:8c8e:0:0:0:0:0 with SMTP id r14csp596642ima; Wed, 6 Feb 2019 05:24:42 -0800 (PST) X-Google-Smtp-Source: AHgI3IakdMkGHBfpcClvACRCGPcx+c6zGwdVxZZCPbIteI+JQ+3juLJEozO3wDsAgUTz7A4pnq2y X-Received: by 2002:a17:902:2867:: with SMTP id e94mr10877791plb.264.1549459482287; Wed, 06 Feb 2019 05:24:42 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1549459482; cv=none; d=google.com; s=arc-20160816; b=ULsxpPrCol/oRG861/VFE2AyMSKokXNHkgc59kBgHuX5lr6TuA02vyZydnWjppjTqN jm9i6ddMatH5jYCN3rkv3PmURrMOglTUfHX+burFTtEdRDl2pPiKYaXap2DxkLktae7+ zBFwbe95lOSU3BxZ/9gKKvORPNf1UDjsWyXC0qT7rGTH9BUd6yHbxI+rW1rt4lKmGow7 RqI428wWj5jmXIZubaTk/VbtkODYGr5YfkhDuVmHksHaAIJ+l7ir+N151QK0jDplnsV4 NRUyQ12df5GTBH0kEk8h6M+6LRCtyewqx+fEEL1n9589m0f0k9IgxuhByG1LWgQMPs2p Mftg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=QG1ePslezRe5oyhdPg+HcqDoLszEkZ7ptmt4LPGx6yk=; b=BIPlub4hcLlKd+obix6gcfqktudtNWDnHAGrxv+y/j/UalmGIod6CAxY0FAuZpBCQo b/JEx7o9C5jF4jaxUPBKU6ADkLqJbOezX/3GFCFFWdz72UgrtH5PER6NBS56UjFhWkGe Iqrn7rvLrYPezmu0eJInObqozfhmHGmWSGb+nxvJece+Phfe3gOpMkjwUSJllNT88Eo7 R7ABjQARYeQGa+OVxa6vvn10PaJ1EnUfAo5dosk9SN8hxeEQLaI5tSte3YQLvsaqoG4r nFj6hb0N4bR1CdrTjBUgxfvdtN95vODSQurIYB5OviR1skgvpLLn+/lmMdGaInJ6x2M5 L00A== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id d3si6292174pla.122.2019.02.06.05.24.26; Wed, 06 Feb 2019 05:24:42 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730902AbfBFNWO (ORCPT + 99 others); Wed, 6 Feb 2019 08:22:14 -0500 Received: from mga12.intel.com ([192.55.52.136]:18600 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730373AbfBFNRr (ORCPT ); Wed, 6 Feb 2019 08:17:47 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga106.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 06 Feb 2019 05:17:46 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.58,340,1544515200"; d="scan'208";a="114136153" Received: from black.fi.intel.com ([10.237.72.28]) by orsmga006.jf.intel.com with ESMTP; 06 Feb 2019 05:17:43 -0800 Received: by black.fi.intel.com (Postfix, from userid 1001) id 12DDE9F; Wed, 6 Feb 2019 15:17:39 +0200 (EET) From: Mika Westerberg To: linux-kernel@vger.kernel.org Cc: Michael Jamet , Yehezkel Bernat , Andreas Noever , Lukas Wunner , "David S . Miller" , Mika Westerberg , Andy Shevchenko , netdev@vger.kernel.org Subject: [PATCH v2 14/28] thunderbolt: Extend tunnel creation to more than 2 adjacent switches Date: Wed, 6 Feb 2019 16:17:24 +0300 Message-Id: <20190206131738.43696-15-mika.westerberg@linux.intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190206131738.43696-1-mika.westerberg@linux.intel.com> References: <20190206131738.43696-1-mika.westerberg@linux.intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Now that we can allocate hop IDs per port on a path, we can take advantage of this and create tunnels covering longer paths than just between two adjacent switches. PCIe actually does not need this as it is always a daisy chain between two adjacent switches but this way we do not need to hard-code creation of the tunnel. Signed-off-by: Mika Westerberg --- drivers/thunderbolt/path.c | 94 ++++++++++++++++++++++++++++++++++-- drivers/thunderbolt/tb.h | 4 +- drivers/thunderbolt/tunnel.c | 54 +++++---------------- 3 files changed, 106 insertions(+), 46 deletions(-) diff --git a/drivers/thunderbolt/path.c b/drivers/thunderbolt/path.c index 48cb15ff4446..122e6a1daf34 100644 --- a/drivers/thunderbolt/path.c +++ b/drivers/thunderbolt/path.c @@ -31,23 +31,97 @@ static void tb_dump_hop(struct tb_port *port, struct tb_regs_hop *hop) } /** - * tb_path_alloc() - allocate a thunderbolt path + * tb_path_alloc() - allocate a thunderbolt path between two ports + * @tb: Domain pointer + * @src: Source port of the path + * @dst: Destination port of the path + * @start_hopid: Hop ID used for the first ingress port in the path + * @end_hopid: Hop ID used for the last egress port in the path (%-1 for + * automatic allocation) + * @link_nr: Preferred link if there are dual links on the path + * + * Creates path between two ports starting with given @start_hopid. Reserves + * hop IDs for each port (they can be different from @start_hopid depending on + * how many hop IDs each port already have reserved). If there are dual + * links on the path, prioritizes using @link_nr. * * Return: Returns a tb_path on success or NULL on failure. */ -struct tb_path *tb_path_alloc(struct tb *tb, int num_hops) +struct tb_path *tb_path_alloc(struct tb *tb, struct tb_port *src, + struct tb_port *dst, int start_hopid, + int end_hopid, int link_nr) { - struct tb_path *path = kzalloc(sizeof(*path), GFP_KERNEL); + struct tb_port *in_port, *out_port; + int in_hopid, out_hopid; + struct tb_path *path; + size_t num_hops; + int i, ret; + + path = kzalloc(sizeof(*path), GFP_KERNEL); if (!path) return NULL; + + i = 0; + tb_for_each_port(in_port, src, dst) + i++; + + /* Each hop takes two ports */ + num_hops = i / 2; + path->hops = kcalloc(num_hops, sizeof(*path->hops), GFP_KERNEL); if (!path->hops) { kfree(path); return NULL; } + + in_hopid = start_hopid; + out_port = NULL; + out_hopid = -1; + + for (i = 0; i < num_hops; i++) { + in_port = tb_port_get_next(src, dst, out_port); + + if (in_port->dual_link_port && in_port->link_nr != link_nr) + in_port = in_port->dual_link_port; + + ret = tb_port_alloc_in_hopid(in_port, in_hopid, -1); + if (ret < 0) + goto err; + in_hopid = ret; + + out_port = tb_port_get_next(src, dst, in_port); + if (!out_port) + goto err; + + if (out_port->dual_link_port && out_port->link_nr != link_nr) + out_port = out_port->dual_link_port; + + if (end_hopid && i == num_hops - 1) + ret = tb_port_alloc_out_hopid(out_port, end_hopid, + end_hopid); + else + ret = tb_port_alloc_out_hopid(out_port, -1, -1); + + if (ret < 0) + goto err; + out_hopid = ret; + + path->hops[i].in_hop_index = in_hopid; + path->hops[i].in_port = in_port; + path->hops[i].in_counter_index = -1; + path->hops[i].out_port = out_port; + path->hops[i].next_hop_index = out_hopid; + + in_hopid = out_hopid; + } + path->tb = tb; path->path_length = num_hops; return path; + +err: + tb_path_free(path); + return NULL; } /** @@ -55,10 +129,24 @@ struct tb_path *tb_path_alloc(struct tb *tb, int num_hops) */ void tb_path_free(struct tb_path *path) { + int i; + if (path->activated) { tb_WARN(path->tb, "trying to free an activated path\n") return; } + + 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); + } + kfree(path->hops); kfree(path); } diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h index 683725915ff7..0e4d9088faf6 100644 --- a/drivers/thunderbolt/tb.h +++ b/drivers/thunderbolt/tb.h @@ -459,7 +459,9 @@ int tb_port_find_cap(struct tb_port *port, enum tb_port_cap cap); int tb_pci_port_enable(struct tb_port *port, bool enable); -struct tb_path *tb_path_alloc(struct tb *tb, int num_hops); +struct tb_path *tb_path_alloc(struct tb *tb, struct tb_port *src, + struct tb_port *dst, int start_hopid, + int end_hopid, int link_nr); void tb_path_free(struct tb_path *path); int tb_path_activate(struct tb_path *path); void tb_path_deactivate(struct tb_path *path); diff --git a/drivers/thunderbolt/tunnel.c b/drivers/thunderbolt/tunnel.c index 20ce28276f7a..cdf9ca1c043e 100644 --- a/drivers/thunderbolt/tunnel.c +++ b/drivers/thunderbolt/tunnel.c @@ -12,6 +12,9 @@ #include "tunnel.h" #include "tb.h" +/* PCIe adapters use always hop ID of 8 for both directions */ +#define TB_PCI_HOPID 8 + #define TB_PCI_PATH_DOWN 0 #define TB_PCI_PATH_UP 1 @@ -86,21 +89,13 @@ static void tb_pci_init_path(struct tb_path *path) * Allocate a PCI tunnel. The ports must be of type TB_TYPE_PCIE_UP and * TB_TYPE_PCIE_DOWN. * - * Currently only paths consisting of two hops are supported (that is the - * ports must be on "adjacent" switches). - * - * The paths are hard-coded to use hop 8 (the only working hop id available on - * my thunderbolt devices). Therefore at most ONE path per device may be - * activated. - * * Return: Returns a tb_tunnel on success or NULL on failure. */ struct tb_tunnel *tb_tunnel_alloc_pci(struct tb *tb, struct tb_port *up, struct tb_port *down) { - struct tb_path *path_to_up; - struct tb_path *path_to_down; struct tb_tunnel *tunnel; + struct tb_path *path; tunnel = tb_tunnel_alloc(tb, 2); if (!tunnel) @@ -110,46 +105,21 @@ struct tb_tunnel *tb_tunnel_alloc_pci(struct tb *tb, struct tb_port *up, tunnel->src_port = down; tunnel->dst_port = up; - path_to_up = tb_path_alloc(tb, 2); - if (!path_to_up) { + path = tb_path_alloc(tb, down, up, TB_PCI_HOPID, -1, 0); + if (!path) { tb_tunnel_free(tunnel); return NULL; } - tunnel->paths[TB_PCI_PATH_UP] = path_to_up; + tb_pci_init_path(path); + tunnel->paths[TB_PCI_PATH_UP] = path; - path_to_down = tb_path_alloc(tb, 2); - if (!path_to_down) { + path = tb_path_alloc(tb, up, down, TB_PCI_HOPID, -1, 0); + if (!path) { tb_tunnel_free(tunnel); return NULL; } - tunnel->paths[TB_PCI_PATH_DOWN] = path_to_down; - - tb_pci_init_path(path_to_up); - tb_pci_init_path(path_to_down); - - path_to_up->hops[0].in_port = down; - path_to_up->hops[0].in_hop_index = 8; - path_to_up->hops[0].in_counter_index = -1; - path_to_up->hops[0].out_port = tb_upstream_port(up->sw)->remote; - path_to_up->hops[0].next_hop_index = 8; - - path_to_up->hops[1].in_port = tb_upstream_port(up->sw); - path_to_up->hops[1].in_hop_index = 8; - path_to_up->hops[1].in_counter_index = -1; - path_to_up->hops[1].out_port = up; - path_to_up->hops[1].next_hop_index = 8; - - path_to_down->hops[0].in_port = up; - path_to_down->hops[0].in_hop_index = 8; - path_to_down->hops[0].in_counter_index = -1; - path_to_down->hops[0].out_port = tb_upstream_port(up->sw); - path_to_down->hops[0].next_hop_index = 8; - - path_to_down->hops[1].in_port = tb_upstream_port(up->sw)->remote; - path_to_down->hops[1].in_hop_index = 8; - path_to_down->hops[1].in_counter_index = -1; - path_to_down->hops[1].out_port = down; - path_to_down->hops[1].next_hop_index = 8; + tb_pci_init_path(path); + tunnel->paths[TB_PCI_PATH_DOWN] = path; return tunnel; } -- 2.20.1