linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Mika Westerberg <mika.westerberg@linux.intel.com>
To: linux-kernel@vger.kernel.org
Cc: Michael Jamet <michael.jamet@intel.com>,
	Yehezkel Bernat <YehezkelShB@gmail.com>,
	Andreas Noever <andreas.noever@gmail.com>,
	Lukas Wunner <lukas@wunner.de>,
	"David S . Miller" <davem@davemloft.net>,
	Andy Shevchenko <andriy.shevchenko@linux.intel.com>,
	Christian Kellner <ckellner@redhat.com>,
	Mario.Limonciello@dell.com,
	Mika Westerberg <mika.westerberg@linux.intel.com>,
	netdev@vger.kernel.org
Subject: [PATCH v3 30/36] thunderbolt: Add support for DMA tunnels
Date: Thu, 28 Mar 2019 15:36:27 +0300	[thread overview]
Message-ID: <20190328123633.42882-31-mika.westerberg@linux.intel.com> (raw)
In-Reply-To: <20190328123633.42882-1-mika.westerberg@linux.intel.com>

In addition to PCIe and Display Port tunnels it is also possible to
create tunnels that forward DMA traffic from the host interface adapter
(NHI) to a NULL port that is connected to another domain through a
Thunderbolt cable. These tunnels can be used to carry software messages
such as networking packets.

To support this we introduce another tunnel type (TB_TUNNEL_DMA) that
supports paths from NHI to NULL port and back.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
 drivers/thunderbolt/path.c    | 22 +++++++--
 drivers/thunderbolt/switch.c  | 22 +++++++++
 drivers/thunderbolt/tb.h      |  2 +
 drivers/thunderbolt/tb_regs.h |  3 ++
 drivers/thunderbolt/tunnel.c  | 93 ++++++++++++++++++++++++++++++++++-
 drivers/thunderbolt/tunnel.h  | 10 ++++
 6 files changed, 147 insertions(+), 5 deletions(-)

diff --git a/drivers/thunderbolt/path.c b/drivers/thunderbolt/path.c
index 9df79548a941..d06fe8bf8872 100644
--- a/drivers/thunderbolt/path.c
+++ b/drivers/thunderbolt/path.c
@@ -341,7 +341,8 @@ static void __tb_path_deallocate_nfc(struct tb_path *path, int first_hop)
 	}
 }
 
-static int __tb_path_deactivate_hop(struct tb_port *port, int hop_index)
+static int __tb_path_deactivate_hop(struct tb_port *port, int hop_index,
+				    bool clear_fc)
 {
 	struct tb_regs_hop hop;
 	ktime_t timeout;
@@ -372,8 +373,20 @@ static int __tb_path_deactivate_hop(struct tb_port *port, int hop_index)
 		if (ret)
 			return ret;
 
-		if (!hop.pending)
+		if (!hop.pending) {
+			if (clear_fc) {
+				/* Clear flow control */
+				hop.ingress_fc = 0;
+				hop.egress_fc = 0;
+				hop.ingress_shared_buffer = 0;
+				hop.egress_shared_buffer = 0;
+
+				return tb_port_write(port, &hop, TB_CFG_HOPS,
+						     2 * hop_index, 2);
+			}
+
 			return 0;
+		}
 
 		usleep_range(10, 20);
 	} while (ktime_before(ktime_get(), timeout));
@@ -387,7 +400,8 @@ static void __tb_path_deactivate_hops(struct tb_path *path, int first_hop)
 
 	for (i = first_hop; i < path->path_length; i++) {
 		res = __tb_path_deactivate_hop(path->hops[i].in_port,
-					       path->hops[i].in_hop_index);
+					       path->hops[i].in_hop_index,
+					       path->clear_fc);
 		if (res)
 			tb_port_warn(path->hops[i].in_port,
 				     "hop deactivation failed for hop %d, index %d\n",
@@ -462,7 +476,7 @@ int tb_path_activate(struct tb_path *path)
 
 		/* If it is left active deactivate it first */
 		__tb_path_deactivate_hop(path->hops[i].in_port,
-				path->hops[i].in_hop_index);
+				path->hops[i].in_hop_index, path->clear_fc);
 
 		/* dword 0 */
 		hop.next_hop = path->hops[i].next_hop_index;
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index 1de1afa24182..ecf53d986a5c 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -555,6 +555,28 @@ int tb_port_add_nfc_credits(struct tb_port *port, int credits)
 			     TB_CFG_PORT, 4, 1);
 }
 
+/**
+ * tb_port_set_initial_credits() - Set initial port link credits allocated
+ * @port: Port to set the initial credits
+ * @credits: Number of credits to to allocate
+ *
+ * Set initial credits value to be used for ingress shared buffering.
+ */
+int tb_port_set_initial_credits(struct tb_port *port, u32 credits)
+{
+	u32 data;
+	int ret;
+
+	ret = tb_port_read(port, &data, TB_CFG_PORT, 5, 1);
+	if (ret)
+		return ret;
+
+	data &= ~TB_PORT_LCA_MASK;
+	data |= (credits << TB_PORT_LCA_SHIFT) & TB_PORT_LCA_MASK;
+
+	return tb_port_write(port, &data, TB_CFG_PORT, 5, 1);
+}
+
 /**
  * tb_port_clear_counter() - clear a counter in TB_CFG_COUNTER
  *
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
index 19bdeeaf1d18..ca53ec145e27 100644
--- a/drivers/thunderbolt/tb.h
+++ b/drivers/thunderbolt/tb.h
@@ -196,6 +196,7 @@ struct tb_path {
 	int weight:4;
 	bool drop_packages;
 	bool activated;
+	bool clear_fc;
 	struct tb_path_hop *hops;
 	int path_length; /* number of hops */
 };
@@ -553,6 +554,7 @@ static inline bool tb_switch_is_fr(const struct tb_switch *sw)
 
 int tb_wait_for_port(struct tb_port *port, bool wait_if_unplugged);
 int tb_port_add_nfc_credits(struct tb_port *port, int credits);
+int tb_port_set_initial_credits(struct tb_port *port, u32 credits);
 int tb_port_clear_counter(struct tb_port *port, int counter);
 int tb_port_alloc_in_hopid(struct tb_port *port, int hopid, int max_hopid);
 void tb_port_release_in_hopid(struct tb_port *port, int hopid);
diff --git a/drivers/thunderbolt/tb_regs.h b/drivers/thunderbolt/tb_regs.h
index 3ce705184e2c..deb9d4a977b9 100644
--- a/drivers/thunderbolt/tb_regs.h
+++ b/drivers/thunderbolt/tb_regs.h
@@ -215,6 +215,9 @@ struct tb_regs_port_header {
 #define TB_PORT_NFC_CREDITS_MASK	GENMASK(19, 0)
 #define TB_PORT_MAX_CREDITS_SHIFT	20
 #define TB_PORT_MAX_CREDITS_MASK	GENMASK(26, 20)
+/* DWORD 5 */
+#define TB_PORT_LCA_SHIFT		22
+#define TB_PORT_LCA_MASK		GENMASK(28, 22)
 
 /* Display Port adapter registers */
 
diff --git a/drivers/thunderbolt/tunnel.c b/drivers/thunderbolt/tunnel.c
index 0bc6639c6e74..9f9b26b12d0a 100644
--- a/drivers/thunderbolt/tunnel.c
+++ b/drivers/thunderbolt/tunnel.c
@@ -27,7 +27,10 @@
 #define TB_DP_AUX_PATH_OUT		1
 #define TB_DP_AUX_PATH_IN		2
 
-static const char * const tb_tunnel_names[] = { "PCI", "DP" };
+#define TB_DMA_PATH_OUT			0
+#define TB_DMA_PATH_IN			1
+
+static const char * const tb_tunnel_names[] = { "PCI", "DP", "DMA" };
 
 #define __TB_TUNNEL_PRINT(level, tunnel, fmt, arg...)                   \
 	do {                                                            \
@@ -471,6 +474,94 @@ struct tb_tunnel *tb_tunnel_alloc_dp(struct tb *tb, struct tb_port *in,
 	return NULL;
 }
 
+static u32 tb_dma_credits(struct tb_port *nhi)
+{
+	u32 max_credits;
+
+	max_credits = (nhi->config.nfc_credits & TB_PORT_MAX_CREDITS_MASK) >>
+		TB_PORT_MAX_CREDITS_SHIFT;
+	return min(max_credits, 13U);
+}
+
+static int tb_dma_activate(struct tb_tunnel *tunnel, bool active)
+{
+	struct tb_port *nhi = tunnel->src_port;
+	u32 credits;
+
+	credits = active ? tb_dma_credits(nhi) : 0;
+	return tb_port_set_initial_credits(nhi, credits);
+}
+
+static void tb_dma_init_path(struct tb_path *path, unsigned int isb,
+			     unsigned int efc, u32 credits)
+{
+	int i;
+
+	path->egress_fc_enable = efc;
+	path->ingress_fc_enable = TB_PATH_ALL;
+	path->egress_shared_buffer = TB_PATH_NONE;
+	path->ingress_shared_buffer = isb;
+	path->priority = 5;
+	path->weight = 1;
+	path->clear_fc = true;
+
+	for (i = 0; i < path->path_length; i++)
+		path->hops[i].initial_credits = credits;
+}
+
+/**
+ * tb_tunnel_alloc_dma() - allocate a DMA tunnel
+ * @tb: Pointer to the domain structure
+ * @nhi: Host controller port
+ * @dst: Destination null port which the other domain is connected to
+ * @transmit_ring: NHI ring number used to send packets towards the
+ *		   other domain
+ * @transmit_path: HopID used for transmitting packets
+ * @receive_ring: NHI ring number used to receive packets from the
+ *		  other domain
+ * @reveive_path: HopID used for receiving packets
+ *
+ * Return: Returns a tb_tunnel on success or NULL on failure.
+ */
+struct tb_tunnel *tb_tunnel_alloc_dma(struct tb *tb, struct tb_port *nhi,
+				      struct tb_port *dst, int transmit_ring,
+				      int transmit_path, int receive_ring,
+				      int receive_path)
+{
+	struct tb_tunnel *tunnel;
+	struct tb_path *path;
+	u32 credits;
+
+	tunnel = tb_tunnel_alloc(tb, 2, TB_TUNNEL_DMA);
+	if (!tunnel)
+		return NULL;
+
+	tunnel->activate = tb_dma_activate;
+	tunnel->src_port = nhi;
+	tunnel->dst_port = dst;
+
+	credits = tb_dma_credits(nhi);
+
+	path = tb_path_alloc(tb, dst, receive_path, nhi, receive_ring, 0, "DMA RX");
+	if (!path) {
+		tb_tunnel_free(tunnel);
+		return NULL;
+	}
+	tb_dma_init_path(path, TB_PATH_NONE, TB_PATH_SOURCE | TB_PATH_INTERNAL,
+			 credits);
+	tunnel->paths[TB_DMA_PATH_IN] = path;
+
+	path = tb_path_alloc(tb, nhi, transmit_ring, dst, transmit_path, 0, "DMA TX");
+	if (!path) {
+		tb_tunnel_free(tunnel);
+		return NULL;
+	}
+	tb_dma_init_path(path, TB_PATH_SOURCE, TB_PATH_ALL, credits);
+	tunnel->paths[TB_DMA_PATH_OUT] = path;
+
+	return tunnel;
+}
+
 /**
  * tb_tunnel_free() - free a tunnel
  * @tunnel: Tunnel to be freed
diff --git a/drivers/thunderbolt/tunnel.h b/drivers/thunderbolt/tunnel.h
index 0373779f43ba..c68bbcd3a62c 100644
--- a/drivers/thunderbolt/tunnel.h
+++ b/drivers/thunderbolt/tunnel.h
@@ -14,6 +14,7 @@
 enum tb_tunnel_type {
 	TB_TUNNEL_PCI,
 	TB_TUNNEL_DP,
+	TB_TUNNEL_DMA,
 };
 
 /**
@@ -47,6 +48,10 @@ struct tb_tunnel *tb_tunnel_alloc_pci(struct tb *tb, struct tb_port *up,
 struct tb_tunnel *tb_tunnel_discover_dp(struct tb *tb, struct tb_port *in);
 struct tb_tunnel *tb_tunnel_alloc_dp(struct tb *tb, struct tb_port *in,
 				     struct tb_port *out);
+struct tb_tunnel *tb_tunnel_alloc_dma(struct tb *tb, struct tb_port *nhi,
+				      struct tb_port *dst, int transmit_ring,
+				      int transmit_path, int receive_ring,
+				      int receive_path);
 
 void tb_tunnel_free(struct tb_tunnel *tunnel);
 int tb_tunnel_activate(struct tb_tunnel *tunnel);
@@ -64,5 +69,10 @@ static inline bool tb_tunnel_is_dp(const struct tb_tunnel *tunnel)
 	return tunnel->type == TB_TUNNEL_DP;
 }
 
+static inline bool tb_tunnel_is_dma(const struct tb_tunnel *tunnel)
+{
+	return tunnel->type == TB_TUNNEL_DMA;
+}
+
 #endif
 
-- 
2.20.1


  parent reply	other threads:[~2019-03-28 12:37 UTC|newest]

Thread overview: 52+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-03-28 12:35 [PATCH v3 00/36] thunderbolt: Software connection manager improvements Mika Westerberg
2019-03-28 12:35 ` [PATCH v3 01/36] net: thunderbolt: Unregister ThunderboltIP protocol handler when suspending Mika Westerberg
2019-03-28 12:35 ` [PATCH v3 02/36] thunderbolt: Remove unused work field in struct tb_switch Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 03/36] thunderbolt: Drop duplicated get_switch_by_route() Mika Westerberg
2019-03-30  9:56   ` Lukas Wunner
2019-03-28 12:36 ` [PATCH v3 04/36] thunderbolt: Block reads and writes if switch is unplugged Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 05/36] thunderbolt: Take domain lock in switch sysfs attribute callbacks Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 06/36] thunderbolt: Do not allocate switch if depth is greater than 6 Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 07/36] thunderbolt: Enable TMU access when accessing port space on legacy devices Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 08/36] thunderbolt: Add dummy read after port capability list walk on Light Ridge Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 09/36] thunderbolt: Move LC specific functionality into a separate file Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 10/36] thunderbolt: Configure lanes when switch is initialized Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 11/36] thunderbolt: Set sleep bit when suspending switch Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 12/36] thunderbolt: Properly disable path Mika Westerberg
2019-03-31 15:24   ` Lukas Wunner
2019-03-28 12:36 ` [PATCH v3 13/36] thunderbolt: Cache adapter specific capability offset into struct port Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 14/36] thunderbolt: Rename tunnel_pci to tunnel Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 15/36] thunderbolt: Generalize tunnel creation functionality Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 16/36] thunderbolt: Add functions for allocating and releasing HopIDs Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 17/36] thunderbolt: Assign remote for both ports in case of dual link Mika Westerberg
2019-04-04 19:28   ` Lukas Wunner
2019-03-28 12:36 ` [PATCH v3 18/36] thunderbolt: Add helper function to iterate from one port to another Mika Westerberg
2019-04-04 19:39   ` Lukas Wunner
2019-03-28 12:36 ` [PATCH v3 19/36] thunderbolt: Extend tunnel creation to more than 2 adjacent switches Mika Westerberg
2019-04-07 16:54   ` Lukas Wunner
2019-04-08  7:35     ` Mika Westerberg
2019-04-08  8:53       ` Lukas Wunner
2019-04-08  9:07         ` Mika Westerberg
2019-04-08  9:49           ` Lukas Wunner
2019-04-08 10:34             ` Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 20/36] thunderbolt: Deactivate all paths before restarting them Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 21/36] thunderbolt: Discover preboot PCIe paths the boot firmware established Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 22/36] thunderbolt: Add support for full PCIe daisy chains Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 23/36] thunderbolt: Scan only valid NULL adapter ports in hotplug Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 24/36] thunderbolt: Generalize port finding routines to support all port types Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 25/36] thunderbolt: Rework NFC credits handling Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 26/36] thunderbolt: Add support for Display Port tunnels Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 27/36] thunderbolt: Do not tear down tunnels when driver is unloaded Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 28/36] thunderbolt: Run tb_xdp_handle_request() in system workqueue Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 29/36] thunderbolt: Add XDomain UUID exchange support Mika Westerberg
2019-03-28 12:36 ` Mika Westerberg [this message]
2019-03-28 12:36 ` [PATCH v3 31/36] thunderbolt: Make tb_switch_alloc() return ERR_PTR() Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 32/36] thunderbolt: Add support for XDomain connections Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 33/36] thunderbolt: Make __TB_[SW|PORT]_PRINT take const parameters Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 34/36] thunderbolt: Make rest of the logging to happen at debug level Mika Westerberg
2019-03-28 15:39   ` Joe Perches
2019-03-28 12:36 ` [PATCH v3 35/36] thunderbolt: Reword output of tb_dump_hop() Mika Westerberg
2019-03-28 12:36 ` [PATCH v3 36/36] thunderbolt: Start firmware on Titan Ridge Apple systems Mika Westerberg
2019-03-28 15:17 ` [PATCH v3 00/36] thunderbolt: Software connection manager improvements Mario.Limonciello
2019-03-28 16:56   ` Mika Westerberg
2019-04-01  4:31     ` Lukas Wunner
2019-04-01  7:44       ` Mika Westerberg

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190328123633.42882-31-mika.westerberg@linux.intel.com \
    --to=mika.westerberg@linux.intel.com \
    --cc=Mario.Limonciello@dell.com \
    --cc=YehezkelShB@gmail.com \
    --cc=andreas.noever@gmail.com \
    --cc=andriy.shevchenko@linux.intel.com \
    --cc=ckellner@redhat.com \
    --cc=davem@davemloft.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lukas@wunner.de \
    --cc=michael.jamet@intel.com \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).