get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 2175224,
    "url": "http://patchwork.ozlabs.org/api/1.0/patches/2175224/?format=api",
    "project": {
        "id": 28,
        "url": "http://patchwork.ozlabs.org/api/1.0/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
    },
    "msgid": "<20251217151609.3162665-29-den@valinux.co.jp>",
    "date": "2025-12-17T15:16:02",
    "name": "[RFC,v3,28/35] ntb_netdev: Multi-queue support",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "65a042c9c1661a6ea6cae3d607f1a4fde6f0a817",
    "submitter": {
        "id": 91573,
        "url": "http://patchwork.ozlabs.org/api/1.0/people/91573/?format=api",
        "name": "Koichiro Den",
        "email": "den@valinux.co.jp"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/linux-pci/patch/20251217151609.3162665-29-den@valinux.co.jp/mbox/",
    "series": [
        {
            "id": 485709,
            "url": "http://patchwork.ozlabs.org/api/1.0/series/485709/?format=api",
            "date": "2025-12-17T15:15:53",
            "name": "NTB transport backed by endpoint DW eDMA",
            "version": 3,
            "mbox": "http://patchwork.ozlabs.org/series/485709/mbox/"
        }
    ],
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2175224/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "\n <linux-pci+bounces-43194-incoming=patchwork.ozlabs.org@vger.kernel.org>",
        "X-Original-To": [
            "incoming@patchwork.ozlabs.org",
            "linux-pci@vger.kernel.org"
        ],
        "Delivered-To": "patchwork-incoming@legolas.ozlabs.org",
        "Authentication-Results": [
            "legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=valinux.co.jp header.i=@valinux.co.jp\n header.a=rsa-sha256 header.s=selector1 header.b=dwCQeaGR;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=172.105.105.114; helo=tor.lore.kernel.org;\n envelope-from=linux-pci+bounces-43194-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)",
            "smtp.subspace.kernel.org;\n\tdkim=pass (1024-bit key) header.d=valinux.co.jp header.i=@valinux.co.jp\n header.b=\"dwCQeaGR\"",
            "smtp.subspace.kernel.org;\n arc=fail smtp.client-ip=52.101.228.20",
            "smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=valinux.co.jp",
            "smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=valinux.co.jp",
            "dkim=none (message not signed)\n header.d=none;dmarc=none action=none header.from=valinux.co.jp;"
        ],
        "Received": [
            "from tor.lore.kernel.org (tor.lore.kernel.org [172.105.105.114])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4dWdXx57Wvz1xty\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 18 Dec 2025 02:50:09 +1100 (AEDT)",
            "from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby tor.lore.kernel.org (Postfix) with ESMTP id D03BA30B18C7\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 17 Dec 2025 15:25:27 +0000 (UTC)",
            "from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id 3B146364E9B;\n\tWed, 17 Dec 2025 15:17:52 +0000 (UTC)",
            "from OS0P286CU011.outbound.protection.outlook.com\n (mail-japanwestazon11010020.outbound.protection.outlook.com [52.101.228.20])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 40691361DAD;\n\tWed, 17 Dec 2025 15:17:49 +0000 (UTC)",
            "from TYWP286MB2697.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:24c::11)\n by TYCP286MB2863.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:306::14) with\n Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9434.6; Wed, 17 Dec\n 2025 15:16:39 +0000",
            "from TYWP286MB2697.JPNP286.PROD.OUTLOOK.COM\n ([fe80::fb7e:f4ed:a580:9d03]) by TYWP286MB2697.JPNP286.PROD.OUTLOOK.COM\n ([fe80::fb7e:f4ed:a580:9d03%5]) with mapi id 15.20.9434.001; Wed, 17 Dec 2025\n 15:16:39 +0000"
        ],
        "ARC-Seal": [
            "i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1765984672; cv=fail;\n b=bqKahxvMH5zqqWIAv/wyOwtvha3+YG/AJIvevgch2oJHdsKHIFXXix24v9GiFc9MAQeAdf+uqkQkq6gDUujIXePsXnEJCzofl287HwGGZjwOjS3EIdoocFpdNtfsqfhMdC53cCD4TgyIthduVhqxDApj6In++mXxiK4lGmYAUVU=",
            "i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none;\n b=NAFviUgJ/eYPP00FdjelQ6molxSmQTtVrxnMQ0y0cCYy7JIssqUUG2UQdz/BTrJE19BxpP2h8k+gTTOLb+wZLl0RX/0nR0UYkqM/Vij59AaA6zC1BzdR6jz2/tJhIV42aMB5C5+ndvokfWlvspzNTfI4ADrb80LtFL/MOwtSJO6dpeDAETY4Yd3IydwCqX7mZ/GuDc7NANOLc7vTsXzkBIVvUhmT7K1P6MHLBnF4X1ZbdCQdOrUqF1AsXYNBvr+tCzMCP3HVzDaFDL4jR+f+DetIlTlAm9Y1QLpGBr5bDqvbYQwH6qYSWZoU+vyr/bTWz5RGNdxXjG8LpQU6UFTtLw=="
        ],
        "ARC-Message-Signature": [
            "i=2; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1765984672; c=relaxed/simple;\n\tbh=fOSJLrLrFLoKv0qHk+W+c7m9DC4dwJUYznyFzyvl1sU=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t Content-Type:MIME-Version;\n b=nJdMBb6dslm5taLpoB8BSOhK25kVnwSYLzPhnS4UrMAayShtr1/ePcRSDpGAyfXLQ6x5BS/0lr3A1t5I1E0XzEkeA7DSjhiweu93HgeXwP3uU6VLeQSOmGgSf0eB6twU/35qIlCr3xGX6Fu1FqOVFPfN6zHIe6K9/20DeeFnus8=",
            "i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com;\n s=arcselector10001;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1;\n bh=d06MQL3alOxYyQ0pwMZdFFY6ArVfMDxTphVx+kcblwo=;\n b=xscci4InYLdJQrmUZHL37StNEZZnHp+OLU4mBwMOMl0w/tjiuhuRR8vWWieFxnxq5n0fvrhGzDBY9OlNAlBs/c9oroRzkRy4Za1GYPIJF1gCRMYNJOIaEy/UQ41bQXsgkexwRtTurs2JfLoyDtc4fIWx/VcFPQv9Bo+k//K+C6a+wTkEgfsTLZc3T03fdvxCJWBvuQK3fvJJgP4iC/vSZUWTAbDybmED+zeJmLmu2waN5nRkw7nYvU+7ZBBJvUGG0CcrzNV4lmX1lxtP9wEfYj4Mgv7UNvmJycCaqmufBBIx/Ud35Tz4G5ghHUI+9z85uyddz7LikbzJnxVf5awyPA=="
        ],
        "ARC-Authentication-Results": [
            "i=2; smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=valinux.co.jp;\n spf=pass smtp.mailfrom=valinux.co.jp;\n dkim=pass (1024-bit key) header.d=valinux.co.jp header.i=@valinux.co.jp\n header.b=dwCQeaGR; arc=fail smtp.client-ip=52.101.228.20",
            "i=1; mx.microsoft.com 1; spf=pass\n smtp.mailfrom=valinux.co.jp; dmarc=pass action=none\n header.from=valinux.co.jp; dkim=pass header.d=valinux.co.jp; arc=none"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=valinux.co.jp;\n s=selector1;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;\n bh=d06MQL3alOxYyQ0pwMZdFFY6ArVfMDxTphVx+kcblwo=;\n b=dwCQeaGRhcQPG0WBOm6ufnjbXhhBqP8NfFzCr4sYY5Edz2RLx/RlZM3DCXbC6ukktcehEdcCG1sbrmPQNbbKrYl2g+rRPqabx1xsm93Asm1JT+mLm9Fax0sNfEZx8Rc2kNbMoOExy53BDQ3OXHqgyLgA8Q8gddmnyA01u62cqL0=",
        "From": "Koichiro Den <den@valinux.co.jp>",
        "To": "Frank.Li@nxp.com,\n\tdave.jiang@intel.com,\n\tntb@lists.linux.dev,\n\tlinux-pci@vger.kernel.org,\n\tdmaengine@vger.kernel.org,\n\tlinux-renesas-soc@vger.kernel.org,\n\tnetdev@vger.kernel.org,\n\tlinux-kernel@vger.kernel.org",
        "Cc": "mani@kernel.org,\n\tkwilczynski@kernel.org,\n\tkishon@kernel.org,\n\tbhelgaas@google.com,\n\tcorbet@lwn.net,\n\tgeert+renesas@glider.be,\n\tmagnus.damm@gmail.com,\n\trobh@kernel.org,\n\tkrzk+dt@kernel.org,\n\tconor+dt@kernel.org,\n\tvkoul@kernel.org,\n\tjoro@8bytes.org,\n\twill@kernel.org,\n\trobin.murphy@arm.com,\n\tjdmason@kudzu.us,\n\tallenbh@gmail.com,\n\tandrew+netdev@lunn.ch,\n\tdavem@davemloft.net,\n\tedumazet@google.com,\n\tkuba@kernel.org,\n\tpabeni@redhat.com,\n\tBasavaraj.Natikar@amd.com,\n\tShyam-sundar.S-k@amd.com,\n\tkurt.schwemmer@microsemi.com,\n\tlogang@deltatee.com,\n\tjingoohan1@gmail.com,\n\tlpieralisi@kernel.org,\n\tutkarsh02t@gmail.com,\n\tjbrunet@baylibre.com,\n\tdlemoal@kernel.org,\n\tarnd@arndb.de,\n\telfring@users.sourceforge.net,\n\tden@valinux.co.jp",
        "Subject": "[RFC PATCH v3 28/35] ntb_netdev: Multi-queue support",
        "Date": "Thu, 18 Dec 2025 00:16:02 +0900",
        "Message-ID": "<20251217151609.3162665-29-den@valinux.co.jp>",
        "X-Mailer": "git-send-email 2.51.0",
        "In-Reply-To": "<20251217151609.3162665-1-den@valinux.co.jp>",
        "References": "<20251217151609.3162665-1-den@valinux.co.jp>",
        "Content-Transfer-Encoding": "8bit",
        "Content-Type": "text/plain",
        "X-ClientProxiedBy": "TY4P301CA0106.JPNP301.PROD.OUTLOOK.COM\n (2603:1096:405:37b::17) To TYWP286MB2697.JPNP286.PROD.OUTLOOK.COM\n (2603:1096:400:24c::11)",
        "Precedence": "bulk",
        "X-Mailing-List": "linux-pci@vger.kernel.org",
        "List-Id": "<linux-pci.vger.kernel.org>",
        "List-Subscribe": "<mailto:linux-pci+subscribe@vger.kernel.org>",
        "List-Unsubscribe": "<mailto:linux-pci+unsubscribe@vger.kernel.org>",
        "MIME-Version": "1.0",
        "X-MS-PublicTrafficType": "Email",
        "X-MS-TrafficTypeDiagnostic": "TYWP286MB2697:EE_|TYCP286MB2863:EE_",
        "X-MS-Office365-Filtering-Correlation-Id": "a4c5e57e-be89-4e7f-4e21-08de3d7f46d9",
        "X-MS-Exchange-SenderADCheck": "1",
        "X-MS-Exchange-AntiSpam-Relay": "0",
        "X-Microsoft-Antispam": "\n\tBCL:0;ARA:13230040|7416014|376014|10070799003|1800799024|366016;",
        "X-Microsoft-Antispam-Message-Info": "\n 4yLkxDCH/B/xkFCekL5/KbJSw76bENkIpzfPTySCCZB4NEszX9t83ZHNzOmI9UdO3wz/gt7MtNR0zzSmjzVB+Oj7lysUEC1odb41xdFza9jd7t7OItMYzBp1etCYnzdfkH4vG4kmnfago33T8uxHCkRPeR/6nyh7PgKB2QfKYMSxKOBBzudhZ6Keu7ZDWxXL0X0hERZ8KFk2czEux0UtL2tgbW5GYKax0CwCGnjQ/Z3x6gtswE63QKgtczGQTj0IC1Edl4SO1RIbVNatzvabjtGaAdPieFpOwjZHb5h3hOjSxC18qAogu4+hwz3K0d7/eED7lb4q4jSua3vbCzWfdZaOCwLtrYURNS0kyePxV/qjQ/uR5W9vu4C+8/Mxd3IEPUPHMpZE1DPrxj5iX19WSIWLFl62k+re1fbz9RYuMPzaYAHAxZS1LJurPvBn06TxqwUg8mVFEQumX+WwnKl9ATHrsMe8ZhPu94X8TQ8XaNFmy+G+s6CqV3dmJ+Rr0U0DdGv9MbYdjlaiGi+lx8o0ImPWJSPnYdQ5LcamHwq03v9w5AleQ9BgGL6QcO6/fTOY29/PODEOaU2zp98U74E07hoA+uBf2kWE+ay7ItdkZRMdHGGzQ5amfWLTV/1pDSrkqkeXY7Vt/EVijNvT4mQiycyYbBWwt3UfkSXJ4g9a1y0AgLjU2RXHFsbzi22NdE9TVX3iANgippEILEgQeuMIQHS3YVThEni6YHfE+lxZAUODSHg1PEJW10zc7RZCyMNPR9YAw8zTJ74RGB1Iw0IP1KIGVj8rXY03qFk9h6Y271P0+4pRP61qYiz2XoNmJjbccaK/CF9/0uGKQaYWuKm1gsUqgYpXlxQ9na1nTrm95N7vAah3mUAc2hUkJoMI3RDijwt76264TghOMXixzaXXKAYaUe2p1WGQmvZaGCIYM8W6a+ZfN/Y3OTkmpTvmJ/rQVcbRRXMytWrfb9JC4HDBUyPV7XzJDpMtpARWowkP8Eu6JQfSBEPIRLxrpYeo/PI72UKTU/cgdJsymAyOqYwUmq0LO6RZroxQDHlV0ffz7OvxGTY2VYPIRODx8K4NyJ7Npu3YbtVJcloTUv7PwPlreS6X5GzzN9K9tgOCKj1epegDloAiKlgzSAtuHa3JJ6cViXmlASgHRj9F9/hRWkQ1Tg4nl01QaqZ6+d0vnzs4+TOECYcSfgr6VLiFxkoXZGkqgAD0VzAMzfWS6T70C1tlBXR26nRXlTR1EN5sP7OnDgnK6EXb4I6tw+1yfoRZ9bt6f1avBLkjEGzvNKVjVz+J6Al1uIBiQMpJiMiA65ISTtrKjWwbhOPOR8xao1zmM3n9hP4qSMacRvXyN/Ghsh7BmkSWmCU+QqDwd1NKu8XocNjIB6ZC2oGg9Ua2ec12spAUGapZIL6qo+NSLVjoGiEQc9sTZP6/P/n5MWgcgcaryNSeJ0MY1rESkqwyhbZ98YVZ",
        "X-Forefront-Antispam-Report": "\n\tCIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:TYWP286MB2697.JPNP286.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(7416014)(376014)(10070799003)(1800799024)(366016);DIR:OUT;SFP:1101;",
        "X-MS-Exchange-AntiSpam-MessageData-ChunkCount": "1",
        "X-MS-Exchange-AntiSpam-MessageData-0": "\n RhEjU/OxcZtLuYJqNF0xsB7I/ypfSQMhebXCpyfzWXA/ElsFl4lIxAdIrOXnU1IOfZM8+B0quMrdDeqx0qCdSbmEpDMiWXUnoq2YXx/RSLlgtxSjJe1C/bR6QgR4ZnF3hM7pQSX9PwA+9N0NBZw27vRZATTwOM2fIjQX818cJt4/STUfjlT5fa9G8GUa9XxBOkxJcU+yS7CoF8b/NQSESByLnL09r1vqDHkznP6C1G6eY0PvSP+NjMXFH1g7sHF1GA0fhPN4uMp2Bj8n9yirFhWv8FrGfDDCyCgTnmkKxl30hZOl4vaOKfucsw7/boC4KUOX7GXCB0NxvYnW9gyIDjPyiDlL4+/R+qKQcBkSB4MrDU1VRAcKg3wVtC8C9vDBrG70jeCHfA8MXMoq6F1OUBUTF56wOpR8/9ypBIlbbuxD3+Iz0S6duE6YmTzeqInuHbbutWlFfzYKhN8Xxfx6xu8B6Y1MqL0uy44ZFPx38O07NsJ6M6EYDR6jIF3gWG1dbl4/7urRQpcLs4ZqEsS1hqmn6YDlMOhHA1emja+N0/cULiIahujqvpn8IT26ScGpPgZo02MxsBbsXaTG5Eh7hqiV2EULgWeCxec6cw8O6SR9TLk1eb3cR3sXQRMM+cpZ0t2ud25sqkMltGeRATGm5ErGHdDhVE5e6Po9ikQIBP36YmytAlvN5adc6hrU1Ul+lv7D+marM/TyPlIlal2+fnUuIMc5jZaIaoqhkzUesLai41MlgLjZ97plfKoSLkYji1MlcBrpyA1dQNcytlFul9+FAXCVHgrzC+6VcbQgsHoEA5gfihe2gQQqw2y2WJWcgybqxzuVnXN0ZihOEXYB30S5uCD58J/CmxvNJh/Apx9JBC7ziueKSPAtiXwXCDgy3MDt3eIQuEf/xxXomrG5A2pKsBAE8ldmgCE9Jv0SJiBO2/+yPXdOWs6kN50XOGykjYHWVhcu+Ykk+t+RjcRpszx+3d/2Q7pl1BnFH/UvyzIsezklETl/WkySBbJzkOi/g6pbedvXo8hsgJLyKJxb2C2k8gZnbi+NgwOCeC2hiNx20xzGDB3eJQBIWFTo2CBzm6XUjalf3UEsdmjbdZs16Vu9YFALZqjasMTolGAd4iX62c0rOhn9gl6ntGAZLjF7rBg9Z0cF9x/+GocxScvCCr1AaM9Ex2HaAzBjkNFYAUL6ZgHPz3oZqL9oc7YRvn24PWsAByaNkL8PDREe8ERulO2OfwowLG1N8qovPy7rB2HGOgeuS6J3pMmyZQ2v8B9HHIHy5CcibeMMlLoyNCnPYAyBgWDtV9sKULGK7B1+3KiF6lGkzvG4Uu/OF+kcVdOe6wzHBIn/3O+NsqrSm0z0J5gAENRYA4qfbebw49jXqr+V7+3KavN4uVxLXm5TgVa7K89FVO6rNki4y7O3KNAlv3tSTxLdR7KI1eHNfZt00QJgnj96Ecno8iLc6H9YudyB79AJOJwjmH9m/6onGd5HvWraXjEDr0AQI8sT9xCBST9IX9p2kTp0S+tly7qKgr2hjAqBQiix/6qzrQMiaB5BGOXHOlvRWJGRjBRGLH1QfM1jDYZcIeavAlB/c1l+NyRZLlfPT8FLzkkYDV4t7CT3yhV0lvXaONye1eSoK6nyU00=",
        "X-OriginatorOrg": "valinux.co.jp",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "\n a4c5e57e-be89-4e7f-4e21-08de3d7f46d9",
        "X-MS-Exchange-CrossTenant-AuthSource": "TYWP286MB2697.JPNP286.PROD.OUTLOOK.COM",
        "X-MS-Exchange-CrossTenant-AuthAs": "Internal",
        "X-MS-Exchange-CrossTenant-OriginalArrivalTime": "17 Dec 2025 15:16:39.2912\n (UTC)",
        "X-MS-Exchange-CrossTenant-FromEntityHeader": "Hosted",
        "X-MS-Exchange-CrossTenant-Id": "7a57bee8-f73d-4c5f-a4f7-d72c91c8c111",
        "X-MS-Exchange-CrossTenant-MailboxType": "HOSTED",
        "X-MS-Exchange-CrossTenant-UserPrincipalName": "\n JZ6dB9yXjKs/zvwAdw+a44MfdhOKlRc6fvBng4/eYTD8XOgcvE1TJ68vkCf5d/dKTC6xwdLcHMvpSus++SfcVQ==",
        "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "TYCP286MB2863"
    },
    "content": "In eDMA-backed mode (use_remote_edma=1), ntb_transport can scale\nthroughput across multiple queue pairs without being constrained by\nscarce PCI memory window space used for data-plane buffers. It contrasts\nwith the default backend mode, where even with a single queue pair, only\nup to 15 in-flight descriptors fit in a 1 MiB MW.\n\nTeach ntb_netdev to allocate multiple ntb_transport queue pairs and\nexpose them as a multi-queue net_device.\n\nWith this patch, up to N queue pairs are created, where N is chosen as\nfollows:\n\n  - By default, N is num_online_cpus(), to give each CPU its own queue.\n  - If the ntb_num_queues module parameter is non-zero, it overrides the\n    default and requests that many queues.\n  - In both cases the requested value is capped at a fixed upper bound\n    to avoid unbounded allocations, and by the number of queue pairs\n    actually available from ntb_transport.\n\nIf only one queue pair can be created (or ntb_num_queues=1 is set), the\ndriver effectively falls back to the previous single-queue behaviour.\n\nSigned-off-by: Koichiro Den <den@valinux.co.jp>\n---\n drivers/net/ntb_netdev.c | 341 ++++++++++++++++++++++++++++-----------\n 1 file changed, 243 insertions(+), 98 deletions(-)",
    "diff": "diff --git a/drivers/net/ntb_netdev.c b/drivers/net/ntb_netdev.c\nindex fbeae05817e9..7aeca35b46c5 100644\n--- a/drivers/net/ntb_netdev.c\n+++ b/drivers/net/ntb_netdev.c\n@@ -53,6 +53,8 @@\n #include <linux/pci.h>\n #include <linux/ntb.h>\n #include <linux/ntb_transport.h>\n+#include <linux/cpumask.h>\n+#include <linux/slab.h>\n \n #define NTB_NETDEV_VER\t\"0.7\"\n \n@@ -70,26 +72,84 @@ static unsigned int tx_start = 10;\n /* Number of descriptors still available before stop upper layer tx */\n static unsigned int tx_stop = 5;\n \n+/*\n+ * Upper bound on how many queue pairs we will try to create even if\n+ * ntb_num_queues or num_online_cpus() is very large. This is an\n+ * arbitrary safety cap to avoid unbounded allocations.\n+ */\n+#define NTB_NETDEV_MAX_QUEUES  64\n+\n+/*\n+ * ntb_num_queues == 0 (default) means:\n+ *   - use num_online_cpus() as the desired queue count, capped by\n+ *     NTB_NETDEV_MAX_QUEUES.\n+ * ntb_num_queues > 0:\n+ *   - try to create exactly ntb_num_queues queue pairs (again capped\n+ *     by NTB_NETDEV_MAX_QUEUES), but fall back to the number of queue\n+ *     pairs actually available from ntb_transport.\n+ */\n+static unsigned int ntb_num_queues;\n+module_param(ntb_num_queues, uint, 0644);\n+MODULE_PARM_DESC(ntb_num_queues,\n+\t\t \"Number of NTB netdev queue pairs to use (0 = per-CPU)\");\n+\n+struct ntb_netdev;\n+\n+struct ntb_netdev_queue {\n+\tstruct ntb_netdev *ntdev;\n+\tstruct ntb_transport_qp *qp;\n+\tstruct timer_list tx_timer;\n+\tu16 qid;\n+};\n+\n struct ntb_netdev {\n \tstruct pci_dev *pdev;\n \tstruct net_device *ndev;\n-\tstruct ntb_transport_qp *qp;\n-\tstruct timer_list tx_timer;\n+\tunsigned int num_queues;\n+\tstruct ntb_netdev_queue *queues;\n };\n \n #define\tNTB_TX_TIMEOUT_MS\t1000\n #define\tNTB_RXQ_SIZE\t\t100\n \n+static unsigned int ntb_netdev_default_queues(void)\n+{\n+\tunsigned int n;\n+\n+\tif (ntb_num_queues)\n+\t\tn = ntb_num_queues;\n+\telse\n+\t\tn = num_online_cpus();\n+\n+\tif (!n)\n+\t\tn = 1;\n+\n+\tif (n > NTB_NETDEV_MAX_QUEUES)\n+\t\tn = NTB_NETDEV_MAX_QUEUES;\n+\n+\treturn n;\n+}\n+\n static void ntb_netdev_event_handler(void *data, int link_is_up)\n {\n-\tstruct net_device *ndev = data;\n-\tstruct ntb_netdev *dev = netdev_priv(ndev);\n+\tstruct ntb_netdev_queue *q = data;\n+\tstruct ntb_netdev *dev = q->ntdev;\n+\tstruct net_device *ndev = dev->ndev;\n+\tbool any_up = false;\n+\tunsigned int i;\n \n-\tnetdev_dbg(ndev, \"Event %x, Link %x\\n\", link_is_up,\n-\t\t   ntb_transport_link_query(dev->qp));\n+\tnetdev_dbg(ndev, \"Event %x, Link %x, qp %u\\n\", link_is_up,\n+\t\t   ntb_transport_link_query(q->qp), q->qid);\n \n \tif (link_is_up) {\n-\t\tif (ntb_transport_link_query(dev->qp))\n+\t\tfor (i = 0; i < dev->num_queues; i++) {\n+\t\t\tif (ntb_transport_link_query(dev->queues[i].qp)) {\n+\t\t\t\tany_up = true;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (any_up)\n \t\t\tnetif_carrier_on(ndev);\n \t} else {\n \t\tnetif_carrier_off(ndev);\n@@ -99,7 +159,9 @@ static void ntb_netdev_event_handler(void *data, int link_is_up)\n static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,\n \t\t\t\t  void *data, int len)\n {\n-\tstruct net_device *ndev = qp_data;\n+\tstruct ntb_netdev_queue *q = qp_data;\n+\tstruct ntb_netdev *dev = q->ntdev;\n+\tstruct net_device *ndev = dev->ndev;\n \tstruct sk_buff *skb;\n \tint rc;\n \n@@ -135,7 +197,8 @@ static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,\n \t}\n \n enqueue_again:\n-\trc = ntb_transport_rx_enqueue(qp, skb, skb->data, ndev->mtu + ETH_HLEN);\n+\trc = ntb_transport_rx_enqueue(q->qp, skb, skb->data,\n+\t\t\t\t      ndev->mtu + ETH_HLEN);\n \tif (rc) {\n \t\tdev_kfree_skb_any(skb);\n \t\tndev->stats.rx_errors++;\n@@ -143,42 +206,37 @@ static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,\n \t}\n }\n \n-static int __ntb_netdev_maybe_stop_tx(struct net_device *netdev,\n-\t\t\t\t      struct ntb_transport_qp *qp, int size)\n+static int ntb_netdev_maybe_stop_tx(struct ntb_netdev_queue *q, int size)\n {\n-\tstruct ntb_netdev *dev = netdev_priv(netdev);\n+\tstruct net_device *ndev = q->ntdev->ndev;\n+\n+\tif (ntb_transport_tx_free_entry(q->qp) >= size)\n+\t\treturn 0;\n+\n+\tnetif_stop_subqueue(ndev, q->qid);\n \n-\tnetif_stop_queue(netdev);\n \t/* Make sure to see the latest value of ntb_transport_tx_free_entry()\n \t * since the queue was last started.\n \t */\n \tsmp_mb();\n \n-\tif (likely(ntb_transport_tx_free_entry(qp) < size)) {\n-\t\tmod_timer(&dev->tx_timer, jiffies + usecs_to_jiffies(tx_time));\n+\tif (likely(ntb_transport_tx_free_entry(q->qp) < size)) {\n+\t\tmod_timer(&q->tx_timer, jiffies + usecs_to_jiffies(tx_time));\n \t\treturn -EBUSY;\n \t}\n \n-\tnetif_start_queue(netdev);\n-\treturn 0;\n-}\n-\n-static int ntb_netdev_maybe_stop_tx(struct net_device *ndev,\n-\t\t\t\t    struct ntb_transport_qp *qp, int size)\n-{\n-\tif (netif_queue_stopped(ndev) ||\n-\t    (ntb_transport_tx_free_entry(qp) >= size))\n-\t\treturn 0;\n+\tnetif_wake_subqueue(ndev, q->qid);\n \n-\treturn __ntb_netdev_maybe_stop_tx(ndev, qp, size);\n+\treturn 0;\n }\n \n static void ntb_netdev_tx_handler(struct ntb_transport_qp *qp, void *qp_data,\n \t\t\t\t  void *data, int len)\n {\n-\tstruct net_device *ndev = qp_data;\n+\tstruct ntb_netdev_queue *q = qp_data;\n+\tstruct ntb_netdev *dev = q->ntdev;\n+\tstruct net_device *ndev = dev->ndev;\n \tstruct sk_buff *skb;\n-\tstruct ntb_netdev *dev = netdev_priv(ndev);\n \n \tskb = data;\n \tif (!skb || !ndev)\n@@ -194,13 +252,12 @@ static void ntb_netdev_tx_handler(struct ntb_transport_qp *qp, void *qp_data,\n \n \tdev_kfree_skb_any(skb);\n \n-\tif (ntb_transport_tx_free_entry(dev->qp) >= tx_start) {\n+\tif (ntb_transport_tx_free_entry(qp) >= tx_start) {\n \t\t/* Make sure anybody stopping the queue after this sees the new\n \t\t * value of ntb_transport_tx_free_entry()\n \t\t */\n \t\tsmp_mb();\n-\t\tif (netif_queue_stopped(ndev))\n-\t\t\tnetif_wake_queue(ndev);\n+\t\tnetif_wake_subqueue(ndev, q->qid);\n \t}\n }\n \n@@ -208,16 +265,26 @@ static netdev_tx_t ntb_netdev_start_xmit(struct sk_buff *skb,\n \t\t\t\t\t struct net_device *ndev)\n {\n \tstruct ntb_netdev *dev = netdev_priv(ndev);\n+\tu16 qid = skb_get_queue_mapping(skb);\n+\tstruct ntb_netdev_queue *q;\n \tint rc;\n \n-\tntb_netdev_maybe_stop_tx(ndev, dev->qp, tx_stop);\n+\tif (unlikely(!dev->num_queues))\n+\t\tgoto err;\n+\n+\tif (unlikely(qid >= dev->num_queues))\n+\t\tqid = qid % dev->num_queues;\n \n-\trc = ntb_transport_tx_enqueue(dev->qp, skb, skb->data, skb->len);\n+\tq = &dev->queues[qid];\n+\n+\tntb_netdev_maybe_stop_tx(q, tx_stop);\n+\n+\trc = ntb_transport_tx_enqueue(q->qp, skb, skb->data, skb->len);\n \tif (rc)\n \t\tgoto err;\n \n \t/* check for next submit */\n-\tntb_netdev_maybe_stop_tx(ndev, dev->qp, tx_stop);\n+\tntb_netdev_maybe_stop_tx(q, tx_stop);\n \n \treturn NETDEV_TX_OK;\n \n@@ -229,80 +296,103 @@ static netdev_tx_t ntb_netdev_start_xmit(struct sk_buff *skb,\n \n static void ntb_netdev_tx_timer(struct timer_list *t)\n {\n-\tstruct ntb_netdev *dev = timer_container_of(dev, t, tx_timer);\n+\tstruct ntb_netdev_queue *q = container_of(t, struct ntb_netdev_queue, tx_timer);\n+\tstruct ntb_netdev *dev = q->ntdev;\n \tstruct net_device *ndev = dev->ndev;\n \n-\tif (ntb_transport_tx_free_entry(dev->qp) < tx_stop) {\n-\t\tmod_timer(&dev->tx_timer, jiffies + usecs_to_jiffies(tx_time));\n+\tif (ntb_transport_tx_free_entry(q->qp) < tx_stop) {\n+\t\tmod_timer(&q->tx_timer, jiffies + usecs_to_jiffies(tx_time));\n \t} else {\n-\t\t/* Make sure anybody stopping the queue after this sees the new\n+\t\t/*\n+\t\t * Make sure anybody stopping the queue after this sees the new\n \t\t * value of ntb_transport_tx_free_entry()\n \t\t */\n \t\tsmp_mb();\n-\t\tif (netif_queue_stopped(ndev))\n-\t\t\tnetif_wake_queue(ndev);\n+\t\tnetif_wake_subqueue(ndev, q->qid);\n \t}\n }\n \n static int ntb_netdev_open(struct net_device *ndev)\n {\n \tstruct ntb_netdev *dev = netdev_priv(ndev);\n+\tstruct ntb_netdev_queue *queue;\n \tstruct sk_buff *skb;\n-\tint rc, i, len;\n-\n-\t/* Add some empty rx bufs */\n-\tfor (i = 0; i < NTB_RXQ_SIZE; i++) {\n-\t\tskb = netdev_alloc_skb(ndev, ndev->mtu + ETH_HLEN);\n-\t\tif (!skb) {\n-\t\t\trc = -ENOMEM;\n-\t\t\tgoto err;\n-\t\t}\n+\tint rc = 0, i, len;\n+\tunsigned int q;\n \n-\t\trc = ntb_transport_rx_enqueue(dev->qp, skb, skb->data,\n-\t\t\t\t\t      ndev->mtu + ETH_HLEN);\n-\t\tif (rc) {\n-\t\t\tdev_kfree_skb(skb);\n-\t\t\tgoto err;\n+\t/* Add some empty rx bufs for each queue */\n+\tfor (q = 0; q < dev->num_queues; q++) {\n+\t\tqueue = &dev->queues[q];\n+\n+\t\tfor (i = 0; i < NTB_RXQ_SIZE; i++) {\n+\t\t\tskb = netdev_alloc_skb(ndev, ndev->mtu + ETH_HLEN);\n+\t\t\tif (!skb) {\n+\t\t\t\trc = -ENOMEM;\n+\t\t\t\tgoto err;\n+\t\t\t}\n+\n+\t\t\trc = ntb_transport_rx_enqueue(queue->qp, skb, skb->data,\n+\t\t\t\t\t\t      ndev->mtu + ETH_HLEN);\n+\t\t\tif (rc) {\n+\t\t\t\tdev_kfree_skb(skb);\n+\t\t\t\tgoto err;\n+\t\t\t}\n \t\t}\n-\t}\n \n-\ttimer_setup(&dev->tx_timer, ntb_netdev_tx_timer, 0);\n+\t\ttimer_setup(&queue->tx_timer, ntb_netdev_tx_timer, 0);\n+\t}\n \n \tnetif_carrier_off(ndev);\n-\tntb_transport_link_up(dev->qp);\n-\tnetif_start_queue(ndev);\n+\n+\tfor (q = 0; q < dev->num_queues; q++)\n+\t\tntb_transport_link_up(dev->queues[q].qp);\n+\n+\tnetif_tx_start_all_queues(ndev);\n \n \treturn 0;\n \n err:\n-\twhile ((skb = ntb_transport_rx_remove(dev->qp, &len)))\n-\t\tdev_kfree_skb(skb);\n+\tfor (q = 0; q < dev->num_queues; q++) {\n+\t\tqueue = &dev->queues[q];\n+\n+\t\twhile ((skb = ntb_transport_rx_remove(queue->qp, &len)))\n+\t\t\tdev_kfree_skb(skb);\n+\t}\n \treturn rc;\n }\n \n static int ntb_netdev_close(struct net_device *ndev)\n {\n \tstruct ntb_netdev *dev = netdev_priv(ndev);\n+\tstruct ntb_netdev_queue *queue;\n \tstruct sk_buff *skb;\n+\tunsigned int q;\n \tint len;\n \n-\tntb_transport_link_down(dev->qp);\n+\tnetif_tx_stop_all_queues(ndev);\n+\n+\tfor (q = 0; q < dev->num_queues; q++) {\n+\t\tqueue = &dev->queues[q];\n \n-\twhile ((skb = ntb_transport_rx_remove(dev->qp, &len)))\n-\t\tdev_kfree_skb(skb);\n+\t\tntb_transport_link_down(queue->qp);\n \n-\ttimer_delete_sync(&dev->tx_timer);\n+\t\twhile ((skb = ntb_transport_rx_remove(queue->qp, &len)))\n+\t\t\tdev_kfree_skb(skb);\n \n+\t\ttimer_delete_sync(&queue->tx_timer);\n+\t}\n \treturn 0;\n }\n \n static int ntb_netdev_change_mtu(struct net_device *ndev, int new_mtu)\n {\n \tstruct ntb_netdev *dev = netdev_priv(ndev);\n+\tstruct ntb_netdev_queue *queue;\n \tstruct sk_buff *skb;\n-\tint len, rc;\n+\tunsigned int q, i;\n+\tint len, rc = 0;\n \n-\tif (new_mtu > ntb_transport_max_size(dev->qp) - ETH_HLEN)\n+\tif (new_mtu > ntb_transport_max_size(dev->queues[0].qp) - ETH_HLEN)\n \t\treturn -EINVAL;\n \n \tif (!netif_running(ndev)) {\n@@ -311,41 +401,54 @@ static int ntb_netdev_change_mtu(struct net_device *ndev, int new_mtu)\n \t}\n \n \t/* Bring down the link and dispose of posted rx entries */\n-\tntb_transport_link_down(dev->qp);\n+\tfor (q = 0; q < dev->num_queues; q++)\n+\t\tntb_transport_link_down(dev->queues[0].qp);\n \n \tif (ndev->mtu < new_mtu) {\n-\t\tint i;\n-\n-\t\tfor (i = 0; (skb = ntb_transport_rx_remove(dev->qp, &len)); i++)\n-\t\t\tdev_kfree_skb(skb);\n+\t\tfor (q = 0; q < dev->num_queues; q++) {\n+\t\t\tqueue = &dev->queues[q];\n \n-\t\tfor (; i; i--) {\n-\t\t\tskb = netdev_alloc_skb(ndev, new_mtu + ETH_HLEN);\n-\t\t\tif (!skb) {\n-\t\t\t\trc = -ENOMEM;\n-\t\t\t\tgoto err;\n-\t\t\t}\n-\n-\t\t\trc = ntb_transport_rx_enqueue(dev->qp, skb, skb->data,\n-\t\t\t\t\t\t      new_mtu + ETH_HLEN);\n-\t\t\tif (rc) {\n+\t\t\tfor (i = 0;\n+\t\t\t     (skb = ntb_transport_rx_remove(queue->qp, &len));\n+\t\t\t     i++)\n \t\t\t\tdev_kfree_skb(skb);\n-\t\t\t\tgoto err;\n+\n+\t\t\tfor (; i; i--) {\n+\t\t\t\tskb = netdev_alloc_skb(ndev,\n+\t\t\t\t\t\t       new_mtu + ETH_HLEN);\n+\t\t\t\tif (!skb) {\n+\t\t\t\t\trc = -ENOMEM;\n+\t\t\t\t\tgoto err;\n+\t\t\t\t}\n+\n+\t\t\t\trc = ntb_transport_rx_enqueue(queue->qp, skb,\n+\t\t\t\t\t\t\t      skb->data,\n+\t\t\t\t\t\t\t      new_mtu +\n+\t\t\t\t\t\t\t      ETH_HLEN);\n+\t\t\t\tif (rc) {\n+\t\t\t\t\tdev_kfree_skb(skb);\n+\t\t\t\t\tgoto err;\n+\t\t\t\t}\n \t\t\t}\n \t\t}\n \t}\n \n \tWRITE_ONCE(ndev->mtu, new_mtu);\n \n-\tntb_transport_link_up(dev->qp);\n+\tfor (q = 0; q < dev->num_queues; q++)\n+\t\tntb_transport_link_up(dev->queues[q].qp);\n \n \treturn 0;\n \n err:\n-\tntb_transport_link_down(dev->qp);\n+\tfor (q = 0; q < dev->num_queues; q++) {\n+\t\tstruct ntb_netdev_queue *queue = &dev->queues[q];\n+\n+\t\tntb_transport_link_down(queue->qp);\n \n-\twhile ((skb = ntb_transport_rx_remove(dev->qp, &len)))\n-\t\tdev_kfree_skb(skb);\n+\t\twhile ((skb = ntb_transport_rx_remove(queue->qp, &len)))\n+\t\t\tdev_kfree_skb(skb);\n+\t}\n \n \tnetdev_err(ndev, \"Error changing MTU, device inoperable\\n\");\n \treturn rc;\n@@ -404,6 +507,7 @@ static int ntb_netdev_probe(struct device *client_dev)\n \tstruct net_device *ndev;\n \tstruct pci_dev *pdev;\n \tstruct ntb_netdev *dev;\n+\tunsigned int q, desired_queues;\n \tint rc;\n \n \tntb = dev_ntb(client_dev->parent);\n@@ -411,7 +515,9 @@ static int ntb_netdev_probe(struct device *client_dev)\n \tif (!pdev)\n \t\treturn -ENODEV;\n \n-\tndev = alloc_etherdev(sizeof(*dev));\n+\tdesired_queues = ntb_netdev_default_queues();\n+\n+\tndev = alloc_etherdev_mq(sizeof(*dev), desired_queues);\n \tif (!ndev)\n \t\treturn -ENOMEM;\n \n@@ -420,6 +526,15 @@ static int ntb_netdev_probe(struct device *client_dev)\n \tdev = netdev_priv(ndev);\n \tdev->ndev = ndev;\n \tdev->pdev = pdev;\n+\tdev->num_queues = 0;\n+\n+\tdev->queues = kcalloc(desired_queues, sizeof(*dev->queues),\n+\t\t\t      GFP_KERNEL);\n+\tif (!dev->queues) {\n+\t\trc = -ENOMEM;\n+\t\tgoto err_free_netdev;\n+\t}\n+\n \tndev->features = NETIF_F_HIGHDMA;\n \n \tndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;\n@@ -436,26 +551,51 @@ static int ntb_netdev_probe(struct device *client_dev)\n \tndev->min_mtu = 0;\n \tndev->max_mtu = ETH_MAX_MTU;\n \n-\tdev->qp = ntb_transport_create_queue(ndev, client_dev,\n-\t\t\t\t\t     &ntb_netdev_handlers);\n-\tif (!dev->qp) {\n+\tfor (q = 0; q < desired_queues; q++) {\n+\t\tstruct ntb_netdev_queue *queue = &dev->queues[q];\n+\n+\t\tqueue->ntdev = dev;\n+\t\tqueue->qid = q;\n+\t\tqueue->qp = ntb_transport_create_queue(queue, client_dev,\n+\t\t\t\t\t\t       &ntb_netdev_handlers);\n+\t\tif (!queue->qp)\n+\t\t\tbreak;\n+\n+\t\tdev->num_queues++;\n+\t}\n+\n+\tif (!dev->num_queues) {\n \t\trc = -EIO;\n-\t\tgoto err;\n+\t\tgoto err_free_queues;\n \t}\n \n-\tndev->mtu = ntb_transport_max_size(dev->qp) - ETH_HLEN;\n+\trc = netif_set_real_num_tx_queues(ndev, dev->num_queues);\n+\tif (rc)\n+\t\tgoto err_free_qps;\n+\n+\trc = netif_set_real_num_rx_queues(ndev, dev->num_queues);\n+\tif (rc)\n+\t\tgoto err_free_qps;\n+\n+\tndev->mtu = ntb_transport_max_size(dev->queues[0].qp) - ETH_HLEN;\n \n \trc = register_netdev(ndev);\n \tif (rc)\n-\t\tgoto err1;\n+\t\tgoto err_free_qps;\n \n \tdev_set_drvdata(client_dev, ndev);\n-\tdev_info(&pdev->dev, \"%s created\\n\", ndev->name);\n+\tdev_info(&pdev->dev, \"%s created with %u queue pairs\\n\",\n+\t\t ndev->name, dev->num_queues);\n \treturn 0;\n \n-err1:\n-\tntb_transport_free_queue(dev->qp);\n-err:\n+err_free_qps:\n+\tfor (q = 0; q < dev->num_queues; q++)\n+\t\tntb_transport_free_queue(dev->queues[q].qp);\n+\n+err_free_queues:\n+\tkfree(dev->queues);\n+\n+err_free_netdev:\n \tfree_netdev(ndev);\n \treturn rc;\n }\n@@ -464,9 +604,14 @@ static void ntb_netdev_remove(struct device *client_dev)\n {\n \tstruct net_device *ndev = dev_get_drvdata(client_dev);\n \tstruct ntb_netdev *dev = netdev_priv(ndev);\n+\tunsigned int q;\n+\n \n \tunregister_netdev(ndev);\n-\tntb_transport_free_queue(dev->qp);\n+\tfor (q = 0; q < dev->num_queues; q++)\n+\t\tntb_transport_free_queue(dev->queues[q].qp);\n+\n+\tkfree(dev->queues);\n \tfree_netdev(ndev);\n }\n \n",
    "prefixes": [
        "RFC",
        "v3",
        "28/35"
    ]
}