{"id":814985,"url":"http://patchwork.ozlabs.org/api/patches/814985/?format=json","web_url":"http://patchwork.ozlabs.org/project/netdev/patch/20170918153049.44185-9-mika.westerberg@linux.intel.com/","project":{"id":7,"url":"http://patchwork.ozlabs.org/api/projects/7/?format=json","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":"<20170918153049.44185-9-mika.westerberg@linux.intel.com>","list_archive_url":null,"date":"2017-09-18T15:30:41","name":"[08/16] thunderbolt: Add support for frame mode","commit_ref":null,"pull_url":null,"state":"not-applicable","archived":true,"hash":"d0c64d66745dae0548b2d743841c5516c402744a","submitter":{"id":14534,"url":"http://patchwork.ozlabs.org/api/people/14534/?format=json","name":"Mika Westerberg","email":"mika.westerberg@linux.intel.com"},"delegate":{"id":34,"url":"http://patchwork.ozlabs.org/api/users/34/?format=json","username":"davem","first_name":"David","last_name":"Miller","email":"davem@davemloft.net"},"mbox":"http://patchwork.ozlabs.org/project/netdev/patch/20170918153049.44185-9-mika.westerberg@linux.intel.com/mbox/","series":[{"id":3664,"url":"http://patchwork.ozlabs.org/api/series/3664/?format=json","web_url":"http://patchwork.ozlabs.org/project/netdev/list/?series=3664","date":"2017-09-18T15:30:47","name":"Thunderbolt networking","version":1,"mbox":"http://patchwork.ozlabs.org/series/3664/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/814985/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/814985/checks/","tags":{},"related":[],"headers":{"Return-Path":"<netdev-owner@vger.kernel.org>","X-Original-To":"patchwork-incoming@ozlabs.org","Delivered-To":"patchwork-incoming@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>)","Received":["from vger.kernel.org (vger.kernel.org [209.132.180.67])\n\tby ozlabs.org (Postfix) with ESMTP id 3xwqq16Wpyz9s78\n\tfor <patchwork-incoming@ozlabs.org>;\n\tTue, 19 Sep 2017 01:36:13 +1000 (AEST)","(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1754230AbdIRPfi (ORCPT <rfc822;patchwork-incoming@ozlabs.org>);\n\tMon, 18 Sep 2017 11:35:38 -0400","from mga01.intel.com ([192.55.52.88]:40495 \"EHLO mga01.intel.com\"\n\trhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP\n\tid S1754720AbdIRPa7 (ORCPT <rfc822;netdev@vger.kernel.org>);\n\tMon, 18 Sep 2017 11:30:59 -0400","from fmsmga002.fm.intel.com ([10.253.24.26])\n\tby fmsmga101.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t18 Sep 2017 08:30:57 -0700","from black.fi.intel.com ([10.237.72.28])\n\tby fmsmga002.fm.intel.com with ESMTP; 18 Sep 2017 08:30:54 -0700","by black.fi.intel.com (Postfix, from userid 1001)\n\tid BA390405; Mon, 18 Sep 2017 18:30:49 +0300 (EEST)"],"X-ExtLoop1":"1","X-IronPort-AV":"E=Sophos;i=\"5.42,413,1500966000\"; d=\"scan'208\";a=\"1220359539\"","From":"Mika Westerberg <mika.westerberg@linux.intel.com>","To":"Greg Kroah-Hartman <gregkh@linuxfoundation.org>,\n\t\"David S . Miller\" <davem@davemloft.net>","Cc":"Andreas Noever <andreas.noever@gmail.com>,\n\tMichael Jamet <michael.jamet@intel.com>,\n\tYehezkel Bernat <yehezkel.bernat@intel.com>,\n\tAmir Levy <amir.jer.levy@intel.com>,\n\tMario.Limonciello@dell.com, Lukas Wunner <lukas@wunner.de>,\n\tAndy Shevchenko <andriy.shevchenko@linux.intel.com>,\n\tMika Westerberg <mika.westerberg@linux.intel.com>,\n\tlinux-kernel@vger.kernel.org, netdev@vger.kernel.org","Subject":"[PATCH 08/16] thunderbolt: Add support for frame mode","Date":"Mon, 18 Sep 2017 18:30:41 +0300","Message-Id":"<20170918153049.44185-9-mika.westerberg@linux.intel.com>","X-Mailer":"git-send-email 2.14.1","In-Reply-To":"<20170918153049.44185-1-mika.westerberg@linux.intel.com>","References":"<20170918153049.44185-1-mika.westerberg@linux.intel.com>","Sender":"netdev-owner@vger.kernel.org","Precedence":"bulk","List-ID":"<netdev.vger.kernel.org>","X-Mailing-List":"netdev@vger.kernel.org"},"content":"When high-speed DMA paths are used to transfer arbitrary data over a\nThunderbolt link, DMA rings should be in frame mode instead of raw mode.\nThe latter is used by the control channel (ring 0). In frame mode each\ndata frame can hold up to 4kB payload.\n\nThis patch modifies the DMA ring code to allow configuring a ring to be\nin frame mode by passing a new flag (RING_FLAG_FRAME) to the ring when\nit is allocated. In addition there might be need to enable end-to-end\n(E2E) workaround for the ring to prevent losing Rx frames in certain\nsituations. We add another flag (RING_FLAG_E2E) that can be used for\nthis purpose.\n\nThis code is based on the work done by Amir Levy and Michael Jamet.\n\nSigned-off-by: Michael Jamet <michael.jamet@intel.com>\nSigned-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>\nReviewed-by: Yehezkel Bernat <yehezkel.bernat@intel.com>\n---\n drivers/thunderbolt/ctl.c      |  3 +-\n drivers/thunderbolt/nhi.c      | 76 ++++++++++++++++++++++++++----------------\n drivers/thunderbolt/nhi.h      | 10 +++++-\n drivers/thunderbolt/nhi_regs.h |  2 ++\n 4 files changed, 61 insertions(+), 30 deletions(-)","diff":"diff --git a/drivers/thunderbolt/ctl.c b/drivers/thunderbolt/ctl.c\nindex 46e393c5fd1d..05400b77dcd7 100644\n--- a/drivers/thunderbolt/ctl.c\n+++ b/drivers/thunderbolt/ctl.c\n@@ -618,7 +618,8 @@ struct tb_ctl *tb_ctl_alloc(struct tb_nhi *nhi, event_cb cb, void *cb_data)\n \tif (!ctl->tx)\n \t\tgoto err;\n \n-\tctl->rx = ring_alloc_rx(nhi, 0, 10, RING_FLAG_NO_SUSPEND);\n+\tctl->rx = ring_alloc_rx(nhi, 0, 10, RING_FLAG_NO_SUSPEND, 0xffff,\n+\t\t\t\t0xffff);\n \tif (!ctl->rx)\n \t\tgoto err;\n \ndiff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c\nindex bc44cbaaf05a..cde8b6d46147 100644\n--- a/drivers/thunderbolt/nhi.c\n+++ b/drivers/thunderbolt/nhi.c\n@@ -22,6 +22,12 @@\n #define RING_TYPE(ring) ((ring)->is_tx ? \"TX ring\" : \"RX ring\")\n \n /*\n+ * Used to enable end-to-end workaround for missing RX packets. Do not\n+ * use this ring for anything else.\n+ */\n+#define RING_E2E_UNUSED_HOPID\t2\n+\n+/*\n  * Minimal number of vectors when we use MSI-X. Two for control channel\n  * Rx/Tx and the rest four are for cross domain DMA paths.\n  */\n@@ -229,23 +235,6 @@ static void ring_work(struct work_struct *work)\n \t\t\tframe->eof = ring->descriptors[ring->tail].eof;\n \t\t\tframe->sof = ring->descriptors[ring->tail].sof;\n \t\t\tframe->flags = ring->descriptors[ring->tail].flags;\n-\t\t\tif (frame->sof != 0)\n-\t\t\t\tdev_WARN(&ring->nhi->pdev->dev,\n-\t\t\t\t\t \"%s %d got unexpected SOF: %#x\\n\",\n-\t\t\t\t\t RING_TYPE(ring), ring->hop,\n-\t\t\t\t\t frame->sof);\n-\t\t\t/*\n-\t\t\t * known flags:\n-\t\t\t * raw not enabled, interupt not set: 0x2=0010\n-\t\t\t * raw enabled: 0xa=1010\n-\t\t\t * raw not enabled: 0xb=1011\n-\t\t\t * partial frame (>MAX_FRAME_SIZE): 0xe=1110\n-\t\t\t */\n-\t\t\tif (frame->flags != 0xa)\n-\t\t\t\tdev_WARN(&ring->nhi->pdev->dev,\n-\t\t\t\t\t \"%s %d got unexpected flags: %#x\\n\",\n-\t\t\t\t\t RING_TYPE(ring), ring->hop,\n-\t\t\t\t\t frame->flags);\n \t\t}\n \t\tring->tail = (ring->tail + 1) % ring->size;\n \t}\n@@ -321,12 +310,17 @@ static void ring_release_msix(struct tb_ring *ring)\n }\n \n static struct tb_ring *ring_alloc(struct tb_nhi *nhi, u32 hop, int size,\n-\t\t\t\t  bool transmit, unsigned int flags)\n+\t\t\t\t  bool transmit, unsigned int flags,\n+\t\t\t\t  u16 sof_mask, u16 eof_mask)\n {\n \tstruct tb_ring *ring = NULL;\n \tdev_info(&nhi->pdev->dev, \"allocating %s ring %d of size %d\\n\",\n \t\t transmit ? \"TX\" : \"RX\", hop, size);\n \n+\t/* Tx Ring 2 is reserved for E2E workaround */\n+\tif (transmit && hop == RING_E2E_UNUSED_HOPID)\n+\t\treturn NULL;\n+\n \tmutex_lock(&nhi->lock);\n \tif (hop >= nhi->hop_count) {\n \t\tdev_WARN(&nhi->pdev->dev, \"invalid hop: %d\\n\", hop);\n@@ -353,6 +347,8 @@ static struct tb_ring *ring_alloc(struct tb_nhi *nhi, u32 hop, int size,\n \tring->is_tx = transmit;\n \tring->size = size;\n \tring->flags = flags;\n+\tring->sof_mask = sof_mask;\n+\tring->eof_mask = eof_mask;\n \tring->head = 0;\n \tring->tail = 0;\n \tring->running = false;\n@@ -384,13 +380,13 @@ static struct tb_ring *ring_alloc(struct tb_nhi *nhi, u32 hop, int size,\n struct tb_ring *ring_alloc_tx(struct tb_nhi *nhi, int hop, int size,\n \t\t\t      unsigned int flags)\n {\n-\treturn ring_alloc(nhi, hop, size, true, flags);\n+\treturn ring_alloc(nhi, hop, size, true, flags, 0, 0);\n }\n \n struct tb_ring *ring_alloc_rx(struct tb_nhi *nhi, int hop, int size,\n-\t\t\t      unsigned int flags)\n+\t\t\t      unsigned int flags, u16 sof_mask, u16 eof_mask)\n {\n-\treturn ring_alloc(nhi, hop, size, false, flags);\n+\treturn ring_alloc(nhi, hop, size, false, flags, sof_mask, eof_mask);\n }\n \n /**\n@@ -400,6 +396,9 @@ struct tb_ring *ring_alloc_rx(struct tb_nhi *nhi, int hop, int size,\n  */\n void ring_start(struct tb_ring *ring)\n {\n+\tu16 frame_size;\n+\tu32 flags;\n+\n \tmutex_lock(&ring->nhi->lock);\n \tmutex_lock(&ring->lock);\n \tif (ring->nhi->going_away)\n@@ -411,18 +410,39 @@ void ring_start(struct tb_ring *ring)\n \tdev_info(&ring->nhi->pdev->dev, \"starting %s %d\\n\",\n \t\t RING_TYPE(ring), ring->hop);\n \n+\tif (ring->flags & RING_FLAG_FRAME) {\n+\t\t/* Means 4096 */\n+\t\tframe_size = 0;\n+\t\tflags = RING_FLAG_ENABLE;\n+\t} else {\n+\t\tframe_size = TB_FRAME_SIZE;\n+\t\tflags = RING_FLAG_ENABLE | RING_FLAG_RAW;\n+\t}\n+\n+\tif (ring->flags & RING_FLAG_E2E && !ring->is_tx) {\n+\t\tu32 hop;\n+\n+\t\t/*\n+\t\t * In order not to lose Rx packets we enable end-to-end\n+\t\t * workaround which transfers Rx credits to an unused Tx\n+\t\t * HopID.\n+\t\t */\n+\t\thop = RING_E2E_UNUSED_HOPID << REG_RX_OPTIONS_E2E_HOP_SHIFT;\n+\t\thop &= REG_RX_OPTIONS_E2E_HOP_MASK;\n+\t\tflags |= hop | RING_FLAG_E2E_FLOW_CONTROL;\n+\t}\n+\n \tring_iowrite64desc(ring, ring->descriptors_dma, 0);\n \tif (ring->is_tx) {\n \t\tring_iowrite32desc(ring, ring->size, 12);\n \t\tring_iowrite32options(ring, 0, 4); /* time releated ? */\n-\t\tring_iowrite32options(ring,\n-\t\t\t\t      RING_FLAG_ENABLE | RING_FLAG_RAW, 0);\n+\t\tring_iowrite32options(ring, flags, 0);\n \t} else {\n-\t\tring_iowrite32desc(ring,\n-\t\t\t\t   (TB_FRAME_SIZE << 16) | ring->size, 12);\n-\t\tring_iowrite32options(ring, 0xffffffff, 4); /* SOF EOF mask */\n-\t\tring_iowrite32options(ring,\n-\t\t\t\t      RING_FLAG_ENABLE | RING_FLAG_RAW, 0);\n+\t\tu32 sof_eof_mask = ring->sof_mask << 16 | ring->eof_mask;\n+\n+\t\tring_iowrite32desc(ring, (frame_size << 16) | ring->size, 12);\n+\t\tring_iowrite32options(ring, sof_eof_mask, 4);\n+\t\tring_iowrite32options(ring, flags, 0);\n \t}\n \tring_interrupt_active(ring, true);\n \tring->running = true;\ndiff --git a/drivers/thunderbolt/nhi.h b/drivers/thunderbolt/nhi.h\nindex 0e05828983db..4503ddbeccb3 100644\n--- a/drivers/thunderbolt/nhi.h\n+++ b/drivers/thunderbolt/nhi.h\n@@ -56,6 +56,8 @@ struct tb_nhi {\n  * @irq: MSI-X irq number if the ring uses MSI-X. %0 otherwise.\n  * @vector: MSI-X vector number the ring uses (only set if @irq is > 0)\n  * @flags: Ring specific flags\n+ * @sof_mask: Bit mask used to detect start of frame PDF\n+ * @eof_mask: Bit mask used to detect end of frame PDF\n  */\n struct tb_ring {\n \tstruct mutex lock;\n@@ -74,10 +76,16 @@ struct tb_ring {\n \tint irq;\n \tu8 vector;\n \tunsigned int flags;\n+\tu16 sof_mask;\n+\tu16 eof_mask;\n };\n \n /* Leave ring interrupt enabled on suspend */\n #define RING_FLAG_NO_SUSPEND\tBIT(0)\n+/* Configure the ring to be in frame mode */\n+#define RING_FLAG_FRAME\t\tBIT(1)\n+/* Enable end-to-end flow control */\n+#define RING_FLAG_E2E\t\tBIT(2)\n \n struct ring_frame;\n typedef void (*ring_cb)(struct tb_ring*, struct ring_frame*, bool canceled);\n@@ -100,7 +108,7 @@ struct ring_frame {\n struct tb_ring *ring_alloc_tx(struct tb_nhi *nhi, int hop, int size,\n \t\t\t      unsigned int flags);\n struct tb_ring *ring_alloc_rx(struct tb_nhi *nhi, int hop, int size,\n-\t\t\t      unsigned int flags);\n+\t\t\t      unsigned int flags, u16 sof_mask, u16 eof_mask);\n void ring_start(struct tb_ring *ring);\n void ring_stop(struct tb_ring *ring);\n void ring_free(struct tb_ring *ring);\ndiff --git a/drivers/thunderbolt/nhi_regs.h b/drivers/thunderbolt/nhi_regs.h\nindex 46eff69b19ad..491a4c0c18fc 100644\n--- a/drivers/thunderbolt/nhi_regs.h\n+++ b/drivers/thunderbolt/nhi_regs.h\n@@ -77,6 +77,8 @@ struct ring_desc {\n  * ..: unknown\n  */\n #define REG_RX_OPTIONS_BASE\t0x29800\n+#define REG_RX_OPTIONS_E2E_HOP_MASK\tGENMASK(22, 12)\n+#define REG_RX_OPTIONS_E2E_HOP_SHIFT\t12\n \n /*\n  * three bitfields: tx, rx, rx overflow\n","prefixes":["08/16"]}