get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 819309,
    "url": "http://patchwork.ozlabs.org/api/patches/819309/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/linux-pci/patch/1506544822-2632-2-git-send-email-jonathan.derrick@intel.com/",
    "project": {
        "id": 28,
        "url": "http://patchwork.ozlabs.org/api/projects/28/?format=api",
        "name": "Linux PCI development",
        "link_name": "linux-pci",
        "list_id": "linux-pci.vger.kernel.org",
        "list_email": "linux-pci@vger.kernel.org",
        "web_url": null,
        "scm_url": null,
        "webscm_url": null,
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<1506544822-2632-2-git-send-email-jonathan.derrick@intel.com>",
    "list_archive_url": null,
    "date": "2017-09-27T20:40:20",
    "name": "[RFC,1/3] PCI: pci-driver: Introduce pci device delete list",
    "commit_ref": null,
    "pull_url": null,
    "state": "not-applicable",
    "archived": false,
    "hash": "dcfa1e54f7509964b965dac31613d5016ff04bf3",
    "submitter": {
        "id": 68102,
        "url": "http://patchwork.ozlabs.org/api/people/68102/?format=api",
        "name": "Jon Derrick",
        "email": "jonathan.derrick@intel.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/linux-pci/patch/1506544822-2632-2-git-send-email-jonathan.derrick@intel.com/mbox/",
    "series": [
        {
            "id": 5445,
            "url": "http://patchwork.ozlabs.org/api/series/5445/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/linux-pci/list/?series=5445",
            "date": "2017-09-27T20:40:19",
            "name": "Introduce PCI device blacklisting",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/5445/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/819309/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/819309/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<linux-pci-owner@vger.kernel.org>",
        "X-Original-To": "incoming@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming@bilbo.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=linux-pci-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 3y2VD00zjzz9t66\n\tfor <incoming@patchwork.ozlabs.org>;\n\tThu, 28 Sep 2017 06:44:00 +1000 (AEST)",
            "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1751890AbdI0Un7 (ORCPT <rfc822;incoming@patchwork.ozlabs.org>);\n\tWed, 27 Sep 2017 16:43:59 -0400",
            "from mga09.intel.com ([134.134.136.24]:28966 \"EHLO mga09.intel.com\"\n\trhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP\n\tid S1751708AbdI0UnT (ORCPT <rfc822;linux-pci@vger.kernel.org>);\n\tWed, 27 Sep 2017 16:43:19 -0400",
            "from fmsmga004.fm.intel.com ([10.253.24.48])\n\tby orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t27 Sep 2017 13:43:18 -0700",
            "from eremita.lm.intel.com (HELO centos7-vm.localdomain)\n\t([10.232.112.85])\n\tby fmsmga004.fm.intel.com with ESMTP; 27 Sep 2017 13:43:17 -0700"
        ],
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.42,446,1500966000\"; d=\"scan'208\";a=\"316977880\"",
        "From": "Jon Derrick <jonathan.derrick@intel.com>",
        "To": "Greg Kroah-Hartman <gregkh@linuxfoundation.org>,\n\tBjorn Helgaas <helgaas@kernel.org>",
        "Cc": "<linux-pci@vger.kernel.org>, <linux-kernel@vger.kernel.org>,\n\tArjan van de Ven <arjan@linux.intel.com>,\n\tAlan Cox <alan@linux.intel.com>,\n\tDan J Williams <dan.j.williams@intel.com>,\n\tJon Derrick <jonathan.derrick@intel.com>",
        "Subject": "[RFC 1/3] PCI: pci-driver: Introduce pci device delete list",
        "Date": "Wed, 27 Sep 2017 16:40:20 -0400",
        "Message-Id": "<1506544822-2632-2-git-send-email-jonathan.derrick@intel.com>",
        "X-Mailer": "git-send-email 1.8.3.1",
        "In-Reply-To": "<1506544822-2632-1-git-send-email-jonathan.derrick@intel.com>",
        "References": "<1506544822-2632-1-git-send-email-jonathan.derrick@intel.com>",
        "Sender": "linux-pci-owner@vger.kernel.org",
        "Precedence": "bulk",
        "List-ID": "<linux-pci.vger.kernel.org>",
        "X-Mailing-List": "linux-pci@vger.kernel.org"
    },
    "content": "This patch introduces a new kernel command line parameter to mask pci\ndevice ids from pci driver id tables. This prevents masked devices from\nautomatically binding to both built-in and module drivers.\n\nDevices can be later attached through the driver's sysfs new_id\ninteface.\n\nThe use cases for this are primarily for debugging, eg, being able to\nprevent attachment before probes are set up. It can also be used to mask\noff faulty built-in hardware or faulty simulated hardware.\n\nAnother use case is to prevent attachment of devices which will be\npassed to VMs, shortcutting the detachment effort.\n\nThe format is similar to the sysfs new_id format. Device ids are\nspecified with:\n\nVVVV:DDDD[:SVVV:SDDD][:CCCC][:MMMM]\n\nWhere:\nVVVV = Vendor ID\nDDDD = Device ID\nSVVV = Subvendor ID\nSDDD = Subdevice ID\nCCCC = Class\nMMMM = Class Mask\n\nIDs can be chained with commas.\n\nExamples:\n\t<driver>.delete_id=1234:5678\n\t<driver>.delete_id=ffffffff:ffffffff\n\t<driver>.delete_id=ffffffff:ffffffff:ffffffff:ffffffff:010802\n\t<driver>.delete_id=1234:5678,abcd:ef01,2345:ffffffff\n\nSigned-off-by: Jon Derrick <jonathan.derrick@intel.com>\n---\n drivers/pci/pci-driver.c | 253 ++++++++++++++++++++++++++++++++++++++++++++++-\n include/linux/pci.h      |   1 +\n 2 files changed, 252 insertions(+), 2 deletions(-)",
    "diff": "diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c\nindex 11bd267..7acdf13 100644\n--- a/drivers/pci/pci-driver.c\n+++ b/drivers/pci/pci-driver.c\n@@ -20,6 +20,7 @@\n #include <linux/pm_runtime.h>\n #include <linux/suspend.h>\n #include <linux/kexec.h>\n+#include <asm/setup.h>\n #include \"pci.h\"\n \n struct pci_dynid {\n@@ -27,6 +28,250 @@ struct pci_dynid {\n \tstruct pci_device_id id;\n };\n \n+static struct pci_device_id *pci_match_deleted_ids(struct pci_driver *drv,\n+\t\t\t\t\t\t   struct pci_dev *dev,\n+\t\t\t\t\t\t   bool inverse)\n+{\n+\tstruct pci_dynid *deleteid;\n+\tstruct pci_device_id *found_id = NULL;\n+\n+\tspin_lock(&drv->deleteids.lock);\n+\tlist_for_each_entry(deleteid, &drv->deleteids.list, node) {\n+\t\tif (!inverse && pci_match_one_device(&deleteid->id, dev)) {\n+\t\t\tfound_id = &deleteid->id;\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (inverse && !pci_match_one_device(&deleteid->id, dev)) {\n+\t\t\tfound_id = &deleteid->id;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\tspin_unlock(&drv->deleteids.lock);\n+\n+\treturn found_id;\n+}\n+\n+/**\n+ * pci_match_non_deleted_ids - match dev against not-deleted ids\n+ * @ids: array of PCI device id structures to search in\n+ * @dev: the PCI device structure to match against.\n+ *\n+ * Finds devices in driver id table not matching the delete list and tries to\n+ * match them individually to dev. Returns the matching pci_dev_id structure,\n+ * %NULL if there is no match, of -errno if there was a failure to allocate\n+ * memory for the temporary pci_dev\n+ */\n+static struct pci_device_id *pci_match_non_deleted_ids(struct pci_driver *drv,\n+\t\t\t\t\t\t       struct pci_dev *dev)\n+{\n+\tconst struct pci_device_id *ids = drv->id_table;\n+\tstruct pci_device_id *match = NULL;\n+\tstruct pci_dev *tmpdev;\n+\n+\ttmpdev = kzalloc(sizeof(*tmpdev), GFP_KERNEL);\n+\tif (!tmpdev)\n+\t\treturn ERR_PTR(-ENOMEM);\n+\n+\twhile (ids->vendor || ids->subvendor || ids->class_mask) {\n+\t\tstruct pci_device_id *found_id = NULL;\n+\n+\t\ttmpdev->vendor = ids->vendor;\n+\t\ttmpdev->device = ids->device,\n+\t\ttmpdev->subsystem_vendor = ids->subvendor,\n+\t\ttmpdev->subsystem_device = ids->subdevice,\n+\t\ttmpdev->class = ids->class;\n+\n+\t\tfound_id = pci_match_deleted_ids(drv, tmpdev, true);\n+\t\tif (found_id) {\n+\t\t\tconst struct pci_device_id id[2] = { *found_id, {0,} };\n+\t\t\tif (pci_match_id(id, dev)) {\n+\t\t\t\tmatch = found_id;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t\tids++;\n+\t}\n+\n+\tkfree(tmpdev);\n+\n+\treturn match;\n+}\n+\n+/**\n+ * pci_add_delete_id - add a new PCI device ID to a built-in driver's blacklist\n+ * @drv: target pci driver\n+ * @vendor: PCI vendor ID\n+ * @device: PCI device ID\n+ * @subvendor: PCI subvendor ID\n+ * @subdevice: PCI subdevice ID\n+ * @class: PCI class\n+ * @class_mask: PCI class mask\n+ *\n+ * Adds a new dynamic pci device ID to this driver's delete list, preventing\n+ * the device from attaching to built-in drivers\n+ *\n+ * CONTEXT:\n+ * Does GFP_KERNEL allocation.\n+ *\n+ * RETURNS:\n+ * 0 on success, -errno on failure.\n+ */\n+static int pci_add_delete_id(struct pci_driver *drv,\n+\t\t  unsigned int vendor, unsigned int device,\n+\t\t  unsigned int subvendor, unsigned int subdevice,\n+\t\t  unsigned int class, unsigned int class_mask)\n+{\n+\tstruct pci_dynid *deleteid;\n+\n+\tdeleteid = kzalloc(sizeof(*deleteid), GFP_KERNEL);\n+\tif (!deleteid)\n+\t\treturn -ENOMEM;\n+\n+\tdeleteid->id.vendor = vendor;\n+\tdeleteid->id.device = device;\n+\tdeleteid->id.subvendor = subvendor;\n+\tdeleteid->id.subdevice = subdevice;\n+\tdeleteid->id.class = class;\n+\tdeleteid->id.class_mask = class_mask;\n+\n+\tspin_lock(&drv->deleteids.lock);\n+\tlist_add_tail(&deleteid->node, &drv->deleteids.list);\n+\tspin_unlock(&drv->deleteids.lock);\n+\n+\tpr_debug(\"%s: added %04x:%04x:[%04x:%04x]:[%08x:%08x] to delete list\\n\",\n+\t\tdrv->driver.name, vendor, device, subvendor, subdevice,\n+\t\tclass, class_mask);\n+\treturn 0;\n+}\n+\n+static void pci_free_delete_ids(struct pci_driver *drv)\n+{\n+\tstruct pci_dynid *deleteid, *n;\n+\n+\tspin_lock(&drv->deleteids.lock);\n+\tlist_for_each_entry_safe(deleteid, n, &drv->deleteids.list, node) {\n+\t\tlist_del(&deleteid->node);\n+\t\tkfree(deleteid);\n+\t}\n+\tspin_unlock(&drv->deleteids.lock);\n+}\n+\n+/**\n+ * pci_parse_and_add_delete_id - parses kernel cmdline for delete ids\n+ * @drv: the driver structure to register\n+ * @ids: string of comma-delimited ids\n+ *\n+ * Parses a comma-delimited list of pci ids and adds them to the driver's\n+ * delete blacklist\n+ *\n+ * Available formats: VVVV:DDDD[:SVVV:SDDD][:CCCC][:MMMM]\n+ * Use full 32-bit format for PCI_ANY_ID (FFFFFFFF)\n+ */\n+static void pci_parse_and_add_delete_id(struct pci_driver *drv, char *ids)\n+{\n+\tint vendor, device, subvendor, subdevice, class, class_mask;\n+\tint count, fields;\n+\n+\twhile (*ids) {\n+\t\tcount = 0;\n+\t\tfields = sscanf(ids, \"%x:%x:%x:%x:%x:%x%n\",\n+\t\t\t\t&vendor, &device, &subvendor, &subdevice,\n+\t\t\t\t&class, &class_mask, &count);\n+\n+\t\tswitch (fields) {\n+\t\tcase 6:\n+\t\t\tbreak;\n+\t\tcase 5:\n+\t\t\tsscanf(ids, \"%x:%x:%x:%x:%x%n\", &vendor, &device,\n+\t\t\t       &subvendor, &subdevice, &class, &count);\n+\t\t\tclass_mask = 0;\n+\t\t\tbreak;\n+\t\tcase 4:\n+\t\t\tsscanf(ids, \"%x:%x:%x:%x%n\", &vendor, &device,\n+\t\t\t       &subvendor, &subdevice, &count);\n+\t\t\tclass_mask = 0;\n+\t\t\tclass = PCI_ANY_ID;\n+\t\t\tbreak;\n+\t\tcase 2:\n+\t\t\tsscanf(ids, \"%x:%x%n\", &vendor, &device, &count);\n+\t\t\tclass_mask = 0;\n+\t\t\tclass = PCI_ANY_ID;\n+\t\t\tsubvendor = subdevice = PCI_ANY_ID;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tpr_err(\"%s: Can't parse delete_id parameter: %s\\n\",\n+\t\t\t\tdrv->driver.name, ids);\n+\t\t\treturn;\n+\t\t}\n+\n+\t\tif (pci_add_delete_id(drv, vendor, device,\n+\t\t\tsubvendor, subdevice, class, class_mask))\n+\t\t\tbreak;\n+\n+\t\tids += count;\n+\t\tif (*ids != ',') {\n+\t\t\t/* End of param or invalid format */\n+\t\t\tbreak;\n+\t\t}\n+\t\tids++;\n+\t}\n+}\n+\n+static int pci_boot_param_cb(char *param, char *val,\n+\t\t\t     const char *modname, void *arg)\n+{\n+\tstruct pci_driver *drv = arg;\n+\tsize_t len;\n+\tchar *p;\n+\n+\t/* Missing arg on right side of <param>= */\n+\tif (!val)\n+\t\treturn 0;\n+\n+\tp = strchr(param, '.');\n+\tif (!p)\n+\t\treturn 0;\n+\n+\tif (strcmp(p + 1, \"delete_id\"))\n+\t\treturn 0;\n+\n+\tlen = p - param;\n+\tif (len != strlen(drv->driver.name) ||\n+\t   (strncmp(param, drv->driver.name, len)))\n+\t\treturn 0;\n+\n+\tpci_parse_and_add_delete_id(drv, val);\n+\n+\treturn 0;\n+}\n+\n+static void __pci_init_delete_ids(struct pci_driver *drv)\n+{\n+\tstatic char cmdline[COMMAND_LINE_SIZE];\n+\tchar doing[strlen(\"pci-driver() params\") + strlen(drv->driver.name) + 1];\n+\n+\tstrcpy(cmdline, saved_command_line);\n+\tsnprintf(doing, sizeof(doing), \"pci-driver(%s) params\",\n+\t\t drv->driver.name);\n+\tparse_args(doing, cmdline, NULL,\n+\t\t   0, 0, 0, drv, &pci_boot_param_cb);\n+}\n+\n+static void pci_init_delete_ids(struct pci_driver *drv)\n+{\n+\tspin_lock_init(&drv->deleteids.lock);\n+\tINIT_LIST_HEAD(&drv->deleteids.list);\n+\n+\t/*\n+\t * Most configurations won't need to blacklist any device ids.\n+\t * Shortcut those cases before calling into parse_args.\n+\t */\n+\tif (!strstr(saved_command_line, \"delete_id\"))\n+\t\treturn;\n+\n+\t__pci_init_delete_ids(drv);\n+}\n+\n /**\n  * pci_add_dynid - add a new PCI device ID to this driver and re-probe devices\n  * @drv: target pci driver\n@@ -124,7 +369,7 @@ static ssize_t new_id_store(struct device_driver *driver, const char *buf,\n \t\tpdev->subsystem_device = subdevice;\n \t\tpdev->class = class;\n \n-\t\tif (pci_match_id(pdrv->id_table, pdev))\n+\t\tif (pci_match_non_deleted_ids(pdrv, pdev))\n \t\t\tretval = -EEXIST;\n \n \t\tkfree(pdev);\n@@ -269,7 +514,8 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv,\n \t}\n \tspin_unlock(&drv->dynids.lock);\n \n-\tif (!found_id)\n+\t/* Check the device blacklist before matching the driver id table */\n+\tif (!found_id && !pci_match_deleted_ids(drv, dev, false))\n \t\tfound_id = pci_match_id(drv->id_table, dev);\n \n \t/* driver_override will always match, send a dummy id */\n@@ -1310,6 +1556,8 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner,\n \tspin_lock_init(&drv->dynids.lock);\n \tINIT_LIST_HEAD(&drv->dynids.list);\n \n+\tpci_init_delete_ids(drv);\n+\n \t/* register with core */\n \treturn driver_register(&drv->driver);\n }\n@@ -1328,6 +1576,7 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner,\n void pci_unregister_driver(struct pci_driver *drv)\n {\n \tdriver_unregister(&drv->driver);\n+\tpci_free_delete_ids(drv);\n \tpci_free_dynids(drv);\n }\n EXPORT_SYMBOL(pci_unregister_driver);\ndiff --git a/include/linux/pci.h b/include/linux/pci.h\nindex f68c58a..6dc190a 100644\n--- a/include/linux/pci.h\n+++ b/include/linux/pci.h\n@@ -757,6 +757,7 @@ struct pci_driver {\n \tconst struct attribute_group **groups;\n \tstruct device_driver\tdriver;\n \tstruct pci_dynids dynids;\n+\tstruct pci_dynids deleteids;\n };\n \n #define\tto_pci_driver(drv) container_of(drv, struct pci_driver, driver)\n",
    "prefixes": [
        "RFC",
        "1/3"
    ]
}