get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/1032822/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 1032822,
    "url": "http://patchwork.ozlabs.org/api/patches/1032822/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/netdev/patch/20190129150143.12681-18-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-18-mika.westerberg@linux.intel.com>",
    "list_archive_url": null,
    "date": "2019-01-29T15:01:32",
    "name": "[17/28] thunderbolt: Add support for full PCIe daisy chains",
    "commit_ref": null,
    "pull_url": null,
    "state": "not-applicable",
    "archived": false,
    "hash": "01b839ae35014cd38da3c1ee0ce309f6c3aad3ff",
    "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-18-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/1032822/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/1032822/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 43pqWY15WCz9sDP\n\tfor <patchwork-incoming-netdev@ozlabs.org>;\n\tWed, 30 Jan 2019 02:03:37 +1100 (AEDT)",
            "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1728892AbfA2PCx (ORCPT\n\t<rfc822;patchwork-incoming-netdev@ozlabs.org>);\n\tTue, 29 Jan 2019 10:02:53 -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 S1728392AbfA2PBy (ORCPT <rfc822;netdev@vger.kernel.org>);\n\tTue, 29 Jan 2019 10:01:54 -0500",
            "from orsmga004.jf.intel.com ([10.7.209.38])\n\tby orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t29 Jan 2019 07:01:54 -0800",
            "from black.fi.intel.com ([10.237.72.28])\n\tby orsmga004.jf.intel.com with ESMTP; 29 Jan 2019 07:01:51 -0800",
            "by black.fi.intel.com (Postfix, from userid 1001)\n\tid 07BF6A0F; Tue, 29 Jan 2019 17:01:45 +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=\"270838765\"",
        "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 17/28] thunderbolt: Add support for full PCIe daisy chains",
        "Date": "Tue, 29 Jan 2019 18:01:32 +0300",
        "Message-Id": "<20190129150143.12681-18-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": "Currently the software connection manager (tb.c) has only supported\ncreating a single PCIe tunnel, no PCIe device daisy chaining has been\nsupported so far. This updates the software connection manager so that\nit now can create PCIe tunnels for full chain of six devices.\n\nSigned-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>\n---\n drivers/thunderbolt/tb.c | 174 +++++++++++++++++++++++----------------\n 1 file changed, 104 insertions(+), 70 deletions(-)",
    "diff": "diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c\nindex 8acd16c3ada6..c2e102f55ee0 100644\n--- a/drivers/thunderbolt/tb.c\n+++ b/drivers/thunderbolt/tb.c\n@@ -1,8 +1,9 @@\n // SPDX-License-Identifier: GPL-2.0\n /*\n- * Thunderbolt Cactus Ridge driver - bus logic (NHI independent)\n+ * Thunderbolt driver - bus logic (NHI independent)\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@@ -50,8 +51,15 @@ static void tb_discover_tunnels(struct tb_switch *sw)\n \t\t}\n \n \t\t/* Find and add existing tunnels */\n-\t\tif (tunnel)\n+\t\tif (tunnel) {\n+\t\t\tstruct tb_port *p;\n+\n+\t\t\t/* Firmware added switches are always authorized */\n+\t\t\ttb_for_each_port(p, tunnel->src_port, tunnel->dst_port)\n+\t\t\t\tp->sw->boot = true;\n+\n \t\t\tlist_add_tail(&tunnel->list, &tcm->tunnel_list);\n+\t\t}\n \t}\n \n \tfor (i = 1; i <= sw->config.max_port_number; i++) {\n@@ -63,6 +71,16 @@ static void tb_discover_tunnels(struct tb_switch *sw)\n \t}\n }\n \n+static void tb_switch_authorize(struct work_struct *work)\n+{\n+\tstruct tb_switch *sw = container_of(work, typeof(*sw), work);\n+\n+\tmutex_lock(&sw->tb->lock);\n+\tif (!sw->is_unplugged)\n+\t\ttb_domain_approve_switch(sw->tb, sw);\n+\tmutex_unlock(&sw->tb->lock);\n+}\n+\n static void tb_scan_port(struct tb_port *port);\n \n /**\n@@ -80,6 +98,7 @@ static void tb_scan_switch(struct tb_switch *sw)\n  */\n static void tb_scan_port(struct tb_port *port)\n {\n+\tstruct tb_cm *tcm = tb_priv(port->sw->tb);\n \tstruct tb_switch *sw;\n \tif (tb_is_upstream_port(port))\n \t\treturn;\n@@ -106,6 +125,14 @@ static void tb_scan_port(struct tb_port *port)\n \t\treturn;\n \t}\n \n+\t/*\n+\t * Do not send uevents until we have discovered all existing\n+\t * tunnels and know which switches were authorized already by\n+\t * the boot firmware.\n+\t */\n+\tif (!tcm->hotplug_active)\n+\t\tdev_set_uevent_suppress(&sw->dev, true);\n+\n \tsw->authorized = true;\n \n \tif (tb_switch_add(sw)) {\n@@ -113,6 +140,9 @@ static void tb_scan_port(struct tb_port *port)\n \t\treturn;\n \t}\n \n+\tINIT_WORK(&sw->work, tb_switch_authorize);\n+\tqueue_work(sw->tb->wq, &sw->work);\n+\n \tport->remote = tb_upstream_port(sw);\n \ttb_upstream_port(sw)->remote = port;\n \ttb_scan_switch(sw);\n@@ -149,6 +179,7 @@ static void tb_free_unplugged_children(struct tb_switch *sw)\n \t\tif (!port->remote)\n \t\t\tcontinue;\n \t\tif (port->remote->sw->is_unplugged) {\n+\t\t\tcancel_work_sync(&port->remote->sw->work);\n \t\t\ttb_switch_remove(port->remote->sw);\n \t\t\tport->remote = NULL;\n \t\t} else {\n@@ -197,72 +228,58 @@ static struct tb_port *tb_find_unused_down_port(struct tb_switch *sw)\n \treturn NULL;\n }\n \n-/**\n- * tb_activate_pcie_devices() - scan for and activate PCIe devices\n- *\n- * This method is somewhat ad hoc. For now it only supports one device\n- * per port and only devices at depth 1.\n- */\n-static void tb_activate_pcie_devices(struct tb *tb)\n+static int tb_tunnel_pci(struct tb *tb, struct tb_switch *sw)\n {\n-\tint i;\n-\tint cap;\n-\tu32 data;\n-\tstruct tb_switch *sw;\n-\tstruct tb_port *up_port;\n-\tstruct tb_port *down_port;\n-\tstruct tb_tunnel *tunnel;\n \tstruct tb_cm *tcm = tb_priv(tb);\n+\tstruct tb_switch *parent_sw;\n+\tstruct tb_port *up, *down;\n+\tstruct tb_tunnel *tunnel;\n \n-\t/* scan for pcie devices at depth 1*/\n-\tfor (i = 1; i <= tb->root_switch->config.max_port_number; i++) {\n-\t\tif (tb_is_upstream_port(&tb->root_switch->ports[i]))\n-\t\t\tcontinue;\n-\t\tif (tb->root_switch->ports[i].config.type != TB_TYPE_PORT)\n-\t\t\tcontinue;\n-\t\tif (!tb->root_switch->ports[i].remote)\n-\t\t\tcontinue;\n-\t\tsw = tb->root_switch->ports[i].remote->sw;\n-\t\tup_port = tb_find_pci_up_port(sw);\n-\t\tif (!up_port) {\n-\t\t\ttb_sw_info(sw, \"no PCIe devices found, aborting\\n\");\n-\t\t\tcontinue;\n-\t\t}\n+\tup = tb_find_pci_up_port(sw);\n+\tif (!up)\n+\t\treturn 0;\n \n-\t\t/* check whether port is already activated */\n-\t\tcap = up_port->cap_adap;\n-\t\tif (cap < 0)\n-\t\t\tcontinue;\n-\t\tif (tb_port_read(up_port, &data, TB_CFG_PORT, cap, 1))\n-\t\t\tcontinue;\n-\t\tif (data & 0x80000000) {\n-\t\t\ttb_port_info(up_port,\n-\t\t\t\t     \"PCIe port already activated, aborting\\n\");\n-\t\t\tcontinue;\n-\t\t}\n+\t/*\n+\t * Look up available down port. Since we are chaining, it is\n+\t * typically found right above this switch.\n+\t */\n+\tdown = NULL;\n+\tparent_sw = tb_to_switch(sw->dev.parent);\n+\twhile (parent_sw) {\n+\t\tdown = tb_find_unused_down_port(parent_sw);\n+\t\tif (down)\n+\t\t\tbreak;\n+\t\tparent_sw = tb_to_switch(parent_sw->dev.parent);\n+\t}\n \n-\t\tdown_port = tb_find_unused_down_port(tb->root_switch);\n-\t\tif (!down_port) {\n-\t\t\ttb_port_info(up_port,\n-\t\t\t\t     \"All PCIe down ports are occupied, aborting\\n\");\n-\t\t\tcontinue;\n-\t\t}\n-\t\ttunnel = tb_tunnel_alloc_pci(tb, up_port, down_port);\n-\t\tif (!tunnel) {\n-\t\t\ttb_port_info(up_port,\n-\t\t\t\t     \"PCIe tunnel allocation failed, aborting\\n\");\n-\t\t\tcontinue;\n-\t\t}\n+\tif (!down)\n+\t\treturn 0;\n \n-\t\tif (tb_tunnel_activate(tunnel)) {\n-\t\t\ttb_port_info(up_port,\n-\t\t\t\t     \"PCIe tunnel activation failed, aborting\\n\");\n-\t\t\ttb_tunnel_free(tunnel);\n-\t\t\tcontinue;\n-\t\t}\n+\ttunnel = tb_tunnel_alloc_pci(tb, up, down);\n+\tif (!tunnel)\n+\t\treturn -EIO;\n \n-\t\tlist_add(&tunnel->list, &tcm->tunnel_list);\n+\tif (tb_tunnel_activate(tunnel)) {\n+\t\ttb_port_info(up,\n+\t\t\t     \"PCIe tunnel activation failed, aborting\\n\");\n+\t\ttb_tunnel_free(tunnel);\n+\t\treturn -EIO;\n \t}\n+\tlist_add_tail(&tunnel->list, &tcm->tunnel_list);\n+\n+\treturn 0;\n+}\n+\n+static int tb_approve_switch(struct tb *tb, struct tb_switch *sw)\n+{\n+\t/*\n+\t * Already authorized by the boot firmware so no need to do\n+\t * anything here.\n+\t */\n+\tif (sw->boot)\n+\t\treturn 0;\n+\n+\treturn tb_tunnel_pci(tb, sw);\n }\n \n /* hotplug handling */\n@@ -316,6 +333,7 @@ static void tb_handle_hotplug(struct work_struct *work)\n \t\t\ttb_port_info(port, \"unplugged\\n\");\n \t\t\ttb_sw_set_unplugged(port->remote->sw);\n \t\t\ttb_free_invalid_tunnels(tb);\n+\t\t\tcancel_work_sync(&sw->work);\n \t\t\ttb_switch_remove(port->remote->sw);\n \t\t\tport->remote = NULL;\n \t\t} else {\n@@ -328,16 +346,8 @@ static void tb_handle_hotplug(struct work_struct *work)\n \t} else {\n \t\ttb_port_info(port, \"hotplug: scanning\\n\");\n \t\ttb_scan_port(port);\n-\t\tif (!port->remote) {\n+\t\tif (!port->remote)\n \t\t\ttb_port_info(port, \"hotplug: no switch found\\n\");\n-\t\t} else if (port->remote->sw->config.depth > 1) {\n-\t\t\ttb_sw_warn(port->remote->sw,\n-\t\t\t\t   \"hotplug: chaining not supported\\n\");\n-\t\t} else {\n-\t\t\ttb_sw_info(port->remote->sw,\n-\t\t\t\t   \"hotplug: activating pcie devices\\n\");\n-\t\t\ttb_activate_pcie_devices(tb);\n-\t\t}\n \t}\n out:\n \tmutex_unlock(&tb->lock);\n@@ -395,6 +405,27 @@ static void tb_stop(struct tb *tb)\n \ttcm->hotplug_active = false; /* signal tb_handle_hotplug to quit */\n }\n \n+static int tb_scan_finalize_switch(struct device *dev, void *data)\n+{\n+\tif (tb_is_switch(dev)) {\n+\t\tstruct tb_switch *sw = tb_to_switch(dev);\n+\n+\t\t/*\n+\t\t * If we found that the switch was already setup by the\n+\t\t * boot firmware, mark it as authorized now before we\n+\t\t * send uevent to userspace.\n+\t\t */\n+\t\tif (sw->boot)\n+\t\t\tsw->authorized = 1;\n+\n+\t\tdev_set_uevent_suppress(dev, false);\n+\t\tkobject_uevent(&dev->kobj, KOBJ_ADD);\n+\t\tdevice_for_each_child(dev, NULL, tb_scan_finalize_switch);\n+\t}\n+\n+\treturn 0;\n+}\n+\n static int tb_start(struct tb *tb)\n {\n \tstruct tb_cm *tcm = tb_priv(tb);\n@@ -428,7 +459,9 @@ static int tb_start(struct tb *tb)\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+\t/* Make the discovered switches available to the userspace */\n+\tdevice_for_each_child(&tb->root_switch->dev, NULL,\n+\t\t\t      tb_scan_finalize_switch);\n \n \t/* Allow tb_handle_hotplug to progress events */\n \ttcm->hotplug_active = true;\n@@ -483,6 +516,7 @@ static const struct tb_cm_ops tb_cm_ops = {\n \t.suspend_noirq = tb_suspend_noirq,\n \t.resume_noirq = tb_resume_noirq,\n \t.handle_event = tb_handle_event,\n+\t.approve_switch = tb_approve_switch,\n };\n \n struct tb *tb_probe(struct tb_nhi *nhi)\n",
    "prefixes": [
        "17/28"
    ]
}