get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 814987,
    "url": "http://patchwork.ozlabs.org/api/patches/814987/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/netdev/patch/20170918153049.44185-3-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": "<20170918153049.44185-3-mika.westerberg@linux.intel.com>",
    "list_archive_url": null,
    "date": "2017-09-18T15:30:35",
    "name": "[02/16] thunderbolt: Add support for XDomain properties",
    "commit_ref": null,
    "pull_url": null,
    "state": "not-applicable",
    "archived": true,
    "hash": "162ad42b9a153bb74daae18e3db6662d3ac2c2a3",
    "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/20170918153049.44185-3-mika.westerberg@linux.intel.com/mbox/",
    "series": [
        {
            "id": 3664,
            "url": "http://patchwork.ozlabs.org/api/series/3664/?format=api",
            "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/814987/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/814987/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 3xwqqW4vJPz9s78\n\tfor <patchwork-incoming@ozlabs.org>;\n\tTue, 19 Sep 2017 01:36:39 +1000 (AEST)",
            "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S932142AbdIRPg2 (ORCPT <rfc822;patchwork-incoming@ozlabs.org>);\n\tMon, 18 Sep 2017 11:36:28 -0400",
            "from mga11.intel.com ([192.55.52.93]:27612 \"EHLO mga11.intel.com\"\n\trhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP\n\tid S1753776AbdIRPaz (ORCPT <rfc822;netdev@vger.kernel.org>);\n\tMon, 18 Sep 2017 11:30:55 -0400",
            "from fmsmga004.fm.intel.com ([10.253.24.48])\n\tby fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t18 Sep 2017 08:30:54 -0700",
            "from black.fi.intel.com ([10.237.72.28])\n\tby fmsmga004.fm.intel.com with ESMTP; 18 Sep 2017 08:30:50 -0700",
            "by black.fi.intel.com (Postfix, from userid 1001)\n\tid 71DB6163; 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=\"312962427\"",
        "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 02/16] thunderbolt: Add support for XDomain properties",
        "Date": "Mon, 18 Sep 2017 18:30:35 +0300",
        "Message-Id": "<20170918153049.44185-3-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": "Thunderbolt XDomain discovery protocol uses directories which contain\nproperties and other directories to exchange information about what\ncapabilities the remote host supports. This also includes identification\ninformation like device ID and name.\n\nThis adds support for parsing and formatting these properties and\nestablishes an API drivers can use in addition to the core Thunderbolt\ndriver. This API is exposed in a new header: include/linux/thunderbolt.h.\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/Makefile   |   2 +-\n drivers/thunderbolt/property.c | 670 +++++++++++++++++++++++++++++++++++++++++\n include/linux/thunderbolt.h    |  89 ++++++\n 3 files changed, 760 insertions(+), 1 deletion(-)\n create mode 100644 drivers/thunderbolt/property.c\n create mode 100644 include/linux/thunderbolt.h",
    "diff": "diff --git a/drivers/thunderbolt/Makefile b/drivers/thunderbolt/Makefile\nindex 4900febc6c8a..7afd21f5383a 100644\n--- a/drivers/thunderbolt/Makefile\n+++ b/drivers/thunderbolt/Makefile\n@@ -1,3 +1,3 @@\n obj-${CONFIG_THUNDERBOLT} := thunderbolt.o\n thunderbolt-objs := nhi.o ctl.o tb.o switch.o cap.o path.o tunnel_pci.o eeprom.o\n-thunderbolt-objs += domain.o dma_port.o icm.o\n+thunderbolt-objs += domain.o dma_port.o icm.o property.o\ndiff --git a/drivers/thunderbolt/property.c b/drivers/thunderbolt/property.c\nnew file mode 100644\nindex 000000000000..55a8aa32b1d6\n--- /dev/null\n+++ b/drivers/thunderbolt/property.c\n@@ -0,0 +1,670 @@\n+/*\n+ * Thunderbolt XDomain property support\n+ *\n+ * Copyright (C) 2017, Intel Corporation\n+ * Authors: Michael Jamet <michael.jamet@intel.com>\n+ *          Mika Westerberg <mika.westerberg@linux.intel.com>\n+ *\n+ * This program is free software; you can redistribute it and/or modify\n+ * it under the terms of the GNU General Public License version 2 as\n+ * published by the Free Software Foundation.\n+ */\n+\n+#include <linux/err.h>\n+#include <linux/slab.h>\n+#include <linux/string.h>\n+#include <linux/uuid.h>\n+#include <linux/thunderbolt.h>\n+\n+struct tb_property_entry {\n+\tu32 key_hi;\n+\tu32 key_lo;\n+\tu16 length;\n+\tu8 reserved;\n+\tu8 type;\n+\tu32 value;\n+} __packed;\n+\n+struct tb_property_rootdir_entry {\n+\tu32 magic;\n+\tu32 length;\n+\tstruct tb_property_entry entries[];\n+} __packed;\n+\n+struct tb_property_dir_entry {\n+\tu32 uuid[4];\n+\tstruct tb_property_entry entries[];\n+} __packed;\n+\n+#define TB_PROPERTY_ROOTDIR_MAGIC\t0x55584401\n+\n+static struct tb_property_dir *__tb_property_parse_dir(const u32 *block,\n+\tsize_t block_len, unsigned int dir_offset, size_t dir_len,\n+\tbool is_root);\n+\n+static inline void parse_dwdata(void *dst, const void *src, size_t dwords)\n+{\n+\tbe32_to_cpu_array(dst, src, dwords);\n+}\n+\n+static inline void format_dwdata(void *dst, const void *src, size_t dwords)\n+{\n+\tcpu_to_be32_array(dst, src, dwords);\n+}\n+\n+static bool tb_property_entry_valid(const struct tb_property_entry *entry,\n+\t\t\t\t  size_t block_len)\n+{\n+\tswitch (entry->type) {\n+\tcase TB_PROPERTY_TYPE_DIRECTORY:\n+\tcase TB_PROPERTY_TYPE_DATA:\n+\tcase TB_PROPERTY_TYPE_TEXT:\n+\t\tif (entry->length > block_len)\n+\t\t\treturn false;\n+\t\tif (entry->value + entry->length > block_len)\n+\t\t\treturn false;\n+\t\tbreak;\n+\n+\tcase TB_PROPERTY_TYPE_VALUE:\n+\t\tif (entry->length != 1)\n+\t\t\treturn false;\n+\t\tbreak;\n+\t}\n+\n+\treturn true;\n+}\n+\n+static bool tb_property_key_valid(const char *key)\n+{\n+\treturn key && strlen(key) <= TB_PROPERTY_KEY_SIZE;\n+}\n+\n+static struct tb_property *\n+tb_property_alloc(const char *key, enum tb_property_type type)\n+{\n+\tstruct tb_property *property;\n+\n+\tproperty = kzalloc(sizeof(*property), GFP_KERNEL);\n+\tif (!property)\n+\t\treturn NULL;\n+\n+\tstrcpy(property->key, key);\n+\tproperty->type = type;\n+\tINIT_LIST_HEAD(&property->list);\n+\n+\treturn property;\n+}\n+\n+static struct tb_property *tb_property_parse(const u32 *block, size_t block_len,\n+\t\t\t\t\tconst struct tb_property_entry *entry)\n+{\n+\tchar key[TB_PROPERTY_KEY_SIZE + 1];\n+\tstruct tb_property *property;\n+\tstruct tb_property_dir *dir;\n+\n+\tif (!tb_property_entry_valid(entry, block_len))\n+\t\treturn NULL;\n+\n+\tparse_dwdata(key, entry, 2);\n+\tkey[TB_PROPERTY_KEY_SIZE] = '\\0';\n+\n+\tproperty = tb_property_alloc(key, entry->type);\n+\tif (!property)\n+\t\treturn NULL;\n+\n+\tproperty->length = entry->length;\n+\n+\tswitch (property->type) {\n+\tcase TB_PROPERTY_TYPE_DIRECTORY:\n+\t\tdir = __tb_property_parse_dir(block, block_len, entry->value,\n+\t\t\t\t\t      entry->length, false);\n+\t\tif (!dir) {\n+\t\t\tkfree(property);\n+\t\t\treturn NULL;\n+\t\t}\n+\t\tproperty->value.dir = dir;\n+\t\tbreak;\n+\n+\tcase TB_PROPERTY_TYPE_DATA:\n+\t\tproperty->value.data = kcalloc(property->length, sizeof(u32),\n+\t\t\t\t\t       GFP_KERNEL);\n+\t\tif (!property->value.data) {\n+\t\t\tkfree(property);\n+\t\t\treturn NULL;\n+\t\t}\n+\t\tparse_dwdata(property->value.data, block + entry->value,\n+\t\t\t     entry->length);\n+\t\tbreak;\n+\n+\tcase TB_PROPERTY_TYPE_TEXT:\n+\t\tproperty->value.text = kcalloc(property->length, sizeof(u32),\n+\t\t\t\t\t       GFP_KERNEL);\n+\t\tif (!property->value.text) {\n+\t\t\tkfree(property);\n+\t\t\treturn NULL;\n+\t\t}\n+\t\tparse_dwdata(property->value.text, block + entry->value,\n+\t\t\t     entry->length);\n+\t\t/* Force null termination */\n+\t\tproperty->value.text[property->length * 4 - 1] = '\\0';\n+\t\tbreak;\n+\n+\tcase TB_PROPERTY_TYPE_VALUE:\n+\t\tproperty->value.immediate = entry->value;\n+\t\tbreak;\n+\n+\tdefault:\n+\t\tproperty->type = TB_PROPERTY_TYPE_UNKNOWN;\n+\t\tbreak;\n+\t}\n+\n+\treturn property;\n+}\n+\n+static struct tb_property_dir *__tb_property_parse_dir(const u32 *block,\n+\tsize_t block_len, unsigned int dir_offset, size_t dir_len, bool is_root)\n+{\n+\tconst struct tb_property_entry *entries;\n+\tsize_t i, content_len, nentries;\n+\tunsigned int content_offset;\n+\tstruct tb_property_dir *dir;\n+\n+\tdir = kzalloc(sizeof(*dir), GFP_KERNEL);\n+\tif (!dir)\n+\t\treturn NULL;\n+\n+\tif (is_root) {\n+\t\tcontent_offset = dir_offset + 2;\n+\t\tcontent_len = dir_len;\n+\t} else {\n+\t\tdir->uuid = kmemdup(&block[dir_offset], sizeof(*dir->uuid),\n+\t\t\t\t    GFP_KERNEL);\n+\t\tcontent_offset = dir_offset + 4;\n+\t\tcontent_len = dir_len - 4; /* Length includes UUID */\n+\t}\n+\n+\tentries = (const struct tb_property_entry *)&block[content_offset];\n+\tnentries = content_len / (sizeof(*entries) / 4);\n+\n+\tINIT_LIST_HEAD(&dir->properties);\n+\n+\tfor (i = 0; i < nentries; i++) {\n+\t\tstruct tb_property *property;\n+\n+\t\tproperty = tb_property_parse(block, block_len, &entries[i]);\n+\t\tif (!property) {\n+\t\t\ttb_property_free_dir(dir);\n+\t\t\treturn NULL;\n+\t\t}\n+\n+\t\tlist_add_tail(&property->list, &dir->properties);\n+\t}\n+\n+\treturn dir;\n+}\n+\n+/**\n+ * tb_property_parse_dir() - Parses properties from given property block\n+ * @block: Property block to parse\n+ * @block_len: Number of dword elements in the property block\n+ *\n+ * This function parses the XDomain properties data block into format that\n+ * can be traversed using the helper functions provided by this module.\n+ * Upon success returns the parsed directory. In case of error returns\n+ * %NULL. The resulting &struct tb_property_dir needs to be released by\n+ * calling tb_property_free_dir() when not needed anymore.\n+ *\n+ * The @block is expected to be root directory.\n+ */\n+struct tb_property_dir *tb_property_parse_dir(const u32 *block,\n+\t\t\t\t\t      size_t block_len)\n+{\n+\tconst struct tb_property_rootdir_entry *rootdir =\n+\t\t(const struct tb_property_rootdir_entry *)block;\n+\n+\tif (rootdir->magic != TB_PROPERTY_ROOTDIR_MAGIC)\n+\t\treturn NULL;\n+\tif (rootdir->length > block_len)\n+\t\treturn NULL;\n+\n+\treturn __tb_property_parse_dir(block, block_len, 0, rootdir->length,\n+\t\t\t\t       true);\n+}\n+\n+/**\n+ * tb_property_create_dir() - Creates new property directory\n+ * @uuid: UUID used to identify the particular directory\n+ *\n+ * Creates new, empty property directory. If @uuid is %NULL then the\n+ * directory is assumed to be root directory.\n+ */\n+struct tb_property_dir *tb_property_create_dir(const uuid_t *uuid)\n+{\n+\tstruct tb_property_dir *dir;\n+\n+\tdir = kzalloc(sizeof(*dir), GFP_KERNEL);\n+\tif (!dir)\n+\t\treturn NULL;\n+\n+\tINIT_LIST_HEAD(&dir->properties);\n+\tif (uuid) {\n+\t\tdir->uuid = kmemdup(uuid, sizeof(*dir->uuid), GFP_KERNEL);\n+\t\tif (!dir->uuid) {\n+\t\t\tkfree(dir);\n+\t\t\treturn NULL;\n+\t\t}\n+\t}\n+\n+\treturn dir;\n+}\n+EXPORT_SYMBOL_GPL(tb_property_create_dir);\n+\n+static void tb_property_free(struct tb_property *property)\n+{\n+\tswitch (property->type) {\n+\tcase TB_PROPERTY_TYPE_DIRECTORY:\n+\t\ttb_property_free_dir(property->value.dir);\n+\t\tbreak;\n+\n+\tcase TB_PROPERTY_TYPE_DATA:\n+\t\tkfree(property->value.data);\n+\t\tbreak;\n+\n+\tcase TB_PROPERTY_TYPE_TEXT:\n+\t\tkfree(property->value.text);\n+\t\tbreak;\n+\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\tkfree(property);\n+}\n+\n+/**\n+ * tb_property_free_dir() - Release memory allocated for property directory\n+ * @dir: Directory to release\n+ *\n+ * This will release all the memory the directory occupies including all\n+ * descendants. It is OK to pass %NULL @dir, then the function does\n+ * nothing.\n+ */\n+void tb_property_free_dir(struct tb_property_dir *dir)\n+{\n+\tstruct tb_property *property, *tmp;\n+\n+\tif (!dir)\n+\t\treturn;\n+\n+\tlist_for_each_entry_safe(property, tmp, &dir->properties, list) {\n+\t\tlist_del(&property->list);\n+\t\ttb_property_free(property);\n+\t}\n+\tkfree(dir->uuid);\n+\tkfree(dir);\n+}\n+EXPORT_SYMBOL_GPL(tb_property_free_dir);\n+\n+static size_t tb_property_dir_length(const struct tb_property_dir *dir,\n+\t\t\t\t     bool recurse, size_t *data_len)\n+{\n+\tconst struct tb_property *property;\n+\tsize_t len = 0;\n+\n+\tif (dir->uuid)\n+\t\tlen += sizeof(*dir->uuid) / 4;\n+\telse\n+\t\tlen += sizeof(struct tb_property_rootdir_entry) / 4;\n+\n+\tlist_for_each_entry(property, &dir->properties, list) {\n+\t\tlen += sizeof(struct tb_property_entry) / 4;\n+\n+\t\tswitch (property->type) {\n+\t\tcase TB_PROPERTY_TYPE_DIRECTORY:\n+\t\t\tif (recurse) {\n+\t\t\t\tlen += tb_property_dir_length(\n+\t\t\t\t\tproperty->value.dir, recurse, data_len);\n+\t\t\t}\n+\t\t\t/* Reserve dword padding after each directory */\n+\t\t\tif (data_len)\n+\t\t\t\t*data_len += 1;\n+\t\t\tbreak;\n+\n+\t\tcase TB_PROPERTY_TYPE_DATA:\n+\t\tcase TB_PROPERTY_TYPE_TEXT:\n+\t\t\tif (data_len)\n+\t\t\t\t*data_len += property->length;\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\treturn len;\n+}\n+\n+static ssize_t __tb_property_format_dir(const struct tb_property_dir *dir,\n+\tu32 *block, unsigned int start_offset, size_t block_len)\n+{\n+\tunsigned int data_offset, dir_end;\n+\tconst struct tb_property *property;\n+\tstruct tb_property_entry *entry;\n+\tsize_t dir_len, data_len = 0;\n+\tint ret;\n+\n+\t/*\n+\t * The structure of property block looks like following. Leaf\n+\t * data/text is included right after the directory and each\n+\t * directory follows each other (even nested ones).\n+\t *\n+\t * +----------+ <-- start_offset\n+\t * |  header  | <-- root directory header\n+\t * +----------+ ---\n+\t * |  entry 0 | -^--------------------.\n+\t * +----------+  |                    |\n+\t * |  entry 1 | -|--------------------|--.\n+\t * +----------+  |                    |  |\n+\t * |  entry 2 | -|-----------------.  |  |\n+\t * +----------+  |                 |  |  |\n+\t * :          :  |  dir_len        |  |  |\n+\t * .          .  |                 |  |  |\n+\t * :          :  |                 |  |  |\n+\t * +----------+  |                 |  |  |\n+\t * |  entry n |  v                 |  |  |\n+\t * +----------+ <-- data_offset    |  |  |\n+\t * |  data 0  | <------------------|--'  |\n+\t * +----------+                    |     |\n+\t * |  data 1  | <------------------|-----'\n+\t * +----------+                    |\n+\t * | 00000000 | padding            |\n+\t * +----------+ <-- dir_end <------'\n+\t * |   UUID   | <-- directory UUID (child directory)\n+\t * +----------+\n+\t * |  entry 0 |\n+\t * +----------+\n+\t * |  entry 1 |\n+\t * +----------+\n+\t * :          :\n+\t * .          .\n+\t * :          :\n+\t * +----------+\n+\t * |  entry n |\n+\t * +----------+\n+\t * |  data 0  |\n+\t * +----------+\n+\t *\n+\t * We use dir_end to hold pointer to the end of the directory. It\n+\t * will increase as we add directories and each directory should be\n+\t * added starting from previous dir_end.\n+\t */\n+\tdir_len = tb_property_dir_length(dir, false, &data_len);\n+\tdata_offset = start_offset + dir_len;\n+\tdir_end = start_offset + data_len + dir_len;\n+\n+\tif (data_offset > dir_end)\n+\t\treturn -EINVAL;\n+\tif (dir_end > block_len)\n+\t\treturn -EINVAL;\n+\n+\t/* Write headers first */\n+\tif (dir->uuid) {\n+\t\tstruct tb_property_dir_entry *pe;\n+\n+\t\tpe = (struct tb_property_dir_entry *)&block[start_offset];\n+\t\tmemcpy(pe->uuid, dir->uuid, sizeof(pe->uuid));\n+\t\tentry = pe->entries;\n+\t} else {\n+\t\tstruct tb_property_rootdir_entry *re;\n+\n+\t\tre = (struct tb_property_rootdir_entry *)&block[start_offset];\n+\t\tre->magic = TB_PROPERTY_ROOTDIR_MAGIC;\n+\t\tre->length = dir_len - sizeof(*re) / 4;\n+\t\tentry = re->entries;\n+\t}\n+\n+\tlist_for_each_entry(property, &dir->properties, list) {\n+\t\tconst struct tb_property_dir *child;\n+\n+\t\tformat_dwdata(entry, property->key, 2);\n+\t\tentry->type = property->type;\n+\n+\t\tswitch (property->type) {\n+\t\tcase TB_PROPERTY_TYPE_DIRECTORY:\n+\t\t\tchild = property->value.dir;\n+\t\t\tret = __tb_property_format_dir(child, block, dir_end,\n+\t\t\t\t\t\t       block_len);\n+\t\t\tif (ret < 0)\n+\t\t\t\treturn ret;\n+\t\t\tentry->length = tb_property_dir_length(child, false,\n+\t\t\t\t\t\t\t       NULL);\n+\t\t\tentry->value = dir_end;\n+\t\t\tdir_end = ret;\n+\t\t\tbreak;\n+\n+\t\tcase TB_PROPERTY_TYPE_DATA:\n+\t\t\tformat_dwdata(&block[data_offset], property->value.data,\n+\t\t\t\t      property->length);\n+\t\t\tentry->length = property->length;\n+\t\t\tentry->value = data_offset;\n+\t\t\tdata_offset += entry->length;\n+\t\t\tbreak;\n+\n+\t\tcase TB_PROPERTY_TYPE_TEXT:\n+\t\t\tformat_dwdata(&block[data_offset], property->value.text,\n+\t\t\t\t      property->length);\n+\t\t\tentry->length = property->length;\n+\t\t\tentry->value = data_offset;\n+\t\t\tdata_offset += entry->length;\n+\t\t\tbreak;\n+\n+\t\tcase TB_PROPERTY_TYPE_VALUE:\n+\t\t\tentry->length = property->length;\n+\t\t\tentry->value = property->value.immediate;\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tentry++;\n+\t}\n+\n+\treturn dir_end;\n+}\n+\n+/**\n+ * tb_property_format_dir() - Formats directory to the packed XDomain format\n+ * @dir: Directory to format\n+ * @block: Property block where the packed data is placed\n+ * @block_len: Length of the property block\n+ *\n+ * This function formats the directory to the packed format that can be\n+ * then send over the thunderbolt fabric to receiving host. Returns %0 in\n+ * case of success and negative errno on faulure. Passing %NULL in @block\n+ * returns number of entries the block takes.\n+ */\n+ssize_t tb_property_format_dir(const struct tb_property_dir *dir, u32 *block,\n+\t\t\t       size_t block_len)\n+{\n+\tssize_t ret;\n+\n+\tif (!block) {\n+\t\tsize_t dir_len, data_len = 0;\n+\n+\t\tdir_len = tb_property_dir_length(dir, true, &data_len);\n+\t\treturn dir_len + data_len;\n+\t}\n+\n+\tret = __tb_property_format_dir(dir, block, 0, block_len);\n+\treturn ret < 0 ? ret : 0;\n+}\n+\n+/**\n+ * tb_property_add_immediate() - Add immediate property to directory\n+ * @parent: Directory to add the property\n+ * @key: Key for the property\n+ * @value: Immediate value to store with the property\n+ */\n+int tb_property_add_immediate(struct tb_property_dir *parent, const char *key,\n+\t\t\t      u32 value)\n+{\n+\tstruct tb_property *property;\n+\n+\tif (!tb_property_key_valid(key))\n+\t\treturn -EINVAL;\n+\n+\tproperty = tb_property_alloc(key, TB_PROPERTY_TYPE_VALUE);\n+\tif (!property)\n+\t\treturn -ENOMEM;\n+\n+\tproperty->length = 1;\n+\tproperty->value.immediate = value;\n+\n+\tlist_add_tail(&property->list, &parent->properties);\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(tb_property_add_immediate);\n+\n+/**\n+ * tb_property_add_data() - Adds arbitrary data property to directory\n+ * @parent: Directory to add the property\n+ * @key: Key for the property\n+ * @buf: Data buffer to add\n+ * @buflen: Number of bytes in the data buffer\n+ *\n+ * Function takes a copy of @buf and adds it to the directory.\n+ */\n+int tb_property_add_data(struct tb_property_dir *parent, const char *key,\n+\t\t\t const void *buf, size_t buflen)\n+{\n+\t/* Need to pad to dword boundary */\n+\tsize_t size = round_up(buflen, 4);\n+\tstruct tb_property *property;\n+\n+\tif (!tb_property_key_valid(key))\n+\t\treturn -EINVAL;\n+\n+\tproperty = tb_property_alloc(key, TB_PROPERTY_TYPE_DATA);\n+\tif (!property)\n+\t\treturn -ENOMEM;\n+\n+\tproperty->length = size / 4;\n+\tproperty->value.data = kzalloc(size, GFP_KERNEL);\n+\tmemcpy(property->value.data, buf, buflen);\n+\n+\tlist_add_tail(&property->list, &parent->properties);\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(tb_property_add_data);\n+\n+/**\n+ * tb_property_add_text() - Adds string property to directory\n+ * @parent: Directory to add the property\n+ * @key: Key for the property\n+ * @text: String to add\n+ *\n+ * Function takes a copy of @text and adds it to the directory.\n+ */\n+int tb_property_add_text(struct tb_property_dir *parent, const char *key,\n+\t\t\t const char *text)\n+{\n+\t/* Need to pad to dword boundary */\n+\tsize_t size = round_up(strlen(text) + 1, 4);\n+\tstruct tb_property *property;\n+\n+\tif (!tb_property_key_valid(key))\n+\t\treturn -EINVAL;\n+\n+\tproperty = tb_property_alloc(key, TB_PROPERTY_TYPE_TEXT);\n+\tif (!property)\n+\t\treturn -ENOMEM;\n+\n+\tproperty->length = size / 4;\n+\tproperty->value.data = kzalloc(size, GFP_KERNEL);\n+\tstrcpy(property->value.text, text);\n+\n+\tlist_add_tail(&property->list, &parent->properties);\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(tb_property_add_text);\n+\n+/**\n+ * tb_property_add_dir() - Adds a directory to the parent directory\n+ * @parent: Directory to add the property\n+ * @key: Key for the property\n+ * @dir: Directory to add\n+ */\n+int tb_property_add_dir(struct tb_property_dir *parent, const char *key,\n+\t\t\tstruct tb_property_dir *dir)\n+{\n+\tstruct tb_property *property;\n+\n+\tif (!tb_property_key_valid(key))\n+\t\treturn -EINVAL;\n+\n+\tproperty = tb_property_alloc(key, TB_PROPERTY_TYPE_DIRECTORY);\n+\tif (!property)\n+\t\treturn -ENOMEM;\n+\n+\tproperty->value.dir = dir;\n+\n+\tlist_add_tail(&property->list, &parent->properties);\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(tb_property_add_dir);\n+\n+/**\n+ * tb_property_remove() - Removes property from a parent directory\n+ * @property: Property to remove\n+ *\n+ * Note memory for @property is released as well so it is not allowed to\n+ * touch the object after call to this function.\n+ */\n+void tb_property_remove(struct tb_property *property)\n+{\n+\tlist_del(&property->list);\n+\tkfree(property);\n+}\n+EXPORT_SYMBOL_GPL(tb_property_remove);\n+\n+/**\n+ * tb_property_find() - Find a property from a directory\n+ * @dir: Directory where the property is searched\n+ * @key: Key to look for\n+ * @type: Type of the property\n+ *\n+ * Finds and returns property from the given directory. Does not recurse\n+ * into sub-directories. Returns %NULL if the property was not found.\n+ */\n+struct tb_property *tb_property_find(struct tb_property_dir *dir,\n+\tconst char *key, enum tb_property_type type)\n+{\n+\tstruct tb_property *property;\n+\n+\tlist_for_each_entry(property, &dir->properties, list) {\n+\t\tif (property->type == type && !strcmp(property->key, key))\n+\t\t\treturn property;\n+\t}\n+\n+\treturn NULL;\n+}\n+EXPORT_SYMBOL_GPL(tb_property_find);\n+\n+/**\n+ * tb_property_get_next() - Get next property from directory\n+ * @dir: Directory holding properties\n+ * @prev: Previous property in the directory (%NULL returns the first)\n+ */\n+struct tb_property *tb_property_get_next(struct tb_property_dir *dir,\n+\t\t\t\t\t struct tb_property *prev)\n+{\n+\tif (prev) {\n+\t\tif (list_is_last(&prev->list, &dir->properties))\n+\t\t\treturn NULL;\n+\t\treturn list_next_entry(prev, list);\n+\t}\n+\treturn list_first_entry_or_null(&dir->properties, struct tb_property,\n+\t\t\t\t\tlist);\n+}\n+EXPORT_SYMBOL_GPL(tb_property_get_next);\ndiff --git a/include/linux/thunderbolt.h b/include/linux/thunderbolt.h\nnew file mode 100644\nindex 000000000000..5673a4b4becb\n--- /dev/null\n+++ b/include/linux/thunderbolt.h\n@@ -0,0 +1,89 @@\n+/*\n+ * Thunderbolt service API\n+ *\n+ * Copyright (C) 2017, Intel Corporation\n+ * Authors: Michael Jamet <michael.jamet@intel.com>\n+ *          Mika Westerberg <mika.westerberg@linux.intel.com>\n+ *\n+ * This program is free software; you can redistribute it and/or modify\n+ * it under the terms of the GNU General Public License version 2 as\n+ * published by the Free Software Foundation.\n+ */\n+\n+#ifndef THUNDERBOLT_H_\n+#define THUNDERBOLT_H_\n+\n+#include <linux/list.h>\n+#include <linux/uuid.h>\n+\n+/**\n+ * struct tb_property_dir - XDomain property directory\n+ * @uuid: Directory UUID or %NULL if root directory\n+ * @properties: List of properties in this directory\n+ *\n+ * User needs to provide serialization if needed.\n+ */\n+struct tb_property_dir {\n+\tconst uuid_t *uuid;\n+\tstruct list_head properties;\n+};\n+\n+enum tb_property_type {\n+\tTB_PROPERTY_TYPE_UNKNOWN,\n+\tTB_PROPERTY_TYPE_DIRECTORY = 0x44,\n+\tTB_PROPERTY_TYPE_DATA = 0x64,\n+\tTB_PROPERTY_TYPE_TEXT = 0x74,\n+\tTB_PROPERTY_TYPE_VALUE = 0x76,\n+};\n+\n+#define TB_PROPERTY_KEY_SIZE\t8\n+\n+/**\n+ * struct tb_property - XDomain property\n+ * @list: Used to link properties together in a directory\n+ * @key: Key for the property (always terminated).\n+ * @type: Type of the property\n+ * @length: Length of the property data in dwords\n+ * @value: Property value\n+ *\n+ * Users use @type to determine which field in @value is filled.\n+ */\n+struct tb_property {\n+\tstruct list_head list;\n+\tchar key[TB_PROPERTY_KEY_SIZE + 1];\n+\tenum tb_property_type type;\n+\tsize_t length;\n+\tunion {\n+\t\tstruct tb_property_dir *dir;\n+\t\tu8 *data;\n+\t\tchar *text;\n+\t\tu32 immediate;\n+\t} value;\n+};\n+\n+struct tb_property_dir *tb_property_parse_dir(const u32 *block,\n+\t\t\t\t\t      size_t block_len);\n+ssize_t tb_property_format_dir(const struct tb_property_dir *dir, u32 *block,\n+\t\t\t       size_t block_len);\n+struct tb_property_dir *tb_property_create_dir(const uuid_t *uuid);\n+void tb_property_free_dir(struct tb_property_dir *dir);\n+int tb_property_add_immediate(struct tb_property_dir *parent, const char *key,\n+\t\t\t      u32 value);\n+int tb_property_add_data(struct tb_property_dir *parent, const char *key,\n+\t\t\t const void *buf, size_t buflen);\n+int tb_property_add_text(struct tb_property_dir *parent, const char *key,\n+\t\t\t const char *text);\n+int tb_property_add_dir(struct tb_property_dir *parent, const char *key,\n+\t\t\tstruct tb_property_dir *dir);\n+void tb_property_remove(struct tb_property *tb_property);\n+struct tb_property *tb_property_find(struct tb_property_dir *dir,\n+\t\t\tconst char *key, enum tb_property_type type);\n+struct tb_property *tb_property_get_next(struct tb_property_dir *dir,\n+\t\t\t\t\t struct tb_property *prev);\n+\n+#define tb_property_for_each(dir, property)\t\t\t\\\n+\tfor (property = tb_property_get_next(dir, NULL);\t\\\n+\t     property;\t\t\t\t\t\t\\\n+\t     property = tb_property_get_next(dir, property))\n+\n+#endif /* THUNDERBOLT_H_ */\n",
    "prefixes": [
        "02/16"
    ]
}